SVG Plot - steps ohne vertikale Linien?

Begonnen von Frank_Huber, 09 April 2018, 15:07:27

Vorheriges Thema - Nächstes Thema

Frank_Huber

Mahlzeit,

Ich habe einen Plot zur Anzeige welche Heizkreise im Haus gerade aktiv sind.
Ich würde hier gerne die vertikalen Linken weg haben und nur an den horizontalen Linien die Aktivität der Heizkreise anzeigen.
in der db sind die Werte mit "on" und "off" geloggt.
Ich wandle "off" in "0" um und "on" je nach Heizkreis in 1 bis 11.
Durch die ganzen vertilaken Linien wird das ganze aber sehr unübersichtlich.

Hab mal ne Grafik zur verdeutlichung angehängt. die oberen drei Linienstränge sind manuell eingezeichten, so hätte ich es gerne. :-)

Danke & Grüße
Frank

mumpitzstuff

Poste doch mal den Inhalt deiner SVG Datei, dann hat man schon mal eine Grundlage um dir zu helfen. Vielleicht auch einen Auszug aus dem Log, damit man die entsprechenden Daten ebenfalls vor sich hat.

Frank_Huber

gerne.

SVG device:
defmod Plot_ETA_Heizkreise SVG logdb:A_Plot_ETA_Heizkreise:HISTORY
attr Plot_ETA_Heizkreise DbLogExclude .*
attr Plot_ETA_Heizkreise captionPos left
attr Plot_ETA_Heizkreise endPlotNow 1
attr Plot_ETA_Heizkreise endPlotToday 1
attr Plot_ETA_Heizkreise label "Heizkreise"
attr Plot_ETA_Heizkreise nrAxis 1,2
attr Plot_ETA_Heizkreise plotsize 1200,250


gplot datei:
# Created by FHEM/98_SVG.pm, 2018-04-09 07:41:32
set terminal png transparent size <SIZE> crop
set output '<OUT>.png'
set xdata time
set timefmt "%Y-%m-%d_%H:%M:%S"
set xlabel " "
set title '<L1>'
set ytics "DG" 11,"Luisa" 10, "Johanna" 9, "OG_Flur" 8, "OG_Bad" 7, "Schlafz." 6, "EG_Bad" 5, "EG_Nord" 4, "EG_Süd" 3, "KG_Hobby" 2, "KG_Flur" 1
set y2tics "DG" 11,"Luisa" 10, "Johanna" 9, "OG_Flur" 8, "OG_Bad" 7, "Schlafz." 6, "EG_Bad" 5, "EG_Nord" 4, "EG_Süd" 3, "KG_Hobby" 2, "KG_Flur" 1
set grid ytics
set ylabel ""
set y2label ""
set yrange [0:12]
set y2range [0:12]

#logdb GPIO_IN_23:state:::$val=($val=~'on'?11:0)
#logdb GPIO_IN_18:state:::$val=($val=~'on'?10:0)
#logdb GPIO_IN_19:state:::$val=($val=~'on'?9:0)
#logdb GPIO_IN_20:state:::$val=($val=~'on'?8:0)
#logdb GPIO_IN_21:state:::$val=($val=~'on'?7:0)
#logdb GPIO_IN_22:state:::$val=($val=~'on'?6:0)
#logdb GPIO_IN_17:state:::$val=($val=~'on'?5:0)
#logdb GPIO_IN_16:state:::$val=($val=~'on'?4:0)
#logdb GPIO_IN_15:state:::$val=($val=~'on'?3:0)
#logdb GPIO_IN_14:state:::$val=($val=~'on'?2:0)
#logdb GPIO_IN_13:state:::$val=($val=~'on'?1:0)

