5 Transpile API reference ๐ - experimental ๐งช
Sometimes, data visualization in the browser requires not only plain JSON structures but also some Javascript code.
One way to generate such code from Clojure is through std.lang, a universal transpiler from Clojure to many languages.
The transpile API of Tableplot provides functions for using this practice in combination with various JS libraries. It is considered experimental at this stage.
5.1 Setup ๐จ
In this tutorial, we use:
- The Tableplot
transpileAPI namepace - Tablecloth for dataset processing and column processing
- the datasets defined in the Datasets chapter
- Kindly to annotate the kind of way certain values should be displayed
(ns tableplot-book.transpile-reference
(:require [scicloj.tableplot.v1.transpile :as transpile]
[tablecloth.api :as tc]
[scicloj.metamorph.ml.rdatasets :as rdatasets]
[clojure.string :as str]
[scicloj.kindly.v4.kind :as kind]))5.2 Functions โ
5.2.1 js
[& forms]
Transpile the given Clojure forms to Javascript code using Std.lang.
5.2.1.1 Examples
(kind/code
(transpile/js '(var x 9)
'(return (+ x 11))))let x = 9;
return x + 11;An adaptation of a Plotly.js example - Animations in Javascript:
(kind/hiccup
[:div
[:button {:onclick (transpile/js '(randomize))}
"Randomize!"]
[:div {:style {:height "auto"}}
[:script
(transpile/js
'(var plotly-animaton-element document.currentScript.parentElement)
'(Plotly.newPlot plotly-animaton-element
[{:x [1 2 3]
:y [0 0.5 1]
:line {:simplify false}}])
'(defn randomize []
(Plotly.animate plotly-animaton-element
{:data [{:y [(Math.random)
(Math.random)
(Math.random)]}]
:traces [0]
:layout {}}
{:transition {:duration 500
:easing "cut-in-out"}
:frame {:duration 500}})))]]]
{:html/deps [:plotly]})5.2.2 div-with-script
[data script kindly-options]
Create a general transpiled data visualization.
Given a data structure data, a form script, and a map kindly-options create a corresponding Hiccup structure.
The structure will be a :div with a :script element that has some Javascript code.
The code is transpiled from script with some variable bindings preceeding it:
- A Javscript variable called
datais bound to thedatavalue converted to JSON. - If
datais a map that has some keys of symbol type, then corresponding Javascript variables named by these symbols are bound to the corresponding values converted to JSON.
The resulting structure is marked by the Kindly standard as kind/hiccup with Kindly options defined by deep-merging kindly-options into *base-kindly-options*.
5.2.2.1 Examples
Let us create an Apache Echarts plot.
(transpile/div-with-script
;; data
[[1 2]
[2 4]
[3 9]
[4 16]]
;; script
['(var myChart
(echarts.init
document.currentScript.parentElement))
(list 'myChart.setOption
{:xAxis {}
:yAxis {}
:series [{:type "scatter"
:data 'data}]})]
;; Kindly options (merged with default)
{:html/deps [:echarts]
:style {:height "300px"
:background "floralwhite"}})5.2.2.2 A closer look
Let us create a Plotly.js plot with some custom event handling. We will explore the resulting structure a little bit.
(def clickable-example
(transpile/div-with-script
;; data (with symbol bindings)
{'x [1 2 3 4]
'y [3 4 9 16]}
;; script
['(var plotly-animaton-element document.currentScript.parentElement)
'(Plotly.newPlot plotly-animaton-element
{:data
[{:x x
:y y
:mode "markers"
:type "scatter"
:marker {:size 20}}]
:layout {:title
"Would you please click the points?"}})
'(. plotly-animaton-element
(on "plotly_click"
(fn []
(alert "Thanks for clicking."))))]
;; Kindly options
{:html/deps [:plotly]}))First, let us see it visualized:
clickable-exampleNow, let us check the metadata:
(meta clickable-example)#:kindly{:kind :kind/hiccup,
:options {:style {:height :auto}, :html/deps [:plotly]}}Now, let us pretty-print it to see the Hiccup structure.
(kind/pprint
clickable-example)[:div
[:script
"(function () {\nlet data = {\"x\":[1,2,3,4],\"y\":[3,4,9,16]};\nlet x = data['x'];\nlet y = data['y'];\nlet plotly_animaton_element = document.currentScript.parentElement;\nPlotly.newPlot(plotly_animaton_element,{\n \"data\":[\n {\n \"x\":x,\n \"y\":y,\n \"mode\":\"markers\",\n \"type\":\"scatter\",\n \"marker\":{\"size\":20}\n }\n ],\n \"layout\":{\"title\":\"Would you please click the points?\"}\n});\nplotly_animaton_element.on(\"plotly_click\",function (){\n alert(\"Thanks for clicking.\");\n});\n})();"]]Let us focus on the code of the script:
(-> clickable-example
second
second
kind/code)(function () {
let data = {"x":[1,2,3,4],"y":[3,4,9,16]};
let x = data['x'];
let y = data['y'];
let plotly_animaton_element = document.currentScript.parentElement;
Plotly.newPlot(plotly_animaton_element,{
"data":[
{
"x":x,
"y":y,
"mode":"markers",
"type":"scatter",
"marker":{"size":20}
}
],
"layout":{"title":"Would you please click the points?"}
});
plotly_animaton_element.on("plotly_click",function (){
alert("Thanks for clicking.");
});
})();5.2.3 echarts
[form]
[data form]
Given a data structure data and a form form, create a corresponding Apache Echarts data visualization using div-with-script.
The script will include the following:
- A Javscript variable called
datais bound to thedatavalue converted to JSON. - If
datais a map that has some keys of symbol type, then corresponding Javascript variables named by these symbols are bound to the corresponding values converted to JSON. - The
formtranspiled to Javascript. - Additional code to visualize it.
The resulting structure is marked by the Kindly standard as kind/hiccup with Kindly options necessart to make the plot work.
If no data value is passed, it is considered nil.
5.2.3.1 Examples
(transpile/echarts
;; data
[[1 2]
[2 4]
[3 9]
[4 16]]
;; form
{:xAxis {}
:yAxis {}
:series [{:type "scatter"
:data 'data}]})(-> (rdatasets/datasets-mtcars)
(tc/select-columns [:wt :mpg :cyl :gear])
tc/rows
(transpile/echarts {:xAxis {:name "weight"}
:yAxis {:name "miles per gallon"}
:visualMap [{:dimension 2
:categories ["4" "6" "8"]
:inRange {:color ["#51689b", "#ce5c5c", "#fbc357"]}
:name "cylinders"}]
:tooltip {:formatter '(fn [obj]
(return
(+
"<p>weight:" (. obj value [0]) "</p>"
"<p>miles per fallon:" (. obj value [1]) "</p>"
"<p>cylinders:" (. obj value [2]) "</p>"
"<p>gears:" (. obj value [3]) "</p>")))}
:series [{:type "scatter"
:symbolSize '(fn [value]
(-> value
(. [3])
(* 5)
return))
:data 'data}]}))5.2.4 plotly
[form]
[data form]
Given a data structure data and a form form, reate a corrseponding Plotly.js data visualization using div-with-script.
The script will include the following:
- A Javscript variable called
datais bound to thedatavalue converted to JSON. - If
datais a map that has some keys of symbol type, then corresponding Javascript variables named by these symbols are bound to the corresponding values converted to JSON. - The
formtranspiled to Javascript. - Additional code to visualize it.
The resulting structure is marked by the Kindly standard as kind/hiccup with Kindly options necessart to make the plot work.
If no data value is passed, it is considered nil.
5.2.4.1 Examples
(transpile/plotly
;; data
{:x [1 2 3 4]
:y [3 4 9 16]}
;; form
{:data ['{:x data.x
:y data.y
:mode "markers"
:type "scatter"}]})(transpile/plotly
;; data with symbol bindings
{'x [1 2 3 4]
'y [3 4 9 16]}
;; form
{:data ['{:x x
:y y
:mode "markers"
:type "scatter"}]})5.2.5 vega-embed
[form]
[data form]
Given a data structure data and a form form, create a corresponding Vega-Embed data visualization using div-with-script.
The script will include the following:
- A Javscript variable called
datais bound to thedatavalue converted to JSON. - If
datais a map that has some keys of symbol type, then corresponding Javascript variables named by these symbols are bound to the corresponding values converted to JSON. - The
formtranspiled to Javascript. - Additional code to visualize it.
The resulting structure is marked by the Kindly standard as kind/hiccup with Kindly options necessart to make the plot work.
If no data value is passed, it is considered nil.
5.2.5.1 Example
(transpile/vega-embed
;; data
[{:x 1 :y 1}
{:x 2 :y 4}
{:x 3 :y 9}
{:x 4 :y 16}]
;; form
{:data {:values 'data}
:mark "point"
:encoding {:x {:field "x" :type "quantitative"}
:y {:field "y" :type "quantitative"}}})5.2.6 highcharts
[form]
[data form]
Given a data structure data and a form form, create a corresponding Highcharts data visualization using div-with-script.
The script will include the following:
- A Javscript variable called
datais bound to thedatavalue converted to JSON. - If
datais a map that has some keys of symbol type, then corresponding Javascript variables named by these symbols are bound to the corresponding values converted to JSON. - The
formtranspiled to Javascript. - Additional code to visualize it.
The resulting structure is marked by the Kindly standard as kind/hiccup with Kindly options necessart to make the plot work.
If no data value is passed, it is considered nil.
5.2.6.1 Example
(transpile/highcharts
;; data
[[1 2]
[2 4]
[3 9]
[4 16]]
;; form
{:title {:text "a scatterplot"}
:chart {:type "scatter"}
:series [{:data 'data}]})5.2.7 leaflet
[form]
[data form]
Given a data structure data and a form form, create a corresponding Leaflet data visualization using div-with-script.
The script will include the following:
- A Javscript variable called
datais bound to thedatavalue converted to JSON. - If
datais a map that has some keys of symbol type, then corresponding Javascript variables named by these symbols are bound to the corresponding values converted to JSON. - The
formtranspiled to Javascript, and is assumed to define a function to process a Leaflet map. - Additional code to visualize it.
The resulting structure is marked by the Kindly standard as kind/hiccup with Kindly options necessart to make the plot work.
If no data value is passed, it is considered nil.
5.2.7.1 Example
(transpile/leaflet
;; data with symbol bindings
{'center [-37.84 144.95]
'zoom 11
'provider "OpenStreetMap.Mapnik"
'marker [-37.9 144.8]
'popup "<i style='color:purple'>Have you been here?</i>"}
;; form
'(fn [m]
(m.setView center zoom)
(-> (L.tileLayer.provider provider)
(. (addTo m)))
(-> marker
L.marker
(. (addTo m))
(. (bindPopup popup))
(. (openPopup)))))5.3 Danymic vars ๐ง
5.3.1 *base-kindly-options*
Base Kindly options for structures generated by div-with-script.
transpile/*base-kindly-options*{:style {:height :auto}}