streamlit icon indicating copy to clipboard operation
streamlit copied to clipboard

Altair chart clipped when no legend title

Open dougmet opened this issue 3 years ago • 6 comments

Summary

When displaying an altair plot, with a legend at the top or the bottom without a title, the chart is being clipped at the sides, losing the y-axis labels.

I'm not 100% sure if this is a streamlit issue or an altair issue. However, I do not experience this problem in a Jupyter notebook without streamlit so thought I'd start here.

Steps to reproduce

Open in Streamlit Cloud

Code snippet:

import altair as alt
import streamlit as st
from vega_datasets import data

iris = data.iris()

iris_chart = alt.Chart(iris).mark_point().encode(
    x='petalWidth',
    y='petalLength',
    color=alt.Color('species', legend=alt.Legend(title=None, orient="top")),
)

st.altair_chart(iris_chart, use_container_width=True)

Expected behavior:

I would expect that the y-axis label is rendered within the viewable area. If you set title=" " then you get the following: image

Actual behavior:

With title=None or title="" I get the y-axis label clipped. You can just about see it's there:

image

Is this a regression?

No. But I am a new user.

Debug info

  • Streamlit version: 1.13.0
  • Python version: 3.10.6
  • Using Pipenv and Poetry
  • OS version: MacOS 12.6 (M1 arm64)
  • Browser version: Chrome 106.0.5249.91

Additional information

As a workaround you can simply set legend=alt.Legend(title=" ", orient="top").

dougmet avatar Oct 03 '22 11:10 dougmet

@dougmet Thanks for reporting this issue. I was able to reproduce this here. I haven't figured out the root cause, but it does look like a bug in altair/vega lite.

lukasmasuch avatar Oct 11 '22 15:10 lukasmasuch

Just fyi, this also affects our internal charts like st.line_chart or st.bar chart. @jrieke fyi cc: @blackary

willhuang1997 avatar Oct 26 '22 19:10 willhuang1997

I did do some investigating too and I also came to the same conclusion that it does seem like an altair/vega lite bug.

willhuang1997 avatar Oct 26 '22 20:10 willhuang1997

I also ran into similar issues of elements in Altair charts being cut off if rendered in Streamlit. Rendering the same charts in e.g. a Jupyter notebook worked fine. Some things I noticed along the way:

  • When I open the Altair chart from the repro Streamlit app, open it in the Vega Editor, and then add the dataset as JSON the chart renders fine: Open the Chart in the Vega Editor
  • Same when I use the Vega Editor to first convert the Vega-Lite spec without data into a Vega spec and then add the data
  • When I render the chart in Streamlit using the HTML that Altair can produce it also renders fine:
import altair as alt
import streamlit as st
import streamlit.components.v1 as components
from vega_datasets import data

iris = data.iris()

iris_chart = (
    alt.Chart(iris)
    .mark_circle()
    .encode(
        x="petalWidth",
        y="petalLength",
        color=alt.Color("species", legend=alt.Legend(title=None, orient="top")),
    )
)

st.header("Y Label cut off")
st.altair_chart(iris_chart, use_container_width=True, theme=None)

st.header("It works like this")
chart_height = 200
buffer = 100
components.html(
    iris_chart.properties(width="container", height=chart_height).to_html(),
    height=chart_height + buffer,
)

image

Hence, the specification which is produced by Altair and also the spec produced by Vega-Lite seem correct to me. I'm not familiar with how the Arrow serialization works but maybe the issue is either somewhere there or in how Vega-Lite then picks up the data?

Is there any way to disable the arrow serialization of the data and instead keep the data in the dict? Would be useful for testing and as an escape hatch for users until there is a fix.

https://github.com/streamlit/streamlit/issues/6431 might be related to this as well.

@thomend fyi

binste avatar Jul 27 '23 09:07 binste

I'm having the same issue. When setting orient='bottom', title='None' of a legend this will clip the y-axis:

chart = alt.Chart(df).mark_area().encode(
    x=alt.X('Year:T'),
    y=alt.Y('Count:Q'),
    color=alt.Color('Gender:N', legend=alt.Legend(orient='bottom', title='None'))
)

image

The workaround I'm using is: title=' ', padding=-20. This achieves a relatively similar result, but is of course not very clean.

LouisDeconinck avatar Nov 21 '23 13:11 LouisDeconinck

Just chiming in to say that I find the same bug but only on the x-axis label. Happens consistently in any chart where the legend title is set to "" or None.

EDIT: Ah. My legend is rendered to the side which might explain why I see the issue on the other axis.

tfenesel avatar Jun 25 '24 08:06 tfenesel

If this issue affects you, please react with a 👍 (thumbs up emoji) to the initial post.

Your feedback helps us prioritize which bugs to investigate and address first.

Views

github-actions[bot] avatar Mar 26 '25 13:03 github-actions[bot]

Closing this issue since it seems to have been fixed in the latest version of Streamlit: https://issues.streamlit.app/?issue=gh-5467

lukasmasuch avatar Jun 09 '25 09:06 lukasmasuch