目次
Pythonでデータ可視化を扱っていると、グラフをブラウザで他の人にも見せたい場面ってありますよね。Plotlyの Dash を使うと最小15行くらいで動くWebダッシュボードが作れるので、最小構成から段階的に組み上げる流れを入門のメモとして残しておきます[1]。
Dashとは
DashはPlotly社が開発するオープンソースのPythonフレームワークで、Webダッシュボード(ブラウザで動くデータ可視化アプリ)をPythonだけで作れる仕組みです。HTMLやJavaScriptを書かずに済むのが特徴で、Webアプリ開発に詳しくないデータ分析者でも、ある程度本格的なダッシュボードを構築できます[1:1]。
Dashの立ち位置(StreamlitやGradioとの違い)
PythonでWebアプリを作る選択肢は他にもあります。代表格との違いを把握しておくと、用途に合っているかが判断しやすくなります[2]。
| 比較軸 | Dash | Streamlit | Gradio |
|---|---|---|---|
| 主用途 | 本格的なダッシュボード | 軽量なデータアプリ | 機械学習モデルのデモUI |
| 学習コスト | やや高め(コード量多) | 低い(Python感覚で書ける) | 低い |
| カスタマイズ性 | 高い | 中 | 低い |
| 実行モデル | 必要なコールバックだけ実行 | スクリプト全体を毎回再実行 | 関数1つで完結 |
ざっくり言えば「軽く試したいならStreamlit、本格的に組みたいならDash、MLのデモならGradio」という棲み分けです。本記事の対象はDashです。
環境構築
DashはPythonパッケージdashをインストールするだけで使えます。最近のPython開発ではuvというRust製のパッケージ管理ツールが事実上の標準になりつつあるので[3]、本記事もuvを使う前提で進めます。
uv自体の入門は別記事にまとめました。インストール方法やコマンドの全体像はこちらを参照してください。
uvが使える状態であれば、Dashプロジェクトは次の3コマンドで一気に整います。
uv init dash-sample
cd dash-sample
uv add dash
uv initでプロジェクトの初期化、uv addで依存パッケージの追加と仮想環境の準備までが一括で完了します。pipとvenvを別々に叩く手数が要りません。
最小のDashアプリ
まずは本当に最小限から始めます。app.pyというファイルを作って、下記の数行を書くだけでDashアプリは起動します。グラフも入力欄もまだありません[4]。
from dash import Dash, html
app = Dash(__name__)
app.layout = html.H1("Hello Dash")
if __name__ == "__main__":
app.run(debug=True)
実行します。
uv run app.py
ブラウザでhttp://127.0.0.1:8050/を開くと、Hello Dashという大きな見出しだけが表示された白い画面が出ます。これがDashアプリとして成立する最小単位です。
コードの読み解き
このわずか5行に、Dashアプリの骨格が全部入っています。
Dash(__name__)— Dashアプリのインスタンスを作ります。内部的にはFlaskというPythonのWebサーバーが起動します。__name__はPythonの慣例で「いまこのファイル自身」を指す変数で、Dashがリソースの場所を特定するために使います。app.layout— このアプリの画面に何を表示するかを定義する場所です。今回はH1要素ひとつだけ。html.H1("Hello Dash")— HTMLの<h1>Hello Dash</h1>に相当するものをPythonで表現したものです。dash.htmlモジュールの中に、HTMLタグに対応するクラスが一通り用意されています。app.run(debug=True)— Dashの開発用サーバーを起動します。debug=Trueにしておくと、コードを変更したときに自動でブラウザが更新されるホットリロードが効きます。
ここまでで、「PythonでHTMLを組み立てて、それをサーバーで配信する」というDashアプリの基本動作が掴めるはずです。
レイアウトの基本
実用的なアプリでは、見出しひとつではなく複数の要素を並べたいことがほとんどです。Dashではhtml.Div(HTMLの<div>要素に相当)を使って、要素のグループを表現します。
from dash import Dash, html
app = Dash(__name__)
app.layout = html.Div([
html.H1("売上ダッシュボード"),
html.P("ここに売上データを表示する予定です。"),
])
if __name__ == "__main__":
app.run(debug=True)
uv run app.pyで起動してブラウザで開くと、見出しの下に説明文が表示されます。
html.Divの引数にリストを渡すと、その中の要素が縦に並びます。HTMLでいう「親タグの中に子タグを入れていく」構造を、Pythonのリストで表現しているわけです。
HTMLタグとの対応
dash.htmlモジュールには、HTMLタグに対応するクラスが揃っています。よく使うものは次のあたりです。
| Dashのクラス | 対応するHTML | 用途 |
|---|---|---|
html.Div |
<div> |
要素のグループ化 |
html.H1 〜 html.H6 |
<h1> 〜 <h6> |
見出し |
html.P |
<p> |
段落 |
html.A |
<a> |
リンク |
html.Img |
<img> |
画像 |
html.Ul / html.Li |
<ul> / <li> |
リスト |
属性は引数で指定します(例: html.A("クリック", href="https://example.com"))。children引数にリストを渡すと中の要素が並びます。HTMLが分かる人なら、ほぼ直感的に書けます。
Dash独自コンポーネント(dcc)を使う
ここまでは普通のHTML要素しか使っていません。ただ、Dashの本領はPlotlyのグラフやリッチな入力部品がほとんど設定なしで使える点にあります。これらはdash.dcc(Dash Core Components)モジュールにまとまっています[5]。
棒グラフを追加するなら、HTMLでゼロから書こうとするとJavaScriptを使って何十行も書くことになりますが、Dashなら次の数行で済みます。
from dash import Dash, html, dcc
app = Dash(__name__)
app.layout = html.Div([
html.H1("売上ダッシュボード"),
html.P("月ごとの売上を棒グラフで表示します。"),
dcc.Graph(
id="sales-graph",
figure={
"data": [
{"x": ["1月", "2月", "3月"], "y": [120, 80, 150], "type": "bar"},
],
"layout": {"title": "売上(万円)"},
},
),
])
if __name__ == "__main__":
app.run(debug=True)
uv run app.pyで実行するとブラウザに棒グラフが表示されます。マウスホバーで数値が出たり、ドラッグで拡大できたりと、最初からインタラクティブな操作が効きます。
dccにあるものは何か
dccにある主な部品は次の通りです。
dcc.Graph— Plotlyグラフ(棒、折れ線、散布図、地図など)dcc.Input— テキスト入力欄dcc.Dropdown— 選択リストdcc.Slider— スライダーdcc.DatePickerSingle/dcc.DatePickerRange— 日付ピッカーdcc.Markdown— Markdownを描画dcc.Tabs/dcc.Tab— タブ切り替え
「htmlでできることは普通のHTML要素、dccで得られるのは"Plotly + Dash独自"のリッチな部品」と覚えておくと使い分けがすっきりします。
インタラクティブにする(コールバック)
ここまでは表示するだけで、ユーザー操作で画面が変わりませんでした。Dashの コールバック を使うと「入力部品の値が変わったら、別の要素を更新する」動きを宣言的に書けます[6]。
先ほどの売上ダッシュボードに、月数を選ぶとそこまでの売上を表示するスライダーを追加してみます。
from dash import Dash, html, dcc, Input, Output
app = Dash(__name__)
# サンプルの月別売上データ
months = ["1月", "2月", "3月", "4月", "5月", "6月"]
sales = [120, 80, 150, 200, 130, 170]
app.layout = html.Div([
html.H1("売上ダッシュボード"),
html.P("スライダーで表示する月数を変えられます。"),
dcc.Slider(
id="month-slider",
min=1, max=6, step=1, value=3,
marks={i: f"{i}月" for i in range(1, 7)},
),
dcc.Graph(id="sales-graph"),
])
@app.callback(
Output("sales-graph", "figure"),
Input("month-slider", "value"),
)
def update_graph(selected_month):
return {
"data": [
{"x": months[:selected_month], "y": sales[:selected_month], "type": "bar"},
],
"layout": {"title": f"1月〜{selected_month}月の売上(万円)"},
}
if __name__ == "__main__":
app.run(debug=True)
uv run app.pyで起動してスライダーを動かすと、棒グラフがリアルタイムで更新されます。スライダーを「3」に動かせば1月〜3月、「5」に動かせば1月〜5月の売上が表示されます。
コールバックの読み解き
@app.callbackの中身がDashの心臓部です。
Output("sales-graph", "figure")— 結果の出力先。「id="sales-graph"の要素のfigureプロパティを更新する」と宣言しています。Input("month-slider", "value")— 入力源。「id="month-slider"の要素のvalueが変わったら関数を呼ぶ」と宣言しています。- 関数
update_graph(selected_month)— 入力値(スライダーの現在値)を受け取って、グラフ用の辞書を返します。返した値がOutputで指定した先に反映されます。
どこの何が変わったら、どこの何を、こう変える を宣言的に書くスタイルです。この仕組みのおかげで、ページ全体をリロードせず、必要な部分だけ高速に更新できます。Streamlitとの大きな違いの1つで、Streamlitはスクリプト全体を毎回再実行します。
さらに学ぶためのリファレンス
入門としてはここまでで全体像が掴めますが、実用的なダッシュボードを作るには各コンポーネントの細かいパラメータや、より複雑なコールバックが必要になります。次のリファレンスを手元に置いておくと便利です。
- 公式チュートリアル: Dash in 20 Minutes Tutorial — 入門の続き
- HTMLコンポーネント一覧: Dash HTML Components —
html.*の全リファレンス - Dash独自コンポーネント一覧: Dash Core Components —
dcc.*の全リファレンス - コールバックの応用: Advanced Callbacks — 複数入力・状態管理・条件分岐など
- Plotlyのグラフ仕様: Plotly Python Open Source Graphing Library —
dcc.Graphで使うグラフの定義方法
Dashを選ばないほうがいい場面
Dashが向かないケースもあります。ユーザー操作が少なく、レポート形式の静的なグラフを並べたいだけ、というような要件なら、Streamlitの方が記述量が少なくて済みます。プロトタイプを30分でひとまず動くところまで持っていく速度はStreamlitの方が上です。
逆に、コールバック設計をきちんと組み立てて、画面のどこを誰が更新するかを明示的に制御したい本番ダッシュボードなら、Dashの設計思想がフィットします。「カスタマイズ性と性能を優先」「コード量がそこそこ増えても許容」という軸で選ぶと納得しやすい選択になります。
参考文献
Dash for Python Documentation - Plotly (2026-05-11 アクセス) ↩︎ ↩︎
Gradio vs Streamlit vs Dash vs Flask - Towards Data Science (2026-05-11 アクセス) ↩︎
uv - Astral (2026-05-11 アクセス) ↩︎
A Minimal Dash App - Plotly Documentation (2026-05-11 アクセス) ↩︎
Dash Core Components - Plotly Documentation (2026-05-11 アクセス) ↩︎
Part 2. Basic Callbacks - Plotly Documentation (2026-05-11 アクセス) ↩︎
