Library: find a better organisation of entrance points to plotting

The intention is to create a library of convenient building blocks;
providing a visualisation should be as simple as invoking a free function
with CSV data, yet with the ability to tweak some lables or display
variations if desired.

This can be achieved by..
 * having a series of ready-made standard visualisations
 * expose a function call for each, accepting a data-context builder
 * provide secondary convenience shortcuts, which add some of the expected bindings
 * notably a shortcut is provided to take the data as CSV-string
 * augmented by a wrapper/builder to allow defining data points inline
This commit is contained in:
Fischlurch 2024-03-31 19:11:58 +02:00
parent 85e77f58a9
commit fc084c1ca5
4 changed files with 122 additions and 69 deletions

View file

@ -43,9 +43,6 @@
using std::string;
using util::join;
using lib::diff::MakeRec;
namespace lib {
namespace gnuplot_gen {
@ -153,31 +150,27 @@ plot $RunData using 1:3 with impulses linestyle 3, \
)~";
template<class IT>
inline string
renderCSV (IT& iter)
{
return join (iter, "\n");
}
}//(End)template and defaults definitions
/** */
/**
* @remark each column of the given data is featured as sequence
* over the first column interpreted as common abscissa. The name
* of the abscissa and the row names in the legend are extracted
* from the header names expected in the first row of CSV data.
*/
string
dataPlot (CSVRowIter& rowIT)
dataPlot (ParamRecord params)
{
TextTemplate plot{GNUPLOT_BASIC_PLOT_DEF
+GNUPLOT_SIMPLE_DATA_PLOT};
auto config
= MakeRec()
.set ("CommonStyleDef", GNUPLOT_CommonStyleDef)
params.set ("CommonStyleDef", GNUPLOT_CommonStyleDef)
.set ("AxisGridSetup", GNUPLOT_AxisGridSetup)
.set ("DiagramKind", "points")
.set ("CSVData", renderCSV(rowIT))
.genNode();
return plot.render(config);
.set (KEY_DiagramKind, "points")
;
return plot.render (params.genNode());
}
}} // namespace lib::gnuplot_gen

View file

@ -47,29 +47,77 @@
#define LIB_GNUPLOT_GEN_H
//#include "lib/format-util.hpp"
#include "lib/iter-source.hpp"
//#include "lib/util.hpp"
#include "lib/stat/csv.hpp"
#include "lib/format-util.hpp"
#include "lib/diff/gen-node.hpp"
//#include <utility>
//#include <sstream>
#include <string>
//#include <vector>
#include <vector>
#include <tuple>
using std::string;
namespace lib {
namespace gnuplot_gen { ///< preconfigured setup for Gnuplot data visualisation
// using util::toString;
// using util::isnil;
using std::string;
// using std::move;
using CSVRowIter = lib::IterSource<const string>::iterator;
/**
* Wrapper to simplify notation in tests.
* Accepts data suitable for representation as CSV
* - either as an std::initializer_list<string> for pre-formatted rows
* - or a list of strings for the header, and then a list of data tuples,
* which will be rendered into data rows in CSV format
* Since this wrapper is-a `vector<string>`, the rows can be retrieved
* directly and then rendered, or the \ref operator string() can be used
* to retrieve the complete data set in a single string of data lines.
*/
struct CSVData
: std::vector<string>
{
CSVData (std::initializer_list<string> lines)
: vector<string>(lines)
{ }
template<class DAT>
CSVData (std::initializer_list<string> header
,std::initializer_list<std::initializer_list<DAT>> data)
{
resize (data.size()+1);
string line;
for (string key : header)
stat::appendCsvField (line, key);
emplace_back (move(line));
for (auto& row : data)
{
line = "";
for (DAT const& val : row)
stat::appendCsvField (line, val);
emplace_back (move(line));
}
}
// standard copy operations acceptable
operator string() const
{
return util::join (*this, "\n");
}
};
using ParamRecord = diff::Rec::Mutator;
const string KEY_CSVData = "CSVData";
const string KEY_DiagramKind = "DiagramKind";
/**
* Generate a Gnuplot diagram to visualise the given data points.
*/
string dataPlot (CSVRowIter&);
string dataPlot (ParamRecord);
string dataPlot (string csvData) { return dataPlot (ParamRecord().set (KEY_CSVData, csvData)); }
}} // namespace lib::gnuplot_gen

