Streamlit Elements Nivo - Fail Adding custom layers

Struggling to add custom layers to the nivo bar chart in streamlit-elements.

Streamlit elements is excellent. Especially since I can use nivo charts.
However, I’m wanting to add custom scatter points to my Bar plot. It isnt natively supported with nivo, but adding lines to the chart can be done with adding layers to the layers prop in nivo bar.

To begin I tried recreating what was done here

Starting code that displays a bar chart perfectly (base layer)

with mui.Box(
             id="test",
             sx={
                  "flex": 1,
                  "minHeight": 50,
                  "height" : 200,
                  "minWidth": None,
                  "width" : None
                  }):
            
            
            nivo.Bar(
                data=[
                        { "x": "0", "v": 2.7 },
                        { "x": "1", "v": 3.3 },
                        { "x": "2", "v": 3.8 },
                        { "x": "3", "v": 4.3 },
                        { "x": "4", "v": 1.7 },
                        { "x": "5", "v": 2.2 },
                        { "x": "6", "v": 5.5 },
                        { "x": "7", "v": 6.0 }
                        ],
                keys=["v"],
                maxValue=6.6,
                padding={0.6},
                margin={
                    "top": 10,
                    "right": 10,
                    "bottom": 36,
                    "left": 36
                },
                indexBy="x",
                enableLabel="true",
                colors=["#bd7a0f"],
                borderRadius=2,
                axisLeft={
                    "tickValues": 7
                },
                layers=["grid", "axes", "bars"]
            )

Displays this:

I then want to add a layer, as per the referenced guide, I define a react function that takes chart computed data.

I modify my code to:

above_bar_layer = """
                        <script>
                            const ScatterCircle = ({ bars, xScale, yScale }) => {
                                return (
                                    <>
                                    {bars.map((bar) => (
                                        // Render the circle SVG in chart using Bars coordinates
                                        <circle
                                            key={`point-${bar.data.data.x}`}
                                            cx={xScale(bar.data.index) + bar.width / 2}
                                            cy={yScale(bar.data.data.v + 0.2)}
                                            r={3}
                                            fill="black"
                                            stroke="black"
                                            style={{ pointerEvents: "none" }}
                                        />
                                    ))}
                                    </>
                                );
                            };

                            // Register the ScatterCircle globally
                            window.ScatterCircle = ScatterCircle;
                        </script>
                        """

        html.script(above_bar_layer)
        
        # ---------------------------------------------
        # Plot
        # ---------------------------------------------
        
        with mui.Box(id="test", sx={
                                "flex": 1,
                                "minHeight": min_height,
                                "height" : height,
                                "minWidth": min_width,
                                "width" : width
                                }):
            
            
            nivo.Bar(
                data=[
                        { "x": "0", "v": 2.7 },
                        { "x": "1", "v": 3.3 },
                        { "x": "2", "v": 3.8 },
                        { "x": "3", "v": 4.3 },
                        { "x": "4", "v": 1.7 },
                        { "x": "5", "v": 2.2 },
                        { "x": "6", "v": 5.5 },
                        { "x": "7", "v": 6.0 }
                        ],
                keys=["v"],
                maxValue=6.6,
                padding={0.6},
                margin={
                    "top": 10,
                    "right": 10,
                    "bottom": 36,
                    "left": 36
                },
                indexBy="x",
                enableLabel="true",
                colors=["#bd7a0f"],
                borderRadius=2,
                axisLeft={
                    "tickValues": 7
                },
                layers=["grid", "axes", "bars", "ScatterCircle"]
            )

Using the html module to inject the react code to the webpage and adding “ScatterCircle” as the js object as an extra layer.

Unfortunately this does not work. The chart loads as normal with no extra layer. I have tried other things too like passing the react code direct to the layer with no avail.

Any ideas? If I got it working I would change the scatter points to bars to have error bars but I cannot seem to get past this first hurdle.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.