Choosing and using charts

Streamlit has native commands for several charting libraries. They differ in which chart types they support, how interactive they are, how well they match your app's theme, and how they handle large data. This guide helps you pick a chart command and use it well.

  1. Start with the simple charts, like st.line_chart and st.bar_chart. Move to st.altair_chart when you need more control.
  2. Use st.echarts_chart for chart types and in-chart features that Vega-Lite doesn't have, like sankey diagrams, gauges, and zoom sliders.
  3. Prefer st.echarts_chart over st.plotly_chart for interactive charts. Use Plotly for 3D and scientific charts, and use st.pyplot only for Matplotlib figures you already have.
  4. Prefer one charting library per page, and set chart colors in your theme instead of per chart.
  5. Pass alt to every chart so assistive technologies can describe it.
  6. Aggregate large data before you chart it, and use st.echarts_chart for very large or frequently changing series.

The Vega-based charts (st.line_chart, st.bar_chart, st.area_chart, st.scatter_chart, st.altair_chart, and st.vega_lite_chart) and st.echarts_chart follow your app's theme, including light and dark mode. They're interactive and send dataframes to the browser efficiently as Arrow. For st.echarts_chart, this applies when you pass the dataframe in dataset.source. Prefer these commands for most charts.

NeedUse
A quick line, bar, area, or scatter chart from a dataframest.line_chart, st.bar_chart, st.area_chart, st.scatter_chart
Chart titles, custom tooltips, layers, dual axes, log scales, faceting, aggregation, binning, or regressionst.altair_chart (Altair is installed with Streamlit)
Brushing one chart to filter linked viewsst.altair_chart
An existing Vega-Lite JSON specificationst.vega_lite_chart
Network graphs, trees, sankey, chord, sunburst, treemap, gauge, radar, funnel, calendar heatmap, or candlestick chartsst.echarts_chart
A built-in zoom slider, in-chart toolbox, or color-range filterst.echarts_chart (dataZoom, toolbox, and visualMap)
Values that animate when a widget changes the datast.echarts_chart
Line, bar, or scatter charts with more than about 100,000 pointsst.echarts_chart (see Chart large datasets)
An existing ECharts option, JSON string, or pyecharts chartst.echarts_chart
3D surfaces, meshes, or volumes; violin, ternary, or carpet plots; or an existing Plotly figurest.plotly_chart
An existing Matplotlib or seaborn figurest.pyplot (a static image)
Points on a mapst.map
Layered, 3D, or interactive geospatial datast.pydeck_chart
Flowcharts, sequence diagrams, or entity-relationship diagramsst.mermaid_chart
A diagram that needs Graphviz layout engines or clustersst.graphviz_chart
A small trend inside a metric or table cellchart_data in st.metric, or LineChartColumn, BarChartColumn, and AreaChartColumn in st.dataframe

A good rule of thumb: start with a simple chart and move to st.altair_chart when the simple chart runs out of options. Move to st.echarts_chart for the chart types and features in the table that Vega-Lite doesn't have, rather than to redraw a plain line, bar, or scatter chart.

Charting libraries differ in their tooltips, legends, toolbars, zoom behavior, and selection gestures. When you mix libraries on a page, the charts look and behave inconsistently. Prefer one charting library per page, and ideally across your whole app.

  • Default to Vega-based charts. The simple charts and st.altair_chart share one look, so you can freely mix them.
  • If a page needs several chart types that only ECharts has, like a sankey diagram next to a gauge, consider drawing the page's other charts with st.echarts_chart too.
  • A single ECharts chart on an otherwise Vega-based page is fine.
  • For operational dashboards with KPIs, monitoring, or several charts driven by the same filters, consider st.echarts_chart for every chart. Filter changes animate from the old values to the new values, and time series can have a zoom slider. For analytical dashboards with aggregation, faceting, or linked brushing, consider st.altair_chart.
  • Sparklines in st.metric and chart columns in st.dataframe fit next to either library.

Keep each chart's default theme="streamlit" so all charts use your app's fonts and colors. To change the chart palette, set chartCategoricalColors and chartSequentialColors in your theme configuration instead of setting colors on each chart.

Pass the keyword-only alt parameter to every chart, map, and diagram. Screen readers announce it as the chart's name. Describe the chart's takeaway or subject in plain text instead of naming the chart type or listing data.

Python
st.bar_chart(
    df,
    x="category",
    y="revenue",
    alt="Revenue by product line, highest for Enterprise",
)

