Open chriddyp opened 7 years ago
I haven't thought about the attribute specs that much yet. One way to get some of these interactions would be through a :hover
suffix like in CSS:
{
marker: {
color: "blue",
"color:hover": "orange",
"color:click": "green",
"color:selected": "purple",
"color:unselected": "grey"
}
}
That doesn't cover the case for drawing a vertical or horizontal line over points.
With custom hover attributes, perhaps users could create their tooltips by using a combination of annotations, shapes, and images that are triggered on and off through custom hover
styles.
cc @charleyferrari who might have some additional examples too
Example from @cpsievert 's work. In this case, highlighting across subplots. That type of linking hover across traces might be out of the scope of this.
Indeed a solution for this would be useful (needed) for the crossfilter as we discussed in https://github.com/plotly/plotly.js/issues/1762
WARNING: totally my personal ramblings and biases only; in part informed by the crossfiltered dashboard work:
If possible, it'd be great to separate the activating affordances (e.g. Click, Hover, Selection, or crossfiltering some points away from another plot) from the specific temporary restyling ie. visual channel updates, as it may depend, as @chriddyp you write, on the intent such as clicking could indicate various intents, e.g. drilling down, including/excluding from filter, showing atomic data for point or jumping to an external link. A dashboard may have various inputs external to the plotly widgets or concepts, e.g. streaming stock prices would highlight the ticker (and time series line) of the last traded stock, or a UI tour or storytelling, so it might be beneficial to make these work and be assignable depending on how the context requires it.
Having made this separation, I think the affordances part is trivial as these plotly.js
events mostly exist or can be extended. So the task is reduced to applying arbitrary styling changes. This is the harder part:
plotly.js
APIOne option is to simply call Plotly.restyle
and/or Plotly.relayout
- which has the following issues:
restyle
and relayout
calls; currently can't be batchedPlotly.newPlot
pretty much throws out everything so it's not fast either, and resets user selections or other user navigated state (zoom, pan etc.)plotly.js
-style column array updates are great when only one thing changes, but (I think) it's not possible to update one or a few points out of eg. 1000 data points, and even if we make such an API, making it faster than a full vector update is still a challenge.It's a quick win b/c the desired effect can be achieved (limited only by the standard), and no code change is needed. It can be made as fast as the DOM allows. Yet it has some drawbacks:
plotly.js
scenegraph, e.g. structuring, classnames etc. may changeplotly.js
ie. not part of a 'contract' with the userYet I think it's an attractive direction as
Maybe @etpinard @alexcjohnson @chriddyp @jackparmer @cpsievert @rreusser @charleyferrari or someone else perhaps has clearer views than I. One option is to provide preconceived restyles (e.g. 'increase salience' - 'decrease salience' etc). Another option could be to somehow open up and declaratively expose the scene graph and commit to class names and using / not using certain CSS styles on certain elements - sounds very laborious.
Recalculate data and update the DOM for only what's needed. E.g. move the sliders under Model tweaks
or Layout tweaks
in this older experiment
Vega is also using reactive streams for much the same purpose. There are very nice papers and videos that describe it, e.g. this one from Arvind Satyanarayan, Ryan Russell, Jane Hoffswell and Jeffrey Heer - thanks Arvind for reminding me of this paper recently.
We've started to use a similar solution with the crossfilter
work but as it uses plotly.js
charts it won't make those faster. For this reason, there's a user exit
facility (SAP terminology which is a huge standard system that needs highly client dependent extensions) that'd allow custom styling and even support for adding and updating non-plotly.js
plots.
react
and redux
Despite the name, react
is not reactive in itself. It can be made reactive, but even then, by its nature, it still regenerates the entire scene graph (as virtual DOM) and does a lot of DOM diffing even where these won't lead to an update. There are some solutions e.g. using immutability and identity equality for shouldComponentUpdate
checks but using an immutable library for our rather large JSON specs (incl. data) and more importantly, the large amounts of scenegraph data generated, is quite expensive too. Caching vdom fragments (subtrees) is also a possibility to reduce vdom tree construction. It could work but it has speed limits.
A more serious limitation with redux
from a viewpoint of continuous interactions - it's great with predictable changes to an essentially global object, yet due to its conventions (e.g. using strings for dispatching actions), best practices eg. immutability, and our need to perform cascading changes, it gets expensive fast. Basically, each mouse move would rebuild the entire dashboard state. For this reason, redux
isn't often used for high-frequency interactions, and a half-solution won't be a solution. I wrote on this in more detail in the last three paragraphs of this and here and here so it deff. makes me an FRP fanboy; glad to learn about other approaches though.
There are some attempts to solve the core issue with redux
involved, e.g. reselect and various caching approaches which might have some memory leak risks. Btw. redux
can be combined with reactive data streams / FRP just fine, so having redux
for overall app state while doing data updates and user interactions via FRP is OK but redux
doesn't add much for the interactivity / 60FPS update aspect so it's not relevant for this discussion.
With custom hover attributes, perhaps users could create their tooltips by using a combination of annotations, shapes, and images that are triggered on and off through custom hover styles.
That sounds painful. We could do better.
We could maybe attach method
and args
attributes to traces similar to updatemenus
buttons and slider
steps which act as a callback on hover and/or click. For example,
Plotly.newPlot('graph', [{
mode: 'markers',
x: [1, 2, 3],
y: [2, 1, 2],
marker: {
color: 'red'
},
interaction: {
type: 'hover', // or 'click' or 'select'
method: 'restyle',
args: ['marker.color', 'blue']
}
}])
I think we should merge this ticket with https://github.com/plotly/plotly.js/issues/1762
Any objections @monfera ?
@etpinard yes I'll close #1762 as this one pretty much supersedes that
https://github.com/plotly/plotly.js/issues/1943 is now closed but its comments are pertinent to this discussion.
I'd love to be able to set the color of an individual bar or scatter point on hover.
For example, in a monotone chart like this:
I'd love to set the hover color of a bar to an accent color like pink.
In Dash, I'd like mode
to a style customizable under the selected
property so that you can set mode: 'markers+text'
while selecting but keep it as markers
when unselected. We used to achieve this just by plotting a new trace on top of it.
mode
is going to be tough, because it changes what objects need to be created, not just how those objects are styled, so it would need to be a much slower update pathway. Would it work to give unselected text a transparent font color?
Would it work to give unselected text a transparent font color?
That works, thanks!
Are there any examples of highlighting a trace upon hover in plotly for python? Or has this functionality not been added to python yet?
Any chance there's a pending update with some of these improvements? :)
how to implement this one
In addition, there are a few other default style changes for clickable points (this could be a separate issue):
Modify the hover interaction of the point to make it seem more "clickable": adding cursor: pointer and making the point a little bit larger
Is this possible? I have markers that open a modal when clicked, but it isn't clear to the user that they are clickable. I'm trying to figure out how to get the cursor to change to a hand pointer e.g. cursor: pointer when hovering over the marker. I am using react
Would love to know how I can help. Is this under active development?
Hi Sebastian,
We have a fairly well developed code for analyzing data from our experiments. Each experiment lasts just less than 1 second, then we have a 15 minutes down time where our power supplies are re-charged, during this down time we have to analyze data, and based on that analysis make some changes before the next experiment.
This data visualization tool which we have developed is under active development.
For our purposes we have a single large app with several pages (the management is quite easy as there is little communication between pages).
Attached is an example of a feature which we often use in various different pages. As this isn’t a multi-page app I haven’t got some of the triggering to work correctly, so if you to start click “>” the app will start. In the app there are two graphs:
All of this code is functional and working, but if the interactive_graph has a lot of data it can take a long time to re-plot (which is unnecessary). It is also quite cumbersome – needing several callbacks which have to be modified every time we use this feature. We also have to do the placement to the next and back buttons which is a bit annoying.
What we would ideally like is for a trigger to come from the client side which tells us to re-plot graph2.
Do we have a time which we can talk tomorrow?
Thanks, Peter
From: Sebastian Heyneman notifications@github.com Sent: 13 June 2020 22:51 To: plotly/plotly.js plotly.js@noreply.github.com Cc: Peter Buxton peter.buxton@tokamakenergy.co.uk; Manual manual@noreply.github.com Subject: Re: [plotly/plotly.js] Customized Click, Hover, and Selection Styles or Traces (#1847)
Would love to know how I can help. Is this under active development?
— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHubhttps://github.com/plotly/plotly.js/issues/1847#issuecomment-643682784, or unsubscribehttps://github.com/notifications/unsubscribe-auth/ABFSBRE4A53L25SBLW7IKQ3RWPYELANCNFSM4DRWINVQ.
In addition, there are a few other default style changes for clickable points (this could be a separate issue): Modify the hover interaction of the point to make it seem more "clickable": adding cursor: pointer and making the point a little bit larger
Is this possible? I have markers that open a modal when clicked, but it isn't clear to the user that they are clickable. I'm trying to figure out how to get the cursor to change to a hand pointer e.g. cursor: pointer when hovering over the marker. I am using react
I am trying to figure this out. I'd like to update modal popup based on scatter mapbox marker click event data. How did you do it?
html.Div([
dbc.Modal(
[
dbc.ModalHeader("Lease Information"),
dbc.ModalBody(
[
dbc.Label("Address:", id='address'),
dbc.Label("Name:", id='name')
]
),
dbc.ModalFooter(
[
dbc.Button("OK", color="primary", size="lg", className="mr-1"),
]
),
],
id="modal",
),
], style={"width": "50%"}),
# Update modal on click event
@app.callback(Output("modal", "is_open"),
[
Input("map-graph1", "clickData")],
[State("modal", "is_open")],
)
def display_popup(clickData, close, is_open):
if clickData is None:
return (no_update)
else:
Name = clickData['points'][0]['customdata']['Name']
Address = clickData['points'][0]['customdata']['Address']
return (Name, Address)
This issue has been tagged with NEEDS SPON$OR
A community PR for this feature would certainly be welcome, but our experience is deeper features like this are difficult to complete without the Plotly maintainers leading the effort.
Sponsorship range: $45k-$50k
What Sponsorship includes:
Please include the link to this issue when contacting us to discuss.
Would like to chime in on the possibility of simply disabling the tooltips. I still want the click behavior to return the closest point. I just don't want the tooltip at all.
@inselbuch that should just be hoverinfo: 'none'
https://plotly.com/javascript/reference/scatter/#scatter-hoverinfo
Wonderful! I had tried "skip" ... did not see "none"
You are a rock star.
Sent from my iPad
On Nov 6, 2020, at 9:14 AM, Alex Johnson notifications@github.com wrote:
@inselbuchhttps://github.com/inselbuch that should just be hoverinfo: 'none' https://plotly.com/javascript/reference/scatter/#scatter-hoverinfo
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHubhttps://github.com/plotly/plotly.js/issues/1847#issuecomment-723132672, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AFMVC6MHADOK7LDBPCLM3BDSOQHDFANCNFSM4DRWINVQ.
Hey sorry to jump in here, hoping my usecase is already supported as the previous commenter's was.
I often use plotly to visualize many series with different ranges on a shared timescale. One feature I've been searching for (and I'm not sure if it's part of this issue or not - so pardon my asking) is the ability to have clicks persist the hover dialog.
For example, I'd love to be able to do something like this by clicking in a few locations, to easily highlight how these many traces are changing over time (and possibly to set some default clickData to show some default hoverinfo for a few points when users first open the page):
Please let me know if this is already supported, or if it's part of this pending feature request.
Thank you very much!
I linked here from part 4 of the tutorial .
I just wanted to chime in that it is possible to customize the hover interactions while using a selection box by changing the code in the tutorial in the "Generic Crossfilter Recipe" section:
[p['customdata'] for p in selected_data['points']])
to [p['pointNumber'] for p in selected_data['points']])
and then getting rid of customdata=df.index,
in update_traces
.
p['pointNumber']
already has point indices so setting p['customdata']
to df.index
makes p['customdata']
identical to p['pointNumber']
and needlessly occupies p['customdata']
which prevents the user from customizing the hover interaction using the method outlined here here.
I'm not sure if this addresses all of the issues presented here or if someone else has already mentioned it before but at the very least the tutorial should probably be updated to use pointNumber
instead of customdata
as a matter of good practice (unless there is some other utility for it that I am missing).
@Andrej4156 thanks! I think the pointNumber
will not match up correctly with df.index
if you have multiple traces in the same figure, which is why the recipe is set up this way.
ECharts is powerful, has a feature of "hover on legend to highlight the respective series and dim the rest of series", please check https://github.com/apache/echarts/issues/17200.
Plotly.js has default styles for hovering (tooltips) and for selection (dimmed traces).
In Dash, users want to be able to customize these styles. While they can customize these styles themselves through Dash callbacks, it's slow (roundtrip to server). And while I could write this behaviour into the Dash
Graph
component, it would be great if this was standard behaviour that everyone could benefit from.Here are some examples that customized interaction styles or traces could enable.
As requested in the Dash community forum
In addition to this example, users might want to:
In this Uber Rides Dash demo created by @alishobeiri, the selected bars are replotted to be white. This persistent style informs the user which bars are selected and also matches the color palette of app itself.
While selected markers have a "dimming" effect, some users will want to customize the style of the selected points and the unselected points. For example, they might want to:
mode: "markers+text"
)In BI platforms, "clicking" is often used for drill downs. While we support click events, we don't modify the look and feel of the graph after clicking. For example, users might want to display constant text when clicking on a point.
In addition, there are a few other default style changes for clickable points (this could be a separate issue):
cursor: pointer
and making the point a little bit largerI'm sure there are many more examples out there.
cc @alexcjohnson @etpinard @cpsievert @monfera @jackparmer