SVG Plots mit Spline Interpolation

Begonnen von eki, 19 Januar 2015, 14:05:33

Vorheriges Thema - Nächstes Thema

eki

Hallo zusammen,

bei GNUPLOT gibt es ja die Möglichkeit Kurven zu glätten. Das funktioniert offensichtlich bei SVG Plots bisher nicht (zumindest habe ich im 98_SVG.pm nichts dergleichen gefunden).
Da ich aber einige Plots mit wenigen Messpunkten (Wetterdaten aus dem Internet) habe, die mir nicht sehr gefallen haben, habe ich einen Versuch gemacht, das 98_SVG.pm entsprechend zu ändern. Jetzt wird der Parameter "smooth csplines" aus den Plotfiles entsprechend berücksichtigt (bisher nicht ganz genau so wie bei GNUPLOT, sieht aber optisch für mich besser aus und die Kurven werden auch ganz ordentlich angenähert). Als Beispiel habe ich ein paar Plots mit und ohne das Smoothing angehängt.

Falls Interesse besteht, könnte ich das 98_SVG.pm bereitstellen. Zusätzlich braucht man noch eine Änderung an den entsprechenden *svg_style.css files (dort muss man zusätzlich zu "polygon.." auch noch die entsprechenden Einstellungen für "path.." einfügen).

Gruss
Kurt Eckert

rudolfkoenig


eki

Bitteschön.

Da ich Perl und auch SVG Novize bin, hoffe ich, dass ich nichts Grobes übersehen habe, wäre ganz gut, wenn ein Profi sich das noch mal anschaut :-/.

Die von mir genutzte Basisversion von 98_SVG.pm müsste OK sein (habe ich gestern noch einmal gecheckt, falls also seit gestern nichts an 98_SVG.pm geändert wurde sollte nichts verloren gehen).

Gruss
Kurt

rudolfkoenig

Ich habe zwar auch viele kleine Probleme mit dem "Patch" wie DOS Format, Tabs, %f statt %d, mAn unnoetig geaenderte Zeilen, keine Plot-Editor-Unterstuetzung, keine Doku.

Das grosse Problem ist aber, dass es nicht moeglich ist, erst Linien ohne und dann welche mit spline zu definieren. Das gleiche Problem gibts zwar auch bei lw/ls/etc, allerdings ist das weniger gravierend.

Ich tendiere dazu, die .gnuplot-Kompatibilitaet hier zu brechen, das wuerde auch das Plot-Editor-Problem einfacher machen.

eki

Anmerkungen zu den kleinen Problemen:
%f geht leider nicht anders, da ich Zwischenwerte berechne und wenn ich die runde, kommt Käse bei den Plots heraus.
Zum Plot Editor und zur Doku könnte ich mich noch mal versuchen.
Die anderen Punkte liegen wahrscheinlich daran das das mein erster Versuch ist, sorry.

Das große Problem verstehe ich allerdings nicht so ganz. Soweit ich das sehe, kann man in einem Plot eine linear interpolierte Linie und eine Spline Linie mischen. Zwischen verschiedenen Plots geht das sowieso (zumindest hat das bei mir geklappt). Ich verwende sogar innerhalb einer Linie interpolierte und nichtinterpolierte Teile (z. B. bei den geschlossenen Linien werden die senkrechten Verbindungsstriche nicht interpoliert).

rudolfkoenig

Zitatwenn ich die runde, kommt Käse bei den Plots heraus.
Glaube ich nicht. Das SVG ist so skaliert, dass man fuer die Koordinaten ganze Zahlen verwenden kann, damit die uebertragenen Daten klein sind.

Das "grosse Problem" hat mit dem .gplot "Parser" in SVG_digestConf zu tun, der nicht in der Lage ist bei einem nicht gesetzten Parameter "undef" oder sowas ins Array ($conf{lSmooth}[$idx]) zu schreiben.

rudolfkoenig

