Skip to content

Commit

Permalink
Calculate axis and tick marks in initial data prep rather than on draw.
Browse files Browse the repository at this point in the history
Factor out histogram SVG into function that can be shared between main hist and mini-hists.
  • Loading branch information
lynaghk committed Aug 18, 2012
1 parent c3201fc commit 4bba17b
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 59 deletions.
76 changes: 56 additions & 20 deletions src/cljs/vcfvis/data.cljs
Expand Up @@ -3,33 +3,69 @@
[reflex.macros :only [constrain!]])
(:use [c2.util :only [clj->js]]
[cljs.reader :only [read-string]])
(:require [vcfvis.core :as core]))
(:require [vcfvis.core :as core]
[vcfvis.ui :as ui]
[c2.scale :as scale]
[c2.ticks :as ticks]))


(def num-bins 100)

(defn expand-metric [metric-id]
(if-let [m (-> @core/!context :metrics metric-id)]
(merge {:id metric-id} m)
(throw (str "No metric information for metric-id: " metric-id))))
(defn expand-metric
"Adds id and an x-scale with tick marks to a metric."
[metric]
(if (metric :range)
(assoc metric
:scale-x (let [{:keys [ticks]} (ticks/search (metric :range)
:clamp? true :length ui/hist-width)
x (scale/linear :domain (metric :range)
:range [0 ui/hist-width])]
(assoc x :ticks ticks)))
(throw (str "Metric doesn't have range: " (pr metric)))))

(defn prep-context [context]
(update-in context [:metrics]
#(reduce (fn [res [id m]]
(assoc res id
(-> m
expand-metric
(assoc :id id))))
{} %)))

