generateme / cljplot

JVM Clojure charting library
Eclipse Public License 2.0
152 stars 7 forks source link

Way to bypass clojure2d's rect? #17

Open joinr opened 5 years ago

joinr commented 5 years ago

I'm working on a treemap renderer using the squarify algorithm. Got everything working....up to the point where I'm rendering the laid out rectangles. I opted to just use a simple variation of the scatter plot backend. Assumming the data is a sequence of [x y w h] defining the rectangles, it seemed straightforward to render rectangles by swapping out the drawing primitive with rect.

(defmethod render-graph :tree-map [_ data {:keys [color stroke size shape] :as conf}
                                   {:keys [w h x y] :as chart-data}]
  (let [scale-x (partial (:scale x) 0 w)
        scale-y (partial (:scale y) 0 h)]
    (do-graph chart-data :highest 
      (let [coords (mapv (fn [[x y w h]]
                           (into (transform c (scale-x x) (scale-y y))
                                 [w h])) data)]
        (reset-matrix c) ;;c is an implicit arg for the canvas
        (doseq [[v [tx ty w h]] (map vector data coords)
                ;:let [local-stroke (update stroke :size (:size stroke) v conf)]
                ]
          (filled-with-stroke c :white :black rect tx ty w h)
          )))))

Except now my rectangles are rendering ignoring orientation (which from my reading of do-graph, shouldn't be possible since it orients the canvas c for you).

Simple example

(-> (b/series [:grid]
      [:tree-map [[0 0 100 100] [100 100 100 100]]])
      (b/preprocess-series)
      (b/add-axes  :bottom)
      (b/add-axes  :left)                      
      (r/render-lattice {:width 1000 :height 1000})
      (show))

results in this We "Should" see two white squares with black strokes, one at the origin, with an area of 100. A second one should be at the point 100 100 (diagonal, upper right, adjacent).

I tried to conform to what I've seen in the other implementations, namely render-shape. What am I missing?

joinr commented 5 years ago

If I create a custom data extent ala

(defmethod data-extent :tree-map [_ data _]
  (let [[xmin xmax ymin ymax]
        (reduce (fn [[xmin xmax ymin ymax] [x y w h]]
                  [(min xmin x (+ x w))
                   (max xmax x (+ x w))
                   (min ymin y (+ y h))
                   (max ymax y (+ y h))])
                [0 0 0 0]
                data)]
    {:x [:numerical [xmin xmax]]
     :y [:numerical [ymin ymax]]}))

We get closer here in that the extents are correctly computed from the data.

joinr commented 5 years ago

Been banging on this for a while, even dropped down to java2d and messed with the graphics2d layer directly just to see where cljplot thinks [0 0] is relative to the plot's origin (I guess anchor)....Something is going on with the transforms that are totally non-obvious to me. In theory, I should be able to change the visual marks for the points with rectangles, but even trivial examples are showing this is not so (at least with my attempts), even with squares.

joinr commented 5 years ago

eliding the calls to transform present in the scatter plot implementation seems to work:

(defmethod render-graph :tree-map [_ data {:keys [color stroke size shape] :as conf}
                                   {:keys [w h x y] :as chart-data}]
  (let [scale-x (partial (:scale x) 0 w)
        scale-y (partial (:scale y) 0 h)]
    (do-graph chart-data false 
      (let [coords (mapv (fn [[x y w h]]
                           [(scale-x x) (scale-y y)
                            (scale-x w) (scale-y  h)]) data)]
        (doseq [[x y w h]  coords
                ;:let [local-stroke (update stroke :size (:size stroke) v conf)]
                ]
          (filled-with-stroke c :white :black rect x y  w h))))))

Correct visuals here

Why then do we need transform at all for the scatter plot, when scaling will suffice here?

joinr commented 5 years ago

Initial results (lacking labels) here

genmeblog commented 5 years ago

Without transform in scatter plot all marks are oriented too. For example letters and triangular marks would be messed up.