フロントエンド開発者がStreamlitの4つのチャートライブラリを試してみた
こんにちは、Squadbase でフロントエンドエンジニアをしている三橋です。普段は React や TypeScript を使っており Python は初学者レベルですが、先日、Streamlit でデータ可視化のダッシュボードを作る機会があり「どのチャートライブラリを使えばいいのか」で迷いました。そこで、主要な 4 つのライブラリを同じデータで試してみました。この記事では、フロントエンド開発者の視点から感じた各ライブラリの特徴と、初心者でも迷わない選び方を紹介します。
Streamlit で使えるチャートライブラリ
標準で使えるだけでも以下があります。
- Streamlit Native Charts(
st.line_chartなど) - Plotly(
st.plotly_chart) - Altair(
st.altair_chart) - Matplotlib(
st.pyplot) 
検証環境とサンプルデータ
今回は以下の環境で検証しました
# requirements.txt
streamlit==1.28.0
plotly==5.17.0
altair==5.1.2
matplotlib==3.8.1
seaborn==0.12.2
pandas==2.1.3
numpy==1.25.2
サンプルデータは、EC サイトの月別売上データを想定して作成しました。
import pandas as pd
import numpy as np
from datetime import datetime, timedelta
# サンプルデータ生成
dates = pd.date_range(start='2023-01-01', end='2023-12-31', freq='D')
sales_data = pd.DataFrame({
    'date': dates,
    'sales': np.random.normal(100000, 20000, len(dates)).astype(int),
    'category': np.random.choice(['Electronics', 'Clothing', 'Books'], len(dates))
})
# 月別集計
monthly_sales = sales_data.groupby(sales_data['date'].dt.to_period('M'))['sales'].sum().reset_index()
monthly_sales['date'] = monthly_sales['date'].dt.to_timestamp()
検証の観点は以下の 3 点です。
- コードの書きやすさ(学習コスト)
 - 見た目の美しさ(デザイン性)
 - パフォーマンス(データ量による制約)
 
Streamlit Native Charts:3 行で書ける手軽さ
最初に試したのは、Streamlit の標準チャート機能です。
import streamlit as st
# これだけで折れ線グラフが完成
st.line_chart(monthly_sales.set_index('date')['sales'])
たった 3 行で美しいグラフが表示されました。フロントエンドで Chart.js を使う時の初期設定の複雑さを思うと、この手軽さは印象的です。

良い点
- 学習コストがほぼゼロ
 - DataFrame をそのまま渡すだけで動作
 - Streamlit のテーマに自動で合わせてくれる
 
つまずいた点
- 色やラベルをカスタマイズしようとすると急に難しくなる
 - 複数系列の表示で思うようにいかない
 
# 複数系列を表示したくて書いたコード
category_sales = sales_data.groupby(['date', 'category'])['sales'].sum().unstack()
st.line_chart(category_sales)
# → 期待通りの見た目にならず...
一方で、フロントエンドでの UI 開発に慣れていると、細かい調整ができない歯がゆさを感じます。
こんな人におすすめ
プロトタイプ作成や簡単なデータ表示で、カスタマイズ性より手軽さを重視する場合
Plotly:インタラクティブ性は抜群だが制約も
次に試したのがPlotlyです。
import plotly.express as px
import plotly.graph_objects as go
# 基本的な折れ線グラフ
fig = px.line(monthly_sales, x='date', y='sales', title='月別売上推移')
st.plotly_chart(fig, use_container_width=True)
ズームやパンができて、ホバーでデータが見られます。フロントエンドでいう D3.js のようなリッチさがあります。

良い点
- インタラクティブ性が高い
 - 
use_container_width=Trueでレスポンシブ対応 - 見た目が洗練されている
 
ハマった点
- WebGL 制限でグラフの描画数に上限がある
 - API が複雑
 
# 複数のグラフを表示しようとしたら...
for i in range(20):
    fig = px.bar(sample_data, x='category', y='sales', title=f'グラフ {i+1}')
    st.plotly_chart(fig)
# → 16個目以降が表示されない!
各ブラウザには WebGL のコンテキスト数に上限があります。Chrome や Edge では 16 個までしか描画できません (バージョンにより異なる可能性があります)。 そのようなケースでは、 render_mode="svg" を指定することで回避できます。
fig = px.line(plot_df, render_mode='svg')
また、グラフの挙動を操作する API も複雑で、ドキュメントを練り歩く必要があります。
こんな人におすすめ
インタラクティブで美しいグラフが必要で、一ページあたりのグラフ数が爆発しないケース
Altair:宣言的記述が心地よいが 5000 行制限
Altairは、Grammar of Graphics ベースのライブラリです。
import altair as alt
# 宣言的な記述
chart = alt.Chart(monthly_sales).mark_line().encode(
    x='date:T',
    y='sales:Q',
    tooltip=['date:T', 'sales:Q']
).interactive()
st.altair_chart(chart, use_container_width=True)
記述がとても直感的で、「データをこう表現したい」という意図がコードに現れます。React での宣言的 UI 作成に慣れているとこの書き方は自然に感じます。

