Simple SparkLine Generator in Clojure 8

Posted by jonathan on February 28, 2008

The following is a little SparkLine generator written in the Clojure language.

There’s an example in the code that covers the usage.

Please post a comment if you find it useful, or have suggestions.

I have since updated this program. It should be pixel-perfect, and much more resistant to bad data.

Thanks Rich, for the comment below. I have updated the main function to use destructuring bind on the function parameters.

SparkLine

; Sparkline Generator
; Copyright (c) Jonathan A Watmough. All Rights Reserved.
;
; The use and distribution terms for this software are covered by the
; Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.txt).
; By using this software in any fashion, you are agreeing to be bound by
; the terms of this license. Do not remove this notice.


(defn 
#^{ :doc "Scale a list of numeric 'values' to a max height of 'height'."
    :private true}
      scale-values ([values height]
  (let [highest (apply max (filter identity values))]
    (map #(if % (dec (- height (/ (* % (- height 3)) highest))) nil) values))))


(defn 
#^{:doc "Make a Win-style java.awt.image.BufferedImage of 'width' x 'height'."}
      make-buffered-image ([width height]
  (let [image-type (. java.awt.image.BufferedImage TYPE_3BYTE_BGR)]
    (new java.awt.image.BufferedImage width height image-type))))


(defn 
#^{:doc "Create pixel-accurate sparkline bitmap graphic from {:width :height :values :marker}. :marker=-1 for last entry."}
      make-sparkline ([{ w :width h :height v :values m :marker }]
  (let [v       (scale-values v h)
        bitmap  (make-buffered-image w h)
        g       (. bitmap (getGraphics))
        m       (if (and m (< m 0)) (+ m (count v)) m)
        step    (/ (- w 3) (- (count v) 1))]
    (do (doto g (setColor (. java.awt.Color white))
                (fillRect 0 0 w h)
                (setColor (. java.awt.Color gray)))
        (dotimes idx (count v)
          (let [x-pos    (inc (* idx step))
                prev-val (nth v idx)
                this-val (nth v (inc idx))]
            (when (and prev-val this-val)
                  (. g (drawLine x-pos (dec prev-val) (+ x-pos step) (dec this-val))))))
        ; Draw marker if present and return the sparkline bitmap
        (when (and m (nth v m))
            (let [bx  (* m step)
                  by  (- (nth v m) 2)]
              (doto g (setColor (. java.awt.Color red))
                      (fillOval bx by 2 2))))
        (. g (dispose))
        bitmap))))


(defn 
#^{:doc "Test code for sparklines graphic generator."}
      test-sparklines []
  (let [spark (make-sparkline {:width 100 :height 30 
                              :values [1 2 10 8 2 5 8 12 14 3 4 15]
                              :marker -1
                              })
        icon  (new javax.swing.ImageIcon spark)]
    (doto (new javax.swing.JFrame "Sparkline Test")
      (add (new javax.swing.JLabel icon))
      (pack)
      (setVisible true))))


(test-sparklines)
Trackbacks

Use this link to trackback from your own site.

Comments

Leave a response

  1. Rich Hickey Thu, 28 Feb 2008 14:54:09 UTC

    You might want to try destructuring in let:

    (let [{w :width h :height v :values} data] …

  2. hitesh Fri, 29 Feb 2008 06:43:03 UTC

    Nice. I like the Lispishness of Clojure. It might be something I’d consider if I had to write code running on the JVM.

  3. newlisper Fri, 29 Feb 2008 23:28:10 UTC

    Nice – I’ve only seen a few positive references to Clojure, and it looks fascinating. It’s interesting to see the way you mix Lisp and Java together – even if the class names look a bit scary.

    You might be interested to see the sparkline generator I did. I only saw your version after I did mine, so I may be able to improve my code after seeing yours.

    Will have to look at Clojure soon.

  4. Gavin Wed, 07 Jan 2009 23:21:37 UTC

    Cool. Good to see some well-written example code out there to learn from.

    One thing I noticed is that it was written before the Java interop macros were implemented. You could shorted probably every s-exp containing Java. E.g. (. bitmap (getGraphics)) –> (.getGraphics bitmap)

    Whether it’s worthwhile is up to you.

  5. Aron Sat, 21 Mar 2009 23:11:49 UTC

    Hi. Thanks for writing this sample code. I ran into two problems running sparklines.clj as written (against clojure-20090320).

    1. Calls against Java objects within (doto ..) needed to be .method.
    (setColor …) -> (.setColor …)
    Changed: setColor, fillRect, fillOval, add, pack, setVisible

    2. dotimes takes a vector.
    (dotimes idx (count v) …)
    becomes
    (dotimes [idx (dec (count v))] …)
    The (dec …) was necessary to avoid an out-of-bounds index exception from:
    this-val (nth v (inc idx))
    on the last iteration.

  6. Michael Mellinger Wed, 02 Sep 2009 13:14:59 UTC

    Diff file:
    —————————————-
    30,33c30,33
    < (do (doto g (setColor (. java.awt.Color white))
    < (fillRect 0 0 w h)
    < (setColor (. java.awt.Color gray)))
    (do (doto g (.setColor (. java.awt.Color white))
    > (.fillRect 0 0 w h)
    > (.setColor (. java.awt.Color gray)))
    > (dotimes [idx (dec (count v))]
    43,44c43,44
    < (doto g (setColor (. java.awt.Color red))
    (doto g (.setColor (. java.awt.Color red))
    > (.fillOval bx by 2 2))))
    57,59c57,59
    < (add (new javax.swing.JLabel icon))
    < (pack)
    (.add (new javax.swing.JLabel icon))
    > (.pack)
    > (.setVisible true))))

  7. Der Zahnarzt Ulm - zahnarzt-roemer.de Sat, 06 Jul 2013 15:39:12 UTC

    If some one wants expert view regarding running a blog then i recommend him/her to pay a
    visit this website, Keep up the good job.

  8. Ultimate SEO Coaching Kurs Sun, 21 Jul 2013 07:04:58 UTC

    After I initially left a comment I seem to have
    clicked on the -Notify me when new comments are
    added- checkbox and from now on each time a comment is added I recieve 4 emails with the same comment.
    There has to be an easy method you can remove
    me from that service? Thanks!

    Here is my web blog; Ultimate SEO Coaching Kurs

Comments