plot "<IN>" using 1:2 axes x1y1 title '' ls l0 lw 1 with steps,\
     "<IN>" using 1:2 axes x1y1 title '' ls l1 lw 1 with steps,\
     "<IN>" using 1:2 axes x1y1 title '' ls l0 lw 1 with steps,\
     "<IN>" using 1:2 axes x1y1 title '' ls l1 lw 1 with steps,\
     "<IN>" using 1:2 axes x1y1 title '' ls l0 lw 1 with steps,\
     "<IN>" using 1:2 axes x1y1 title '' ls l1 lw 1 with steps,\
     "<IN>" using 1:2 axes x1y1 title '' ls l0 lw 1 with steps,\
     "<IN>" using 1:2 axes x1y1 title '' ls l1 lw 1 with steps,\
     "<IN>" using 1:2 axes x1y1 title '' ls l0 lw 1 with steps,\
     "<IN>" using 1:2 axes x1y1 title '' ls l1 lw 1 with steps,\
     "<IN>" using 1:2 axes x1y1 title '' ls l0 lw 1 with steps


Auszug aus DBlog: (ein Auszug)
2018-04-09 06:13:40|GPIO_IN_16|RPI_GPIO|state: off|state|off|
2018-04-09 07:13:49|GPIO_IN_16|RPI_GPIO|state: on|state|on|
2018-04-09 08:05:59|GPIO_IN_16|RPI_GPIO|state: off|state|off|
2018-04-09 08:46:14|GPIO_IN_16|RPI_GPIO|state: on|state|on|
2018-04-09 09:34:06|GPIO_IN_16|RPI_GPIO|state: off|state|off|
2018-04-09 10:04:22|GPIO_IN_16|RPI_GPIO|state: on|state|on|
2018-04-09 10:31:47|GPIO_IN_16|RPI_GPIO|state: off|state|off|
2018-04-09 11:08:20|GPIO_IN_16|RPI_GPIO|state: on|state|on|
2018-04-09 11:53:34|GPIO_IN_16|RPI_GPIO|state: off|state|off|
2018-04-09 12:34:27|GPIO_IN_16|RPI_GPIO|state: on|state|on|



mumpitzstuff

Noch mal drüber nachgedacht und ich bin der Meinung, das geht nicht. Mir jedenfalls ist keine Funktion bekannt, um die vertikalen Linien auszublenden. Das wäre quasi steps + hide vertical lines. Bei logProxy habe ich auch nichts dergleichen gefunden, was aber noch nicht bedeutet, das es wirklich nicht geht. Vielleicht kommt ja noch ein Profi auf eine Lösung.

helmut

Zitat von: Frank_Huber am 09 April 2018, 15:07:27
Hab mal ne Grafik zur verdeutlichung angehängt. die oberen drei Linienstränge sind manuell eingezeichten, so hätte ich es gerne. :-)

Hallo Frank,

nicht genauso wie Du es haben moechtest, aber schon mal uebersichtlicher als Deine jetzige Darstellung.

set terminal png transparent size <SIZE> crop
set output '<OUT>.png'
set xdata time
set timefmt "%Y-%m-%d_%H:%M:%S"
set xlabel " "
set title '<L1>'
set ytics ("BRN" 0.3, "WWP" 1.3, "HKP" 2.3, "FBP" 3.3)
set y2tics ("BRN" 0.3, "WWP" 1.3, "HKP" 2.3, "FBP" 3.3)
set grid y2tics
set ylabel ""
set y2label ""
set yrange [0:4.3]
set y2range [0:4.3]

#FileLog_hzg_rel_0 3:hzg_rel_0_fbp.deviceMsg\x3a:0:$fld[3]=~"off"?3.3:4
#FileLog_hzg_rel_0 3:hzg_rel_0_hkp.deviceMsg\x3a:0:$fld[3]=~"off"?2.3:3
#FileLog_hzg_rel_0 3:hzg_rel_0_wwp.deviceMsg\x3a:0:$fld[3]=~"off"?1.3:2
#FileLog_hzg_rel_0 3:hzg_rel_0_brn.deviceMsg\x3a:0:$fld[3]=~"off"?0.3:1

plot "<IN>" using 1:2 axes x1y2 title 'Fußbodenheizungspumpe' ls l5 lw 1 with steps,\
     "<IN>" using 1:2 axes x1y2 title 'Heizkörperpumpe' ls l1 lw 1 with steps,\
     "<IN>" using 1:2 axes x1y2 title 'Warmwasserpumpe' ls l2 lw 1 with steps,\
     "<IN>" using 1:2 axes x1y2 title 'Brenner' ls l0 lw 1 with steps


Gruss Helmut

Intelligenz ist die Fähigkeit, Arbeit zu vermeiden, aber dafür zu sorgen, daß die Arbeit gemacht wird.
(Linus Torvalds)

mumpitzstuff

#5
Hat mich mal interessiert und ich habe einen Quick and Dirty Patch geschrieben:

fhem/FHEM/98_SVG.pm | 29 +++++++++++++++++++++++++++--
1 file changed, 27 insertions(+), 2 deletions(-)

diff --git a/fhem/FHEM/98_SVG.pm b/fhem/FHEM/98_SVG.pm
index a740ab7a4..11b154c6f 100644
--- a/fhem/FHEM/98_SVG.pm
+++ b/fhem/FHEM/98_SVG.pm
@@ -500,8 +500,8 @@ SVG_PEdit($$$$)
     my $sel = ($v && $v eq "x1y1") ? "left" : "right";
     $o .= SVG_sel("axes_${idx}", "left,right,left log,right log", $sel );
     $o .= SVG_sel("type_${idx}",
-                "lines,points,steps,fsteps,histeps,bars,ibars,".
-                        "cubic,quadratic,quadraticSmooth",
+                "lines,points,steps,fsteps,histeps,errorbarhigh,errorbarlow,".
+                        "bars,ibars,cubic,quadratic,quadraticSmooth",
                 $conf{lType}[$idx]);
     my $ls = $conf{lStyle}[$idx];
     if($ls) {
@@ -1978,6 +1978,31 @@ SVG_render($$$$$$$$$$)

       SVG_pO "<polyline $attributes $lStyle points=\"$ret\"/>";

+    } elsif($lType eq "errorbarhigh" || $lType eq "errorbarlow" ) {
+
+      if(@{$dxp} == 1) {
+          my $y1 = $y+$h-($dyp->[0]-$min)*$hmul;
+          $ret .=  sprintf(" %d,%d %d,%d %d,%d %d,%d",
+                $x,$y+$h, $x,$y1, $x+$w,$y1, $x+$w,$y+$h);
+
+          SVG_pO "<polyline $attributes $lStyle points=\"$ret\"/>";
+      } else {
+        foreach my $i (1..int(@{$dxp})-1) {
+          my ($x1, $y1) = ($x+$dxp->[$i-1], $y+$h-($dyp->[$i-1]-$min)*$hmul);
+          my ($x2, $y2) = ($x+$dxp->[$i],   $y+$h-($dyp->[$i]  -$min)*$hmul);
+          next if(int($x2) == $lx && int($y1) == $ly);
+          $lx = int($x2); $ly = int($y2);
+          if($lType eq "errorbarhigh" && $y1 >= $y2) {
+            $attributes =~ s/id=\"line_(\d+)\"/id=\"line_$1_$i\"/;
+            SVG_pO "<line $attributes $lStyle x1=\"$x1\" y1=\"$y1\" x2=\"$x2\" y2=\"$y1\"/>";
+
+          } elsif ($lType eq "errorbarlow" && $y1 <= $y2) {
+            $attributes =~ s/id=\"line_(\d+)\"/id=\"line_$1_$i\"/;
+            SVG_pO "<line $attributes $lStyle x1=\"$x1\" y1=\"$y1\" x2=\"$x2\" y2=\"$y1\"/>";
+          }
+        }
+      }
+
     } elsif($lType eq "histeps" ) {
       $ret .=  sprintf(" %d,%d", $x+$dxp->[0], $y+$h) if($isFill && @{$dxp});
       if(@{$dxp} == 1) {


Damit hat man 2 weitere Linienstyles.

errorbarhigh: nur wenn y1 >= y2 wird die Linie gezeichnet
errorbarlow: nur wenn y1 <= y2 wird die Linie gezeichnet

Wenn Low und High immer die selben Werte haben z.B. 0 und 1, dann gibt es keinen Unterschied zwischen den 2 Styles.

Ich habe bisher keine Variante drin, in der alle horizontalen Linien gezeichnet werden (high und low), das wäre aber auch relativ einfach umsetzbar. Kann ich bei Bedarf nachreichen.

PS: Nochmal angepasst und einen Bug behoben...

Frank_Huber

Danke mumpitzstuff,

allerdings bekomme ich beim einsoielen einen Fehler:
/opt/fhem/FHEM# patch -p1 98_SVG.pm < 98_SVG_patch.pm
(Stripping trailing CRs from patch; use --binary to disable.)
patching file 98_SVG.pm
patch unexpectedly ends in middle of line
Hunk #2 succeeded at 1978 with fuzz 1.
root@FHEM-PI-KG:/opt/fhem/FHEM#

Frank_Huber

#7
Der Patch funktioniert dennoch. :-)

Allerdings:
"errorbarhigh" zeichnet die Null-Linien.
"errorbarlow" zeichnet die Linien am höheren Wert.
vom Wording her würde ich das anderstrum sehen.

Der letzte "high" Wert wird allerdings verschluckt.
im angehängten Beispiel müssten die beiden Heizkreise ab 6:31 wieder high sein. diese Linie fehlt.
sqlite> select * from HISTORY where DEVICE = "GPIO_IN_16" and TIMESTAMP > "2018-04-11 00:00:00";
2018-04-11 04:24:44|GPIO_IN_16|RPI_GPIO|state: on|state|on|
2018-04-11 05:00:06|GPIO_IN_16|RPI_GPIO|state: off|state|off|
2018-04-11 05:31:00|GPIO_IN_16|RPI_GPIO|state: on|state|on|
2018-04-11 05:57:15|GPIO_IN_16|RPI_GPIO|state: off|state|off|
2018-04-11 06:31:50|GPIO_IN_16|RPI_GPIO|state: on|state|on|
sqlite> select * from HISTORY where DEVICE = "GPIO_IN_15" and TIMESTAMP > "2018-04-11 00:00:00";
2018-04-11 04:11:21|GPIO_IN_15|RPI_GPIO|state: on|state|on|
2018-04-11 05:06:46|GPIO_IN_15|RPI_GPIO|state: off|state|off|
2018-04-11 05:23:36|GPIO_IN_15|RPI_GPIO|state: on|state|on|
2018-04-11 06:00:17|GPIO_IN_15|RPI_GPIO|state: off|state|off|
2018-04-11 06:31:42|GPIO_IN_15|RPI_GPIO|state: on|state|on|

Das bekomme ich aber evtl mit "event-min-interval" und nem DOIF/at hin. wird dann bischen mehr geloggt, aber die Linie würde stehen.
Das ist ja ein "normales" Verhalten bei SVG. mit steps hat man hier durch die ungewollte vertikale Linie das einschalten gesehen.

Davon abgesehen: Super Arbeit, vielen vielen Dank! :-)
Du machst damit bestimmt nicht nur mich glücklich!

