Arduinoのセンサーデータをリアルタイムでグラフ表示する方法|Python連携
シリアルモニタに並ぶ数字の羅列は、値の変化を目で追うにはあまり向いていません。センサーの値を折れ線グラフとして、リアルタイムに動く形で見られたら、変化の傾向や異常値にずっと気づきやすくなります。本記事では、追加インストール不要のArduino純正機能から、Pythonの Matplotlib を使った本格的な可視化、複数センサーの同時表示、CSV記録との組み合わせまで、初心者の方に向けて順を追って解説します。
01リアルタイムグラフ表示とは|何ができるようになるか

数字の羅列とグラフの決定的な違い
シリアルモニタは、値を確認する手段として手軽で優秀です。ただし、数字がひたすら流れていくだけなので、「値がじわじわ上がっている」「一瞬だけ大きく跳ねた」といった変化のパターンは、読み取りづらいという弱点があります。同じデータでも、折れ線グラフとして時系列に並べるだけで、傾向や異常値に気づく速度は大きく変わります。センサーのチューニングやキャリブレーション、動作確認の効率も、グラフ表示によって格段に上がります。
この記事で扱う2つのアプローチ
センサーデータをリアルタイムでグラフ表示する方法には、大きく分けて2つのアプローチがあります。1つは、Arduino IDEに標準で搭載されている「シリアルプロッタ」を使う方法です。追加のソフトは一切不要で、今すぐ試せます。もう1つは、Pythonの可視化ライブラリ「Matplotlib」を使う方法です。少し準備は必要ですが、複数センサーの自由なレイアウト表示や、画像保存、しきい値による色分けなど、表現の幅が大きく広がります。まずは手軽な方法から見ていきましょう。
Arduinoでソイルセンサーの値を記録していたKさんは、シリアルモニタの数字を目で追うだけでは、値がゆっくり下がっているのか、実は上下に揺れているだけなのか、判断がつかなかった。試しにシリアルプロッタを開いてみると、値は緩やかな右肩下がりの直線を描いており、乾燥が着実に進んでいることが一目で分かった。数字の羅列では気づけなかった傾向が、グラフにした瞬間にはっきりと見えるようになった。
02最も手軽な方法|Arduino純正「シリアルプロッタ」

1行書くだけでグラフが出る
Arduino IDEには、標準で「シリアルプロッタ」という機能が搭載されています。ツールバーのアイコン、または「ツール」メニューから開くことができます。Arduino側のコードは、シリアルモニタで使うのとまったく同じSerial.println()だけで構いません。特別な準備は一切不要です。
// シリアルプロッタで1本の折れ線を表示するコード
void setup() {
Serial.begin(9600);
}
void loop() {
int value = analogRead(A0);
Serial.println(value); // これだけでグラフになる
delay(50);
}
複数の値を同時に表示する
複数の値を1つのグラフに重ねて表示したい場合は、カンマまたは空白区切りで、1行にまとめて出力します。さらに「ラベル名:値」という書き方をすると、凡例に名前を表示させることもできます。
// 2つの値を、名前つきで同時にグラフ表示するコード
void setup() {
Serial.begin(9600);
}
void loop() {
int sensorA = analogRead(A0);
int sensorB = analogRead(A1);
Serial.print("SensorA:");
Serial.print(sensorA);
Serial.print(",");
Serial.print("SensorB:");
Serial.println(sensorB);
delay(50);
}
シリアルプロッタの限界
シリアルプロッタは手軽な反面、いくつかの制約もあります。表示できる時間軸は直近の一定区間のみで、グラフを画像として保存する機能はありません。また、ボーレート(通信速度)は、コード内のSerial.begin()とプロッタ側の設定を必ず一致させる必要があります。ここが食い違うと、文字化けした値や、グラフが表示されない状態になります。もっと自由度の高い表示や記録をしたい場合は、次の章から解説するPython側のアプローチに進みましょう。
03本格的に可視化するなら|Python × Matplotlibを使う理由

