jakub holý

building the right thing, building it right, fast

Creating A Chart With A Logarithmic Axis In Incanter 1.5.1

2013-07-12 18:17:35General

Incanter 1.5.1 doesn't support logarithmic axes, fortunately it is easy to add one manually.

Update: Pushed improved version to Incanter.

This is how our final code will look like:


;; core and charts are the incanter namespaces
(defn plot-power []
  (let [fun #(Math/pow 10 %)
        y-axis (log-axis :label "log(x)")
        chart (charts/function-plot fun 0 5)]
    (set-axis chart :y y-axis)
    (core/view chart :window-title "LogAxis Test: Incanter fun plot")))




And this is the supporting code:


(defn log-axis
" Create a logarithmic axis.

Beware: The data may not contain zero. Otherwise the chart will look rather strange (log doesn't like zeros).

Options: :base (default 10) base of the logarithm; typically 2 or 10 :label (default none) the label of the axis " [& options] (let [opts (when options (apply assoc {} options)) base (or (:base opts) 10) label (:label opts)] (doto (if label (LogAxis. label) (LogAxis.)) (.setBase base) ;; Use normal numbers instead of 10^num, i.e. 1 inst. of 10^0.0 (.setStandardTickUnits (NumberAxis/createIntegerTickUnits)))))

(defmulti set-axis "Set the selected axis of the chart, returning the chart. (Beware: the axis' label will replace the x-label or y-label set previously on the chart.)

Arguments: chart - the JFreeChart object whose axis to change dimension - depends on the plot type, f.ex. :x or :y for an XYPlot axis - the axis to set, an instance of ValueAxis

Examples: (use '(incanter core charts))

(doto (function-plot #(Math/pow 10 %) 0 5) (set-axis :x (log-axis :base 10, :label \"log(x)\")) view) "

(fn [chart dimension axis] (type (.getPlot chart))))

(defmethod set-axis org.jfree.chart.plot.XYPlot ([chart dimension axis] {:pre [(#{:x :y} dimension)]} (let [plot (.getXYPlot chart)] (if (= :x dimension) (.setDomainAxis plot axis) (.setRangeAxis plot axis))) chart))


Admittedly, this is a little overengineered with the multimethod, but there were reasons for it :-).