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.