シリアルプロッタでは足りなくなる場面
シリアルプロッタは手軽ですが、「グラフを画像として残したい」「しきい値を超えたら色を変えたい」「複数のグラフを自由なレイアウトで並べたい」「表示しながら同時にファイルへ記録したい」といった要望には応えられません。こうした表現をしたくなったら、Pythonの可視化ライブラリ「Matplotlib(マットプロットリブ)」の出番です。
ArduinoとPythonの役割分担
この構成では、Arduinoは「センサーの値を読み取り、シリアル通信で送信する」役割に専念します。グラフの描画や記録といった重い処理は、パソコン側のPythonが担当します。マイコン側の処理を軽く保てるため、より高速なセンサー読み取りにも対応しやすくなるという利点もあります。
04環境構築|必要なライブラリのインストール

必要なライブラリは2つ
Python側で必要になるライブラリは、シリアル通信用の「pyserial」と、グラフ描画用の「matplotlib」の2つです。ターミナル(コマンドプロンプト)で、次のコマンドを実行してインストールします。
pip install pyserial matplotlib
Pythonがインストール済みか確認する
ターミナルでpython --version(環境によってはpython3 --version)を実行し、バージョンが表示されることを確認します。表示されない場合は、先にPython本体をインストールしてください。
pipでライブラリをインストールする
pip install pyserial matplotlibを実行します。数十秒〜数分でインストールが完了します。
インストールを確認する
pip show matplotlibを実行し、バージョン情報が表示されればインストール成功です。
05Arduino側の準備|データを送信するコード
シンプルな1値送信のコード
Python側でグラフ表示をする場合も、Arduino側のコードは驚くほどシンプルです。基本的には、値を一定間隔でSerial.println()するだけで構いません。
// センサー値を一定間隔で送信するコード
const int sensorPin = A0;
void setup() {
Serial.begin(9600);
}
void loop() {
int value = analogRead(sensorPin);
Serial.println(value);
delay(50); // 送信間隔(短くするほどグラフが滑らかになる)
}
送信間隔と滑らかさのバランス
delay()の値を短くするほど、送られてくるデータの密度が上がり、グラフは滑らかに動きます。ただし、短くしすぎるとパソコン側の処理が追いつかなくなる場合もあります。まずは50ミリ秒程度から試し、用途に応じて調整するとよいでしょう。
06Pythonの基本コード|1つのセンサー値をリアルタイム表示

FuncAnimationで定期的にグラフを更新する
Matplotlibには、グラフを一定間隔で自動更新できるFuncAnimationという仕組みがあります。これを使うと、シリアルポートから読み取った値を、そのままリアルタイムに描画し続けることができます。
# Arduinoのセンサー値をリアルタイムでグラフ表示するコード
import serial
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from collections import deque
# ポート名は環境に合わせて変更する(Windowsは"COM3"等、Macは"/dev/cu.usbmodemXXXX"等)
ser = serial.Serial("COM3", 9600, timeout=1)
MAX_LEN = 100 # 画面に表示する点の数
data = deque([0] * MAX_LEN, maxlen=MAX_LEN)
fig, ax = plt.subplots()
line, = ax.plot(data)
ax.set_ylim(0, 1023) # analogReadの範囲に合わせて調整する
ax.set_xlabel("Time (frames)")
ax.set_ylabel("Sensor Value")
ax.set_title("Arduino Sensor - Realtime Plot")
def update(frame):
if ser.in_waiting > 0:
raw = ser.readline().decode("utf-8", errors="ignore").strip()
if raw.isdigit():
data.append(int(raw))
line.set_ydata(data)
line.set_xdata(range(len(data)))
return line,
ani = animation.FuncAnimation(fig, update, interval=50, blit=True, cache_frame_data=False)
plt.show()
コードのポイント
deque(maxlen=MAX_LEN)を使うことで、常に直近100個分のデータだけを保持する「流れるグラフ」を簡単に作れます。ser.in_waitingで受信バッファにデータが来ているかを確認してから読み取ることで、データが来ていないときの無駄な待機を減らせます。interval=50は、グラフを更新する間隔(ミリ秒)です。Arduino側の送信間隔とおおよそ揃えておくと、無駄のない滑らかな表示になります。
07応用|複数センサーを同時にグラフ表示する