良い点
- 宣言的な記述でコードが読みやすい
 - パフォーマンスが良い(体感でもかなり早い)
 - JSON で出力されるため軽量
 
困った点
- 5000 行データ制限に引っかかった
 
# 大量データで試したら...
large_data = pd.DataFrame({
    'x': range(6000),
    'y': np.random.randn(6000)
})
chart = alt.Chart(large_data).mark_point().encode(x='x', y='y')
st.altair_chart(chart)
# → MaxRowsError: The number of rows in your dataset is greater than the maximum allowed (5000).
この制限は以下のコードで回避できます:
# 5000行制限の回避
alt.data_transformers.enable('json')
こんな人におすすめ
宣言的な記述を好み、パフォーマンスを重視する場合(データ量に注意)
Matplotlib:定番だが用途を選ぶ
最後に、Python の定番Matplotlibを試しました。
import matplotlib.pyplot as plt
import seaborn as sns
# 基本的な折れ線グラフ
plt.figure(figsize=(10, 6))
plt.plot(monthly_sales['date'], monthly_sales['sales'], marker='o')
plt.title('月別売上推移')
plt.xticks(rotation=45)
plt.tight_layout()
st.pyplot(plt)
「安心の定番ライブラリだから大丈夫」と思っていましたが、予想外の問題に遭遇しました。

良い点
- Python の標準的なライブラリで情報が豊富
 - 細かいカスタマイズも可能
 - 画像出力なので取り回しがいい
 
つまずいた点
- Streamlit のスライダーと組み合わせると激重
 - インタラクティブ性がない
 
# スライダーとの組み合わせ
year = st.slider('年度', 2020, 2023, 2023)
filtered_data = data[data['year'] == year]
plt.figure(figsize=(10, 6))
plt.plot(filtered_data['month'], filtered_data['sales'])
st.pyplot(plt)
# → スライダーを動かすたびに重い描画処理が走る
当然と言えば当然ですが、インタラクティブな UI には向いていないと思います。そもそもが静的な画像で出力されるので、そのまま渡すと「ホバーしても何も出ない」みたいなフィードバックが来るかもしれません。
こんな人におすすめ
静的なグラフで細かいカスタマイズが必要な場合、または統計的な可視化を行う場合
実際の使い分けと選定基準
4 つのライブラリを試した結果、以下の使い分けが見えてきました。
初心者向け学習順序
- Streamlit Native Chartsでグラフ作成に慣れる
 - Plotlyでインタラクティブ性を体験
 - Altairで宣言的記述を学ぶ
 - Matplotlibで細かいカスタマイズを覚える
 
個人的な推奨度
| ライブラリ | 推奨度 | 学習コスト | 理由 | 
|---|---|---|---|
| Plotly | ★★★★★ | 中 | バランスが良く、制約を理解すれば最強 | 
| Altair | ★★★★☆ | 中 | 宣言的記述が美しく、パフォーマンスも良い | 
| Streamlit Native | ★★★☆☆ | 低 | 学習用には最適、カスタマイズ性は物足りない | 
| Matplotlib | ★★☆☆☆ | 中 | Streamlit では使いにくい、Jupyter 向け | 
まとめ
フロントエンド開発者の視点から 4 つのライブラリを比較してみて、以下のことが分かりました。
Streamlit でのグラフ作成は、意外と制約が多い
WebGL コンテキスト制限(Plotly)や 5000 行制限(Altair)など、実際に使ってみないと分からない制約があります。
初心者には学習順序が重要
いきなり複雑なライブラリから始めると挫折します。Streamlit Native → Plotly → Altair の順序で学習するのがおすすめです。
用途に応じた使い分けが大切
「とりあえず Plotly」ではなく、データ量やインタラクティブ性の要件に応じて選択することで、より良いユーザー体験が作れます。
これから Streamlit でデータ可視化を始める方の参考になれば幸いです。
実際のプロジェクトでは、要件に応じて複数のライブラリを使い分けることも多いですが、まずは一つのライブラリを深く理解することから始めることをおすすめします。
Squadbase では、データ可視化を含むインターナルアプリ開発の知見を発信しています。よろしければ覗いてみてください!
Discussion