Skip to content

Instantly share code, notes, and snippets.

@holyjak
Created November 1, 2018 12:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save holyjak/07adc39c88f99dab27491f636749da53 to your computer and use it in GitHub Desktop.
Save holyjak/07adc39c88f99dab27491f636749da53 to your computer and use it in GitHub Desktop.
Incanter: show bytes as kB/MB/GB on an axis

Modify an axis to display the number of bytes with scale suffixes such as kB, MB, GB, and display more reader-friendly ticks such as "500MB" instead of "496M".

The trick is to supply a custom "tick source" that tells JFreeChart what ticks it should prefer. I cheat a little and reuse the existing IntegerTickUnitSource, optimally I would rewrite it to work with multiples of 2 rather than 10.

(defn byte-scale [num]
(let [k 1024
m (int (Math/pow 1024 2))
g (int (Math/pow 1024 3))]
(condp <= num
g [g "GB"]
m [m "MB"]
k [k "kB"]
[1 ""])))
(defn format-bytes [num]
(let [[scale unit] (byte-scale num)]
[(/ num scale) unit]))
(def byteFmt (let [dec-fmt (java.text.DecimalFormat. "#.#")]
(proxy [java.text.NumberFormat] []
(format [^double number, ^StringBuffer toAppendTo, ^FieldPosition pos]
(let [[n u] (format-bytes number)]
(.append
(.format dec-fmt n toAppendTo pos)
u))))))
(defn nearest-byte-tick
([^double size tick-fn]
(let [[scale] (byte-scale size)]
(NumberTickUnit.
(* scale
;; FIXME if size = 1000 upgrade to 1024
(.getSize
(tick-fn
(NumberTickUnit. (/ size scale)))))
byteFmt))))
(def byte-tick-source
"TickUnitSource suitable for byte values spanning multiple of kB - MB - GB"
;; FIXME Should return 1GB rather than 1000 MB
(let [int-tick-units (NumberAxis/createIntegerTickUnits)]
(reify
TickUnitSource
(^TickUnit getLargerTickUnit [_ ^TickUnit unit]
(nearest-byte-tick
(.getSize unit)
#(.getLargerTickUnit int-tick-units %)))
(^TickUnit getCeilingTickUnit [me ^TickUnit unit]
(.getCeilingTickUnit me (.getSize unit)))
(^TickUnit getCeilingTickUnit [_ ^double size]
(nearest-byte-tick
size
#(.getCeilingTickUnit int-tick-units %))))))
(defn set-bytes-tick-unit [^JFreeChart chart]
(let [^XYPlot plot (.getPlot chart)
^NumberAxis axis (.getRangeAxis plot)]
(.setStandardTickUnits axis byte-tick-source)
chart))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment