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:
parent
85e77f58a9
commit
fc084c1ca5
4 changed files with 122 additions and 69 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -114288,8 +114288,8 @@ std::cout << tmpl.render({"what", "World"}) << s
|
|||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1711767367983" ID="ID_447481681" MODIFIED="1711767384545" TEXT="geignet in Templating übersetzen">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1711767367983" ID="ID_447481681" MODIFIED="1711904772361" TEXT="geignet in Templating ü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 »dumm« halten"/>
|
||||
|
|
@ -114306,8 +114306,8 @@ std::cout << tmpl.render({"what", "World"}) << 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ält die Template-Texte vor">
|
||||
|
|
@ -114322,14 +114322,13 @@ std::cout << tmpl.render({"what", "World"}) << 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 << tmpl.render({"what", "World"}) << s
|
|||
<node CREATED="1711816648544" ID="ID_1216726530" MODIFIED="1711816663402" TEXT="damit ist auch die String-Konvertierung schon gewährleistet"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1711820689562" ID="ID_1257950036" MODIFIED="1711820696505" TEXT="Problem Daten-Übergabe">
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node COLOR="#338800" CREATED="1711820689562" ID="ID_1257950036" MODIFIED="1711904725885" TEXT="Problem Daten-Ü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önnte man abstrahieren als Iterator-über-Strings"/>
|
||||
|
|
@ -114360,8 +114359,7 @@ std::cout << tmpl.render({"what", "World"}) << s
|
|||
...wegen <i>möglichen</i> Style-Adjustments, die ggfs. eine spezielle Datenspalte auswerten könnten, um Entscheidungen zu treffen — allesamt Entscheidungen, die man notfalls auch hart-gecodet als Parameter durchgeben kö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 << tmpl.render({"what", "World"}) << s
|
|||
manches Problem kann man auch<i> in Gnuplot lö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 << tmpl.render({"what", "World"}) << 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<double>">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node COLOR="#338800" CREATED="1711820811033" ID="ID_1587185713" MODIFIED="1711904722630" TEXT="Header + Datentupel<double>">
|
||||
<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ä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 << tmpl.render({"what", "World"}) << 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 << tmpl.render({"what", "World"}) << 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übergabe klären">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node COLOR="#338800" CREATED="1711845527808" ID="ID_1938525708" MODIFIED="1711904814410" TEXT="bessere Datenübergabe klären">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1711900187961" ID="ID_761065242" LINK="#ID_941034907" MODIFIED="1711900225891" TEXT="inzwischen hat sich geklärt: man kann praktisch alles direkt in Gnuplot machen"/>
|
||||
<node CREATED="1711900234698" ID="ID_64548436" MODIFIED="1711900256979" TEXT="damit kö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ü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"/>
|
||||
|
|
|
|||
Loading…
Reference in a new issue