Arduino側:カンマ区切りで複数の値を送る
加速度センサーのようにX・Y・Zの3軸を持つセンサーは、複数の値を同時にグラフ化したい代表例です。Arduino側では、値をカンマ区切りの1行にまとめて送信します。
// 3つの値をカンマ区切りで送信するコード(例:3軸のセンサーを想定)
void setup() {
Serial.begin(9600);
}
void loop() {
int x = analogRead(A0);
int y = analogRead(A1);
int z = analogRead(A2);
Serial.print(x);
Serial.print(",");
Serial.print(y);
Serial.print(",");
Serial.println(z);
delay(50);
}
Python側:カンマで分割して3本の線を描く
# 3つの値を同時にグラフ表示するコード
import serial
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from collections import deque
ser = serial.Serial("COM3", 9600, timeout=1)
MAX_LEN = 100
data_x = deque([0] * MAX_LEN, maxlen=MAX_LEN)
data_y = deque([0] * MAX_LEN, maxlen=MAX_LEN)
data_z = deque([0] * MAX_LEN, maxlen=MAX_LEN)
fig, ax = plt.subplots()
line_x, = ax.plot(data_x, label="X")
line_y, = ax.plot(data_y, label="Y")
line_z, = ax.plot(data_z, label="Z")
ax.set_ylim(0, 1023)
ax.legend(loc="upper right")
def update(frame):
if ser.in_waiting > 0:
raw = ser.readline().decode("utf-8", errors="ignore").strip()
parts = raw.split(",")
if len(parts) == 3 and all(p.lstrip("-").isdigit() for p in parts):
data_x.append(int(parts[0]))
data_y.append(int(parts[1]))
data_z.append(int(parts[2]))
line_x.set_ydata(data_x)
line_y.set_ydata(data_y)
line_z.set_ydata(data_z)
return line_x, line_y, line_z
ani = animation.FuncAnimation(fig, update, interval=50, blit=True, cache_frame_data=False)
plt.show()
データの分割数を必ずチェックする
len(parts) == 3という条件は、意外と重要です。通信の途中でデータが1行分だけ欠けたり、途中で切れたりすると、想定より少ない・多い数の値が届くことがあります。この確認を省略すると、リストの範囲外を参照してプログラムがエラーで止まってしまうことがあるため、必ず件数を確認してから処理するようにしましょう。
08実践|グラフ表示しながらCSVにも記録する

