
1. 導入:なぜ、素晴らしいAIモデルだけでは不十分なのか?
想像してみてください。あなたは世界最高峰のシェフが作った、栄養満点で味も完璧な「究極のスープ」を持っています。しかし、そのスープはお皿に入っておらず、重たい鍋のまま、しかもお玉もスプーンもない状態でテーブルに置かれています。
目の前の患者さん(あるいは医療スタッフ)は、どうやってそのスープを飲めばいいのでしょうか?
これまでの講義で作ってきた PythonのAIモデル は、まさにこの「鍋に入ったままのスープ」です。計算能力は凄まじく、予測精度も高いかもしれません。しかし、黒い画面(ターミナル)に文字の羅列だけで結果が表示されるシステムを、分刻みのスケジュールで動く忙しい診察室の医師や看護師が使いこなせるでしょうか?
恐らく、その答えは「No」です。現場で実際に使われるためには、誰でも直感的に操作でき、一目で結果がわかる「器」と「スプーン」が必要です。それが ユーザーインターフェース(UI) です。
本講義では、Web開発の標準技術である JavaScript (React) を使い、あなたのPython AIモデルに「使いやすい画面」という架け橋をかける方法を学びます。これは単なる「見た目」の話ではありません。技術を現場に届け、実際に価値を生むための「ラストワンマイル」をつなぐ、極めて重要な工程なのです。

2. 医療UI開発を支える「三種の神器」
医療現場で「本当に使ってもらえる」システムを作るためには、信頼性が高く、かつ直感的に操作できるインターフェースが不可欠です。本コースでは、世界中のモダンなWeb開発現場で標準的に採用されている、以下の3つの技術(道具)を「三種の神器」として採用します。

① React(リアクト):変幻自在の「レゴブロック」
- 正体: Meta社(旧Facebook)が開発した、ユーザーインターフェース(UI)を作るためのJavaScriptライブラリです。
- 役割とメリット:
- 「部品」で作る: Reactの最大の特徴は、画面を「コンポーネント」と呼ばれる小さな部品(ボタン、入力フォーム、ヘッダーなど)に分けて作ることです。これはまさにレゴブロックのようなものです。一度作った「患者検索バー」というブロックは、他の画面でも使い回すことができます。
- データと見た目の同期: 従来の技術では、データが変わるたびに画面を書き換える命令が必要でしたが、Reactは「データが変われば、画面も自動的に更新される」という仕組み(リアクティブ)を持っています。刻一刻と変化するバイタルサインを表示する医療モニターのようなシステムに最適です。
② TypeScript(タイプスクリプト):医療ミスを防ぐ「安全装置」
- 正体: Microsoftが開発したプログラミング言語で、JavaScriptの「進化版(スーパーセット)」です。
- 役割とメリット:
- 「型」による保証: 通常のJavaScriptは非常に自由度が高い反面、「数値を入れるべき場所に、間違って文字を入れても動いてしまう」という危うさがあります。TypeScriptは、データに「これは数値(Number)」「これは文字列(String)」といった「型(Type)」というラベルを貼ることで、コードを書く段階でミスを検知します。
- 医療における意義: 例えば、「患者ID(数値)」と「病室番号(数値)」を取り違えたり、投薬量(数値)に単位(文字)が混入して計算エラーになったりすることは、医療システムでは許されません。TypeScriptは、こうしたケアレスミスを未然に防ぐ強力な安全装置として機能します (Gao et al. 2017)。
③ Chart.js(チャート・ジェイエス):データの「翻訳機」
- 正体: データを美しく、インタラクティブなグラフとして描画するためのライブラリです。
- 役割とメリット:
- 数字を「意味」に変える: 電子カルテに並ぶ「120, 118, 125…」という血圧の数値データも、折れ線グラフにすれば「上昇傾向にある」ことが一目でわかります。Chart.jsは、無機質なデータの羅列を、医療従事者が瞬時に判断できる「視覚情報」へと翻訳します。
- 手軽さと美しさ: 複雑な設定なしで、アニメーション付きの洗練されたグラフを表示できるため、ダッシュボード開発の第一歩として最適です。
3. なぜUIデザインが「医療安全」に関わるのか?
「たかが画面のデザインでしょ?動けばいいんじゃないの?」
エンジニアや研究者が陥りがちなこの考えは、医療現場においては致命的なリスクを孕んでいます。なぜなら、使いにくいシステムは単なるストレスの原因になるだけでなく、患者の命に関わる重大な医療ミスを引き起こす可能性があるからです。

