3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

血圧を記録するアプリを作る その3 〜 血圧測定の結果を元にグラフを作る 〜

Last updated at Posted at 2025-12-02

「血圧を記録するアプリを作る」シリーズです
前回は「AIを使って血圧計の写真を元に値を入力する」でした

今回は「A血圧測定の結果を元にグラフを作る」を作ります

実行環境

  • OS Ubuntu 24.04
  • GPU RTX4090(今回はなくても動く)
  • Elixir 1.17.1-otp-27
  • Erlang 27.2.1
  • Phoenix 1.8.2
  • Olama 0.13.0 (今回はなくても動く)
  • モデル gemma3:27b(今回はなくても動く)

今回の実行イメージ

image.png

前提知識

VegaLite

過去の僕の検証

公式

プログラムを書く

vega_liteとvega_lite_convertを追加

グラフを描くライブラリです

mix.exs
defmodule BloodPressureRecord.MixProject do
  use Mix.Project
# 省略 #

  defp deps do
    [
# 省略 #
+     {:vega_lite, "~> 0.1.11"},
+     {:vega_lite_convert, "~> 1.0.1"}
    ]
  end
# 省略 #

ライブラリーを取得

$ mix deps.get

ルータ追加

/graphを追加

lib/blood_pressure_record_web/router.ex
defmodule BloodPressureRecordWeb.Router do
# 省略 #
  pipeline :api do
    plug :accepts, ["json"]
  end

  scope "/", BloodPressureRecordWeb do
    pipe_through :browser

    get "/", PageController, :home
    live "/blood_pressures", BloodPressureLive.Index, :index
    live "/blood_pressures/new", BloodPressureLive.Form, :new
    live "/blood_pressures/:id", BloodPressureLive.Show, :show
    live "/blood_pressures/:id/edit", BloodPressureLive.Form, :edit
    live "/up", BloodPressureLive.UploadLive, :index
+   live "/graph", BloodPressureLive.Graph, :index
  end
# 省略 #

lib/blood_pressure_record_web/live/blood_pressure_live/index.exをコピーして作ります

lib/blood_pressure_record_web/live/blood_pressure_live/graph.ex
defmodule BloodPressureRecordWeb.BloodPressureLive.Graph do
use BloodPressureRecordWeb, :live_view

alias BloodPressureRecord.BloodPressures
alias VegaLite, as: Vl
alias VegaLite.Convert, as: VlConvert

@impl true
def render(assigns) do
  ~H"""
  <Layouts.app flash={@flash}>
    <img src={"data:image/png;base64,#{@blood_pressures_png}"}>
  </Layouts.app>
  """
end

解説

  • render
    • 画像を描画します
    • imgタグにbase64形式で画像データを渡します
lib/blood_pressure_record_web/live/blood_pressure_live/graph.ex
  @impl true
  def mount(_params, _session, socket) do
    {:ok,
     socket
     |> assign(:page_title, "Listing Blood pressures")
     |> assign(:blood_pressures_png, blood_pressures_png())}
  end

  defp blood_pressures_png() do
    BloodPressures.list_blood_pressures()
    |> Enum.map(&convert_data/1)
    |> List.flatten()
    |> draw_graph()
  end

  def convert_data(data) do
    date = NaiveDateTime.to_date(data.measured_at)

    [
      %{date: date, type: "最高血圧", value: data.systolic},
      %{date: date, type: "最低血圧", value: data.diastolic},
      %{date: date, type: "脈拍", value: data.pulse}
    ]
  end

  def draw_graph(data) do
    # 1. グラフ化するデータの定義 (ロングフォーマット)
    # 日付(date), 測定項目(type), 値(value) を持たせる

    # 2. Vega-Liteの定義
    Vl.new(width: 600, height: 400)
    # データをグラフに渡す
    |> Vl.data_from_values(data)
    # マークは折れ線のみを使用
    # point: trueでデータ点も表示し、見やすくする
    |> Vl.mark(:line, point: true)

    # X軸のエンコーディング: 日付は時系列データとして扱う
    |> Vl.encode_field(:x, "date",
      type: :temporal,
      title: "測定日",
      axis: [
        format: "%Y/%m/%d",
        tickCount: "day"
      ]
    )
    # Y軸のエンコーディング: 値をマッピング
    |> Vl.encode_field(:y, "value", type: :quantitative, title: "値 (mmHg または 拍/分)")
    # 色のエンコーディング: type(測定項目)ごとに色分けして、線を分ける
    |> Vl.encode_field(:color, "type", type: :nominal, title: "測定項目")

    # グラフの書き出し
    |> VlConvert.to_png()
    |> Base.encode64()
  end
end

解説

  • mount

    • ページを開いた時に実行されます
    • blood_pressures_pngでグラフの画像を作ります
  • blood_pressures_png

    • list_blood_pressuresでDBからデータを取得
    • convert_dataでグラフで扱える用にデータを変換
    • draw_graphでグラフを描く
  • draw_graph

    • 細かい内容はコメントを参照
    • VlConvert.to_pngでpng形式に変換
    • Base.encode64()でBase64形式に変換

Webサーバーを起動

$ mix phx.server

http://localhost:4000/graph アクセスしてください
グラフ画面を表示できます

image.png

ソース(各回共通のため更新されます)

おしまい

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?