新型コロナウイルス感染症データのグラフ化

0

まず初めに、最新の公開データをダウンロードしてみましょう。

厚生労働省が提供してくれています。

https://www.mhlw.go.jp/stf/covid-19/open-data.html

今回使用するのデータは

上記の5つにします。

新型コロナウイルス感染症データに登場する主なメソッド

new FileReader()
#Filereaderオブジェクトを生成する

FileReader.onload = 関数定義
#読み込みが成功したとき関数定義内の処理が実行される

FileReader.readAsText(ファイルオブジェクト)
#ファイルオブジェクトを読み込む。読み込まれた内容はresultプロパティに文字列として格納される。

FileReader.result
#読み込んだファイルの内容を返すプロパティ

文字列.split(区切り文字)
#指定した区切り文字で文字列を分割して配列として返す

new Date(日付文字列)
#Dataオブジェクト作成。引数の無い場合は現在の日時のオブジェクトが生成される。

getFullYear()
#Dataオブジェクトから4桁の年を取りだす

getDay()
#dateオブジェクトから曜日(0~6)を取り出す。日曜日は0、月曜日は1・・・土曜日は6

source

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>新型コロナウイルス感染症データ</title>
<script>
let canvas, context;                    //キャンバス
let titleData = new Array();               //タイトル
let numData = new Array();                //件数
let sDate = new Date(),eDate = new Date("2000/1/1");     //期間
let max = 100;                      //最大件数
const week = ["日","月","火","水","木","金","土"];    //曜日
const color = ["red","green","blue","magenta","gray"];    //グラフの色

const init = () => {
       //キャンバスの取得
    canvas = document.getElementById("graph");
        context = canvas.getContext("2d");
}

const loadData = files => {
       //CSVファイルの読み込み
     for (file of files) {
          const reader = new FileReader();
          reader.onload = () => {         //ファイルの読み込みが成功したとき
             //行に分割
       const rows = reader.result.split("\n"); //改行記号で分割する
            //データチェック
      const header = rows[0].split(",");
            if ((header.length == 2)&&(header[0]=="日付")
             &&(titleData. indexOf(header[1]) == -1)) { //タイトルデータがないなら
       //タイトルをセット
             const index = titleData. length;
              titleData[index] = header[1];      //タイトルデータ追加
        const title = document.createElement("span");
              title.innerHTML = `■${header[1]}`;
              title.style.color = color[index];
              document.getElementById("guide").appendChild(title); //データ名表示エリア
           	 //件数をセット
			  numData[index] = new Array();
              for(let i=1; i<rows, length; i++) {   //データの行数分繰り返す
            	const data = row[i].split(",");
            	const target = new Date(data[0]);  //日付データ
            	const num = Number(data[1]);
				numData[index][getYMD(target)] = num;
              	if (sDate > target) sDate = target; //開始日を求める
				if (eDate < target) eDate = target; //終了日を求める
				if (max < num) max = num; //データの最大値を求める
             }
           }
         //表、グラフを表示
     drawGraph();
       }
       reader.readAsText(file);
       }
    }

const getYMD = (targetDate,format = "ymd") => {     //formatデフォルト値「ymd」
  //日付 (yyyy-mm-dd)を取得
  const yyyy = targetDate.getFullYear();
  const mm = ("00" + (targetDate.getMonth()+1)).slice(-2); //年月日曜日求める
  const dd = ("00" + (targetDate.getDate())).slice(-2);
  const day = targetDate.getDay();
  let ret = `${yyyy}/${mm}/${dd}`
  if (format == "ymdd") ret = `${yyyy}/${mm}/${dd} (${week[day]})`;
  if (format == "md") ret = `${mm}/${dd}`;
  return ret;
}

const drawText = {text,x,y,base,align) => {
  //テキストの描画
  context.font = "10px sans-serif";     //文字サイズ
  context.textBaseline = base;               //文字の基準位置
  context.textAlign = align;
  context.fillText(text,x,y);
}

