iT邦幫忙

0

Day 21:健康資料視覺化——使用圖表呈現紀錄趨勢

  • 分享至 

  • xImage
  •  

一、前言

在前幾天的學習中,我已經完成健康紀錄的新增、查詢、修改與刪除,也學會計算平均喝水量、平均睡眠時間,以及每週運動總時間。

然而,當健康紀錄逐漸增加時,只透過表格與數字查看資料,可能不容易發現長期的變化。例如,睡眠時間是否逐漸增加、喝水量是否每天都差不多,以及最近幾週的運動時間是否有所改變。

因此,今天將學習如何使用圖表呈現健康資料,並透過 Streamlit 內建的圖表功能,將每日紀錄與每週運動統計轉換成更容易閱讀的視覺化資訊。

二、學習目標

了解資料視覺化的目的與常見圖表類型。

使用 Pandas 整理適合繪圖的健康資料。

使用 Streamlit 的 st.line_chart() 呈現每日健康趨勢。

使用 st.bar_chart() 比較每週運動時間。

將圖表整合到個人健康習慣追蹤系統。

測試沒有資料、資料缺失及日期不完整時的呈現情況。

三、認識資料視覺化

資料視覺化是將原本的數字或表格轉換成圖形,讓使用者更容易理解資料的分布、差異與變化趨勢。

在健康習慣追蹤系統中,可以依照不同的分析目的選擇適合的圖表。
https://ithelp.ithome.com.tw/upload/images/20261028/20178903dWvrKXzree.png
例如,若想知道最近七天的睡眠時間是否穩定,折線圖通常比單純閱讀七個數字更容易辨認變化。

若想比較不同週的運動總時間,長條圖則能清楚呈現各週之間的差異。

因此,圖表的選擇應該依照想回答的問題決定,而不是單純將所有資料都畫成圖。

四、使用 Streamlit 建立第一張圖表

Streamlit 提供了簡單的圖表函式,不需要先建立複雜的圖形物件,就能將 Pandas 資料呈現在網頁中。

例如,先建立一組測試資料:

import pandas as pd
import streamlit as st

data = pd.DataFrame({
"日期": [
"10/19",
"10/20",
"10/21",
"10/22",
"10/23"
],
"喝水量": [1500, 1800, 2000, 1700, 2200]
})

st.title("每日喝水量趨勢")
st.line_chart(
data.set_index("日期")["喝水量"]
)

這段程式會建立一張折線圖,橫軸代表日期,縱軸代表喝水量。

其中:

pd.DataFrame():建立表格形式的資料。

set_index("日期"):將日期設定為圖表的索引。

st.line_chart():將資料繪製成折線圖。

透過這種方式,就能將原本的數字轉換成容易閱讀的趨勢圖。

五、讀取健康紀錄並整理資料

在正式系統中,不需要每次手動輸入測試資料,而是應該直接讀取先前保存的 health_records.csv。

目前系統使用的主要欄位如下:

https://ithelp.ithome.com.tw/upload/images/20261028/20178903Avn0TX3ckT.png

在繪製圖表之前,需要先將日期轉換成日期格式,並將喝水量、睡眠時間與運動時間轉換成數值。

import pandas as pd
from pathlib import Path

FILE_PATH = Path("health_records.csv")

if FILE_PATH.exists():
records = pd.read_csv(FILE_PATH)

records["date"] = pd.to_datetime(
    records["date"],
    errors="coerce"
)

for column in [
    "water_ml",
    "sleep_hours",
    "exercise_minutes"
]:
    records[column] = pd.to_numeric(
        records[column],
        errors="coerce"
    )

records = records.dropna(subset=["date"])
records = records.sort_values("date")

print(records)

else:
print("目前尚無健康紀錄。")

這個步驟的重點是讓資料具有一致的格式,避免因為日期或數值格式不正確,造成圖表無法正常顯示。

如果 CSV 檔案缺少必要欄位,實際系統還需要先檢查欄位是否存在,再執行轉換與繪圖。

六、實作:建立健康資料視覺化儀表板

接下來,將每日喝水量、睡眠時間與每週運動時間整合成一個視覺化頁面。

請先備份目前的 app.py,再將以下完整程式碼放入檔案中。此版本會讀取既有 CSV,不會覆寫原本的健康紀錄。

from pathlib import Path

import pandas as pd
import streamlit as st

FILE_PATH = Path("health_records.csv")

st.set_page_config(
page_title="個人健康習慣追蹤系統",
page_icon="🌱",
layout="wide"
)

st.title("🌱 個人健康習慣追蹤系統")
st.subheader("健康資料視覺化")

讀取健康紀錄

if not FILE_PATH.exists():
st.info("目前尚無健康紀錄,請先新增每日健康資料。")
st.stop()

try:
records = pd.read_csv(FILE_PATH)
except (OSError, pd.errors.ParserError, UnicodeDecodeError):
st.error("讀取健康紀錄失敗,請檢查 CSV 檔案。")
st.stop()

if records.empty:
st.info("目前沒有可供分析的健康紀錄。")
st.stop()

檢查必要欄位

required_columns = [
"date",
"water_ml",
"sleep_hours",
"exercise_minutes"
]

missing_columns = [
column
for column in required_columns
if column not in records.columns
]

if missing_columns:
st.error(
"健康紀錄缺少必要欄位:" + ", ".join(missing_columns)
)
st.stop()

整理資料格式

records["date"] = pd.to_datetime(
records["date"],
errors="coerce"
)

for column in [
"water_ml",
"sleep_hours",
"exercise_minutes"
]:
records[column] = pd.to_numeric(
records[column],
errors="coerce"
)

records = records.dropna(subset=["date"]).copy()

