git: 2f8b9c25e4aa - main - graphics/jkqtplotter: Change to latest revision; Make flavors to not conflict with each other; Add examples

From: Yuri Victorovich <yuri_at_FreeBSD.org>
Date: Fri, 17 Apr 2026 06:50:42 UTC
The branch main has been updated by yuri:

URL: https://cgit.FreeBSD.org/ports/commit/?id=2f8b9c25e4aa6e92c7dae0ca277ad6bb473573bc

commit 2f8b9c25e4aa6e92c7dae0ca277ad6bb473573bc
Author:     Yuri Victorovich <yuri@FreeBSD.org>
AuthorDate: 2026-04-17 05:26:48 +0000
Commit:     Yuri Victorovich <yuri@FreeBSD.org>
CommitDate: 2026-04-17 06:50:34 +0000

    graphics/jkqtplotter: Change to latest revision; Make flavors to not conflict with each other; Add examples
---
 graphics/jkqtplotter/Makefile                      |   63 +-
 graphics/jkqtplotter/distinfo                      |    6 +-
 .../files/examples/all-in-tabs/CMakeLists.txt      |   19 +
 .../files/examples/all-in-tabs/main.cpp            | 1044 ++++++++++++++++++++
 .../files/examples/simple-plot/CMakeLists.txt      |   23 +
 .../files/examples/simple-plot/main.cpp            |   44 +
 graphics/jkqtplotter/files/patch-CMakeLists.txt    |   11 +
 .../files/patch-cmake_jkqtplotter__macros.cmake    |   14 +
 .../files/patch-lib_jkqtmathtext_CMakeLists.txt    |   20 +
 graphics/jkqtplotter/pkg-descr                     |   20 +-
 graphics/jkqtplotter/pkg-plist                     |  141 +++
 graphics/jkqtplotter/pkg-plist.qt5                 |  143 ---
 graphics/jkqtplotter/pkg-plist.qt6                 |  143 ---
 13 files changed, 1379 insertions(+), 312 deletions(-)

diff --git a/graphics/jkqtplotter/Makefile b/graphics/jkqtplotter/Makefile
index 2f8e979a40a5..cced576747c5 100644
--- a/graphics/jkqtplotter/Makefile
+++ b/graphics/jkqtplotter/Makefile
@@ -1,45 +1,68 @@
 PORTNAME=	jkqtplotter
 DISTVERSION=	5.0.0 # not tagged yet, see https://github.com/jkriege2/JKQtPlotter/issues/155
+PORTREVISION=	1
 CATEGORIES=	graphics
-PKGNAMESUFFIX?=	-${FLAVOR}
+PKGNAMESUFFIX=	-${FLAVOR}
 
 MAINTAINER=	yuri@FreeBSD.org
-COMMENT=	Qt plotter framework
-WWW=		https://github.com/jkriege2/JKQtPlotter \
-		https://jkriege2.github.io/JKQtPlotter/index.html
+COMMENT=	Extensive Qt plotter framework
+WWW=		https://github.com/jkriege2/JKQtPlotter
 
-LICENSE=	LGPL21
+LICENSE=	LGPL21+
 LICENSE_FILE=	${WRKSRC}/LICENSE
 
 FLAVORS=	qt6 qt5
 FLAVOR?=	qt6
 
