declarative web data visualization using clojurescript
TRANSCRIPT
Keming Labs
Kevin Lynagh 2012 July 20OSCON@lynaghk
Declarative web data visualization using ClojureScript
Friday, July 20, 12
Agenda
Friday, July 20, 12
Agenda
?1WhatVisualization
is
Friday, July 20, 12
Agenda
2doin’ itInternetson the
Friday, July 20, 12
Agenda
3Examplean
Friday, July 20, 12
Agenda
4Why
(not)
ClojureFriday, July 20, 12
Agenda
0 Talk
Anti-
Techideas
Friday, July 20, 12
Friday, July 20, 12
?1WhatVisualization
is
Friday, July 20, 12
Bioinformatics
Friday, July 20, 12
Wind energy
Friday, July 20, 12
Doc & patient,meet
DataFriday, July 20, 12
Friday, July 20, 12
Friday, July 20, 12
(didn’t make this, just ♥ it)
Friday, July 20, 12
?Whathave in
common do these things
Friday, July 20, 12
Data
VisualFriday, July 20, 12
0 25 50 75 100
Data: [17, 26, 53, 96]
Friday, July 20, 12
0
5
10
15
20
0 3 6 9 12 15
Data: [[1, 2] [3, 4] [5, 5] [6, 8] [8, 13] [9, 16] [11, 18]]
Friday, July 20, 12
Agenda
2doin’ itInternetson the
Friday, July 20, 12
D3: Data Driven Documents (2011)Mike Bostock Vadim OgievetskyJeffrey Heer
+
Friday, July 20, 12
D3 (JavaScript)
DOM
d3.select("body").selectAll("div") .data([17, 26, 53, 96]) .enter().append("div") .style("width", function(d){d+"px";});
Friday, July 20, 12
Awesome Declarative
Familiar representationHTML, CSS, SVG; dev toolsNo reinvented wheels
Easy to think, exploreOptimizable
Friday, July 20, 12
Awesomer Clojure(Script)
Rich data structuresNamespacesDeliberate state/mutation
Friday, July 20, 12
ClojurePhilosophy
Friday, July 20, 12
Treat yourlike Datadata
It is better to have 100 functions operate on one data structure than 10 functions on 10 data structures.
Alan Perlis
Friday, July 20, 12
D3 (JavaScript)d3.select("body").selectAll("div") .data([17, 26, 53, 96]) .enter().append("div") .style("width", function(d){d+"px";});
Friday, July 20, 12
D3 (JavaScript)d3.select("body").selectAll("div") .data([17, 26, 53, 96]) .enter().append("div") .style("width", function(d){d+"px";});
Friday, July 20, 12
D3 (JavaScript)d3.select("body").selectAll("div") .data([17, 26, 53, 96]) .enter().append("div") .style("width", function(d){d+"px";});
Can we do better?Friday, July 20, 12
Agenda
3Examplean
Friday, July 20, 12
Friday, July 20, 12
Friday, July 20, 12
[{:flight-no 2, :price 106, :carrier "Alaska" :depart 16.91, :arrive 21.42}
{:flight-no 1, :price 190, :carrier "United" :depart 6.20, :arrive 10.87}
{:flight-no 5, :price 213, :carrier "United" :depart 4.73, :arrive 9.48} ... ]
Start with your data
Friday, July 20, 12
Friday, July 20, 12
Friday, July 20, 12
(unify! "#chart" flight-data (fn [{:keys [price carrier depart arrive]} idx] [:div.row [:button.price (str "$" price)] [:div.flight {:style {:left (time-scale depart) :width (time-scale (- arrive depart))} :carrier carrier} [:span carrier]]]))
Friday, July 20, 12
(unify! "#chart" flight-data (fn [{:keys [price carrier depart arrive]} idx] [:div.row [:button.price (str "$" price)] [:div.flight {:style {:left (time-scale depart) :width (time-scale (- arrive depart))} :carrier carrier} [:span carrier]]]))
Friday, July 20, 12
(unify! "#chart" flight-data (fn [{:keys [price carrier depart arrive]} idx] [:div.row [:button.price (str "$" price)] [:div.flight {:style {:left (time-scale depart) :width (time-scale (- arrive depart))} :carrier carrier} [:span carrier]]]))
Friday, July 20, 12
(unify! "#chart" flight-data (fn [{:keys [price carrier depart arrive]} idx] [:div.row [:button.price (str "$" price)] [:div.flight {:style {:left (time-scale depart) :width (time-scale (- arrive depart))} :carrier carrier} [:span carrier]]]))
Friday, July 20, 12
(unify! "#chart" flight-data (fn [{:keys [price carrier depart arrive]} idx] [:div.row [:button.price (str "$" price)] [:div.flight {:style {:left (time-scale depart) :width (time-scale (- arrive depart))} :carrier carrier} [:span carrier]]]))
(let [time-scale (scale/linear :domain [0 24] :range :percent)]
(time-scale 0) ;=> “0%” (time-scale 12) ;=> “50%” (time-scale 24) ;=> “100%”)
Friday, July 20, 12
(unify! "#chart" flight-data (fn [{:keys [price carrier depart arrive]} idx] [:div.row [:button.price (str "$" price)] [:div.flight {:style {:left (time-scale depart) :width (time-scale (- arrive depart))} :carrier carrier} [:span carrier]]]))
Friday, July 20, 12
(unify! "#chart" flight-data (fn [{:keys [price carrier depart arrive]} idx] [:div.row [:button.price (str "$" price)] [:div.flight {:style {:left (time-scale depart) :width (time-scale (- arrive depart))} :carrier carrier} [:span carrier]]]))
Friday, July 20, 12
(unify! "#chart" flight-data (fn [{:keys [price carrier depart arrive]} idx] [:div.row [:button.price (str "$" price)] [:div.flight {:style {:left (time-scale depart) :width (time-scale (- arrive depart))} :carrier carrier} [:span carrier]]]))
Friday, July 20, 12
(unify! "#chart" flight-data (fn [{:keys [price carrier depart arrive]} idx] [:div.row [:button.price (str "$" price)] [:div.flight {:style {:left (time-scale depart) :width (time-scale (- arrive depart))} :carrier carrier} [:span carrier]]]))
Friday, July 20, 12
(unify! "#chart" flight-data (fn [{:keys [price carrier depart arrive]}] [:div.row [:button.price (str "$" price)] [:div.flight {:style {:left (time-scale depart) :width (time-scale (- arrive depart))} :carrier carrier} [:span carrier]]]))
Friday, July 20, 12
(map flight-data (fn [{:keys [price carrier depart arrive]}] [:div.row [:button.price (str "$" price)] [:div.flight {:style {:left (time-scale depart) :width (time-scale (- arrive depart))} :carrier carrier} [:span carrier]]]))
Friday, July 20, 12
(map flight-data (fn [{:keys [price carrier depart arrive]}] [:div.row [:button.price (str "$" price)] [:div.flight {:style {:left (time-scale depart) :width (time-scale (- arrive depart))} :carrier carrier} [:span carrier]]]))
Friday, July 20, 12
C2http://keminglabs.com/c2http://github.com/lynaghk/c2
Friday, July 20, 12
Advantagesof the
dataapproach
Friday, July 20, 12
Declarative
(fn [{:keys [price carrier depart arrive]}] [:div.row [:button.price (str "$" price)] [:div.flight {:style {:left (time-scale depart) :width (time-scale (- arrive depart))} :carrier carrier} [:span carrier]]])
Friday, July 20, 12
Declarative
(fn [{:keys [price carrier depart arrive]}] [:div.row [:button.price (str "$" price)] [:div.flight {:style (flight-style depart arrive)
:carrier carrier} [:span carrier]]])
Friday, July 20, 12
Declarative
(fn [{:keys [price carrier depart arrive]}] [:div.row [:button.price (str "$" price)] [:div.flight {:style (merge {:background-color "blue"} (flight-style depart arrive)) :carrier carrier} [:span carrier]]])
Friday, July 20, 12
Decoupled2) rendering1) construction
Friday, July 20, 12
Agenda
4Why
(not)
ClojureFriday, July 20, 12
Why Clojure
SaneOpinionated
&Friday, July 20, 12
Why Clojure
Runtimes:JVMCLR
JavaScript
Lua CFriday, July 20, 12
NotClojure
Friday, July 20, 12
Why not Clojure
WTFis Clojure?
Friday, July 20, 12
Why not Clojure
Clojure is the #23 most popular language on GitHub
Friday, July 20, 12
Why not Clojure
Assembly is the #18 most popular language on GitHub
Friday, July 20, 12
Why not Clojure
900+ forks
Friday, July 20, 12
Friday, July 20, 12
Keming Labs
Kevin Lynagh@lynaghk
Friday, July 20, 12