ZitatDie anderen Punkte liegen wahrscheinlich daran das das mein erster Versuch ist, sorry.

Meine Bemerkungen waren weder boese gemeint, noch zum Abschrecken gedacht.
Aber wenn ich das nie sage...

oliverk


Egal wie, aber machen !!!  ::)  8)  ::)

Das trägt auf jeden Fall dazu bei, dass die Akzeptanz bei allen Betrachtern deutlich steigt. Auch wenn diese Kurven ja mathematisch nicht den wirklichen Verlauf darstellen.
Kurven sind immer besser als Ecken und Kanten. Sicherlich für jede Grafik, aber wenn es eine Option im Editor ist, dann wäre es für viele Graphen eine tolle Sache.

Oliver

Fhem: 5.7 auf RaspPi / Fhem: 5.7 auf Cubie
ca. 80 net4home Buskomponenten
zum Spielen diverse FS20, HomeMatic, EnOcean, hue Geräte, Fritz!Box 7490, Fritz!Dect 200, netatmo, eve

eki

Zitat von: rudolfkoenig am 19 Januar 2015, 16:16:00
Glaube ich nicht. Das SVG ist so skaliert, dass man fuer die Koordinaten ganze Zahlen verwenden kann, damit die uebertragenen Daten klein sind.
Möglicherweise hast Du teilweise recht, ich habe zuerst alles mit %d probiert, dabei kam Käse heraus. Danach habe ich allerdings alle outputs, die was mit "path" zu tun haben auf %f umgestellt. Das war wahrscheinlich zu viel. Was vermutlich auf %f bleiben muss ist die Zeile:
"$ret .=  sprintf(" %f,%f", ($lx+$x1)/2, ($ly+$y1)/2);"
der Rest kann möglicherweise auf %d geändert werden. Ich test mal und melde mich dann (morgen) wieder.

Zitat von: rudolfkoenig am 19 Januar 2015, 16:16:00
Das "grosse Problem" hat mit dem .gplot "Parser" in SVG_digestConf zu tun, der nicht in der Lage ist bei einem nicht gesetzten Parameter "undef" oder sowas ins Array ($conf{lSmooth}[$idx]) zu schreiben.
OK, jetzt hab ich's verstanden.

Zitat von: rudolfkoenig am 19 Januar 2015, 16:16:00
Meine Bemerkungen waren weder boese gemeint, noch zum Abschrecken gedacht.
Aber wenn ich das nie sage...
Ich hab's auch nicht böse aufgefasst und abschrecken lasse ich mich auch nicht, dazu ist FHEM viel zu spannend.

rudolfkoenig

- lines von <polyline> auf <path> umgestellt. Hat auch eine Anpassung von svg.js nachgezogen, wg. "Display plot values".

- mit <path> waren die weiteren Typen cubic, cubicSmooth, quadratic, quadraticSmooth einzufuehren trivial, diese entsprechen den SVG <path> Optionen C, S, Q und T. Das ist zwar nicht .gnuplot compatibel, dafuer waren die Aenderungen fuer den PlotEditor und fuer die Darstellung minimal. quadraticSmooth ist sehr "haarig", wenn jemand es "kaemmen" kann/will, bitte erst mit fhem.cfg.demo testen, und dann hier melden.

- meine 5 verlorengegangenen Linientypen (l0_dot,l1_dot,l0fill_stripe,l1fill_stripe,l0fill_gyr) restauriert. Das ist in svg_style.css definiert, fuer dark muesste es nachgezogen werden

eki

ich habe mir Deine Version mal angeschaut und getestet, hier meine Anmerkungen