「見る」と「残す」を同時に行う
リアルタイムに眺めるだけでなく、あとから分析やレポートに使いたい場合は、受信したデータをCSVファイルに書き込みながら、同時にグラフ表示する構成が便利です。update()関数の中で、グラフの更新とファイルへの書き込みを両方行うだけで実現できます。
# グラフ表示しながらCSVにも記録するコード
import serial
import csv
import time
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from collections import deque
ser = serial.Serial("COM3", 9600, timeout=1)
MAX_LEN = 100
data = deque([0] * MAX_LEN, maxlen=MAX_LEN)
csv_file = open("sensor_log.csv", "w", newline="")
csv_writer = csv.writer(csv_file)
csv_writer.writerow(["timestamp", "value"]) # ヘッダー行
fig, ax = plt.subplots()
line, = ax.plot(data)
ax.set_ylim(0, 1023)
def update(frame):
if ser.in_waiting > 0:
raw = ser.readline().decode("utf-8", errors="ignore").strip()
if raw.isdigit():
value = int(raw)
data.append(value)
line.set_ydata(data)
line.set_xdata(range(len(data)))
# グラフ表示と同時にCSVへ1行ずつ追記する
csv_writer.writerow([time.time(), value])
csv_file.flush()
return line,
ani = animation.FuncAnimation(fig, update, interval=50, blit=True, cache_frame_data=False)
plt.show()
csv_file.close()
flush()を入れておく理由
csv_file.flush()を呼ぶと、書き込んだ内容がすぐにディスクへ反映されます。これを省略すると、Pythonの内部バッファに一時的にデータが溜まったままになり、プログラムを異常終了させてしまった際に、直近の記録が失われてしまうことがあります。長時間の記録を行う場合は、この一手間を入れておくと安心です。
09よくあるトラブルと対処法
症状別の対処早見表
| 症状 | 主な原因 | 対処法 |
|---|---|---|
| 「could not open port」というエラーが出る | ポート名の指定違い、またはArduino IDEのシリアルモニタが開いたまま | ポート名を確認し、Arduino IDE側のシリアルモニタ・シリアルプロッタを閉じてから実行する |
| グラフが真っ直ぐなまま動かない | ボーレートの不一致、または受信データの形式違い | Serial.begin()の数値とser = serial.Serial()の数値を一致させる(5章参照) |
| 途中でエラーが出て止まる(ValueError等) | ノイズや欠損で不完全な行を受信し、int()変換に失敗している | isdigit()等で数値として妥当かを確認してから変換する(6・7章のコード参照) |
| 3軸のはずが2つしか表示されない | データの一部が欠けて届いている | len(parts)の件数チェックを入れる(7章参照) |
| グラフの動きがカクカクする | 更新間隔(interval)や送信間隔(delay)が長すぎる | 両方の間隔を30〜50ms程度に短くし、blit=Trueを指定する(10章FAQ参照) |
原因を素早く切り分けるコツ
Mさんは3軸センサーのグラフ化コードを試したが、数分に1回、プログラムがエラーで止まってしまう現象に悩まされていた。原因を調べたところ、USBケーブルの接触が不安定なタイミングで、1行分のデータが「12,34」のように途中で切れて届いていたことが分かった。件数チェックの条件を追加したところ、不完全な行は静かに読み飛ばされるようになり、エラーで止まることがなくなった。
10よくある質問
基本のQ&A
応用のQ&A
関連記事・参考資料
基礎を学べる記事
- YOFUKASI LAB「ArduinoとPCのシリアル通信入門|Serial.printで値を可視化する」2026年, https://yofukasi-lab-wp.com/2026/08/18/arduinoとpcのシリアル通信入門――serial-printで値を可視化す/
- YOFUKASI LAB「Arduinoのシリアルモニタ活用術」2026年, https://yofukasi-lab-wp.com/2026/08/22/arduino-serial-monitor-debugging/
- YOFUKASI LAB「Arduinoで使える定番センサー30選」2026年, https://yofukasi-lab-wp.com/2026/09/11/arduino-30-sensors-guide/
- YOFUKASI LAB「Arduinoに必要な工具・部品リスト」2026年, https://yofukasi-lab-wp.com/2026/08/22/arduino-tools-parts/
- YOFUKASI LAB「Arduino IDEのダウンロード・インストール方法」2026年, https://yofukasi-lab-wp.com/2026/08/01/arduino-install-download/
応用・関連記事
- YOFUKASI LAB「電子工作×プログラミング入門」2026年, https://yofukasi-lab-wp.com/2026/09/12/electronics-programming-getting-started/
- YOFUKASI LAB「Arduinoで土壌水分センサーを使う」2026年, https://yofukasi-lab-wp.com/2026/09/03/arduino-soil-moisture-sensor/
- YOFUKASI LAB「Arduinoで音センサーを使う方法」2026年, https://yofukasi-lab-wp.com/2026/09/04/arduino-sound-sensor/
- YOFUKASI LAB「Arduino×MPU6050で加速度・ジャイロセンサーを使う方法」2026年, https://yofukasi-lab-wp.com/2026/08/31/mpu6050/
- YOFUKASI LAB「ArduinoでSDカードにCSV保存する方法」2026年, https://yofukasi-lab-wp.com/2026/08/31/arduino-sd-card-csv-save/
- YOFUKASI LAB「Arduinoが「ポートが見つからない」時の原因と解決策」2026年, https://yofukasi-lab-wp.com/2026/08/23/arduino-port-not-found/
- YOFUKASI LAB「Arduinoのコンパイルエラー一覧」2026年, https://yofukasi-lab-wp.com/2026/07/30/error/
参考資料(外部・一次情報)
- Arduino Documentation「Using the Serial Plotter Tool」, https://docs.arduino.cc/software/ide-v2/tutorials/ide-v2-serial-plotter
- Luis Llamas「Easily Create Graphs in Arduino IDE with Serial Plotter」, https://www.luisllamas.es/en/arduino-serial-plotter/
- Matplotlib Documentation「matplotlib.animation.FuncAnimation」, https://matplotlib.org/stable/api/_as_gen/matplotlib.animation.FuncAnimation.html
- pySerial Documentation, https://pyserial.readthedocs.io/en/latest/pyserial.html
※本記事は個人の学習・電子工作用途を対象にしています。医療機器や製品として実際に運用する場合は、精度検証・電気安全・関連法規について専門家に別途ご相談ください。
コメント