Unsupported operation error when adding rows to st.line_chart while specifying x & y

Summary

I want to update a line chart by adding rows. This works as long as I don’t specify x & y in st.line_chart(…). But as soon as I add those parameters I get the following error:

Unsupported operation. The data passed into `add_rows()` must have the same data signature as the original data.

In this case, `add_rows()` received `["int64","unicode","float64"]` but was expecting `["int64","float64"]`.

Steps to reproduce

Code snippet:

import streamlit as st
import pandas as pd
import time

df = pd.DataFrame({"steps":[0,1,2,3],"values": [4,2,1.4,0.9]})
my_chart = st.line_chart(df, x="steps", y="values")
df_new = pd.DataFrame({"steps":[4,5,6],"values": [0.5,0.3,0.5]})
time.sleep(3)
my_chart.add_rows(df_new)

Expected behavior:

The chart should be updated using this data:
steps values
0 4.0
1 2.0
2 1.4
3 0.9
4 0.5
5 0.3
6 0.5
Actual behavior:

When I run my_chart = st.line_chart(df) then the error doesn’t pop up but the chart is not what I want. I want to use ‘steps’ as x-values for my graph and ‘values’ as y-values.

Debug info

  • Streamlit version: 1.16.0
  • Python version: 3.10.8
  • Using Conda
  • OS version: MacOS 12.5.1
  • Browser version: Chrome - Version 108.0.5359.124 (Official Build) (x86_64)

Hey @ml_user, welcome to our forum! :balloon:

Thanks a lot for your detailed post with reproducible code, that helps a lot. I think this might well be a bug… Sharing this with our engineers!

Meanwhile, you can use st.line_chart without the explicit x, y parameters to avoid the error. Indeed, when you’re not specifying x and y, then st.line_chart expects x to be the index, and y to be the series:

import time

import pandas as pd
import streamlit as st

df = pd.DataFrame({"steps": [0, 1, 2, 3], "values": [4, 2, 1.4, 0.9]}).set_index(
    "steps"
)["values"]

my_chart = st.line_chart(df)

df_new = pd.DataFrame({"steps": [4, 5, 6], "values": [0.5, 0.3, 0.5]}).set_index(
    "steps"
)["values"]

time.sleep(3)
my_chart.add_rows(df_new)

Check out this playground to see how that looks like!

Hope that helps,

@ml_user I have shared your post with our engineers, and it seems that this is indeed a bug on our side. Would you mind adding an issue in our repository so they can have a deeper look into it? Here’s the link to create an issue. Thanks so much again!

Hello @arnaud,

Thanks for sharing the issue and providing a workaround.

  1. I submitted an issue here: Issue
  2. I used your workaround to plot a second series. I checked the documentation of st.line_chart() but it doesn’t seem like I can label the axis without running into the same bug we had before. Is there a way I can label the axis?

This is the code:

df = pd.DataFrame({"steps": [0, 1, 2, 3], "values": [4, 2, 1.4, 0.9], "values_2": [3, 1, 1, 0.9]}).set_index(
    "steps"
)

my_chart = st.line_chart(df)

df_new = pd.DataFrame({"steps": [4, 5, 6], "values": [0.5, 0.3, 0.5], "values_2": [0.8, 0.5, 0.3]}).set_index(
    "steps"
)

time.sleep(3)
my_chart.add_rows(df_new)
  1. On an unrelated note, is there a feature where one can update charts of other types such as st.plotly_chart via the add_rows command? My actual use case is that I want users to specify model parameters and let them train a model using the app. I made a page which displays the loss values in the left column as an updating st.dataframe() and plot the train and validation loss updating with each epoch in the right column. I succeed to do so using st.line_chart() with your help. However, ideally I want to do it with plotly. Is this possible? Here is another minimal example in which the update is currently returned as a second chart but I want it to update the first one:
import time
import pandas as pd
import plotly.express as px
import streamlit as st

col1, col2 = st.columns(2)
df = pd.DataFrame(
    {"steps": [0, 1, 2, 3], "values": [4, 2, 1.4, 0.9], "values_2": [3, 1, 1, 0.9]}
).set_index("steps")

df_new = pd.DataFrame(
    {"steps": [4, 5, 6], "values": [0.5, 0.3, 0.5], "values_2": [0.8, 0.5, 0.3]}
).set_index("steps")

df_all = pd.concat([df, df_new], axis=0)
fig = px.line(df, x=df.index, y=["values", "values_2"])
with st.empty():
    with col2:
        my_chart = st.plotly_chart(fig)
    with col1:
        my_df = st.dataframe(df)
    time.sleep(3)
    fig = px.line(df_all, x=df_all.index, y=["values", "values_2"])
    my_df.add_rows(df_new)    
    with col2:
            my_chart = st.plotly_chart(fig)

Thank you a lot for your help and time!

Hey @ml_user

  1. I submitted an issue here: Issue

Thanks so much!

  1. I used your workaround to plot a second series. I checked the documentation of st.line_chart() but it doesn’t seem like I can label the axis without running into the same bug we had before. Is there a way I can label the axis?

Currently, our built-in charts st.line_chart, st.area_chart, st.bar_chart do not support passing custom labels to the axes or a title to the overall chart. You can actually tweak them when passing explicit x, y columns, since we use the respective column names as labels. But since you can’t use explicit x, y and st.add_rows here, this is certainly not a solution for you. We have been thinking about adding an explicit passing parameter for labels, though! By the way, how would you have expected/loved to pass those labels? Always curious what people love as an API. I was thinking a simple title, x_title and y_title… but we didn’t settle!

If you like the style of our built-in charts, you may notice they’re a simple lightweight API on top of Altair charts, so things you can’t do with our built-in charts, you may be able to easily do using Altair. Here’s an example of a simple line chart with custom titles in Altair: https://playground.streamlit.app?q=altair-chart-with-labels

  1. On an unrelated note, is there a feature where one can update charts of other types such as st.plotly_chart via the add_rows command?

I could not make add_rows work with a Plotly chart, since I get the elementType 'plotlyChart' is not a valid arrowAddRows target! error (I guess you had that one too?).

But forgetting the add_rows feature for a second, you may also try to naïvely build the chart again, and the result turns out pretty smooth anyway. Here’s an example that simply re-builds the chart upon every new data row coming in: https://playground.streamlit.app/?q=add-rows-for-plotly

Hope that helps. And once again, thanks for your reproducible pieces of code all the way!

Hey Arnaud,

I marked your post as the solution. It may not be directly the answer to the original question since this was related to a possible bug but in the end this is what I wanted to do.

  1. Naming conventions for axis and title.
    I think there are two options to go for. Either go for the x_title and y_title option which would be more close to the way how it is being done in Altair and Plotly. But it would still be a bit different since they use slightly different names for it.
    Alternatively, one could stick to the conventions of matplotlib and therefore seaborn as well since it is built on top of it. Using the name xlabel and ylabel would be the option I prefer. In my opinion, most people start learning plotting in Python with these two libraries and will therefore be used to these conventions. I think passing these two arguments as optional arguments to st.line_chart() to overwrite the selected column names in the plot would be nice.
  1. Yes I had the same error and the overwriting the plotly chart was the option I went for in the end.

Thank you again very much!

1 Like

Hey @ml_user,

Truly appreciate your inputs and efforts in making Streamlit a better library. :slightly_smiling_face:

You make a good point for xlabel and ylabel. The error on using add_rows for Plotly chart is expected - I asked for it - but we will update the docs to make that clearer.

See you around! Hope you can share what you built, too!

Sure will do once its done! See you around. :slight_smile:

1 Like