gplot:
# Created by FHEM/98_SVG.pm, 2018-04-09 07:41:32
set terminal png transparent size <SIZE> crop
set output '<OUT>.png'
set xdata time
set timefmt "%Y-%m-%d_%H:%M:%S"
set xlabel " "
set title '<L1>'
set ytics "DG" 11,"Luisa" 10, "Johanna" 9, "OG_Flur" 8, "OG_Bad" 7, "Schlafz." 6, "EG_Bad" 5, "EG_Nord" 4, "EG_Süd" 3, "KG_Hobby" 2, "KG_Flur" 1
set y2tics "DG" 11,"Luisa" 10, "Johanna" 9, "OG_Flur" 8, "OG_Bad" 7, "Schlafz." 6, "EG_Bad" 5, "EG_Nord" 4, "EG_Süd" 3, "KG_Hobby" 2, "KG_Flur" 1
set grid ytics
set ylabel ""
set y2label ""
set yrange [0:12]
set y2range [0:12]

#logdb GPIO_IN_23:state:::$val=($val=~'on'?11:0)
#logdb GPIO_IN_18:state:::$val=($val=~'on'?10:0)
#logdb GPIO_IN_19:state:::$val=($val=~'on'?9:0)
#logdb GPIO_IN_20:state:::$val=($val=~'on'?8:0)
#logdb GPIO_IN_21:state:::$val=($val=~'on'?7:0)
#logdb GPIO_IN_22:state:::$val=($val=~'on'?6:0)
#logdb GPIO_IN_17:state:::$val=($val=~'on'?5:0)
#logdb GPIO_IN_16:state:::$val=($val=~'on'?4:0)
#logdb GPIO_IN_15:state:::$val=($val=~'on'?3:0)
#logdb GPIO_IN_14:state:::$val=($val=~'on'?2:0)
#logdb GPIO_IN_13:state:::$val=($val=~'on'?1:0)

