タイトル : 血圧降下剤の処方数量 データをチャートで表示する rechartsを使う
更新日 : 2024-03-31
カテゴリ : プログラミング
タグ :
opendata   
python   
fastapi   
nextjs   
recharts   
datagrid   

データをチャートでみてみましょう

チャート表示はrechartsを使うことにしました。

nextjsで使うといろいろ警告とか出るのでちょっと面倒ですね。まあしょうがないかな

画像

チャートで比較すると、飲んでいる薬のジルムロが使われるようになった分、ザクラスが減ったのかな。

今更だけど、飲んでいる薬の数量データが1年分しかない。ジルムロの複数年データがないと確認し難いかな...

ソース

フロントエンドのチャートのコンポーネントです

"use client"

import { Stack } from "@mui/material";
import React from "react";
import { CartesianGrid, Legend, Line, LineChart, Tooltip, XAxis, YAxis} from 'recharts';

// Support for defaultProps will be removed from function components in a future major release. 
// Use JavaScript default parameters instead. at {Component} 
// https://github.com/recharts/recharts/issues/3615
const error = console.error;
console.error = (...args: any) => {
  if (/defaultProps/.test(args[0])) return;
  error(...args);
};

type MychartProps = {
    data: any;  // データ
    lines: any[];  // データ
    xaxisDataKey : string;
};

export const MyChart: React.FC<MychartProps> = (props) => {

  return (
    <Stack padding={2} spacing={1}>
      <LineChart width={830} height={250} data={props.data}
        margin={{ top: 5, right: 30, left: 50, bottom: 5 }}>
        <CartesianGrid strokeDasharray="3 3" />
        <XAxis dataKey={props.xaxisDataKey} />
        <YAxis />
        <Tooltip />
        <Legend />
        {
            props.lines.map((line:any) => {
                return (
                  <Line key={line.dataKey} type={line.type} name={line.name} dataKey={line.dataKey} stroke={line.stroke} />
                )
              })
        }
      </LineChart>
    </Stack>
  );
}

フロントエンドのpage.tsxです

"use client"

import { Typography, Stack, Button } from "@mui/material";
import { DataGrid, GridRowSelectionModel,  useGridApiContext, GridPagination,
  useGridSelector, gridPageCountSelector } from '@mui/x-data-grid';
import MuiPagination from '@mui/material/Pagination';
import { TablePaginationProps } from '@mui/material/TablePagination';
import dynamic from 'next/dynamic'

import { useEffect, useState } from "react";

import { API_URL } from "@/store/settings";
import { IyCodeInfo , IyCodeChartInfo} from "@/openapi_generated";

/*
Next.jsでRechartsを使うと ConsoleにWarningが出る
https://zenn.dev/tanoshima/articles/10a26f3741333f

Rechart を Next.js で使うと「Warning: Prop id did not match. Server:」 が発生
https://qiita.com/dosukoi_man/items/bab4aa4b8eceb8aab1a3
*/
const MyChartImpoet = dynamic(
  () =>
    import("@/components/mychart").then((mod) => mod.MyChart),
  { ssr: false }
)

function MyChartOn({ data ,lines,xaxisDataKey }: any) {
  return <MyChartImpoet data={data} lines={lines} xaxisDataKey={xaxisDataKey}/>
}

function Pagination({
  page,
  onPageChange,
  className,
}: Pick<TablePaginationProps, 'page' | 'onPageChange' | 'className'>) {
  const apiRef = useGridApiContext();
  const pageCount = useGridSelector(apiRef, gridPageCountSelector);

  return (
    <MuiPagination
      color="primary"
      className={className}
      count={pageCount}
      page={page + 1}
      onChange={(event, newPage) => {
        onPageChange(event as any, newPage - 1);
      }}
    />
  );
}

function CustomPagination(props: any) {
  return <GridPagination ActionsComponent={Pagination} {...props} />;
}

export default function Home() {

  // 血圧降下剤をデフォルトにしておく
  const categoryId = "214";

  const [rowSelectionModel, setRowSelectionModel] = useState<GridRowSelectionModel>([]);

  const [columns, setColumns] = useState([{field: 'id', headerName: 'ID'}]);
  const [rows, setRows] = useState([{"id": 1}]);

  const [chartData, setChartData] = useState([{}]);
  const [chartLines, setChartLines] = useState([{}]);
  const [chartXAxisDataKey, setChartXAxisDataKey] = useState("");

  const fetchData = async (iyCode:String) => {
    try {
        const response = await fetch(`${API_URL}/iycode/${iyCode}`);
        const res_json = await response.json();
        const iyCodeInfo:IyCodeInfo = res_json.iyCodeInfo
        return iyCodeInfo
    } catch (error) {
        console.error("Error fetching IyCode Data", error);
        const iyCodeInfo:IyCodeInfo = {
          iycodes: [],
          columns: [],
          rows: []
        }
        return iyCodeInfo
    }
  }

  const fetchChartData = async (iyCodes:Number[]) => {
    try {
        let queryString = ""
        iyCodes.map((iycode, index) =>{
          if ( index == 0) {
            queryString += `iycodes=${iycode}`
          } else {
            queryString += `&iycodes=${iycode}`
          }
        })
        console.log("queryString : ", queryString);
        const response = await fetch(`${API_URL}/chart?${queryString}`);

        const res_json = await response.json();
        console.log("res_json : ", res_json);
        const iyCodeChartInfo:IyCodeChartInfo = res_json.iyCodeChartInfo
        return iyCodeChartInfo
    } catch (error) {
        console.error("Error fetching IyCode ChartData", error);
        const iyCodeChartInfo:IyCodeChartInfo = {
          data: [],
          lines: [],
          xaxisDataKey: ""
        }
        return iyCodeChartInfo
    }
  }

  const dispChart = async () => {
    console.log(rowSelectionModel)
    const iyCodeChartInfo: IyCodeChartInfo = await fetchChartData(rowSelectionModel as Number[])

    setChartData(iyCodeChartInfo.data as any)
    setChartLines(iyCodeChartInfo.lines as any)
    setChartXAxisDataKey(iyCodeChartInfo.xaxisDataKey as any)
  };

  useEffect(() => {
    setData(categoryId)
  }, []);

  const setData = async (iyCodeStr: String) => {
    const iyCodeInfo = await fetchData(iyCodeStr)

    // TODO : any使わないようにしないと
    setColumns(iyCodeInfo.columns as any)
    setRows(iyCodeInfo.rows as any)
  };
 
  return (
    <Stack padding={2} spacing={1}>
      <Typography color={"secondary"}>血圧降下剤-医薬品名</Typography>
      <DataGrid
        rows={rows}
        density="compact"
        rowHeight={30}
        columns={columns}
        initialState={{
          pagination: {
            paginationModel: {
              pageSize: 5,
            },
          },
        }}
        pageSizeOptions={[5,10]}
        slots={{
          pagination: CustomPagination,
        }}

        checkboxSelection
        onRowSelectionModelChange={(newRowSelectionModel) => {
          setRowSelectionModel(newRowSelectionModel);
        }}
        rowSelectionModel={rowSelectionModel}
        disableRowSelectionOnClick
      />
      <Stack spacing={2}>
        <Button sx={{width:110}}size={"small"} variant={"contained"} onClick={dispChart}>チャート表示</Button>
        <MyChartOn data={chartData} lines={chartLines} xaxisDataKey={chartXAxisDataKey}/>
      </Stack>
    </Stack>
  );
}