plotly / plotly/react-plotly.js

uirevision not preserving the trace's visibility (legend click)

未关闭
#171 0 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 Issue。

主要语言
JavaScript
星标
1.1k
派生
138
平均合并
3 天 2 小时
30 天内合并 PR
4

描述

When adding the below line to the layout [1], one would expect that the chart preserves the trace's visibility even after the data is reload, or other elements of a webapp change.

Whilst it works nice and clean in a simple test, in an almost empty react project, it doesn't seem to work well in a medium sized app, with dozens of Components and states.

In my specific example, it is enough for someone to change the navigation bar dropdowns, which trigger an event changing the state of App.js, where the charts originate, too. In the very same second when the dropdown changes its value, the charts lose their 'memory' of what was previously selected, and revert back to their original state.

I'll see if I can reproduce this in a sharable code-pen, but perhaps someone already encountered this issue?

Am using react-plotly 2.4.0 with plotly.js 1.48.0

**1**
uirevision: 'true'

Was able to recreate it. ui revision seems to be failing when callbacks are used in reacts setState.
Clicking 'Button2' twice, will reset the selected traces to their default. Simply removing the callback (which does not affect the plot) makes it behave as intended again.

import React, { Component } from 'react';
import './App.css';
import MyPlot from "./plotly_test";
import NavbarTop from "./NavbarTop";


class App extends Component {
  constructor() {
    super();
    this.onClickButton = this.onClickButton.bind(this);
    this.onClickButton2 = this.onClickButton2.bind(this);
    this.state = {
      myID: 1,
      countries: {names: ['Alal', 'lqwel', 'qpweok'], labels: ['loqwe', 'qwoel', 'qlweo']},
      country: 'Poland',
    }
  };


  onClickButton() {
    this.setState({myID: this.state.myID + 1})
    this.changeCountry = this.changeCountry.bind(this);
    var labels = this.state.countries.labels
    this.setState({
      labels: labels.push('SomeLabel')
    })
  }

  onClickButton2() {
    this.setState({
      country: "SomeCountry",
    }, ()=>{
      this.setState({
        country: 'Yet Another'
      })
    })
  }

  changeCountry = (value, callback) => {
    this.setState({
      country: value,
    }, () => {
      callback(value)
    })
  };

  getCharts() {
    let components = [];
    components.push((<MyPlot id={this.state.myID}/>));
    return components
  }

  render() {
    let charts = this.getCharts();

    return (
      <div>
        <h1>{this.state.country}</h1>
        <NavbarTop callbackChange={this.changeCountry}/>

        <div className="App">
          {charts}
          <button
            onClick={this.onClickButton}
          > Button1
          </button>
          <button
            onClick={this.onClickButton2}
          > Button2
          </button>
        </div>
      </div>
    )
  }
}

export default App;

Navbar:

import React, { Component } from 'react';

class NavbarTop extends Component {
  constructor(props) {
    super(props);
    this.handleChange = this.handleChange.bind(this);
  }

  handleChange(event) {
    this.props.callbackChange(event.target.value, (something) => {
      console.log(something);
    })
  }

  render() {
    return (
      <div>
        <nav>
          <nav>
            <select name="countries" id="countries"
                    onChange={this.handleChange} value={'PL'}>
              <option value='DE'>Germany</option>
              <option value='FR'>France</option>
              <option value='ES'>Spain</option>
              <option value='UK'>United Kingdom</option>
            </select>
          </nav>
        </nav>
      </div>
    );
  }
}

export default NavbarTop;

plotly_test:


import React, {Component} from 'react'
import Plot from 'react-plotly.js'

class MyPlot extends Component {

  render() {
    const rand = () => 1;
    var x = [1, 2, 3, 4, 5];
    const new_data = (trace) => Object.assign(trace, {y: x.map(rand)});

// add random data to three line traces
    var data = [
      {mode:'lines', line: {color: "#b55400"}},
      {mode: 'lines', line: {color: "#393e46"}},
      {mode: 'lines', line: {color: "#222831"}}
    ].map(new_data);

    var layout = {
      title: this.props.id,
      uirevision:'true',
      xaxis: {autorange: true},
      yaxis: {autorange: true}
    };

    return (
      <div>
        <Plot
        layout={layout}
        data={data}
        />
      </div>
    );
  }
}

export default MyPlot;

贡献指南

这个仓库没有索引到贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

调研方向

从提供的 App 组件以及 plotly_test 和 NavbarTop 组件开始,然后通过点击图例项并触发 Button2 基于 callback 的 setState 更新来重现问题。跟踪 react-plotly.js 如何接收更新后的 Props,并确定 uirevision 为什么不再保留可见性;当选定 trace 的可见性在这些更新后保持不变时即表示完成。

由索引模型根据 Issue 内容生成。

评估

技术栈
javascript, react
领域
data-visualization, frontend
Issue 类型
缺陷
难度
4/5
预计耗时
3-5 天
活跃度
停滞
描述清晰度
基本清楚
新手友好度
35/100

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。