Skip to content

Bar plots can't be drawn with a negative y-axis #87

@kxygk

Description

@kxygk

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

normal-bar-plot

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

negative-bar-plot

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions