化学実験で使える検量線アプリをPythonで手軽に開発する方法

# はじめに
こんにちは！普段は化学科の学部生として勉強しています。実験がある理系学生なら、日常的にデータをグラフ化してレポートにまとめる必要があると思います。私は毎回Excelでグラフを作るのが大変で、特にMacだと操作が少し面倒に感じることもありました。そこで、PythonのmatplotlibとStreamlitを組み合わせて、効率化を図る方法を試してみました。

---

# matplotlibの基本と検量線作図

## matplotlibとは
Pythonのmatplotlibは、科学分野で広く使われるグラフ作成ライブラリです。検量線をプロットするのに必要な散布図や直線フィットも簡単に実現できます。

### 検量線をmatplotlibだけで作成するコード
以下は、検量線をプロットするための簡単な例です。

```python
import numpy as np
import matplotlib.pyplot as plt
import japanize_matplotlib

# データ
x = np.array([0.1, 0.2, 0.3, 0.4, 0.5])
y = np.array([0.05, 0.10, 0.15, 0.20, 0.25])

# 近似直線の計算
k = np.polyfit(x, y, 1)[0]  

# プロット
plt.scatter(x, y, label='データ', color='blue')
plt.plot(x, k * x, label=f'近似直線: y = {k:.3f}x', color='red')
plt.xlabel('濃度 (c)')
plt.ylabel('吸光度 (Abs)')
plt.title('検量線グラフ')  
plt.legend()
plt.show()
```

このコードを実行すると、検量線の散布図と近似直線が描画されます。
(体裁は適当)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3686753/65b29aa7-a1b4-3534-fd92-a75438089571.png)

---

# Streamlitの概要

## Streamlitとは
StreamlitはPythonで簡単にWebアプリケーションを構築できるフレームワークです。科学データの可視化やツールの共有に非常に便利です。今回は、このStreamlitを使って、検量線グラフを動的に作成できるアプリを作ります。

### 最小構成の例
Streamlitアプリの基本構成は非常にシンプルです！

```python
import streamlit as st

st.title('検量線アプリ')
st.write('Streamlitを使うと、Pythonだけで簡単にWebアプリを作成できます！')
```
このコードを実行すると、タイトルとテキストが表示される簡単なWebページを作成できます!
![スクリーンショット 2024-12-05 23.11.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3686753/b62932bf-ccf5-cf47-f69d-5a60046adcff.png)


---

# アプリの実装：検量線作図のWebアプリ
以下は、検量線グラフを作成するStreamlitアプリの概要です。
完成版が最後にあるので、ぜひご覧ください！

## ユーザー入力と設定
- 濃度(x) と 測定値(y) ：カンマ区切りで入力
- グラフの設定 ：タイトル、軸ラベル、凡例、原点を通るか否かなどをカスタマイズ可能
```python
concentration_input = st.text_input('濃度(x) (カンマ区切り)', '0.1, 0.2, 0.3, 0.4, 0.5')
absorbance_input = st.text_input('測定値(y) (カンマ区切り)', '0.05, 0.10, 0.15, 0.20, 0.25')
include_origin = st.checkbox('原点を通る直線にする', value=True)
```

## 近似線
- `curve_fit`を使い、近似直線を計算します
- 原点を通る場合と通らない場合の両方に対応
```python
def fit_model(concentration, absorbance, include_origin=True):
    if include_origin:
        popt, _ = curve_fit(lambda x, k: k * x, concentration, absorbance)
        return popt[0], 0
    else:
        return np.polyfit(concentration, absorbance, 1)
```

## グラフの描画
matplotlibを使って以下の要素を描画します

- 散布図：入力データを表示
- 近似直線：計算した直線式をプロット
- タイトル、軸ラベル、凡例はすべてユーザー設定を反映

```python
plt.scatter(concentration, absorbance, edgecolors='black', facecolors='white',
                label=legend_label if legend_label else None, marker='o', s=100, zorder=2)
plt.plot(x_fit, y_fit, color='black', linestyle='-',
             label=legend_line if legend_line else None, zorder=1)
```

## 出力とダウンロード

完成したグラフを画面に表示し、ダウンロード機能をつけます

- `BytesIO`を利用してPNG形式で保存
- Streamlitのst.download_buttonを使い、ボタン一つでダウンロード可能に

```python
buf = BytesIO()
plot.savefig(buf, format='png')
buf.seek(0)
st.download_button(label='グラフをダウンロード', data=buf, file_name='calibration_curve.png', mime='image/png')
```

## 便利機能
- 測定値(y)から濃度(x)を計算する機能を追加
- フィット結果や計算結果をリアルタイムに表示
```python
concentration_value = absorbance_value / k if include_origin else (absorbance_value - b) / k
st.write(f'計算された濃度(x): {concentration_value:.3f}')
```
---

# アプリの工夫点
- シンプルで分かりやすいUI
    Streamlitの操作性を活用して、UIを作成しました
- 柔軟なカスタマイズ
    フィッティングの設定やグラフの装飾を自由に変更可能にしました
---

## 実際に作ったアプリ
![localhost_8501_ (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3686753/e2a057de-318a-db6d-0cf6-06a950aeca3b.png)
![localhost_8501_.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3686753/4c8dd6f0-1bf2-3f88-3350-a8fda5c3a52a.png)


このアプリはStreamlit Cloudを使ってデプロイしました。以下のリンクから実際に試してみてください。

[デプロイされたアプリはこちら](https://ryoma0101-calibration-curve-app-tcftgg.streamlit.app/)

---
# 最後に
読んでいただきありがとうございます。これを作ってから、グラフ作成がかなり楽になりました。今のところ線形回帰しかできないので、もっと柔軟な機能になるようにアップグレードしていきたいと思います。


## 付録
- **GitHubリンク**：https://github.com/Ryoma0101/Calibration-curve
- **参考リンク**：
  - [Streamlit公式ドキュメント](https://docs.streamlit.io/)
  - [matplotlibの基本操作ガイド](https://matplotlib.org/stable/tutorials/index.html)