if records.empty:
st.info("目前沒有有效的日期資料。")
st.stop()

排除負數等無效數值

for column in [
"water_ml",
"sleep_hours",
"exercise_minutes"
]:
records.loc[records[column] < 0, column] = float("nan")

同一天可能有多筆紀錄,先彙整成每日資料

daily = records.groupby(
records["date"].dt.normalize()
).agg(
water_ml=("water_ml", "mean"),
sleep_hours=("sleep_hours", "mean"),
exercise_minutes=("exercise_minutes", "sum")
).sort_index()

st.write("以下圖表根據目前已保存的健康紀錄產生。")

每日喝水量

st.subheader("每日喝水量趨勢")

water_chart = daily[["water_ml"]].dropna()

if water_chart.empty:
st.info("目前沒有有效的喝水量資料。")
else:
st.line_chart(
water_chart,
y="water_ml",
x_label="日期",
y_label="喝水量(毫升)"
)

每日睡眠時間

st.subheader("每日睡眠時間趨勢")

sleep_chart = daily[["sleep_hours"]].dropna()

if sleep_chart.empty:
st.info("目前沒有有效的睡眠時間資料。")
else:
st.line_chart(
sleep_chart,
y="sleep_hours",
x_label="日期",
y_label="睡眠時間(小時)"
)

每週運動時間

st.subheader("每週運動總時間")

exercise_data = daily[
["exercise_minutes"]
].dropna().copy()

if exercise_data.empty:
st.info("目前沒有有效的運動時間資料。")
else:
exercise_data["week"] = (
exercise_data.index
.to_period("W-SUN")
.astype(str)
)

weekly = exercise_data.groupby("week").agg(
    total_exercise_minutes=("exercise_minutes", "sum")
)

st.bar_chart(
    weekly,
    y="total_exercise_minutes",
    x_label="週次",
    y_label="運動總時間(分鐘)"
)

st.divider()

st.subheader("每日健康紀錄明細")

display_records = daily.reset_index(names="date")
st.dataframe(
display_records.sort_values("date", ascending=False),
use_container_width=True,
hide_index=True
)

st.caption(
"同一天的多筆喝水量與睡眠紀錄會取平均,"
"運動時間則會加總。未記錄的日期不代表沒有相關活動。"
)

程式碼重點說明

  1. 同一天的紀錄先進行彙整

daily = records.groupby(
records["date"].dt.normalize()
).agg(
water_ml=("water_ml", "mean"),
sleep_hours=("sleep_hours", "mean"),
exercise_minutes=("exercise_minutes", "sum")
)

如果同一天有多筆紀錄,這個版本會將喝水量與睡眠時間取平均,並將運動時間加總。

這是一種簡化的處理方式。實際使用時,必須先確認喝水量是「全天總量」還是「單次喝水量」,以及睡眠時間是否為不同睡眠時段,避免把不同意義的數據直接合併。

  1. 使用 dropna() 排除缺失資料

water_chart = daily[["water_ml"]].dropna()

dropna() 可以排除沒有有效喝水量的日期,避免無效數值影響圖表。

不過,這不代表所有沒有紀錄的日期都能被補成零。若使用者當天沒有填寫資料,系統並不知道他實際喝了多少水,因此應保留資料缺失的意義。

  1. 使用折線圖觀察趨勢

st.line_chart(
sleep_chart,
y="sleep_hours",
x_label="日期",
y_label="睡眠時間(小時)"
)

折線圖可以呈現睡眠時間隨日期的變化,幫助使用者觀察數值是否有明顯起伏。

  1. 使用長條圖比較每週運動時間

st.bar_chart(
weekly,
y="total_exercise_minutes",
x_label="週次",
y_label="運動總時間(分鐘)"
)

長條圖可以將每週運動總時間並列比較,讓不同週之間的差異更加明顯。

七、實際執行與測試

完成程式碼後,開啟終端機,進入專案資料夾,執行:

python -m streamlit run app.py

接著,確認網頁中的圖表是否能正確呈現。

https://ithelp.ithome.com.tw/upload/images/20261028/201789039guJVIINVP.png

測試時,可以先建立至少五至七天的測試紀錄,讓圖表有足夠的資料點。如果所有日期的數值都相同,折線圖仍然可以正常顯示,但不容易看出變化。

另外,若同一天存在多筆紀錄,應確認彙整方式是否符合資料的實際意義。若每天只會保存一筆完整的健康紀錄,就不需要特別處理同日多筆資料。

八、今日成果與學習心得

今天完成了健康習慣追蹤系統的基礎資料視覺化功能,學習如何利用 Pandas 整理日期與數值,再透過 Streamlit 將資料呈現為折線圖及長條圖。

透過這次實作,我了解到資料分析不只是計算平均值或總和,也可以透過視覺化方式,讓使用者更直觀地理解資料中的變化。

例如,平均睡眠時間可以提供整體概況,但無法完整呈現每天的差異;折線圖則能讓使用者觀察哪些日期的睡眠時間比較長或比較短。同樣地,每週運動總時間的長條圖也可以幫助使用者比較不同週的活動情況。

此外,我也學到圖表的正確性取決於資料品質。如果資料有缺失、日期格式錯誤或重複紀錄,就可能影響圖表的解讀。因此,在建立圖表之前,必須先進行資料清理與彙整。

九、下一步學習方向

第二十二天的主題是「習慣完成率計算——追蹤個人目標的達成情況」。

下一階段將學習如何設定個人的健康習慣目標,例如每日喝水量、每週運動次數等,再根據實際紀錄計算目標完成率。

透過完成率與目前的統計圖表結合,系統就能從單純呈現健康資料,進一步發展成協助使用者追蹤個人習慣目標的工具。


圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言