Grafikbibliothek:imageline() liefert krumme Werte


Status
Dieses Thema wurde gelöst! Zur Lösung gehen…

tklustig

Erfahrenes Mitglied
#1
Hallo Leute,
folgender Code liefert eine ungenau Ausgabe an Temperaturwerten aus der Datenbank. Die Achsenbeschriftungen stimmen soweit, allerdings wird die temperatur nur andeutungsweise ausgegeben. Die Temperaturwerte im Array lauten: 11,11,11,12,12,12,12,12,12,13,13,13
So sieht's aus:
tempgraphicsPHP.jpg

hier der Code:
PHP:
<?php

session_start();
error_reporting(E_ALL ^ E_NOTICE);
// Grafik erzeugen
$im = imagecreate(400, 400);
// Farben, Schriftart
$grau = imagecolorallocate($im, 192, 192, 192);
imagefill($im, 0, 0, $grau);
$s = imagecolorallocate($im, 0, 0, 0);
$r = imagecolorallocate($im, 255, 0, 0);
$folder = getcwd();
$schriftart = $folder . "/inc/Free Hustle Hardcore.ttf";
// Werte
spl_autoload_register('classAutoloader');
$DatabaseObject = new MySQLClass('root', '', 'mysql', '192.168.1.10', 'temperatur');
$connection = $DatabaseObject->Verbinden();
if (!$connection){
    print_r("MySQL-Aufbau ist gescheitert!");
    die();
}
if (isset($_SESSION['pk']))
    $id = $_SESSION['pk'];
else
    $id = 100;
$sql = "SELECT id,Temperatur_Celsius,Luftfeuchtigkeit_Prozent,datum,uhrzeit FROM temperaturs WHERE id>=$id ORDER BY id ASC LIMIT 12";
$query1 = $DatabaseObject->Abfragen($connection, $sql);
$temperaturA = array();
$uhrzeitA = array();
for ($i = 0; $i < count($query1); $i++) {
    $record = $query1[$i]['Temperatur_Celsius'];
    array_push($temperaturA, $record);
    $record = $query1[$i]['uhrzeit'];
    array_push($uhrzeitA, $record);
}
// Gitternetz, Beschriftung
for ($i = 0; $i < count($uhrzeitA); $i++) {
    imageline($im, 30, 30 + $i * 340 / count($uhrzeitA), 370, 30 + $i * 340 / count($uhrzeitA), $s);
    imagettftext($im, 11, 0, 375, 30 + $i * 340 / count($uhrzeitA), $s, $schriftart, max($temperaturA) - $i);
    imageline($im, 30 + $i * 340 / count($uhrzeitA), 30, 30 + $i * 340 / count($uhrzeitA), 370, $s);
    $time = date("G:i", strtotime($uhrzeitA[$i]));
    imagettftext($im, 11, 0, 25 + $i * 340 / count($uhrzeitA), 380, $s, $schriftart, $time);
}

// Temperatur darstellen:11,11,11,12,12,12,12,12,12,13,13,13
for ($i = 0; $i < count($temperaturA) - 1; $i++) {
    imageline($im, ($i + 1) * 300 / 10, 130 - $temperaturA[$i] * 130 / 50, ($i + 2) * 300 / 10, 130 - $temperaturA[$i + 1] * 130 / 50, $r);
}
// Grafik darstellen
header("Content-Type: image/jpeg");
imagejpeg($im);

// Speicher freigeben
imagedestroy($im);
?>
 

Anhänge

Zuletzt bearbeitet:

tklustig

Erfahrenes Mitglied
#3
Sieht vielversprechend aus.
Diesem Beispiel wird das Array übergeben, und Fertig! Genau das, was ich eigentlich brauche. Nichts desto Trotz: Vielleicht weiß der eine oder andere, wie man das Array $temperaturA grafisch darstellt? Eigentlich muß 'nur' die zählerindizierte Schleife
PHP:
// Temperatur darstellen:11,11,11,12,12,12,12,12,12,13,13,13
for ($i = 0; $i < count($temperaturA) - 1; $i++) {
    imageline($im, ($i + 1) * 300 / 10, 130 - $temperaturA[$i] * 130 / 50, ($i + 2) * 300 / 10, 130 - $temperaturA[$i + 1] * 130 / 50, $r);
}
korrekt implementiert werden...
 

Sempervivum

