watch superbowl live

super bowl

SuperBowl

Watch The Superbowl online

Watch The Superbowl online

live superbowl stream

watch superbowl live

watch superbowl online

watch superbowl online

SuperBowl

Simple SparkLine Generator in Clojure 6

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

Comments