View file

@ -42,6 +42,8 @@ using std::array;
namespace lib {
namespace test {
using gnuplot_gen::CSVData;
/***************************************************************************//**
* @test verify data visualisation by generated Gnuplot scripts
@ -73,18 +75,16 @@ namespace test {
void
simpeUsage()
{
using CSVlines = std::initializer_list<string>;
auto data = CSVlines{"x,y"
,"0,1"
,"1,1"
,"2,2"
,"3,3"
,"4,5"
,"5,8"
,"6,13"
};
auto csvIter = explore(data).asIterSource();
string gnuplot = gnuplot_gen::dataPlot (csvIter);
string gnuplot = gnuplot_gen::dataPlot (CSVData{{"step","fib"}
,{{0,1}
,{1,1}
,{2,2}
,{3,3}
,{4,5}
,{5,8}
,{6,13}
,{7,21}
}});
cout << gnuplot <<endl;
}

View file

@ -114288,8 +114288,8 @@ std::cout &lt;&lt; tmpl.render({&quot;what&quot;, &quot;World&quot;}) &lt;&lt; s
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1711767367983" ID="ID_447481681" MODIFIED="1711767384545" TEXT="geignet in Templating &#xfc;bersetzen">
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1711767367983" ID="ID_447481681" MODIFIED="1711904772361" TEXT="geignet in Templating &#xfc;bersetzen">
<icon BUILTIN="pencil"/>
<node CREATED="1711815238130" ID="ID_644083123" MODIFIED="1711815256928" TEXT="Grundidee: Bausteine + externe Steuer-Mechanik">
<icon BUILTIN="idea"/>
<node CREATED="1711815907291" ID="ID_530652307" MODIFIED="1711815930539" TEXT="Templates relativ &#xbb;dumm&#xab; halten"/>
@ -114306,8 +114306,8 @@ std::cout &lt;&lt; tmpl.render({&quot;what&quot;, &quot;World&quot;}) &lt;&lt; s
<node CREATED="1711816185232" ID="ID_301292459" MODIFIED="1711816215559" TEXT="Range-Grenzen und Namen der Achsenbeschriftungen"/>
<node CREATED="1711816271564" ID="ID_1862603482" MODIFIED="1711816277255" TEXT="Parameter der Regressionslinie"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1711816316013" ID="ID_1527861975" MODIFIED="1711816667950" TEXT="Rahmen schaffen">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1711816316013" ID="ID_1527861975" MODIFIED="1711904757510" TEXT="Rahmen schaffen">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1711816320800" ID="ID_310548089" MODIFIED="1711845412382" TEXT="separate Translation-Unit">
<icon BUILTIN="button_ok"/>
<node CREATED="1711816330795" ID="ID_41779330" MODIFIED="1711816336896" TEXT="diese h&#xe4;lt die Template-Texte vor">
@ -114322,14 +114322,13 @@ std::cout &lt;&lt; tmpl.render({&quot;what&quot;, &quot;World&quot;}) &lt;&lt; s
watt soll der Jeitz
</p>
</body>
</html>
</richcontent>
</html></richcontent>
<font ITALIC="true" NAME="SansSerif" SIZE="14"/>
<icon BUILTIN="yes"/>
</node>
</node>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1711816463929" ID="ID_1654160554" MODIFIED="1711845409327" TEXT="und bekommt Daten als CSVFile">
<icon BUILTIN="flag-pink"/>
<node COLOR="#338800" CREATED="1711816463929" ID="ID_1654160554" MODIFIED="1711904751100" TEXT="und bekommt Daten als fertig gerenderten CSV-String">
<icon BUILTIN="button_ok"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1711816503707" ID="ID_1610562996" MODIFIED="1711816512171" TEXT="Hilfsmittel zur Aufbereitung">
@ -114340,8 +114339,8 @@ std::cout &lt;&lt; tmpl.render({&quot;what&quot;, &quot;World&quot;}) &lt;&lt; s
<node CREATED="1711816648544" ID="ID_1216726530" MODIFIED="1711816663402" TEXT="damit ist auch die String-Konvertierung schon gew&#xe4;hrleistet"/>
</node>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1711820689562" ID="ID_1257950036" MODIFIED="1711820696505" TEXT="Problem Daten-&#xdc;bergabe">
<icon BUILTIN="pencil"/>
<node COLOR="#338800" CREATED="1711820689562" ID="ID_1257950036" MODIFIED="1711904725885" TEXT="Problem Daten-&#xdc;bergabe">
<icon BUILTIN="button_ok"/>
<node CREATED="1711820697640" ID="ID_681694171" MODIFIED="1711820712194" TEXT="das DataFile ist generisch, aber kein Interface"/>
<node CREATED="1711820712878" ID="ID_935453700" MODIFIED="1711820724089" TEXT="eigentlich brauche ich nur eine Sequenz von CSV-Zeilen">
<node CREATED="1711820738627" ID="ID_1878202648" MODIFIED="1711820752493" TEXT="k&#xf6;nnte man abstrahieren als Iterator-&#xfc;ber-Strings"/>
@ -114360,8 +114359,7 @@ std::cout &lt;&lt; tmpl.render({&quot;what&quot;, &quot;World&quot;}) &lt;&lt; s
...wegen <i>m&#246;glichen</i>&#160;Style-Adjustments, die ggfs. eine spezielle Datenspalte auswerten k&#246;nnten, um Entscheidungen zu treffen &#8212; allesamt Entscheidungen, die man notfalls auch hart-gecodet als Parameter durchgeben k&#246;nnte
</p>
</body>
</html>
</richcontent>
</html></richcontent>
</node>
<node CREATED="1711838373819" ID="ID_369179473" MODIFIED="1711838436751">
<richcontent TYPE="NODE"><html>
@ -114371,8 +114369,7 @@ std::cout &lt;&lt; tmpl.render({&quot;what&quot;, &quot;World&quot;}) &lt;&lt; s
manches Problem kann man auch<i>&#160;in Gnuplot l&#246;sen...</i>
</p>
</body>
</html>
</richcontent>
</html></richcontent>
<arrowlink COLOR="#941450" DESTINATION="ID_1167069071" ENDARROW="Default" ENDINCLINATION="30;-94;" ID="Arrow_ID_1563038872" STARTARROW="None" STARTINCLINATION="-447;24;"/>
<node CREATED="1711838442489" ID="ID_941034907" MODIFIED="1711838459826" TEXT="Gnuplot ist Turing-complete">
<icon BUILTIN="smiley-oh"/>
@ -114382,21 +114379,27 @@ std::cout &lt;&lt; tmpl.render({&quot;what&quot;, &quot;World&quot;}) &lt;&lt; s
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1711820779334" ID="ID_820373527" MODIFIED="1711820787802" TEXT="einfache Builder-Methoden bereitstellen">
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1711820796179" ID="ID_693535760" MODIFIED="1711820809898" TEXT="direkt eine Liste von Strings (zeilenweise)">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1711820779334" ID="ID_820373527" MODIFIED="1711904723984" TEXT="einfache Builder-Methoden bereitstellen">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1711820796179" ID="ID_693535760" MODIFIED="1711904721354" TEXT="direkt eine Liste von Strings (zeilenweise)">
<linktarget COLOR="#5f8cc1" DESTINATION="ID_693535760" ENDARROW="Default" ENDINCLINATION="250;16;" ID="Arrow_ID_530425185" SOURCE="ID_1979550070" STARTARROW="None" STARTINCLINATION="507;-20;"/>
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1711820811033" ID="ID_1587185713" MODIFIED="1711820838686" TEXT="Header + Datentupel&lt;double&gt;">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1711820811033" ID="ID_1587185713" MODIFIED="1711904722630" TEXT="Header + Datentupel&lt;double&gt;">
<icon BUILTIN="button_ok"/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1711900330296" ID="ID_1080765414" MODIFIED="1711900374682" TEXT="typischerweise: Familie von Aufruf-Front-ends">
<icon BUILTIN="flag-yellow"/>
<node CREATED="1711900349274" ID="ID_1386251374" MODIFIED="1711900360595" TEXT="der eigentliche Aufruf kann mit einem Rec::Mutator erfolgen"/>
<node CREATED="1711900361616" ID="ID_1245877883" MODIFIED="1711900371643" TEXT="dann gibt es zus&#xe4;tzliche Builder, die schon Teile vorbereiten"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1711820846814" ID="ID_131434294" MODIFIED="1711821174833" TEXT="Template-Bausteine">
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1711820852404" ID="ID_1098550176" MODIFIED="1711821039412" TEXT="einfacher Daten-Plot">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1711820852404" ID="ID_1098550176" MODIFIED="1711904777126" TEXT="einfacher Daten-Plot">
<icon BUILTIN="button_ok"/>
<node CREATED="1711820876736" ID="ID_1449855332" MODIFIED="1711820912379" TEXT="gemeinsame Abszisse + 1...9 Datenreihen"/>
<node CREATED="1711820916356" ID="ID_1235091819" MODIFIED="1711820929101" TEXT="stellt diese als Punkte oder Linien dar"/>
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1711820977003" ID="ID_1738447878" MODIFIED="1711836510572" TEXT="Thema: Daten sortieren">
@ -114450,8 +114453,11 @@ std::cout &lt;&lt; tmpl.render({&quot;what&quot;, &quot;World&quot;}) &lt;&lt; s
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1710079848190" ID="ID_227233521" MODIFIED="1710079870844" TEXT="Darstellung ausarbeiten">
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1710079848190" ID="ID_227233521" MODIFIED="1711904804957" TEXT="Darstellung ausarbeiten">
<icon BUILTIN="pencil"/>
<node COLOR="#338800" CREATED="1711904787566" ID="ID_1933798904" MODIFIED="1711904792520" TEXT="einfacher Daten-Plot">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1710079926851" ID="ID_1457237228" MODIFIED="1710079939594" TEXT="Scatter-Plot">
<icon BUILTIN="flag-yellow"/>
</node>
@ -114474,8 +114480,14 @@ std::cout &lt;&lt; tmpl.render({&quot;what&quot;, &quot;World&quot;}) &lt;&lt; s
<node COLOR="#338800" CREATED="1711845516384" ID="ID_1778551442" MODIFIED="1711845526641" TEXT="kann einfaches Diagramm generieren">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1711845527808" ID="ID_1938525708" MODIFIED="1711845538478" TEXT="bessere Daten&#xfc;bergabe kl&#xe4;ren">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1711845527808" ID="ID_1938525708" MODIFIED="1711904814410" TEXT="bessere Daten&#xfc;bergabe kl&#xe4;ren">
<icon BUILTIN="button_ok"/>
<node CREATED="1711900187961" ID="ID_761065242" LINK="#ID_941034907" MODIFIED="1711900225891" TEXT="inzwischen hat sich gekl&#xe4;rt: man kann praktisch alles direkt in Gnuplot machen"/>
<node CREATED="1711900234698" ID="ID_64548436" MODIFIED="1711900256979" TEXT="damit k&#xf6;nnen wir die Daten bereits fertig gerenert in die Implementierung geben"/>
<node COLOR="#435e98" CREATED="1711900258110" ID="ID_1979550070" MODIFIED="1711904812252" TEXT="somit brauchen wir nur Adapter-Funktionen f&#xfc;r einfache Text-Notation">
<arrowlink COLOR="#5f8cc1" DESTINATION="ID_693535760" ENDARROW="Default" ENDINCLINATION="250;16;" ID="Arrow_ID_530425185" STARTARROW="None" STARTINCLINATION="507;-20;"/>
<icon BUILTIN="yes"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1711845539821" ID="ID_1805048889" MODIFIED="1711845580237" TEXT="einige Bestandteile verifizieren">
<icon BUILTIN="flag-yellow"/>