Markdown isn't rendered in alt, so screen readers announce Markdown syntax literally. For st.echarts_chart, alt replaces the description that ECharts generates from your data, so make it at least as informative.

The simple chart commands take a dataframe and column names. Use color to group series, stack to stack bars and areas, horizontal and sort to arrange bars, and size to size scatter points.

Python
import streamlit as st
from vega_datasets import data

df = data.seattle_weather()

st.line_chart(df, x="date", y=["temp_max", "temp_min"], alt="Daily temperatures in Seattle")

precipitation = df.groupby("weather", as_index=False)["precipitation"].sum()
st.bar_chart(precipitation, x="weather", y="precipitation", alt="Total precipitation by weather type")

If your column names are cryptic, use x_label and y_label to give the axes readable names. For example, for a dataframe with dt and rev columns:

Python
st.line_chart(df, x="dt", y="rev", x_label="Date", y_label="Revenue", alt="Revenue over time")

Move to st.altair_chart when you need a chart title, custom tooltips, layered or dual-axis charts, log scales, faceting, transforms, or selections.

Altair is installed with Streamlit and gives you the full power of Vega-Lite:

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

df = data.stocks()

chart = (
    alt.Chart(df)
    .mark_line()
    .encode(
        x=alt.X("date:T", title="Date"),
        y=alt.Y("price:Q", title="Price (USD)"),
        color=alt.Color("symbol:N", title="Company"),
        tooltip=["date:T", "symbol:N", alt.Tooltip("price:Q", format="$,.2f")],
    )
    .properties(title="Stock prices")
)
st.altair_chart(chart, alt="Stock prices of five tech companies, 2000 to 2010")

Altair normally limits charts to 5,000 rows. Streamlit sends chart data separately, so this limit doesn't apply and you don't need alt.data_transformers.disable_max_rows().

st.echarts_chart accepts an ECharts option as a dictionary, a JSON string, or a pyecharts chart. When your data is in a dataframe, pass it as dataset.source instead of converting columns into lists for series.data or xAxis.data. Always do this for more than about 1,000 rows. Streamlit sends a dataframe source as Arrow, which is faster than inline values, and the chart's toolbar gets a Show data button that displays the dataframe as a table.

Python
import pandas as pd
import streamlit as st

df = pd.DataFrame(
    {
        "product": ["Matcha", "Milk tea", "Cocoa"],
        "2025": [43.3, 83.1, 86.4],
        "2026": [85.8, 73.4, 65.2],
    }
)

st.echarts_chart(
    {
        "legend": {},
        "tooltip": {"trigger": "axis", "valueFormatter": "dollar"},
        "dataset": {"source": df},
        "xAxis": {"type": "category"},
        "yAxis": {},
        "series": [{"type": "bar"}, {"type": "bar"}],
    },
    alt="Sales by product for 2025 and 2026, Matcha up the most",
)

Keep these points in mind:

  • Streamlit doesn't send the dataframe index. Call df.reset_index() to plot it.
  • Graph, sankey, tree, treemap, sunburst, and other series that don't read dataset take their data in series.data (and series.links) instead.
  • Options must be JSON-compatible. JavaScript callbacks, like formatter functions, aren't supported. To format tooltip values without JavaScript, set tooltip.valueFormatter to a number format like "dollar", "compact", or "%,d visits", as you would in st.metric. String templates like "{b}: {c}" also work in labels and tooltips.
  • On a category axis, ECharts reads numbers as 0-based category positions. Pass category labels as strings, and cast numeric category columns, like years, with .astype(str).
  • Text in the option is plain text. Put formatted copy in st.markdown next to the chart.
  • When a rerun changes the data, the chart animates from the old values to the new values. Set key to give the chart a stable identity. Without a key, moving the chart, or changing the spec of a chart with selections, resets it and replays its entry animation.

st.altair_chart, st.vega_lite_chart, st.echarts_chart, st.plotly_chart, and st.pydeck_chart can return the user's selection to your app when you set on_select="rerun" or pass a callback. Each library enables selections differently:

CommandEnable selections withRead the selection from
st.altair_chart and st.vega_lite_chartA named selection parameter, like alt.selection_point("name") or alt.selection_interval("name")event.selection.<name>
st.echarts_chartselectedMode on a series for points, or a brush component for regionsevent.selection.selected and event.selection.areas
st.plotly_chartNo extra configuration. Use selection_mode to limit selections to "points", "box", or "lasso".event.selection.points
st.pydeck_chartAn id on each selectable layer. Use selection_mode="multi-object" to select several objects.event.selection.objects

