vega / vega-lite

A concise grammar of interactive graphics, built on Vega.
https://vega.github.io/vega-lite/
BSD 3-Clause "New" or "Revised" License
4.62k stars 599 forks source link

Error: "Cannot read properties of undefined (reading '0')" when trying to link selections between a probability density histogram and a scatterplot #9390

Open NateLanza opened 1 month ago

NateLanza commented 1 month ago

Bug Description

I've been attempting to create a visualization in react-vega that links a histogram to a scatterplot with an interval selection brush and accepts default values for the brush. I've noticed that, when a default value is provided to the scatterplot, the histogram generates an error Cannot read properties of undefined (reading '0') (no error is generated for two linked scatterplots). In react, this manifests as no lines rendering in the histogram. In the vega editor, the histogram instead does not update when the selection is cleared (the pink line should only appear when a selection is active): Open the Chart in the Vega Editor. This vega chart appears perfectly correct when you load it but clicking the scatterplot once immediately creates the bug.

{
  "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
  "data": {"url": "data/cars.json"},
  "vconcat": [
    {
        "hconcat": [
            {
                "width": 200,
                "height": 200,
                "mark": {
                    "type": "point"
                },
                "params": [
                    {
                        "name": "brush",
                        "select": {
                            "type": "interval",
                            "clear": "mousedown"
                        },
                        "value": {
                            "x": [3000, 4000],
                            "y": [200, 300]
                        }
                    }
                ],
                "encoding": {
                    "x": {
                        "field": "Weight_in_lbs",
                        "type": "quantitative",
                        "scale": {
                            "zero": false,
                            "type": "linear"
                        }
                    },
                    "y": {
                        "field": "Displacement",
                        "type": "quantitative",
                        "scale": {
                            "zero": false,
                            "type": "linear"
                        }
                    },
                    "color": {
                        "condition": {
                            "param": "brush",
                            "empty": false,
                            "value": "#e377c2"
                        }
                    }
                }
            }
        ]
    },
    {
        "hconcat": [
            {
                "width": 200,
                "height": 200,
                "layer": [
                    {
                        "transform": [
                            {
                                "density": "Displacement"
                            },
                            {
                                "calculate": "datum[\"value\"]",
                                "as": "Displacement"
                            }
                        ],
                        "params": [
                            {
                                "name": "brush",
                                "select": {
                                    "type": "interval",
                                    "encodings": [
                                        "x"
                                    ],
                                    "clear": "mousedown"
                                }
                            }
                        ],
                        "mark": "line",
                        "encoding": {
                            "x": {
                                "field": "Displacement",
                                "type": "quantitative",
                                "title": "Displacement"
                            },
                            "y": {
                                "field": "density",
                                "type": "quantitative",
                                "title": "probabiity"
                            },
                            "opacity": {
                                "condition": [
                                    {
                                        "param": "brush",
                                        "empty": false,
                                        "value": 1
                                    }
                                ],
                                "value": 0.4
                            }
                        }
                    },
                    {
                        "transform": [
                            {
                                "filter": {
                                    "param": "brush"
                                }
                            },
                            {
                                "density": "Displacement"
                            },
                            {
                                "calculate": "datum[\"value\"]",
                                "as": "Displacement"
                            }
                        ],
                        "mark": "line",
                        "encoding": {
                            "x": {
                                "field": "Displacement",
                                "type": "quantitative",
                                "title": "Displacement"
                            },
                            "y": {
                                "field": "density",
                                "type": "quantitative",
                                "title": "probability",
                                "scale": {"domain": [0, 0.1]}
                            },
                            "color": {"value": "#e377c2"},
                            "opacity": {
                                "value": 1
                            }
                        }
                    }
                ]
            }
        ]
    }
]
}

You'll note that, when dragging a new selection, the histogram bugs out with tons of errors: Cannot read properties of undefined (reading 'marktype'). This appears to be caused by encoding.color on the histogram. Before entirely narrowing down this minimal example, I produced this error on this chart without the marktype error. The only difference is encoding.color on the histogram, which is set to an object related to my dataset that shouldn't work as well in the vega editor, but somehow works better. In this example, no selection line is displayed on the second histogram due to the color being incorrect, but it does produce the titular error message with no additional errors. I'm not sure whether this difference in behavior between the two is a second bug that deserves its own issue.

Checklist

NateLanza commented 1 month ago

If it helps, the stacktrace in React:

TypeError: Cannot read properties of undefined (reading '0')
    at Object.eval (eval at Fd (vega-runtime.module.js:88:14), <anonymous>:3:102)
    at Ot._update (vega-dataflow.module.js:965:19)
    at Ot.evaluate (vega-dataflow.module.js:576:20)
    at Ot.run (vega-dataflow.module.js:601:17)
    at ij.Nue [as evaluate] (vega-dataflow.module.js:1525:17)
    at ij.evaluate (vega-view.module.js:1087:39)
    at ij.Due [as run] (vega-dataflow.module.js:1633:48)
    at Vega.js:46:23
    at VegaEmbed.js:36:13

Per the debugger, this comes from the following anonymous function, which I assume is eval'd:

var datum=event.item&&event.item.datum;
return [this.scale("concat_1_concat_0_x",_["$brush_AvgRating"][0]),this.scale("concat_1_concat_0_x",_["$brush_AvgRating"][1])]; 

Let me know if a separate issue in react-vega would be helpful.

NateLanza commented 4 weeks ago

Here's a slightly simpler version where the issue still occurs; I've removed the calculation to rename "value" to the name of the field in the density plot. I wanted the signal to include the name of the field being brushed over because my application listens to signals & saves brush values externally, but this issues still occurs without the calculation.

I've also noticed that removing the params field entirely from the histogram solves this issue, as seen here. However, since I want the selection to go both ways, this doesn't really solve my issue. It appears that the density calculation in general doesn't work well with linking selections to other plots.