Zur besten Antwort gewählt
Okt 27, 2017 - 12:22
Ich habe mir diverse verfügbare Grafik-Bibliotheken angeschaut und mich letztendlich für JPGraph entschieden. Ich habe nach einem einfachen Paket gesucht, das Grafiken erstellen kann; Interaktion etc. war mir nicht so wichtig.
Die Programmierung erfolgt in PHP.
Wenn man Interaktion haben möchte und Javascript nicht scheut, wäre Highchart meine Alternative. Das ist natürlich eine persönliche Entscheidung, die auch stark davon abhängt, was man damit erreichen will, Installationsanleitung man braucht dafür natürliche einen laufenden Web-Server, wobei man immer darüber nachdenken muss, ob dieser ausserhalb des eigenen WLAN's erreichbar sein muss oder darf. Ich habe die Installation auf meiner Synology-Diskstation durchgeführt. Bitte beachten, das die GD-Library und die FreeType-Unterstützung von php aktiviert ist (auf den Synology siehe Modul Web-Server). Zuerst die aktuelle Version ermitteln, das kann man hier machen.
Dann installieren (den ermittelten Link verwenden, zur Zeit ist die Version 4.1.0).
Hinweis: es sind nur FONT1 .. FONT3 vorhanden (was grundsätzlich reicht), die zusätzlichen vorgesehenen TrueType-Fonts (.ttf) kann man hier downloaden:
http://ftp.gnome.org/pub/GNOME/source... https://sourceforge.net/projects/deja... http://www.egr.msu.edu/apps/tools/jpg... Diese in das Web-Verzeichnis nach /volume1/web/jpgraph/fonts kopieren Dokumentation gibt es hier: http://jpgraph.net/download/manuals/
sowie einige Tutorials http://www.binnendijk.net/jpgraph/ (Anmerkung: die Notiz zu "CACHE_DIR" ist obsolete) http://www.kiddinx.de/portal/includes... http://www.inisnet.de/inisnet/jggraph/
Das hier gezeigte Script dient dazu, Datenpunkte anzuzeigen, die ich zyklische speichere (siehe hier).
Ich habe das Script so angelegt, das man es per Parameter etwas steuern kann; diese Grafiken kommen dann heraus:
In der der Fernbedienung habe ich das als normale Webseite eigebunden, die dieses Script aufruft.
Es sind also 4 Grafiken, Temperatur und Luftfeuchtigkeit jeweils mit den Min/Max-Werten pro Tag für die letzten 14 Tagen und die aktuellen Werte des Tages jeweils der Mittelwert / Stunde.
die beiden anderen Grafiken kann man per Scrollen erreichen.
Das Ganze ist natürlich mehr gedacht als Vorlage für eigene Entwicklungen und als Beispiel.
Die Programmierung erfolgt in PHP.
Wenn man Interaktion haben möchte und Javascript nicht scheut, wäre Highchart meine Alternative. Das ist natürlich eine persönliche Entscheidung, die auch stark davon abhängt, was man damit erreichen will, Installationsanleitung man braucht dafür natürliche einen laufenden Web-Server, wobei man immer darüber nachdenken muss, ob dieser ausserhalb des eigenen WLAN's erreichbar sein muss oder darf. Ich habe die Installation auf meiner Synology-Diskstation durchgeführt. Bitte beachten, das die GD-Library und die FreeType-Unterstützung von php aktiviert ist (auf den Synology siehe Modul Web-Server). Zuerst die aktuelle Version ermitteln, das kann man hier machen.
Dann installieren (den ermittelten Link verwenden, zur Zeit ist die Version 4.1.0).
cd /volume1/web
mkdir tmp
cd tmp
wget --output-document=jpgraph.tar.gz http://jpgraph.net/download/download....
tar xvfz jpgraph.tar.gz
mv jpgraph-4.1.0/ ../jpgraph
Hinweis: es sind nur FONT1 .. FONT3 vorhanden (was grundsätzlich reicht), die zusätzlichen vorgesehenen TrueType-Fonts (.ttf) kann man hier downloaden:
http://ftp.gnome.org/pub/GNOME/source... https://sourceforge.net/projects/deja... http://www.egr.msu.edu/apps/tools/jpg... Diese in das Web-Verzeichnis nach /volume1/web/jpgraph/fonts kopieren Dokumentation gibt es hier: http://jpgraph.net/download/manuals/
sowie einige Tutorials http://www.binnendijk.net/jpgraph/ (Anmerkung: die Notiz zu "CACHE_DIR" ist obsolete) http://www.kiddinx.de/portal/includes... http://www.inisnet.de/inisnet/jggraph/
Das hier gezeigte Script dient dazu, Datenpunkte anzuzeigen, die ich zyklische speichere (siehe hier).
<?php
// Zugangsdaten
$db_host = "localhost";
$db_user = "mediola";
$db_password = "mediola";
$db_name = "mediola";
include "../jpgraph/jpgraph.php";
include "../jpgraph/jpgraph_date.php";
include "../jpgraph/jpgraph_line.php";
include "../jpgraph/jpgraph_scatter.php";
date_default_timezone_set("Europe/Berlin");
// Datenpunkt
if (!isset($_GET["tag"])) {
error_log("Option 'tag' fehlt\n");
exit(1);
}
$tag = $_GET["tag"];
switch ($tag) {
case "GW_temperatur":
$title = "Temperatur";
break;
case "GW_humidity":
$title = "Luftfeuchtigkeit";
break;
default:
error_log("Option 'tag' hat unbekannten Wert '$tag'\n");
exit(1);
}
// Dimension der Zeitachse
$time_dim = isset($_GET["time_dim"]) ? $_GET["time_dim"] : "DAY";
switch ($time_dim) {
case "MONTH":
$date_format = "%Y-%m";
if ($time_range == "")
$time_range = "6";
$xdata_interval = 2;
$tstamp_fmt = "d/m";
$title .= " (" . $time_range . " Monate)";
break;
case "WEEK":
$date_format = "%Y-%u";
if ($time_range == "")
$time_range = "6";
$xdata_interval = 2;
$tstamp_fmt = "W/y";
$title .= " (" . $time_range . " Wochen)";
break;
case "DAY":
$date_format = "%Y-%m-%d";
if ($time_range == "")
$time_range = "14";
$xdata_interval = 3;
$tstamp_fmt = "d.m.";
$title .= " (" . $time_range . " Tage)";
break;
case "HOUR":
$date_format = "%Y-%m-%d %H";
if ($time_range == "")
$time_range = "24";
$xdata_interval = 3;
$tstamp_fmt = "H";
$title .= " (" . $time_range . " Stunden)";
break;
default:
error_log("Option 'time_dim' hat unbekannten Wert '$time_dim'\n");
exit(1);
}
// Länge der Zeitachse
$time_range = isset($_GET["time_range"]) ? $_GET["time_range"] : $time_range;
if (!is_numeric($time_range)) {
error_log("Option 'time_range' hat unzulässigen Wert '$time_range'\n");
exit(1);
}
// Art der Grafik
$graph_mode = isset($_GET["graph_mode"]) ? $_GET["graph_mode"] : "scatter";
switch ($graph_mode) {
case "line":
case "scatter":
break;
default:
error_log("Option 'graph_mode' hat unbekannten Wert '$graph_mode'\n");
exit(1);
}
// Art der Datenpunkte
$data_spec = isset($_GET["data_spec"]) ? $_GET["data_spec"] : "single";
switch ($data_spec) {
case "single":
case "avrg":
switch ($tag) {
case "GW_temperatur":
$color0 = "darkgreen";
break;
case "GW_humidity":
$color0 = "darkblue";
break;
}
break;
case "minmax":
switch ($tag) {
case "GW_temperatur":
$color0 = "red";
$color1 = "darkgreen";
break;
case "GW_humidity":
$color0 = "darkorange";
$color1 = "darkblue";
break;
}
break;
default:
error_log("Option 'data_spec' hat unbekannten Wert '$data_spec'\n");
exit(1);
}
// X-Achse ist der Zeitstempel
$xdata = array();
// Y-Achsen für zwei Messwert-Kurven
$ydata0 = array();
$ydata1 = array();
// Messbereich ermitteln und etwas vergrößern, damit die Kurven etwas "Abstand" haben
$ydata_lo = "";
$ydata_hi = "";
// Daten holen
$pdo = new PDO('mysql:host=' . $db_host . ';dbname=' . $db_name, $db_user, $db_password);
$sql = "select tstamp, ";
switch ($data_spec) {
case "single":
$sql .= "value as val0";
break;
case "avrg":
$sql .= "avg(value) as val0";
break;
case "minmax":
$sql .= "min(value) as val0, max(value) as val1";
break;
}
$sql .= " from measurements where tag = \"" . $tag . "\" and timestampdiff(" . $time_dim . ", tstamp, current_timestamp()) <= " . $time_range;
switch ($data_spec) {
case "avrg":
case "minmax":
$sql .= " group by date_format(tstamp, '" . $date_format . "')";
break;
}
$sql .= " order by tstamp";
error_log("sql=" . $sql . "\n");
foreach ($pdo->query($sql) as $row) {
$fail = 0;
$ts = $row["tstamp"];
if ($ts == "")
$fail = 1;
$val0 = $row["val0"];
if ($val0 == "" || !is_numeric($val0))
$fail = 1;
switch ($data_spec) {
case "minmax":
$val1 = $row["val1"];
if ($val1 == "" || !is_numeric($val1))
$fail = 1;
break;
}
// Zeilen mit ungültigen Daten überspringen
if ($fail)
continue;
// timestamp in benötigte UNIX-Format wandeln
$xdata[] = strtotime($ts);
// 1. Wert
$ydata0[] = $val0;
// minimalen und maximalen Wert ermitteln
if ($ydata_lo == "" || $val0 < $ydata_lo)
$ydata_lo = $val0;
if ($ydata_hi == "" || $val0 > $ydata_hi)
$ydata_hi = $val0;
switch ($data_spec) {
case "minmax":
// 2. Wert
$ydata1[] = $val1;
// minimalen und maximalen Wert ermitteln
if ($ydata_lo == "" || $val1 < $ydata_lo)
$ydata_lo = $val1;
if ($ydata_hi == "" || $val1 > $ydata_hi)
$ydata_hi = $val1;
break;
}
}
// bei weniger als 2 Datenpunkten streikt die Bibliothek
if (count($xdata) < 2) {
$xdata = array(0,$xdata[0]);
$ydata0 = array(0,$ydata0[0]);
$ydata1 = array(0,$ydata1[0]);
$ydata_lo = 0;
}
if (count($xdata) < 1) {
$xdata = array(0,1);
$ydata0 = array(0,0);
$ydata1 = array(0,0);
$ydata_lo = 0;
$ydata_hi = 0;
}
if (is_numeric($ydata_lo) && is_numeric($ydata_hi)) {
// oberer/unterer Punkt soll nicht auf der Grenze liegen
$i = ($ydata_hi - $ydata_lo) / 10;
$ydata_lo -= $i;
$ydata_hi += $i;
// gleiche oder nächste kleinere ganze Zahl
$ydata_lo = floor($ydata_lo);
// gleiche oder nächste größere ganze Zahl
$ydata_hi = round($ydata_hi + 0.5);
}
// Grafik erstellen
$graph = new Graph(300,150,"auto");
$graph->img->SetMargin(35,20,20,25);
$graph->SetShadow();
// X-Achse ist Zeitstempel, Y-Achse die Werte
$graph->SetScale('datlin');
switch ($graph_mode) {
case "line":
$lineplot0 = new LinePlot($ydata0,$xdata);
$graph->Add($lineplot0);
$lineplot0->SetWeight(2);
$lineplot0->SetColor($color0);
switch ($data_spec) {
case "minmax":
$lineplot1 = new LinePlot($ydata1,$xdata);
$graph->Add($lineplot1);
$lineplot1->SetColor($color1);
$lineplot1->SetWeight(2);
break;
}
break;
case "scatter":
$scplot0 = new ScatterPlot($ydata0,$xdata);
$scplot0->mark->SetType(MARK_CIRCLE);
$scplot0->mark->SetColor($color0);
$scplot0->mark->SetWidth(0.75);
$graph->Add($scplot0);
switch ($data_spec) {
case "minmax":
$scplot1 = new ScatterPlot($ydata1,$xdata);
$scplot1->mark->SetType(MARK_CIRCLE);
$scplot1->mark->SetColor($color1);
$scplot1->mark->SetWidth(0.75);
$graph->Add($scplot1);
break;
}
break;
}
$graph->title->Set($title);
$graph->title->SetFont(FF_ARIAL,FS_BOLD);
$graph->xaxis->scale->SetDateFormat($tstamp_fmt);
$graph->xaxis->SetTextLabelInterval($xdata_interval);
$graph->xaxis->SetLabelAngle(0);
$graph->yaxis->SetWeight(2);
$graph->yaxis->SetLabelFormatString("%d");
$graph->yaxis->scale->SetAutoMin($ydata_lo);
$graph->yaxis->scale->SetAutoMax($ydata_hi);
$graph->Stroke();
exit(0);
?>
Ich habe das Script so angelegt, das man es per Parameter etwas steuern kann; diese Grafiken kommen dann heraus:
In der der Fernbedienung habe ich das als normale Webseite eigebunden, die dieses Script aufruft.
<?php
echo "<!DOCTYPE html>\n";
echo "<html>\n";
echo "<head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n";
echo "<title>Gewächshaus-Klima</title>\n";
echo "<style>\n";
echo "html { height: 100%; background-color: darkgrey; overflow: hidden; }\n";
echo "body { table-cell; text-align: left; vertical-align: top; height: 100%; }\n";
echo "</style>\n";
echo "</head>\n";
echo "<body>\n";
echo "<img src=\"measurements.php?tag=GW_temperatur&time_dim=DAY&time_range=14&
;data_spec=minmax&graph_mode=line\">\n";
echo "<br>\n";
echo "<img src=\"measurements.php?tag=GW_humidity&time_dim=DAY&time_range=14&d
ata_spec=minmax&graph_mode=line\">\n";
echo "<br>\n";
echo "<br>\n";
echo "<img src=\"measurements.php?tag=GW_temperatur&time_dim=HOUR&time_range=24&am
p;data_spec=avrg&graph_mode=line\">\n";
echo "<br>\n";
echo "<img src=\"measurements.php?tag=GW_humidity&time_dim=HOUR&time_range=24&
data_spec=avrg&graph_mode=line\">\n";
echo "<br>\n";
echo "</body>\n";
echo "</html>\n";
exit(0);
?>
Es sind also 4 Grafiken, Temperatur und Luftfeuchtigkeit jeweils mit den Min/Max-Werten pro Tag für die letzten 14 Tagen und die aktuellen Werte des Tages jeweils der Mittelwert / Stunde.
die beiden anderen Grafiken kann man per Scrollen erreichen.
Das Ganze ist natürlich mehr gedacht als Vorlage für eigene Entwicklungen und als Beispiel.
Neuen Kommentar hinzufügen