diff --git a/src/lib/gnuplot-gen.cpp b/src/lib/gnuplot-gen.cpp index 53f0d3866..ce88e5ce8 100644 --- a/src/lib/gnuplot-gen.cpp +++ b/src/lib/gnuplot-gen.cpp @@ -106,8 +106,11 @@ ${else set xlabel abscissaName ${end if XLabel }${if YLabel -}set ylabel '${YLabel}' -${end if YLabel +}set ylabel '${YLabel}' ${end if YLabel +} +${if Yrange} +set yrange [${Yrange}] +${endif } set key autotitle columnheader tmargin @@ -122,34 +125,64 @@ plot for [i=2:*] $RunData using 1:i with ${DiagramKind} linestyle i-1 const string GNUPLOT_SCATTER_REGRESSION = R"~(# # +####---------Scatter-Regression-Plot------------- # +stats $RunData using 1:2 nooutput -set arrow 1 from graph 0, first 1 to graph 1, first 30 nohead ls 9 - -set multiplot layout 2,1 -set lmargin at screen 0.12 -set rmargin at screen 0.88 +# draw regression line as arrow +regLine(x) = STATS_slope * x + STATS_intercept +set arrow 1 from graph 0, first regLine(STATS_min_x) \ + to graph 1, first regLine(STATS_max_x) \ + nohead linestyle 9 +plots = STATS_columns - 1 +# Adjust layout based on number of data sequences; +# additional sequences placed into secondary diagram +# +if (plots > 1) { + set multiplot layout 2,1 # 2 rows 1 column + set lmargin at screen 0.12 # fixed margins to align diagrams + set rmargin at screen 0.88 +} +####------------------------------- plot $RunData using 1:2 with points linestyle 1 -unset arrow 1 -unset arrow 10 -unset arrow 11 -set border 2+8 -set yrange [0:8] -set y2range [500:2000] - -unset x2label -set format x "" -set ylabel "Y1 axis" -set y2label "Y2 axis" offset -2 -set y2tics -plot $RunData using 1:3 with impulses linestyle 3, \ - $RunData using 1:4 with points linestyle 5 axes x1y2 +if (plots > 1) { + # switch off decorations for secondary diagram + unset arrow 1 + unset arrow 10 + unset arrow 11 + set border 2+8 +${if Y2range} + set yrange [${Y2range}] +${endif +} unset x2label + set format x "" +${if Y2label +} set ylabel '${Y2label}' ${endif +} + if (plots <= 2) { + ####--------------------------------- + plot $RunData using 1:3 with impulses linestyle 3 + } else { + # more than one additional data sequence + # +${if Y3range +} set y2range [${Y3range}] ${endif +} set y2tics +${if Y3label +} set y2label '${Y3label}' offset -1 ${endif +} + ####--------------------------------------------- + plot $RunData using 1:3 with impulses linestyle 3, \ + for [i=4:*] $RunData using 1:i with points linestyle 5+(i-4) axes x1y2 + } +} )~"; + }//(End)template and defaults definitions @@ -173,4 +206,17 @@ plot $RunData using 1:3 with impulses linestyle 3, \ return plot.render (params.genNode()); } + + string + scatterRegression (ParamRecord params) + { + TextTemplate plot{GNUPLOT_BASIC_PLOT_DEF + +GNUPLOT_SCATTER_REGRESSION}; + + params.set ("CommonStyleDef", GNUPLOT_CommonStyleDef) + .set ("AxisGridSetup", GNUPLOT_AxisGridSetup) + ; + return plot.render (params.genNode()); + } + }} // namespace lib::gnuplot_gen diff --git a/src/lib/gnuplot-gen.hpp b/src/lib/gnuplot-gen.hpp index ad29cb874..2c8055f65 100644 --- a/src/lib/gnuplot-gen.hpp +++ b/src/lib/gnuplot-gen.hpp @@ -67,13 +67,38 @@ namespace gnuplot_gen { ///< preconfigured setup for Gnuplot data visualisation const string KEY_CSVData = "CSVData"; const string KEY_DiagramKind = "DiagramKind"; + const string KEY_Yrange = "Yrange"; + const string KEY_Y2range = "Y2range"; + const string KEY_Y3range = "Y3range"; + const string KEY_Xlabel = "Xlabel"; + const string KEY_Ylabel = "Ylabel"; + const string KEY_Y2label = "Y2label"; + const string KEY_Y3label = "Y2label"; + /** * Generate a Gnuplot diagram to visualise the given data points. */ string dataPlot (ParamRecord); - string dataPlot (string csvData) { return dataPlot (ParamRecord().set (KEY_CSVData, csvData)); } + + inline string + dataPlot (string csvData) + { + return dataPlot (ParamRecord().set (KEY_CSVData, csvData)); + } + + + /** + * Generate a (X,Y)-scatter plot with regression line + */ + string scatterRegression (ParamRecord); + + inline string + scatterRegression (string csvData) + { + return scatterRegression (ParamRecord().set (KEY_CSVData, csvData)); + } }} // namespace lib::gnuplot_gen diff --git a/tests/library/gnuplot-gen-test.cpp b/tests/library/gnuplot-gen-test.cpp index 3015e9132..b48f8c9fc 100644 --- a/tests/library/gnuplot-gen-test.cpp +++ b/tests/library/gnuplot-gen-test.cpp @@ -55,7 +55,7 @@ namespace test{ run (Arg) { simpeUsage(); - verify_instantiation(); + plot_scatter_regression(); verify_keySubstituton(); verify_conditional(); verify_iteration(); @@ -71,17 +71,19 @@ namespace test{ void simpeUsage() { - string gnuplot = gnuplot_gen::dataPlot (CSVData{{"step","fib"} - ,{{0,1} - ,{1,1} - ,{2,2} - ,{3,3} - ,{4,5} - ,{5,8} - ,{6,13} - ,{7,21.55} - }}); - cout << gnuplot < CHECK (contains (gnuplot, "set datafile separator \",;\"")); CHECK (contains (gnuplot, "\"step\",\"fib\"")); @@ -92,12 +94,37 @@ namespace test{ - /** @test TODO - * @todo WIP 4/24 🔁 define ⟶ implement + /** @test Create a (x,y) scatter plot with regression line + * - in the simple case, there is only one diagram + * - use the `stats` command to let Gnuplot calculate the linear regression + * - draw a regrsssion line using the `arrow` command + * and a function representing the linear regression model + * @todo WIP 4/24 🔁 define ⟶ ✔ implement */ void - verify_instantiation() + plot_scatter_regression() { + string gnuplot = gnuplot_gen::scatterRegression( + CSVData{{"step","fib"} + ,{{0,1} + ,{1,1} + ,{2,2} + ,{3,3} + ,{4,5} + ,{5,8} + ,{6,13} + ,{7,21.55} + }}); + cout << gnuplot < no multiplot layout + CHECK (not contains (gnuplot, "set multiplot")); } diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index efc01e3c6..d8afb7f25 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -112419,9 +112419,10 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - + + + + @@ -114497,11 +114498,72 @@ std::cout << tmpl.render({"what", "World"}) << s - + + + + + + + + + + + + + + +

+ nicht Header-Zeile, also Zeile 2. +

+

+ Einzelne Datenpunkte können problemlos fehlen.... +

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + @@ -123747,6 +123809,24 @@ unsigned int ThreadIdAsInt = *static_cast<unsigned int*>(static_cast<vo + + + + + + + + + + + + + + + + + +