react-plotly.js icon indicating copy to clipboard operation
react-plotly.js copied to clipboard

Plotly selection state is lost when re-rendering.

Open DylanVann opened this issue 6 years ago • 17 comments

This codepen shows the issue: https://codepen.io/dylanvann/pen/OYaedz

The onHover handler forces a re-render.

Whenever the Plot is re-rendered some state is lost. In particular the selection is lost.

How it behaves when re-rendering (selection box is not maintained):

selection

How it behaves when not re-rendering (selection box is maintained):

better-selection

DylanVann avatar May 31 '19 17:05 DylanVann

You should be able to use uirevision to avoid most such problems: https://plot.ly/javascript/uirevision/

nicolaskruchten avatar May 31 '19 19:05 nicolaskruchten

It does not seem to work for selection state.

DylanVann avatar May 31 '19 19:05 DylanVann

In your codepen, what does the problem look like? Can you post a gif? I can't replicate any issues on this end...

nicolaskruchten avatar May 31 '19 19:05 nicolaskruchten

Posted a couple gifs in the description.

DylanVann avatar May 31 '19 19:05 DylanVann

Oh I see, the selection box disappears. Yes, this is not something which is persistent in plotly.js at the moment (it's not part of the figure spec at all actually) ... issue: https://github.com/plotly/plotly.js/issues/1851

nicolaskruchten avatar Jun 01 '19 00:06 nicolaskruchten

Cool. Ideally to fit React's model selection could even be a controlled prop.

DylanVann avatar Jun 05 '19 13:06 DylanVann

Yes, this would be ideal but the underlying Plotly.js library doesn't really work in such a way as to be compatible with this. The idea behind uirevision is for it to be more controllably uncontrolled :)

nicolaskruchten avatar Jun 06 '19 02:06 nicolaskruchten

@DylanVann you can control the constraint-range + range + selectedpoints property of traces to maintain the select state yourself, but it takes a lot of time. The api is not programmer-friendly

yifei-zhan avatar Jun 21 '19 11:06 yifei-zhan

Just ran into this issue myself. When I drag to select a region on the scatter plot, I want to show the selected items so I'm using onSelected to update the selected IDs in a parent Component. But unfortunately this state change is causing the <Plot/> inside the <PlotContainer /> to re-render and so I don't see the selection change in the Plot:

Component = () => {
    const [selectedIds, setSelectdIds] = React.useState([]);

    return (
        <div>
            <PlotContainer setSelectdIds={setSelectdIds} />
            <ShowSelected selectedIds={selectedIds} />
        </div>
    )

Any pointers or workarounds would be much appreciated? Thanks.

will-moore avatar Feb 22 '20 22:02 will-moore

Actually, I re-read the issue above and realise that was really concerned about the selection box but I'm not too bothered about the box. For me, I lose the selection itself. Is there a way to preserve the selected points? I've used all the state management described at https://github.com/plotly/react-plotly.js#state-management to preserve the axis ranges etc but I don't see selected objects in any of that state?

will-moore avatar Feb 23 '20 16:02 will-moore

It would be good to get the selection as an input props. I was hoping to use react-plotly. I'm implementing something like crossfilter where the plot selections/brushes are a key part of the interface.

However it sounds like the underlying plotly library doesn't have robust selection support. Is there some workaround, so I can use react-plotly instead of d3? — maybe overlaying my own selection box outside of plotly, but then it would have to synchronize with the margins and scales.

matthias-ccri avatar Feb 28 '20 20:02 matthias-ccri

I'm using Plotly with crossfilter, and it seems that sometimes I am losing the current selection because of a re-render and sometimes not. Haven't got to the bottom of it yet.... https://github.com/will-moore/parade-crossfilter/blob/master/src/plots/Plot.js is my wrapper to maintain axis ranges on re-render. The parent https://github.com/will-moore/parade-crossfilter/blob/master/src/plots/ScatterPlot.js listens for when the crossfilter filter changes to update the plot. Based on React-crossfilter example at https://www.lighttag.io/blog/react-dc-js/.

will-moore avatar Mar 01 '20 23:03 will-moore

@DylanVann Is your problem resolved? Shall we close this issue?

m-podlesny avatar Sep 17 '20 12:09 m-podlesny

As far as I'm aware it is not.

DylanVann avatar Sep 17 '20 12:09 DylanVann

Any update on this issue ?

mlisthenewcool avatar Jun 28 '21 10:06 mlisthenewcool

I have same issue, In React when it's re-rendering.

juls-k avatar Nov 10 '21 06:11 juls-k

I see this is an old issue, but I've been recently successful in working around it by using the selections attribute from the plot's layout object. The idea was to use it as a controlled prop as discussed earlier.

Essentially, I have the onSelected callback set a state on the parent component. The state is set to be event.selections. I then pass this same state as a prop for the plot component and make it the value of the selections attribute. To clear the selection, I just set the state to an empty array. Something like this:

// Parent Component

function ParentComponent(){
  const [selections, setSelections] = React.useState([])

  const handleSelect = ( event ) => {
    setSelections( event.selections )
  }

  const handleDeselect = ( event ) => {
    setSelections([])
  }

  return (
    <ChildComponent selections={selections} handleSelect={handleSelect} handleDeselect={handleDeselect} />
  )
}


// Child Component

function ChildComponent({selections, handleSelect, handleDeselect}){
  return (
    < Plot
      data={...}
      layout={{
        ...,
        selections: selections,
        ...
      }}
     onSelected={handleSelect}
     onDeselect={handleDeselect}
    />
  )
}

sellings-dev avatar Jun 18 '23 13:06 sellings-dev