plot "<IN>" using 1:2 axes x1y1 title '' ls l0 lw 2 with errorbarlow,\
     "<IN>" using 1:2 axes x1y1 title '' ls l1 lw 2 with errorbarlow,\
     "<IN>" using 1:2 axes x1y1 title '' ls l0 lw 2 with errorbarlow,\
     "<IN>" using 1:2 axes x1y1 title '' ls l1 lw 2 with errorbarlow,\
     "<IN>" using 1:2 axes x1y1 title '' ls l0 lw 2 with errorbarlow,\
     "<IN>" using 1:2 axes x1y1 title '' ls l1 lw 2 with errorbarlow,\
     "<IN>" using 1:2 axes x1y1 title '' ls l0 lw 2 with errorbarlow,\
     "<IN>" using 1:2 axes x1y1 title '' ls l1 lw 2 with errorbarlow,\
     "<IN>" using 1:2 axes x1y1 title '' ls l0 lw 2 with errorbarlow,\
     "<IN>" using 1:2 axes x1y1 title '' ls l1 lw 2 with errorbarlow,\
     "<IN>" using 1:2 axes x1y1 title '' ls l0 lw 2 with errorbarlow


Ergebnis im angehängten Bild.

mumpitzstuff

#8
Das es umgedreht sein soll ist komisch und muss ich mir ansehen. Eventuell ist das aber eine minimale Änderung.

Das mit dem letzten Punkt und eventuell auch am Anfang kann sein, ich glaube bei den anderen plots wird dort ein virtueller Punkt dazu berechnet. Muss ich noch mal nachsehen. Kannst du mir vielleicht einen errorbar plot und den selben mit steps noch mal zeigen bitte? Ich würde das gern optisch sehen.

PS: oh ich sehe grad das ich gestern vergessen habe den Patch zu aktualisieren. Ich hab's anscheinend nur geschrieben, aber den Code vergessen. Ich aktualisiere das heute Abend noch mal.

Frank_Huber

Zitat von: mumpitzstuff am 11 April 2018, 12:45:09
Kannst du mir vielleicht einen errorbar plot und den selben mit steps noch mal zeigen bitte? Ich würde das gern optisch sehen.

Bitteschön
oben: errorbarlow
unten: steps

mumpitzstuff

#10
Das ist völlig ok so. Um das zu verhindern, musst du logProxy verwenden. Damit kannst du dir virtuelle Punkte davor und danach errechnen lassen und dadurch den Plotabriss verhindern. An der letzten Stelle fehlt einfach ein zweiter x Wert, um die Linie ziehen zu können. Warum sich SVG da nicht selbst einen virtuellen Punkt rein legt habe ich auch nie verstanden. Wenn ich das auch noch rein bastel, dann muss ich am Ende noch das Modul übernehmen...  :o
Aber das würde auch nur im steps Modus was bringen, für die Errorbar würde sich trotzdem keine Änderung ergeben. Die würde sich nur ergeben, wenn am Ende die Linie nach oben anstatt nach unten gehen würde. Dann könnte man die Linie bis zum Rand zeichnen lassen.

