geom
geom copied to clipboard
Bar plots can't be drawn with a negative y-axis
There is bit of a weird limitation with the bar plots. The bars are at the moment drawn with respect to the first value in the domain - but this causes some usability issues
If you have bar plots that have mostly negative values - for instance:
(let [left-margin 50
width 720
height 180]
(->> {:x-axis (linear-axis
{:domain [0 5]
:range [left-margin width]
:pos (/ height 2)})
:y-axis (linear-axis
{:domain [0 10] ;; the first values in effect sets the bar's `zero`
:range [(/ height
2.0)
0]
:major 1
:pos (+ left-margin 0)})
:data [{:values [[1 4] [2 -6] [3 -3] [4 2]]
:attribs {:fill "none" :stroke "#0af" :stroke-width (/ width 6)}
:layout svg-bar-plot}]}
(svg-plot2d-cartesian)
(svg {:width width :height height })
(serialize)
(spit "normal-bar-plot.svg")))
Adding a Y axis that spans the full range is impossible b/c the domain range must start with a zero (otherwise the zero point of the bar will be some negative value)
.An alternative that almost works - that will give you just a negative Y axis - is to give it a decreasing :domain
and a modified :range
(let [left-margin 50
width 720
height 180]
(->> {:x-axis (linear-axis
{:domain [0 5]
:range [left-margin width]
:label-style {:fill "none"}
:pos (/ height 2)})
:y-axis (linear-axis
{:domain [0 -10] ;; the first values in effect sets the bar's `zero`
:range [(/ height
2.0)
height ]
:major 1
:pos (+ left-margin 0)})
:data [{:values [[1 4] [2 -6] [3 -3] [4 2] ]
:attribs {:fill "none" :stroke "#0af" :stroke-width (/ width 6)}
:layout svg-bar-plot}]}
(svg-plot2d-cartesian)
(svg {:width width :height height })
(serialize)
(spit "negative-bar-plot.svg")))
This however clobbers the axis labels.
It looks like an issue in thi.ng.geom.viz.core/lin-tick-marks
I tried changing the code to look like
(defn lin-tick-marks
[[d1 d2] delta]
(if (m/delta= delta 0.0 m/*eps*)
'()
(let [dr (- d2 d1)
d1' (m/roundto d1 delta)]
(filter #(m/in-range? d1 d2 %) (range d1' (+ d2 delta) (if (< d1 d2) delta (- delta)))))))
(b/c if the first argument to range
is smaller than the second, then the incrementor need to be negative)
However this didn't seem to fix the issue. My guess is that thi.ng.math.core/in-range?
isn't meant to handle d2 > d1
. I didn't want to go deeper and change things in math.core
b/c it might break something else in the larger project
In any case, maybe decreasing domain ranges shouldn't be supported :)
Ideally some alternate solution would allow the axis to go from negative to positive in whatever domain the user wants (by setting some sort of :zero-point
for the bar plots maybe?).