Creating A Chart With A Logarithmic Axis In Incanter 1.5.1

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)
      (.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.)

    chart - the JFreeChart object whose axis to change
    dimension - depends on the plot type, f.ex. 😡 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 😡 (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 (= 😡 dimension)
         (.setDomainAxis plot axis)
         (.setRangeAxis plot axis)))

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


Published by Jakub Holý

I’m a JVM-based developer since 2005, consultant, and occasionally a project manager, working currently with Iterate AS in Norway.