Leider fürchte ich, dass das nicht so einfach geht wie Du es jetzt eingebaut hast. Die Interpolationsmethoden bei "path" scheinen leider unterschiedlich zu arbeiten. Grundsätzlich braucht man immer Datenpunkte und Stützwerte, die festlegen wie die Kurve durch die Datenwerte geplottet wird. Bei quadraticSmooth, also der Option "T" werden einfach immer die vorherigen und nächsten Punkte in der Reihe als Stützwerte genommen. Wenn man das jetzt einfach genauso macht wie bei der Linie, kommen recht eigenartige Ergebnisse heraus. Daher habe ich in meinem Vorschlag als Datenpunkte nicht die egentlichen Input Datenpunkte verwendet,  sondern immer die Mittelwerte zwischen zwei Datenpunkten (daher die Zeile mit ($lx+$x1)/2 und %f). Dadurch läuft die Kurve dann zwar nicht mehr genau durch die Datenpunkte, aber sie nähert sich ganz gut einem Verlauf an, wie ich ihn erwarten würde. Wenn man will, dass man die Datenpunkte trifft, muss man die Stützpunkte komplizierter berechnen, dann muss man nämlich darauf achten, dass die Steigungen im Vergleich zum vorherigen Punkt passen (die Mathematik dazu müsste ich mir aber auch noch mal anschauen).
Für die anderen Interpolationsmethoden muss man z.T. die Stützwerte zusätzlich zu den Datenpunkten angeben, hier wird wohl nicht einfach der vorherige und nächste Punkt verwendet. In diesem Fall kommen also zusätzliche Werte in die Liste, die man auch entsprechend ausrechnen muss.

Alles mit path zu machen (auch die Linien) macht den Code natürlich einfacher und macht Sinn, habe ich mich nur nicht von vorne herein getraut.

Wenn Du willst, kann ich das noch einmal genauer anschauen, und einen auf Deiner Version basierenden Vorschlag machen (ohne Tabs und mit Unix LF ;-). Wir werden aber um getrennte Behandlung der verschiedenen Interpolationsfälle nicht herum kommen fürchte ich.

rudolfkoenig

Einverstanden. Du darfst die haarige Linie gerne kaemmen :)

eki

So, ich habe mich gestern abend noch einmal mit dem Thema beschäftigt. Die 4 Varianten, die in "path" möglich sind ("C" "S" "Q" "T"), sind mathematisch immer Bezier Kurven. Die ersten beiden und die letzten beiden sind jeweils nur Varianten der gleichen grundsätzlichen Methode (bei den ersten beiden zwei Kontrollpunkte pro Segment, bei den zweiten beiden ein Kontrollpunkt pro Segment) siehe auch https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Paths.
Der Trick ist eine sinnvolle Festlegung der Kontrollpunkte. Dazu habe ich einen Algorithmus gefunden (https://www.particleincell.com/2012/bezier-splines/), der ganz ordentlich zu funktionieren scheint. Allerdings ist dazu ein bisschen Rumrechnerei notwendig, macht die Plots eventuell etwas langsamer. Unten Beispiele, wie die Kurven dann aussehen würden.
Eine zusätzliche Möglichkeit wäre das, was ich, wie vorher beschrieben, zuerst gemacht hatte (also als Punkte nicht die Datenpunkte sondern die Mitte dazwischen zu nehmen und die "T" Variante). Dann wäre kein großer Rechenaufwand notwendig. Auch hier ein Beispiel Bild unten.

Bitte gebt mir mal kurz Bescheid was Ihr denkt, dann kann ich mich ans Implementieren in Perl machen (bisher habe ich nur mit JS herumprobiert, weil das für mich einfacher und schneller ist).

Das Thema %f ist übrigens kein Problem, wenn man die gerechneten Werte zum Schluss kaufmännisch auf Ganzzahlen rundet.

Gruss
Kurt

rudolfkoenig

Ich wuerde die aufwendige Berechnung nur bei den Splines anwenden, wer Spline waehlt, der hat entweder nur wenige Punkte, oder muss die erhoehte Rechenzeit in Kauf nehmen.

justme1968

ist es nicht sinnvoll eine variante einzubauen die zumindest durch die tatsächlich vorhanden punkte geht? auch die interpolierte kurve sollte doch so viel wie möglich mit den tatsächlichen werten zu tun haben.
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968