For example, here's an Altair chart where the user can brush a date range:

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

df = data.seattle_weather()

brush = alt.selection_interval(name="brush", encodings=["x"])
chart = (
    alt.Chart(df)
    .mark_bar()
    .encode(x="date:T", y="precipitation:Q")
    .add_params(brush)
)
event = st.altair_chart(chart, on_select="rerun", key="weather_chart")
st.write(event.selection.brush)
  • st.echarts_chart has no selection_mode parameter. You must enable selections in the ECharts option with selectedMode or a brush component. Otherwise, the chart never returns a selection.
  • ECharts graph and sankey series report selected nodes and edges separately, which makes st.echarts_chart a good choice when users should click through network and flow charts.
  • Set key on Altair, Vega-Lite, ECharts, and pydeck charts to keep the selection when the data changes. Plotly selections reset whenever the figure changes, even with a key.
  • To annotate the returned event, import VegaLiteState, EChartsState, PlotlyState, or PydeckState from streamlit.typing.

Every row in a chart is sent to and processed in the browser. From about 10,000 points per chart, rendering in the browser takes longer than your Python code. Choose the chart command by the number of points:

Points per chartRecommendation
Up to about 10,000Any chart command. Choose by features.
10,000 to 100,000A Vega-based chart or st.echarts_chart.
100,000 to 1,000,000st.echarts_chart. For dense lines, add "sampling": "lttb" to the series.
More than 1,000,000Aggregate the data first.
  • Aggregate in pandas, Polars, or SQL before charting. Vega-Lite transforms like aggregate and bin also run in the browser, on every row.
  • If a chart's data changes often, like with filters or live data, prefer st.echarts_chart from about 50,000 points. It updates faster than Vega-based charts. Reruns that don't change a chart's data are cheap for every chart command.
  • For st.echarts_chart, always pass large data as a dataframe in dataset.source, never as lists.
  • Cache data loading with st.cache_data, and put charts that refresh on a timer in a fragment with run_every.
  • If the data loads slowly, wrap the loading code and the chart in st.skeleton so the chart's space is reserved while it loads. For more information, see Optimizing app performance.

Streamlit automatically sets some rendering options for large charts. Vega-based charts with more than 2,000 per-row marks, like points and bars, render to a canvas instead of SVG. This includes the hover points of st.line_chart, but not the lines and areas of an Altair chart. For charts without selections, st.echarts_chart turns on ECharts' large mode for big scatter and bar series and hides symbols on long line series.

The Vega-based charts and st.echarts_chart cover ordinary 2D charts and match your app's theme more closely, so prefer them for new charts. If you're used to Plotly for interactive charts, st.echarts_chart is usually the closest replacement. It has hover tooltips, zooming, an in-chart toolbox, animated updates, and selections, and it stays fast with large datasets. Plotly selections also reset whenever the figure changes, while ECharts selections persist when you set a key.

  • Use st.plotly_chart for charts that neither Vega-Lite nor ECharts draws: 3D charts, scientific traces like violin, ternary, or carpet plots, or a Plotly figure you already have. Browsers allow only a few WebGL contexts per page, so limit the number of WebGL-based Plotly charts on a page.
  • st.pyplot displays a Matplotlib figure as a static image without zoom, hover, or selections. It doesn't follow your app's theme and renders on the server every rerun. Use it for a figure you already have, or for libraries that only produce Matplotlib output, like seaborn or statsmodels. Pass a Figure, not an Axes. For example, pandas' .plot() returns an Axes, so pass its .get_figure() result.
  • st.map draws points on a basemap without an API token, and its markers use your theme's primary color by default. Use st.pydeck_chart for polygons, arcs, hexagons, heatmaps, 3D, tooltips, multiple layers, or selections.
  • st.mermaid_chart draws flowcharts, sequence diagrams, entity-relationship diagrams, and other Mermaid diagrams, styled for light and dark mode.
  • st.graphviz_chart is for diagrams that need Graphviz layout engines or clusters. It doesn't adapt to your theme, so set node, edge, and font colors explicitly if your app uses a dark theme. Otherwise, prefer st.mermaid_chart.
forum

Still have questions?

Our forums are full of helpful information and Streamlit experts.