0%

温度可视化

时序数据,使用简单的 HTML 对其进行展示。

需求描述

树莓派折腾记录 中"获取小米温湿度计"的数据, 现在有了若干数据后,希望用一种直观的方式展示出来。

解决方案

不想用复杂的前后端代码,希望用最简单的方式画一个折线图即可。所以解决方案是,用 Python 处理日志数据,将其保存到 json 中,最后用 HTML 结合现有的可视化库进行展示。为了有一定的实时性,所以在用 Python 处理日志时,也需要一个定时任务,以定期更新前端页面的数据。

一种不太优雅的方案,可以用 Python 的画图库,将其导出为图片,然后用 HTML 的 img 标签进行展示。但是这样的话,图片的大小就不好控制了,而且也不太好看。所以还是用 HTML 的可视化库比较好。

1
2
3
4
5
6
7
8
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<img src="static/pi_data.png" alt="温度曲线">
</body>
</html>

代码实现

用 Google 的可视化库 https://www.gstatic.com/charts/loader.js,下载后将其保存在本地。

成品展示:https://raspberrypi.tail54f27.ts.net/temp。为了节约显示数据,Python 中只处理过去 24 小时的数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
<html>

<head>
<script type="text/javascript" src="static/loader.js"></script>
<script type="text/javascript">
google.charts.load('current', { 'packages': ['corechart'] });
/*
读取 json 文件,约定好几个字段 data, title, left_label, right_label 即可
其中,data 是一个二维数组,第一列是时间,第二列是温度,第三列是湿度。但第一行是标题 ["横坐标标题", "第x条线的标题"]。
left_label 是左边的纵坐标标题,right_label 是右边的纵坐标标题。
*/

fetch('static/pi_data.json')
.then(response => response.json())
.then(data => {
var drawChart_callback = drawChart(data.data, "chart", data.title, data.left_label, data.right_label);
google.charts.setOnLoadCallback(drawChart_callback);
})
.catch(error => {
console.error('读取JSON文件时出错:', error);
});
function drawChart(data_arr, chart_id, title, left_label, right_label) {
return function () {
var data = google.visualization.arrayToDataTable(data_arr);

var options = {
hAxis: {
useFormatFromData: true,
viewWindow: null,
minValue: null,
maxValue: null,
viewWindowMode: null,
},
legacyScatterChartLabels: true,
vAxes: [{
"useFormatFromData": true,
"viewWindow": { "max": null, "min": null },
"minValue": null,
"maxValue": null,
"title": left_label,
"logScale": false,
}, {
"useFormatFromData": true,
"viewWindow": { "max": null, "min": null },
"minValue": null,
"maxValue": null,
"title": right_label,
"logScale": false,
}],
booleanRole: "certainty",
lineWidth: 2,
legend: "top",
title: title,
fontName: "sans-serif",
useFirstColumnAsDomain: false,
titleTextStyle: { "color": "#000", "fontSize": 24, "bold": true },
series: { "1": { "targetAxisIndex": 1 } },
curveType: "",
interpolateNulls: true,
series: {
"2": {
"targetAxisIndex": 1
}
} /* 这个字段用于控制第几列放在右边?作为调整左右纵坐标位置的参数,2表示用第3列的数据*/
};
var isDefaultVisualization = true;
var chart = new google.visualization.LineChart(document.getElementById(chart_id));

chart.draw(data, options, isDefaultVisualization);
}
}
</script>
<style>
.container {
display: flex;
flex-wrap: wrap;
}

.chart {
flex-basis: 50%;
width: auto;
height: 400px;
}
</style>
</head>

<body>
<div id="chart" class="chart"></div>
</body>

</html>