グラフを画像にできるようになると、別の企業や指標も同じ画面で見たくなります。毎回Pythonのコードを書き換えるより、画面のプルダウンから選べると、調べたいことに集中できます。
今回から、これまでの計算や比較をブラウザの画面へつなげます。目指すのは、売上高や利益率を見て、別の企業と比較し、気になった数値の元データを確認できる企業分析画面です。
この画面は架空企業のデモです。 実践①〜③で使ったトヨタやHondaの実データとは別です。今回は会員登録やAPIキーを使わず、画面を動かす仕組みに集中します。実データへの切り替えは実践⑧で扱います。
私たち株式会社Crabgrassは、企業の財務データなどをAPIで提供するZENITH Codeを開発しています。本記事は自社サービスのデータを使うためのテンプレートを題材にした実装例です。
前回までに、ZENITH Code実践①で1社の売上高・営業利益の推移を、ZENITH Code実践②で営業利益率の計算とAPIの値との照合を、ZENITH Code実践③で2社の比較を扱いました。
この記事のコードは、公開サンプル集のcompany-analysisテンプレート(執筆時点の版)に対応しています。
1. 今回扱う画面と操作
完成版テンプレートをまず起動し、その中から企業選択・指標選択・描画の3つを読みます。すべてのコードを最初から書き写す必要はありません。動く画面を見ながら、表示が変わる場所を少しずつ追います。
| 操作 | 画面で変わるもの | 今回読むコード |
|---|---|---|
| サンプル企業を選び「表示する」を押す | 企業名、数値カード、グラフ、表、出典 |
loadDemo() と render()
|
| 「業績の推移」の指標を選ぶ | 売上高・営業利益・純利益の棒グラフ |
metric のchangeイベントと chart()
|
| 架空クラウドの営業利益を表示する | 赤字と欠損があるグラフ |
finite() とグラフの欠損処理 |
完成版には決算期選択、比較、CSV保存、表示設定も入っています。これらを詳しく読むのは次回以降です。今回は「入力に応じて同じデータの見せ方が変わる」という流れを押さえます。
2. ローカルで開く準備
公開サンプル集を取得し、そのフォルダをターミナルで開きます。Gitを使う場合は次のとおりです。Gitを使わない場合は、GitHubの「Code」→「Download ZIP」で保存して展開します。
git clone https://github.com/Crab-grass/zenith-code-examples.git
cd zenith-code-examples
Python 3.9以降を使います。追加のPythonパッケージ、Node.js、Matplotlibはこの画面を動かすためには不要です。
zenith-code-examples/
├── python/
│ └── zenith_examples.py
└── templates/
└── company-analysis/
├── server.py
├── index.html
├── style.css
├── workspace.css
├── app.mjs
├── model.mjs
└── demo.json
上は今回使う部分だけを抜き出した図です。server.pyだけを取り出さず、このフォルダ構成のまま使ってください。Python側の共通処理を読み込むため、python/zenith_examples.pyも必要です。サンプル起動では、この共通処理からZENITH CodeのAPIを呼び出すことはありません。
macOSやLinuxでは、取得したフォルダで次を実行します。
python3 templates/company-analysis/server.py --port 8765
Windowsでは、Pythonランチャーを利用する場合は次の形です。
py -3 templates/company-analysis/server.py --port 8765
起動すると、ターミナルに Open http://127.0.0.1:8765 と表示されます。そのURLを同じパソコンのブラウザで開きます。ターミナルは開いたままにしてください。終了するときは、起動したターミナルで Ctrl+C を押します。
127.0.0.1 は、自分のパソコンを指すアドレスです。外部公開用のURLではありません。スマホで同じURLを入力しても、パソコン上の画面にはつながりません。この記事のスマホ画像はブラウザの画面幅を390pxにして確認したものです。実機で共有して試すための公開環境は、今回の手順には含みません。
index.htmlをダブルクリックする方法では、サンプルJSONを配信する窓口が動きません。ファイルを直接開くのではなく、上のPythonプログラムを起動してURLから開く点が、画像を表示するだけの場合との違いです。
3. ファイルの役割
ブラウザに表示されるものは、大きく3つに分かれます。
| 種類 | 役割 | このテンプレート |
|---|---|---|
| HTML | 見出し、ボタン、表、グラフの置き場所 | index.html |
| CSS | 文字、色、余白、画面幅に応じた並び |
style.css、workspace.css
|
| JavaScript | 選んだ企業を読み、数値やグラフを更新 |
app.mjs、model.mjs
|
.mjsはJavaScriptのモジュールを表す拡張子です。app.mjsは画面の操作を担当し、model.mjsには数値やデータ形式を扱う処理を分けています。計算と表示を分けておくと、色や余白を変える作業で数値の扱いまで変えてしまうことを防ぎやすくなります。
Pythonのserver.pyは、これらのファイルとサンプルデータをブラウザへ渡します。サンプル起動では、ブラウザが自分のパソコンにある /api/demo を読みます。これはZENITH Codeの /stable/income-statement とは別の、テンプレート内部の窓口です。
図の上から順に、データを用意し、選択した内容を画面へ表示します。企業や指標を選び直す操作は、すでに読み込んだデータを使います。操作するたびにZENITH CodeのAPIへ通信する仕組みではありません。
4. JSONと画面の対応
demo.jsonは2社分の架空データです。配列の1件が1社にあたり、会社名と、画面に必要なデータをまとめたsnapshotを持ちます。
{
"name": { "ja": "架空精密工業", "en": "Example Precision" },
"snapshot": {
"symbol": "DEMO-A",
"retrievedAt": "2026-10-26T00:00:00Z",
"annualFinancials": [],
"latestClose": []
}
}
これは構造だけを示す抜粋です。上の空配列をサンプルファイルに上書きする手順ではありません。実際のannualFinancialsには3期分、latestCloseには1件の架空データが入っています。
snapshot全体が損益計算書APIの返却形式というわけではありません。損益計算書の配列をannualFinancials、直近終値の配列をlatestCloseに入れ、画面用にまとめた形式です。実践③で保存したrowsや比較CSVを、そのままdemo.jsonへ置き換えることもできません。
| データ | 画面での用途 | 実データ接続時の元 |
|---|---|---|
annualFinancials[].revenue |
売上高カード・棒グラフ・表 | /stable/income-statement |
annualFinancials[].operatingIncome |
営業利益カード・棒グラフ・表 | 同上 |
annualFinancials[].operatingMargin |
営業利益率カード・折れ線グラフ | 同上 |
annualFinancials[].provenance |
書類IDなどの出典欄 | 同上 |
latestClose[].price、priceDate
|
直近終値とその日付 | /stable/quote |
retrievedAt |
自分が取得した日時 | テンプレート側で記録 |
ZENITH Codeの損益計算書ドキュメントで確認した項目名を、そのままグラフと表の対応に使えます。数値だけでなくprovenanceも保持しておくと、画面を作った後から「この値の元書類はどれか」を確認しやすくなります。
今回は画面をコンパクトにするため3期を表示します。実践①の5期と表示件数は違いますが、金額が円、利益率が小数比率という扱いは同じです。
5. 企業を選んだときの処理
app.mjsのloadDemo()が、選択した企業を読み込みます。次はテンプレートのコードの抜粋です。
function loadDemo() {
const company = companies[Number($("company").value) || 0];
current = normalize(company.snapshot);
currentName = company.name;
notice("demoNotice");
render();
}
companiesは読み込み済みのサンプル企業一覧です。$("company")は企業選択欄で、valueに選択した番号が入ります。Number()で文字を数値に変え、配列から該当する企業を取り出しています。
normalize()は、画面で使う前にデータを確認する関数です。対象企業と行のsymbolが一致するか、periodが通期のFYか、同じ決算期が重複していないかを確認し、古い期から順に並べます。条件が壊れたデータを、見た目だけ整えて表示するための処理ではありません。
整えたデータはcurrentへ入ります。render()がこのcurrentを使って、会社名・数値カード・グラフ・表・出典を更新します。カードとグラフに別々の値を手書きしないことが、表示の食い違いを避ける基本になります。
画面で「架空クラウド」を選び、「表示する」を押してください。企業名だけでなく、売上高が76億円、営業利益が6.1億円に変われば、別の企業データが画面へ反映されています。いずれも説明用の架空の値です。
6. 指標を選んだときの処理
次に、「業績の推移」で営業利益を選びます。企業選択とは違い、このプルダウンは選んだ時点でグラフが変わります。
$("metric").addEventListener("change", () => {
if (current) chart("barChart", $("metric").value);
renderApiHelp();
});
changeは選択値が変わったときのイベントです。metricの値には、revenue、operatingIncome、netIncomeのいずれかが入ります。chart()へその項目名を渡すことで、同じ企業・同じ3期のうち、どの数値を描くかを変えています。
renderApiHelp()は、選択した指標に合わせてAPI説明を更新する処理です。説明を開くために追加のデータ取得をするものではありません。画面上部の「表示をカスタマイズ」で「各カードにAPIの説明を表示」を有効にすると、データの項目名と画面の関係を確認できます。
棒や線はSVGで描いています。SVGは、四角形・線・文字などを座標で置く画像形式です。PNGのように完成した画像を差し替えるのではなく、JavaScriptが値に応じて棒の高さやラベルを作り直します。
7. 欠損と赤字の表示
架空クラウドの営業利益には、表示の違いを試せる3つのケースを用意しています。
| 決算期 | 元の値(円) | 画面の意味 |
|---|---|---|
| 2024-03 | -420,000,000 | 営業損失4.2億円。ゼロより下へ棒を描く |
| 2025-03 | null |
未取得。棒を描かず、欠損の表示を残す |
| 2026-03 | 610,000,000 | 営業利益6.1億円。ゼロより上へ棒を描く |
ここでnullを0へ置き換えると、「営業利益がちょうど0円だった」という別の意味になります。テンプレートでは、欠損は欠損のまま扱います。利益率の折れ線でも、値がない期を飛び越えて線をつなぎません。
model.mjsのfinite()は、JavaScriptで有限の数値かを確かめます。nullや文字列の"0"を勝手に数値へ変換せず、扱える数値だけを使います。APIのレスポンス形式が想定と違った場合に、もっともらしいグラフを作らないためです。
表示の単位も確認します。売上高・営業利益・純利益のグラフは億円、財務表の金額は円です。財務表とグラフで見かけの桁が違うのは、元の値が違うのではなく表示単位が違うためです。営業利益率は小数比率を100倍して%で表示します。
8. 小さな変更で処理を確かめる
最初の変更は、初期表示する指標だけにします。index.htmlで、id="metric"の選択肢を探してください。営業利益のoptionにselectedを付けます。
<option value="revenue" data-i18n="revenue"></option>
<option value="operatingIncome" data-i18n="operatingIncome" selected></option>
<option value="netIncome" data-i18n="netIncome"></option>
ファイルを保存し、ブラウザを再読み込みすると、最初に営業利益のグラフが表示されます。これは初期選択を変える変更であり、売上高のデータを削除したり、計算結果を変えたりするものではありません。
app.mjsやCSS、HTMLを変更した場合は、まず保存とブラウザの再読み込みを確認します。demo.jsonはPythonの起動時に読み込むため、そのファイルを変更した場合はサーバーも終了・再起動します。この違いを覚えておくと、「保存したのに変わらない」ときに確認しやすくなります。
9. PCとスマホの並び方
PCでは数値カードを4列、業績と利益率のグラフを左右に並べています。狭い画面ではカードを2列にし、グラフは縦に並べます。画面全体を縮小して文字を小さくする方法ではありません。
長い財務表は、表の範囲だけ横スクロールできます。数値を見比べる場所では列の関係を保ち、見出しや操作ボタンまで画面の外へ押し出さないようにしています。余白、文字サイズ、テーマの変更は実践⑦でまとめて扱います。
10. 起動・表示の確認箇所
| 症状 | 確認箇所 |
|---|---|
| Pythonのファイルが見つからない | 取得したzenith-code-examplesフォルダをターミナルで開いているか |
zenith_examplesが見つからない |
python/を含むフォルダ構成を保っているか |
| ポートが使用中と表示される | すでに起動していないか。別のポートなら--port 8766とURLの両方を変更 |
| HTMLを開いてもデータが出ない |
file://ではなく、Pythonが表示したhttp://127.0.0.1:...から開いているか |
| 別の端末から開けない | このサーバーは同じパソコンから使う設定。スマホ共有用ではない |
| 実データの取得ボタンが押せない | 今回はサンプル起動のため。キーが必要な接続は実践⑧ |
| 欠損の期に棒がない | 0円ではなく、nullの表示か確認 |
コードをAIと一緒に調整する場合も、変更する場所を絞ると確認しやすくなります。
company-analysisテンプレートの初期表示指標を営業利益に変更してください。
対象は index.html の select#metric です。
operatingIncomeを初期選択にしてください。
画面を開いた後は、売上高・営業利益・純利益を引き続き選べるようにします。
JSON、計算処理、APIの呼び出し回数は変更しないでください。
nullを0に変換しないでください。
変更箇所と、ブラウザで確認する操作を説明してください。
この変更にAPIキーや実企業のレスポンスを渡す必要はありません。表示の調整とデータの取得を分けることで、変更後に何を確認すればよいかも明確になります。
11. 財務表と出典へのつながり
今回のグラフは、画面の中の独立した飾りではありません。同じcurrentから財務表や出典も作っています。次回のZENITH Code実践⑤では、グラフで気になった数値を表で確認し、書類ID・発表日時・取得日時をたどる部分を読みます。CSVへ出した数値が画面と同じかどうかも確認します。



