Skip to content

li-yiyang/gurafu

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

46 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

GURAFU

About

GURAFU (グラフ) is a plotting lib for Common Lisp. (though it’s still work in progress…)

GURAFU learnt a lot from CLIM (McCLIM) and SCIGRAPH, though, I hop GURAFU would not be too complex.

Installation

You should clone the following repos to your lisp load path (for example: ~/quicklisp/local-projects):

  • cl-bdf: used in opticl backend for BDF font support

How to Use

NOTE: Right now the documentation is poor. Hidden bugs are possible… But these should be at least functionable.

I will have to slow down the developing speed… Clean the code, write some docs. But every time when I have to refer to Mathematica’s Plot, or Python’s matplotlib, I shall consider adding similar functionality into GURAFU.

You could just try:

(in-package :gurafu)

(with-present-to-file
    (plot plot :margin 10)
    (out-path :width 400 :height 400)
  (add-plot-data plot
      (line-plot-pane sin :color +yellow+)
    (loop for x from -10.0 upto 10.0 by 0.1
          collect (list x (sin x))))
  (add-plot-data plot
      (line-plot-pane cos :color +green+)
    (loop for x from -10.0 upto 10.0 by 0.1
          collect (list x (cos x)))))

out-path

You could see the result as below:

./demo-img/first-usable-plot-sin-cos-demo.png

Also, you may try some more plot pane types:

  • histogram-pane:
    (in-package :gurafu)
    
    (with-present-to-file
        (plot plot :margin 10)
        (out-path :width 400 :height 400)
      (add-plot-data plot
          (histogram-pane sin :color +莲红+)
        (with-open-file (dat dat-path)
          (loop for line = (read-line dat nil nil)
                while line
                collect (parse-integer line)))))
    
    out-path
        

    ./demo-img/histogram-pane-demo.png

    Note: the demo-dat/hist.txt is generated by following Mathematica code: Round[100*#] & /@ RandomVariate[NormalDistribution[], 1000].

  • 2d-grid-pane:
    (in-package :gurafu)
    
    (with-present-to-file
        (plot plot :margin 20)
        (out-path :width 400 :height 400)
      (add-plot-data plot
          (2d-grid-pane grid :color (make-linear-color-mapper +white+ +银红+))
        (loop for y from -10 upto 10 by 0.5
              collect (loop for x from -10 upto 10 by 0.5
                            collect (sin (sqrt (+ (* x x) (* y y)))))))
      (set-xy-bounding-box plot -10.0 10.0 -10.0 10.0))
    
    out-path
        

    ./demo-img/2d-grid-pane-demo.png

  • 2d-histogram-pane
    (in-package :gurafu)
    
    (with-present-to-file
        (plot plot :margin 20)
        (out-path :width 400 :height 400)
      (add-plot-data plot
          (2d-histogram-pane arc :color (make-linear-color-mapper +white+ +翠蓝+))
        (loop for i below 10000
              for r = (+ 0.5 (random 0.5))
              for theta = (* 2 pi (1- (random 2.0)))
              collect (list (* r (cos theta)) (* r (sin theta)))))
      (set-xy-bounding-box plot -1.0 1.0 -1.0 1.0))
    
    out-path
        

    ./demo-img/2d-histogram-pane-demo.png

    NOTE: the color map function is quite plain, I need to make this more easier to use…

  • scatter-pane
    (in-package :gurafu)
    
    (with-present-to-file
        (plot plot :margin 20)
        (out-path :width 400 :height 400)
      (add-plot-data plot
          (scatter-pane pesudo-data :point-style :cross
                                    :point-size 4
                                    :color +鹅黄+)
        (loop for x from -2 upto 2 by 0.1
              for delta-x = (- 0.2 (random 0.4))
              for delta-y = (- 0.8 (random 1.6))
              collect (list (+ x delta-x) (+ (* x x) delta-y))))
      (add-plot-data plot
          (line-plot-pane fit :color +大红+)
        (loop for x from -2 upto 2 by 0.01
              collect (list x (* x x))))
      (set-xy-bounding-box plot -2 2 -0.5 5))
    
    out-path
        

    ./demo-img/scatter-pane-demo.png

Work in Progress

Here are some little developing memos about GURAFU:

  • GURAFU should be device independent. It should support different backends.

    Although currently backend output only opticl is done…

  • opticl backend use BDF font (UNIFONT) for draw-char!
  • better color map function
  • more graph styles
  • make GURAFU more easy to use
  • get it a good documentation

Naming Conventions

  • GURAFU class slot variables should be prefixed with %, for example %backend, %width, %height;
  • GURAFU low-level operation methods should be postfixed with !, for example draw-text!, draw-line!;
  • GURAFU constants should be wrapped with +, for example +white+, +black+;
  • GURAFU global variables should be wrapped with *, for example *foreground-color*, *background-color*;

Historical Codes

This codes maybe outdated, so may not work. Or these codes need some patches to make it work, so may not recommanded.

I should update them later:

Right now it’s quite mass… though you could load gurafu/core and then switch into gurafu/core package, and try the following code:

(define-presentation labeled-point ()
  ((label :initform "" :initarg :label)
   (style :initform :dot :initarg :point-style))
  (:draw
   (%uv-left %uv-top style label)
   (draw-point self 0 0 :point-style style :pen-width 5)
   (draw-text  self 0 16 label :font-size 16 :text-align :center)))

(defun present-labled-point (label x y style)
  (present (make-instance 'labeled-point
                          :label label :left x :top y
                          :point-style style)))

(let* ((*default-backend* (make-backend :opticl :width 200 :height 200))
       (patterns '(("DOT" :dot)
                   ("CIRCLE" :circle)
                   ("PLUS" :plus)
                   ("BOX"  :box)
                   ("CROSS" :cross)
                   ("TRIANGLE" :triangle))))
  (loop for col below 2 do
    (loop for row below 3 do
      (destructuring-bind (label style)
          (pop patterns)
        (present-labled-point
         label (* 60 (1+ col)) (* 50 (1+ row)) style))))
  (output! *default-backend* "/path/to/demo-img/first-usable-demo.png"))

