Andrea Amantini / Jul 02 2019

Clojure + Python

apt-get update &&\
apt-get install libpython3.6-dev python3-pip &&\
pip3 install numpy pandas
(require '[libpython-clj.python :as py])
(require '[camel-snake-kebab.core :as csk])
(require '[camel-snake-kebab.extras :as cske])
(require '[clojure.core.memoize :as m])
;(require '[oz.core :as oz])
(py/initialize!)
:ok
{:deps
 {org.clojure/clojure      {:mvn/version "1.10.1"}
  compliment               {:mvn/version "0.3.9"}
  cnuernber/libpython-clj  {:mvn/version "0.10"}
  camel-snake-kebab        {:mvn/version "0.4.0"}
  org.clojure/core.memoize {:mvn/version "0.7.2"}
  #_#_metasoarous/oz       {:mvn/version "1.5.6"}}}
deps.edn
Extensible Data Notation
pokemon.csv
(require '[libpython-clj.python :as py])
(require '[camel-snake-kebab.core :as csk])
(require '[camel-snake-kebab.extras :as cske])
(require '[clojure.core.memoize :as m])
(py/initialize!)
:ok
(defn plot [spec] (with-meta spec {:nextjournal/viewer "vega-lite"}))
(defonce pandas (py/import-module "pandas"))
(defonce np (py/import-module "numpy"))
(defonce builtins (py/import-module "builtins"))

(def memo-key-converter
  (m/fifo csk/->snake_case_string {} :fifo/threshold 512))

(defn keyword->pyarg
  [m]
  (cske/transform-keys memo-key-converter m))

(defn key->arg
  [k]
  (if (keyword? k)
    (memo-key-converter k)
    k))

(defn read-csv
  [filename & [attrs]]
  (py/call-attr-kw pandas "read_csv" 
                   [filename] (keyword->pyarg attrs)))

(def pokemon (read-csv 
pokemon.csv
{:nrows 10}))
'user/pokemon

Since we cannot put metadata on a string value, we can return a map of the form

(defn show
  [obj]
  (let [csv (py/call-attr obj "to_csv")]
      {:nextjournal.viewer/value csv
       :nextjournal.viewer/content-type "text/csv"}))
'user/show

or

(defn show'
  [obj]
  (let [csv (py/call-attr obj "to_csv")]
    {:nextjournal.viewer/value csv
     :nextjournal/viewer "table"}))
'user/show'
(defn head
  [df-or-series & [n]]
  (py/call-attr df-or-series "head" (or n 5)))
'user/head
(defn pandas->clj
  [df-or-series]
  (map #(into {} %) (vec (py/call-attr df-or-series "to_dict" "records"))))
'user/pandas->clj
(-> pokemon head show')
#NameType 1Type 2HPAttackDefenseSp. AtkSp. DefSpeedGenerationLegendary
01BulbasaurGrassPoison4549496565451False
12IvysaurGrassPoison6062638080601False
23VenusaurGrassPoison808283100100801False
34Mega VenusaurGrassPoison80100123122120801False
45CharmanderFire3952436050651False
5 items
(-> pokemon head show)
#NameType 1Type 2HPAttackDefenseSp. AtkSp. DefSpeedGenerationLegendary
01BulbasaurGrassPoison4549496565451False
12IvysaurGrassPoison6062638080601False
23VenusaurGrassPoison808283100100801False
34Mega VenusaurGrassPoison80100123122120801False
45CharmanderFire3952436050651False
5 items
(println pokemon)