Erfahrenes Mitglied
#4
Ich empfehle, die Umrechnung der Werte (Zeit, Temp., Feuchte) in Pixel-Koordinaten nicht bei jedem Gebrauch auszuformulieren, sondern dafür Funktionen zu definieren, dann wird das Ganze übersichtlicher:
Code:
// Grafik erzeugen
$im = imagecreate(400, 500);
// Farben, Schriftart
$grau = imagecolorallocate($im, 192, 192, 192);
imagefill($im, 0, 0, $grau);
$s = imagecolorallocate($im, 0, 0, 0);
$r = imagecolorallocate($im, 255, 0, 0);
$b = imagecolorallocate($im, 0, 0, 255);
$folder = getcwd();
$schriftart = $folder . "/century-gothic.ttf";

// die Daten, Temperatur und Feuchte (y-Achse) sowie Uhrzeit (x-Achse)
$temperaturA = [11,11,11,12,12,12,12,12,12,13,13,13];
$feuchteA = [70, 70, 75, 75, 80, 80, 85, 85, 90, 90, 85, 85];
$uhrzeitA = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"];

// Ursprung des Koordinatensystems in px festlegen
$xursprung = 10;
$yursprung = 470;

// Faktoren für Umrechnung der Indizes in px
$factorx = 30;
$factory = 30;

// Faktor um die Darstellung der Feuchte umzurechnen
$factoryhum = 10;

// Anzahl der Rasterlinien
$nrx = 11;
$nry = 15;

// x-Koordinate in px aus x-Wert ermitteln
function getx($x) {
    global $xursprung, $factorx;
    return $xursprung + $x * $factorx;
}

// y-Koordinate in px aus y-Wert ermitteln
function gety($y) {
    global $yursprung, $factory;
    return $yursprung - $y * $factory;
}

// Gitternetz, Beschriftung

// vertikale Linien mit Beschriftung
for ($i = 0; $i <= $nrx; $i++) {
    imageline($im, getx($i), gety(0), getx($i), gety($nry), $s);
    imagettftext($im, 11, 0, getx($i), gety(0) + 15, $s, $schriftart, $uhrzeitA[$i]);
}

// horizontale Linien mit Beschriftung
for ($j = 0; $j <= $nry; $j++) {
    imageline($im, getx(0), gety($j), getx($nrx), gety($j), $s);
    imagettftext($im, 11, 0, getx($nrx) + 5, gety($j), $r, $schriftart, $j);
    imagettftext($im, 11, 0, getx($nrx) + 25, gety($j), $b, $schriftart, $j * $factoryhum);
}

// Temperatur- und Feuchtewerte eintragen
for ($k = 0; $k < $nrx; $k++) {
    imageline($im, getx($k), gety($temperaturA[$k]), getx($k + 1), gety($temperaturA[$k + 1]), $r);
    imageline($im, getx($k), gety($feuchteA[$k] / $factoryhum), getx($k + 1), gety($feuchteA[$k + 1] / $factoryhum), $b);
}

// Grafik darstellen
header("Content-Type: image/jpeg");
imagejpeg($im);

// Speicher freigeben
imagedestroy($im);
Man gewinnt dabei eine Vorstellung davon, wieviel Arbeit in solchen Bibliotheken für das Zeichnen von Diagrammen steckt. Was ich da gebaut habe ist ja bei weitem nicht so flexibel und anpassungsfähig wie diese.
 

tklustig

Erfahrenes Mitglied
#5
Die Bibliothek erlaubt mir nicht die Verwendung von Arraywerten als Achenbezeichnungen und ist damit ungeeignet. Die horizontale Zeitachse sind Arraywerte aus der Datenbank in der Form von 0:00 bis 23:30! Deine Lösung sieht eigentlich ganz vielversprechend aus, allerdings sind die Werte zu statisch. Die Datenbankwerte können von 5 -34 alles enthalten. Wenn Dein Code Zufallswerte von 0-40 verarbeiten könnte, er wäre Gold wert. Hier eine Abwandlung, die allerdings so noch nicht funktioniert:
PHP:
/* die Daten, Temperatur und Feuchte (y-Achse) sowie Uhrzeit (x-Achse)
  $temperaturA = [11, 11, 11, 12, 12, 12, 12, 12, 12, 13, 13, 13];
  $feuchteA = [70, 70, 75, 75, 80, 80, 85, 85, 90, 90, 85, 85];
  $uhrzeitA = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"]; */