(defn prep-vcf-json [vcf-json]
(let [info (read-string (aget vcf-json "clj"))
(let [info (-> (read-string (aget vcf-json "clj"))
;;Expand metric-ids to full metric maps available in context (a join, basically)
(update-in [:available-metrics] #(map (@core/!context :metrics) %)))

cf (js/crossfilter (aget vcf-json "raw"))]
(merge (update-in info [:available-metrics] #(set (map expand-metric %)))
{:cf (into {:crossfilter cf}
(for [metric (info :available-metrics)]
(let [[start end] (get-in @core/!context [:metrics metric :range])
bin-width (/ (- end start) num-bins)
dim (.dimension cf #(aget % metric))
binned (.group dim (fn [x]
(+ start (* bin-width
;;take the min to catch any roundoff into the last bin
(min (Math/floor (/ (- x start) bin-width))
(dec num-bins))))))]
[metric {:bin-width bin-width
:dimension dim
:binned binned}])))})))

(assoc info
:cf (into {:crossfilter cf}
(for [{:keys [id range]} (info :available-metrics)]
(let [[start end] range
bin-width (/ (- end start) num-bins)
dim (.dimension cf #(aget % id))
binned (.group dim (fn [x]
(+ start (* bin-width
;;take the min to catch any roundoff into the last bin
(min (Math/floor (/ (- x start) bin-width))
(dec num-bins))))))]
[id {:bin-width bin-width
:dimension dim
:binned binned}]))))))
















Expand Down
67 changes: 29 additions & 38 deletions src/cljs/vcfvis/histogram.cljs
Expand Up @@ -5,26 +5,20 @@
[c2.maths :only [irange extent]])
(:require [vcfvis.core :as core]
[vcfvis.data :as data]
[vcfvis.ui :as ui]
[vcfvis.double-range :as double-range]
[c2.dom :as dom]
[c2.event :as event]
[c2.scale :as scale]
[c2.svg :as svg]
[c2.ticks :as ticks]
[goog.string :as gstr]))

(def margin "left/right margin" 20)
(def inter-hist-margin "vertical margin between stacked histograms" 20)
(def axis-height (js/parseFloat (dom/style "#hist-axis" :height)))
(def height ui/hist-height)
(def width ui/hist-width)
(def margin ui/hist-margin)
(def inter-hist-margin ui/inter-hist-margin)
(def axis-height ui/axis-height)

(def height
"height available to histogram facet grid"
(js/parseFloat (dom/style "#histograms" :height)))

(def width
"Width of histogram facet grid"
(- (js/parseFloat (dom/style "#histograms" :width))
(* 2 margin)))


;; (def !selected-extent (atom [0 1]))
Expand Down Expand Up @@ -53,53 +47,50 @@
;; (fn [_ _ _ _] (data/reset-statuses!)))




(defn histogram* [vcf scale-x metric]
(defn hist-svg* [vcf metric & {:keys [margin]}]
(let [height (- height axis-height)
{:keys [dimension binned bin-width]} (get-in vcf [:cf (metric :id)])
{metric-id :id scale-x :scale-x} metric
{:keys [dimension binned bin-width]} (get-in vcf [:cf metric-id])
;;Since we're only interested in relative density, histograms have free y-scales.
scale-y (scale/linear :domain [0 (aget (first (.top binned 1)) "value")]
:range [0 height])
dx (- (scale-x bin-width) (scale-x 0))]

[:div.histogram
[:span.label (vcf :file-url)]
[:svg {:width (+ width (* 2 margin)) :height (+ height inter-hist-margin)}
[:g {:transform (svg/translate [margin margin])}
[:g.distribution {:transform (str (svg/translate [0 height])
(svg/scale [1 -1]))}

[:svg {:width (+ width (* 2 margin)) :height (+ height inter-hist-margin)}
[:g {:transform (svg/translate [margin margin])}
[:g.distribution {:transform (str (svg/translate [0 height])
(svg/scale [1 -1]))}
(for [d (.all binned)]
(let [x (aget d "key"), count (aget d "value")]
[:rect.bar {:x (scale-x x)
:width (- (scale-x (+ x bin-width))
(scale-x x))
:height (scale-y count)}]))]]]]))
(for [d (.all binned)]
(let [x (aget d "key"), count (aget d "value")]
[:rect.bar {:x (scale-x x)
:width (- (scale-x (+ x bin-width))
(scale-x x))
:height (scale-y count)}]))]]]))




(bind! "#main-hist"
(let [vcfs @core/!vcfs]
(if (seq vcfs)
(let [metric @core/!metric
metric-extent (metric :range)
{:keys [ticks]} (ticks/search metric-extent
:clamp? true :length width)
x (scale/linear :domain metric-extent
:range [0 width])]
(let [{x :scale-x :as metric} @core/!metric]
[:div#main-hist
[:div#histograms

;;histogram distributions
(histogram* (first vcfs) x metric)]
(for [vcf vcfs]
[:div.histogram
[:span.label (vcf :file-url)]
(hist-svg* vcf metric :margin margin)])]

[:div#hist-axis
[:div.axis.abscissa
[:svg {:width (+ width (* 2 margin)) :height axis-height}
[:g {:transform (svg/translate [margin 2])}
(svg/axis x ticks :orientation :bottom
(svg/axis x (:ticks x)
:orientation :bottom
:formatter (partial gstr/format "%.1f"))]]]]])


;;If no VCFs, clear everything
[:div#main-hist
[:div#histograms]
Expand Down
2 changes: 1 addition & 1 deletion src/cljs/vcfvis/stub.cljs
Expand Up @@ -31,7 +31,7 @@

(defn load-context [callback]
(timeout 10
(callback context)))
(callback (data/prep-context context))))

(defn load-vcf [file-url callback]
(.getJSON js/$ "big.json"
Expand Down
20 changes: 20 additions & 0 deletions src/cljs/vcfvis/ui.cljs
Expand Up @@ -7,3 +7,23 @@
(let [$dd (dom/select "#user-dropdown")]
(constrain!
(dom/text $dd (get @core/!context :username "USER"))))





;;;;;;;;;;;;;;;;;;;
;;Histogram params

(def hist-margin "left/right margin" 20)
(def inter-hist-margin "vertical margin between stacked histograms" 20)
(def axis-height (js/parseFloat (dom/style "#hist-axis" :height)))

(def hist-height
"Height available to histogram facet grid"
(js/parseFloat (dom/style "#histograms" :height)))

(def hist-width
"Width of histogram facet grid"
(- (js/parseFloat (dom/style "#histograms" :width))
(* 2 hist-margin)))

0 comments on commit 4bba17b

Please sign in to comment.