const drawGraph = () => {
    //グラフの作成
  context.clearRect(0,0,canvas.width,canvas.height);
   context.strokeStyle = "black";
    context.beginPath();
    context.moveTo(50,0);
    context.lineTo(50,350);
    context.lineTo(750,350);
    context.stroke();
    //ラベル(縦軸)の描画
    const h = Math.celi(max/1000) * 1000;
    drawText(h/4,45,350*(1-(h/4)/max),"middle","right");
    drawText(h/2,45,350*(1-(h/2/max),"middle","right");
    drawText(h/4*3,45,350*(1-(h/4*3/max),"middle","right");
    //ラベル(横軸)の描画
    let [target,cnt] = [new Date(sDate),0];
    const w = Math.floor((eDate - sDate)/(60*60*24*1000));
    while (target <= eDate) {
        drawText(getYMD(target,"md"),50+cnt/w*700,360,"top","center"),
        target.setDate(target.getDate() + 14); //横軸に2週間ごとの日付表示
        cnt  += 14;
    }
    //折れ線グラフの描画   
	for (let i=0; i<titleData. length; i++) {
		context.strokeStyle = color[i];
		context.beginPath();
		[target,cnt] = [new Date(sDate),0];
		while (target <= eDate) {
			let num = numData[i][getYMD(target)];
			if (num == undefined) num = 0;
			const x = 50 + cnt/w*700;
			const y = 350 * (1 - num/max);
			if (target == sDate) context.moveTo(x,y);
			if (target > sDate) context.lineTo(x,y);
			target.setDate(target.getDate() + 1);
			cnt++;
		}
			context.stroke();
	}
	//表の作成
	const table = document.getElementById("dataTable");
	table.innerHTML = "";
	//ヘッダ("日付"、各タイトル)
	const header = document.createElement("tr");
	const td = document.createElement("td");
	td.innerText = "日付";
	header.appendChild(td);
	for (let i=0; i<titleData. length; i++) {
		const td = document.createElement("td");
		td.innerText = titleData[i];
		header.appendChild(td);
	}
	table.appendChild(header);
	//データ(日付、各件数)
	target = new Date(sDate);
	while (target <= eDate) {
		const data = document.createElement("tr");
		//日付
		const td = document.createElement("td");
		td.style.textAlign = "left";
		td.innerText = getYMD(target,"ymdd");     //曜日付き日付の表示
		data.appendChild(td);
		//件数
		for (let i=0; i<titleData. length; i++) {
			const td = document.createElement("td");
			td.style.textAlign = "right";
			let num = numData[i][getYMD(target)];
			if (num == undefined) num = "--";
			td.innerText = num;
			data.appendChild(td);
		}
		table.appendChild(data);
		target.setDate(target.getDate() + 1);
	}
}
</script>
<style>
#scroll {
    height: 200px;
    overflow-y: scroll;       
}
table {border-collapse: collapse;}
td {
    font-size: small;
    text-align: center;
    border: thin solid #000000;
}
</style>
</head>
<body onload="init()">
<p>新型コロナウイルス感染症データ</p>
<a href="https://www.mhlw.go.jp/content/pcr_positive_daily.csv">
陽性者数</a>
<a href="https://www.mhlw.go.jp/content/pcr_tested_daily.csv">
PCR検査実施数</a>
<a href="https://www.mhlw.go.jp/content/cases_total.csv">
入院治療者数</a>
<a href="https://www.mhlw.go.jp/content/recovery_total.csv">
退院数</a>
<a href="https://www.mhlw.go.jp/content/death_total.csv">
死亡者数</a>
<input type="file" multiple accept=".csv" onchange="loadData(this.files)"><hr>
<div id="guide"></div>
<canvas id="graph" width="800" height="400"></canvas><hr>
<div id="scroll"><table id="dataTable"></table></div>
</body>
</html>

数字をグラフという視覚的に見ることで流れと傾向の把握がなんとなく予測でき心の安心にも繋がると思い、取り組んでみることにしました。