// Ursprung des Koordinatensystems in px festlegen
$xursprung = 20;
$yursprung = 470;

// Faktoren für Umrechnung der Indizes in px
$factorx = 30;
$factory = 30;

// Faktor um die Darstellung der Feuchte umzurechnen
$factoryhum = 10;

// Anzahl der Rasterlinien
$nrx = count($temperaturA) - 1;
$nry = count($uhrzeitA);

// x-Koordinate in px aus x-Wert ermitteln
function getx($x) {
    global $xursprung, $factorx;
    return $xursprung + $x * $factorx;
}

// y-Koordinate in px aus y-Wert ermitteln
function gety($y) {
    global $yursprung, $factory;
    return $yursprung - $y * $factory;
}

/* Gitternetz, Beschriftung
  vertikale Linien mit Beschriftung */
for ($i = 0; $i <= $nrx; $i++) {
    imageline($im, getx($i), gety(0), getx($i), gety($nry), $s);
    imagettftext($im, 11, 0, getx($i), gety(0) + 15, $s, $schriftart, $uhrzeitA[$i]);
}
// horizontale Linien mit Beschriftung
for ($j = min($temperaturA); $j <= max($temperaturA); $j++) {
    // Temperaturscala
    imageline($im, getx(0), gety($j), getx($nrx), gety($j), $s);
    imagettftext($im, 11, 0, getx($nrx) + 5, gety($j), $r, $schriftart, $j);
    /* Luftfeuchtigkeitsscala
      imagettftext($im, 11, 0, getx($nrx) + 25, gety($j), $b, $schriftart, $j * $factoryhum);
     */
}
// Temperaturwerte eintragen. Luftfeuchtigkeit folgt...
for ($k = 0; $k < $nrx; $k++) {
    imageline($im, getx($k), gety($temperaturA[$k]), getx($k + 1), gety($temperaturA[$k + 1]), $r);
    imagettftext($im, 20, 0, getx(0), gety(14), $s, $schriftart, $datumA[0]);
    //imageline($im, getx($k), gety($feuchteA[$k] / $factoryhum), getx($k + 1), gety($feuchteA[$k + 1] / $factoryhum), $b);
}
// Grafik darstellen
header("Content-Type: image/jpeg");
imagejpeg($im);
// Speicher freigeben
imagedestroy($im);
temppic.jpg
 
Zuletzt bearbeitet:

Sempervivum

Erfahrenes Mitglied
#6
Die Bibliothek erlaubt mir nicht die Verwendung von Arraywerten als Achenbezeichnungen und ist damit ungeeignet. Die horizontale Zeitachse sind Arraywerte aus der Datenbank in der Form von 0:00 bis 23:30!
Null Problemo, solche Bibltiotheken sind i. allg flexibel. Die Beschriftung der x-Achse kann aus einem Array übernommen werden:
Code:
<?php // content="text/plain; charset=utf-8"
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
require_once 'jpgraph/jpgraph.php';
require_once 'jpgraph/jpgraph_line.php';

// $datay1 = array(20, 15, 23, 15);
// $datay2 = array(12, 9, 42, 8);
// $datay3 = array(5, 17, 32, 24);
// die Daten, Temperatur und Feuchte (y-Achse) sowie Uhrzeit (x-Achse)
$temperaturA = [11, 11, 11, 12, 12, 12, 12, 12, 12, 13, 13, 13];
$feuchteA = [70, 70, 75, 75, 80, 80, 85, 85, 90, 90, 85, 85];
$uhrzeitA = ["10:00", "11:00", "12:00", "13:00", "14:00", "15:00", "16:00", "17:00", "18:00", "19:00", "20:00", "21:00"];

// Setup the graph
$graph = new Graph(600, 500);
$graph->SetScale("textlin");

$theme_class = new UniversalTheme;

$graph->SetTheme($theme_class);
$graph->img->SetAntiAliasing(false);
$graph->title->Set('Filled Y-grid');
$graph->SetBox(false);

$graph->SetMargin(40, 20, 36, 63);

$graph->img->SetAntiAliasing();

$graph->yaxis->HideZeroLabel();
$graph->yaxis->HideLine(false);
$graph->yaxis->HideTicks(false, false);

$graph->xgrid->Show();
$graph->xgrid->SetLineStyle("solid");
$graph->xaxis->SetTickLabels($uhrzeitA);
$graph->xgrid->SetColor('#E3E3E3');

