mindok / contex

Charting and graphing library for Elixir
https://contex-charts.org/
MIT License
710 stars 56 forks source link

Details not appearing on mouse-hover with PieChart #77

Open APB9785 opened 1 year ago

APB9785 commented 1 year ago

I'm making a PieChart like so

dataset = Contex.Dataset.new(data, ["Name", "Avg Runtime"])

opts = [
  mapping: %{category_col: "Name", value_col: "Avg Runtime"},
  legend_setting: :legend_right,
  data_labels: true,
  title: "System Runtimes"
]

Contex.Plot.new(dataset, Contex.PieChart, 600, 400, opts)

But I'm not getting the Avg Runtime details displaying when the user hovers the mouse over the pie slice. I must be missing an option, but I don't see in the docs a list of the options and their effects. What do I need for on-hover functionality?

If this is a bug or missing feature, let me know - I'm happy to contribute :)

mindok commented 1 year ago

Hi @APB9785 - using the :data_labels option should result in labels being shown regardless of whether you hover over or not. If that's not the case, that's a bug.

For the hover functionality in the bar chart, we use an SVG title element (around line 542 of barchart.ex)- it is pretty much the only way using standard SVG without javascript, but browser implementations are a a bit inconsistent.

I had a quick look at piechart.ex - it looks like the required title element isn't generated (it would be around line 202/203 - within the circle element). It also looks like the data label has hard-coded formatting to round to 2 decimal places (around Line 189 - #{Float.round(value, 2)}%).

What I'd be inclined to do is:

  1. Pull over the value_scale, custom_value_formatter & custom_value_scale handling code from barchart.ex in order to get a consistent and configurable approach to formatting the values (plus update the options part of the docs)
  2. Fix up the data label code to format using the value formatter attached to the scale
  3. Add the title element (to fix the problem you first asked about!)

Happy for you to make the appropriate changes if you would like to. Otherwise, I can look at it over the next 2-3 days.

APB9785 commented 1 year ago

I did take a look at all the code you referenced, but there is a big problem trying to understand what these terms "scale" and "label" are supposed to mean. The ambiguity comes when the slice values are "scaled" according to their percentage, and the percentage is assigned as the "label". This isn't how it works in the bar chart, so I'm not sure how you want to approach that.

mindok commented 1 year ago

Ah - good point. What do you think makes sense for a label on a pie chart. I suspect users would expect percent or value depending on the situation.

What if the options were something like the following if you want "hover" labels for the data:

[label_formatter: &("{Float.round(&1, 2)}")]

and existing labels using percentage would remain:

[data_labels: true]

We could then do away with the custom value scale as we would only be introducing it to carry a formatting function.

I'm not sure if the naming is right.

Alternatively, we take a custom formatter function that takes two arguments - the first is the percentage and the second is the actual value. It is then up to the library user to determine what they want, and it would default to showing the percentage as-is.

e.g.

format_fun = fn percent, value -> "#{Float.round(percent, 2)}% (#{Float.round(value, 3)}) end
[data_labels: false, label_format: format_fun]

Would show something like "12.4% (223.567)" on hover, but not on the label. Setting data_labels: true would display it on the pie wedge too.

[data_labels: false]

Would show "12.4%" on hover, but not without the hover.

[data_labels: true]

Would show "12.4%" on hover, and also on the wedge without the hover.

This approach is a bit different to other chart types, but then pie charts are all about showing proportions rather than absolute values.

Thoughts?

APB9785 commented 1 year ago

It sounds like, with that approach, that [data_labels: true] would show "12.4% (223.567)" on the slice. Is there a way to show something different on-hover than on the label? That seems like it would be optimal. For my use-case, I'd prefer to show something like 223 ms, so that would require a formatter function for sure.

Pie Charts need percentages, but should those percentages take the place of the labels? There's a use-case for displaying those percentages, sure, but I think the raw values are somewhat more important. Ideally, both would be exposed to the user, who can decide what to display on-hover, and what to display as a "label".