Frank_Huber

Ja klar, das ist bei SVG immer so. da hab ich mir aber schon nen workaround gebastelt.

ein DOIF dass beim Event "on" nach 302 Sek den GPIO abfrägt.
im GPIO dann event-min-interval auf 300 und gut is. alle 5min gibt es einen datenpunkt wenn der Heizkreis an ist.

mumpitzstuff

Hier noch mal der richtige Patch:

fhem/FHEM/98_SVG.pm | 21 +++++++++++++++++++--
1 file changed, 19 insertions(+), 2 deletions(-)

diff --git a/fhem/FHEM/98_SVG.pm b/fhem/FHEM/98_SVG.pm
index a740ab7a4..606bb071f 100644
--- a/fhem/FHEM/98_SVG.pm
+++ b/fhem/FHEM/98_SVG.pm
@@ -500,8 +500,8 @@ SVG_PEdit($$$$)
     my $sel = ($v && $v eq "x1y1") ? "left" : "right";
     $o .= SVG_sel("axes_${idx}", "left,right,left log,right log", $sel );
     $o .= SVG_sel("type_${idx}",
-                "lines,points,steps,fsteps,histeps,bars,ibars,".
-                        "cubic,quadratic,quadraticSmooth",
+                "lines,points,steps,fsteps,histeps,errorbar,errorbarhigh,errorbarlow,".
+                        "bars,ibars,cubic,quadratic,quadraticSmooth",
                 $conf{lType}[$idx]);
     my $ls = $conf{lStyle}[$idx];
     if($ls) {
@@ -1978,6 +1978,23 @@ SVG_render($$$$$$$$$$)

       SVG_pO "<polyline $attributes $lStyle points=\"$ret\"/>";

+    } elsif($lType eq "errorbar" || $lType eq "errorbarhigh" || $lType eq "errorbarlow" ) {
+
+      if(@{$dxp} > 1) {
+        foreach my $i (1..int(@{$dxp})-1) {
+          my ($x1, $y1) = ($x+$dxp->[$i-1], $y+$h-($dyp->[$i-1]-$min)*$hmul);
+          my ($x2, $y2) = ($x+$dxp->[$i],   $y+$h-($dyp->[$i]  -$min)*$hmul);
+          next if(int($x2) == $lx && int($y1) == $ly);
+          if(($lType eq "errorbarhigh" && $y1 <= $y2) ||
+             ($lType eq "errorbarlow" && $y1 > $y2) ||
+             ($lType eq "errorbar")) {
+            $attributes =~ s/id=\"line_[^\"]+\"/id=\"line_$idx\_$i\"/;
+            SVG_pO "<line $attributes $lStyle x1=\"$x1\" y1=\"$y1\" x2=\"$x2\" y2=\"$y1\"/>";
+          }
+          $lx = int($x2); $ly = int($y2);
+        }
+      }
+
     } elsif($lType eq "histeps" ) {
       $ret .=  sprintf(" %d,%d", $x+$dxp->[0], $y+$h) if($isFill && @{$dxp});
       if(@{$dxp} == 1) {

Frank_Huber

Super, morgen gleich testen.
Danke!

Gesendet von meinem S60 mit Tapatalk


Frank_Huber

#14
Zitat von: mumpitzstuff am 11 April 2018, 22:32:26
Hier noch mal der richtige Patch:
Danke! läuft bestens!
Einziger Verbesserungsvorschlag wäre jetzt noch auch die Null-Linien auszublenden. :-)

Und was auffiel:
bei normalen Plots kann man mit der rechten Maustaste Linien ausblenden etc, diese Funktion gibt es bei der errorbar auch nicht.
stört in dem Fall nicht, wollte es aber erwähnt haben. :)

Danke nochmal!