データが語る「悪いUI」の恐ろしさ
米国食品医薬品局(FDA)が行ったリコール(製品回収)データの分析は、衝撃的な事実を明らかにしています。
- ソフトウェア原因のリコールの約半数が、バグやアルゴリズムの誤りではなく、ユーザーインターフェース(UI)の設計ミスに起因していました (Alvaro et al. 2019)。
つまり、AIの予測がどれほど正確でも、それを表示する画面がわかりにくければ、その機器は「欠陥品」として市場から排除される可能性があるのです。
「わかりにくさ」が招く医療事故のシナリオ
具体的に、UIの設計ミスがどのような事故につながるのか、対照的な例を見てみましょう。
| 悪いUIの例(事故の元) | 良いUIの例(安全装置) | |
|---|---|---|
| 状況 | 心拍数が低下し、アラートが鳴った | 心拍数が低下し、アラートが鳴った |
| 画面表示 | 小さな文字で「Error Code: 403」と表示されるだけで、どの患者か、何が起きたか即座にわからない。 | 画面全体が赤く点滅し、大きな文字で「〇〇号室:心拍低下」と表示される。 |
| 結果 | 対応が遅れ、最悪の場合、救命の機会を逃す。 | 医療スタッフが瞬時に状況を理解し、処置に向かうことができる。 |
FDAが求める「人間中心」の設計
こうした背景から、FDAはガイダンス(指針)において、医療機器開発におけるヒューマンファクター工学(人間工学)の適用を強く推奨しています (FDA 2016)。
これは、「人間はミスをする生き物である」という前提に立ち、疲労や焦りがあっても誤操作しにくいデザイン(ユーザビリティ)を設計段階から組み込むことを求めているのです。私たちがこれから作る画面は、単なるデータの表示板ではありません。医療従事者の認知負荷を下げ、医療ミスを水際で防ぐための防波堤なのです。
4. 実践:FastAPIとReactを連携させる
理論の学習お疲れ様でした。ここからは、いよいよ手を動かして「動くアプリケーション」を作っていきましょう。
今回のシステム構成を、レストランに例えてイメージしてみてください。

- Backend (Python/FastAPI):
ここは「厨房」です。AIモデルという熟練シェフがいて、データという食材を調理し、提供できる形に加工します。しかし、厨房はお客さん(ユーザー)からは見えません。 - Frontend (React/TypeScript):
ここは「ホール(客席)」です。厨房で作られた料理(データ)を受け取り、綺麗なお皿(グラフ)に盛り付けて、お客さんに提供します。
この2つをつなぐのがAPI(Application Programming Interface)、つまり「注文票」のやり取りです。それでは、厨房作りから始めましょう。
🤔 素朴な疑問:フロントエンドは「どこ」で動いているの?
ここで、鋭い方は一つの疑問を持つかもしれません。
「『ホール』と『厨房』って言うけど、物理的にはどこにあるの?私のパソコンの中?」
この「場所」の理解こそが、Webシステムを理解する最大の鍵です。結論から言うと、この2つは物理的に全く別の場所で動いています。
1. 物理的な距離:ブラウザ vs サーバー
- フロントエンド(React)= あなたのブラウザ(手元)
- あなたがWebサイトにアクセスした瞬間、Reactのプログラム一式がサーバーからあなたのパソコン(ブラウザ)にダウンロードされます。
- そして、あなたのパソコンのパワー(CPU/メモリ)を使って、画面を描画します。つまり、ホールは「あなたの目の前」に設営されるのです。
- バックエンド(FastAPI)= サーバー(遠くのデータセンター)
- Pythonのプログラムは、あなたのパソコンには来ません。AmazonやGoogleが管理する遠く離れたデータセンター(クラウド)の中にずっと居座っています。
- 厨房は「立ち入り禁止の奥の部屋」であり、そこには機密情報(患者データベース)や高価な設備(AI用のGPU)があります。
2. なぜ分ける必要があるのか?
「全部自分のパソコンで動かせば速いのでは?」と思うかもしれませんが、分けることには明確な理由があります。
| 理由 | 解説 |
|---|---|
| セキュリティ (防犯) | もしPythonコード(厨房)もブラウザに送ってしまうと、コードの中に書かれた「データベースのパスワード」や「AIの秘密のロジック」が、ユーザーに丸見えになってしまいます。秘密を守るために、厨房は遠くに隔離する必要があります。 |
| パフォーマンス (設備) | 医療AIのような高度な計算には、高性能なコンピュータ(GPU)が必要です。ユーザーの一般的なノートPCやスマホでは処理しきれません。重い処理は、設備が整ったサーバー(厨房)に任せるのが効率的です。 |
3. APIがつなぐ「見えない糸」
物理的に離れた「手元のブラウザ(React)」と「遠くのサーバー(FastAPI)」をつなぐのが、インターネットというウェイターです。

