Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Template strings in hover data #3007

Closed
chriddyp opened this issue Sep 13, 2018 · 18 comments
Closed

Template strings in hover data #3007

chriddyp opened this issue Sep 13, 2018 · 18 comments
Assignees
Labels
feature something new

Comments

@chriddyp
Copy link
Member

This could include both attributes that exist in the trace

trace.hovertemplate = '{text}<br>{marker.size} Items<br>{y} Dollars'

But also data that is computed on-the-fly by plotly.js, like the bin widths:

trace.hovertemplate = 'The number of people between the age of {binleft} and {binright} is {bintotal}.'

This means you could express the existing box and violin text with some type of hovertemplate

This could span across traces, like the hover data on stacked bars

trace.template = 'This represents {trace.y} out of {data.total}'

Or one day, perhaps even trace level computations, like the sum of the area

texttemplate = 'The sum of the money is {trace.sum}'
@chriddyp
Copy link
Member Author

I believe this ties in to the parcoords PR, in customizing the different types of computed data to display (cc @jonmmease)

@etpinard etpinard added the feature something new label Sep 13, 2018
@etpinard
Copy link
Contributor

Very related to #1919 (more precisely https://github.com/plotly/plotly.js/pull/1919/files#r130172295), where Ricky added nameformat to allow groupby trace to be names via templates.

The syntax uses %{} to denote values, so we would have:

trace.hovertemplate = '%{text}<br>%{marker.size} Items<br>%{y} Dollars'

@nicolaskruchten
Copy link
Contributor

In terms of the types of output that would be permitted by this, here's an example:

image

@nicolaskruchten
Copy link
Contributor

Note that we'll likely need to bake in some kind of printf-style number formatting here as well to control precision, separators etc.

@nicolaskruchten
Copy link
Contributor

Here's how Highcharts does it:

tooltip: {
        pointFormat: '<b>${point.y:,.2f}</b> USD'
    },

@etpinard
Copy link
Contributor

Ha poor Highcharts. Using ${} must lead to 🤕 for people using ES6 template strings.

@nicolaskruchten
Copy link
Contributor

;) I was mostly pointing at the way they encode separators and precision

@alexcjohnson
Copy link
Collaborator

the way they encode separators and precision

Right, that's essentially the same sprintf model that python uses, and that we pulled from d3 and already use for various other contexts

'Sets the tick label formatting rule using d3 formatting mini-languages',
'which are very similar to those in Python. For numbers, see:',
'https://github.com/d3/d3-format/blob/master/README.md#locale_format',
'And for dates see:',
'https://github.com/d3/d3-time-format/blob/master/README.md#locale_format',
'We add one item to d3\'s date formatter: *%{n}f* for fractional seconds',
'with n digits. For example, *2016-10-13 09:15:23.456* with tickformat',
'*%H~%M~%S.%2f* would display *09~15~23.46*'

@antoinerg antoinerg self-assigned this Oct 4, 2018
@antoinerg
Copy link
Contributor

Should I go ahead and do as Highcharts does: if a variable name is followed by a semicolon, use the remainder as the d3 format string?

${variable_name:d3_format_string}

@nicolaskruchten @etpinard @chriddyp @alexcjohnson

@etpinard
Copy link
Contributor

etpinard commented Oct 5, 2018

Should I go ahead and do as Highcharts does

Please don't! We should use the same syntax as in #1919

@etpinard
Copy link
Contributor

etpinard commented Oct 5, 2018

i.e. %{} not ${} which conflicts with es6 template strings.

@nicolaskruchten
Copy link
Contributor

... but the idea of : then formatting-language sounds fine to me :)

@nicolaskruchten
Copy link
Contributor

Re the syntax of the variable names, the original issue description contains both y and trace.y ... should we always use trace.<whatever> for all trace values, so that we can leave the door open to computed values namespaced under data.total or computed.binleft or whatever?

@etpinard
Copy link
Contributor

etpinard commented Oct 5, 2018

I'd vote staying "in-trace" e.g. using y not trace.y. If users want to compute cross-trace total or other statistics, they could fill those in customdata combined with a template string of e.g %{customdata.total}

@nicolaskruchten
Copy link
Contributor

Oh i meant for stuff that plotly computes... like binleft/binright/total (for stacked bars) etc

@etpinard
Copy link
Contributor

etpinard commented Oct 5, 2018

. like binleft/binright/total (for stacked bars) etc

That would imply exposing some our internal API (mostly from gd.calcdata) to users, which probably isn't a bad idea, but making that robust will require a pretty big effort.

Other example of "computed" values, box q1, median, q3, histogram "heights". Violin kde is a funny one, as its hover value, isn't even stored in gd.calcdata, it is computed on hover.

@nicolaskruchten
Copy link
Contributor

right, but right now those make their way into hovertext, so it would be nice to be able to replicate the current hovertext using the new language... i.e. if you like the 'median' but you want to change the way that number is displayed?

@alexcjohnson
Copy link
Collaborator

Lets just insert these values - per trace type - into the same namespace as the regular trace attributes, and deal with combining the two in the respective hover routines. We don't want to use the same clipped names as in calcdata and anyway, as @etpinard points out, that's not even complete. We can describe these options in attributes.hovertemplate.description for each type, like "You can refer to any trace attribute, and if that attribute is an array we pick out the value being hovered on. In addition, box traces support calculated attributes min, lowerfence, q1, median, mean, stddev, q3, upperfence, and max"

Box and violin have an extra challenge though: this syntax assumes there's only one kind of hover label for a trace. When you have separate labels for each level of the box, each one could in principle get its own formatting. What if you think min and max are obvious so you want only the numbers there, and for quartiles you want %{q1} (25%) and %{q3} (75%)? Do we need to make a separate template attribute for each of these (hovertemplates: {q1: '...', q3: '...', ...}?)
Also an issue for finance types using #2959, and scatter types with hoveron: 'points+fills'.

And one more question: currently the hover label formatting can depend on hover mode and occasionally on other traces that also generate hover data. So in "compare" mode normally you only get y data in each trace hover label, and x data sits in the "common label" on the x axis. But in "closest" mode both x and y are in the trace hover label and there is no common label. Occasionally other traces influence this, like if in compare mode if you make two hover labels but they don't quite share the same x, you may get a common label, and only y data in labels for traces that match the common label, but traces that don't match (but are still close enough to generate a hover label) will get both x and y in their labels. So do we just ignore this distinction when there's an explicit hovertemplate? Or do we accept two variants of the template somehow? I guess I'm leaning toward ignore but we should be clear about it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature something new
Projects
None yet
Development

No branches or pull requests

5 participants