// Create the first line
$p1 = new LinePlot($temperaturA);
$graph->Add($p1);
$p1->SetColor("#6495ED");
$p1->SetLegend('Temperatur');

// Create the second line
$p2 = new LinePlot($feuchteA);
$graph->Add($p2);
$p2->SetColor("#B22222");
$p2->SetLegend('Luftfeuchtigkeit');

// Create the third line
// $p3 = new LinePlot($datay3);
// $graph->Add($p3);
// $p3->SetColor("#FF1493");
// $p3->SetLegend('Line 3');

$graph->legend->SetFrameWeight(1);

// Output line
$graph->Stroke();
In der Doku gibt es auch ein Kaptitel für "multiple y-axis", d. h. eine individuelle Beschriftung für Temp., Feuchte etc. sollte machbar sein.
 
Zuletzt bearbeitet:

tklustig

Erfahrenes Mitglied
#7
Na gut, dann werde ich mal versuchen, die Libray in mein Temperaturprojekt zu integrieren. Was mich a bissel stört ist der enorme Umfang der zu integrierenden Klassen bzw. Dateien. Wenn es nur die
jpgraph.php und jpgraph_line.php wären, kein Problem. Allerdings enthält die jpgraph.php zahlreiche require_once Anweisungen, die wiederum andere Dateien integrieren. Eigentlich wollte ich das Projekt schlank halten, was bei Verwendung dieser Bibliothek so nicht mehr haltbar ist.
 

tklustig

Erfahrenes Mitglied
#8
So, habe die Library jetzt initialisiert und werde im nächsten Schritt ma' eruiere, welche der Dateien ich löschen kann, um das Projekt so schmall wie möglich zu halten. Ein Dartsellungsfehler hat die ganze Sache allerdings noch. Für das Array:
PHP:
$temperaturA = [21, 21, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20];
ergibt sich folgende Ausgabe:
diagramm.jpg

Eigentlich sollten die Werte für 20 auch noch sichtbar sein; entweder knapp über der x-Achse oder auf der x-Achse. Momentan entsteht der Eindruck, ab 1:30 Uhr gäbe es keine Messwerte mehr...
 
Zuletzt bearbeitet:

Sempervivum

Erfahrenes Mitglied
#9
Was mich a bissel stört ist der enorme Umfang der zu integrierenden Klassen bzw. Dateien.
Das stimmt, es sind mehrere Megabyte. Es erleichtert die Sache jedoch, dass sich das Ganze auf dem Server abspielt, die Dateien müssen ja nicht herunter geladen werden.

Eigentlich sollten die Werte für 20 auch noch sichtbar sein; entweder knapp über der x-Achse oder auf der x-Achse. Momentan entsteht der Eindruck, ab 1:30 Uhr gäbe es keine Messwerte mehr...
Das habe ich auch bemerkt und man kann etwas machen: Der Maximal- und Minimalwert des Gitters lassen sich verschieben, so dass die Linien nicht ganz oben oder ganz unten liegen:
Code:
<?php // content="text/plain; charset=utf-8"
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
require_once 'jpgraph/jpgraph.php';
require_once 'jpgraph/jpgraph_line.php';

// die Daten, Temperatur und Feuchte (y-Achse) sowie Uhrzeit (x-Achse)
$temperaturA = [11, 11, 11, 12, 12, 12, 12, 12, 12, 13, 13, 13];
$feuchteA = [70, 70, 75, 75, 80, 80, 85, 85, 90, 90, 85, 85];
$uhrzeitA = ["10:00", "11:00", "12:00", "13:00", "14:00", "15:00", "16:00", "17:00", "18:00", "19:00", "20:00", "21:00"];

$graph = new Graph(600, 500);
$graph->SetMargin(40, 150, 40, 30);
$graph->SetMarginColor('white');

// Hier wird der Min- und Max-Wert fuer die Feuchte festgelegt
$graph->SetScale('intlin', 0, 100);
$graph->yscale->ticks->Set(10);
$graph->title->Set('Using multiple Y-axis');
$graph->title->SetFont(FF_ARIAL, FS_NORMAL, 14);
$graph->xgrid->Show();
$graph->ygrid->Show();
$graph->xgrid->SetLineStyle("solid");
$graph->xgrid->SetColor('#E3E3E3');
$graph->xaxis->SetTickLabels($uhrzeitA);

// Hier wird der Min- und Max-Wert fuer die Temperatur festgelegt
$graph->SetYScale(0, 'lin', -20, 30);

