How to manipulate legend in Incanter chart

2019-05-06 14:46发布

I'm trying to include a legend in an Incanter chart, but I'm having some troubles getting what I want:

  1. I want to be able to instantiate a chart with no data first (using [] [] as my x y arguments), then add the data points in a separate step. However the only way to add a legend is to specify :legend true after the initial x y points are given in the constructor. Cannot specify :legend true without x y arguments, and I have not found any add-legend function.

  2. The legend option captures the code I use when adding the chart data, which means if I don't want ugly code to appear in the legend I have to create a nice-looking vars for the X and Y points, rather than just calling a function in line.

  3. Therefore the legend that is created includes the [][] used when creating the blank plot, it includes the function calls used when getting the data for the points, and it includes the name-mangled anonymous function (fn*[p1__3813#](second p1__3813#)) which is non-communicative to consumers of my chart.

  4. I just want to be able to associate a string with each group of points in the legend like in matlab, excel, etc.

Here is my current code;

(def lux-ratios-plot
   (doto (scatter-plot [] [] :legend true
                             :title  "Lux/CH0 vs. CH1/CH0"
                             :x-label "CH1/CH0"
                             :y-label "Lux/CH0")
     (view)))

(doseq [dut [incs hals cfls leds]]
  (add-points lux-ratios-plot (get-vals :CH1/CH0 dut) (get-vals :Lux/CH0 dut) :points true))

; Show the trend line for each bulb
(doseq [fit [inc-fit hal-fit cfl-fit led-fit]]
  (add-lines lux-ratios-plot (map #(second %) (:x fit)) (:fitted fit)))

Therefore is there any way in Incanter plots to specify a legend string with each (add-lines ...) or (add-points ...) call?

Thanks a lot

Michael

2条回答
成全新的幸福
2楼-- · 2019-05-06 15:02

Every Incanter chart is also a JFreeChart object. So you could use any of the JFreeChart methods to manipulate your Incanter chart.

For example to remove the legend you can do (.removeLegend lux-ratios-plot). There is also an addLegend method. Haven't tried that one myself. Hope this helps.

查看更多
趁早两清
3楼-- · 2019-05-06 15:09

To associate nice names with series of points, or lines, use the keyword :series-label in the command that adds that data to the chart. For example:

(def c (scatter plot x y :legend true))
(add-lines c x1 y1 :series-label "Primary")
(add-lines c x2 y2 :series-label "Secondary")

This doesn't address the other problem in your question: In order to create a bare scatter plot that has a legend, you have to pass empty data to scatter-plot, i.e. with x and y as empty sequences above, since Incanter doesn't allow you to specify :legend without passing data to scatter-plot. If x and y are empty (e.g. they are nil), the empty data shows up in as an element the legend, too. I don't believe that this problem can be overcome directly currently (version 1.5.7).

One solution is to pass real data in the scatter-plot call, along with a :series-label parameter. However, that may make it more awkward to programmatically generate a scatter plot when the number of datasets is unknown in advance, since you have to treat the first dataset differently than the others.

Another, kludgey solution is this:

(def chart (scatter-plot nil nil :legend true :series-label ""))
(set-stroke-color chart (java.awt.Color. 0 0 0 0) :dataset 0)

Using the empty string as the value of :series-label means that the label in the legend for the first, empty dataset will not display. The set-stroke-color call makes the color of the empty dataset (i.e. dataset 0) transparent. Otherwise, you'll have a red dot for this dataset in your legend. You will have a small empty space in the legend where the red dot and the empty string belong, but that's less confusing than seeing a red dot there.

查看更多
登录 后发表回答