diff --git a/INTERNALS.md b/INTERNALS.md index 8585fb6..387f65f 100644 --- a/INTERNALS.md +++ b/INTERNALS.md @@ -175,12 +175,23 @@ Each continuous scale by default maps domain to `[0.0 1.0]` range. Scale can be (s/inverse (s/log [1 10]) 0.5) ;; => 3.1622776601683804 -(s/time-interval [(dt/local-date) (dt/local-date 2019 03 30)]) -;; => #charts.scale.ContinuousRange{:start #object[java.time.LocalDate 0x6025234c "2019-03-28"], :end #object[java.time.LocalDate 0x60e60a32 "2019-03-30"], :type :time, :forward #function[charts.scale/time-forward/fn--23480], :inverse #function[charts.scale/time-inverse/fn--23483], :info {:time-diff-millis 1.728E8}} -((s/time-interval [(dt/local-date-time "2019-03-01T00:00:00") (dt/local-date-time "2019-03-03T00:00:00")]) (dt/local-date "2019-03-02")) -;; => 0.5 -(s/inverse (s/time-interval [(dt/local-date-time "2019-03-01T00:00:00") (dt/local-date-time "2019-03-03T00:00:00")]) 0.1) -;; => #object[java.time.LocalDateTime 0x5e3ff815 "2019-03-01T04:48"] +(t/time-scale [(dt/local-date) (dt/local-date 2019 03 30)]) +;; => +{:start #object[java.time.LocalDateTime 0x21613dd9 "2020-04-09T00:00"], + :end #object[java.time.LocalDateTime 0x5c9ee492 "2019-03-30T00:00"], + :domain + [#object[java.time.LocalDateTime 0x21613dd9 "2020-04-09T00:00"] + #object[java.time.LocalDateTime 0x5c9ee492 "2019-03-30T00:00"]], + :type :time, + :forward #function[cljplot.scale.time/time-forward/fn--14021], + :inverse #function[cljplot.scale.time/time-inverse/fn--14024], + :info {:time-diff-millis -32486400000.0M}} +((t/time-scale [(dt/local-date-time "2019-03-01T00:00:00") (dt/local-date-time "2019-03-03T00:00:00")]) (dt/local-date "2019-03-02")) +;; => +0.5 +(s/inverse (t/time-scale [(dt/local-date-time "2019-03-01T00:00:00") (dt/local-date-time "2019-03-03T00:00:00")]) 0.1) +;; => +#object[java.time.LocalDateTime 0x5e3ff815 "2019-03-01T04:48"] ``` #### Bands @@ -195,12 +206,26 @@ Parameters are: * align - position of the selected point (0.0 - left, 1.0 - right, 0.5 - midpoint, default) ``` -(s/bands [:a :b]) -;; => #charts.scale.OrdinalRange{:domain [:a :b], :range ({:start 0.0, :end 0.5, :point 0.25} {:start 0.5, :end 1.0, :point 0.75}), :type :bands, :forward {:a {:start 0.0, :end 0.5, :point 0.25}, :b {:start 0.5, :end 1.0, :point 0.75}}, :inverse #function[charts.scale/bands-inverse-fn/fn--23540], :info {:bandwidth 0.5, :step 0.5, :value :point}} -((s/bands [:a :b]) :a) -;; => {:start 0.0, :end 0.5, :point 0.25} -((s/bands {:padding-in 0.2 :padding-out 0.2 :align 0.25} [:a :b]) :a) -;; => {:start 0.09090909090909091, :end 0.4545454545454546, :point 0.18181818181818182} +(b/bands [:a :b]) +;; => +{:domain [:a :b], + :range + ({:start 0.0, :end 0.5, :point 0.25} {:start 0.5, :end 1.0, :point 0.75}), + :cnt 2, + :type :bands, + :forward + {:a {:start 0.0, :end 0.5, :point 0.25}, + :b {:start 0.5, :end 1.0, :point 0.75}}, + :inverse #function[cljplot.scale.bands/bands-inverse-fn/fn--33870], + :info {:bandwidth 0.5, :step 0.5}} +((b/bands [:a :b]) :a) +;; => +{:start 0.0, :end 0.5, :point 0.25} +((b/bands [:a :b] {:padding-in 0.2 :padding-out 0.2 :align 0.25}) :a) +;; => +{:start 0.09090909090909091, + :end 0.4545454545454546, + :point 0.18181818181818182} ``` #### Scale map diff --git a/project.clj b/project.clj index d8aa2c3..683a3bb 100644 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject cljplot "0.0.3-SNAPSHOT" +(defproject cljplot :lein-v :description "JVM chart library" :url "https://github.com/generateme/cljplot" :license {:name "Eclipse Public License" @@ -9,6 +9,11 @@ [clojure.java-time "0.3.2"] [org.clojure/data.csv "1.0.0"] [org.clojure/data.json "1.0.0"]] + :plugins + [ + ;; Drive leiningen project version from git instead of the other way around + [com.roomkey/lein-v "7.2.0"] + ] :repl-options {:timeout 120000} :java-source-paths ["src"] :javac-options ["-target" "1.8" "-source" "1.8"] diff --git a/src/cljplot/axis.clj b/src/cljplot/axis.clj index 368a7d1..8d5fd94 100644 --- a/src/cljplot/axis.clj +++ b/src/cljplot/axis.clj @@ -98,7 +98,7 @@ (defn- find-max-tick-size "Find maximum tick size." - [{:keys [ticks]} config] + [scale {:keys [ticks] :as config}] (let [size-fn (-> config :ticks :size)] (max 0.0 (inc (double (-> config :line :stroke :size))) ^double (reduce fast-max (map #(size-fn % config) ticks))))) diff --git a/src/cljplot/common.clj b/src/cljplot/common.clj index ab8db8a..3eb4e0d 100644 --- a/src/cljplot/common.clj +++ b/src/cljplot/common.clj @@ -9,17 +9,27 @@ [clojure.data.json :as json] [clojure.java.io :as io] [java-time :as dt] + [cljplot.scale.time :as t] [cljplot.scale :as s])) (set! *warn-on-reflection* true) (set! *unchecked-math* :warn-on-boxed) (m/use-primitive-operators) -(defn fast+ {:inline (fn [^double x ^double y] `(+ ~x ~y)) :inline-arities #{2}} ^double [^double a ^double b] (+ a b)) -(defn fast- {:inline (fn [^double x ^double y] `(- ~x ~y)) :inline-arities #{2}} ^double [^double a ^double b] (- a b)) -(defn fast* {:inline (fn [^double x ^double y] `(* ~x ~y)) :inline-arities #{2}} ^double [^double a ^double b] (* a b)) -(defn fast-max {:inline (fn [^double x ^double y] `(+ ~x ~y)) :inline-arities #{2}} ^double [^double a ^double b] (max a b)) -(defn fast-min {:inline (fn [^double x ^double y] `(+ ~x ~y)) :inline-arities #{2}} ^double [^double a ^double b] (min a b)) +(defn fast+ {:inline (fn [^double x ^double y] `(+ ~x ~y)) :inline-arities #{2}} + ^double [^double a ^double b] (+ a b)) + +(defn fast- {:inline (fn [^double x ^double y] `(- ~x ~y)) :inline-arities #{2}} + ^double [^double a ^double b] (- a b)) + +(defn fast* {:inline (fn [^double x ^double y] `(* ~x ~y)) :inline-arities #{2}} + ^double [^double a ^double b] (* a b)) + +(defn fast-max {:inline (fn [^double x ^double y] `(+ ~x ~y)) :inline-arities #{2}} + ^double [^double a ^double b] (max a b)) + +(defn fast-min {:inline (fn [^double x ^double y] `(+ ~x ~y)) :inline-arities #{2}} + ^double [^double a ^double b] (min a b)) (defn graph-canvas "Create canvas to draw a chart on" @@ -63,8 +73,8 @@ (defn wrap-interpolator-for-dt "Wrap interpolator to work with date/time values." [interpolator domain x y] - (if (date-time? (first x)) - (let [scale (s/time-interval domain) + (if (date-time? (first x)) + (let [scale (t/time-scale domain) interp (interpolator (mapv scale x) y)] (fn [v] (interp (scale v)))) @@ -160,7 +170,7 @@ data)) (defn coerce-format-fn - "Find formating funciton." + "Find formatting function." [fmt] (cond (string? fmt) (partial format fmt) diff --git a/src/cljplot/core.clj b/src/cljplot/core.clj index 4d3d03c..b2c29ae 100644 --- a/src/cljplot/core.clj +++ b/src/cljplot/core.clj @@ -1,18 +1,8 @@ (ns cljplot.core - (:require [clojure2d.core :refer [next-filename]] - [cljplot.common :refer :all] - [clojure2d.extra.utils :as utils] - [cljplot.impl.histogram :refer :all] - [cljplot.build :as b] + (:require [cljplot.build :as b] [cljplot.render :as r] - [cljplot.impl.strips :refer :all] - [cljplot.impl.scatter :refer :all] - [cljplot.impl.line :refer :all] - [cljplot.impl.heatmap :refer :all] - [cljplot.impl.label :refer :all] - [cljplot.impl.math :refer :all] - [cljplot.impl.free :refer :all] - [cljplot.impl.time-series :refer :all])) + [clojure2d.core :refer [next-filename]] + [clojure2d.extra.utils :as utils])) (defn save "Save `chart`." diff --git a/src/cljplot/impl/histogram.clj b/src/cljplot/impl/histogram.clj index 7b79361..8e284c9 100644 --- a/src/cljplot/impl/histogram.clj +++ b/src/cljplot/impl/histogram.clj @@ -1,5 +1,6 @@ (ns cljplot.impl.histogram (:require [cljplot.common :refer :all] + [cljplot.scale.bands :as b] [cljplot.scale :as s] [fastmath.core :as m] [fastmath.stats :as stats] @@ -85,7 +86,7 @@ (defn- draw-series [canvas data {:keys [palette stroke stroke? type padding-in padding-out ^double zero] :or {type :bars}}] - (let [bands (s/bands {:padding-out padding-out :padding-in padding-in} (count data)) + (let [bands (b/bands {:padding-out padding-out :padding-in padding-in} (count data)) zero (+ zero 3)] (doseq [[idx d] (map-indexed vector data)] (let [{:keys [^double start ^double end ^double point]} (bands idx) diff --git a/src/cljplot/impl/math.clj b/src/cljplot/impl/math.clj index df2f81e..9930d9f 100644 --- a/src/cljplot/impl/math.clj +++ b/src/cljplot/impl/math.clj @@ -9,6 +9,7 @@ [clojure2d.core :refer :all] [fastmath.grid :as grid] [fastmath.stats :as stats] + [cljplot.utils :as u] [cljplot.scale :as s]) (:import [marchingsquares Algorithm])) @@ -133,7 +134,7 @@ (f (iscale-x xx) (iscale-y yy)))] (let [^Algorithm algo (Algorithm. (m/seq->double-double-array (partition (int w) values))) - steps (s/splice-range (inc contours) (.-min algo) (.-max algo))] + steps (u/slice-range (inc contours) (.-min algo) (.-max algo))] (do-graph chart-data true (doseq [[id p] (map-indexed vector (.buildContours algo (double-array steps))) :let [col (nth palette id)]] diff --git a/src/cljplot/impl/scatter.clj b/src/cljplot/impl/scatter.clj index 59d931f..61fd037 100644 --- a/src/cljplot/impl/scatter.clj +++ b/src/cljplot/impl/scatter.clj @@ -2,6 +2,7 @@ (:require [clojure2d.core :refer :all] [cljplot.common :refer :all] [cljplot.scale :as s] + [cljplot.utils :as u] [fastmath.random :as r] [fastmath.protocols :as pr] [fastmath.core :as m] @@ -91,7 +92,7 @@ (Blur/gaussianBlur g target w h (if (< blur-kernel-size 1.0) (* 0.1 blur-kernel-size (max w h)) blur-kernel-size))) (let [^Algorithm algo (Algorithm. (m/seq->double-double-array (partition (int w) target))) - steps (rest (s/splice-range (inc contours) (.-min algo) (.-max algo)))] + steps (rest (u/slice-range (inc contours) (.-min algo) (.-max algo)))] (do-graph chart-data true (doseq [[id p] (map-indexed vector (.buildContours algo (double-array steps))) :let [col (nth palette id)]] diff --git a/src/cljplot/impl/strips.clj b/src/cljplot/impl/strips.clj index 445e768..f8b83b1 100644 --- a/src/cljplot/impl/strips.clj +++ b/src/cljplot/impl/strips.clj @@ -5,6 +5,7 @@ [clojure2d.core :refer :all] [fastmath.stats :as stats] [fastmath.kernel :as k] + [cljplot.scale.bands :as b] [cljplot.scale :as s] [clojure2d.color :as c] [fastmath.core :as m])) @@ -215,7 +216,7 @@ (defmethod render-graph :bar [_ data {:keys [palette color stroke stroke? padding-in padding-out] :as conf} {:keys [w ^int h x] :as chart-data}] (let [cnt (count data) - bands (s/bands {:padding-out padding-out :padding-in padding-in} cnt) + bands (b/bands {:padding-out padding-out :padding-in padding-in} cnt) scale-x (partial (:scale x) 0 w) ^double zero (scale-x 0) pal (if (seq palette) (cycle palette) (repeat color)) @@ -243,7 +244,7 @@ :or {size 0.3} :as conf} {:keys [^int w ^int h x] :as chart-data}] (let [cnt (count data) - bands (s/bands {:padding-out padding-out :padding-in padding-in} cnt) + bands (b/bands {:padding-out padding-out :padding-in padding-in} cnt) scale-x (partial (:scale x) 0 w) ^double zero (scale-x 0) pal (if (seq palette) (cycle palette) (repeat color)) @@ -269,7 +270,7 @@ (defmethod render-graph :rbar [_ data {:keys [color stroke stroke? padding] :as conf} {:keys [w ^int h x] :as chart-data}] - (let [{:keys [^double start ^double end]} ((s/bands {:padding-out padding} 1) 0) + (let [{:keys [^double start ^double end]} ((b/bands {:padding-out padding} 1) 0) st (* start h) hh (* (- end start) h) scale-x (partial (:scale x) 0 w)] @@ -304,7 +305,7 @@ (defmethod render-graph :sbar [_ {:keys [sum data]} {:keys [method palette stroke stroke? padding] :as conf} {:keys [w ^int h x] :as chart-data}] - (let [{:keys [^double start ^double end]} ((s/bands {:padding-out padding} 1) 0) + (let [{:keys [^double start ^double end]} ((b/bands {:padding-out padding} 1) 0) scale-x (partial (:scale x) 0 w) zero (scale-x 0) pal (cycle palette) diff --git a/src/cljplot/render.clj b/src/cljplot/render.clj index e0a830e..65a6ca7 100644 --- a/src/cljplot/render.clj +++ b/src/cljplot/render.clj @@ -1,5 +1,6 @@ (ns cljplot.render (:require [cljplot.scale :as s] + [cljplot.scale.bands :as b] [cljplot.common :refer :all] [cljplot.axis :as ax] [clojure2d.core :refer :all] @@ -63,8 +64,8 @@ ww (- width l r) hh (- height t b) bands-conf {:padding-in padding-in :padding-out padding-out} - bands-x (bands->positions-size (s/bands cols bands-conf) ww) - bands-y-raw (s/bands (reverse (range rows)) bands-conf) + bands-x (bands->positions-size (b/bands cols bands-conf) ww) + bands-y-raw (b/bands (reverse (range rows)) bands-conf) bands-y (bands->positions-size bands-y-raw hh) scale-x (:x scales) scale-y (:y scales)] diff --git a/src/cljplot/scale.clj b/src/cljplot/scale.clj index d3388da..f52270c 100644 --- a/src/cljplot/scale.clj +++ b/src/cljplot/scale.clj @@ -68,13 +68,14 @@ {:ticks ticks}))) (defn- coerce-format-fn - "Find formating funciton." - [scale ticks fmt] - (cond - (string? fmt) (partial (if (= (:type scale) :time) dt/format format) fmt) - (fn? fmt) fmt - (= (:type scale) :time) (time-format scale ticks) - :else str)) + "Find formatting function." + ([scale fmt] (coerce-format-fn scale nil fmt)) + ([scale ticks fmt] + (cond + (string? fmt) (partial (if (= (:type scale) :time) dt/format format) fmt) + (fn? fmt) fmt + (= (:type scale) :time) (time-format scale ticks) + :else str))) (defn scale-map "Create scale data from definition" diff --git a/src/cljplot/scale/discrete.clj b/src/cljplot/scale/discrete.clj index 9b198d3..fa97d2f 100644 --- a/src/cljplot/scale/discrete.clj +++ b/src/cljplot/scale/discrete.clj @@ -74,7 +74,7 @@ (linear-search r) {:steps steps})))) (defn threshold - "Returns discrete scale for given steps or evenly spliced domain." + "Returns discrete scale for given steps or evenly sliced domain." ([] (threshold-from-steps 10)) ([steps] (if (sequential? steps) (threshold steps 10)