-USES=		cmake gl qt:${FLAVOR:S/qt//}
-_USE_QT_qt5=	core gui opengl printsupport svg xml widgets qmake:build buildtools:build
-_USE_QT_qt6=	base svg tools:build
-USE_QT=		${_USE_QT_${FLAVOR}}
-USE_GL=		gl opengl
+QT_VER=		${FLAVOR:S/qt//}
+
+USES=		cmake compiler:c++11-lang dos2unix gl qt:${QT_VER}
+USE_GL=		opengl
+USE_LDCONFIG=	yes
 
 USE_GITHUB=	yes
 GH_ACCOUNT=	jkriege2
-GH_TAGNAME=	d243218
+GH_PROJECT=	JKQtPlotter
+GH_TAGNAME=	ff89c530
 
-WRKSRC=		${WRKDIR}/JKQtPlotter-${GH_TAGNAME}
+DOS2UNIX_FILES=	CMakeLists.txt \
+		lib/jkqtmathtext/CMakeLists.txt \
+		lib/jkqtplotter/graphs/jkqtpbarchart.h \
+		lib/jkqtplotter/graphs/jkqtpcontour.h \
+		lib/jkqtplotter/graphs/jkqtpfilledcurve.h \
+		lib/jkqtplotter/graphs/jkqtpimpulses.h \
+		lib/jkqtplotter/graphs/jkqtprange.h \
+		lib/jkqtplotter/graphs/jkqtpscatter.h \
+		lib/jkqtplotter/graphs/jkqtpspecialline.h
 
-CMAKE_ARGS=	-DQT_VERSION=${FLAVOR:S/qt//}
-CMAKE_OFF=	JKQtPlotter_BUILD_TESTS \
-		JKQtPlotter_BUILD_EXAMPLES
+_USE_QT_qt5=	core gui opengl printsupport svg testlib xml widgets qmake:build buildtools:build
+_USE_QT_qt6=	base svg tools:build
+USE_QT=		${_USE_QT_${FLAVOR}}
+
+CMAKE_ON=	JKQtPlotter_BUILD_SHARED_LIBS
+CMAKE_OFF=	JKQtPlotter_BUILD_STATIC_LIBS \
+		JKQtPlotter_BUILD_TOOLS \
+		JKQtPlotter_BUILD_TESTS \
+		JKQtPlotter_BUILD_EXAMPLES \
+		JKQtPlotter_BUILD_DECORATE_LIBNAMES_WITH_BUILDTYPE
 
-DOCSDIR=	${PREFIX}/share/doc/JKQTPlotter
+CMAKE_ARGS=	-DCMAKE_INSTALL_INCLUDEDIR=include/qt${QT_VER}
 
-PLIST=		${.CURDIR}/pkg-plist.${FLAVOR}
+PLIST_SUB=	CMAKE_BUILD_TYPE=release \
+		QT_VER=${QT_VER}
 
-OPTIONS_DEFINE=	DOCS
+OPTIONS_DEFINE=	EXAMPLES
 
-PORTDOCS=	*
+EXAMPLESDIR=	${PREFIX}/share/examples/${PORTNAME}${QT_VER}
+PORTEXAMPLES=	*
 
 post-patch:
-	@${REINPLACE_CMD} -e 's|find_package(QT NAMES Qt6 Qt5 COMPONENTS Core REQUIRED)|find_package(QT NAMES Qt${FLAVOR:S/qt//} COMPONENTS Core REQUIRED)|g' \
+	@${REINPLACE_CMD} -e 's|NAMES Qt6 Qt5|NAMES Qt${QT_VER}|g' \
 		${WRKSRC}/cmake/jkqtplotter_common_qtsettings.cmake
 
+post-install-EXAMPLES-on:
+	@cd ${FILESDIR}/examples && \
+		${COPYTREE_SHARE} all-in-tabs ${STAGEDIR}${EXAMPLESDIR} && \
+		${COPYTREE_SHARE} simple-plot ${STAGEDIR}${EXAMPLESDIR}
+
 .include <bsd.port.mk>
diff --git a/graphics/jkqtplotter/distinfo b/graphics/jkqtplotter/distinfo
index 16f5e372f59b..c6ae466aea1a 100644
--- a/graphics/jkqtplotter/distinfo
+++ b/graphics/jkqtplotter/distinfo
@@ -1,3 +1,3 @@
-TIMESTAMP = 1762722146
-SHA256 (jkriege2-jkqtplotter-5.0.0-d243218_GH0.tar.gz) = 711eab4604e7ed29878b4cb4ab1c9942e31ed598d184dcd864f98383358bbbb3
-SIZE (jkriege2-jkqtplotter-5.0.0-d243218_GH0.tar.gz) = 93987448
+TIMESTAMP = 1776403369
+SHA256 (jkriege2-JKQtPlotter-5.0.0-ff89c530_GH0.tar.gz) = 4fa2c9dff34208c50073fe3129f0c6e45756473d8c92c33831a51ffd5f2928cf
+SIZE (jkriege2-JKQtPlotter-5.0.0-ff89c530_GH0.tar.gz) = 93989821
diff --git a/graphics/jkqtplotter/files/examples/all-in-tabs/CMakeLists.txt b/graphics/jkqtplotter/files/examples/all-in-tabs/CMakeLists.txt
new file mode 100644
index 000000000000..cdafe248aa1b
--- /dev/null
+++ b/graphics/jkqtplotter/files/examples/all-in-tabs/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 3.23)
+
+project(jkqtplotter_examples_all LANGUAGES CXX)
+
+set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+
+find_package(Qt6 6.0 REQUIRED COMPONENTS Core Widgets)
+qt_standard_project_setup()
+
+find_package(JKQTPlotter6 REQUIRED)
+
+qt_add_executable(jkqtplotter_examples_all main.cpp)
+
+target_link_libraries(jkqtplotter_examples_all PRIVATE
+    Qt6::Core
+    Qt6::Widgets
+    JKQTPlotter6::JKQTPlotter6
+)
diff --git a/graphics/jkqtplotter/files/examples/all-in-tabs/main.cpp b/graphics/jkqtplotter/files/examples/all-in-tabs/main.cpp
new file mode 100644
index 000000000000..6fd2ff1f6e27
--- /dev/null
+++ b/graphics/jkqtplotter/files/examples/all-in-tabs/main.cpp
@@ -0,0 +1,1044 @@
+/**
+ * JKQtPlotter examples-all: A tab widget showing all major examples
+ */
+
+#include <QApplication>
+#include <QMainWindow>
+#include <QTabWidget>
+#include <random>
+#include <cmath>
+
+#include "jkqtplotter/jkqtplotter.h"
+#include "jkqtcommon/jkqtpmathtools.h"
+#include "jkqtcommon/jkqtpstringtools.h"
+#include "jkqtplotter/jkqtptools.h"
+#include "jkqtplotter/jkqtpcoordinateaxes.h"
+#include "jkqtplotter/graphs/jkqtplines.h"
+#include "jkqtplotter/graphs/jkqtpscatter.h"
+#include "jkqtplotter/graphs/jkqtpbarchart.h"
+#include "jkqtplotter/graphs/jkqtpboxplot.h"
+#include "jkqtplotter/graphs/jkqtpcontour.h"
+#include "jkqtplotter/graphs/jkqtpevaluatedparametriccurve.h"
+#include "jkqtplotter/graphs/jkqtpfilledcurve.h"
+#include "jkqtplotter/graphs/jkqtpgraphlabels.h"
+#include "jkqtplotter/graphs/jkqtpimage.h"
+#include "jkqtplotter/graphs/jkqtpimpulses.h"
+#include "jkqtplotter/graphs/jkqtpgeometric.h"
+#include "jkqtplotter/graphs/jkqtpviolinplot.h"
+#include "jkqtplotter/graphs/jkqtpsinglecolumnsymbols.h"
+#include "jkqtplotter/graphs/jkqtpstatisticsadaptors.h"
+#include "jkqtplotter/graphs/jkqtpvectorfield.h"
+#include "jkqtmath/jkqtpstatbasics.h"
+#include "jkqtmath/jkqtpstatkde.h"
+#include "jkqtmath/jkqtpstathistogram.h"
+
+
+// 1. Simple sine wave (simpletest)
+void setup_simpletest(JKQTPlotter* plot)
+{
+    JKQTPDatastore* ds = plot->getDatastore();
+    QVector<double> X, Y;
+    const int Ndata = 100;
+    for (int i = 0; i < Ndata; i++) {
+        const double x = double(i) / double(Ndata) * 8.0 * JKQTPSTATISTICS_PI;
+        X << x;
+        Y << sin(x);
+    }
+    size_t columnX = ds->addCopiedColumn(X, "x");
+    size_t columnY = ds->addCopiedColumn(Y, "y");
+
+    JKQTPXYLineGraph* graph1 = new JKQTPXYLineGraph(plot);
+    graph1->setXColumn(columnX);
+    graph1->setYColumn(columnY);
+    graph1->setTitle(QObject::tr("sine graph"));
+    plot->addGraph(graph1);
+    plot->zoomToFit();
+    plot->getPlotter()->setPlotLabel(QObject::tr("Simple Test"));
+}
+
+
+// 2. Scatter graph with noise (scatter)
+void setup_scatter(JKQTPlotter* plot)
+{
+    JKQTPDatastore* ds = plot->getDatastore();
+    size_t columnX = ds->addColumn("x");
+    auto colXInserter = ds->backInserter(columnX);
+    size_t columnY = ds->addColumn("y");
+    auto colYInserter = ds->backInserter(columnY);
+
+    std::default_random_engine generator(123);
+    std::normal_distribution<double> distribution(0, 0.5);
+    const int Ndata = 100;
+    for (int i = 0; i < Ndata; i++) {
+        const double x = double(i) / double(Ndata) * 8.0 * JKQTPSTATISTICS_PI;
+        *colXInserter = x;
+        *colYInserter = sin(x) + distribution(generator);
+        colXInserter++;
+        colYInserter++;
+    }
+
+    JKQTPXYScatterGraph* graph1 = new JKQTPXYScatterGraph(plot);
+    graph1->setXColumn(columnX);
+    graph1->setYColumn(columnY);
+    graph1->setTitle(QObject::tr("sine graph"));
+    plot->addGraph(graph1);
+    plot->zoomToFit();
+    plot->getPlotter()->setPlotLabel(QObject::tr("Scatter Example"));
+}
+
+
+// 3. Bar chart (barchart)
+void setup_barchart(JKQTPlotter* plot)
+{
+    plot->getPlotter()->setUseAntiAliasingForGraphs(true);
+    plot->getPlotter()->setUseAntiAliasingForSystem(true);
+    plot->getPlotter()->setUseAntiAliasingForText(true);
+    JKQTPDatastore* ds = plot->getDatastore();
+
+    const int Ndata = 5;
+    QString L[Ndata] = {"cat. A", "cat. C", "cat. B", "cat. D", "other"};
+    double  X[Ndata] = {1, 3, 2, 4, 5};
+    double Y1[Ndata] = {5, 4, 3, 4, 5};
+    double Y2[Ndata] = {-5, -3, 1, 3, 6};
+    double Y3[Ndata] = {6, 2, 5, 3, 6};
+
+    size_t columnX  = ds->addCopiedColumn(X, Ndata, "x");
+    size_t columnY1 = ds->addCopiedColumn(Y1, Ndata, "y1");
+    size_t columnY2 = ds->addCopiedColumn(Y2, Ndata, "y2");
+    size_t columnY3 = ds->addCopiedColumn(Y3, Ndata, "y3");
+
+    JKQTPBarVerticalGraph* graph1 = new JKQTPBarVerticalGraph(plot);
+    graph1->setBarPositionColumn(columnX);
+    graph1->setBarHeightColumn(columnY1);
+    graph1->setTitle(QObject::tr("dataset 1"));
+    JKQTPBarVerticalGraph* graph2 = new JKQTPBarVerticalGraph(plot);
+    graph2->setBarPositionColumn(columnX);
+    graph2->setBarHeightColumn(columnY2);
+    graph2->setTitle(QObject::tr("dataset 2"));
+    JKQTPBarVerticalGraph* graph3 = new JKQTPBarVerticalGraph(plot);
+    graph3->setBarPositionColumn(columnX);
+    graph3->setBarHeightColumn(columnY3);
+    graph3->setTitle(QObject::tr("dataset 3"));
+
+    plot->addGraph(graph1);
+    plot->addGraph(graph2);
+    plot->addGraph(graph3);
+    graph1->autoscaleBarWidthAndShift();
+
+    plot->getXAxis()->addAxisTickLabels(X, L, Ndata);
+    plot->getXAxis()->setTickLabelAngle(45);
+    plot->getXAxis()->setTickLabelFontSize(12);
+    plot->getPlotter()->setKeyPosition(JKQTPKeyOutsideTopRight);
+    plot->getMainKey()->setLayout(JKQTPKeyLayoutOneRow);
+    plot->zoomToFit();
+    plot->getPlotter()->setPlotLabel(QObject::tr("Bar Chart"));
+}
+
+
+// 4. Box plots (boxplot)
+void setup_boxplot(JKQTPlotter* plot)
+{
+    plot->getPlotter()->setUseAntiAliasingForGraphs(true);
+    plot->getPlotter()->setUseAntiAliasingForSystem(true);
+    plot->getPlotter()->setUseAntiAliasingForText(true);
+    JKQTPDatastore* ds = plot->getDatastore();
+
+    QVector<double> POS, POSY, MEDIAN, MEAN, Q25, Q75, MIN, MAX, OUTLIERSX, OUTLIERSY;
+    POS    << 1   << 4   << 7   << 10;
+    POSY   << -1  << -2  << -3  << -4;
+    MIN    << 2   << 3   << 2.5 << 6;
+    Q25    << 4   << 4.5 << 5   << 7;
+    MEDIAN << 5   << 6   << 7   << 9;
+    MEAN   << 5.5 << 5.2 << 8   << 8;
+    Q75    << 6   << 7   << 9   << 11;
+    MAX    << 8   << 7.5 << 11  << 12;
+    OUTLIERSX << 4 << 4   << 4   << 4 << 4      << 10 << 10 << 10   << 10 << 10   << 10   << 10;
+    OUTLIERSY << 1 << 0.5 << 1.3 << 8 << 8.1    << 5  << 4  << 12.2 << 13 << 12.5 << 13.5 << 13.1;
+
+    size_t columnPOS      = ds->addCopiedColumn(POS,      "POS");
+    size_t columnPOSY     = ds->addCopiedColumn(POSY,     "POSY");
+    size_t columnMIN      = ds->addCopiedColumn(MIN,      "MIN");
+    size_t columnQ25      = ds->addCopiedColumn(Q25,      "Q25");
+    size_t columnMEDIAN   = ds->addCopiedColumn(MEDIAN,   "MEDIAN");
+    size_t columnMEAN     = ds->addCopiedColumn(MEAN,     "MEAN");
+    size_t columnQ75      = ds->addCopiedColumn(Q75,      "Q75");
+    size_t columnMAX      = ds->addCopiedColumn(MAX,      "MAX");
+    size_t columnOUTLIERSX = ds->addCopiedColumn(OUTLIERSX, "OUTLIERSX");
+    size_t columnOUTLIERSY = ds->addCopiedColumn(OUTLIERSY, "OUTLIERSY");
+
+    JKQTPBoxplotVerticalGraph* graph = new JKQTPBoxplotVerticalGraph(plot);
+    graph->setPositionColumn(columnPOS);
+    graph->setMinColumn(columnMIN);
+    graph->setPercentile25Column(columnQ25);
+    graph->setMedianColumn(columnMEDIAN);
+    graph->setMeanColumn(columnMEAN);
+    graph->setPercentile75Column(columnQ75);
+    graph->setMaxColumn(columnMAX);
+    graph->setTitle("vertical Boxplots");
+
+    JKQTPXYLineGraph* graphOutliers = new JKQTPXYLineGraph(plot);
+    graphOutliers->setXColumn(columnOUTLIERSX);
+    graphOutliers->setYColumn(columnOUTLIERSY);
+    graphOutliers->setTitle("outliers");
+    graphOutliers->setColor(graph->getLineColor().darker());
+    graphOutliers->setSymbolFillColor(QColor("white"));
+    graphOutliers->setSymbolType(JKQTPCircle);
+    graphOutliers->setDrawLine(false);
+    graphOutliers->setSymbolSize(7);
+
+    JKQTPBoxplotHorizontalGraph* graphh = new JKQTPBoxplotHorizontalGraph(plot);
+    graphh->setPositionColumn(columnPOSY);
+    graphh->setMinColumn(columnMIN);
+    graphh->setPercentile25Column(columnQ25);
+    graphh->setMedianColumn(columnMEDIAN);
+    graphh->setMeanColumn(columnMEAN);
+    graphh->setPercentile75Column(columnQ75);
+    graphh->setMaxColumn(columnMAX);
+    graphh->setTitle("horizontal Boxplots");
+    graphh->setFillColor(graphh->getLineColor().lighter());
+    graphh->setWhiskerLineStyle(Qt::DashLine);
+    graphh->setWhiskerLineColor(graphh->getLineColor().darker());
+    graphh->setWhiskerCapLineStyle(Qt::SolidLine);
+    graphh->setWhiskerCapLineColor(graphh->getLineColor().darker());
+    graphh->setWhiskerCapLineWidth(graphh->getLineWidth() * 2.5);
+    graphh->setMeanSymbolType(JKQTPFilledStar);
+    graphh->setMeanFillColor(QColor("silver"));
+    graphh->setMedianLineColor(QColor("darkgreen"));
+    graphh->setBoxWidthRelative(0.75);
+
+    plot->addGraph(graph);
+    plot->addGraph(graphOutliers);
+    plot->addGraph(graphh);
+    plot->zoomToFit();
+    plot->getPlotter()->setKeyPosition(JKQTPKeyInsideTopLeft);
+    plot->getPlotter()->setPlotLabel(QObject::tr("Box Plots"));
+}
+
+
+// 5. Contour plot of quadrupole electric potential (contourplot)
+void setup_contourplot(JKQTPlotter* plot)
+{
+    plot->getPlotter()->setUseAntiAliasingForGraphs(true);
+    plot->getPlotter()->setUseAntiAliasingForSystem(true);
+    plot->getPlotter()->setUseAntiAliasingForText(true);
+
+    JKQTPDatastore* ds = plot->getDatastore();
+    const int NX = 200;
+    const int NY = 200;
+    const double w = 2.7e-6;
+    const double dx = w / static_cast<double>(NX);
+    const double h = NY * dx;
+    size_t cPotential = ds->addImageColumn(NX, NY, "imagedata");
+
+    double y = -h / 2.0;
+    const double eps0  =  8.854187e-12;
+    const double Q1    =  1.6e-19,  Q1_x0 = -0.5e-6, Q1_y0 = -0.5e-6;
+    const double Q2    =  1.6e-19,  Q2_x0 =  0.5e-6, Q2_y0 =  0.5e-6;
+    const double Q3    = -1.6e-19,  Q3_x0 = -0.5e-6, Q3_y0 =  0.5e-6;
+    const double Q4    = -1.6e-19,  Q4_x0 =  0.5e-6, Q4_y0 = -0.5e-6;
+    for (size_t iy = 0; iy < NY; iy++) {
+        double x = -w / 2.0;
+        for (size_t ix = 0; ix < NX; ix++) {
+            const double r1 = sqrt((x-Q1_x0)*(x-Q1_x0) + (y-Q1_y0)*(y-Q1_y0));
+            const double r2 = sqrt((x-Q2_x0)*(x-Q2_x0) + (y-Q2_y0)*(y-Q2_y0));
+            const double r3 = sqrt((x-Q3_x0)*(x-Q3_x0) + (y-Q3_y0)*(y-Q3_y0));
+            const double r4 = sqrt((x-Q4_x0)*(x-Q4_x0) + (y-Q4_y0)*(y-Q4_y0));
+            ds->setPixel(cPotential, ix, iy,
+                Q1 / (4.0*JKQTPSTATISTICS_PI*eps0) / r1 +
+                Q2 / (4.0*JKQTPSTATISTICS_PI*eps0) / r2 +
+                Q3 / (4.0*JKQTPSTATISTICS_PI*eps0) / r3 +
+                Q4 / (4.0*JKQTPSTATISTICS_PI*eps0) / r4);
+            x += dx;
+        }
+        y += dx;
+    }
+
+    JKQTPColumnContourPlot* graph = new JKQTPColumnContourPlot(plot);
+    graph->setTitle("");
+    graph->setImageColumn(cPotential);
+    graph->setX(-w / 2.0);
+    graph->setY(-h / 2.0);
+    graph->setWidth(w);
+    graph->setHeight(h);
+    graph->setColorPalette(JKQTPMathImageBlueGreenRed);
+    graph->getColorBarRightAxis()->setAxisLabel("electric potential [V]");
+
+    QVector<double> reldists; reldists << 0.1 << 0.25 << 0.5 << 1 << 1.5 << 2 << 2.5 << 3;
+    for (auto reldist : reldists) {
+        const double level = fabs(Q1 / (4.0*JKQTPSTATISTICS_PI*eps0) / (Q1_x0 * reldist));
+        graph->addContourLevel(-level);
+        graph->addContourLevel(level);
+    }
+    graph->setAutoImageRange(false);
+    graph->setImageMin(graph->getContourLevels().first());
+    graph->setImageMax(graph->getContourLevels().last());
+
+    plot->addGraph(graph);
+    plot->getXAxis()->setAxisLabel("x [m]");
+    plot->getYAxis()->setAxisLabel("y [m]");
+    plot->getPlotter()->setMaintainAspectRatio(true);
+    plot->getPlotter()->setAspectRatio(w / h);
+    plot->getPlotter()->setMaintainAxisAspectRatio(true);
+    plot->getPlotter()->setAxisAspectRatio(w / h);
+    plot->zoomToFit();
+    plot->getPlotter()->setPlotLabel(QObject::tr("Contour Plot"));
+}
+
+
+// 6. Error bar styles (errorbarstyles)
+void setup_errorbarstyles(JKQTPlotter* plot)
+{
+    JKQTPDatastore* ds = plot->getDatastore();
+    QVector<double> X, Yerror, Xerror;
+    const int Ndata = 7;
+    for (int i = 0; i < Ndata; i++) {
+        const double x = 10.0 + double(i) * 2.0;
+        X << x;
+        Yerror << 0.35 + 0.3 * sin(x);
+        Xerror << 0.35 + 0.3 * sin(x);
+    }
+    size_t columnX      = ds->addCopiedColumn(X,      "x");
+    size_t columnXError = ds->addCopiedColumn(Xerror,  "xerror");
+    size_t columnYError = ds->addCopiedColumn(Yerror,  "yerror");
+
+    QVector<JKQTPErrorPlotstyle> errorStyles {
+        JKQTPNoError, JKQTPErrorBars, JKQTPErrorSimpleBars, JKQTPErrorLines,
+        JKQTPErrorPolygons, JKQTPErrorBoxes, JKQTPErrorEllipses,
+        JKQTPErrorBarsPolygons, JKQTPErrorBarsLines,
+        JKQTPErrorSimpleBarsLines, JKQTPErrorSimpleBarsPolygons
+    };
+    QVector<bool> showXandYError {
+        false, true, true, false, false, true, true, false, false, false, false
+    };
+
+    for (int errorID = 0; errorID < errorStyles.size(); errorID++) {
+        QVector<double> Y;
+        for (auto& xx : X)
+            Y << xx * 0.5 + static_cast<double>(errorID) * 2.5;
+
+        JKQTPXYLineErrorGraph* graph = new JKQTPXYLineErrorGraph(plot);
+        graph->setXColumn(columnX);
+        graph->setYColumn(ds->addCopiedColumn(Y, "y" + QString::number(errorID)));
+        graph->setXErrorColumn(columnXError);
+        graph->setYErrorColumn(columnYError);
+        graph->setYErrorStyle(errorStyles[errorID]);
+        graph->setXErrorStyle(JKQTPNoError);
+        if (showXandYError[errorID]) {
+            graph->setXErrorStyle(errorStyles[errorID]);
+            graph->setDrawLine(false);
+        }
+        QColor c = graph->getErrorFillColor();
+        c.setAlphaF(0.3);
+        graph->setErrorFillColor(c);
+        graph->setErrorLineWidth(1);
+        graph->setErrorBarCapSize(15);
+        graph->setSymbolType(JKQTPCross);
+        graph->setLineStyle(Qt::DashLine);
+        graph->setSymbolSize(5);
+        graph->setSymbolLineWidth(1);
+        graph->setLineWidth(1);
+        graph->setTitle("\\verb!" + JKQTPErrorPlotstyle2String(errorStyles[errorID]) + "!");
+        plot->addGraph(graph);
+    }
+
+    plot->zoomToFit();
+    plot->getPlotter()->setKeyPosition(JKQTPKeyOutsideRightTop);
+    plot->getXAxis()->setDrawGrid(false);
+    plot->getXAxis()->setDrawMinorGrid(false);
+    plot->getYAxis()->setDrawGrid(false);
+    plot->getYAxis()->setDrawMinorGrid(false);
+    plot->getPlotter()->setPlotLabel(QObject::tr("Error Bar Styles"));
+}
+
+
+// 7. Evaluated parametric curves — butterfly curve (evalcurve)
+void setup_evalcurve(JKQTPlotter* plot)
+{
+    JKQTPXYFunctionLineGraph* func1 = new JKQTPXYFunctionLineGraph(plot);
+    func1->setPlotFunctionFunctor([](double t) -> QPointF {
+        return QPointF(
+            sin(t) * (exp(cos(t)) - 2.0*cos(4.0*t) - jkqtp_pow5(sin(t/12.0))),
+            cos(t) * (exp(cos(t)) - 2.0*cos(4.0*t) - jkqtp_pow5(sin(t/12.0)))
+        );
+    });
+    func1->setTRange(0, 12.0 * JKQTPSTATISTICS_PI);
+    func1->setTitle("C++-inline function: \"Butterfly Curve\"");
+    plot->addGraph(func1);
+
+    JKQTPXYFunctionLineGraph* func2 = new JKQTPXYFunctionLineGraph(plot);
+    func2->setPlotFunctionFunctor([](double t, const QVector<double>& params) -> QPointF {
+        return QPointF(
+            3.0*sin(params[0]*t + params[2]) + 8.0,
+            3.0*sin(params[1]*t)
+        );
+    });
+    func2->setParamsV(5, 4, JKQTPSTATISTICS_PI / 4.0);
+    func2->setTRange(0, 2.0 * JKQTPSTATISTICS_PI);
+    func2->setTitle("C++-inline function $[ sin(5{\\cdot}t+\\pi/4), sin(4{\\cdot}t) ]$");
+    plot->addGraph(func2);
+
+    plot->getXAxis()->setAxisLabel(QObject::tr("x-axis"));
+    plot->getYAxis()->setAxisLabel(QObject::tr("y-axis"));
+    plot->getPlotter()->setKeyPosition(JKQTPKeyOutsideBottomLeft);
+    plot->setXY(-3, 12, -3.2, 3.2);
+    plot->getPlotter()->setPlotLabel(QObject::tr("Parametric Curves (Butterfly)"));
+}
+
+
+// 8. Filled curve graph with sine waves (filledgraphs — adapted, no image resource)
+void setup_filledgraphs(JKQTPlotter* plot)
+{
+    JKQTPDatastore* ds = plot->getDatastore();
+    size_t columnX  = ds->addLinearColumn(256, 0.0, 2.0*JKQTPSTATISTICS_PI, "x");
+    size_t columnY1 = ds->addCalculatedColumnFromColumn(columnX, [](double x) { return sin(x); },      "sin(x)");
+    size_t columnY2 = ds->addCalculatedColumnFromColumn(columnX, [](double x) { return cos(x); },      "cos(x)");
+    size_t columnY3 = ds->addCalculatedColumnFromColumn(columnX, [](double x) { return 0.5*sin(2*x); }, "0.5*sin(2x)");
+
+    auto makeGraph = [&](size_t colY, const QString& title, const QString& colorName) {
+        JKQTPFilledCurveXGraph* g = new JKQTPFilledCurveXGraph(plot);
+        g->setXColumn(columnX);
+        g->setYColumn(colY);
+        g->setTitle(title);
+        QColor col = QColor(colorName);
+        g->setColor(col);
+        col.setAlphaF(0.35f);
+        g->setFillColor(col);
+        g->setLineWidth(1);
+        plot->addGraph(g);
+    };
+
+    makeGraph(columnY1, "sin(x)",       "red");
+    makeGraph(columnY2, "cos(x)",       "blue");
+    makeGraph(columnY3, "0.5·sin(2x)", "green");
+
+    plot->getXAxis()->setAxisLabel("x");
+    plot->getYAxis()->setAxisLabel("f(x)");
+    plot->zoomToFit();
+    plot->getPlotter()->setPlotLabel(QObject::tr("Filled Curves"));
+}
+
+
+// 9. Graph labels on a bar chart (graphlabels)
+void setup_graphlabels(JKQTPlotter* plot)
+{
+    plot->getPlotter()->setUseAntiAliasingForGraphs(true);
+    plot->getPlotter()->setUseAntiAliasingForSystem(true);
+    plot->getPlotter()->setUseAntiAliasingForText(true);
+    JKQTPDatastore* ds = plot->getDatastore();
+
+    const int Ndata = 6;
+    const size_t columnX = ds->addLinearColumn(Ndata, -1, 1, "x");
+    const size_t columnY = ds->addCalculatedColumnFromColumn(columnX,
+        [](double x) { return jkqtp_roundToDigits(-sin(x*3.0), 2); }, "data");
+
+    JKQTPBarVerticalGraph* graph1 = new JKQTPBarVerticalGraph(plot);
+    graph1->setBarPositionColumn(columnX);
+    graph1->setBarHeightColumn(columnY);
+    graph1->setTitle(QObject::tr("dataset: bars"));
+    graph1->setColor(QColorWithAlphaF(graph1->getFillColor(), 0.25));
+
+    JKQTPXYLineGraph* graph2 = new JKQTPXYLineGraph(plot);
+    graph2->setXColumn(columnX);
+    graph2->setYColumn(columnY);
+    graph2->setTitle(QObject::tr("dataset: lines"));
+    graph2->setColor(QColorWithAlphaF(graph2->getLineColor(), 0.5));
+
+    JKQTPXYGraphLabels* graphLabels = new JKQTPXYGraphLabels(JKQTPXYGraphLabels::YValueLabel, plot);
+    graphLabels->setXColumn(graph1->getXColumn());
+    graphLabels->setYColumn(graph1->getYColumn());
+    graphLabels->setLabelPosition(JKQTPGLabelAwayFromXAxis);
+    graphLabels->setTextFontSize(14);
+
+    plot->addGraph(graph1);
+    plot->addGraph(graph2);
+    plot->addGraph(graphLabels);
+
+    plot->setXY(-1.5, 1.5, -1.5, 1.5);
+    plot->getXAxis()->setDrawMode1(JKQTPCADMLine);
+    plot->getXAxis()->setDrawMode2(JKQTPCADMLine);
+    plot->getYAxis()->setDrawMode1(JKQTPCADMLine);
+    plot->getYAxis()->setDrawMode2(JKQTPCADMLine);
+    plot->getPlotter()->setPlotLabel(QObject::tr("Graph Labels"));
+}
+
+
+// 10. Image plot — Airy disk (imageplot)
+void setup_imageplot(JKQTPlotter* plot)
+{
+    plot->getPlotter()->setUseAntiAliasingForGraphs(true);
+    plot->getPlotter()->setUseAntiAliasingForSystem(true);
+    plot->getPlotter()->setUseAntiAliasingForText(true);
+    JKQTPDatastore* ds = plot->getDatastore();
+
+    const int NX = 100, NY = 100;
+    const double dx = 1e-2, dy = 1e-2;
+    const double w = static_cast<double>(NX) * dx;
+    const double h = static_cast<double>(NY) * dy;
+    double airydisk[NX * NY];
+
+    const double NA = 1.1;
+    const double wavelength = 488e-3;
+
+    double y = -h / 2.0;
+    for (int iy = 0; iy < NY; iy++) {
+        double x = -w / 2.0;
+        for (int ix = 0; ix < NX; ix++) {
+            const double r = sqrt(x*x + y*y);
+            const double v = 2.0 * JKQTPSTATISTICS_PI * NA * r / wavelength;
+            airydisk[iy*NX + ix] = pow(2.0 * jkqtp_j1(v) / v, 2);
+            x += dx;
+        }
+        y += dy;
+    }
+
+    size_t cAiryDisk = ds->addCopiedImageAsColumn(airydisk, NX, NY, "imagedata");
+
+    JKQTPColumnMathImage* graph = new JKQTPColumnMathImage(plot);
+    graph->setTitle("");
+    graph->setImageColumn(cAiryDisk);
+    graph->setNx(NX);
+    graph->setNy(NY);
+    graph->setX(-w / 2.0);
+    graph->setY(-h / 2.0);
+    graph->setWidth(w);
+    graph->setHeight(h);
+    graph->setColorPalette(JKQTPMathImageMATLAB);
+    graph->getColorBarRightAxis()->setAxisLabel("light intensity [A.U.]");
+    graph->setAutoImageRange(true);
+
+    plot->addGraph(graph);
+    plot->getXAxis()->setAxisLabel("x [{\\mu}m]");
+    plot->getYAxis()->setAxisLabel("y [{\\mu}m]");
+    plot->getPlotter()->setMaintainAspectRatio(true);
+    plot->getPlotter()->setMaintainAxisAspectRatio(true);
+    plot->zoomToFit();
+    plot->getPlotter()->setPlotLabel(QObject::tr("Image Plot (Airy Disk)"));
+}
+
+
+// 11. Impulse graph (impulsesplot)
+void setup_impulsesplot(JKQTPlotter* plot)
+{
+    JKQTPDatastore* ds = plot->getDatastore();
+    const int NData = 40;
+    QVector<double> X, Y, E;
+    for (int i = 0; i < NData; i++) {
+        const double xx = double(i) / 40.0 * 8.0 * JKQTPSTATISTICS_PI;
+        X << xx;
+        Y << cos(xx) * exp(-xx / 10.0);
+        E << 0.2 * Y.last();
+    }
+    size_t columnX = ds->addCopiedColumn(X, "x");
+    size_t columnY = ds->addCopiedColumn(Y, "y");
+
+    JKQTPImpulsesVerticalGraph* graph = new JKQTPImpulsesVerticalGraph(plot);
+    graph->setKeyColumn(columnX);
+    graph->setValueColumn(columnY);
+    graph->setLineWidth(2);
+    graph->setBaseline(0.0);
+    graph->setColor(QColor("red"));
+    graph->setTitle(QObject::tr("$\\cos(x)\\cdot\\exp(-x/10)$"));
+
+    plot->addGraph(graph);
+    plot->getXAxis()->setAxisLabel(QObject::tr("x-axis"));
+    plot->getYAxis()->setAxisLabel(QObject::tr("y-axis"));
+    plot->getXAxis()->setDrawGrid(false);
+    plot->getYAxis()->setDrawGrid(false);
+    plot->zoomToFit();
+    plot->getPlotter()->setShowKey(false);
+    plot->getPlotter()->setPlotLabel(QObject::tr("Impulse Plot"));
+}
+
+
+// 12. Logarithmic axes — resonance curve (logaxes)
+void setup_logaxes(JKQTPlotter* plot)
+{
+    JKQTPDatastore* ds = plot->getDatastore();
+    auto sqr = [](double x) { return x * x; };
+
+    QVector<double> X;
+    QVector<double> D {0.001, 0.1, 1, 10};
+    const int Ndata = 500;
+    for (int i = 0; i < Ndata; i++)
+        X << double(i) / double(Ndata) * 3;
+    size_t columnX = ds->addCopiedColumn(X, "x");
+
+    QVector<Qt::PenStyle> pens {Qt::SolidLine, Qt::DashLine, Qt::DotLine, Qt::DashDotLine, Qt::DashDotDotLine};
+    for (int id = 0; id < D.size(); id++) {
+        QVector<double> Y;
+        for (auto& xx : X)
+            Y << 1.0 / sqrt(sqr(1 - sqr(xx)) + sqr(2*xx*D[id]));
+
+        JKQTPXYLineGraph* graph = new JKQTPXYLineGraph(plot);
+        graph->setXColumn(columnX);
+        graph->setYColumn(ds->addCopiedColumn(Y, "y" + QString::number(id)));
+        graph->setSymbolType(JKQTPNoSymbol);
+        graph->setLineStyle(pens[id % pens.size()]);
+        graph->setLineWidth(1.5);
+        graph->setTitle(QString("$D=\\delta/\\omega_0=%1$").arg(D[id]));
+        plot->addGraph(graph);
+    }
+
+    plot->addGraph(new JKQTPGeoText(plot, 1.25, 10,
+        "$\\frac{A}{A_{stat}}=\\frac{1}{\\sqrt{\\left(1-\\eta^2\\right)^2+\\left(2{\\eta}D\\right)^2}}$",
+        15, QColor("black")));
+
+    plot->getYAxis()->setLogAxis(true);
+    plot->getYAxis()->setMinorTicks(9);
+    plot->getYAxis()->setDrawMinorGrid(true);
+    plot->getYAxis()->setTickLabelType(JKQTPCALTexponent);
+    plot->getYAxis()->setLabelDigits(0);
+    plot->getYAxis()->setTickLabelFontSize(10);
+    plot->getYAxis()->setMinorTickLabelFontSize(7);
+    plot->getYAxis()->setLabelFontSize(14);
+    plot->getXAxis()->setTickLabelFontSize(10);
+    plot->getXAxis()->setMinorTickLabelFontSize(7);
+    plot->getXAxis()->setLabelFontSize(14);
+    plot->getYAxis()->setAxisLabel("Amplitude $A/A_{stat}$");
+    plot->getXAxis()->setAxisLabel("relative driving frequency $\\eta=\\omega/\\omega_0$");
+    plot->zoomToFit();
+    plot->getPlotter()->setPlotLabel(QObject::tr("Logarithmic Axes (Resonance)"));
+}
+
+
+// 13. Parametric scatter — varying symbols/colors/sizes (paramscatterplot)
+void setup_paramscatterplot(JKQTPlotter* plot)
+{
+    JKQTPDatastore* ds = plot->getDatastore();
+    QVector<double> X, Y1, Y2, Y3, Y4, P, C, S, RGB, LW;
+    const int Ndata = 10;
+    for (int i = 0; i < Ndata; i++) {
+        const double x = double(i) / double(Ndata) * 2.0 * JKQTPSTATISTICS_PI;
+        X  << x;
+        Y1 << 1.5 + sin(x);
+        Y2 << 3.5 + sin(x);
+        Y3 << 5.5 + sin(x);
+        Y4 << 7.5 + sin(x);
+        P  << (i + 2);
+        C  << x;
+        S  << 5 * (i + 1);
+        LW << (i + 1) * 1.5;
+        RGB << double(qRgb(double(i)/double(Ndata)*255, 0, 255 - double(i)/double(Ndata)*255));
+    }
+    size_t columnX   = ds->addCopiedColumn(X,   "x");
+    size_t columnY1  = ds->addCopiedColumn(Y1,  "y1");
+    size_t columnY2  = ds->addCopiedColumn(Y2,  "y2");
+    size_t columnY3  = ds->addCopiedColumn(Y3,  "y3");
+    size_t columnY4  = ds->addCopiedColumn(Y4,  "y4");
+    size_t columnP   = ds->addCopiedColumn(P,   "point_style");
+    size_t columnC   = ds->addCopiedColumn(C,   "color_value");
+    size_t columnS   = ds->addCopiedColumn(S,   "size");
+    size_t columnLW  = ds->addCopiedColumn(LW,  "linewidth");
+    size_t columnRGB = ds->addCopiedColumn(RGB, "rgb");
+
+    auto mkGraph = [&](size_t colY, const QString& title) {
+        auto* g = new JKQTPXYParametrizedScatterGraph(plot);
+        g->setXColumn(columnX); g->setYColumn(colY);
+        g->setTitle(title);
+        return g;
+    };
+
+    auto* g1 = mkGraph(columnY1, "1: symbol type");
+    g1->setSymbolColumn(columnP); g1->setDrawLine(true); g1->setColor(QColor("blueviolet"));
+    plot->addGraph(g1);
+
+    auto* g2 = mkGraph(columnY2, "2: color");
+    g2->setColorColumn(columnC); g2->setColorPalette(JKQTPMathImageRYGB);
+    g2->setSymbolType(JKQTPFilledRect); g2->setDrawLine(true);
+    g2->getColorBarRightAxis()->setAxisLabel("color scale");
+    plot->addGraph(g2);
+
+    auto* g3 = mkGraph(columnY3, "3: symbol size");
+    g3->setSizeColumn(columnS); g3->setSymbolType(JKQTPFilledCircle); g3->setDrawLine(true);
+    plot->addGraph(g3);
+
+    auto* g4 = mkGraph(columnY4, "4: RGB-color");
+    g4->setColorColumn(columnRGB); g4->setColorColumnContainsRGB(true);
+    g4->setDrawLine(true); g4->setSymbolType(JKQTPFilledDownTriangle);
+    plot->addGraph(g4);
+
+    plot->getPlotter()->setKeyPosition(JKQTPKeyOutsideBottomLeft);
+    plot->getMainKey()->setLayout(JKQTPKeyLayoutOneRow);
+    plot->getXAxis()->setAxisLabel("x-axis");
+    plot->getYAxis()->setAxisLabel("y-axis");
+    plot->getXAxis()->setDrawGrid(false);
+    plot->getYAxis()->setDrawGrid(false);
+    plot->zoomToFit();
+    plot->getPlotter()->setPlotLabel(QObject::tr("Parametric Scatter"));
+}
+
+
+// 14. Parametric curve — logarithmic spiral (parametriccurve)
+void setup_parametriccurve(JKQTPlotter* plot)
+{
+    JKQTPDatastore* ds = plot->getDatastore();
+    QVector<double> X, Y, R;
+    const int Ndata = 500;
+    const double phiMax = 4.0 * JKQTPSTATISTICS_PI;
+    const double a = 1, k = 0.2;
+    for (double phi = -phiMax; phi <= phiMax; phi += phiMax / double(Ndata)) {
+        const double x = a * exp(k*phi) * cos(phi);
+        const double y = a * exp(k*phi) * sin(phi);
+        X << x; Y << y; R << sqrt(x*x + y*y);
+    }
+    size_t columnX = ds->addCopiedColumn(X, "x");
+    size_t columnY = ds->addCopiedColumn(Y, "y");
+    size_t columnR = ds->addCopiedColumn(R, "r");
+
+    JKQTPXYParametrizedScatterGraph* graph2 = new JKQTPXYParametrizedScatterGraph(plot);
+    graph2->setXColumn(columnX);
+    graph2->setYColumn(columnY);
+    graph2->setColorColumn(columnR);
+    graph2->setColorPalette(JKQTPMathImageMATLAB);
+    graph2->setSymbolType(JKQTPNoSymbol);
+    graph2->setDrawLine(true);
+    graph2->setTitle("colored spiral");
+    graph2->getColorBarRightAxis()->setAxisLabel("color scale radius $r(\\phi)$");
+    plot->addGraph(graph2);
+
+    plot->getPlotter()->setMaintainAspectRatio(true);
+    plot->getPlotter()->setAspectRatio(1);
+    plot->getXAxis()->setAxisLabel("x-axis");
+    plot->getYAxis()->setAxisLabel("y-axis");
+    plot->getXAxis()->setDrawGrid(false);
+    plot->getYAxis()->setDrawGrid(false);
+    plot->setXY(-15, 15, -15, 15);
+    plot->getPlotter()->setPlotLabel(QObject::tr("Logarithmic Spiral"));
+}
+
+
+// 15. Secondary Y-axes (second_axis)
+void setup_second_axis(JKQTPlotter* plot)
+{
+    JKQTPDatastore* ds = plot->getDatastore();
+    size_t columnX  = ds->addLinearColumn(40, 0, 10, "x");
+    size_t columnY1 = ds->addCalculatedColumnFromColumn(columnX, [](double x) { return x; },        "y1");
+    size_t columnY2 = ds->addCalculatedColumnFromColumn(columnX, [](double x) { return cos(x); },   "y2");
+    size_t columnY3 = ds->addCalculatedColumnFromColumn(columnX, [](double x) { return x*x; },      "y3");
+    size_t columnY4 = ds->addCalculatedColumnFromColumn(columnX, [](double x) { return sqrt(x); },  "y4");
+
+    auto yAxisRef2 = plot->getPlotter()->addSecondaryYAxis(new JKQTPVerticalAxis(plot->getPlotter(), JKQTPPrimaryAxis));
+    plot->getYAxis(yAxisRef2)->setDrawGrid(false);
+    plot->getYAxis(yAxisRef2)->setDrawMode1(JKQTPCADMnone);
+    plot->getYAxis(yAxisRef2)->setDrawMode2(JKQTPCADMcomplete);
+    plot->getYAxis(yAxisRef2)->setDrawMode0(JKQTPCADMnone);
+    plot->getYAxis(yAxisRef2)->setShowZeroAxis(false);
+
+    auto yAxisRef3 = plot->getPlotter()->addSecondaryYAxis(new JKQTPVerticalAxis(plot->getPlotter(), JKQTPPrimaryAxis));
+    plot->getYAxis(yAxisRef3)->setDrawGrid(false);
+    plot->getYAxis(yAxisRef3)->setDrawMode1(JKQTPCADMnone);
+    plot->getYAxis(yAxisRef3)->setDrawMode2(JKQTPCADMcomplete);
+    plot->getYAxis(yAxisRef3)->setDrawMode0(JKQTPCADMnone);
+    plot->getYAxis(yAxisRef3)->setShowZeroAxis(false);
+
+    auto yAxisRef4 = plot->getPlotter()->addSecondaryYAxis(new JKQTPVerticalAxis(plot->getPlotter(), JKQTPPrimaryAxis));
+    plot->getYAxis(yAxisRef4)->setDrawGrid(false);
+    plot->getYAxis(yAxisRef4)->setDrawMode1(JKQTPCADMcomplete);
+    plot->getYAxis(yAxisRef4)->setDrawMode2(JKQTPCADMnone);
+    plot->getYAxis(yAxisRef4)->setDrawMode0(JKQTPCADMnone);
+    plot->getYAxis(yAxisRef4)->setShowZeroAxis(false);
+
+    plot->getYAxis()->setDrawMode2(JKQTPCADMnone);
+    plot->getYAxis()->setAxisLabel("graph1");
+
+    JKQTPXYLineGraph* graph1 = new JKQTPXYLineGraph(plot);
+    graph1->setKeyColumn(columnX); graph1->setValueColumn(columnY1);
+    plot->addGraph(graph1);
+    plot->getYAxis()->setColor(graph1->getLineColor());
+
+    JKQTPXYLineGraph* graph2 = new JKQTPXYLineGraph(plot);
+    graph2->setKeyColumn(columnX); graph2->setValueColumn(columnY2);
+    plot->addGraph(graph2);
+    graph2->setYAxis(yAxisRef2);
+    plot->getYAxis(yAxisRef2)->setColor(graph2->getLineColor());
+    plot->getYAxis(yAxisRef2)->setAxisLabel("graph2");
+
+    JKQTPXYLineGraph* graph3 = new JKQTPXYLineGraph(plot);
+    graph3->setKeyColumn(columnX); graph3->setValueColumn(columnY3);
+    plot->addGraph(graph3);
+    graph3->setYAxis(yAxisRef3);
+    plot->getYAxis(yAxisRef3)->setColor(graph3->getLineColor());
+    plot->getYAxis(yAxisRef3)->setAxisLabel("graph3");
+
+    JKQTPXYLineGraph* graph4 = new JKQTPXYLineGraph(plot);
+    graph4->setKeyColumn(columnX); graph4->setValueColumn(columnY4);
+    plot->addGraph(graph4);
+    graph4->setYAxis(yAxisRef4);
+    plot->getYAxis(yAxisRef4)->setColor(graph4->getLineColor());
+    plot->getYAxis(yAxisRef4)->setAxisLabel("graph4");
+
+    plot->zoomToFit();
+    plot->getPlotter()->setPlotLabel(QObject::tr("Secondary Axes"));
+}
+
+
+// 16. Stacked bar chart — German energy mix (stackedbars)
+void setup_stackedbars(JKQTPlotter* plot)
+{
+    plot->getPlotter()->setUseAntiAliasingForGraphs(true);
+    plot->getPlotter()->setUseAntiAliasingForSystem(true);
+    plot->getPlotter()->setUseAntiAliasingForText(true);
+    JKQTPDatastore* ds = plot->getDatastore();
+
+    QVector<double> year, pct_other, pct_coaloil, pct_gas, pct_nuclear, pct_green;
+    year        << 1990  << 1995  << 2000  << 2005  << 2010  << 2015;
+    pct_other   << 3.5   << 3.5   << 4.4   << 4.4   << 5.0   << 5.0 ;
+    pct_coaloil << 58.7  << 55.7  << 51.5  << 48.2  << 42.9  << 43.1;
+    pct_gas     << 6.5   << 7.7   << 8.5   << 11.7  << 14.1  << 9.6 ;
+    pct_nuclear << 27.7  << 28.7  << 29.4  << 26.2  << 22.2  << 14.2;
+    pct_green   << 3.6   << 4.4   << 6.2   << 9.5   << 15.8  << 28.1;
+
+    size_t cYear    = ds->addCopiedColumn(year,        "year");
+    size_t cOther   = ds->addCopiedColumn(pct_other,   "other");
+    size_t cCoalOil = ds->addCopiedColumn(pct_coaloil, "coal & oil");
+    size_t cGas     = ds->addCopiedColumn(pct_gas,     "natural gas");
+    size_t cNuclear = ds->addCopiedColumn(pct_nuclear, "nuclear energy");
+    size_t cGreen   = ds->addCopiedColumn(pct_green,   "green energy");
+
+    QVector<JKQTPBarVerticalStackableGraph*> graphs;
+    auto addBar = [&](size_t colY, const QString& title, const QString& color) {
+        auto* g = new JKQTPBarVerticalStackableGraph(plot);
+        g->setXColumn(cYear); g->setYColumn(colY);
+        g->setTitle(title);
+        g->setFillColor_and_darkenedColor(QColor(color));
+        graphs.push_back(g);
+        if (graphs.size() > 1)
+            g->stackUpon(graphs[graphs.size()-2]);
+        plot->addGraph(g);
+    };
+
+    addBar(cOther,   QObject::tr("other sources"),  "red");
+    addBar(cCoalOil, QObject::tr("coal & oil"),     "darkgrey");
+    addBar(cGas,     QObject::tr("natural gas"),    "blue");
+    addBar(cNuclear, QObject::tr("nuclear energy"), "gold");
+    addBar(cGreen,   QObject::tr("green energy"),   "darkgreen");
+
+    plot->getXAxis()->setAxisLabel("year");
+    plot->getYAxis()->setAxisLabel("fraction of energy production in Germany [%]");
+    plot->getPlotter()->setKeyPosition(JKQTPKeyOutsideTopRight);
+    plot->getMainKey()->setLayout(JKQTPKeyLayoutOneRow);
+    plot->zoomToFit();
+    plot->getPlotter()->setPlotLabel(QObject::tr("Stacked Bar Chart"));
+}
+
+
+// 17. Symbols and error bars — sine with errors (symbols_and_errors)
*** 831 LINES SKIPPED ***