$graph->yaxis->SetColor('blue');

$p1 = new LinePlot($feuchteA);
$graph->Add($p1);
$p1->SetColor('blue');
$p1->SetLegend('Luftfeuchtigkeit');

$p2 = new LinePlot($temperaturA);
$graph->AddY(0, $p2);
$p2->SetColor('red');
$p2->SetLegend('Temperatur');
$graph->ynscale[0]->ticks->Set(5);
$graph->ynaxis[0]->SetColor('red');

// Output line
$graph->Stroke();
Was ich ein wenig enttäuschend bei dieser Bibliothek finde ist, dass die automatische Konfiguration nicht so gut aussieht. Auch die Ticks musste ich anpassen.
Das Problem vom Anfang, dass die Linie nicht sichtbar ist, wenn sie ganz unten oder ganz oben liegt, kann man u. U. auch dadurch verbessern, indem man die Stärke vergrößert. Das habe ich jedoch noch nicht gefunden.
 

tklustig

Erfahrenes Mitglied
#10
Vielen Dank für Deine Hilfe, Jetzt habe ich den grafischen Bereich so, wie ich ihn haben wollte. Was meinst du mit der Aussage, alles spiele sich auf dem Server ab, die Daten müssten nicht runtergeladen werden? Ich habe die Bibliothek runtergeladen und in mein Webserververzeichnis hinterlegt. Auf die JQuery-Bibliothek greife ich online zu:
HTML:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js" type="text/javascript" charset="utf-8"></script>
Wie kann ich auf die Bibliothek online zugreifen, ohne sie runterladen zu müssen? Folgender Einbindungsversuch funktioniert jedenfalls nicht:
PHP:
$path2Library="https://jpgraph.net/";
require_once $path2Library . 'jpgraph/jpgraph.php';
Folgender funktioniert hingegen:
PHP:
$folder = getcwd();
require_once $folder . '/inc/graphicsLibrary/jpgraph.php';
 
Zuletzt bearbeitet:

Sempervivum

Erfahrenes Mitglied
#11
Was meinst du mit der Aussage, alles spiele sich auf dem Server ab, die Daten müssten nicht runtergeladen werden?
Du hast die Bibliothek zwar herunter geladen und auf deinen Server gelegt, aber damit ist es dann auch getan. Wenn ein Besucher dann deine Seite aufruft, müssen sie ja nicht auf seinen Client heruntergeladen werden, denn das Generieren der Grafik geschieht ja auf dem Server und die PHP-Dateien müssen dort lediglich aus dem lokalen Dateisystem geladen werden.
Anders ist es bei jQuery: Das läuft auf dem Client des Besuchers und muss jedes Mal dorthin herunter geladen werden (wenn sie nicht im Browsercache ist), entweder aus einem CDN oder von deinem Server, wenn Du sie dort hostest.
 
Zuletzt bearbeitet:

tklustig

Erfahrenes Mitglied
#12
Aha, so hattest Du das also gemeint. Nichts desto trotz habe ich all diejenigen PHP Dateien, die ich nicht benötige, vom Webserver entfernt. Jetzt umfasst die Bibliothek nur noch 1.20 MByte. Nochmals vielen Dank für Deine Mühen. Dieses Forum ist Top....
CU
Thomas Kipp alias tklustig

P.S.: Anbei nochmals die Grafik, die keine Wünsche mehr offen lässt(y):sneaky:(y)
tempPHP.jpg
 

Sempervivum

Erfahrenes Mitglied
#13
Freut mich, dass es zu deiner Zufriedenheit funktioniert. War ein interessantes Thema. Ich hatte mich vorher nur mit den Charting-Bibliotheken von Javascript beschäftigt und wusste nicht, dass es das auch für PHP gibt.
 

Sempervivum

Erfahrenes Mitglied
#15
Die Werte aus der Datenbank kann man in eine JSON-kodierte Struktur eintragen und an den Client übertragen, entweder gleich beim Laden der Seite oder mit Ajax. Wenn ich mich richtig erinnere, unterstützen einige Bibliotheken das letztere.
 

tklustig

Erfahrenes Mitglied
#16
Nun gut, dann würde ich mir also mit PHP die Werte holen, und sie mittels json_encode() JS zur Verfügung stellen. Gut, dass ich diesen Weg nicht gehen musste. Bye!
 
Status
Dieses Thema wurde gelöst! Zur Lösung gehen…