You could see the result as below:

./demo-img/first-usable-demo.png

I add some Chinese traditional colors in 《天宫开物》 (according to 《染作江南春水色》), you could see as below:

(define-presentation color-box-present (base-presentation
                                        margined-mixin)
  ((%color :initform *foreground-color*
           :initarg :color)
   (%label-color :initform *foreground-color*
                 :initarg :label-color)
   (%label :initform ""
           :initarg :label))
  (:draw (%color %label %label-color)
         (draw-rect self 0.0 1.0 1.0 0.0                      
                    :color %color
                    :fill? t
                    :fill-color %color)
         (draw-text self 0.5 0.5 %label
                    :color %label-color
                    :text-align :centered
                    :line-width (stream-box-width self)))
  (:documentation
   "Present a color box. "))

(defun map-present-list (list map-fn &optional (layout :horizontal))
  (if (listp list)
      (let ((layout (ecase layout
                      (:horizontal (make-instance 'horizontal-layout-presentation))
                      (:vertical   (make-instance 'vertical-layout-presentation))))
            (child-layout (if (eq layout :horizontal) :vertical :horizontal)))
        (loop with weight = (/ 1.0 (length list))
              for elem in list              
              do (add-component layout
                                (gensym "LIST")
                                (map-present-list elem map-fn child-layout)
                                weight)
              finally (return layout)))
      (funcall map-fn list)))

(with-present-to-file
    (plot base-presentation)
    (out-path :width 800 :height 800)
  (setf plot (map-present-list
              '((+大红+ +莲红+ +桃红+ +银红+)
                (+水红+ +木红+ +鹅黄+ +紫+)
                (+天青+ +葡萄青+ +蛋青+ +翠蓝+)
                (+天蓝+ +月白+ +草白+ +毛青+)
                (+大红官绿+ +豆绿+ +油绿+ +藕色+)
                (+茶褐+ +包头青+))
              (lambda (color-name)
                (make-instance 'color-box-present
                               :label-color +white+
                               :margin 5
                               :label (format nil "~a" color-name)
                               :color (symbol-value color-name)))))
  (set-stream-bounding-box plot 0 800 800 0))

out-path

./demo-img/tiangongkaiwu-colors-demo.png

About

GURAFU is a plotting libaray.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published