\image html JKQTPGLSimpleBoxAndLineONLYLABELS_small.png
+
\subpage JKQTPXYGraphLabels
+
`JKQTPXYGraphLabels`
\subsection jkqtp_extut_keyaxesstyles Examples for Styling the Plot, Keys, Axes, ...
diff --git a/doc/dox/jkqtplotter_plotelements_classdoc.dox b/doc/dox/jkqtplotter_plotelements_classdoc.dox
index d68c72dfdb..a790e137e3 100644
--- a/doc/dox/jkqtplotter_plotelements_classdoc.dox
+++ b/doc/dox/jkqtplotter_plotelements_classdoc.dox
@@ -29,7 +29,10 @@ These classes are used by JKQTPlotterBase to output the plot.
\defgroup jkqtplotter_basegraphserrors Mix-In Classes for Error Indicators
\ingroup jkqtplotter_mixins
-\defgroup jkqtplotter_basegraphs_stylemixins Mix-In Classes for Plot Styling
+\defgroup jkqtplotter_basegraphs_stylemixins Mix-In Classes for Styling General Graphs
+\ingroup jkqtplotter_mixins
+
+\defgroup jkqtplotter_specialgraphs_stylemixins Mix-In Classes for Styling Specialized Graphs (Boxplots etz.)
\ingroup jkqtplotter_mixins
@@ -116,6 +119,21 @@ This group assembles graphs that show their data with symbols and optionally wit
+\defgroup jkqtplotter_graphlabels Labeling Datapoints
+\ingroup jkqtplotter_concretegraphs
+
+This group assembles graphs that add (textual) labels to the datapoints in a plot:
+
+
+
Screenshot
+
Classes
+
+
\image html JKQTPGLSimpleBoxAndLineONLYLABELS_small.png
+
\image html JKQTPGLSimpleBoxAndLineONLYLABELS_small.png
+
JKQTPXYGraphLabels
\image html JKQTPHorizontalRange_small.png
JKQTPHorizontalRange, JKQTPVerticalRange
diff --git a/doc/dox/todo.dox b/doc/dox/todo.dox
index fcb914dab6..4c0a8ce3ad 100644
--- a/doc/dox/todo.dox
+++ b/doc/dox/todo.dox
@@ -20,7 +20,6 @@ This page lists several todos and wishes for future version of JKQTPlotter
graphs: gant-chart as simplified vector field with (x,y1,y2) or (x1,x2,y), or (x,y,dx), (x,y,dy) ... different head/tail style
graphs: matrix plots with boxes, labels, ...
graphs: matrix plots with symbols: symbol-type, color, size should be parametric, cf. scatter plots
-
graphs: text labels at positions/for graphs
graphs: vector field graph (arrows), variant (x,y,dx,dy), (x,y,alpha,length), (x1,y1,x2,y2) ... different head/tail styles
graphs: waterfall charts (see https://en.wikipedia.org/wiki/Waterfall_chart)
graphs: parametrized variant of JKQTPSingleColumnSymbolsGraph (beeswarm plots etz.) where each symbol may have a color given by a second column
NEW/REWORKED all functions in JKQTBasePlotter are re-entrant, i.e. different instances can be used from different threads in parallel (although there is some overhead due to shared caches between the threads!). This is demonstrated and discussed in \ref JKQTPlotterMultiThreaded .
NEW: allow linear-gradient(), currentcolor, ... in brush definitions of style.ini-file ... and using it is cyberpunk and dark styles
NEW: style simple_noaxes.ini
+
NEW: JKQTPXYGraphLabels which can draw a label next to each datapoint in the given x/y-dataset. The labels can be x-/y- or x&y-coordinates or custom, then defined by a user-supplied functor (+example \ref JKQTPlotterGraphLabels)
JKQTMathText:
diff --git a/doc/images/JKQTPGLSimple.png b/doc/images/JKQTPGLSimple.png
new file mode 100644
index 0000000000..d30b3c7f44
Binary files /dev/null and b/doc/images/JKQTPGLSimple.png differ
diff --git a/doc/images/JKQTPGLSimpleBoxAndLine.png b/doc/images/JKQTPGLSimpleBoxAndLine.png
new file mode 100644
index 0000000000..a308804eae
Binary files /dev/null and b/doc/images/JKQTPGLSimpleBoxAndLine.png differ
diff --git a/doc/images/JKQTPGLSimpleBoxAndLineONLYLABELS.png b/doc/images/JKQTPGLSimpleBoxAndLineONLYLABELS.png
new file mode 100644
index 0000000000..2a5e8486e4
Binary files /dev/null and b/doc/images/JKQTPGLSimpleBoxAndLineONLYLABELS.png differ
diff --git a/doc/images/JKQTPGLSimpleBoxAndLineONLYLABELSVertical.png b/doc/images/JKQTPGLSimpleBoxAndLineONLYLABELSVertical.png
new file mode 100644
index 0000000000..c9fb82799f
Binary files /dev/null and b/doc/images/JKQTPGLSimpleBoxAndLineONLYLABELSVertical.png differ
diff --git a/doc/images/JKQTPGLSimpleBoxAndLineONLYLABELSVertical_small.png b/doc/images/JKQTPGLSimpleBoxAndLineONLYLABELSVertical_small.png
new file mode 100644
index 0000000000..e5f1190730
Binary files /dev/null and b/doc/images/JKQTPGLSimpleBoxAndLineONLYLABELSVertical_small.png differ
diff --git a/doc/images/JKQTPGLSimpleBoxAndLineONLYLABELS_small.png b/doc/images/JKQTPGLSimpleBoxAndLineONLYLABELS_small.png
new file mode 100644
index 0000000000..ac56399551
Binary files /dev/null and b/doc/images/JKQTPGLSimpleBoxAndLineONLYLABELS_small.png differ
diff --git a/doc/images/JKQTPGLSimpleBoxAndLineVertical.png b/doc/images/JKQTPGLSimpleBoxAndLineVertical.png
new file mode 100644
index 0000000000..11ac84043d
Binary files /dev/null and b/doc/images/JKQTPGLSimpleBoxAndLineVertical.png differ
diff --git a/doc/images/JKQTPGLSimpleVertical.png b/doc/images/JKQTPGLSimpleVertical.png
new file mode 100644
index 0000000000..dcf0b1e820
Binary files /dev/null and b/doc/images/JKQTPGLSimpleVertical.png differ
diff --git a/doc/images/JKQTPGLabelAboveData.png b/doc/images/JKQTPGLabelAboveData.png
new file mode 100644
index 0000000000..bb75658aa4
Binary files /dev/null and b/doc/images/JKQTPGLabelAboveData.png differ
diff --git a/doc/images/JKQTPGLabelAwayFromXAxis.png b/doc/images/JKQTPGLabelAwayFromXAxis.png
new file mode 100644
index 0000000000..bdad341f16
Binary files /dev/null and b/doc/images/JKQTPGLabelAwayFromXAxis.png differ
diff --git a/doc/images/JKQTPGLabelAwayFromYAxis.png b/doc/images/JKQTPGLabelAwayFromYAxis.png
new file mode 100644
index 0000000000..22c87e6c97
Binary files /dev/null and b/doc/images/JKQTPGLabelAwayFromYAxis.png differ
diff --git a/doc/images/JKQTPGLabelBelowData.png b/doc/images/JKQTPGLabelBelowData.png
new file mode 100644
index 0000000000..ce09d9bfe4
Binary files /dev/null and b/doc/images/JKQTPGLabelBelowData.png differ
diff --git a/doc/images/JKQTPGLabelLeftHandSide.png b/doc/images/JKQTPGLabelLeftHandSide.png
new file mode 100644
index 0000000000..7c6be19a42
Binary files /dev/null and b/doc/images/JKQTPGLabelLeftHandSide.png differ
diff --git a/doc/images/JKQTPGLabelRightHandSide.png b/doc/images/JKQTPGLabelRightHandSide.png
new file mode 100644
index 0000000000..eaa3e0ce6a
Binary files /dev/null and b/doc/images/JKQTPGLabelRightHandSide.png differ
diff --git a/doc/images/JKQTPGLabelTowardsXAxis.png b/doc/images/JKQTPGLabelTowardsXAxis.png
new file mode 100644
index 0000000000..d684d396d3
Binary files /dev/null and b/doc/images/JKQTPGLabelTowardsXAxis.png differ
diff --git a/doc/images/JKQTPGLabelTowardsYAxis.png b/doc/images/JKQTPGLabelTowardsYAxis.png
new file mode 100644
index 0000000000..abb2a5385c
Binary files /dev/null and b/doc/images/JKQTPGLabelTowardsYAxis.png differ
diff --git a/doc/images/jkqtpxygraphlabels.png b/doc/images/jkqtpxygraphlabels.png
new file mode 100644
index 0000000000..69afd70824
Binary files /dev/null and b/doc/images/jkqtpxygraphlabels.png differ
diff --git a/doc/images/jkqtpxygraphlabels.svg b/doc/images/jkqtpxygraphlabels.svg
new file mode 100644
index 0000000000..06f266338c
--- /dev/null
+++ b/doc/images/jkqtpxygraphlabels.svg
@@ -0,0 +1,310 @@
+
+
+
+
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index 09bd8ffe75..332c445fcc 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -74,6 +74,7 @@ if (JKQtPlotter_BUILD_LIB_JKQTPLOTTER)
add_subdirectory(geo_simple)
add_subdirectory(geo_coordinateaxis0)
add_subdirectory(geometric)
+ add_subdirectory(graphlabels)
add_subdirectory(imageplot)
add_subdirectory(imageplot_cimg)
add_subdirectory(imageplot_modifier)
diff --git a/examples/graphlabels/CMakeLists.txt b/examples/graphlabels/CMakeLists.txt
new file mode 100644
index 0000000000..dd1e642a16
--- /dev/null
+++ b/examples/graphlabels/CMakeLists.txt
@@ -0,0 +1,25 @@
+cmake_minimum_required(VERSION 3.23)
+
+set(EXAMPLE_NAME graphlabels)
+set(EXENAME jkqtptest_${EXAMPLE_NAME})
+
+message( STATUS ".. Building Example ${EXAMPLE_NAME}" )
+
+
+
+add_executable(${EXENAME} WIN32 ${EXAMPLE_NAME}.cpp)
+target_link_libraries(${EXENAME} JKQTPExampleToolsLib)
+target_include_directories(${EXENAME} PRIVATE ../../lib)
+target_link_libraries(${EXENAME} ${jkqtplotter_namespace}JKQTPlotter${jkqtplotter_LIBNAME_VERSION_PART})
+
+# precomiled headers to speed up compilation
+if (JKQtPlotter_BUILD_WITH_PRECOMPILED_HEADERS)
+ target_precompile_headers(${EXENAME} REUSE_FROM jkqtptest_simpletest)
+endif (JKQtPlotter_BUILD_WITH_PRECOMPILED_HEADERS)
+
+
+# Installation
+install(TARGETS ${EXENAME} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
+
+#Installation of Qt DLLs on Windows
+jkqtplotter_deployqt(${EXENAME})
diff --git a/examples/graphlabels/README.md b/examples/graphlabels/README.md
new file mode 100644
index 0000000000..bca529010a
--- /dev/null
+++ b/examples/graphlabels/README.md
@@ -0,0 +1,16 @@
+# Example (JKQTPlotter): Simple Graph Labels Example {#JKQTPlotterGraphLabels}
+This project (see [`graphlabels`](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/graphlabels) demonstrates the use of JKQTPXYGraphLabels to add labels to the datapoints of a graph.
+
+The source code of the main application is (see [`graphlabels.cpp`](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/graphlabels/graphlabels.cpp):
+```.cpp
+```
+
+
+The result looks like this:
+
+![graphlabels](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/graphlabels.png)
+
+or this:
+
+![graphlabels_hor](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/graphlabels_hor.png)
+
diff --git a/examples/graphlabels/graphlabels.cpp b/examples/graphlabels/graphlabels.cpp
new file mode 100644
index 0000000000..9f82a31ed0
--- /dev/null
+++ b/examples/graphlabels/graphlabels.cpp
@@ -0,0 +1,144 @@
+/** \example graphlabels.cpp
+ * Shows how to draw datapoint labels using JKQTPXYGraphLabels
+ *
+ * \ref JKQTPlotterGraphLabels
+ */
+
+#include "jkqtpexampleapplication.h"
+#include
+#include "jkqtplotter/jkqtplotter.h"
+#include "jkqtplotter/graphs/jkqtpscatter.h"
+#include "jkqtplotter/graphs/jkqtpbarchart.h"
+#include "jkqtplotter/graphs/jkqtpgraphlabels.h"
+#include "jkqtpexampleapplication.h"
+
+#define Ndata 6
+
+
+template
+std::pair doExample(JKQTPlotter& plot, const QString& title, JKQTPGraphLabelPosition labPos)
+{
+ // 1. create a plotter window and get a pointer to the internal datastore (for convenience)
+ plot.getPlotter()->setUseAntiAliasingForGraphs(true); // nicer (but slower) plotting
+ plot.getPlotter()->setUseAntiAliasingForSystem(true); // nicer (but slower) plotting
+ plot.getPlotter()->setUseAntiAliasingForText(true); // nicer (but slower) text rendering
+ JKQTPDatastore* ds=plot.getDatastore();
+
+
+
+ // 2. make up some arbitrary data to be used for plotting
+ 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");
+
+
+ // 3. create barchart and line-chart to display the data:
+ TCHART* graph1=new TCHART(&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);
+ if (typeid(TCHART)==typeid(JKQTPBarVerticalGraph)) {
+ graph2->setXColumn(columnX);
+ graph2->setYColumn(columnY);
+ } else {
+ graph2->setXColumn(columnY);
+ graph2->setYColumn(columnX);
+ }
+ graph2->setTitle(QObject::tr("dataset: lines"));
+ graph2->setColor(QColorWithAlphaF(graph2->getLineColor(),0.5));
+
+ // 4.1. create barchart to display the data:
+ JKQTPXYGraphLabels* graphLabels=new JKQTPXYGraphLabels((typeid(TCHART)==typeid(JKQTPBarVerticalGraph)) ? JKQTPXYGraphLabels::YValueLabel : JKQTPXYGraphLabels::XValueLabel, &plot);
+ graphLabels->setXColumn(graph1->getXColumn());
+ graphLabels->setYColumn(graph1->getYColumn());
+
+ // 4.2. set position of labels and some styling options
+ graphLabels->setLabelPosition(labPos);
+ graphLabels->setTextFontSize(14);
+
+ // 5. add the graphs to the plot, so it is actually displayed
+ plot.addGraph(graph1);
+ plot.addGraph(graph2);
+ plot.addGraph(graphLabels);
+
+ // 6. scale the plot so the graph is contained
+ plot.setXY(-1.5,1.5,-1.5,1.5);
+
+ // 7.modify the plot style a bit
+ plot.getXAxis()->setDrawMode1(JKQTPCADMLine);
+ plot.getXAxis()->setDrawMode2(JKQTPCADMLine);
+ plot.getYAxis()->setDrawMode1(JKQTPCADMLine);
+ plot.getYAxis()->setDrawMode2(JKQTPCADMLine);
+
+ // show plotter and make it a decent size
+ plot.setWindowTitle(title);
+ plot.show();
+ plot.resize(400/plot.devicePixelRatioF(),250/plot.devicePixelRatioF());
+
+ return {graph1, graphLabels};
+}
+
+int main(int argc, char* argv[])
+{
+
+ JKQTPAppSettingController highDPIController(argc,argv);
+ JKQTPExampleApplication app(argc, argv);
+
+ JKQTPlotter plotV;
+ auto gV=doExample(plotV, "1: JKQTPXYGraphLabels+JKQTPBarVerticalGraph", JKQTPGLabelAwayFromXAxis);
+ JKQTPlotter plotH;
+ auto gH=doExample(plotH, "2: JKQTPXYGraphLabels+JKQTPBarHorizontalGraph", JKQTPGLabelAwayFromYAxis);
+
+ app.addExportStepFunctor([&](){
+ gV.second->setLabelPosition(JKQTPGLabelTowardsXAxis);
+ gH.second->setLabelPosition(JKQTPGLabelTowardsYAxis);
+ plotV.redrawPlot();
+ plotH.redrawPlot();
+ });
+
+ app.addExportStepFunctor([&](){
+ gV.second->setLabelPosition(JKQTPGLabelAboveData);
+ gH.second->setLabelPosition(JKQTPGLabelRightHandSide);
+ plotV.redrawPlot();
+ plotH.redrawPlot();
+ });
+
+ app.addExportStepFunctor([&](){
+ gV.second->setLabelPosition(JKQTPGLabelBelowData);
+ gH.second->setLabelPosition(JKQTPGLabelLeftHandSide);
+ plotV.redrawPlot();
+ plotH.redrawPlot();
+ });
+ app.addExportStepFunctor([&](){
+ gV.second->setLabelPosition(JKQTPGLabelAwayFromXAxis);
+ gV.second->setLabelBoxType(JKQTPGLSimpleBox);
+ gV.second->setDrawLabelBoxFrame(true);
+ gH.second->setLabelPosition(JKQTPGLabelAwayFromYAxis);
+ gH.second->setLabelBoxType(JKQTPGLSimpleBox);
+ gH.second->setDrawLabelBoxFrame(true);
+ plotV.redrawPlot();
+ plotH.redrawPlot();
+ });
+ app.addExportStepFunctor([&](){
+ gV.second->setLabelPosition(JKQTPGLabelAwayFromXAxis);
+ gV.second->setLabelBoxType(JKQTPGLSimpleBoxAndLine);
+ gV.second->setDrawLabelBoxFrame(true);
+ gH.second->setLabelPosition(JKQTPGLabelAwayFromYAxis);
+ gH.second->setLabelBoxType(JKQTPGLSimpleBoxAndLine);
+ gH.second->setDrawLabelBoxFrame(true);
+ plotV.redrawPlot();
+ plotH.redrawPlot();
+ });
+ app.addExportStepFunctor([&](){
+ //plotV.getPlotter()->setOnlyGraphVisible(plotV.getPlotter()->indexOfGraph(gV.second));
+ //plotH.getPlotter()->setOnlyGraphVisible(plotH.getPlotter()->indexOfGraph(gH.second));
+ gV.first->setVisible(false);
+ gH.first->setVisible(false);
+
+ plotV.redrawPlot();
+ plotH.redrawPlot();
+ });
+
+ return app.exec();
+}
diff --git a/examples/multithreaded/README.md b/examples/multithreaded/README.md
index 353feee8df..83f16b80be 100644
--- a/examples/multithreaded/README.md
+++ b/examples/multithreaded/README.md
@@ -97,10 +97,10 @@ This test results in the following numbers (on my AMD Ryzen5 8/16-core laptop):
VERSION: 5.0.0
BUILD MODE: Release
-SERIAL RESULTS: runtime, overall = 11199.2ms single runtimes = (466.6 +/- 1681.5) ms speedup = 1.00x threads / available = 1 / 16
+SERIAL RESULTS: runtime, overall = 12353.5ms single runtimes = (514.6 +/- 1737.1) ms speedup = 1.00x threads / available = 1 / 16
PARALLEL RESULTS:
-runtime, overall = 2157.8ms single runtimes = (596.8 +/- 85.1) ms speedup = 6.64x threads / available = 8 / 16 batch runs = 3
speedup vs. serial = 5.2x
+runtime, overall = 3440.1ms single runtimes = (739.1 +/- 91.8) ms speedup = 5.16x threads / available = 8 / 16 batch runs = 3
speedup vs. serial = 3.6x
[comment]:RESULTS_END
diff --git a/lib/jkqtplotter.pri b/lib/jkqtplotter.pri
index 63b8d5edda..18d2b973cf 100644
--- a/lib/jkqtplotter.pri
+++ b/lib/jkqtplotter.pri
@@ -57,6 +57,7 @@ isEmpty(JKQTP_PLOTTER_PRI_INCLUDED) {
$$PWD/jkqtplotter/graphs/jkqtpbarchart.h \
$$PWD/jkqtplotter/graphs/jkqtpevaluatedparametriccurve.h \
$$PWD/jkqtplotter/graphs/jkqtplines.h \
+ $$PWD/jkqtplotter/graphs/jkqtpgraphlabels.h \
$$PWD/jkqtplotter/gui/jkqtpcomboboxes.h \
$$PWD/jkqtplotter/gui/jkqtpenhancedspinboxes.h \
$$PWD/jkqtplotter/gui/jkqtpenhancedtableview.h \
@@ -111,6 +112,7 @@ isEmpty(JKQTP_PLOTTER_PRI_INCLUDED) {
$$PWD/jkqtplotter/graphs/jkqtpbarchart.cpp \
$$PWD/jkqtplotter/graphs/jkqtpevaluatedparametriccurve.cpp \
$$PWD/jkqtplotter/graphs/jkqtplines.cpp \
+ $$PWD/jkqtplotter/graphs/jkqtpgraphlabels.cpp \
$$PWD/jkqtplotter/gui/jkqtpcomboboxes.cpp \
$$PWD/jkqtplotter/gui/jkqtpenhancedspinboxes.cpp \
$$PWD/jkqtplotter/gui/jkqtpenhancedtableview.cpp \
diff --git a/lib/jkqtplotter/graphs/CMakeLists.txt b/lib/jkqtplotter/graphs/CMakeLists.txt
index d44e3ba13f..f5ccdf31c1 100644
--- a/lib/jkqtplotter/graphs/CMakeLists.txt
+++ b/lib/jkqtplotter/graphs/CMakeLists.txt
@@ -31,6 +31,8 @@ target_sources(${lib_name} PRIVATE
jkqtpstatisticsadaptors.cpp
jkqtpevaluatedparametriccurve.cpp
jkqtplines.cpp
+ jkqtpgraphlabelstylemixin.cpp
+ jkqtpgraphlabels.cpp
)
# ... and add headers
target_sources(${lib_name} PUBLIC FILE_SET HEADERS TYPE HEADERS
@@ -64,4 +66,6 @@ target_sources(${lib_name} PUBLIC FILE_SET HEADERS TYPE HEADERS
jkqtpbarchart.h
jkqtpevaluatedparametriccurve.h
jkqtplines.h
-)
\ No newline at end of file
+ jkqtpgraphlabelstylemixin.h
+ jkqtpgraphlabels.h
+)
diff --git a/lib/jkqtplotter/graphs/jkqtpboxplotstylingmixins.h b/lib/jkqtplotter/graphs/jkqtpboxplotstylingmixins.h
index a2da61f95f..a786670f6c 100644
--- a/lib/jkqtplotter/graphs/jkqtpboxplotstylingmixins.h
+++ b/lib/jkqtplotter/graphs/jkqtpboxplotstylingmixins.h
@@ -34,7 +34,7 @@
/*! \brief Styling Mix-In for Boxplots
- \ingroup jkqtplotter_basegraphs_stylemixins
+ \ingroup jkqtplotter_specialgraphs_stylemixins
\image html plot_boxplothorizontalelement.png
diff --git a/lib/jkqtplotter/graphs/jkqtpgraphlabels.cpp b/lib/jkqtplotter/graphs/jkqtpgraphlabels.cpp
new file mode 100644
index 0000000000..bb26044894
--- /dev/null
+++ b/lib/jkqtplotter/graphs/jkqtpgraphlabels.cpp
@@ -0,0 +1,216 @@
+/*
+ Copyright (c) 2008-2022 Jan W. Krieger ()
+
+
+
+ This software is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License (LGPL) as published by
+ the Free Software Foundation, either version 2.1 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License (LGPL) for more details.
+
+ You should have received a copy of the GNU Lesser General Public License (LGPL)
+ along with this program. If not, see .
+*/
+
+
+
+#include "jkqtplotter/graphs/jkqtpgraphlabels.h"
+#include "jkqtplotter/jkqtpbaseplotter.h"
+#include "jkqtplotter/jkqtplotter.h"
+#include
+#include
+#include "jkqtcommon/jkqtpdrawingtools.h"
+#include "jkqtplotter/jkqtptools.h"
+
+#define SmallestGreaterZeroCompare_xvsgz() if ((xvsgz>10.0*DBL_MIN)&&((smallestGreaterZero<10.0*DBL_MIN) || (xvsgzgetPlotter())
+{
+}
+
+JKQTPXYGraphLabels::JKQTPXYGraphLabels(const LabelGenerator &lgen, JKQTBasePlotter *parent):
+ JKQTPXYGraphLabels(YValueLabel, parent)
+{
+ setCustomLabelGenerator(lgen);
+}
+
+JKQTPXYGraphLabels::JKQTPXYGraphLabels(const LabelGenerator &lgen, JKQTPlotter *parent):
+ JKQTPXYGraphLabels(lgen, parent->getPlotter())
+{
+
+}
+
+JKQTPXYGraphLabels::JKQTPXYGraphLabels(LabelContentsDefaultType lt, JKQTBasePlotter* parent):
+ JKQTPXYGraph(parent), JKQTPGraphValueLabelStyleMixin(parent)
+{
+ sortData=JKQTPXYGraph::Unsorted;
+
+ initValueLabelStyle(parent, parentPlotStyle, JKQTPPlotStyleType::Default);
+
+ switch(lt) {
+ case XValueLabel:
+ setDefaultXLabelGenerator();
+ break;
+ case YValueLabel:
+ setDefaultYLabelGenerator();
+ break;
+ case XYValueLabel:
+ setDefaultXYLabelGenerator();
+ break;
+ }
+}
+
+void JKQTPXYGraphLabels::draw(JKQTPEnhancedPainter& painter) {
+#ifdef JKQTBP_AUTOTIMER
+ JKQTPAutoOutputTimer jkaaot("JKQTPXYGraphLabels::draw");
+#endif
+ if (parent==nullptr) return;
+ const JKQTPDatastore* datastore=parent->getDatastore();
+ if (datastore==nullptr) return;
+
+ drawErrorsBefore(painter);
+ {
+ painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
+
+ int imax=0;
+ int imin=0;
+ if (getIndexRange(imin, imax)) {
+ for (int iii=imin; iiiget(static_cast(xColumn),static_cast(i));
+ const double yv=datastore->get(static_cast(yColumn),static_cast(i));
+ const double x=transformX(xv);
+ const double y=transformY(yv);
+ if (JKQTPIsOKFloat(xv) && JKQTPIsOKFloat(yv) && JKQTPIsOKFloat(x) && JKQTPIsOKFloat(y)) {
+ const QString label=generateLabel(xv,yv,iii);
+ drawLabel(painter, QPointF(x,y), QPointF(xv,yv), label, parent);
+ }
+ }
+
+ }
+ }
+ drawErrorsAfter(painter);
+}
+
+void JKQTPXYGraphLabels::drawKeyMarker(JKQTPEnhancedPainter& painter, const QRectF& rect) {
+ painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
+ painter.setFont(QFont(QGuiApplication::font().family(), getTextFontSize()));
+ painter.setPen(getTextColor());
+ painter.drawText(rect,Qt::AlignHCenter|Qt::AlignVCenter, "12");
+}
+
+QColor JKQTPXYGraphLabels::getKeyLabelColor() const {
+ return getTextColor();
+}
+
+void JKQTPXYGraphLabels::setColor(QColor c, bool setTextColor_, bool setFrameColor_)
+{
+ if (setTextColor_) setTextColor(c);
+ if (setFrameColor_) setLineColor(c);
+}
+
+void JKQTPXYGraphLabels::setCustomLabelGenerator(const LabelGenerator &labgen)
+{
+ m_labelGenerator=labgen;
+}
+
+void JKQTPXYGraphLabels::setDefaultXLabelGenerator()
+{
+ m_labelGenerator=std::bind(std::mem_fn(&JKQTPXYGraphLabels::generateDefaultXLabel), this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
+}
+
+void JKQTPXYGraphLabels::setDefaultYLabelGenerator()
+{
+ m_labelGenerator=std::bind(std::mem_fn(&JKQTPXYGraphLabels::generateDefaultYLabel), this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
+}
+
+void JKQTPXYGraphLabels::setDefaultXYLabelGenerator()
+{
+ m_labelGenerator=std::bind(std::mem_fn(&JKQTPXYGraphLabels::generateDefaultXYLabel), this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
+}
+
+
+bool JKQTPXYGraphLabels::getXMinMax(double &minx, double &maxx, double &smallestGreaterZero)
+{
+ const bool baseResult=JKQTPXYGraph::getXMinMax(minx,maxx,smallestGreaterZero);
+ if (baseResult) {
+ /*
+ // this does not work, as it depends on the widget size, when called!!!
+ qDebug()<<"JKQTPXYGraphLabels::getXMinMax():";
+ qDebug()<<" minx="<minx="<minx="<)
+
+
+
+ This software is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License (LGPL) as published by
+ the Free Software Foundation, either version 2.1 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License (LGPL) for more details.
+
+ You should have received a copy of the GNU Lesser General Public License (LGPL)
+ along with this program. If not, see .
+*/
+
+#ifndef jkqtpgraphlabels_H
+#define jkqtpgraphlabels_H
+
+
+#include
+#include
+#include
+#include
+#include "jkqtplotter/jkqtptools.h"
+#include "jkqtplotter/jkqtplotter_imexport.h"
+#include "jkqtplotter/jkqtpgraphsbase.h"
+#include "jkqtplotter/graphs/jkqtpgraphlabelstylemixin.h"
+
+// forward declarations
+class JKQTBasePlotter;
+class JKQTPlotter;
+class JKQTPCoordinateAxis;
+class JKQTPDatastore;
+
+
+
+/*! \brief This graph plots a series of data labels. This can be used to add number-labels to e.g. a barchart.
+ \ingroup jkqtplotter_graphlabels
+
+ Sometimes it is necessary to display the numeric value of a datapoint right in the plot.
+ To achieve this, JKQTPXYGraphLabels is provided, which draws a text-label next to each datapoint in a
+ series of x- and y-values (thus it is derived from JKQTPXYGraph). Each label is drawn with a little offset
+ from the actual datapoint. Under each label, a small (stylable) box is drawn, which is by default simply
+ the same color as the background color of complete plot, but with transparency, thus providing a certain
+ level of contrast to the text, even if drawn above other plot elements. Use the properties of the parent
+ mix-in class JKQTPGraphValueLabelStyleMixin to style the text and the box.
+
+ Here is an example of labels together with a bars and lines chart:
+
+ \image html JKQTPGLabelAwayFromXAxis.png
+
+ To achieve this, use code like this:
+ \code
+ // create barchart and line-chart to display the data:
+ JKQTPBarVerticalGraph* graph1=new JKQTPBarVerticalGraph(&plot);
+ graph1->setBarPositionColumn(columnX);
+ graph1->setBarHeightColumn(columnY);
+
+ JKQTPXYLineGraph* graph2=new JKQTPXYLineGraph(&plot);
+ graph2->setXColumn(columnX);
+ graph2->setYColumn(columnY);
+
+ // create the data labels:
+ JKQTPXYGraphLabels* graphLabels=new JKQTPXYGraphLabels(JKQTPXYGraphLabels::YValueLabel, &plot);
+ graphLabels->setXColumn(graph1->getXColumn());
+ graphLabels->setYColumn(graph1->getYColumn());
+ graphLabels->setLabelPosition(JKQTPGLabelAwayFromXAxis),
+
+ // add the graphs to the plot, so it is actually displayed
+ plot.addGraph(graph1);
+ plot.addGraph(graph2);
+ plot.addGraph(graphLabels);
+ \endcode
+
+ The text shown in the label is determined by a functor of type JKQTPXYGraphLabels::LabelGenerator that calculates
+ it from the labels position and data-index.
+ This functor can be custimized (set setCustomLabelGenerator() or the matching constructor), or it may be one of
+ three default immplementations, that display:
+ - the current x-value (JKQTPXYGraphLabels::XValueLabel constructor arguent or setDefaultXLabelGenerator() )
+ - the current y-value (JKQTPXYGraphLabels::YValueLabel constructor arguent or setDefaultYLabelGenerator() )
+ - the current x- and y-value (JKQTPXYGraphLabels::XYValueLabel constructor arguent or setDefaultXYLabelGenerator() )
+ .
+
+ The default generators can be further customized with a series of properties on how to format their output:
+ - setXValueLabelFormat(), setYValueLabelFormat(), setXYValueLabelFormat() ... these set the basic label and are
+ typically only \c "$%1$" or \c "$%1/%2$" , but you can set them to any string (\c %1 / \c %2 is replaced by
+ the string-converted x-/y-values) and e.g. add a prefix, like \c setXValueLabelFormat("$x=%1$").
+ You can use any LaTeX-markup that is allowed by JKQTMathText here!
+ - setXDefaultConverter(), setXDefaultPrecision(), setXBelowIsZero(), ... (all these exist in X and Y variants!)
+ .
+
+ \see \ref JKQTPlotterGraphLabels
+
+ */
+class JKQTPLOTTER_LIB_EXPORT JKQTPXYGraphLabels: public JKQTPXYGraph, public JKQTPGraphValueLabelStyleMixin, public JKQTPXYLabelsGeneratorMixin {
+ Q_OBJECT
+ public:
+ enum LabelContentsDefaultType {
+ XValueLabel, //!< \brief generates a label with the x-coordinate only, calls setDefaultXLabelGenerator()
+ YValueLabel, //!< \brief generates a label with the y-coordinate only, calls setDefaultYLabelGenerator()
+ XYValueLabel //!< \brief generates a label with the x- and y-coordinate, calls setDefaultXYLabelGenerator()
+ };
+ Q_ENUM(LabelContentsDefaultType)
+ /** \brief type of a functor that generates a label */
+ typedef std::function LabelGenerator;
+
+ /** \brief class constructor, generates a JKQTPXYGraphLabels with one of the default label generator functors (x-value, y-value or x+y-values) */
+ explicit JKQTPXYGraphLabels(LabelContentsDefaultType lt, JKQTBasePlotter* parent=nullptr);
+ /** \brief class constructor, generates a JKQTPXYGraphLabels with one of the default label generator functors (x-value, y-value or x+y-values) */
+ JKQTPXYGraphLabels(LabelContentsDefaultType lt, JKQTPlotter* parent);
+ /** \brief class constructor, generates a JKQTPXYGraphLabels with a custom LabelGenerator functor */
+ JKQTPXYGraphLabels(const LabelGenerator& lgen, JKQTBasePlotter* parent=nullptr);
+ /** \brief class constructor, generates a JKQTPXYGraphLabels with a custom LabelGenerator functor */
+ JKQTPXYGraphLabels(const LabelGenerator& lgen, JKQTPlotter* parent);
+
+ /** \brief plots the graph to the plotter object specified as parent */
+ virtual void draw(JKQTPEnhancedPainter& painter) override;
+ /** \brief plots a key marker inside the specified rectangle \a rect */
+ virtual void drawKeyMarker(JKQTPEnhancedPainter& painter, const QRectF& rect) override;
+ /** \brief returns the color to be used for the key label */
+ virtual QColor getKeyLabelColor() const override;
+ /** \copydoc JKQTPPlotElement::getXMinMax() */
+ virtual bool getXMinMax(double& minx, double& maxx, double& smallestGreaterZero) override;
+ /** \copydoc JKQTPPlotElement::getYMinMax() */
+ virtual bool getYMinMax(double& miny, double& maxy, double& smallestGreaterZero) override;
+
+
+ /** \brief set color of line and symbol */
+ void setColor(QColor c, bool setTextColor_=true, bool setFrameColor_=true);
+ /** \brief sets a custom label geneator function of type LabelGenerator to use
+ *
+ * \see m_labelGenerator, setDefaultXLabelGenerator(), setDefaultYLabelGenerator(), setDefaultXYLabelGenerator()
+ */
+ void setCustomLabelGenerator(const LabelGenerator& labgen);
+ /** \brief sets the label geneator function to a default implementation, that prints the x-value only
+ *
+ * The generator uses m_xValueLabelFormat, m_xDefaultConverter, ...
+ * \see m_labelGenerator, setCustomLabelGenerator(), setDefaultXLabelGenerator(), setDefaultYLabelGenerator(), setDefaultXYLabelGenerator()
+ */
+ void setDefaultXLabelGenerator();
+ /** \brief sets the label geneator function to a default implementation, that prints the y-value only
+ *
+ * The generator uses m_yValueLabelFormat, m_yDefaultConverter, ...
+ * \see m_labelGenerator, setCustomLabelGenerator(), setDefaultXLabelGenerator(), setDefaultYLabelGenerator(), setDefaultXYLabelGenerator()
+ */
+ void setDefaultYLabelGenerator();
+ /** \brief sets the label geneator function to a default implementation, that prints the x- and y-value
+ *
+ * The generator uses m_xyValueLabelFormat, m_xDefaultConverter, m_yDefaultConverter, ...
+ * \see m_labelGenerator, setCustomLabelGenerator(), setDefaultXLabelGenerator(), setDefaultYLabelGenerator(), setDefaultXYLabelGenerator()
+ */
+ void setDefaultXYLabelGenerator();
+ protected:
+ /** \brief generates the label at position (\a x , \a y ) and at the given data \a index */
+ QString generateLabel(double x, double y, int index) const;
+ private:
+ /** \brief generate the label for the datapoint at location (\a x , \a y ) and being the \a index -th value in the columns */
+ LabelGenerator m_labelGenerator;
+};
+
+
+
+
+#endif // jkqtpgraphlabels_H
diff --git a/lib/jkqtplotter/graphs/jkqtpgraphlabelstylemixin.cpp b/lib/jkqtplotter/graphs/jkqtpgraphlabelstylemixin.cpp
new file mode 100644
index 0000000000..40dd7f0033
--- /dev/null
+++ b/lib/jkqtplotter/graphs/jkqtpgraphlabelstylemixin.cpp
@@ -0,0 +1,524 @@
+/*
+ Copyright (c) 2008-2024 Jan W. Krieger ()
+
+
+
+ This software is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License (LGPL) as published by
+ the Free Software Foundation, either version 2.1 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License (LGPL) for more details.
+
+ You should have received a copy of the GNU Lesser General Public License (LGPL)
+ along with this program. If not, see .
+*/
+
+#include "jkqtplotter/graphs/jkqtpgraphlabelstylemixin.h"
+#include "jkqtplotter/jkqtpbaseplotter.h"
+#include
+#include
+#include
+
+
+QString JKQTPGraphLabelPosition2String(JKQTPGraphLabelPosition pos)
+{
+ switch(pos) {
+ case JKQTPGLabelAboveData: return "label_above_data";
+ case JKQTPGLabelBelowData: return "label_below_data";
+ case JKQTPGLabelLeftHandSide: return "label_left_hand_side";
+ case JKQTPGLabelRightHandSide: return "label_right_hand_side";
+ case JKQTPGLabelAwayFromXAxis: return "label_away_from_xaxis";
+ case JKQTPGLabelAwayFromYAxis: return "label_away_from_yaxis";
+ case JKQTPGLabelTowardsXAxis: return "label_towards_xaxis";
+ case JKQTPGLabelTowardsYAxis: return "label_towards_xaxis";
+ }
+ return "label_away_from_xaxis";
+}
+
+JKQTPGraphLabelPosition String2JKQTPGraphLabelPosition(const QString &pos)
+{
+ const QString m=pos.trimmed().toLower();
+ if (m=="label_above_data" || m=="above_data" || m=="above") return JKQTPGLabelAboveData;
+ if (m=="label_below_data" || m=="below_data" || m=="below") return JKQTPGLabelBelowData;
+ if (m=="label_left_hand_side" || m=="left_hand_side" || m=="left_hand" || m=="left" || m=="lhs") return JKQTPGLabelLeftHandSide;
+ if (m=="label_right_hand_side" || m=="right_hand_side" || m=="right_hand" || m=="right" || m=="rhs") return JKQTPGLabelRightHandSide;
+ if (m=="label_away_from_xaxis" || m=="away_from_xaxis") return JKQTPGLabelAwayFromXAxis;
+ if (m=="label_away_from_yaxis" || m=="away_from_yaxis") return JKQTPGLabelAwayFromYAxis;
+ if (m=="label_towars_xaxis" || m=="towars_xaxis") return JKQTPGLabelTowardsXAxis;
+ if (m=="label_towars_yaxis" || m=="towars_yaxis") return JKQTPGLabelTowardsYAxis;
+ return JKQTPGraphLabelDefault;
+}
+
+QString JKQTPGraphLabelBoxType2String(JKQTPGraphLabelBoxType pos)
+{
+ switch(pos) {
+ case JKQTPGLSimpleBox: return "simple_box";
+ case JKQTPGLSimpleBoxAndLine: return "simple_box_and_line";
+ }
+ return "simple_box";
+}
+
+JKQTPGraphLabelBoxType String2JKQTPGraphLabelBoxType(const QString &pos)
+{
+ const QString m=pos.trimmed().toLower();
+ if (m=="simple_box" || m=="simple" || m=="box") return JKQTPGLSimpleBox;
+ if (m=="simple_box_and_line" || m=="box_and_line") return JKQTPGLSimpleBoxAndLine;
+ return JKQTPGraphLabelBoxDefault;
+}
+
+
+
+JKQTPGraphValueLabelStyleMixin::JKQTPGraphValueLabelStyleMixin(JKQTBasePlotter *parent):
+ JKQTPGraphTextStyleMixin(parent), JKQTPGraphLineStyleMixin(), JKQTPGraphFillStyleMixin()
+{
+ m_labelOffset=getTextFontSize()/4.0;
+ m_labelOffsetWithConnector=getTextFontSize()*0.75;
+ m_labelBoxRounding=getTextFontSize()/3.0;
+ m_labelXPadding=getTextFontSize()/3.0;
+ m_labelYPadding=getTextFontSize()/8.0;
+ m_labelPosition=JKQTPGraphLabelDefault;
+ m_labelBoxType=JKQTPGLSimpleBox;
+ m_drawLabelBoxFrame=false;
+ setFillStyle(Qt::NoBrush);
+}
+
+void JKQTPGraphValueLabelStyleMixin::initValueLabelStyle(JKQTBasePlotter *parent, int &parentPlotStyle, JKQTPPlotStyleType styletype)
+{
+
+ setFillStyle(Qt::NoBrush);
+ if (parent) { // get style settings from parent object
+ initTextStyle(parent, parentPlotStyle,styletype);
+ initLineStyle(parent, parentPlotStyle, styletype);
+ initFillStyle(parent, parentPlotStyle, styletype);
+ setFillColor(QColorWithAlphaF(parent->getCurrentPlotterStyle().plotBackgroundBrush.color(), 0.5));
+ setFillStyle(Qt::SolidPattern);
+ setLineWidth(parent->getCurrentPlotterStyle().keyStyle.frameWidth);
+ }
+}
+
+JKQTPGraphValueLabelStyleMixin::~JKQTPGraphValueLabelStyleMixin()
+{
+
+}
+
+void JKQTPGraphValueLabelStyleMixin::setLabelOffset(double r)
+{
+ m_labelOffset=r;
+}
+
+double JKQTPGraphValueLabelStyleMixin::getLabelOffset() const
+{
+ return m_labelOffset;
+}
+
+double JKQTPGraphValueLabelStyleMixin::getUsedLabelOffset() const
+{
+ if (m_labelBoxType==JKQTPGLSimpleBox) {
+ return m_labelOffset;
+ }
+
+ return m_labelOffsetWithConnector;
+}
+
+void JKQTPGraphValueLabelStyleMixin::setLabelOffsetWithConnector(double r)
+{
+ m_labelOffsetWithConnector=r;
+}
+
+double JKQTPGraphValueLabelStyleMixin::getLabelOffsetWithConnector() const
+{
+ return m_labelOffsetWithConnector;
+}
+void JKQTPGraphValueLabelStyleMixin::setLabelBoxRounding(double r)
+{
+ m_labelBoxRounding=r;
+}
+
+double JKQTPGraphValueLabelStyleMixin::getLabelBoxRounding() const
+{
+ return m_labelBoxRounding;
+}
+
+void JKQTPGraphValueLabelStyleMixin::setLabelXPadding(double r)
+{
+ m_labelXPadding=r;
+}
+
+double JKQTPGraphValueLabelStyleMixin::getLabelXPadding() const
+{
+ return m_labelXPadding;
+}
+
+void JKQTPGraphValueLabelStyleMixin::setLabelYPadding(double r)
+{
+ m_labelYPadding=r;
+}
+
+double JKQTPGraphValueLabelStyleMixin::getLabelYPadding() const
+{
+ return m_labelYPadding;
+}
+
+void JKQTPGraphValueLabelStyleMixin::setLabelPosition(JKQTPGraphLabelPosition r)
+{
+ m_labelPosition=r;
+}
+
+JKQTPGraphLabelPosition JKQTPGraphValueLabelStyleMixin::getLabelPosition() const
+{
+ return m_labelPosition;
+}
+
+bool JKQTPGraphValueLabelStyleMixin::isLabelPositioningGrowingInX() const
+{
+ switch (m_labelPosition) {
+ case JKQTPGLabelAwayFromYAxis:
+ case JKQTPGLabelLeftHandSide:
+ case JKQTPGLabelRightHandSide:
+ return true;
+ case JKQTPGLabelAboveData:
+ case JKQTPGLabelBelowData:
+ case JKQTPGLabelAwayFromXAxis:
+ case JKQTPGLabelTowardsXAxis:
+ case JKQTPGLabelTowardsYAxis:
+ return false;
+ }
+ return false;
+}
+
+bool JKQTPGraphValueLabelStyleMixin::isLabelPositioningGrowingInY() const
+{
+ switch (m_labelPosition) {
+ case JKQTPGLabelAwayFromXAxis:
+ case JKQTPGLabelAboveData:
+ case JKQTPGLabelBelowData:
+ return true;
+ case JKQTPGLabelAwayFromYAxis:
+ case JKQTPGLabelTowardsXAxis:
+ case JKQTPGLabelTowardsYAxis:
+ case JKQTPGLabelLeftHandSide:
+ case JKQTPGLabelRightHandSide:
+ return false;
+ }
+ return false;
+}
+
+void JKQTPGraphValueLabelStyleMixin::setDrawLabelBoxFrame(bool r)
+{
+ m_drawLabelBoxFrame=r;
+}
+
+bool JKQTPGraphValueLabelStyleMixin::drawsLabelBoxFrame() const
+{
+ return m_drawLabelBoxFrame;
+}
+
+void JKQTPGraphValueLabelStyleMixin::setLabelBoxType(JKQTPGraphLabelBoxType r)
+{
+ m_labelBoxType=r;
+}
+
+JKQTPGraphLabelBoxType JKQTPGraphValueLabelStyleMixin::getLabelBoxType() const
+{
+ return m_labelBoxType;
+}
+
+void JKQTPGraphValueLabelStyleMixin::drawLabel(JKQTPEnhancedPainter &painter, const QPointF &xDataPixel, const QPointF &xData, const QString &contents, JKQTBasePlotter *parent) const
+{
+ painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
+
+ // calculate geometry
+ const LabelGeometry g=calcLabelGeometry(painter, xDataPixel, xData, contents, parent);
+
+ // draw Box
+ if (m_drawLabelBoxFrame) painter.setPen(getLinePenForRects(painter, parent));
+ else painter.setPen(Qt::NoPen);
+ painter.setBrush(getFillBrush(painter, parent));
+ if (m_labelBoxType==JKQTPGLSimpleBox || m_labelBoxType==JKQTPGLSimpleBoxAndLine) {
+ painter.drawRoundedRectOrRect(g.boxRect, m_labelBoxRounding);
+ }
+ if (m_labelBoxType==JKQTPGLSimpleBoxAndLine) {
+ //qDebug()<<"linestyle="<::min()*4),
+ m_yBelowIsZero(std::numeric_limits::min()*4),
+ m_xMinNoExponent(1e-3),
+ m_yMinNoExponent(1e-3),
+ m_xMaxNoExponent(1e4),
+ m_yMaxNoExponent(1e4),
+ m_xDateTimeFormat(QLocale().dateTimeFormat(QLocale::NarrowFormat)),
+ m_yDateTimeFormat(QLocale().dateTimeFormat(QLocale::NarrowFormat))
+{
+
+}
+
+JKQTPXYLabelsGeneratorMixin::~JKQTPXYLabelsGeneratorMixin()
+{
+
+}
+
+int JKQTPXYLabelsGeneratorMixin::getXDefaultPrecision() const
+{
+ return m_xDefaultPrecision;
+}
+
+void JKQTPXYLabelsGeneratorMixin::setXDefaultPrecision(int v)
+{
+ m_xDefaultPrecision=v;
+}
+
+int JKQTPXYLabelsGeneratorMixin::getYDefaultPrecision() const
+{
+ return m_yDefaultPrecision;
+}
+
+void JKQTPXYLabelsGeneratorMixin::setYDefaultPrecision(int v)
+{
+ m_yDefaultPrecision=v;
+}
+
+JKQTPGraphLabelConverterType JKQTPXYLabelsGeneratorMixin::getXDefaultConverter() const
+{
+ return m_xDefaultConverter;
+}
+
+void JKQTPXYLabelsGeneratorMixin::setXDefaultConverter(JKQTPGraphLabelConverterType v)
+{
+ m_xDefaultConverter=v;
+}
+
+JKQTPGraphLabelConverterType JKQTPXYLabelsGeneratorMixin::getYDefaultConverter() const
+{
+ return m_yDefaultConverter;
+}
+
+void JKQTPXYLabelsGeneratorMixin::setYDefaultConverter(JKQTPGraphLabelConverterType v)
+{
+ m_yDefaultConverter=v;
+}
+
+QString JKQTPXYLabelsGeneratorMixin::getXValueLabelFormat() const
+{
+ return m_xValueLabelFormat;
+}
+
+void JKQTPXYLabelsGeneratorMixin::setXValueLabelFormat(const QString &v)
+{
+ m_xValueLabelFormat=v;
+}
+
+QString JKQTPXYLabelsGeneratorMixin::getYValueLabelFormat() const
+{
+ return m_yValueLabelFormat;
+}
+
+void JKQTPXYLabelsGeneratorMixin::setYValueLabelFormat(const QString &v)
+{
+ m_yValueLabelFormat=v;
+}
+
+QString JKQTPXYLabelsGeneratorMixin::getXYValueLabelFormat() const
+{
+ return m_xyValueLabelFormat;
+}
+
+void JKQTPXYLabelsGeneratorMixin::setXYValueLabelFormat(const QString &v)
+{
+ m_xyValueLabelFormat=v;
+}
+
+double JKQTPXYLabelsGeneratorMixin::getXBelowIsZero() const
+{
+ return m_xBelowIsZero;
+}
+
+void JKQTPXYLabelsGeneratorMixin::setXBelowIsZero(double v)
+{
+ m_xBelowIsZero=v;
+}
+
+double JKQTPXYLabelsGeneratorMixin::getYBelowIsZero() const
+{
+ return m_yBelowIsZero;
+}
+
+void JKQTPXYLabelsGeneratorMixin::setYBelowIsZero(double v)
+{
+ m_yBelowIsZero=v;
+}
+
+double JKQTPXYLabelsGeneratorMixin::getXMinNoExponent() const
+{
+ return m_xMinNoExponent;
+}
+
+void JKQTPXYLabelsGeneratorMixin::setXMinNoExponent(double v)
+{
+ m_xMinNoExponent=v;
+}
+
+double JKQTPXYLabelsGeneratorMixin::getYMinNoExponent() const
+{
+ return m_yMinNoExponent;
+}
+
+void JKQTPXYLabelsGeneratorMixin::setYMinNoExponent(double v)
+{
+ m_yMinNoExponent=v;
+}
+
+double JKQTPXYLabelsGeneratorMixin::getXMaxNoExponent() const
+{
+ return m_xMaxNoExponent;
+}
+
+void JKQTPXYLabelsGeneratorMixin::setXMaxNoExponent(double v)
+{
+ m_xMaxNoExponent=v;
+}
+
+double JKQTPXYLabelsGeneratorMixin::getYMaxNoExponent() const
+{
+ return m_yMaxNoExponent;
+}
+
+void JKQTPXYLabelsGeneratorMixin::setYMaxNoExponent(double v)
+{
+ m_yMaxNoExponent=v;
+}
+
+QString JKQTPXYLabelsGeneratorMixin::getXDateTimeFormmat() const
+{
+ return m_xDateTimeFormat;
+}
+
+void JKQTPXYLabelsGeneratorMixin::setXDateTimeFormmat(const QString &v)
+{
+ m_xDateTimeFormat=v;
+}
+
+QString JKQTPXYLabelsGeneratorMixin::getYDateTimeFormmat() const
+{
+ return m_yDateTimeFormat;
+}
+
+void JKQTPXYLabelsGeneratorMixin::setYDateTimeFormmat(const QString &v)
+{
+ m_yDateTimeFormat=v;
+}
+
+
+QString JKQTPXYLabelsGeneratorMixin::generateDefaultXLabel(double x, double , int ) const
+{
+ return m_xValueLabelFormat.arg(xValToString(x));
+}
+
+QString JKQTPXYLabelsGeneratorMixin::generateDefaultYLabel(double , double y, int ) const
+{
+ return m_yValueLabelFormat.arg(yValToString(y));
+}
+
+QString JKQTPXYLabelsGeneratorMixin::generateDefaultXYLabel(double x, double y, int ) const
+{
+ return m_xyValueLabelFormat.arg(xValToString(x)).arg(yValToString(y));
+}
+
+QString JKQTPXYLabelsGeneratorMixin::valToString(double x, JKQTPGraphLabelConverterType converter, int precision, double belowIsZero, double minNoExponent, double maxNoExponent, const QString& dateTimeFormat)
+{
+ switch(converter) {
+ case JKQTPGLCdecimal: return jkqtp_floattoqstr(x,'f',precision,true);
+ case JKQTPGLCscientific: return jkqtp_floattoqstr(x,'e',precision,true);
+ case JKQTPGLCexponentCharacter: return jkqtp_floattolatexunitqstr(x,precision,true, belowIsZero);
+ case JKQTPGLCexponent: return jkqtp_floattolatexqstr(x,precision,true, belowIsZero,minNoExponent,maxNoExponent);
+ case JKQTPGLCdatetime: {
+ QDateTime dt;
+ dt.setMSecsSinceEpoch(uint64_t(x));
+ return dt.toString(dateTimeFormat);
+ }
+ }
+ qWarning()<<"unknown m_xDefaultConverter="<)
+
+
+
+ This software is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License (LGPL) as published by
+ the Free Software Foundation, either version 2.1 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License (LGPL) for more details.
+
+ You should have received a copy of the GNU Lesser General Public License (LGPL)
+ along with this program. If not, see .
+*/
+
+
+#ifndef jkqtpgraphlabelstylemixin_H
+#define jkqtpgraphlabelstylemixin_H
+
+
+#include
+#include
+#include
+#include
+#include "jkqtplotter/jkqtptools.h"
+#include "jkqtplotter/jkqtplotter_imexport.h"
+#include "jkqtplotter/jkqtpbaseplotter.h"
+#include "jkqtcommon/jkqtpdrawingtools.h"
+#include "jkqtplotter/jkqtplotter_configmacros.h"
+#include "jkqtplotter/jkqtpgraphsbasestylingmixins.h"
+
+
+class JKQTPlotter; // forward
+
+
+
+/** \brief position of a label near a data-point, used by JKQTPGraphValueLabelStyleMixin
+ * \ingroup jkqtplotter_specialgraphs_stylemixins
+ *
+ * \see JKQTPGraphValueLabelStyleMixin
+ */
+enum JKQTPGraphLabelPosition {
+ JKQTPGLabelAboveData=0, /*!< \brief all labels always above the datapoint \image html JKQTPGLabelAboveData.png */
+ JKQTPGLabelBelowData, /*!< \brief all labels always below the datapoint \image html JKQTPGLabelBelowData.png */
+ JKQTPGLabelTowardsXAxis, /*!< \brief all labels between the datapoint and the x-axis the datapoint \image html JKQTPGLabelTowardsXAxis.png */
+ JKQTPGLabelAwayFromXAxis, /*!< \brief all labels pointing away from the x-axis \image html JKQTPGLabelAwayFromXAxis.png */
+ JKQTPGLabelRightHandSide, /*!< \brief all labels always on the right-hand side of the datapoint \image html JKQTPGLabelRightHandSide.png */
+ JKQTPGLabelLeftHandSide, /*!< \brief all labels always on the left-hand side of the datapoint \image html JKQTPGLabelLeftHandSide.png */
+ JKQTPGLabelTowardsYAxis, /*!< \brief all labels between the datapoint and the y-axis the datapoint \image html JKQTPGLabelTowardsYAxis.png */
+ JKQTPGLabelAwayFromYAxis, /*!< \brief all labels pointing away from the y-axis \image html JKQTPGLabelAwayFromYAxis.png */
+
+ JKQTPGraphLabelDefault=JKQTPGLabelAwayFromXAxis,
+};
+
+
+/** \brief converts a JKQTPGraphLabelPosition variable into a human-readable string
+ * \ingroup jkqtplotter_specialgraphs_stylemixins
+ */
+JKQTPLOTTER_LIB_EXPORT QString JKQTPGraphLabelPosition2String(JKQTPGraphLabelPosition pos);
+
+/** \brief converts a String into a JKQTPGraphLabelPosition
+ * \ingroup jkqtplotter_specialgraphs_stylemixins
+ */
+JKQTPLOTTER_LIB_EXPORT JKQTPGraphLabelPosition String2JKQTPGraphLabelPosition(const QString& pos);
+
+/** \brief type of box surrounding a label near a data-point, used by JKQTPGraphValueLabelStyleMixin
+ * \ingroup jkqtplotter_specialgraphs_stylemixins
+ *
+ * \see JKQTPGraphValueLabelStyleMixin
+ */
+enum JKQTPGraphLabelBoxType {
+ JKQTPGLSimpleBox=0, /*!< \brief a simple (possibly rounded and outlined) box \image html JKQTPGLSimpleBox.png */
+ JKQTPGLSimpleBoxAndLine=1, /*!< \brief a simple (possibly rounded and outlined) box, connected to the datapoint by a line \image html JKQTPGLSimpleBoxAndLine.png */
+
+ JKQTPGraphLabelBoxDefault=JKQTPGLSimpleBox,
+};
+
+
+/** \brief converts a JKQTPGraphLabelBoxType variable into a human-readable string
+ * \ingroup jkqtplotter_specialgraphs_stylemixins
+ */
+JKQTPLOTTER_LIB_EXPORT QString JKQTPGraphLabelBoxType2String(JKQTPGraphLabelBoxType pos);
+
+/** \brief converts a String into a JKQTPGraphLabelBoxType
+ * \ingroup jkqtplotter_specialgraphs_stylemixins
+ */
+JKQTPLOTTER_LIB_EXPORT JKQTPGraphLabelBoxType String2JKQTPGraphLabelBoxType(const QString& pos);
+
+
+
+
+/*! \brief This Mix-In class provides setter/getter methods, storage and other facilities for value labels in graphs
+ \ingroup jkqtplotter_specialgraphs_stylemixins
+
+ in addition to all properties of JKQTPGraphTextStyleMixin for the actual label text,
+ JKQTPGraphLineStyleMixin & JKQTPGraphFillStyleMixin for a box around the label,
+ it also supports properties for positioning and further sryling the labels.
+
+ supported properties:
+ - padding from actual label to border
+ - distance of label to actual datapoint
+ - positioning of the label
+ - styling for the box around the label
+ .
+
+ \image html jkqtpxygraphlabels.png
+
+ \see JKQTPGraphTextStyleMixin, JKQTPGraphLineStyleMixin, JKQTPGraphFillStyleMixin, JKQTPXYGraphLabels
+ */
+class JKQTPLOTTER_LIB_EXPORT JKQTPGraphValueLabelStyleMixin: public JKQTPGraphTextStyleMixin, public JKQTPGraphLineStyleMixin, public JKQTPGraphFillStyleMixin {
+#ifndef JKQTPLOTTER_WORKAROUND_QGADGET_BUG
+ Q_GADGET
+#endif
+public:
+
+
+ /** \brief class constructor */
+ JKQTPGraphValueLabelStyleMixin(JKQTBasePlotter *parent);
+
+ /** \brief initiaize the fill style (from the parent plotter) */
+ void initValueLabelStyle(JKQTBasePlotter* parent, int &parentPlotStyle, JKQTPPlotStyleType styletype=JKQTPPlotStyleType::Default);
+
+ virtual ~JKQTPGraphValueLabelStyleMixin();
+
+ /** \copydoc m_labelOffset */
+ void setLabelOffset(double r);
+ /** \copydoc m_labelOffset */
+ double getLabelOffset() const;
+ /** \brief determines, whether to use getLabelOffset() or getLabelOffsetWithConnector() (or something else) and returns it */
+ double getUsedLabelOffset() const;
+
+ /** \copydoc m_labelOffsetWithConnector */
+ void setLabelOffsetWithConnector(double r);
+ /** \copydoc m_labelOffsetWithConnector */
+ double getLabelOffsetWithConnector() const;
+
+ /** \copydoc m_labelBoxRounding */
+ void setLabelBoxRounding(double r);
+ /** \copydoc m_labelBoxRounding */
+ double getLabelBoxRounding() const;
+
+ /** \copydoc m_labelXPadding */
+ void setLabelXPadding(double r);
+ /** \copydoc m_labelXPadding */
+ double getLabelXPadding() const;
+
+
+ /** \copydoc m_labelYPadding */
+ void setLabelYPadding(double r);
+ /** \copydoc m_labelYPadding */
+ double getLabelYPadding() const;
+
+ /** \copydoc m_labelPosition */
+ void setLabelPosition(JKQTPGraphLabelPosition r);
+ /** \copydoc m_labelPosition */
+ JKQTPGraphLabelPosition getLabelPosition() const;
+ /** \brief determines whether a label is positioned left of the mininmum, or right of the maxinmum datapoint (\c true ) */
+ bool isLabelPositioningGrowingInX() const;
+ /** \brief determines whether a label is positioned below the mininmum, or above the maxinmum datapoint (\c true ) */
+ bool isLabelPositioningGrowingInY() const;
+
+ /** \copydoc m_drawLabelBoxFrame */
+ void setDrawLabelBoxFrame(bool r);
+ /** \copydoc m_drawLabelBoxFrame */
+ bool drawsLabelBoxFrame() const;
+
+ /** \copydoc m_labelBoxType */
+ void setLabelBoxType(JKQTPGraphLabelBoxType r);
+ /** \copydoc m_labelBoxType */
+ JKQTPGraphLabelBoxType getLabelBoxType() const;
+
+ /** \brief draws a label, including its box
+ *
+ * \brief painter the JKQTPEnhancedPainter to use for drawing
+ * \brief xDataPixel position of the labeled datapoint in (screen) pixels
+ * \brief xData x- and y-coordinate of the datapoint (needed for some JKQTPGraphLabelPosition)
+ * \brief contents the text to be rendered
+ * \brief parent the JKQTPBasePlotter in whos context we are drawing (e.g. needed to render \a contents )
+ *
+ */
+ void drawLabel(JKQTPEnhancedPainter& painter, const QPointF& xDataPixel, const QPointF& xData, const QString& contents, JKQTBasePlotter *parent) const;
+
+
+
+#ifndef JKQTPLOTTER_WORKAROUND_QGADGET_BUG
+ Q_PROPERTY(double labelOffset MEMBER m_labelOffset READ getLabelOffset WRITE setLabelOffset)
+ Q_PROPERTY(double labelOffsetWithConnector MEMBER m_labelOffsetWithConnector READ getLabelOffsetWithConnector WRITE setLabelOffsetWithConnector)
+ Q_PROPERTY(double labelBoxRounding MEMBER m_labelBoxRounding READ getLabelBoxRounding WRITE setLabelBoxRounding)
+ Q_PROPERTY(double labelXPadding MEMBER m_labelXPadding READ getLabelXPadding WRITE setLabelXPadding)
+ Q_PROPERTY(double labelYPadding MEMBER m_labelYPadding READ getLabelYPadding WRITE setLabelYPadding)
+ Q_PROPERTY(JKQTPGraphLabelPosition labelPosition MEMBER m_labelPosition READ getLabelPosition WRITE setLabelPosition)
+ Q_PROPERTY(bool drawLabelBoxFrame MEMBER m_drawLabelBoxFrame READ drawsLabelBoxFrame WRITE setDrawLabelBoxFrame)
+ Q_PROPERTY(JKQTPGraphLabelBoxType labelBoxType MEMBER m_labelBoxType READ getLabelBoxType WRITE setLabelBoxType)
+#endif
+
+protected:
+ /** \brief describes details about the geometry of a label, used by calcLabelGeometry() */
+ struct LabelGeometry {
+ inline LabelGeometry():
+ labelOffsetPx(0.0),
+ padX(0.0),
+ padY(0.0),
+ lw(0.0),
+ label(""),
+ textSize(),
+ textRect(),
+ boxRect(),
+ boxpos(BoxTop)
+ { };
+ double labelOffsetPx;
+ double padX;
+ double padY;
+ double lw;
+ QString label;
+ JKQTMathTextNodeSize textSize;
+ QRectF textRect;
+ QRectF boxRect;
+ enum BoxPos {
+ BoxLeft,
+ BoxRight,
+ BoxTop,
+ BoxBottom
+ };
+ BoxPos boxpos;
+ };
+
+ /** \brief calculate everything that is necessary to draw a label, including its box
+ *
+ * \brief painter the JKQTPEnhancedPainter to use for drawing
+ * \brief xDataPixel position of the labeled datapoint in (screen) pixels
+ * \brief xData x- and y-coordinate of the datapoint (needed for some JKQTPGraphLabelPosition)
+ * \brief contents the text to be rendered
+ * \brief parent the JKQTPBasePlotter in whos context we are drawing (e.g. needed to render \a contents )
+ *
+ */
+ LabelGeometry calcLabelGeometry(JKQTPEnhancedPainter& painter, const QPointF& xDataPixel, const QPointF& xData, const QString& contents, JKQTBasePlotter *parent) const;
+
+private:
+ /** \brief offset of the box rectangle to the actual data point location [pt], this is used for simple boxes and is a rather close distance (e.g. JKQTPGLSimpleBox)
+ *
+ * \see setLabelOffset(), getLabelOffset(), setLabelOffsetWithConnector(), getLabelOffsetWithConnector()
+ */
+ double m_labelOffset;
+ /** \brief offset of the box rectangle to the actual data point location [pt], this variant is used when a visible connector is shown (e.g. JKQTPGLSimpleBoxAndLine)
+ *
+ * \see setLabelOffsetWithConnector(), getLabelOffsetWithConnector(), setLabelOffset(), getLabelOffset()
+ */
+ double m_labelOffsetWithConnector;
+ /** \brief rounding radius of the box rectangle (<=0 -> no rounded rectangle) [pt] */
+ double m_labelBoxRounding;
+ /** \brief padding in x-direction between label and surrounding box [pt] */
+ double m_labelXPadding;
+ /** \brief padding in y-direction between label and surrounding box [pt] */
+ double m_labelYPadding;
+ /** \brief indicates whether to draw a frame around the box */
+ bool m_drawLabelBoxFrame;
+ /** \brief position of the label
+ *
+ * \see JKQTPGraphLabelPosition for details on available options
+ */
+ JKQTPGraphLabelPosition m_labelPosition;
+ /** \brief type or style of the box surrounding the label text
+ *
+ * \see JKQTPGraphLabelBoxType for details on available options
+ */
+ JKQTPGraphLabelBoxType m_labelBoxType;
+};
+
+
+
+
+/** \brief display mode for the (axis) labels
+ * \ingroup jkqtplotter_specialgraphs_stylemixins */
+enum JKQTPGraphLabelConverterType {
+ JKQTPGLCdecimal, /*!< \brief print the numbers in decimal notation, without using exponent characters e.g. \c "0.00123" */
+ JKQTPGLCscientific, /*!< \brief print the numbers in scientific notation, e.g. \c "1.23e-4" */
+ JKQTPGLCexponentCharacter, /*!< \brief print the numbers and show a unit character, i.e. 5μ for \f$ 5\cdot 10^{-6} \f$ , \c 3k for \f$ 3\cdot 10^3 \f$ ... */
+ JKQTPGLCexponent, /*!< \brief show numbers in exponential for, e.g. \f$ 3\cdot 10^5 \f$ ... */
+ JKQTPGLCdatetime, /*!< \brief show numbers as times */
+
+ JKQTPGLDefaultConverter=JKQTPGLCexponent,
+ };
+
+
+/*! \brief This Mix-In class provides setter/getter methods, and tools for x- and y-value label formatting (i.e. double to string conversion)
+ \ingroup jkqtplotter_specialgraphs_stylemixins
+
+ \see JKQTPXYGraphLabels
+ */
+class JKQTPLOTTER_LIB_EXPORT JKQTPXYLabelsGeneratorMixin {
+#ifndef JKQTPLOTTER_WORKAROUND_QGADGET_BUG
+ Q_GADGET
+#endif
+public:
+
+ /** \brief class constructor */
+ explicit JKQTPXYLabelsGeneratorMixin();
+
+ virtual ~JKQTPXYLabelsGeneratorMixin();
+
+
+
+ /** \copydoc m_xDefaultPrecision */
+ int getXDefaultPrecision() const;
+ /** \copydoc m_xDefaultPrecision */
+ void setXDefaultPrecision(int v);
+ /** \copydoc m_yDefaultPrecision */
+ int getYDefaultPrecision() const;
+ /** \copydoc m_yDefaultPrecision */
+ void setYDefaultPrecision(int v);
+
+ /** \copydoc m_xDefaultConverter */
+ JKQTPGraphLabelConverterType getXDefaultConverter() const;
+ /** \copydoc m_xDefaultConverter */
+ void setXDefaultConverter(JKQTPGraphLabelConverterType v);
+ /** \copydoc m_yDefaultConverter */
+ JKQTPGraphLabelConverterType getYDefaultConverter() const;
+ /** \copydoc m_yDefaultConverter */
+ void setYDefaultConverter(JKQTPGraphLabelConverterType v);
+
+
+ /** \copydoc m_xValueLabelFormat */
+ QString getXValueLabelFormat() const;
+ /** \copydoc m_xValueLabelFormat */
+ void setXValueLabelFormat(const QString& v);
+ /** \copydoc m_yValueLabelFormat */
+ QString getYValueLabelFormat() const;
+ /** \copydoc m_yValueLabelFormat */
+ void setYValueLabelFormat(const QString& v);
+ /** \copydoc m_xyValueLabelFormat */
+ QString getXYValueLabelFormat() const;
+ /** \copydoc m_xyValueLabelFormat */
+ void setXYValueLabelFormat(const QString& v);
+
+
+ /** \copydoc m_xBelowIsZero */
+ double getXBelowIsZero() const;
+ /** \copydoc m_xBelowIsZero */
+ void setXBelowIsZero(double v);
+ /** \copydoc m_yBelowIsZero */
+ double getYBelowIsZero() const;
+ /** \copydoc m_yBelowIsZero */
+ void setYBelowIsZero(double v);
+
+
+ /** \copydoc m_xMinNoExponent */
+ double getXMinNoExponent() const;
+ /** \copydoc m_xMinNoExponent */
+ void setXMinNoExponent(double v);
+ /** \copydoc m_yMinNoExponent */
+ double getYMinNoExponent() const;
+ /** \copydoc m_yMinNoExponent */
+ void setYMinNoExponent(double v);
+
+
+ /** \copydoc m_xMaxNoExponent */
+ double getXMaxNoExponent() const;
+ /** \copydoc m_xMaxNoExponent */
+ void setXMaxNoExponent(double v);
+ /** \copydoc m_yMaxNoExponent */
+ double getYMaxNoExponent() const;
+ /** \copydoc m_yMaxNoExponent */
+ void setYMaxNoExponent(double v);
+
+
+
+ /** \copydoc m_xDateTimeFormmat */
+ QString getXDateTimeFormmat() const;
+ /** \copydoc m_xDateTimeFormmat */
+ void setXDateTimeFormmat(const QString& v);
+ /** \copydoc m_yDateTimeFormmat */
+ QString getYDateTimeFormmat() const;
+ /** \copydoc m_yDateTimeFormmat */
+ void setYDateTimeFormmat(const QString& v);
+
+
+protected:
+ /** \brief default label generator for x-value only */
+ QString generateDefaultXLabel(double x, double y, int index) const;
+ /** \brief default label generator for y-value only */
+ QString generateDefaultYLabel(double x, double y, int index) const;
+ /** \brief default label generator for x- and y-value */
+ QString generateDefaultXYLabel(double x, double y, int index) const;
+ /** \brief converts \a x to a string, using several of the formatting properties set in this class for x-values */
+ QString xValToString(double x) const;
+ /** \brief converts \a y to a string, using several of the formatting properties set in this class for y-values */
+ QString yValToString(double y) const;
+ /** \rief converts \a x to a QString, using the provided options */
+ static QString valToString(double x, JKQTPGraphLabelConverterType m_xDefaultConverter, int m_xDefaultPrecision, double m_xBelowIsZero, double m_xMinNoExponent, double m_xMaxNoExponent, const QString& m_xDateTimeFormat);
+private:
+ /** \brief format string for the x-label, use \c %1 as placeholder for the numeric value */
+ QString m_xValueLabelFormat;
+ /** \brief format string for the y-label, use \c %1 as placeholder for the numeric value */
+ QString m_yValueLabelFormat;
+ /** \brief format string for the x/y-label, use \c %1 as placeholder for the numeric value of x and \c %2 for y */
+ QString m_xyValueLabelFormat;
+ /** \brief type of number to string conversion for x-values */
+ JKQTPGraphLabelConverterType m_xDefaultConverter;
+ /** \brief type of number to string conversion for y-values */
+ JKQTPGraphLabelConverterType m_yDefaultConverter;
+ /** \brief default precision for x-labels */
+ int m_xDefaultPrecision;
+ /** \brief default precision for x-labels */
+ int m_yDefaultPrecision;
+ /** \brief x-values below this value are treated as exactly 0 */
+ double m_xBelowIsZero;
+ /** \brief y-values below this value are treated as exactly 0 */
+ double m_yBelowIsZero;
+ /** \brief x-values below this value will be shown in exponent notation, above in decimal notation */
+ double m_xMinNoExponent;
+ /** \brief y-values below this value will be shown in exponent notation, above in decimal notation */
+ double m_yMinNoExponent;
+ /** \brief x-values above this value will be shown in exponent notation, below in decimal notation */
+ double m_xMaxNoExponent;
+ /** \brief y-values above this value will be shown in exponent notation, below in decimal notation */
+ double m_yMaxNoExponent;
+ /** \brief format string for datetime -> string conversion of x-values */
+ QString m_xDateTimeFormat;
+ /** \brief format string for datetime -> string conversion of y-value */
+ QString m_yDateTimeFormat;
+};
+
+
+
+#endif // jkqtpgraphlabelstylemixin_H
diff --git a/lib/jkqtplotter/graphs/jkqtpviolinplotstylingmixins.h b/lib/jkqtplotter/graphs/jkqtpviolinplotstylingmixins.h
index 92e7e8fc02..9c63fae323 100644
--- a/lib/jkqtplotter/graphs/jkqtpviolinplotstylingmixins.h
+++ b/lib/jkqtplotter/graphs/jkqtpviolinplotstylingmixins.h
@@ -34,7 +34,7 @@
/*! \brief Styling Mix-In for Violinplots
- \ingroup jkqtplotter_basegraphs_stylemixins
+ \ingroup jkqtplotter_specialgraphs_stylemixins
\image html JKQTPViolinplotHorizontalElement_elements.png
diff --git a/lib/jkqtplotter/jkqtpgraphsbasestylingmixins.cpp b/lib/jkqtplotter/jkqtpgraphsbasestylingmixins.cpp
index 34d108566f..e10f1a4278 100644
--- a/lib/jkqtplotter/jkqtpgraphsbasestylingmixins.cpp
+++ b/lib/jkqtplotter/jkqtpgraphsbasestylingmixins.cpp
@@ -36,13 +36,22 @@ JKQTPGraphLineStyleMixin::JKQTPGraphLineStyleMixin()
void JKQTPGraphLineStyleMixin::initLineStyle(JKQTBasePlotter* parent, int &parentPlotStyle, JKQTPPlotStyleType styletype)
{
if (parent) { // get style settings from parent object
- if (parentPlotStyle<0) parentPlotStyle=parent->getNextStyle();
- const JKQTBasePlotter::JKQTPPen pen=parent->getPlotStyle(parentPlotStyle, styletype);
- m_linePen.setColor(pen.color());
- m_linePen.setStyle(pen.style());
- m_lineWidth=pen.widthF();
- m_highlightingLineColor=getLineColor();
- m_highlightingLineColor.setAlphaF(0.5);
+ if (styletype==JKQTPPlotStyleType::Annotation) {
+ m_linePen=QPen(parent->getCurrentPlotterStyle().graphsStyle.annotationStyle.defaultLineStyle);
+ m_linePen.setColor(parent->getCurrentPlotterStyle().graphsStyle.annotationStyle.defaultColor);
+ m_linePen.setWidthF(parent->getCurrentPlotterStyle().graphsStyle.annotationStyle.defaultLineWidth);
+ m_lineWidth=m_linePen.widthF();
+ m_highlightingLineColor=getLineColor();
+ m_highlightingLineColor.setAlphaF(0.5);
+ } else {
+ if (parentPlotStyle<0) parentPlotStyle=parent->getNextStyle();
+ const JKQTBasePlotter::JKQTPPen pen=parent->getPlotStyle(parentPlotStyle, styletype);
+ m_linePen.setColor(pen.color());
+ m_linePen.setStyle(pen.style());
+ m_lineWidth=pen.widthF();
+ m_highlightingLineColor=getLineColor();
+ m_highlightingLineColor.setAlphaF(0.5);
+ }
}
}
@@ -219,14 +228,22 @@ JKQTPGraphSymbolStyleMixin::JKQTPGraphSymbolStyleMixin()
void JKQTPGraphSymbolStyleMixin::initSymbolStyle(JKQTBasePlotter *parent, int& parentPlotStyle, JKQTPPlotStyleType styletype)
{
if (parent) { // get style settings from parent object
- if (parentPlotStyle<0) parentPlotStyle=parent->getNextStyle();
- const JKQTBasePlotter::JKQTPPen pen=parent->getPlotStyle(parentPlotStyle, styletype);
- m_symbolColor=pen.color();
- m_symbolSize=pen.symbolSize();
- m_symbolLineWidth=pen.symbolLineWidthF();
- m_symbolType=pen.symbol();
- m_symbolFillColor=pen.symbolFillColor();
- m_symbolFontName=parent->getDefaultTextFontName();
+ if (styletype==JKQTPPlotStyleType::Annotation) {
+ m_symbolType=parent->getCurrentPlotterStyle().graphsStyle.annotationStyle.defaultSymbol;
+ m_symbolColor=parent->getCurrentPlotterStyle().graphsStyle.annotationStyle.defaultColor;
+ m_symbolLineWidth=parent->getCurrentPlotterStyle().graphsStyle.annotationStyle.defaultSymbolLineWidth;
+ m_symbolSize=parent->getCurrentPlotterStyle().graphsStyle.annotationStyle.defaultSymbolSize;
+ m_symbolFillColor=JKQTPGetDerivedColor(parent->getCurrentPlotterStyle().graphsStyle.annotationStyle.symbolFillColorDerivationMode, m_symbolColor);
+ } else {
+ if (parentPlotStyle<0) parentPlotStyle=parent->getNextStyle();
+ const JKQTBasePlotter::JKQTPPen pen=parent->getPlotStyle(parentPlotStyle, styletype);
+ m_symbolColor=pen.color();
+ m_symbolSize=pen.symbolSize();
+ m_symbolLineWidth=pen.symbolLineWidthF();
+ m_symbolType=pen.symbol();
+ m_symbolFillColor=pen.symbolFillColor();
+ m_symbolFontName=parent->getDefaultTextFontName();
+ }
}
}
@@ -395,10 +412,15 @@ void JKQTPGraphFillStyleMixin::initFillStyleInvertedColor(JKQTPGraphFillStyleMix
void JKQTPGraphFillStyleMixin::initFillStyle(JKQTBasePlotter *parent, int &parentPlotStyle, JKQTPPlotStyleType styletype)
{
if (parent) { // get style settings from parent object
- if (parentPlotStyle<0) parentPlotStyle=parent->getNextStyle();
- const JKQTBasePlotter::JKQTPPen pen=parent->getPlotStyle(parentPlotStyle, styletype);
- m_fillColor=pen.fillColor();
- m_fillBrush=pen.fillStyle().brush(m_fillColor);
+ if (styletype==JKQTPPlotStyleType::Annotation) {
+ m_fillColor=JKQTPGetDerivedColor(parent->getCurrentPlotterStyle().graphsStyle.annotationStyle.fillColorDerivationMode, parent->getCurrentPlotterStyle().graphsStyle.annotationStyle.defaultColor);
+ m_fillBrush=parent->getCurrentPlotterStyle().graphsStyle.annotationStyle.defaultFillStyle.brush(m_fillColor);
+ } else {
+ if (parentPlotStyle<0) parentPlotStyle=parent->getNextStyle();
+ const JKQTBasePlotter::JKQTPPen pen=parent->getPlotStyle(parentPlotStyle, styletype);
+ m_fillColor=pen.fillColor();
+ m_fillBrush=pen.fillStyle().brush(m_fillColor);
+ }
}
}
@@ -537,10 +559,14 @@ JKQTPGraphTextStyleMixin::JKQTPGraphTextStyleMixin(JKQTBasePlotter *parent)
void JKQTPGraphTextStyleMixin::initTextStyle(JKQTBasePlotter *parent, int &/*parentPlotStyle*/, JKQTPPlotStyleType styletype)
{
- if (parent && styletype==JKQTPPlotStyleType::Annotation) { // get style settings from parent object
- m_textFontSize=parent->getCurrentPlotterStyle().graphsStyle.annotationStyle.defaultFontSize;
+ if (parent) { // get style settings from parent object
m_textColor=parent->getCurrentPlotterStyle().graphsStyle.annotationStyle.defaultTextColor;
m_textFontName=parent->getCurrentPlotterStyle().graphsStyle.annotationStyle.defaultFontName;
+ if (styletype==JKQTPPlotStyleType::Annotation) {
+ m_textFontSize=parent->getCurrentPlotterStyle().graphsStyle.annotationStyle.defaultFontSize;
+ } else {
+ m_textFontSize=QApplication::font().pointSizeF();
+ }
}
}
diff --git a/screenshots/graphlabels.png b/screenshots/graphlabels.png
new file mode 100644
index 0000000000..56d6aede44
Binary files /dev/null and b/screenshots/graphlabels.png differ
diff --git a/screenshots/graphlabels_hor.png b/screenshots/graphlabels_hor.png
new file mode 100644
index 0000000000..1726619ca7
Binary files /dev/null and b/screenshots/graphlabels_hor.png differ
diff --git a/screenshots/graphlabels_hor_small.png b/screenshots/graphlabels_hor_small.png
new file mode 100644
index 0000000000..ae0d20150f
Binary files /dev/null and b/screenshots/graphlabels_hor_small.png differ
diff --git a/screenshots/graphlabels_small.png b/screenshots/graphlabels_small.png
new file mode 100644
index 0000000000..5a7f16caa0
Binary files /dev/null and b/screenshots/graphlabels_small.png differ