question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Brush can't be used with ScatterChart

See original GitHub issue

When I try to use a Brush with a ScatterChart, no Brush shows up, and no warning or error is visible. Is this expected behavior? Because of this issue, I am now trying to create a scatter-like chart from of a LineChart (in order to get Brush functionality) but it is a lot more difficult.

Issue Analytics

  • State:closed
  • Created 7 years ago
  • Reactions:1
  • Comments:7 (1 by maintainers)

github_iconTop GitHub Comments

8reactions
itwasmattgreggcommented, Jan 26, 2018

@xile611 Why do the docs have <ScatterChart /> listed as a parent of <Brush /> then?

0reactions
mosofskycommented, Sep 21, 2022

I got working ScatterChart and Brush (although onChange listener is needed, but that’s no big deal):

const { startIndex, endIndex } = this.state;
const data = unchangedData.filter(datum => datum.hour >= startIndex && datum.hour <= endIndex)

return (
  <ScatterChart width={width} height={300} data={unchangedData}>
    <XAxis type="category" dataKey="hour" interval={0} />
    <YAxis type="number" dataKey="processor" interval={0} />
    <Brush 
      dataKey="hour"
      height={30}
      stroke="#8884d8"
      onChange={({ startIndex, endIndex }) => this.setState({ startIndex, endIndex })} />
    <Scatter data={data} />
  </ScatterChart>
)

Notice data props for ScatterChart and Brush components.

I’m not sure this solution works in general. The startIndex and endIndex are compared to the hour column of your data. What if there are some hours missing from the data, which is possible in a scatter plot? What if there are multiple y-values for a given x-axis?

I think Recharts Brush assumes that startIndex and endIndex are indices into the data passed to the ScatterChart. However, for any value of x there can be multiple y values and vice versa. There is only one data point for any given x and y value, then Brush might work for the Scatter. But if not, let’s say the the Brush is configured (via its dataKey property) to limit the data based on the x-axis and there are a few values of x that appear multiple times in the data because there are multiple y values for that x. When the user changes the startIndex, the Brush’s onChange is called with a startIndex that refers to the original data array, not to the domain of the x-axis.

For example, let’s say we have the following data:

const dataSetWithMultipleXValues = [
  {x: 5, y: 7, z: 10}, 
  {x: 6, y: 1, z: 2}, 
  {x: 6, y: 9, z: 4}
]

Let’s assume the XAxis’s dataKey is x and so it the Brush’s. Since there are 3 entries in the data array, the Brush will initialize to startIndex=0 and endIndex=2. If the user slides the left Brush traveler from startIndex 0 to startIndex 2, then what should happen? It will remove the first two data points from the data and only show the final one. However, data[1] and data[2] share the same x coordinate. That sounds like a very goofy user experience. Probably what’s desired is for the Brush’s startIndex and endIndex to refer to the unique values for the XAxis. But instead if refers to the data’s indices.

Another issue is the label on the Brush which should only ever say on x-value a single time but since it actually refers to the data, when the user slides the traveler, the label could end up saying the same value twice.

I have been able to get a solution to work with a slider widget (https://mui.com/material-ui/react-slider/) that’s not part of Recharts. I just pass it the unique values of my x-axis and use its onChange. Here is a rough sketch using the example from above:

import Slider from "@mui/material/Slider";

// ...

const uniqueXValues = [5, 6];  // i.e. the unique values of x in dataSetWithMultipleXValues

const onSliderChange = (event: Event, newValue: number | number[]) => {
    if (!Array.isArray(newValue)) {
        throw new Error(`Expected Slider onChange to pass an array but got |${newValue}|`);
    }

    this.setState({
        startIndex: newValue[0],
        endIndex: newValue[1],
    });
};

const sliderValueLabelFormat = (value: number, _index: number): React.ReactNode => {
    // the value is actually an index for our purposes based on testing
    return uniqueDatesStringArray[value];
};

const { startIndex, endIndex } = this.state;
const filteredData = dataSetWithMultipleXValues.filter(datum => datum.hour >= startIndex && datum.hour <= endIndex)

return (
  <div>
    <ScatterChart width={width} height={300} data={dataSetWithMultipleXValues}>
      <XAxis type="category" dataKey="x" interval={0} />
      <YAxis type="number" dataKey="y" interval={0} />
      <Scatter data={filteredData} />
    </ScatterChart>
    <Slider
        value={[this.state.startIndex!!, this.state.endIndex!!]}
        onChange={this.onSliderChange}
        valueLabelDisplay="auto"
        valueLabelFormat={uniqueXValues}
        min={0} max={uniqueXValues.length - 1}
    />
  </div>
)
Read more comments on GitHub >

github_iconTop Results From Across the Web

Brushing Scatter Plots Example - Vega & Vega-Lite
This example uses an interactive scatter plot matrix of penguin measurements, and echoes the original Brushing Scatterplots paper by Becker & Cleveland. Click ......
Read more >
Creating a scatter plot with brush using D3.js v4 - Raj Vansia
Today we will be creating the above graph which will give you the basic recipe to create a scatterplot with brush functionality in...
Read more >
Brushing Scatterplots
Brushing is a collection of dynamic methods for viewing multidimensional data. It is very effective when used on a scatterplot matrix, a rectangular...
Read more >
Can you build a dynamic scatter plot with proportional brushing?
The scatter plot is built to be dynamic, with both the axes and ... used Orders – I chose to use Orders too...
Read more >
echarts - Brush by default active on scatter chart - Stack Overflow
Similarly you can enable any echarts toolbar feature using the same mechanism. Note: If you are using latest EChart then you may have...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found