Skip to content

Commit 8b639c7

Browse files
committed
Time series chart working
1 parent aaeb99e commit 8b639c7

File tree

4 files changed

+3649
-3641
lines changed

4 files changed

+3649
-3641
lines changed

cljs-om/externs/misc.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,8 @@ BirdWatch.updateBarchart = function (words) {};
1212
var Rickshaw = {};
1313
Rickshaw.Fixtures = {};
1414
Rickshaw.Fixtures.RandomData = {};
15-
Rickshaw.Fixtures.RandomData.addData = function (n) {}
15+
Rickshaw.Fixtures.RandomData.addData = function (n) {};
1616
Rickshaw.Graph = {};
17+
Rickshaw.Graph.Axis = {};
18+
Rickshaw.Graph.Axis.Time = function (graph) {};
19+
Rickshaw.Graph.HoverDetail = function (graph) {};

cljs-om/src/cljs_om/core.cljs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,7 @@
2727
(def word-cloud (.WordCloud js/BirdWatch cloud-w (* cloud-w 0.7) 250 (fn [e]) "#wordCloud"))
2828

2929
;;; refresh BarChart and time series chart occasionally (could potentially be more elegant)
30-
(js/setInterval #(ts/update ts/graph-with-legend app-state) 5000)
31-
;(js/setInterval #(.updateBarchart js/BirdWatch (clj->js (take 25 (:words-sorted-by-count @app-state)))) 1000)
30+
(js/setInterval #(ts/update ts/graph-with-legend app-state) 2500)
3231
(js/setInterval #(.updateBarchart js/BirdWatch (clj->js (wc/get-words app-state 25))) 1000)
3332

3433
;;; Channels for handling information flow in the application.

cljs-om/src/cljs_om/timeseries.cljs

Lines changed: 43 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -18,81 +18,65 @@
1818
(def ts-elem (. js/document (getElementById "timeseries1")))
1919
(def ts-w (aget ts-elem "offsetWidth"))
2020

21-
#_(def ts-chart (js/Rickshaw.Graph.
22-
(clj->js {:element ts-elem
23-
:renderer "bar"
24-
:width ts-w
25-
:height 100
26-
:series [{:color "steelblue"
27-
:name "Tweets"
28-
:data [{:x 100 :y 10} {:x 100 :y 110}]}]})))
29-
30-
#_(Rickshaw.Graph.Axis.Time. (clj->js {:graph ts-chart}))
31-
#_(.render ts-chart)
32-
#_(def hover-detail (Rickshaw.Graph.HoverDetail. (clj->js {:graph ts-chart})))
33-
34-
(defn random-data []
35-
(let [series-data (array (array))
36-
random (Rickshaw.Fixtures.RandomData. 150)]
37-
(dotimes [i 100] (.addData random series-data))
38-
series-data))
39-
40-
;; https://gist.github.com/msgodf/8495781
4121
(def graph-with-legend
4222
(doto
43-
(Rickshaw.Graph. (clj->js {:element ts-elem
44-
:renderer "bar"
45-
:width ts-w
46-
:height 100
47-
:series [{:color "steelblue"
48-
:data (nth (random-data) 0)
49-
:name "Tweets"}]}))
23+
(Rickshaw.Graph. (clj->js {:element ts-elem :renderer "bar"
24+
:width ts-w :height 100
25+
:series [{:color "steelblue" :data [{:x 1 :y 0}] :name "Tweets"}]}))
5026
(.render)))
5127

52-
(defn floor [x] (Math/floor x))
28+
(Rickshaw.Graph.Axis.Time. (clj->js {:graph graph-with-legend}))
29+
(def hover-detail (Rickshaw.Graph.HoverDetail. (clj->js {:graph graph-with-legend :yFormatter #(Math/round %)})))
5330

5431
(defn date-round [s]
5532
"return function that rounds the provided seconds since epoch down to the nearest time interval s
5633
e.g. (date-round 60) creates a function that takes seconds t and rounds them to the nearest minute"
57-
(fn [t] (* s (floor (/ t s)))))
34+
(fn [t] (* s (Math/floor (/ t s)))))
5835

5936
(def m 60)
37+
(def qhr (* 15 m))
6038
(def hr (* 60 m))
39+
(def qday (* 6 hr))
6140
(def day (* 24 hr))
6241

63-
(defn grouper [newest oldest]
42+
(defn grouping-interval [newest oldest]
6443
(cond
65-
(> (- newest oldest) (* 20 day)) (date-round (* 24 60 60)) ;round by nearest day
66-
(> (- newest oldest) (* 5 day)) (date-round (* 6 60 60)) ;round by nearest quarter day
67-
(> (- newest oldest) (* 10 hr)) (date-round (* 60 60)) ;round by nearest hour
68-
(> (- newest oldest) (* 2 hr)) (date-round (* 15 60)) ;round by nearest quarter hour
69-
:else (date-round 60))) ;round by nearest minute
44+
(> (- newest oldest) (* 20 day)) day ;round by nearest day
45+
(> (- newest oldest) (* 5 day)) qday ;round by nearest quarter day
46+
(> (- newest oldest) (* 20 hr)) hr ;round by nearest hour
47+
(> (- newest oldest) (* 4 hr)) qhr ;round by nearest quarter hour
48+
:else m)) ;round by nearest minute
49+
50+
(defn empty-ts-map [newest oldest interval]
51+
"generates map with all rounded intervals between oldest and newest, initialized to a count of 0"
52+
(let [rounder (date-round interval)
53+
values (range (rounder oldest) (rounder newest) interval)]
54+
(apply sorted-map-by < (flatten [(interpose 0 values) 0]))))
55+
56+
(defn count-into-map [ts-map k]
57+
"increment count for time interval"
58+
(update-in ts-map [k] inc))
59+
60+
(defn tweet-ts [t]
61+
"retrieve seconds since epoch from tweet using moment.js"
62+
(.unix (js/moment. (:created_at t))))
7063

7164
(defn ts-data [app]
72-
(let [state @app
73-
by-id (util/tweets-by-order :tweets-map :by-id)
74-
tweets-by-id (by-id state 10000)
75-
oldest (js/moment. (:created_at (last tweets-by-id)))
76-
newest (js/moment. (:created_at (first tweets-by-id)))
77-
rounder (grouper (.unix newest) (.unix oldest))
78-
]
79-
(print "oldest" (.toLocaleString oldest))
80-
(print "oldest unix" (.unix oldest))
81-
(print "oldest min rounded unix" (round-min (.unix oldest)))
82-
(print "oldest min rounded parsed" (.toLocaleString (.unix js/moment (round-min (.unix oldest)))))
83-
(print "oldest hr rounded unix" (round-hr (.unix oldest)))
84-
(print "oldest hr rounded parsed" (.toLocaleString (.unix js/moment (round-hr (.unix oldest)))))
85-
(print "oldest day rounded unix" (round-day (.unix oldest)))
86-
(print "oldest day rounded parsed" (.toLocaleString (.unix js/moment (round-day (.unix oldest)))))
87-
(print "oldest rounded unix" (rounder (.unix oldest)))
88-
(print "oldest rounded parsed" (.toLocaleString (.unix js/moment (rounder (.unix oldest)))))
89-
(print "---")
90-
(print "newest" (.toLocaleString newest))
91-
(print "newest" (.unix newest))
92-
(print "---")
93-
))
65+
"perform time series analysis by counting tweets in even intervals"
66+
(let [tweets-by-id ((util/tweets-by-order :tweets-map :by-id) @app 10000)
67+
oldest (tweet-ts (last tweets-by-id))
68+
newest (tweet-ts (first tweets-by-id))
69+
interval (grouping-interval newest oldest)
70+
rounder (date-round interval)]
71+
(reduce count-into-map
72+
(empty-ts-map newest oldest interval)
73+
(map #(rounder (tweet-ts %)) tweets-by-id))))
74+
75+
(defn ts-map-vec [ts-map]
76+
"creates a vector of maps required by Rickshaw chart"
77+
(map #(zipmap [:x :y] %)(vec ts-map)))
9478

9579
(defn update [chart app]
96-
(ts-data app)
97-
(aset graph-with-legend "series" "0" "data" (nth (random-data) 0))
80+
"update time series chart"
81+
(aset graph-with-legend "series" "0" "data" (clj->js (ts-map-vec (ts-data app))))
9882
(.update chart))

0 commit comments

Comments
 (0)