A simple plotter for clojure
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
doc
src/simple_plotter
test/simple_plotter
.gitignore
README.md
examples.clj
project.clj

README.md

simple-plotter

An attempt to make plotting as easy on a modern computer running clojure as it used to be on a ZX Spectrum.

See my original blogpost about simple plotter: http://www.learningclojure.com/2010/09/graphics-like-its-1979-how-to-get.html

Or the original rant: http://johnlawrenceaspden.blogspot.co.uk/2009/11/behold-in-its-full-glory-program-that-i.html

Usage

;; The classic ZX Spectrum sine drawing program

(use 'simple-plotter.core)
(create-window "ZX Graphics" 256 176)

;; 10 FOR X = 1 TO 255
;; 20 PLOT X, 88+80*SIN(X/128*PI)
;; 30 NEXT X

(doseq [x (range 256)]
  (plot x (+ 88 (* 80 (Math/sin (* Math/PI (/ x 128)))))))

;; Hey, let's have some axes as well

;; 40 INK 6
;; 50 PLOT 0,88: DRAW 255,0
;; 60 PLOT 127,0: DRAW 0,168

(ink gray)
(plot 0 88) (draw 255 0)
(plot 127 0) (draw 0 175)

Let us concede that having more pixels on a modern screen is a good thing:

(use 'simple-plotter.core)

(create-window "sine")

;; sine graph
(doseq [x (range 1024)]
  (plot x (+ 384 (* 376 (Math/sin (* Math/PI (/ x 512)))))))

;; axes
(ink yellow)
(plot 0 384) (draw 1024 0)
(line 512 0 512 1024)

Scaling things is a pain. You can get the plotter to do all the scaling and axis stuff for you, and you can use draw-to to get lines rather than points:

(use 'simple-plotter.core)

(create-window "sine in sane coords" 200 100 black white -7.0 7.0 -1.0 1.0)
(plot -7 0)
(doseq [x (range -7 7 0.01)]
  (draw-to x (Math/sin (* Math/PI x))))

;; axes
(ink lightgray)
(axes)

Here is Barnsley's famous Fractal Fern, generated by an iterated function system.

(use 'simple-plotter.core)

(defn transform [[xx xy yx yy dx dy]]
  (fn [[x y]] [(+ (* xx x) (* xy y) dx)
               (+ (* yx x) (* yy y) dy)]))

(def barnsleys-fern '((2  [  0    0     0     0.16 0 0    ])
                      (6  [  0.2 -0.26  0.23  0.22 0 0    ])
                      (7  [ -0.15 0.28  0.26  0.24 0 0.44 ])
                      (85 [  0.85 0.04 -0.004 0.85 0 1.6  ])))

(defn iteration [transforms]
  (let [transform-list (mapcat (fn [[n t]] (repeat n (transform t))) transforms)]
    (fn [x] ((rand-nth transform-list) x))))

(def barnsley-points (iterate (iteration barnsleys-fern) [0 1]))

(create-window "Barnsley's Fern" 350 450)

(ink green)
(scaled-scatter-plot (take 10000 barnsley-points) 50 300 50 400 100)

It's conceivable that a man might want two different windows on the go at once:

(use 'simple-plotter.core)

(defn draw-grid [step]
  (let [h (get-original-height) w (get-original-width)]
    (doseq [i (range 0 w step)]
      (plot i 0) (draw 0 h))
    (doseq [i (range 0 h step)]
      (line 0 i w i))))

(defn draw-grids [n colors]
  (when (and (<= n (get-original-width)) (seq colors))
    (ink (first colors))
    (draw-grid n)
    (recur (* n 2) (rest colors))))

(def g1 (create-window "grid1" 300 400))
(def g2 (create-window "grid2" 300 400))

(window! g1)
(draw-grids 2 (list red yellow green))

(window! g2)
(draw-grids 2 (repeat white))

(window! g1)
(ink blue)
(draw-grid 16)

I have absolutely no idea why I wrote this program. Presumably it demonstrates some terribly important aspect of simple-plotter, but I am damned if I can see what.

(use 'simple-plotter.core)

(def tinyrange '(1
                 1/10000000000 
                 1/100000000000000000000000 
                 1/100000000000000000000000000000000000000000000000
                 0.1 
                 0.00000000000000000000000001
                 0.000000000000000000000000000000000000000000000001))



(for [tiny tinyrange]
  (let [xcoords (range (- tiny) tiny (/ tiny 100))
        ycoords (map #(* tiny (Math/sin (* Math/PI (/ % tiny)))) xcoords)
        pairs (partition 2 (interleave xcoords ycoords))]

    (create-window (str "minute scales:" tiny) 400 300 white black  (- tiny) tiny (- tiny) tiny)
    (axes)
    (doseq [[x y] pairs] (draw-to x y))))

License

Copyright © 2013 John Lawrence Aspden

Distributed under the Eclipse Public License, the same as Clojure.