これから行う「FastAPIとReactの連携」とは、この「遠距離通話の仕組み」を作ることと同義です。それでは、まずは遠くで待機する「厨房(バックエンド)」の構築から始めましょう。
ステップ1:バックエンドの準備(厨房を作る)
まずは、データを提供するPython側のサーバーを作ります。今回はAIモデルの代わりに、架空の患者バイタルデータを生成して返すシンプルなAPIを用意します。
1. 必要な道具のインストール
ターミナル(またはコマンドプロンプト)で以下のコマンドを実行し、ライブラリをインストールします。
pip install fastapi uvicorn
- fastapi: 高速なAPIサーバーを作るためのフレームワークです。
- uvicorn: 作ったAPIサーバーを実際に動かすための土台(Webサーバー)です。
2. サーバーの実装
以下のコードを backend/main.py として保存してください。
# ==========================================
# 1. 必要な「道具(ライブラリ)」を準備する
# ==========================================
# FastAPI: 高速なWebサーバーを作るためのメインの道具です
from fastapi import FastAPI
# CORSMiddleware: セキュリティ(ブラウザからのアクセス許可)を設定するための道具です
from fastapi.middleware.cors import CORSMiddleware
# random: 偽のデータを作るために、ランダムな数字を作り出す道具です
import random
# datetime, timedelta: 日付や時間を扱うための道具です
from datetime import datetime, timedelta
# ==========================================
# 2. サーバー(厨房)を立ち上げる
# ==========================================
# FastAPIというアプリ(厨房)の実体を作ります。
# これがサーバーの本体になります。
app = FastAPI()
# ==========================================
# 3. セキュリティ(CORS)の設定
# ==========================================
# 【重要】ブラウザ(React)とサーバー(FastAPI)をつなぐための許可証発行
# 解説:通常、Webブラウザはセキュリティのため、異なる場所(ポート)への接続を拒否します。
# これを書くことで「React(localhost:5173)からのお客さんは通していいよ」と設定します。
app.add_middleware(
CORSMiddleware,
# 許可するオリジン(アクセス元)。今回はVite(React)の標準ポートを指定。
allow_origins=["http://localhost:5173"],
# クッキーなどの認証情報を含めることを許可するか(今回はTrue)
allow_credentials=True,
# 許可するHTTPメソッド(GETやPOSTなど)。"*"は「全部OK」という意味。
allow_methods=["*"],
# 許可するヘッダー情報。"*"は「全部OK」という意味。
allow_headers=["*"],
)
# ==========================================
# 4. API(注文窓口)を作る
# ==========================================
# @app.get(...): 「デコレーター」と呼ばれる飾りです。
# 「もし /api/vitals というURLにアクセス(注文)があったら、下の関数を実行してね」という看板です。
@app.get("/api/vitals")
def get_patient_vitals():
"""
【厨房の仕事:バイタルデータの提供】
ここが実際にデータを作る「調理場」です。
アクセスされるたびに実行されます。
"""
# データを貯めるための空のリスト(お皿)を用意します
data = []
# 今日の日付を取得します(基準日)
base_date = datetime.now()
# 【重要】乱数の「シード(種)」を固定します。
# これを書くと、何度実行しても「同じパターンのランダムな数値」が出ます。
# 学習中に「さっきとグラフの形が違う!」と混乱しないための工夫です。
random.seed(42)
# 過去7日分(0から6まで)のデータをループで作ります
for i in range(7):
# 計算:基準日から「6-i」日分、過去に戻った日付を計算します
# i=0なら6日前、i=6なら0日前(今日)になります
target_date = base_date - timedelta(days=6-i)
# 1日分のデータ(辞書型)を作って、リスト(お皿)に追加します
data.append({
# strftime: 日付データを "2026-02-04" のような文字列に変換します
"date": target_date.strftime("%Y-%m-%d"),
# randint(a, b): aからbの間でランダムな整数を作ります
"sbp": random.randint(110, 140), # 収縮期血圧(上の血圧)
"dbp": random.randint(70, 90), # 拡張期血圧(下の血圧)
"hr": random.randint(60, 100) # 心拍数
})
# 【提供】作ったデータをJSON形式(Webで使いやすい形式)で返します。
# FastAPIが自動的にPythonの辞書をJSONに変換してくれます。
return {"patient_id": "P001", "vitals": data}
# ==========================================
# 5. サーバーを起動する(開店スイッチ)
# ==========================================
# 「このファイルが直接実行されたときだけ」以下のコードを動かす、というおまじないです。
if __name__ == "__main__":
# サーバーを動かすためのエンジン(Uvicorn)をインポートします
import uvicorn
# サーバーを起動します
# host="0.0.0.0": どこからでもアクセスOKにする設定
# port=8000: 8000番ポート(窓口)を開く
uvicorn.run(app, host="0.0.0.0", port=8000)
ステップ2:フロントエンドの構築(ホールを作る)
次に、データを受け取ってグラフ表示する画面を作ります。今回は、Vite (ヴィート) という非常に高速なビルドツールを使います。
1. プロジェクトの作成
ターミナルで以下のコマンドを順番に実行してください。(※Node.jsがインストールされている必要があります)
# ==========================================
# 1. お店(プロジェクト)の土台を作る
# ==========================================
# npm create: 「新しいプロジェクトを作って!」という命令です。
# vite@latest: 「Vite(ヴィート)」という最新の高速ビルドツールを使います。
# medical-dashboard: 作成するフォルダの名前です。
# -- --template react-ts: 「React」と「TypeScript」が入ったセットを選びます。
# 解説:これで「ホールの設計図一式」がダウンロードされます。
npm create vite@latest medical-dashboard -- --template react-ts
# ==========================================
# 2. お店の中に入る
# ==========================================
# cd (Change Directory): 今いる場所を移動するコマンドです。
# さっき作った「medical-dashboard」というフォルダの中に入ります。
# これを忘れると、関係ない場所で作業することになるので注意!
cd medical-dashboard
# ==========================================
# 3. お店で使う「備品」を仕入れる(本番用)
# ==========================================
# npm install: 指定したライブラリ(部品)をインターネットからダウンロードしてきます。
# ここで入れるのは「お客さんに提供する機能」に関わる重要な部品です。
#
# - chart.js: グラフを描くための本体(絵筆とキャンバス)
# - react-chartjs-2: ReactでChart.jsを使いやすくするためのアダプター
# - axios: 厨房(FastAPI)に電話をかけてデータを注文するための通信機
npm install chart.js react-chartjs-2 axios
# ==========================================
# 4. 内装工事用の「道具」を仕入れる(開発用)
# ==========================================
# -D (または --save-dev): 「これは開発中(工事中)にしか使いません」という印です。
# お客さんのブラウザにはこれらは送られません。
#
# - tailwindcss: CSSを直接書かずに、クラス名だけでデザインできる便利なツール
# - postcss: CSSを変換するための土台
# - autoprefixer: 古いブラウザでもデザインが崩れないように自動調整してくれる道具
npm install -D tailwindcss postcss autoprefixer
# ==========================================
# 5. デザインツールの初期設定をする
# ==========================================
# npx: 「インストールせずに一度だけツールを実行する」ためのコマンドです。
# tailwindcss init: Tailwind CSSの設定ファイル(tailwind.config.js)を作ります。
# -p: 一緒にPostCSSの設定ファイル(postcss.config.js)も作ってね、というオプション。
# これを実行すると、フォルダに設定ファイルが2つポンと生まれます。
npx tailwindcss init -p
※ tailwind.config.js と index.css の設定は、Tailwind CSSの公式ドキュメントに従って設定してください(本記事では簡略化のため、スタイル調整の詳細は割愛します)。
2. グラフコンポーネントの実装
src/App.tsx を以下のコードに書き換えます。これが画面の「設計図」になります。
Reactの重要な機能である「Hooks(フック)」を使って、データの取得と表示を制御しています。
// ==========================================
# 1. 必要な「道具」を倉庫から持ってくる
// ==========================================
// Reactの基本機能をインポート
// - useEffect: 画面が表示されたタイミングで何かする(データの注文など)ための機能
// - useState: 画面上の「変化する値(データやロード中などの状態)」を管理する機能
import { useEffect, useState } from 'react';
// axios: 厨房(FastAPI)に電話をかけるための通信ツール
import axios from 'axios';
// Chart.js(グラフ描画ツール)から、今回使う部品だけを選んでインポート
// 解説:全部読み込むと重くなるので、使うものだけ「指名」して持ってきます。
import {
Chart as ChartJS,
CategoryScale, // X軸(カテゴリー)を描く定規
LinearScale, // Y軸(数値)を描く定規
PointElement, // 折れ線グラフの「点」
LineElement, // 折れ線グラフの「線」
Title, // グラフのタイトル
Tooltip, // マウスを乗せた時に出る詳細表示
Legend, // 凡例(「赤線は血圧ですよ」みたいな説明)
} from 'chart.js';
// Reactの中でChart.jsを使いやすくした「Line(折れ線グラフ)」コンポーネント
import { Line } from 'react-chartjs-2';
// ==========================================
# 2. 道具の手入れ(初期登録)
// ==========================================
// 持ってきた部品をChart.js本体に登録します。
// これをやらないと「え?線を引く道具なんて持ってないよ?」と怒られます。
ChartJS.register(
CategoryScale,
LinearScale,
PointElement,
LineElement,
Title,
Tooltip,
Legend
);
// ==========================================
# 3. データの「型(設計図)」を作る
// ==========================================
// 【TypeScriptの強み】
// 「バイタルデータ」とはこういう形ですよ、とあらかじめ決めておきます。
// これがあると、sbp(血圧)と書くところを sap と書き間違えても、エディタが赤線で教えてくれます。
interface VitalData {
date: string; // 日付は文字
sbp: number; // 数値
dbp: number; // 数値
hr: number; // 数値
}
// APIから返ってくる「注文の品(JSON)」全体の形です。
interface ApiResponse {
patient_id: string;
vitals: VitalData[]; // VitalDataがたくさん入ったリスト(配列)
}
// ==========================================
# 4. 画面を作るメインの部品(コンポーネント)
// ==========================================
function App() {
// 【状態管理(useState)】
// ここは「ホワイトボード」のようなものです。データが変わると、画面も自動で書き換わります。
// 1. グラフ用データ置き場
// <VitalData[]> は「ここにはVitalDataのリストしか入れないぞ!」という宣言です。
// ([]): 最初は空っぽのリストにしておきます。
const [chartData, setChartData] = useState<VitalData[]>([]);
// 2. 準備中かどうか(ローディング)
// true: 「ただいま準備中」 / false: 「営業中(データ表示)」
const [loading, setLoading] = useState<boolean>(true);
// 【副作用(useEffect)】
// 画面が表示された「直後」に1回だけ実行される処理です。
// お店がオープンした瞬間に、厨房へ注文を流すイメージです。
useEffect(() => {
// 非同期処理(完了を待つ必要がある処理)をするための関数を作ります
const fetchData = async () => {
try {
// axiosを使って、FastAPIサーバー(localhost:8000)に「電話」をかけます
// await: 「厨房から返事が来るまで、ここで待機!」という命令です。
const response = await axios.get<ApiResponse>('http://localhost:8000/api/vitals');
// データが届いたら、ホワイトボード(State)を更新します
// これを実行した瞬間、Reactが画面を再描画(リフレッシュ)します。
setChartData(response.data.vitals);
// データが届いたので「準備中」の看板を下ろします
setLoading(false);
} catch (error) {
// エラーが起きたらコンソール(開発者ツール)に表示
console.error("データの取得に失敗しました:", error);
setLoading(false); // エラーでも一応ローディングは終わらせる
}
};
// 上で作った関数を実行します
fetchData();
}, []); // 【重要】この [] は「最初の一回だけ実行してね」という意味です。忘れると無限ループします!
// ==========================================
# 5. グラフの設定(お皿への盛り付け)
// ==========================================
// グラフに渡すデータを整形します
const data = {
// 横軸(X軸)のラベル:データの「日付」だけを取り出して並べます
labels: chartData.map((d) => d.date),
// グラフの線ごとの設定
datasets: [
{
label: '収縮期血圧 (SBP)', // 線の名前
data: chartData.map((d) => d.sbp), // 縦軸のデータ:血圧(上)だけを取り出す
borderColor: 'rgb(255, 99, 132)', // 線の色(赤)
backgroundColor: 'rgba(255, 99, 132, 0.5)', // 塗りつぶしの色
},
{
label: '拡張期血圧 (DBP)',
data: chartData.map((d) => d.dbp), // 縦軸のデータ:血圧(下)だけを取り出す
borderColor: 'rgb(53, 162, 235)', // 線の色(青)
backgroundColor: 'rgba(53, 162, 235, 0.5)',
},
],
};
// グラフの見た目のオプション(タイトルなど)
const options = {
responsive: true, // 画面サイズに合わせて大きさを変える
plugins: {
legend: { position: 'top' as const }, // 凡例を上に表示
title: {
display: true,
text: '週間バイタルデータ推移', // タイトル文字
},
},
};
// ==========================================
# 6. 最終的な画面表示(レンダリング)
// ==========================================
// ここで書いたHTML(に見えるJSX)が、実際のブラウザに表示されます。
return (
<div style={{ padding: '20px', fontFamily: 'sans-serif' }}>
<h1>🏥 医療AIダッシュボード</h1>
<p>Python (FastAPI) から取得した患者データを可視化しています。</p>
{/* 条件付きレンダリング(三項演算子) */}
{/* 書き方: 条件 ? (Yesの時表示) : (Noの時表示)
意味: loadingがtrueなら「読み込み中...」を表示し、
false(完了)なら「グラフ」を表示する。
*/}
{loading ? (
<p>データを読み込み中...(厨房にオーダーを通しています)</p>
) : (
<div style={{ maxWidth: '800px', margin: '0 auto' }}>
{/* ここでChart.jsのコンポーネントを配置! */}
<Line options={options} data={data} />
</div>
)}
</div>
);
}
export default App;
ステップ3:グランドオープン(実行と連携確認)
さあ、いよいよ開店の時間です!
厨房(バックエンドAPI)とホール(フロントエンド画面)、それぞれの準備が整いました。両方のシステムを同時に起動して、オーダーが正しく通り、料理(データ)が提供されるか確認してみましょう。
import { Dashboard } from ‘./components’;
// メインコンポーネント
export default function App() {
return <Dashboard />;
}
🔧 実行用:安全な操作コマンド一覧
1. バックエンド起動 (Terminal 1)
cd backendpython main.py
※ Uvicornサーバーが8000番で待機します。
2. フロントエンド起動 (Terminal 2)
cd medical-dashboardnpm run dev
※ Vite開発サーバーが5173番で待機します。
3. 動作確認
ブラウザで http://localhost:5173 にアクセス。
1. バックエンド(厨房)の起動
まず、ホールからの注文を待ち受けるためのAPIサーバーを立ち上げます。
- 新しいターミナルを開きます(VS Codeを使用している場合は、「ターミナル」メニューから「新しいターミナル」を選択してください)。
backendフォルダに移動し、以下のコマンドを実行してサーバーを起動します。
cd backend python main.py
成功すると、以下のようなメッセージが表示されます。これで、厨房がポート8000番で注文待ちの状態になりました。
INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
2. フロントエンド(ホール)の起動
次に、Reactで作った画面のファイルをブラウザに届けるための「開発サーバー」を立ち上げます。
🤔 素朴な疑問:「ブラウザで動く」のになぜ「起動」が必要?
Reactは最終的にユーザーのブラウザ上で動きますが、そもそもブラウザがそのプログラム(ホールの設計図)を読み込むためには、ファイルを配ってくれる相手が必要です。
これから打つコマンドは、プログラムそのものを動かすためではなく、ブラウザからの要求に応じて必要なファイルを渡すための「配送センター(Webサーバー)」を開店するためのものです。ここが開いていないと、ブラウザはどこにアクセスしてもファイルを受け取れず、画面は真っ白なままになってしまいます。
- もう一つ別のターミナルを開きます(※先ほど開いたバックエンド用のターミナルはそのまま動かしておいてください)。
medical-dashboardフォルダに移動し、以下のコマンドを実行します。
cd medical-dashboard npm run dev
成功すると、以下のようなメッセージが表示されます。これで配送センターがオープンし、ポート5173番でブラウザからのアクセスを待ち受ける状態になりました。
VITE v5.x.x ready in 240 ms ➜ Local: http://localhost:5173/ ➜ Network: use --host to expose
3. ブラウザで確認(連携の完了)
表示されたURL(例: http://localhost:5173)を、Ctrlキー(MacならCmdキー)を押しながらクリックするか、ブラウザのアドレスバーに直接入力してアクセスしてください。
【成功の証】
画面に「🏥 医療AIダッシュボード」というタイトルが表示され、一瞬「データを読み込み中…」と表示された後、赤と青の折れ線グラフが美しく描画されれば大成功です!
これが表示されたということは、以下の「一連の連携」が完璧に行われたことを意味します。
- ① ホールの設営: ブラウザが配送センター(
localhost:5173)からReactの設計図を受け取り、画面を構築した。 - ② 注文(APIリクエスト): 構築されたホール(React)から、厨房(
localhost:8000のFastAPI)へ、インターネット(API)を通じて注文が飛んだ。 - ③ 調理と提供: 厨房がデータを調理し、その料理(JSONデータ)がホールに届き、Chart.jsというお皿に綺麗に盛り付けられた。
5. 次なる挑戦:D3.jsで描く「自由自在」な医療ビジュアライゼーション
今回使用した Chart.js は、折れ線グラフや棒グラフといった「定型的なグラフ」を、誰でも簡単に、美しく描画できる素晴らしいライブラリです。しかし、医療の世界には、定型のグラフだけでは表現しきれない複雑なデータが存在します。
そこで登場するのが、データ可視化の王者 D3.js (Data-Driven Documents) です。

「プレハブ住宅」と「注文住宅」の違い
Chart.jsとD3.jsの違いを、家の建築に例えてみましょう。
- Chart.js は「プレハブ住宅」:
- すでに完成された壁や屋根(部品)が用意されており、組み立てるだけで高品質な家(グラフ)がすぐに建ちます。初心者でも失敗がありません。
- しかし、「壁を曲線にしたい」「天井をガラス張りにしたい」といった特殊な要望(カスタマイズ)には限界があります。
- D3.js は「木材と工具、そして設計図」:
- 完成品ではありません。線一本、円一つから自分でプログラムして描画します。学習コストは高いですが、あなたの想像力と技術さえあれば、どんな形状の建築物でも建てることができます。
医療分野におけるD3.jsの活用例
D3.jsの自由度の高さは、複雑な医療データの解析において真価を発揮します。
- ゲノム解析の可視化:何千もの遺伝子の類似性や相互作用を表現する、巨大な系統樹(デンドログラム)や円形配置図(サーコスプロット)。
- 患者フロー分析(サンキーダイアグラム):患者さんが「外来→入院→手術→ICU→転院」とどのように移動したか、その流量と分岐を太い矢印の流れで可視化します。
- 解剖学的マッピング:人体のイラスト上に、患者ごとの痛みの部位や、検査値の異常箇所をヒートマップとして重ね合わせる表現。
まずはChart.jsで基本を押さえ、表現の幅を広げたくなったらD3.jsに挑戦するのが、データサイエンティストとしての確実なステップアップの道です。
💡 コラム:現場で使うための「あと一歩」
本記事のサンプルコードは学習用ですが、実際の医療現場で運用するためには、さらに以下の2点を考慮する必要があります。
- リアルタイム更新(ポーリング)
現在のコードは「画面を開いた瞬間」のデータしか表示しません。実際の生体モニタのようにデータを常に更新するには、useEffectの中でsetIntervalを使い、「5秒ごとにデータを再取得する」といった仕組みを追加します。 - セキュリティと認証
患者データは極めて機密性の高い情報です。本番環境では、必ずログイン機能(認証)を実装し、通信を暗号化(HTTPS)して、権限のない人がデータを見られないように防御する必要があります。
6. まとめ:画面の向こうにいる「患者」を想う
本記事では、Pythonで作ったAIモデルを、Reactという技術を使って「実際に使えるアプリケーション」へと進化させる過程を学びました。
- バックエンド(FastAPI)で、データを調理し提供する厨房を作りました。
- フロントエンド(React/TypeScript)で、安全かつ効率的にデータをさばくホールスタッフを配置しました。
- Chart.jsという器を使って、データを直感的に理解できる形で提供しました。
私たちが作っているのは、単なるプログラムのコードではありません。モニターの画面越しに、医師の判断を支え、その先にいる患者さんの安全を守るための「医療の一部」を作っているのです。
使いにくいUIは医療ミスを誘発し、優れたUIは命を救う手助けとなります。「データを画面に出す」という第一歩を踏み出した今、ぜひその先にある「現場で愛されるシステム」を目指して、開発を続けてください。
参考文献
- Alvaro, S. et al. (2019). User Interface Software Errors in Medical Devices: A Study of US Device Recall Data. Biomedical Instrumentation & Technology, 53(3), 182–192. https://doi.org/10.2345/0899-8205-53.3.182
- FDA. (2016). Applying Human Factors and Usability Engineering to Medical Devices. U.S. Food and Drug Administration. https://www.fda.gov/regulatory-information/search-fda-guidance-documents/applying-human-factors-and-usability-engineering-medical-devices
- Gao, Z. et al. (2023). To Type or Not to Type: Quantifying Detectable Bugs in JavaScript. ICSE ’17: Proceedings of the 39th International Conference on Software Engineering. https://doi.org/10.1145/3097368.3097423
FastAPI React Tutorial
この動画では、FastAPIとReactを連携させたフルスタックアプリケーションの構築手順が、環境構築からデプロイまで実践的に解説されています。
※本記事は情報提供を目的としたものであり、特定の治療法を推奨するものではありません。健康に関するご懸念やご相談は、必ず専門の医療機関にご相談ください。
ご利用規約(免責事項)
当サイト(以下「本サイト」といいます)をご利用になる前に、本ご利用規約(以下「本規約」といいます)をよくお読みください。本サイトを利用された時点で、利用者は本規約の全ての条項に同意したものとみなします。
第1条(目的と情報の性質)
- 本サイトは、医療分野におけるAI技術に関する一般的な情報提供および技術的な学習機会の提供を唯一の目的とします。
- 本サイトで提供されるすべてのコンテンツ(文章、図表、コード、データセットの紹介等を含みますが、これらに限定されません)は、一般的な学習参考用であり、いかなる場合も医学的な助言、診断、治療、またはこれらに準ずる行為(以下「医行為等」といいます)を提供するものではありません。
- 本サイトのコンテンツは、特定の製品、技術、または治療法の有効性、安全性を保証、推奨、または広告・販売促進するものではありません。紹介する技術には研究開発段階のものが含まれており、その臨床応用には、さらなる研究と国内外の規制当局による正式な承認が別途必要です。
- 本サイトは、情報提供を目的としたものであり、特定の治療法を推奨するものではありません。健康に関するご懸念やご相談は、必ず専門の医療機関にご相談ください。
第2条(法令等の遵守)
利用者は、本サイトの利用にあたり、医師法、医薬品、医療機器等の品質、有効性及び安全性の確保等に関する法律(薬機法)、個人情報の保護に関する法律、医療法、医療広告ガイドライン、その他関連する国内外の全ての法令、条例、規則、および各省庁・学会等が定める最新のガイドライン等を、自らの責任において遵守するものとします。これらの適用判断についても、利用者が自ら関係各所に確認するものとし、本サイトは一切の責任を負いません。
第3条(医療行為における責任)
- 本サイトで紹介するAI技術・手法は、あくまで研究段階の技術的解説であり、実際の臨床現場での診断・治療を代替、補助、または推奨するものでは一切ありません。
- 医行為等に関する最終的な判断、決定、およびそれに伴う一切の責任は、必ず法律上その資格を認められた医療専門家(医師、歯科医師等)が負うものとします。AIによる出力を、資格を有する専門家による独立した検証および判断を経ずに利用することを固く禁じます。
- 本サイトの情報に基づくいかなる行為によって利用者または第三者に損害が生じた場合も、本サイト運営者は一切の責任を負いません。実際の臨床判断に際しては、必ず担当の医療専門家にご相談ください。本サイトの利用によって、利用者と本サイト運営者の間に、医師と患者の関係、またはその他いかなる専門的な関係も成立するものではありません。
第4条(情報の正確性・完全性・有用性)
- 本サイトは、掲載する情報(数値、事例、ソースコード、ライブラリのバージョン等)の正確性、完全性、網羅性、有用性、特定目的への適合性、その他一切の事項について、何ら保証するものではありません。
- 掲載情報は執筆時点のものであり、予告なく変更または削除されることがあります。また、技術の進展、ライブラリの更新等により、情報は古くなる可能性があります。利用者は、必ず自身で公式ドキュメント等の最新情報を確認し、自らの責任で情報を利用するものとします。
第5条(AI生成コンテンツに関する注意事項)
本サイトのコンテンツには、AIによる提案を基に作成された部分が含まれる場合がありますが、公開にあたっては人間による監修・編集を経ています。利用者が生成AI等を用いる際は、ハルシネーション(事実に基づかない情報の生成)やバイアスのリスクが内在することを十分に理解し、その出力を鵜呑みにすることなく、必ず専門家による検証を行うものとします。
第6条(知的財産権)
- 本サイトを構成するすべてのコンテンツに関する著作権、商標権、その他一切の知的財産権は、本サイト運営者または正当な権利を有する第三者に帰属します。
- 本サイトのコンテンツを引用、転載、複製、改変、その他の二次利用を行う場合は、著作権法その他関連法規を遵守し、必ず出典を明記するとともに、権利者の許諾を得るなど、適切な手続きを自らの責任で行うものとします。
第7条(プライバシー・倫理)
本サイトで紹介または言及されるデータセット等を利用する場合、利用者は当該データセットに付随するライセンス条件および研究倫理指針を厳格に遵守し、個人情報の匿名化や同意取得の確認など、適用される法規制に基づき必要とされるすべての措置を、自らの責任において講じるものとします。
第8条(利用環境)
本サイトで紹介するソースコードやライブラリは、執筆時点で特定のバージョンおよび実行環境(OS、ハードウェア、依存パッケージ等)を前提としています。利用者の環境における動作を保証するものではなく、互換性の問題等に起因するいかなる不利益・損害についても、本サイト運営者は責任を負いません。
第9条(免責事項)
- 本サイト運営者は、利用者が本サイトを利用したこと、または利用できなかったことによって生じる一切の損害(直接損害、間接損害、付随的損害、特別損害、懲罰的損害、逸失利益、データの消失、プログラムの毀損等を含みますが、これらに限定されません)について、その原因の如何を問わず、一切の法的責任を負わないものとします。
- 本サイトの利用は、学習および研究目的に限定されるものとし、それ以外の目的での利用はご遠慮ください。
- 本サイトの利用に関連して、利用者と第三者との間で紛争が生じた場合、利用者は自らの費用と責任においてこれを解決するものとし、本サイト運営者に一切の迷惑または損害を与えないものとします。
- 本サイト運営者は、いつでも予告なく本サイトの運営を中断、中止、または内容を変更できるものとし、これによって利用者に生じたいかなる損害についても責任を負いません。
第10条(規約の変更)
本サイト運営者は、必要と判断した場合、利用者の承諾を得ることなく、いつでも本規約を変更することができます。変更後の規約は、本サイト上に掲載された時点で効力を生じるものとし、利用者は変更後の規約に拘束されるものとします。
第11条(準拠法および合意管轄)
本規約の解釈にあたっては、日本法を準拠法とします。本サイトの利用および本規約に関連して生じる一切の紛争については、東京地方裁判所を第一審の専属的合意管轄裁判所とします。
For J³, may joy follow you.

