diff --git a/JKQtPlotterBuildAllExamples.pro b/JKQtPlotterBuildAllExamples.pro index 9a120f9125..e19977d62a 100644 --- a/JKQtPlotterBuildAllExamples.pro +++ b/JKQtPlotterBuildAllExamples.pro @@ -98,5 +98,6 @@ defineTest(addTest) { addTest(multiplot) addTest(user_interaction) addTest(styling) -#addTest(distributionplot) +addTest(styledboxplot) +addTest(distributionplot) diff --git a/doc/dox/examples_and_tutorials.dox b/doc/dox/examples_and_tutorials.dox index 6b33131543..914e18011f 100644 --- a/doc/dox/examples_and_tutorials.dox +++ b/doc/dox/examples_and_tutorials.dox @@ -78,6 +78,12 @@ All test-projects are Qt-projects that use qmake to build. You can load them int \image html jkqtplotter_simpletest_advancedlineandfillstyling_small.png \subpage JKQTPlotterAdvancedLineAndFillStyling `JKQTPXYLineGraph`, `JKQTPSpecialLineHorizontalGraph` and `JKQTPBarVerticalGraph`
C++ vector of data
advanced line styling and filling + \image html test_styledboxplot_small.png + \subpage JKQTPlotterBoxplotStyling + Modifying different Aspects of the Styling of boxplots + \image html test_styling_small.png + \subpage JKQTPlotterStyling + Modifying different Aspects of the Styling of JKQTPlotter diff --git a/doc/dox/jkqtplotter.dox b/doc/dox/jkqtplotter.dox index fc099f97ea..2208b73bdf 100644 --- a/doc/dox/jkqtplotter.dox +++ b/doc/dox/jkqtplotter.dox @@ -8,7 +8,7 @@ C++ standard library. \defgroup jkqtpplotterclasses_tools Support Classes/Structs/Functions for JKQTPlotter&JKQTBasePlotter \ingroup jkqtptools -\defgroup tools_math Tools for Mathematical Computations & Equation Parsing +\defgroup jkqtptools_math Tools for Mathematical Computations & Equation Parsing \ingroup jkqtptools \defgroup jkqtptools_string String Tool Functions @@ -20,7 +20,7 @@ C++ standard library. \defgroup jkqtptools_qtwidgets Additional Widgets for Qt \ingroup jkqtptools -\defgroup jkqtptools_drawing Drawing Tools +\defgroup jkqtptools_drawing Drawing & Graphics Tools \ingroup jkqtptools \defgroup jkqtptools_debugging Debugging Tools diff --git a/doc/dox/whatsnew.dox b/doc/dox/whatsnew.dox index 7f2538c2cc..716266543f 100644 --- a/doc/dox/whatsnew.dox +++ b/doc/dox/whatsnew.dox @@ -41,6 +41,8 @@ Changes, compared to \ref WHATSNEW_V2018_08 "v2018.08" include:
  • new: JKQTPXYParametrizedScatterGraph: added functors to transform column values into symbol type+size and line-width to give even more control
  • new: user-interaction tool that shows coordinates of data points near the current mouse position (when mouse is dragged, while mouse button is pressed) \see jkqtpmdaToolTipForClosestDataPoint
  • new: user-interaction tool that measures distances and angles when mouse is dragged, while mouse button is pressed) \see jkqtpmdaRuler
  • +
  • new: advanced styling options for boxplots + example for the styling: \ref JKQTPlotterBoxplotStyling
  • +
  • new: notched boxplots
  • changed: removed old selection-code and replaced by general highlighting feature
  • changed: JKQTPStepHorizontalGraph has been renamed to JKQTPSpecialLineHorizontalGraph (vertical variants also) and have gained additional features (baseline for filling and drawing of symbols)
  • changed: filled curve graphs (e.g. JKQTPSpecialLineHorizontalGraph) are now merely a specializedly initialized JKQTPSpecialLineHorizontalGraph
  • diff --git a/doc/images/boxplots.png b/doc/images/boxplots.png index f30d446720..6a1b1bf5dd 100644 Binary files a/doc/images/boxplots.png and b/doc/images/boxplots.png differ diff --git a/doc/images/plot_boxplothorizontalelement.png b/doc/images/plot_boxplothorizontalelement.png new file mode 100644 index 0000000000..6a1b1bf5dd Binary files /dev/null and b/doc/images/plot_boxplothorizontalelement.png differ diff --git a/doc/images/plot_boxplotverticalelement.png b/doc/images/plot_boxplotverticalelement.png new file mode 100644 index 0000000000..8b5aa19d74 Binary files /dev/null and b/doc/images/plot_boxplotverticalelement.png differ diff --git a/examples/README.md b/examples/README.md index cd226e6c44..4b06f5f6e6 100644 --- a/examples/README.md +++ b/examples/README.md @@ -31,7 +31,9 @@ All test-projects are Qt-projects that use qmake to build. You can load them int |:-------------:| ------------- | ------------- | | [![](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/jkqtplotter_simpletest_logaxes_small.png)](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/simpletest_logaxes) | [logarithmic axes](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/simpletest_logaxes) | `JKQTPXYLineGraph` and `JKQTPGeoText`
    C++ vector of data
    logarithmic axes and styling
    plot line styles
    internal LaTeX parser
    add commenting text to a graph | | [![](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/jkqtplotter_simpletest_dateaxes_small.png)
    ![](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/jkqtplotter_simpletest_dateaxes_dates_small.png)
    ![](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/jkqtplotter_simpletest_dateaxes_timeaxis_small.png)](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/simpletest_dateaxes) | [date/time axes](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/simpletest_dateaxes) | `JKQTPXYLineGraph` and `JKQTPFilledVerticalRangeGraph`
    C++ vector of data
    date/time axes
    plot min/max range graph
    internal LaTeX parser
    data from CSV files | -| [![](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/jkqtplotter_simpletest_advancedlineandfillstyling_small.png)](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/simpletest_advancedlineandfillstyling) | [logarithmic axes](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/simpletest_advancedlineandfillstyling) | `JKQTPXYLineGraph`, `JKQTPSpecialLineHorizontalGraph` and `JKQTPBarVerticalGraph`
    C++ vector of data
    advanced line styling and filling | +| [![](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/jkqtplotter_simpletest_advancedlineandfillstyling_small.png)](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/simpletest_advancedlineandfillstyling) | [advanced line and fill styling](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/simpletest_advancedlineandfillstyling) | `JKQTPXYLineGraph`, `JKQTPSpecialLineHorizontalGraph` and `JKQTPBarVerticalGraph`
    C++ vector of data
    advanced line styling and filling | +| [![](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/test_styledboxplot_small.png)](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/test_styledboxplot) | [Styling of Boxplots](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/test_styledboxplot) | Modifying different Aspects of the Styling of boxplots | +| [![](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/test_styling_small.png)](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/test_styling) | [Styling of JKQTPlotter](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/test_styling) | Modifying different Aspects of the Styling of JKQTPlotter | ## Image data Plots diff --git a/examples/simpletest_advancedlineandfillstyling/jkqtplotter_simpletest_advancedlineandfillstyling.cpp b/examples/simpletest_advancedlineandfillstyling/jkqtplotter_simpletest_advancedlineandfillstyling.cpp index 253d8cfbc1..fae179fbfc 100644 --- a/examples/simpletest_advancedlineandfillstyling/jkqtplotter_simpletest_advancedlineandfillstyling.cpp +++ b/examples/simpletest_advancedlineandfillstyling/jkqtplotter_simpletest_advancedlineandfillstyling.cpp @@ -109,8 +109,8 @@ int main(int argc, char* argv[]) linearGrad.setColorAt(0.3, c2); linearGrad.setColorAt(0.7, c3); linearGrad.setColorAt(1, c4); - linearGrad.setCoordinateMode(QGradient::ObjectBoundingMode); // use this CoordinateMode, so the gradient fills the whole graph area + linearGrad.setCoordinateMode(QGradient::ObjectBoundingMode); graphF2->setFillGradient(linearGrad); // 5.4 fill barcharts with transparencies and make the surrounding line invisible (colored transparent) diff --git a/examples/simpletest_boxplot/README.md b/examples/simpletest_boxplot/README.md index ba3abee868..1f49cd5ed6 100644 --- a/examples/simpletest_boxplot/README.md +++ b/examples/simpletest_boxplot/README.md @@ -45,18 +45,22 @@ After adding all necessary data to the JKQTDatastore: You can further style the plot by e.g. setting: ```.cpp - // 4.1 make fill collor a lighter shade of the outline color - graph->setFillColor(graphh->getColor().lighter()); - // 4.2 make whiskers dashed - graph->setWhiskerLineStyle(Qt::DashLine); - graph->setWhiskerLineColor(graph->getLineColor().darker()); - // 4.3 change mean symbol - graph->setSymbolType(JKQTPFilledStar); - graph->setSymbolFillColor(QColor("silver")); - // 4.4 change median line color - graph->setMedianLineColor(QColor("darkgreen")); - // 4.5 change box width to 75% of distance - graph->setBoxWidth(0.75); + // 6.1 make fill collor a lighter shade of the outline color + graphh->setFillColor(graphh->getLineColor().lighter()); + // 6.2 make whiskers dashed + graphh->setWhiskerLineStyle(Qt::DashLine); + graphh->setWhiskerLineColor(graphh->getLineColor().darker()); + // 6.3 make whiskers caps solid and thick + graphh->setWhiskerCapLineStyle(Qt::SolidLine); + graphh->setWhiskerCapLineColor(graphh->getLineColor().darker()); + graphh->setWhiskerCapLineWidth(graphh->getLineWidth()*2.5); + // 6.4 change mean symbol + graphh->setMeanSymbolType(JKQTPFilledStar); + graphh->setMeanFillColor(QColor("silver")); + // 6.5 change median line color + graphh->setMedianLineColor(QColor("darkgreen")); + // 6.6 change box width to 75% of distance + graphh->setBoxWidthRelative(0.75); ``` The result looks like this: diff --git a/examples/simpletest_boxplot/jkqtplotter_simpletest_boxplot.cpp b/examples/simpletest_boxplot/jkqtplotter_simpletest_boxplot.cpp index 7097c20e84..9e13ed2aa0 100644 --- a/examples/simpletest_boxplot/jkqtplotter_simpletest_boxplot.cpp +++ b/examples/simpletest_boxplot/jkqtplotter_simpletest_boxplot.cpp @@ -85,13 +85,17 @@ int main(int argc, char* argv[]) // 6.2 make whiskers dashed graphh->setWhiskerLineStyle(Qt::DashLine); graphh->setWhiskerLineColor(graphh->getLineColor().darker()); - // 6.3 change mean symbol - graphh->setSymbolType(JKQTPFilledStar); - graphh->setSymbolFillColor(QColor("silver")); - // 6.4 change median line color + // 6.3 make whiskers caps solid and thick + graphh->setWhiskerCapLineStyle(Qt::SolidLine); + graphh->setWhiskerCapLineColor(graphh->getLineColor().darker()); + graphh->setWhiskerCapLineWidth(graphh->getLineWidth()*2.5); + // 6.4 change mean symbol + graphh->setMeanSymbolType(JKQTPFilledStar); + graphh->setMeanFillColor(QColor("silver")); + // 6.5 change median line color graphh->setMedianLineColor(QColor("darkgreen")); - // 6.5 change box width to 75% of distance - graphh->setBoxWidth(0.75); + // 6.6 change box width to 75% of distance + graphh->setBoxWidthRelative(0.75); // 7. add the graphs to the plot, so it is actually displayed plot.addGraph(graph); diff --git a/examples/test_distributionplot/README.md b/examples/test_distributionplot/README.md index e375cd496a..ffaca77491 100644 --- a/examples/test_distributionplot/README.md +++ b/examples/test_distributionplot/README.md @@ -47,6 +47,7 @@ After adding all necessary data to the JKQTDatastore: const double rndMedian=RANDVAL[RANDVAL.size()/2]; const double rndQ25=RANDVAL[RANDVAL.size()/4]; const double rndQ75=RANDVAL[RANDVAL.size()*3/4]; + const double rndMedianConfidence=2.0*1.57*fabs(rndQ75-rndQ25)/sqrt(static_cast(NDATA)); // 3. make data available to JKQTPlotter by adding it to the internal datastore. size_t columnRANDVAL=ds->addCopiedColumn(RANDVAL, "RANDVAL"); // copy random values @@ -99,15 +100,16 @@ After adding all necessary data to the JKQTDatastore: graphBoxPlot->setPercentile25(rndQ25); graphBoxPlot->setMean(rndMean); graphBoxPlot->setMedian(rndMedian); + graphBoxPlot->setMedianConfidenceIntervalWidth(rndMedianConfidence); graphBoxPlot->setPercentile75(rndQ75); graphBoxPlot->setMax(rndMax); - graphBoxPlot->setBoxWidth(24); - graphBoxPlot->setSymbolTypeSize(16); - graphBoxPlot->setSymbolTypeWidth(2); + graphBoxPlot->setBoxWidthAbsolute(24); + graphBoxPlot->setMeanSize(16); + graphBoxPlot->setLineWidth(2); graphBoxPlot->setTitle("Statistical Properties"); - graphBoxPlot->setColor(QColor("blue")); + graphBoxPlot->setBoxplotColor(QColor("blue"), plot.getPlotter()); // make fill collor a lighter shade of the outline color - graphBoxPlot->setFillColor(graphBoxPlot->getColor().lighter(180)); + graphBoxPlot->setFillColor(graphBoxPlot->getLineColor().lighter(180)); // make whiskers dashed graphBoxPlot->setWhiskerLineStyle(Qt::DashLine); diff --git a/examples/test_distributionplot/test_distributionplot.cpp b/examples/test_distributionplot/test_distributionplot.cpp index 8e1c4c6654..0888ebcd89 100644 --- a/examples/test_distributionplot/test_distributionplot.cpp +++ b/examples/test_distributionplot/test_distributionplot.cpp @@ -61,6 +61,7 @@ int main(int argc, char* argv[]) const double rndMedian=RANDVAL[RANDVAL.size()/2]; const double rndQ25=RANDVAL[RANDVAL.size()/4]; const double rndQ75=RANDVAL[RANDVAL.size()*3/4]; + const double rndMedianConfidence=2.0*1.57*fabs(rndQ75-rndQ25)/sqrt(static_cast(NDATA)); // 3. make data available to JKQTPlotter by adding it to the internal datastore. size_t columnRANDVAL=ds->addCopiedColumn(RANDVAL, "RANDVAL"); // copy random values @@ -112,15 +113,20 @@ int main(int argc, char* argv[]) graphBoxPlot->setPercentile25(rndQ25); graphBoxPlot->setMean(rndMean); graphBoxPlot->setMedian(rndMedian); + graphBoxPlot->setMedianConfidenceIntervalWidth(rndMedianConfidence); graphBoxPlot->setPercentile75(rndQ75); graphBoxPlot->setMax(rndMax); - graphBoxPlot->setBoxWidth(24); - graphBoxPlot->setSymbolTypeSize(16); - graphBoxPlot->setSymbolTypeWidth(2); + graphBoxPlot->setBoxWidthAbsolute(24); + graphBoxPlot->setMeanSize(12); + graphBoxPlot->setMeanSymbolType(JKQTPCross); + graphBoxPlot->setLineWidth(2); graphBoxPlot->setTitle("Statistical Properties"); - graphBoxPlot->setColor(QColor("blue")); + // set color of all elements + graphBoxPlot->setBoxplotColor(QColor("blue"), plot.getPlotter()); + // change color of mean symbol + graphBoxPlot->setMeanColor(QColor("red")); // make fill collor a lighter shade of the outline color - graphBoxPlot->setFillColor(graphBoxPlot->getColor().lighter(180)); + graphBoxPlot->setFillColor(graphBoxPlot->getLineColor().lighter(180)); // make whiskers dashed graphBoxPlot->setWhiskerLineStyle(Qt::DashLine); @@ -140,7 +146,7 @@ int main(int argc, char* argv[]) // 11. show plotter and make it a decent size plot.show(); - plot.resize(800,800); + plot.resize(800,650); return app.exec(); } diff --git a/examples/test_styledboxplot/README.md b/examples/test_styledboxplot/README.md new file mode 100644 index 0000000000..6b967df6fe --- /dev/null +++ b/examples/test_styledboxplot/README.md @@ -0,0 +1,119 @@ +# Example (JKQTPlotter): Styling different aspects of boxplots {#JKQTPlotterBoxplotStyling} +This project (see [`test_styledboxplot`](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/test_styledboxplot) demonstrates how to style different aspects of boxplots and how to draw different types and styles of boxplots. For a simple introduction into how to use boxplots, see [Plotting Box Plots](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/simpletest_boxplot) and [Plotting a Statistical Distribution of Data](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/test_distributionplot). + +The link http://vita.had.co.nz/papers/boxplots.pdf leads to a paper that described the history and different types of boxplots. + +The source code of the main application can be found in [`test_styledboxplot.cpp`](test_styledboxplot.cpp). +The major parts that are concerned with the styling are: + +```.cpp + // 2. create a basic boxplot + plot.addGraph(graphBoxPlot=new JKQTPBoxplotVerticalElement(&plot)); + plot.addGraph(new JKQTPGeoText(&plot, x-dx/2.0, y0+9, "\\textbf{\\begin{matrix}basic boxplot\\\\\"Turkey's style\"\\end{matrix}}", 8, QColor("black"))); + graphBoxPlot->setPos(x); + graphBoxPlot->setMin(y0+1); + graphBoxPlot->setPercentile25(y0+2.5); + graphBoxPlot->setMedian(y0+4); + graphBoxPlot->setPercentile75(y0+5.5); + graphBoxPlot->setMax(y0+8); + // set color of all elements + graphBoxPlot->setBoxplotColor(QColor("black"),QColor("white"), plot.getPlotter()); + + // ... + // ... + + // 3. create a basic boxplot with mean as symbol + // ... + // set mean value to show mean symbol + graphBoxPlot->setMean(y0+3.5); + graphBoxPlot->setDrawMean(true); + graphBoxPlot->setMeanMode(JKQTPGraphBoxplotStyleMixin::MeanAsSymbol); + graphBoxPlot->setMeanColor(QColor("darkgreen")); + graphBoxPlot->setMeanSymbolType(JKQTPFilledTriangle); + + // ... + // ... + + // 4. create a basic boxplot with mean as line + // ... + // set mean value to show mean symbol + graphBoxPlot->setMean(y0+3.5); + graphBoxPlot->setDrawMean(true); + graphBoxPlot->setMeanMode(JKQTPGraphBoxplotStyleMixin::MeanAsLine); + graphBoxPlot->setMeanColor(QColor("darkgreen")); + graphBoxPlot->setMeanLineStyle(Qt::DashLine); + graphBoxPlot->setMeanLineWidth(2); + + // ... + // ... + + // 5. create a notched boxplot + // ... + // for a notched plot, you need to set the confidence interval + graphBoxPlot->setMedianConfidenceIntervalWidth(1); + graphBoxPlot->setDrawNotch(true); + graphBoxPlot->setRelativeNotchIndent(y0+0.5); + + // ... + // ... + + // 6. create a notched boxplot + // ... + // restyle as Tufte's box-less + graphBoxPlot->setDrawBox(false); + + // ... + // ... + + // 7. style box + // ... + // style box line&fill + graphBoxPlot->setLineColor(QColor("red")); + graphBoxPlot->setLineStyle(Qt::DotLine); + graphBoxPlot->setLineWidth(1); + graphBoxPlot->setFillColor(QColor("yellow")); + + // ... + // ... + + // 8. fancy style box + // ... + // style box fill + QLinearGradient linearGrad(QPointF(0, 0), QPointF(1, 1)); + QColor c1(Qt::red); + QColor c2(Qt::yellow); + QColor c3(Qt::blue); + linearGrad.setColorAt(0, c1); + linearGrad.setColorAt(0.3, c2); + linearGrad.setColorAt(1, c3); + // use this CoordinateMode, so the gradient fills the whole graph area + linearGrad.setCoordinateMode(QGradient::ObjectBoundingMode); + graphBoxPlot->setFillGradient(linearGrad); + + // ... + // ... + + // 9. style median + // ... + // style box line + graphBoxPlot->setMedianLineColor(QColor("red")); + graphBoxPlot->setMedianLineWidth(3); + + // ... + // ... + + // 10. style whiskers&caps + // ... + // style box line + graphBoxPlot->setWhiskerLineColor(QColor("red")); + graphBoxPlot->setWhiskerLineStyle(Qt::DotLine); + graphBoxPlot->setWhiskerLineWidth(1); + graphBoxPlot->setWhiskerCapLineColor(QColor("blue")); + graphBoxPlot->setWhiskerCapLineStyle(Qt::SolidLine); + graphBoxPlot->setWhiskerCapLineWidth(4); + graphBoxPlot->setRelativeWhiskerWidth(0.9); +``` + +The result looks like this: + +![test_styledboxplot](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/test_styledboxplot.png) diff --git a/examples/test_styledboxplot/test_styledboxplot.cpp b/examples/test_styledboxplot/test_styledboxplot.cpp new file mode 100644 index 0000000000..1f2550faf6 --- /dev/null +++ b/examples/test_styledboxplot/test_styledboxplot.cpp @@ -0,0 +1,214 @@ +/** \example test_styledboxplot.cpp + * Shows how to style different aspects of boxplots. + * + * \ref JKQTPlotterBoxplotStyling + */ + +#include +#include "jkqtplotter/jkqtplotter.h" +#include "jkqtplotter/jkqtpgraphsboxplot.h" +#include "jkqtplotter/jkqtpgraphsgeometric.h" + +int main(int argc, char* argv[]) +{ + QApplication app(argc, argv); + + // 1. create a plotter window and get a pointer to the internal datastore (for convenience) + JKQTPlotter plot; + 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 + + + JKQTPBoxplotVerticalElement* graphBoxPlot; + double x=1; + double dx=1; + double y0=11; + + // 2. create a basic boxplot + plot.addGraph(graphBoxPlot=new JKQTPBoxplotVerticalElement(&plot)); + plot.addGraph(new JKQTPGeoText(&plot, x-dx/2.0, y0+9, "\\textbf{\\begin{matrix}basic boxplot\\\\\"Turkey's style\"\\end{matrix}}", 8, QColor("black"))); + graphBoxPlot->setPos(x); + graphBoxPlot->setMin(y0+1); + graphBoxPlot->setPercentile25(y0+2.5); + graphBoxPlot->setMedian(y0+4); + graphBoxPlot->setPercentile75(y0+5.5); + graphBoxPlot->setMax(y0+8); + // set color of all elements + graphBoxPlot->setBoxplotColor(QColor("black"),QColor("white"), plot.getPlotter()); + x+=dx; + + // 3. create a basic boxplot with mean as symbol + plot.addGraph(graphBoxPlot=new JKQTPBoxplotVerticalElement(&plot)); + plot.addGraph(new JKQTPGeoText(&plot, x-dx/2.0, y0+9, "\\textbf{\\begin{matrix}basic boxplot\\\\ + mean symbol\\end{matrix}}", 8, QColor("black"))); + graphBoxPlot->setPos(x); + graphBoxPlot->setMin(y0+1); + graphBoxPlot->setPercentile25(y0+2.5); + graphBoxPlot->setMedian(y0+4); + graphBoxPlot->setPercentile75(y0+5.5); + graphBoxPlot->setMax(y0+8); + // set color of all elements + graphBoxPlot->setBoxplotColor(QColor("black"),QColor("white"), plot.getPlotter()); + // set mean value to show mean symbol + graphBoxPlot->setMean(y0+3.5); + graphBoxPlot->setDrawMean(true); + graphBoxPlot->setMeanMode(JKQTPGraphBoxplotStyleMixin::MeanAsSymbol); + graphBoxPlot->setMeanColor(QColor("darkgreen")); + graphBoxPlot->setMeanSymbolType(JKQTPFilledTriangle); + x+=dx; + + // 4. create a basic boxplot with mean as line + plot.addGraph(graphBoxPlot=new JKQTPBoxplotVerticalElement(&plot)); + plot.addGraph(new JKQTPGeoText(&plot, x-dx/2.0, y0+9, "\\textbf{\\begin{matrix}basic boxplot\\\\ + mean line\\end{matrix}}", 8, QColor("black"))); + graphBoxPlot->setPos(x); + graphBoxPlot->setMin(y0+1); + graphBoxPlot->setPercentile25(y0+2.5); + graphBoxPlot->setMedian(y0+4); + graphBoxPlot->setPercentile75(y0+5.5); + graphBoxPlot->setMax(y0+8); + // set color of all elements + graphBoxPlot->setBoxplotColor(QColor("black"),QColor("white"), plot.getPlotter()); + // set mean value to show mean symbol + graphBoxPlot->setMean(y0+3.5); + graphBoxPlot->setDrawMean(true); + graphBoxPlot->setMeanMode(JKQTPGraphBoxplotStyleMixin::MeanAsLine); + graphBoxPlot->setMeanColor(QColor("darkgreen")); + graphBoxPlot->setMeanLineStyle(Qt::DashLine); + graphBoxPlot->setMeanLineWidth(2); + x+=dx; + + // 5. create a notched boxplot + plot.addGraph(graphBoxPlot=new JKQTPBoxplotVerticalElement(&plot)); + plot.addGraph(new JKQTPGeoText(&plot, x-dx/2.0, y0+9, "\\textbf{notched boxplot}", 8, QColor("black"))); + graphBoxPlot->setPos(x); + graphBoxPlot->setMin(y0+1); + graphBoxPlot->setPercentile25(y0+2.5); + graphBoxPlot->setMedian(y0+4); + graphBoxPlot->setPercentile75(y0+5.5); + graphBoxPlot->setMax(y0+8); + // set color of all elements + graphBoxPlot->setBoxplotColor(QColor("black"), QColor("white"), plot.getPlotter()); + // for a notched plot, you need to set the confidence interval + graphBoxPlot->setMedianConfidenceIntervalWidth(1); + graphBoxPlot->setDrawNotch(true); + graphBoxPlot->setRelativeNotchIndent(0.5); + x+=dx; + + + // 6. create a notched boxplot + plot.addGraph(graphBoxPlot=new JKQTPBoxplotVerticalElement(&plot)); + plot.addGraph(new JKQTPGeoText(&plot, x-dx/2.0, y0+9, "\\textbf{\\begin{matrix}basic boxplot\\\\\"Tufte's style\"\\end{matrix}}", 8, QColor("black"))); + graphBoxPlot->setPos(x); + graphBoxPlot->setMin(y0+1); + graphBoxPlot->setPercentile25(y0+2.5); + graphBoxPlot->setMedian(y0+4); + graphBoxPlot->setPercentile75(y0+5.5); + graphBoxPlot->setMax(y0+8); + // set color of all elements + graphBoxPlot->setBoxplotColor(QColor("black"), QColor("white"), plot.getPlotter()); + // restyle as Tufte's box-less + graphBoxPlot->setDrawBox(false); + x+=dx; + + + + x=1; + y0=0; + + // 7. style box + plot.addGraph(graphBoxPlot=new JKQTPBoxplotVerticalElement(&plot)); + plot.addGraph(new JKQTPGeoText(&plot, x-dx/2.0, y0+9, "\\textbf{styled box}", 8, QColor("black"))); + graphBoxPlot->setPos(x); + graphBoxPlot->setMin(y0+1); + graphBoxPlot->setPercentile25(y0+2.5); + graphBoxPlot->setMedian(y0+4); + graphBoxPlot->setPercentile75(y0+5.5); + graphBoxPlot->setMax(y0+8); + // set color of all elements + graphBoxPlot->setBoxplotColor(QColor("black"),QColor("white"), plot.getPlotter()); + // style box line&fill + graphBoxPlot->setLineColor(QColor("red")); + graphBoxPlot->setLineStyle(Qt::DotLine); + graphBoxPlot->setLineWidth(1); + graphBoxPlot->setFillColor(QColor("yellow")); + x+=dx; + + // 8. fancy style box + plot.addGraph(graphBoxPlot=new JKQTPBoxplotVerticalElement(&plot)); + plot.addGraph(new JKQTPGeoText(&plot, x-dx/2.0, y0+9, "\\textbf{styled box}", 8, QColor("black"))); + graphBoxPlot->setPos(x); + graphBoxPlot->setMin(y0+1); + graphBoxPlot->setPercentile25(y0+2.5); + graphBoxPlot->setMedian(y0+4); + graphBoxPlot->setPercentile75(y0+5.5); + graphBoxPlot->setMax(y0+8); + // set color of all elements + graphBoxPlot->setBoxplotColor(QColor("black"),QColor("white"), plot.getPlotter()); + // style box fill + QLinearGradient linearGrad(QPointF(0, 0), QPointF(1, 1)); + QColor c1(Qt::red); + QColor c2(Qt::yellow); + QColor c3(Qt::blue); + linearGrad.setColorAt(0, c1); + linearGrad.setColorAt(0.3, c2); + linearGrad.setColorAt(1, c3); + // use this CoordinateMode, so the gradient fills the whole graph area + linearGrad.setCoordinateMode(QGradient::ObjectBoundingMode); + graphBoxPlot->setFillGradient(linearGrad); + x+=dx; + + // 9. style median + plot.addGraph(graphBoxPlot=new JKQTPBoxplotVerticalElement(&plot)); + plot.addGraph(new JKQTPGeoText(&plot, x-dx/2.0, y0+9, "\\textbf{styled median}", 8, QColor("black"))); + graphBoxPlot->setPos(x); + graphBoxPlot->setMin(y0+1); + graphBoxPlot->setPercentile25(y0+2.5); + graphBoxPlot->setMedian(y0+4); + graphBoxPlot->setPercentile75(y0+5.5); + graphBoxPlot->setMax(y0+8); + // set color of all elements + graphBoxPlot->setBoxplotColor(QColor("black"),QColor("white"), plot.getPlotter()); + // style box line + graphBoxPlot->setMedianLineColor(QColor("red")); + graphBoxPlot->setMedianLineWidth(3); + x+=dx; + + + // 10. style whiskers&caps + plot.addGraph(graphBoxPlot=new JKQTPBoxplotVerticalElement(&plot)); + plot.addGraph(new JKQTPGeoText(&plot, x-dx/2.0, y0+9, "\\textbf{styled whiskers}", 8, QColor("black"))); + graphBoxPlot->setPos(x); + graphBoxPlot->setMin(y0+1); + graphBoxPlot->setPercentile25(y0+2.5); + graphBoxPlot->setMedian(y0+4); + graphBoxPlot->setPercentile75(y0+5.5); + graphBoxPlot->setMax(y0+8); + // set color of all elements + graphBoxPlot->setBoxplotColor(QColor("black"),QColor("white"), plot.getPlotter()); + // style box line + graphBoxPlot->setWhiskerLineColor(QColor("red")); + graphBoxPlot->setWhiskerLineStyle(Qt::DotLine); + graphBoxPlot->setWhiskerLineWidth(1); + graphBoxPlot->setWhiskerCapLineColor(QColor("blue")); + graphBoxPlot->setWhiskerCapLineStyle(Qt::SolidLine); + graphBoxPlot->setWhiskerCapLineWidth(4); + graphBoxPlot->setRelativeWhiskerWidth(0.9); + x+=dx; + + + + + + // 11. autoscale the plot so the graph is contained + plot.setXY(0.5,5.5,0, 21); + + // 12. style plot + plot.getPlotter()->setShowKey(false); + plot.getPlotter()->setGrid(false); + + // 13. show plotter and make it a decent size + plot.show(); + plot.resize(600,500); + + return app.exec(); +} diff --git a/examples/test_styledboxplot/test_styledboxplot.pro b/examples/test_styledboxplot/test_styledboxplot.pro new file mode 100644 index 0000000000..8708da16f4 --- /dev/null +++ b/examples/test_styledboxplot/test_styledboxplot.pro @@ -0,0 +1,25 @@ +# source code for this simple demo +SOURCES = test_styledboxplot.cpp + +# configure Qt +CONFIG += link_prl qt +QT += core gui xml svg +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets printsupport + +# output executable name +TARGET = test_styledboxplot + +# include JKQTPlotter source code +DEPENDPATH += ../../lib ../../staticlib/jkqtplotterlib +INCLUDEPATH += ../../lib +CONFIG (debug, debug|release) { + LIBS += -L../../staticlib/jkqtplotterlib/debug -ljkqtplotterlib_debug +} else { + LIBS += -L../../staticlib/jkqtplotterlib/release -ljkqtplotterlib +} +message("LIBS = $$LIBS") + + + + + diff --git a/examples/test_styledboxplot/test_styledboxplot_and_lib.pro b/examples/test_styledboxplot/test_styledboxplot_and_lib.pro new file mode 100644 index 0000000000..35564d409b --- /dev/null +++ b/examples/test_styledboxplot/test_styledboxplot_and_lib.pro @@ -0,0 +1,8 @@ +TEMPLATE = subdirs + +SUBDIRS += jkqtplotterlib test_styledboxplot + +jkqtplotterlib.file = ../../staticlib/jkqtplotterlib/jkqtplotterlib.pro + +test_styledboxplot.file=$$PWD/test_styledboxplot.pro +test_styledboxplot.depends = jkqtplotterlib diff --git a/lib/jkqtplotter.pri b/lib/jkqtplotter.pri index 61a506e409..3a61b2637e 100644 --- a/lib/jkqtplotter.pri +++ b/lib/jkqtplotter.pri @@ -20,6 +20,7 @@ HEADERS += \ $$PWD/jkqtplotter/jkqtpgraphsbaseerrors.h \ $$PWD/jkqtplotter/jkqtpgraphsbasestylingmixins.h \ $$PWD/jkqtplotter/jkqtpgraphsboxplot.h \ + $$PWD/jkqtplotter/jkqtpgraphsboxplotstylingmixins.h \ $$PWD/jkqtplotter/jkqtpgraphsevaluatedfunction.h \ $$PWD/jkqtplotter/jkqtpgraphsfilledcurve.h \ $$PWD/jkqtplotter/jkqtpgraphsgeometric.h \ @@ -65,6 +66,7 @@ SOURCES += \ $$PWD/jkqtplotter/jkqtpgraphsbaseerrors.cpp \ $$PWD/jkqtplotter/jkqtpgraphsbasestylingmixins.cpp \ $$PWD/jkqtplotter/jkqtpgraphsboxplot.cpp \ + $$PWD/jkqtplotter/jkqtpgraphsboxplotstylingmixins.cpp \ $$PWD/jkqtplotter/jkqtpgraphsevaluatedfunction.cpp \ $$PWD/jkqtplotter/jkqtpgraphsfilledcurve.cpp \ $$PWD/jkqtplotter/jkqtpgraphsgeometric.cpp \ diff --git a/lib/jkqtplotter/jkqtpdatastorage.cpp b/lib/jkqtplotter/jkqtpdatastorage.cpp index 3dd932b6f6..6dfcdc3f74 100644 --- a/lib/jkqtplotter/jkqtpdatastorage.cpp +++ b/lib/jkqtplotter/jkqtpdatastorage.cpp @@ -336,7 +336,7 @@ int JKQTPDatastore::getColumnNum(const QString& name) { QMapIterator it(columns); while (it.hasNext()) { it.next(); - if (it.value().getName()==name) return it.key(); + if (it.value().getName()==name) return static_cast(it.key()); } return -1; } @@ -347,21 +347,22 @@ int JKQTPDatastore::ensureColumnNum(const QString& name) { QMapIterator it(columns); while (it.hasNext()) { it.next(); - if (it.value().getName()==name) return it.key(); + if (it.value().getName()==name) return static_cast(it.key()); } - return addColumn(0, name); + return static_cast(addColumn(0, name)); } //////////////////////////////////////////////////////////////////////////////////////////////// JKQTPColumn JKQTPDatastore::getColumn(size_t i) const { - return columns.value(i); + return columns.value(i, JKQTPColumn()); } //////////////////////////////////////////////////////////////////////////////////////////////// JKQTPColumn JKQTPDatastore::getColumn(int i) const { - return columns.value(i); + if (i<0) return JKQTPColumn(); + return getColumn(static_cast(i)); } //////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/lib/jkqtplotter/jkqtpdatastorage.h b/lib/jkqtplotter/jkqtpdatastorage.h index ac2fbf6304..0257344c15 100644 --- a/lib/jkqtplotter/jkqtpdatastorage.h +++ b/lib/jkqtplotter/jkqtpdatastorage.h @@ -197,6 +197,10 @@ class JKQTP_LIB_EXPORT JKQTPDatastore{ /** \brief returns the value at position (\c column, \c row). \c column is the logical column and will be mapped to the according memory block internally!) */ inline double get(int column, size_t row) const ; + /** \brief returns the value at position (\c column, \c row). \c column is the logical column and will be mapped to the according memory block internally!) */ + inline double get(int column, int row) const ; + /** \brief returns the value at position (\c column, \c row). \c column is the logical column and will be mapped to the according memory block internally!) */ + inline double get(size_t column, int row) const ; /** \brief gets the index of the datapoint with the nearest, but lower value in the column (in a given inclusive row range [start ... end] values of -1 for the ranges are "wildcards", i.e. start/end of column)*/ int getNextLowerIndex(size_t column, size_t row, int start, int end) const; /** \brief gets the index of the datapoint with the nearest, but lower value in the column */ @@ -876,16 +880,16 @@ inline void JKQTPColumn::incValue(size_t n, double increment){ //////////////////////////////////////////////////////////////////////////////////////////////// inline double JKQTPColumn::getValue(size_t n) const { - if (!datastore) return nan(""); - if (!datastore->getItem(datastoreItem)) return nan(""); + if (!datastore) return JKQTP_NAN; + if (!datastore->getItem(datastoreItem)) return JKQTP_NAN; return datastore->getItem(datastoreItem)->get(datastoreOffset, n); } //////////////////////////////////////////////////////////////////////////////////////////////// inline double JKQTPColumn::getValue(int n) const { - if (!datastore) return nan(""); - if (!datastore->getItem(datastoreItem)) return nan(""); - if (n<0) return nan(""); + if (!datastore) return JKQTP_NAN; + if (!datastore->getItem(datastoreItem)) return JKQTP_NAN; + if (n<0) return JKQTP_NAN; return datastore->getItem(datastoreItem)->get(datastoreOffset, static_cast(n)); } @@ -896,6 +900,21 @@ inline double JKQTPDatastore::get(size_t column, size_t row) const { //////////////////////////////////////////////////////////////////////////////////////////////// inline double JKQTPDatastore::get(int column, size_t row) const { + if (column<0) return JKQTP_NAN; + return get(static_cast(column), static_cast(row)); +} + +//////////////////////////////////////////////////////////////////////////////////////////////// +inline double JKQTPDatastore::get(int column, int row) const { + if (column<0) return JKQTP_NAN; + if (row<0) return JKQTP_NAN; + return get(static_cast(column), static_cast(row)); +} + + +//////////////////////////////////////////////////////////////////////////////////////////////// +inline double JKQTPDatastore::get(size_t column, int row) const { + if (row<0) return JKQTP_NAN; return get(static_cast(column), static_cast(row)); } diff --git a/lib/jkqtplotter/jkqtpgraphsbase.cpp b/lib/jkqtplotter/jkqtpgraphsbase.cpp index dcddf362ab..d1ec5e95ba 100644 --- a/lib/jkqtplotter/jkqtpgraphsbase.cpp +++ b/lib/jkqtplotter/jkqtpgraphsbase.cpp @@ -197,11 +197,11 @@ QString JKQTPPlotElement::formatHitTestDefaultLabel(double x, double y, int inde double JKQTPPlotElement::hitTest(const QPointF & posSystem, QPointF* closestSpotSystem, QString* label, HitTestMode mode) const { - if (parent==nullptr) return nan(""); + if (parent==nullptr) return JKQTP_NAN; int closest=-1; - double closedist=nan(""); - double closedistsec=nan(""); + double closedist=JKQTP_NAN; + double closedistsec=JKQTP_NAN; QPointF closestPos; QPointF posF=transform(posSystem); for (int i=0; igetDatastore(); int imin=0; int imax=0; - if (!getIndexRange(imin, imax)) return nan(""); + if (!getIndexRange(imin, imax)) return JKQTP_NAN; int closest=-1; - double closedist=nan(""); - double closedistsec=nan(""); + double closedist=JKQTP_NAN; + double closedistsec=JKQTP_NAN; QPointF closestPos; QPointF posF=transform(posSystem); for (int i=imin; iQPainter to draw to \param x x-coordinate of the symbol center \param y y-coordinate of the symbol center @@ -228,6 +229,7 @@ class JKQTP_LIB_EXPORT JKQTPGraphSymbolStyleMixin { void plotStyledSymbol(JKQTBasePlotter* parent, JKQTPEnhancedPainter& painter, double x, double y) const; /*! \brief plot a symbol at location x,y (in painter coordinates), using the current style + \param parent parent JKQTBasePlotter of the graph that uses this mix-in (used e.g. for line-width transformation) \param painter the QPainter to draw to \param x x-coordinate of the symbol center \param y y-coordinate of the symbol center @@ -236,6 +238,7 @@ class JKQTP_LIB_EXPORT JKQTPGraphSymbolStyleMixin { void plotStyledSymbol(JKQTBasePlotter* parent, JKQTPEnhancedPainter& painter, double x, double y, double symbolSize) const; /*! \brief plot a symbol at location x,y (in painter coordinates), using the current style + \param parent parent JKQTBasePlotter of the graph that uses this mix-in (used e.g. for line-width transformation) \param painter the QPainter to draw to \param x x-coordinate of the symbol center \param y y-coordinate of the symbol center @@ -245,6 +248,7 @@ class JKQTP_LIB_EXPORT JKQTPGraphSymbolStyleMixin { void plotStyledSymbol(JKQTBasePlotter* parent, JKQTPEnhancedPainter& painter, double x, double y, JKQTPGraphSymbols type) const; /*! \brief plot a symbol at location x,y (in painter coordinates), using the current style + \param parent parent JKQTBasePlotter of the graph that uses this mix-in (used e.g. for line-width transformation) \param painter the QPainter to draw to \param x x-coordinate of the symbol center \param y y-coordinate of the symbol center diff --git a/lib/jkqtplotter/jkqtpgraphsboxplot.cpp b/lib/jkqtplotter/jkqtpgraphsboxplot.cpp index 36214c3729..e720155900 100644 --- a/lib/jkqtplotter/jkqtpgraphsboxplot.cpp +++ b/lib/jkqtplotter/jkqtpgraphsboxplot.cpp @@ -32,258 +32,12 @@ -JKQTPGraphBoxplotStyleMixin::JKQTPGraphBoxplotStyleMixin() -{ - - boxWidth=0.4; - - m_whiskerLinePen=QPen(getLineColor(), getLineWidth()); - whiskerLineWidth=getLineWidth(); - m_medianLinePen=QPen(getLineColor(), getLineWidth()); - medianLineWidth=getLineWidth(); - -} - - -void JKQTPGraphBoxplotStyleMixin::initBoxplotStyle(JKQTBasePlotter *parent, int &parentPlotStyle) -{ - initFillStyle(parent, parentPlotStyle); - initLineStyle(parent, parentPlotStyle); - initSymbolStyle(parent, parentPlotStyle); - if (parent && parentPlotStyle>=0) { // get style settings from parent object - parentPlotStyle=parent->getNextStyle(); - m_whiskerLinePen.setColor(parent->getPlotStyle(parentPlotStyle).color()); - m_whiskerLinePen.setStyle(parent->getPlotStyle(parentPlotStyle).style()); - whiskerLineWidth=parent->getPlotStyle(parentPlotStyle).widthF(); - m_medianLinePen.setColor(parent->getPlotStyle(parentPlotStyle).color()); - m_medianLinePen.setStyle(parent->getPlotStyle(parentPlotStyle).style()); - medianLineWidth=parent->getPlotStyle(parentPlotStyle).widthF(); - } - - setWhiskerLineColor(getLineColor()); - setMedianLineColor(getLineColor()); -} - -void JKQTPGraphBoxplotStyleMixin::setBoxplotColor(QColor c, JKQTBasePlotter *parent) -{ - setLineColor(c); - setFillColor(JKQTPGetDerivedColor(parent->getCurrentPlotterStyle().graphFillColorDerivationMode, c)); - c.setAlphaF(0.5); - setHighlightingLineColor(c); - setSymbolColor(c); - setSymbolFillColor(JKQTPGetDerivedColor(parent->getCurrentPlotterStyle().graphFillColorDerivationMode, c)); - setWhiskerLineColor(getLineColor()); - setMedianLineColor(getLineColor()); -} - -void JKQTPGraphBoxplotStyleMixin::setBoxWidth(double __value) -{ - this->boxWidth = __value; -} - -double JKQTPGraphBoxplotStyleMixin::getBoxWidth() const -{ - return this->boxWidth; -} - -void JKQTPGraphBoxplotStyleMixin::setWhiskerLineStyle(Qt::PenStyle __value) -{ - this->m_whiskerLinePen.setStyle(__value); -} - -Qt::PenStyle JKQTPGraphBoxplotStyleMixin::getWhiskerLineStyle() const -{ - return this->m_whiskerLinePen.style(); -} - - -void JKQTPGraphBoxplotStyleMixin::setWhiskerLineWidth(double __value) -{ - whiskerLineWidth=__value; -} - -double JKQTPGraphBoxplotStyleMixin::getWhiskerLineWidth() const -{ - return whiskerLineWidth; -} - -void JKQTPGraphBoxplotStyleMixin::setWhiskerLineColor(QColor __value) -{ - m_whiskerLinePen.setColor(__value); -} - -QColor JKQTPGraphBoxplotStyleMixin::getWhiskerLineColor() const -{ - return m_whiskerLinePen.color(); -} - -void JKQTPGraphBoxplotStyleMixin::setWhiskerLineDashOffset(qreal offset) -{ - m_whiskerLinePen.setDashOffset(offset); -} - -qreal JKQTPGraphBoxplotStyleMixin::getWhiskerLineDashOffset() const -{ - return m_whiskerLinePen.dashOffset(); -} - -void JKQTPGraphBoxplotStyleMixin::setWhiskerLineDashPattern(const QVector &pattern) -{ - m_whiskerLinePen.setDashPattern(pattern); - m_whiskerLinePen.setStyle(Qt::CustomDashLine); -} - -QVector JKQTPGraphBoxplotStyleMixin::getWhiskerLineDashPattern() const -{ - return m_whiskerLinePen.dashPattern(); -} - -void JKQTPGraphBoxplotStyleMixin::setWhiskerLineJoinStyle(Qt::PenJoinStyle style) -{ - m_whiskerLinePen.setJoinStyle(style); -} - -Qt::PenJoinStyle JKQTPGraphBoxplotStyleMixin::getWhiskerLineJoinStyle() const -{ - return m_whiskerLinePen.joinStyle(); -} - -void JKQTPGraphBoxplotStyleMixin::setWhiskerLineCapStyle(Qt::PenCapStyle style) -{ - m_whiskerLinePen.setCapStyle(style); -} - -Qt::PenCapStyle JKQTPGraphBoxplotStyleMixin::getWhiskerLineCapStyle() const -{ - return m_whiskerLinePen.capStyle(); -} - -void JKQTPGraphBoxplotStyleMixin::setWhiskerLineBrush(const QBrush &style) -{ - m_whiskerLinePen.setBrush(style); -} - -QBrush JKQTPGraphBoxplotStyleMixin::getWhiskerLineBrush() const -{ - return m_whiskerLinePen.brush(); -} - -QPen JKQTPGraphBoxplotStyleMixin::getWhiskerPen(JKQTPEnhancedPainter &painter, JKQTBasePlotter *parent) const -{ - QPen pw=m_whiskerLinePen; - pw.setWidthF(qMax(JKQTPlotterDrawinTools::ABS_MIN_LINEWIDTH,parent->pt2px(painter, parent->getLineWidthMultiplier()*whiskerLineWidth))); - pw.setJoinStyle(Qt::MiterJoin); - return pw; -} - - - - - -void JKQTPGraphBoxplotStyleMixin::setMedianLineStyle(Qt::PenStyle __value) -{ - this->m_medianLinePen.setStyle(__value); -} - -Qt::PenStyle JKQTPGraphBoxplotStyleMixin::getMedianLineStyle() const -{ - return this->m_medianLinePen.style(); -} - - -void JKQTPGraphBoxplotStyleMixin::setMedianLineWidth(double __value) -{ - medianLineWidth=__value; -} - -double JKQTPGraphBoxplotStyleMixin::getMedianLineWidth() const -{ - return medianLineWidth; -} - -void JKQTPGraphBoxplotStyleMixin::setMedianLineColor(QColor __value) -{ - m_medianLinePen.setColor(__value); -} - -QColor JKQTPGraphBoxplotStyleMixin::getMedianLineColor() const -{ - return m_medianLinePen.color(); -} - -void JKQTPGraphBoxplotStyleMixin::setMedianLineDashOffset(qreal offset) -{ - m_medianLinePen.setDashOffset(offset); -} - -qreal JKQTPGraphBoxplotStyleMixin::getMedianLineDashOffset() const -{ - return m_medianLinePen.dashOffset(); -} - -void JKQTPGraphBoxplotStyleMixin::setMedianLineDashPattern(const QVector &pattern) -{ - m_medianLinePen.setDashPattern(pattern); - m_medianLinePen.setStyle(Qt::CustomDashLine); -} - -QVector JKQTPGraphBoxplotStyleMixin::getMedianLineDashPattern() const -{ - return m_medianLinePen.dashPattern(); -} - -void JKQTPGraphBoxplotStyleMixin::setMedianLineJoinStyle(Qt::PenJoinStyle style) -{ - m_medianLinePen.setJoinStyle(style); -} - -Qt::PenJoinStyle JKQTPGraphBoxplotStyleMixin::getMedianLineJoinStyle() const -{ - return m_medianLinePen.joinStyle(); -} - -void JKQTPGraphBoxplotStyleMixin::setMedianLineCapStyle(Qt::PenCapStyle style) -{ - m_medianLinePen.setCapStyle(style); -} - -Qt::PenCapStyle JKQTPGraphBoxplotStyleMixin::getMedianLineCapStyle() const -{ - return m_medianLinePen.capStyle(); -} - -void JKQTPGraphBoxplotStyleMixin::setMedianLineBrush(const QBrush &style) -{ - m_medianLinePen.setBrush(style); -} - -QBrush JKQTPGraphBoxplotStyleMixin::getMedianLineBrush() const -{ - return m_medianLinePen.brush(); -} - -QPen JKQTPGraphBoxplotStyleMixin::getMedianPen(JKQTPEnhancedPainter &painter, JKQTBasePlotter *parent) const -{ - QPen pw=m_medianLinePen; - pw.setWidthF(qMax(JKQTPlotterDrawinTools::ABS_MIN_LINEWIDTH,parent->pt2px(painter, parent->getLineWidthMultiplier()*medianLineWidth))); - pw.setJoinStyle(Qt::MiterJoin); - return pw; -} - - - - - - - - - - - JKQTPBoxplotVerticalGraph::JKQTPBoxplotVerticalGraph(JKQTBasePlotter* parent): JKQTPGraph(parent) { + boxWidthRelative=0.4; + useRelativeBoxWidth=true; posColumn=-1; medianColumn=-1; meanColumn=-1; @@ -291,6 +45,7 @@ JKQTPBoxplotVerticalGraph::JKQTPBoxplotVerticalGraph(JKQTBasePlotter* parent): maxColumn=-1; percentile25Column=-1; percentile75Column=-1; + medianConfidenceColumn=-1; sortData=Unsorted; @@ -316,14 +71,7 @@ void JKQTPBoxplotVerticalGraph::draw(JKQTPEnhancedPainter& painter) { drawErrorsBefore(painter); - - QPen p=getLinePenForRects(painter, parent); - QPen pw=getWhiskerPen(painter, parent); - QPen pm=getMedianPen(painter, parent); - QPen np(Qt::NoPen); - QBrush b=getFillBrush(painter, parent); - - int imax=datastore->getColumn(posColumn).getRows(); + int imax=static_cast(datastore->getColumn(static_cast(posColumn)).getRows()); int imin=0; if (imaxget(posColumn,i-1)); - double xv=transformX(datastore->get(posColumn,i)); + int i=qBound(imin+1, getDataIndex(iii), imax); + double xv0=transformX(datastore->get(static_cast(posColumn),static_cast(i-1))); + double xv=transformX(datastore->get(static_cast(posColumn),static_cast(i))); if (posColumn>=0 && JKQTPIsOKFloat(xv) && JKQTPIsOKFloat(xv0)) { if (bwfirst) { boxwidth_real=fabs(xv-xv0); @@ -355,6 +103,7 @@ void JKQTPBoxplotVerticalGraph::draw(JKQTPEnhancedPainter& painter) { } } } + // 2. plot: { painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();}); @@ -365,11 +114,9 @@ void JKQTPBoxplotVerticalGraph::draw(JKQTPEnhancedPainter& painter) { const double minv=datastore->get(minColumn,static_cast(i)); const double maxv=datastore->get(maxColumn,static_cast(i)); const double medianv=datastore->get(medianColumn,static_cast(i)); + const double medConf=datastore->get(medianConfidenceColumn,static_cast(i)); const double meanv=datastore->get(meanColumn,static_cast(i)); - QVector lines_p, lines_pw, lines_m; - - //std::cout<<"(xv, yv) = ( "<=0 && JKQTPIsOKFloat(xv) ) { // collect single-value labels for hitTest()-data at the bottom of this loop! @@ -379,72 +126,33 @@ void JKQTPBoxplotVerticalGraph::draw(JKQTPEnhancedPainter& painter) { labelValues<=0 && JKQTPIsOKFloat(minv)) { labelNames<<"\\min"; labelValues<=0 && JKQTPIsOKFloat(p25v)) { labelNames<<"q_{25}"; labelValues<=0 && JKQTPIsOKFloat(medianv)) { labelNames<<"\\median"; labelValues<=0 && JKQTPIsOKFloat(medianv)) { + if (medianConfidenceColumn>=0 && JKQTPIsOKFloat(medConf)) { + labelNames<<"\\median"; labelValues<<(QString::fromStdString(jkqtp_floattolatexstr(medianv, 3))+"\\:{\\pm}\\:"+QString::fromStdString(jkqtp_floattolatexstr(medConf, 3))); labMedian=labelValues.size()-1; + } else { + labelNames<<"\\median"; labelValues<=0 && JKQTPIsOKFloat(meanv)) { labelNames<<"\\mu"; labelValues<=0 && JKQTPIsOKFloat(p75v)) { labelNames<<"q_{75}"; labelValues<=0 && JKQTPIsOKFloat(maxv)) { labelNames<<"\\max"; labelValues<get(posColumn,static_cast(i+1))); - else if (i-1>=0) xn=transformX(datastore->get(posColumn,static_cast(i-1))); - else xn=x+1; - - double w=((boxwidth_real>0)?boxwidth_real:(fabs(xn-x)))*getBoxWidth(); - double minstop=p25; - double maxstop=p75; - if (percentile25Column<0 && medianColumn>=0) minstop=median; - else if (percentile25Column<0 && meanColumn>=0) minstop=mean; - else if (percentile25Column<0 && maxColumn>=0) minstop=max; - if (percentile75Column<0 && medianColumn>=0) maxstop=median; - else if (percentile75Column<0 && meanColumn>=0) maxstop=mean; - else if (percentile75Column<0 && minColumn>=0) maxstop=min; + double w=(useRelativeBoxWidth && boxwidth_real>0)?(boxwidth_real*getBoxWidthRelative()):parent->pt2px(painter,getBoxWidthAbsolute()); double xma=x+w/2.0; double xmi=x-w/2.0; - double xma4=x+w/4.0; - double xmi4=x-w/4.0; - if (imax<=0) { - xma=transformX(xv+getBoxWidth()/2.0); - xmi=transformX(xv-getBoxWidth()/2.0); - xma4=transformX(xv+getBoxWidth()/4.0); - xmi4=transformX(xv-getBoxWidth()/4.0); - } - - if (minColumn>=0) { - lines_pw.append(QLineF(xmi4, min, xma4, min)); - lines_pw.append(QLineF(x, min, x, minstop)); - } - if (maxColumn>=0) { - lines_pw.append(QLineF(xmi4, max, xma4, max)); - lines_pw.append(QLineF(x, max, x, maxstop)); - } - - if (percentile25Column>=0 && percentile75Column>=0) painter.drawRect(QRectF(xmi, p75, fabs(xma-xmi), fabs(p75-p25))); - if (medianColumn>=0) lines_m.append(QLineF(xmi+p.widthF()/2.0, median, xma-p.widthF()/2.0, median)); - if (meanColumn>=0 && JKQTPIsOKFloat(meanv)) { - plotStyledSymbol(parent, painter,x,mean); - } - - - painter.setPen(p); - if (lines_p.size()>0) painter.drawLines(lines_p); - painter.setPen(pw); - if (lines_pw.size()>0) painter.drawLines(lines_pw); - painter.setPen(pm); - if (lines_m.size()>0) painter.drawLines(lines_m); + plotVerticalBoxplot(parent, painter, x, xmi, xma, min, p25, median, p75, max, mean, medianu, mediano); // add hit-test graph points @@ -505,7 +213,7 @@ bool JKQTPBoxplotVerticalGraph::getXMinMax(double& minx, double& maxx, double& s JKQTPDatastore* datastore=parent->getDatastore(); int imin=0; - int imax=datastore->getColumn(posColumn).getRows(); + int imax=static_cast(datastore->getColumn(static_cast(posColumn)).getRows()); if (imaxget(posColumn,i); + double xv=datastore->get(posColumn,static_cast(i)); if (JKQTPIsOKFloat(xv)) { double xn=xv+1; if (i+1get(posColumn,i+1); else if (i-1>=0) xn=datastore->get(posColumn,i-1); else xn=xv+1; double delta=fabs(xn-xv); - double w=delta*getBoxWidth(); + double w=delta*getBoxWidthRelative(); double xma=xv+w; double xmi=xv-w; if (start || xma>maxx) maxx=xma; @@ -603,7 +311,7 @@ JKQTPBoxplotVerticalGraph::DataSortOrder JKQTPBoxplotVerticalGraph::getDataSortO } void JKQTPBoxplotVerticalGraph::setDataSortOrder(int __value) { - sortData=(DataSortOrder)__value; + sortData=static_cast(__value); if (__value>0) sortData=Sorted; } @@ -705,44 +413,39 @@ void JKQTPBoxplotVerticalGraph::setPercentile75Column(size_t __value) { this->percentile75Column = static_cast(__value); } +int JKQTPBoxplotVerticalGraph::getMedianConfidenceColumn() const +{ + return medianConfidenceColumn; +} + +void JKQTPBoxplotVerticalGraph::setMedianConfidenceColumn(size_t __value) +{ + medianConfidenceColumn=static_cast(__value); +} + +void JKQTPBoxplotVerticalGraph::setBoxWidthRelative(double __value) +{ + this->boxWidthRelative = __value; +} + +double JKQTPBoxplotVerticalGraph::getBoxWidthRelative() const +{ + return this->boxWidthRelative; +} + +void JKQTPBoxplotVerticalGraph::setUseRelativeBoxWidth(bool __value) +{ + useRelativeBoxWidth=__value; +} + +bool JKQTPBoxplotVerticalGraph::getUseRelativeBoxWidth() const +{ + return useRelativeBoxWidth; +} + void JKQTPBoxplotVerticalGraph::drawKeyMarker(JKQTPEnhancedPainter& painter, QRectF& rect) { - painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();}); - QPen p=getLinePenForRects(painter, parent); - QPen pw=getWhiskerPen(painter, parent); - QPen pm=getMedianPen(painter, parent); - QPen np(Qt::NoPen); - QBrush b=getFillBrush(painter, parent); - - p.setWidthF(qMin(1.0, p.widthF())); - pw.setWidthF(qMin(1.0, pw.widthF())); - pm.setWidthF(qMin(1.0, pm.widthF())); - - double x=rect.left()+rect.width()/2.0; - double xma=x+rect.width()/2.5; - double xmi=x-rect.width()/2.5; - double min=rect.bottom(); - double max=rect.top(); - double median=max+rect.height()/2.0; - double w=rect.width()/1.8; - double p25=max+0.75*rect.height(); - double p75=max+0.25*rect.height(); - - painter.setPen(p); - { - painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();}); - painter.setBrush(b); - painter.drawRect(QRectF(xmi, p75, fabs(xma-xmi), fabs(p75-p25))); - } - - painter.setPen(pm); - painter.drawLine(QLineF(xmi, median, xma, median)); - painter.setPen(pw); - painter.drawLine(QLineF(x-w/4.0, max, x+w/4.0, max)); - painter.drawLine(QLineF(x-w/4.0, min, x+w/4.0, min)); - painter.drawLine(QLineF(x, max, x, p75)); - painter.drawLine(QLineF(x, min, x, p25)); - + plotVerticalKeyMarker(parent, painter, rect); } QColor JKQTPBoxplotVerticalGraph::getKeyLabelColor() const { @@ -758,41 +461,7 @@ void JKQTPBoxplotVerticalGraph::setColor(QColor c) void JKQTPBoxplotHorizontalGraph::drawKeyMarker(JKQTPEnhancedPainter& painter, QRectF& rect) { - painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();}); - QPen p=getLinePenForRects(painter, parent); - QPen pw=getWhiskerPen(painter, parent); - QPen pm=getMedianPen(painter, parent); - QPen np(Qt::NoPen); - QBrush b=getFillBrush(painter, parent); - p.setWidthF(qMin(1.0, p.widthF())); - pw.setWidthF(qMin(1.0, pw.widthF())); - pm.setWidthF(qMin(1.0, pm.widthF())); - - - double y=rect.top()+rect.height()/2.0; - double yma=y+rect.height()/2.5; - double ymi=y-rect.height()/2.5; - double min=rect.left(); - double max=rect.right(); - double median=max-rect.width()/2.0; - double w=rect.height()/1.8; - double p25=min+0.75*rect.width(); - double p75=min+0.25*rect.width(); - - painter.setPen(p); - { - painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();}); - painter.setBrush(b); - painter.drawRect(QRectF(p75, ymi, fabs(p75-p25), fabs(yma-ymi))); - } - - painter.setPen(pm); - painter.drawLine(QLineF(median, ymi, median, yma)); - painter.setPen(pw); - painter.drawLine(QLineF(max, y-w/4.0, max, y+w/4.0)); - painter.drawLine(QLineF(min, y-w/4.0, min, y+w/4.0)); - painter.drawLine(QLineF(max, y, p75, y)); - painter.drawLine(QLineF(min, y, p25, y)); + plotHorizontalKeyMarker(parent, painter, rect); } @@ -857,7 +526,7 @@ bool JKQTPBoxplotHorizontalGraph::getYMinMax(double& minx, double& maxx, double& JKQTPDatastore* datastore=parent->getDatastore(); int imin=0; - int imax=datastore->getColumn(posColumn).getRows(); + int imax=static_cast(datastore->getColumn(static_cast(posColumn)).getRows()); if (imaxget(posColumn,i); + double xv=datastore->get(posColumn,static_cast(i)); double xn=xv+1; if (i+1get(posColumn,i+1); else if (i-1>=0) xn=datastore->get(posColumn,i-1); else xn=xv+1; double delta=fabs(xn-xv); - double w=delta*getBoxWidth(); + double w=delta*getBoxWidthRelative(); double xma=xv+w; double xmi=xv-w; if (JKQTPIsOKFloat(xma) && JKQTPIsOKFloat(xmi) ) { @@ -908,14 +577,8 @@ void JKQTPBoxplotHorizontalGraph::draw(JKQTPEnhancedPainter& painter) { drawErrorsBefore(painter); - QPen p=getLinePenForRects(painter, parent); - QPen pw=getWhiskerPen(painter, parent); - QPen pm=getMedianPen(painter, parent); - QPen np(Qt::NoPen); - QBrush b=getFillBrush(painter, parent); - - int imax=datastore->getColumn(posColumn).getRows(); + int imax=static_cast(datastore->getColumn(static_cast(posColumn)).getRows()); int imin=0; if (imaxget(maxColumn,static_cast(i)); const double medianv=datastore->get(medianColumn,static_cast(i)); const double meanv=datastore->get(meanColumn,static_cast(i)); + const double medConf=datastore->get(medianConfidenceColumn,static_cast(i)); - QVector lines_p, lines_pw, lines_m; - //std::cout<<"(xv, yv) = ( "<=0 && JKQTPIsOKFloat(yv) ) { @@ -968,16 +630,18 @@ void JKQTPBoxplotHorizontalGraph::draw(JKQTPEnhancedPainter& painter) { labelValues<=0 && JKQTPIsOKFloat(minv)) { labelNames<<"\\min"; labelValues<=0 && JKQTPIsOKFloat(p25v)) { labelNames<<"q_{25}"; labelValues<=0 && JKQTPIsOKFloat(medianv)) { labelNames<<"\\median"; labelValues<=0 && JKQTPIsOKFloat(medianv)) { + if (medianConfidenceColumn>=0 && JKQTPIsOKFloat(medConf)) { + labelNames<<"\\median"; labelValues<<(QString::fromStdString(jkqtp_floattolatexstr(medianv, 3))+"\\:{\\pm}\\:"+QString::fromStdString(jkqtp_floattolatexstr(medConf, 3))); labMedian=labelValues.size()-1; + } else { + labelNames<<"\\median"; labelValues<=0 && JKQTPIsOKFloat(meanv)) { labelNames<<"\\mu"; labelValues<=0 && JKQTPIsOKFloat(p75v)) { labelNames<<"q_{75}"; labelValues<=0 && JKQTPIsOKFloat(maxv)) { labelNames<<"\\max"; labelValues<=0) minstop=median; - else if (percentile25Column<0 && maxColumn>=0) minstop=max; - else if (percentile25Column<0 && meanColumn>=0) minstop=mean; - if (percentile75Column<0 && medianColumn>=0) maxstop=median; - else if (percentile75Column<0 && minColumn>=0) maxstop=min; - else if (percentile75Column<0 && meanColumn>=0) maxstop=mean; + double w=(useRelativeBoxWidth && boxwidth_real>0)?(boxwidth_real*getBoxWidthRelative()):parent->pt2px(painter,getBoxWidthAbsolute()); + double yma=y+w/2.0; + double ymi=y-w/2.0; - double yn=y+1; - if (i+1get(posColumn,static_cast(i+1))); - else if (i-1>=0) yn=transformY(datastore->get(posColumn,static_cast(i-1))); - else yn=y+1; - double delta=fabs(yn-y); - double w=((boxwidth_real>0)?boxwidth_real:(delta))*getBoxWidth(); - double yma=y-w/2.0; - double ymi=y+w/2.0; - double yma4=y+w/4.0; - double ymi4=y-w/4.0; - if (imax<=1) { - ymi=transformY(yv+getBoxWidth()/2.0); - yma=transformY(yv-getBoxWidth()/2.0); - yma4=transformY(yv+getBoxWidth()/4.0); - ymi4=transformY(yv-getBoxWidth()/4.0); - } - if (minColumn>=0) { - lines_pw.append(QLineF(min, ymi4, min, yma4)); - lines_pw.append(QLineF(min, y, minstop, y)); - } - if (maxColumn>=0) { - lines_pw.append(QLineF(max, ymi4, max, yma4)); - lines_pw.append(QLineF(max, y, maxstop, y)); - } - if (percentile25Column>=0 && percentile75Column>=0) painter.drawRect(QRectF(p25, qMin(yma,ymi), fabs(p75-p25), fabs(yma-ymi))); - if (medianColumn>=0) lines_m.append(QLineF(median, ymi-p.widthF()/2.0, median, yma+p.widthF()/2.0)); - - if (meanColumn>=0 && JKQTPIsOKFloat(meanv)) { - plotStyledSymbol(parent, painter, mean, y); - } - - //first=true; - painter.setPen(p); - if (lines_p.size()>0) painter.drawLines(lines_p); - painter.setPen(pw); - if (lines_pw.size()>0) painter.drawLines(lines_pw); - painter.setPen(pm); - if (lines_m.size()>0) painter.drawLines(lines_m); + plotHorizontalBoxplot(parent, painter, y, ymi, yma, min, p25, median, p75, max, mean, medianu, mediano); // add hit-test graph points @@ -1108,15 +731,17 @@ void JKQTPBoxplotHorizontalGraph::draw(JKQTPEnhancedPainter& painter) { JKQTPBoxplotVerticalElement::JKQTPBoxplotVerticalElement(JKQTBasePlotter* parent): JKQTPPlotObject(parent) { - pos=0; - median=0; - mean=0; - min=-1; - max=1; - drawMean=true; - drawMinMax=true; - percentile25=-0.75; - percentile75=0.75; + pos=JKQTP_NAN; + median=JKQTP_NAN; + mean=JKQTP_NAN; + min=JKQTP_NAN; + max=JKQTP_NAN; + drawMean=false; + drawMinMax=false; + percentile25=JKQTP_NAN; + percentile75=JKQTP_NAN; + medianConfidenceIntervalWidth=JKQTP_NAN; + drawNotch=false; initBoxplotStyle(parent, parentPlotStyle); @@ -1137,20 +762,13 @@ void JKQTPBoxplotVerticalElement::draw(JKQTPEnhancedPainter& painter) { { painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();}); - QPen p=getLinePenForRects(painter, parent); - QPen pw=getWhiskerPen(painter, parent); - QPen pm=getMedianPen(painter, parent); - QPen np(Qt::NoPen); - QBrush b=getFillBrush(painter, parent); - - - const double xv=pos; const double p25v=percentile25; const double p75v=percentile75; const double minv=min; const double maxv=max; const double medianv=median; + const double medConf=medianConfidenceIntervalWidth; const double meanv=mean; //std::cout<<"(xv, yv) = ( "<pt2px(painter, getBoxWidth()); + double w=parent->pt2px(painter,getBoxWidthAbsolute()); double xma=x+w/2.0; double xmi=x-w/2.0; - painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();}); - painter.setPen(p); + plotVerticalBoxplot(parent, painter, x, xmi, xma, (drawMinMax)?min:JKQTP_NAN, p25, (drawMedian)?median:JKQTP_NAN, p75, (drawMinMax)?max:JKQTP_NAN, (drawMean)?mean:JKQTP_NAN, (drawMedian&&drawNotch)?medianu:JKQTP_NAN, (drawMedian&&drawNotch)?mediano:JKQTP_NAN); + if (JKQTPIsOKFloat(p25v) && JKQTPIsOKFloat(p75v)) { - painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();}); - painter.setBrush(b); - painter.drawRect(QRectF(xmi, p75, fabs(xma-xmi), fabs(p75-p25))); if (JKQTPIsOKFloat(p25v)) { QStringList sl=labelValues, sll=labelNames; sl[labQ25]="\\ul{"+sl[labQ25]+"}"; @@ -1201,8 +825,6 @@ void JKQTPBoxplotVerticalElement::draw(JKQTPEnhancedPainter& painter) { } if (drawMedian && JKQTPIsOKFloat(medianv)) { - painter.setPen(pm); - painter.drawLine(QLineF(xmi, median, xma, median)); if (JKQTPIsOKFloat(medianv)) { QStringList sl=labelValues, sll=labelNames; sl[labMedian]="\\ul{"+sl[labMedian]+"}"; @@ -1211,11 +833,6 @@ void JKQTPBoxplotVerticalElement::draw(JKQTPEnhancedPainter& painter) { } } if (drawMinMax) { - painter.setPen(pw); - if (JKQTPIsOKFloat(maxv)) painter.drawLine(QLineF(x-w/4.0, max, x+w/4.0, max)); - if (JKQTPIsOKFloat(minv)) painter.drawLine(QLineF(x-w/4.0, min, x+w/4.0, min)); - if (JKQTPIsOKFloat(maxv)) painter.drawLine(QLineF(x, max, x, p75)); - if (JKQTPIsOKFloat(minv)) painter.drawLine(QLineF(x, min, x, p25)); if (JKQTPIsOKFloat(minv)) { QStringList sl=labelValues, sll=labelNames; sl[labMin]="\\ul{"+sl[labMin]+"}"; @@ -1232,8 +849,6 @@ void JKQTPBoxplotVerticalElement::draw(JKQTPEnhancedPainter& painter) { if (drawMean && JKQTPIsOKFloat(meanv)) { - double mean=transformY(meanv); - plotStyledSymbol(parent, painter, x, mean); if (JKQTPIsOKFloat(meanv)) { QStringList sl=labelValues, sll=labelNames; sl[labMean]="\\ul{"+sl[labMean]+"}"; @@ -1327,6 +942,19 @@ double JKQTPBoxplotVerticalElement::getMedian() const return this->median; } +void JKQTPBoxplotVerticalElement::setMedianConfidenceIntervalWidth(double __value) +{ + if (this->medianConfidenceIntervalWidth != __value) { + this->medianConfidenceIntervalWidth = __value; + drawNotch=true; + } +} + +double JKQTPBoxplotVerticalElement::getMedianConfidenceIntervalWidth() const +{ + return this->medianConfidenceIntervalWidth; +} + void JKQTPBoxplotVerticalElement::setMean(double __value) { if (this->mean != __value) { @@ -1416,44 +1044,19 @@ bool JKQTPBoxplotVerticalElement::getDrawMinMax() const return this->drawMinMax; } +void JKQTPBoxplotVerticalElement::setDrawNotch(bool __value) +{ + drawNotch=__value; +} + +bool JKQTPBoxplotVerticalElement::getDrawNotch() const +{ + return drawNotch; +} + void JKQTPBoxplotVerticalElement::drawKeyMarker(JKQTPEnhancedPainter& painter, QRectF& rect) { - painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();}); - QPen p=getLinePenForRects(painter, parent); - QPen pw=getWhiskerPen(painter, parent); - QPen pm=getMedianPen(painter, parent); - QPen np(Qt::NoPen); - QBrush b=getFillBrush(painter, parent); - p.setWidthF(qMin(1.0, p.widthF())); - pw.setWidthF(qMin(1.0, pw.widthF())); - pm.setWidthF(qMin(1.0, pm.widthF())); - - - double x=rect.left()+rect.width()/2.0; - double xma=x+rect.width()/2.5; - double xmi=x-rect.width()/2.5; - double min=rect.bottom(); - double max=rect.top(); - double median=max+rect.height()/2.0; - double w=rect.width()/1.8; - double p25=max+0.75*rect.height(); - double p75=max+0.25*rect.height(); - - painter.setPen(p); - { - painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();}); - painter.setBrush(b); - painter.drawRect(QRectF(xmi, p75, fabs(xma-xmi), fabs(p75-p25))); - } - - painter.setPen(pm); - painter.drawLine(QLineF(xmi, median, xma, median)); - painter.setPen(pw); - painter.drawLine(QLineF(x-w/4.0, max, x+w/4.0, max)); - painter.drawLine(QLineF(x-w/4.0, min, x+w/4.0, min)); - painter.drawLine(QLineF(x, max, x, p75)); - painter.drawLine(QLineF(x, min, x, p25)); - + plotVerticalKeyMarker(parent, painter, rect); } QColor JKQTPBoxplotVerticalElement::getKeyLabelColor() const { @@ -1464,41 +1067,7 @@ QColor JKQTPBoxplotVerticalElement::getKeyLabelColor() const { void JKQTPBoxplotHorizontalElement::drawKeyMarker(JKQTPEnhancedPainter& painter, QRectF& rect) { - painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();}); - QPen p=getLinePenForRects(painter, parent); - QPen pw=getWhiskerPen(painter, parent); - QPen pm=getMedianPen(painter, parent); - QPen np(Qt::NoPen); - QBrush b=getFillBrush(painter, parent); - p.setWidthF(qMin(1.0, p.widthF())); - pw.setWidthF(qMin(1.0, pw.widthF())); - pm.setWidthF(qMin(1.0, pm.widthF())); - - double y=rect.top()+rect.height()/2.0; - double yma=y+rect.height()/2.5; - double ymi=y-rect.height()/2.5; - double min=rect.left(); - double max=rect.right(); - double median=max-rect.width()/2.0; - double w=rect.height()/1.8; - double p25=min+0.75*rect.width(); - double p75=min+0.25*rect.width(); - - painter.setPen(p); - { - painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();}); - painter.setBrush(b); - painter.drawRect(QRectF(p75, ymi, fabs(p75-p25), fabs(yma-ymi))); - } - - painter.setPen(pm); - painter.drawLine(QLineF(median, ymi, median, yma)); - painter.setPen(pw); - painter.drawLine(QLineF(max, y-w/4.0, max, y+w/4.0)); - painter.drawLine(QLineF(min, y-w/4.0, min, y+w/4.0)); - painter.drawLine(QLineF(max, y, p75, y)); - painter.drawLine(QLineF(min, y, p25, y)); - + plotHorizontalKeyMarker(parent, painter, rect); } bool JKQTPBoxplotHorizontalElement::getXMinMax(double& minx, double& maxx, double& smallestGreaterZero) { @@ -1576,17 +1145,13 @@ void JKQTPBoxplotHorizontalElement::draw(JKQTPEnhancedPainter& painter) { { painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();}); - QPen p=getLinePenForRects(painter, parent); - QPen pw=getWhiskerPen(painter, parent); - QPen pm=getMedianPen(painter, parent); - QPen np(Qt::NoPen); - QBrush b=getFillBrush(painter, parent); const double yv=pos; const double p25v=percentile25; const double p75v=percentile75; const double minv=min; const double maxv=max; const double medianv=median; + const double medConf=medianConfidenceIntervalWidth; const double meanv=mean; //std::cout<<"(xv, yv) = ( "<pt2px(painter, getBoxWidth()); + double w=parent->pt2px(painter,getBoxWidthAbsolute()); double yma=y+w/2.0; double ymi=y-w/2.0; - painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();}); - painter.setPen(p); + plotHorizontalBoxplot(parent, painter, y, ymi, yma, (drawMinMax)?min:JKQTP_NAN, p25, (drawMedian)?median:JKQTP_NAN, p75, (drawMinMax)?max:JKQTP_NAN, (drawMean)?mean:JKQTP_NAN, (drawMedian&&drawNotch)?medianu:JKQTP_NAN, (drawMedian&&drawNotch)?mediano:JKQTP_NAN); + if (JKQTPIsOKFloat(p25v) && JKQTPIsOKFloat(p75v)) { - painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();}); - painter.setBrush(b); - painter.drawRect(QRectF(p25, ymi, fabs(p75-p25), fabs(yma-ymi))); if (JKQTPIsOKFloat(p25v)) { QStringList sl=labelValues, sll=labelNames; sl[labQ25]="\\ul{"+sl[labQ25]+"}"; @@ -1637,20 +1208,13 @@ void JKQTPBoxplotHorizontalElement::draw(JKQTPEnhancedPainter& painter) { } if (drawMedian && JKQTPIsOKFloat(medianv)) { - painter.setPen(pm); - painter.drawLine(QLineF(median, ymi, median, yma)); - if (JKQTPIsOKFloat(medianv)) { + if (JKQTPIsOKFloat(medianv)) { QStringList sl=labelValues, sll=labelNames; sl[labMedian]="\\ul{"+sl[labMedian]+"}"; sll[labMedian]="\\ul{"+sll[labMedian]+"}"; addHitTestData(medianv, yv, "\\ensuremath{\\begin{bmatrix}"+sll.join("\\\\")+"\\end{bmatrix}\\;=\\;\\begin{bmatrix}"+sl.join("\\\\")+"\\end{bmatrix}}"); } } if (drawMinMax) { - painter.setPen(pw); - if (JKQTPIsOKFloat(maxv)) painter.drawLine(QLineF(max, y-w/4.0, max, y+w/4.0)); - if (JKQTPIsOKFloat(minv)) painter.drawLine(QLineF(min, y-w/4.0, min, y+w/4.0)); - if (JKQTPIsOKFloat(maxv)) painter.drawLine(QLineF(max, y, p75, y)); - if (JKQTPIsOKFloat(minv)) painter.drawLine(QLineF(min, y, p25, y)); if (JKQTPIsOKFloat(minv)) { QStringList sl=labelValues, sll=labelNames; sl[labMin]="\\ul{"+sl[labMin]+"}"; @@ -1667,8 +1231,6 @@ void JKQTPBoxplotHorizontalElement::draw(JKQTPEnhancedPainter& painter) { if (drawMean && JKQTPIsOKFloat(meanv)) { - double mean=transformY(meanv); - plotStyledSymbol(parent, painter, mean, y); if (JKQTPIsOKFloat(meanv)) { QStringList sl=labelValues, sll=labelNames; sl[labMean]="\\ul{"+sl[labMean]+"}"; @@ -1697,7 +1259,7 @@ void JKQTPBoxplotVerticalGraph::intSortData() JKQTPDatastore* datastore=parent->getDatastore(); int imin=0; - int imax=datastore->getColumn(posColumn).getRows(); + int imax=static_cast(datastore->getColumn(static_cast(posColumn)).getRows()); if (imaxget(posColumn,i); + double xv=datastore->get(posColumn,static_cast(i)); sortedIndices< &pattern); - /** \brief gets the dash pattern for a custom dash style of whisker lines - * \see https://doc.qt.io/qt-5/qpen.html#setDashPattern - */ - QVector getWhiskerLineDashPattern() const; - /** \brief sets the join style of whisker lines - * \see https://doc.qt.io/qt-5/qpen.html#setJoinStyle - */ - void setWhiskerLineJoinStyle(Qt::PenJoinStyle style); - /** \brief returns the join style of whisker lines - * \see https://doc.qt.io/qt-5/qpen.html#setJoinStyle - */ - Qt::PenJoinStyle getWhiskerLineJoinStyle() const; - /** \brief sets the cap style of whisker lines - * \see https://doc.qt.io/qt-5/qpen.html#setCapStyle - */ - void setWhiskerLineCapStyle(Qt::PenCapStyle style); - /** \brief gets the cap style of whisker lines - * \see https://doc.qt.io/qt-5/qpen.html#setCapStyle - */ - Qt::PenCapStyle getWhiskerLineCapStyle() const; - /** \brief sets the brush used to fill the line area of whisker lines - * \see https://doc.qt.io/qt-5/qpen.html#setBrush - */ - void setWhiskerLineBrush(const QBrush& style); - /** \brief gets the brush used to fill the line area of whisker lines - * \see https://doc.qt.io/qt-5/qpen.html#setBrush - */ - QBrush getWhiskerLineBrush() const; - - /** \brief build a pen to be used for drawing whiskers */ - QPen getWhiskerPen(JKQTPEnhancedPainter &painter, JKQTBasePlotter *parent) const; - - - - - - - - /*! \brief set the line style of median lines */ - void setMedianLineStyle(Qt::PenStyle __value); - /*! \brief get the line style of median lines */ - Qt::PenStyle getMedianLineStyle() const; - - /*! \brief set the width [pt] of median lines */ - void setMedianLineWidth(double __value); - /*! \brief get the width [pt] of median lines */ - double getMedianLineWidth() const; - - /*! \brief set the color of median lines */ - void setMedianLineColor(QColor __value); - /*! \brief get the color of median lines */ - QColor getMedianLineColor() const; - - - /** \brief sets the dash offset for a custom dash style of median lines - * \see https://doc.qt.io/qt-5/qpen.html#setDashOffset - */ - void setMedianLineDashOffset(qreal offset); - /** \brief returns the dash offset for a custom dash style of median lines - * \see https://doc.qt.io/qt-5/qpen.html#setDashOffset - */ - qreal getMedianLineDashOffset() const; - /** \brief sets the dash pattern for a custom dash style of median lines - * \see https://doc.qt.io/qt-5/qpen.html#setDashPattern - */ - void setMedianLineDashPattern(const QVector &pattern); - /** \brief gets the dash pattern for a custom dash style of median lines - * \see https://doc.qt.io/qt-5/qpen.html#setDashPattern - */ - QVector getMedianLineDashPattern() const; - /** \brief sets the join style of median lines - * \see https://doc.qt.io/qt-5/qpen.html#setJoinStyle - */ - void setMedianLineJoinStyle(Qt::PenJoinStyle style); - /** \brief returns the join style of median lines - * \see https://doc.qt.io/qt-5/qpen.html#setJoinStyle - */ - Qt::PenJoinStyle getMedianLineJoinStyle() const; - /** \brief sets the cap style of median lines - * \see https://doc.qt.io/qt-5/qpen.html#setCapStyle - */ - void setMedianLineCapStyle(Qt::PenCapStyle style); - /** \brief gets the cap style of median lines - * \see https://doc.qt.io/qt-5/qpen.html#setCapStyle - */ - Qt::PenCapStyle getMedianLineCapStyle() const; - /** \brief sets the brush used to fill the line area of median lines - * \see https://doc.qt.io/qt-5/qpen.html#setBrush - */ - void setMedianLineBrush(const QBrush& style); - /** \brief gets the brush used to fill the line area of median lines - * \see https://doc.qt.io/qt-5/qpen.html#setBrush - */ - QBrush getMedianLineBrush() const; - - /** \brief build a pen to be used for drawing medians */ - QPen getMedianPen(JKQTPEnhancedPainter &painter, JKQTBasePlotter *parent) const; - - protected: - /*! \brief set the color of the graph (colors all elements, based on the given color \a c )*/ - void setBoxplotColor(QColor c, JKQTBasePlotter *parent); - private: - /** \brief line style of the whisker lines */ - QPen m_whiskerLinePen; - /** \brief line width (in pt) of the whisker lines */ - double whiskerLineWidth; - /** \brief line style of the median lines */ - QPen m_medianLinePen; - /** \brief line width (in pt) of the median lines */ - double medianLineWidth; - /** \brief width of box in percent of distance between the current two posColumn values - * if we only plot one box&whiskers then this is the width in pt */ - double boxWidth; - -}; - - - - - - -/*! \brief This implements vertical boxplots +/*! \brief This implements vertical boxplots, optionally also a notched boxplot \ingroup jkqtplotter_statgraphs The x position is given in posColumn. All other data are given in the medianColumn, minColumn, maxColumn, @@ -213,9 +43,15 @@ class JKQTP_LIB_EXPORT JKQTPGraphBoxplotStyleMixin: public JKQTPGraphLineStyleMi \image html plot_boxplotvertical.png + The different features of a boxplot are: - \image html boxplots.png + \image html plot_boxplotverticalelement.png + + + The example \ref JKQTPlotterBoxplotStyling discusses different options to style boxplots: + + \image html test_styledboxplot.png This class also implements hitTest() in a way that displays all data of the boxplot in the tooltips: @@ -381,14 +217,43 @@ class JKQTP_LIB_EXPORT JKQTPBoxplotVerticalGraph: public JKQTPGraph, public JKQT \details Description of the parameter percentile75Column is:
    \copydoc percentile75Column
    \see percentile75Column for more information */ void setPercentile75Column (size_t __value); + /*! \copydoc medianConfidenceColumn + \see see medianConfidenceColumn for details */ + int getMedianConfidenceColumn() const; + /*! \brief sets the property medianConfidenceColumn ( \copybrief medianConfidenceColumn ) to the specified \a __value, where __value is static_cast'ed from size_t to int. + \details Description of the parameter medianConfidenceColumn is:
    \copydoc medianConfidenceColumn
    + \see medianConfidenceColumn for more information */ + void setMedianConfidenceColumn (size_t __value); + /*! \copydoc boxWidthRelative + \see see boxWidthRelative for details */ + void setBoxWidthRelative(double __value); + /*! \copydoc boxWidthRelative + \see see boxWidthRelative for details */ + double getBoxWidthRelative() const; + + + /*! \copydoc useRelativeBoxWidth + \see see useRelativeBoxWidth for details */ + void setUseRelativeBoxWidth(bool __value); + /*! \copydoc useRelativeBoxWidth + \see see useRelativeBoxWidth for details */ + bool getUseRelativeBoxWidth() const; protected: + /** \brief width of box in percent of distance between the current two posColumn values + * if we only plot one box&whiskers then JKQTPGraphBoxplotStyleMixin::boxWidthAbsolute in pt is used */ + double boxWidthRelative; + /** \brief if set \c true, boxplot widths are calculated automatically, based on boxWidthRelative, + * otherwise JKQTPGraphBoxplotStyleMixin::boxWidthAbsolute is used. */ + bool useRelativeBoxWidth; /** \brief the column that contains the x-component of the datapoints */ int posColumn; /** \brief the column that contains the median-component of the datapoints */ int medianColumn; + /** \brief the column that contains the confidence interval width of the median (e.g. 1.57*IQR/sqrt(n) ). This is used to draw a notch in the plot (if set) */ + int medianConfidenceColumn; /** \brief the column that contains the median-component of the datapoints. \note This column is strictly optional. */ int meanColumn; /** \brief the column that contains the minimum-component of the datapoints */ @@ -414,7 +279,7 @@ class JKQTP_LIB_EXPORT JKQTPBoxplotVerticalGraph: public JKQTPGraph, public JKQT }; -/*! \brief This implements horizontal boxplots +/*! \brief This implements horizontal boxplots, optionally also a notched boxplot \ingroup jkqtplotter_statgraphs the x position is given in posColumn. All other data are given in the medianColumn, minColumn, maxColumn, @@ -459,20 +324,25 @@ class JKQTP_LIB_EXPORT JKQTPBoxplotHorizontalGraph: public JKQTPBoxplotVerticalG -/*! \brief This implements a single vertical boxplot as a "geometric element", +/*! \brief This implements a single vertical (notched) boxplot as a "geometric element", where the data is directly given to the object and not stored in a column, as in JKQTPBoxplotVerticalGraph \ingroup jkqtplotter_statgraphs \ingroup jkqtplotter_geoplots - \image html plot_boxplotverticalelement.png the x position is given in posColumn. All other data are given in the median, min, max, percentile25 and percentile75. The different features of a boxplot are: - \image html boxplots.png + \image html plot_boxplotverticalelement.png + + + The example \ref JKQTPlotterBoxplotStyling discusses different options to style boxplots: + + \image html test_styledboxplot.png + */ class JKQTP_LIB_EXPORT JKQTPBoxplotVerticalElement: public JKQTPPlotObject, public JKQTPGraphBoxplotStyleMixin { Q_OBJECT @@ -563,14 +433,30 @@ class JKQTP_LIB_EXPORT JKQTPBoxplotVerticalElement: public JKQTPPlotObject, publ /*! \copydoc drawMinMax \see see drawMinMax for details */ bool getDrawMinMax() const; + /*! \copydoc drawNotch + \see see drawNotch for details */ + void setDrawNotch(bool __value); + /*! \copydoc drawNotch + \see see drawNotch for details */ + bool getDrawNotch() const; + /*! \copydoc medianConfidenceIntervalWidth + \see see medianConfidenceIntervalWidth for details */ + double getMedianConfidenceIntervalWidth() const; + /*! \copydoc medianConfidenceIntervalWidth + \see see medianConfidenceIntervalWidth for details */ + void setMedianConfidenceIntervalWidth(double __value); protected: - /** \brief the column that contains the x-component of the datapoints */ + /** \brief the position of the boxplot on the "other" axis */ double pos; - /** \brief the column that contains the median-component of the datapoints */ + /** \brief the median value to be used for the boxplot */ double median; - /** \brief the column that contains the median-component of the datapoints. \note This column is strictly optional. */ + /** \brief the width of the confidence interval around the median */ + double medianConfidenceIntervalWidth; + /** \brief indicates whether to draw a notch with width medianConfidenceIntervalWidth */ + bool drawNotch; + /** \brief the mean value to be used for the boxplot */ double mean; /** \brief indicates whether to draw the mean */ bool drawMean; @@ -578,18 +464,18 @@ class JKQTP_LIB_EXPORT JKQTPBoxplotVerticalElement: public JKQTPPlotObject, publ bool drawMedian; /** \brief indicates whether to draw the percentiles */ bool drawMinMax; - /** \brief the column that contains the minimum-component of the datapoints */ + /** \brief the minimum value to be used for the boxplot */ double min; - /** \brief the column that contains the maximum-component of the datapoints */ + /** \brief the maximum value to be used for the boxplot */ double max; - /** \brief the column that contains the 25% percentile-component of the datapoints */ + /** \brief the 25% percentile value to be used for the boxplot */ double percentile25; - /** \brief the column that contains the 75% percentile-component of the datapoints */ + /** \brief the 75% percentile value to be used for the boxplot */ double percentile75; }; -/*! \brief This implements a horizontal boxplot where the data is directly given to the +/*! \brief This implements a horizontal (notched) boxplot where the data is directly given to the object and not stored in a column, as in JKQTPBoxplotVerticalGraph \ingroup jkqtplotter_statgraphs \ingroup jkqtplotter_geoplots diff --git a/lib/jkqtplotter/jkqtpgraphsboxplotstylingmixins.cpp b/lib/jkqtplotter/jkqtpgraphsboxplotstylingmixins.cpp new file mode 100644 index 0000000000..95a973af5c --- /dev/null +++ b/lib/jkqtplotter/jkqtpgraphsboxplotstylingmixins.cpp @@ -0,0 +1,785 @@ +/* + Copyright (c) 2008-2019 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/jkqtpgraphsboxplotstylingmixins.h" +#include "jkqtplotter/jkqtpbaseplotter.h" +#include +#include +#include +#include "jkqtplottertools/jkqtptools.h" +#include "jkqtplotter/jkqtpgraphsimage.h" +#include "jkqtplotter/jkqtpbaseelements.h" +#include "jkqtplotter/jkqtplotter.h" + + + +JKQTPGraphBoxplotStyleMixin::JKQTPGraphBoxplotStyleMixin() +{ + + m_whiskerLinePen=QPen(getLineColor(), getLineWidth()); + whiskerLineWidth=getLineWidth(); + m_whiskerCapLinePen=QPen(getLineColor(), getLineWidth()); + whiskerCapLineWidth=getLineWidth(); + m_medianLinePen=QPen(getLineColor(), getLineWidth()); + medianLineWidth=getLineWidth(); + + m_meanSymbolLinePen=QPen(getLineColor(), getLineWidth()); + m_meanSymbolLineWidth=1; + meanMode=MeanAsSymbol; + m_meanSymbolType=JKQTPGraphSymbols::JKQTPDefaultSymbol; + m_meanSymbolSize=12; + m_meanSymbolFillColor=m_meanSymbolLinePen.color().lighter(); + + + boxWidthAbsolute=m_meanSymbolSize*3.0; + relativeWhiskerWidth=0.5; + relativeNotchIndent=0.25; + drawBox=true; + +} + + +void JKQTPGraphBoxplotStyleMixin::initBoxplotStyle(JKQTBasePlotter *parent, int &parentPlotStyle) +{ + setFillStyle(Qt::SolidPattern); + setFillColor(parent->getCurrentPlotterStyle().plotBackgroundBrush.color()); + initLineStyle(parent, parentPlotStyle); + if (parent) { // get style settings from parent object + if (parentPlotStyle<0) parentPlotStyle=parent->getNextStyle(); + m_whiskerLinePen.setColor(parent->getPlotStyle(parentPlotStyle).color()); + m_whiskerLinePen.setStyle(parent->getPlotStyle(parentPlotStyle).style()); + whiskerLineWidth=parent->getPlotStyle(parentPlotStyle).widthF(); + m_whiskerCapLinePen.setColor(parent->getPlotStyle(parentPlotStyle).color()); + m_whiskerCapLinePen.setStyle(parent->getPlotStyle(parentPlotStyle).style()); + whiskerCapLineWidth=parent->getPlotStyle(parentPlotStyle).widthF(); + m_medianLinePen.setColor(parent->getPlotStyle(parentPlotStyle).color()); + m_medianLinePen.setStyle(parent->getPlotStyle(parentPlotStyle).style()); + medianLineWidth=parent->getPlotStyle(parentPlotStyle).widthF(); + m_meanSymbolLinePen=QPen(parent->getPlotStyle(parentPlotStyle).color(), parent->getPlotStyle(parentPlotStyle).style()); + m_meanSymbolSize=parent->getPlotStyle(parentPlotStyle).symbolSize(); + m_meanSymbolLineWidth=parent->getPlotStyle(parentPlotStyle).symbolLineWidthF(); + m_meanSymbolType=parent->getPlotStyle(parentPlotStyle).symbol(); + m_meanSymbolFillColor=parent->getPlotStyle(parentPlotStyle).symbolFillColor(); + } + + setWhiskerLineColor(getLineColor()); + setWhiskerCapLineColor(getLineColor()); + setMedianLineColor(getLineColor()); + + if (m_meanSymbolSize>0) { + boxWidthAbsolute=m_meanSymbolSize*3.0; + } +} + +void JKQTPGraphBoxplotStyleMixin::setBoxWidthAbsolute(double __value) +{ + boxWidthAbsolute=__value; +} + +double JKQTPGraphBoxplotStyleMixin::getBoxWidthAbsolute() const +{ + return boxWidthAbsolute; +} + +void JKQTPGraphBoxplotStyleMixin::setBoxplotColor(QColor c, JKQTBasePlotter *parent) +{ + setLineColor(c); + setFillColor(JKQTPGetDerivedColor(parent->getCurrentPlotterStyle().graphFillColorDerivationMode, c)); + setMeanColor(c); + setMeanFillColor(JKQTPGetDerivedColor(parent->getCurrentPlotterStyle().graphFillColorDerivationMode, c)); + setWhiskerLineColor(getLineColor()); + setWhiskerCapLineColor(getLineColor()); + setMedianLineColor(getLineColor()); + c.setAlphaF(0.5); + setHighlightingLineColor(c); +} + +void JKQTPGraphBoxplotStyleMixin::setBoxplotColor(QColor c, QColor bc, JKQTBasePlotter *parent) +{ + setBoxplotColor(c, parent); + setFillColor(bc); + setMeanFillColor(bc); +} + +void JKQTPGraphBoxplotStyleMixin::setDrawBox(bool __value) +{ + drawBox=__value; +} + +bool JKQTPGraphBoxplotStyleMixin::getDrawBox() const +{ + return drawBox; +} + +void JKQTPGraphBoxplotStyleMixin::setRelativeWhiskerWidth(double __value) +{ + relativeWhiskerWidth=__value; +} + +double JKQTPGraphBoxplotStyleMixin::getRelativeWhiskerWidth() const +{ + return relativeWhiskerWidth; +} + +void JKQTPGraphBoxplotStyleMixin::setRelativeNotchIndent(double __value) +{ + relativeNotchIndent=__value; +} + +double JKQTPGraphBoxplotStyleMixin::getRelativeNotchIndent() const +{ + return relativeNotchIndent; +} + +void JKQTPGraphBoxplotStyleMixin::setMeanMode(JKQTPGraphBoxplotStyleMixin::MeanMode __value) +{ + meanMode=__value; +} + +JKQTPGraphBoxplotStyleMixin::MeanMode JKQTPGraphBoxplotStyleMixin::getMeanMode() const +{ + return meanMode; +} + + + + + + + +void JKQTPGraphBoxplotStyleMixin::setMeanSymbolType(JKQTPGraphSymbols __value) +{ + m_meanSymbolType=__value; +} + +JKQTPGraphSymbols JKQTPGraphBoxplotStyleMixin::getMeanSymbolType() const +{ + return m_meanSymbolType; +} + +void JKQTPGraphBoxplotStyleMixin::setMeanSize(double __value) +{ + m_meanSymbolSize=__value; +} + +double JKQTPGraphBoxplotStyleMixin::getMeanSize() const +{ + return m_meanSymbolSize; +} + +void JKQTPGraphBoxplotStyleMixin::setMeanColor(const QColor &__value) +{ + m_meanSymbolLinePen.setColor(__value); +} + +QColor JKQTPGraphBoxplotStyleMixin::getMeanColor() const +{ + return m_meanSymbolLinePen.color(); +} + +void JKQTPGraphBoxplotStyleMixin::setMeanFillColor(const QColor &__value) +{ + m_meanSymbolFillColor=__value; +} + +QColor JKQTPGraphBoxplotStyleMixin::getMeanFillColor() const +{ + return m_meanSymbolFillColor; +} + +void JKQTPGraphBoxplotStyleMixin::setMeanLineWidth(double __value) +{ + m_meanSymbolLineWidth=__value; +} + +double JKQTPGraphBoxplotStyleMixin::getMeanLineWidth() const +{ + return m_meanSymbolLineWidth; +} + + +void JKQTPGraphBoxplotStyleMixin::setMeanLineStyle(Qt::PenStyle __value) +{ + this->m_meanSymbolLinePen.setStyle(__value); +} + +Qt::PenStyle JKQTPGraphBoxplotStyleMixin::getMeanLineStyle() const +{ + return this->m_meanSymbolLinePen.style(); +} + + +void JKQTPGraphBoxplotStyleMixin::setMeanLineDashOffset(qreal offset) +{ + m_meanSymbolLinePen.setDashOffset(offset); +} + +qreal JKQTPGraphBoxplotStyleMixin::getMeanLineDashOffset() const +{ + return m_meanSymbolLinePen.dashOffset(); +} + +void JKQTPGraphBoxplotStyleMixin::setMeanLineDashPattern(const QVector &pattern) +{ + m_meanSymbolLinePen.setDashPattern(pattern); + m_meanSymbolLinePen.setStyle(Qt::CustomDashLine); +} + +QVector JKQTPGraphBoxplotStyleMixin::getMeanLineDashPattern() const +{ + return m_meanSymbolLinePen.dashPattern(); +} + +void JKQTPGraphBoxplotStyleMixin::setMedianLineWidth(double __value) +{ + medianLineWidth=__value; +} + +double JKQTPGraphBoxplotStyleMixin::getMedianLineWidth() const +{ + return medianLineWidth; +} + +void JKQTPGraphBoxplotStyleMixin::setMedianLineColor(QColor __value) +{ + m_medianLinePen.setColor(__value); +} + +QColor JKQTPGraphBoxplotStyleMixin::getMedianLineColor() const +{ + return m_medianLinePen.color(); +} + +void JKQTPGraphBoxplotStyleMixin::setMedianLineStyle(Qt::PenStyle __value) +{ + this->m_medianLinePen.setStyle(__value); +} + +Qt::PenStyle JKQTPGraphBoxplotStyleMixin::getMedianLineStyle() const +{ + return this->m_medianLinePen.style(); +} + + +void JKQTPGraphBoxplotStyleMixin::setMedianLineDashOffset(qreal offset) +{ + m_medianLinePen.setDashOffset(offset); +} + +qreal JKQTPGraphBoxplotStyleMixin::getMedianLineDashOffset() const +{ + return m_medianLinePen.dashOffset(); +} + +void JKQTPGraphBoxplotStyleMixin::setMedianLineDashPattern(const QVector &pattern) +{ + m_medianLinePen.setDashPattern(pattern); + m_medianLinePen.setStyle(Qt::CustomDashLine); +} + +QVector JKQTPGraphBoxplotStyleMixin::getMedianLineDashPattern() const +{ + return m_medianLinePen.dashPattern(); +} + +void JKQTPGraphBoxplotStyleMixin::setMedianLineJoinStyle(Qt::PenJoinStyle style) +{ + m_medianLinePen.setJoinStyle(style); +} + +Qt::PenJoinStyle JKQTPGraphBoxplotStyleMixin::getMedianLineJoinStyle() const +{ + return m_medianLinePen.joinStyle(); +} + +void JKQTPGraphBoxplotStyleMixin::setMedianLineCapStyle(Qt::PenCapStyle style) +{ + m_medianLinePen.setCapStyle(style); +} + +Qt::PenCapStyle JKQTPGraphBoxplotStyleMixin::getMedianLineCapStyle() const +{ + return m_medianLinePen.capStyle(); +} + +void JKQTPGraphBoxplotStyleMixin::setMedianLineBrush(const QBrush &style) +{ + m_medianLinePen.setBrush(style); +} + +QBrush JKQTPGraphBoxplotStyleMixin::getMedianLineBrush() const +{ + return m_medianLinePen.brush(); +} + +void JKQTPGraphBoxplotStyleMixin::setWhiskerLineStyle(Qt::PenStyle __value) +{ + this->m_whiskerLinePen.setStyle(__value); +} + +Qt::PenStyle JKQTPGraphBoxplotStyleMixin::getWhiskerLineStyle() const +{ + return this->m_whiskerLinePen.style(); +} + + +void JKQTPGraphBoxplotStyleMixin::setWhiskerLineWidth(double __value) +{ + whiskerLineWidth=__value; +} + +double JKQTPGraphBoxplotStyleMixin::getWhiskerLineWidth() const +{ + return whiskerLineWidth; +} + +void JKQTPGraphBoxplotStyleMixin::setWhiskerLineColor(QColor __value) +{ + m_whiskerLinePen.setColor(__value); +} + +QColor JKQTPGraphBoxplotStyleMixin::getWhiskerLineColor() const +{ + return m_whiskerLinePen.color(); +} + +void JKQTPGraphBoxplotStyleMixin::setWhiskerLineDashOffset(qreal offset) +{ + m_whiskerLinePen.setDashOffset(offset); +} + +qreal JKQTPGraphBoxplotStyleMixin::getWhiskerLineDashOffset() const +{ + return m_whiskerLinePen.dashOffset(); +} + +void JKQTPGraphBoxplotStyleMixin::setWhiskerLineDashPattern(const QVector &pattern) +{ + m_whiskerLinePen.setDashPattern(pattern); + m_whiskerLinePen.setStyle(Qt::CustomDashLine); +} + +QVector JKQTPGraphBoxplotStyleMixin::getWhiskerLineDashPattern() const +{ + return m_whiskerLinePen.dashPattern(); +} + +void JKQTPGraphBoxplotStyleMixin::setWhiskerLineJoinStyle(Qt::PenJoinStyle style) +{ + m_whiskerLinePen.setJoinStyle(style); +} + +Qt::PenJoinStyle JKQTPGraphBoxplotStyleMixin::getWhiskerLineJoinStyle() const +{ + return m_whiskerLinePen.joinStyle(); +} + +void JKQTPGraphBoxplotStyleMixin::setWhiskerLineCapStyle(Qt::PenCapStyle style) +{ + m_whiskerLinePen.setCapStyle(style); +} + +Qt::PenCapStyle JKQTPGraphBoxplotStyleMixin::getWhiskerLineCapStyle() const +{ + return m_whiskerLinePen.capStyle(); +} + +void JKQTPGraphBoxplotStyleMixin::setWhiskerLineBrush(const QBrush &style) +{ + m_whiskerLinePen.setBrush(style); +} + +QBrush JKQTPGraphBoxplotStyleMixin::getWhiskerLineBrush() const +{ + return m_whiskerLinePen.brush(); +} + +QPen JKQTPGraphBoxplotStyleMixin::getWhiskerPen(JKQTPEnhancedPainter &painter, JKQTBasePlotter *parent) const +{ + QPen pw=m_whiskerLinePen; + pw.setWidthF(qMax(JKQTPlotterDrawinTools::ABS_MIN_LINEWIDTH,parent->pt2px(painter, parent->getLineWidthMultiplier()*whiskerLineWidth))); + pw.setJoinStyle(Qt::MiterJoin); + pw.setCapStyle(Qt::FlatCap); + return pw; +} + + + + + + + + +void JKQTPGraphBoxplotStyleMixin::setWhiskerCapLineStyle(Qt::PenStyle __value) +{ + this->m_whiskerCapLinePen.setStyle(__value); +} + +Qt::PenStyle JKQTPGraphBoxplotStyleMixin::getWhiskerCapLineStyle() const +{ + return this->m_whiskerCapLinePen.style(); +} + + +void JKQTPGraphBoxplotStyleMixin::setWhiskerCapLineWidth(double __value) +{ + whiskerCapLineWidth=__value; +} + +double JKQTPGraphBoxplotStyleMixin::getWhiskerCapLineWidth() const +{ + return whiskerCapLineWidth; +} + +void JKQTPGraphBoxplotStyleMixin::setWhiskerCapLineColor(QColor __value) +{ + m_whiskerCapLinePen.setColor(__value); +} + +QColor JKQTPGraphBoxplotStyleMixin::getWhiskerCapLineColor() const +{ + return m_whiskerCapLinePen.color(); +} + +void JKQTPGraphBoxplotStyleMixin::setWhiskerCapLineDashOffset(qreal offset) +{ + m_whiskerCapLinePen.setDashOffset(offset); +} + +qreal JKQTPGraphBoxplotStyleMixin::getWhiskerCapLineDashOffset() const +{ + return m_whiskerCapLinePen.dashOffset(); +} + +void JKQTPGraphBoxplotStyleMixin::setWhiskerCapLineDashPattern(const QVector &pattern) +{ + m_whiskerCapLinePen.setDashPattern(pattern); + m_whiskerCapLinePen.setStyle(Qt::CustomDashLine); +} + +QVector JKQTPGraphBoxplotStyleMixin::getWhiskerCapLineDashPattern() const +{ + return m_whiskerCapLinePen.dashPattern(); +} + +void JKQTPGraphBoxplotStyleMixin::setWhiskerCapLineJoinStyle(Qt::PenJoinStyle style) +{ + m_whiskerCapLinePen.setJoinStyle(style); +} + +Qt::PenJoinStyle JKQTPGraphBoxplotStyleMixin::getWhiskerCapLineJoinStyle() const +{ + return m_whiskerCapLinePen.joinStyle(); +} + +void JKQTPGraphBoxplotStyleMixin::setWhiskerCapLineCapStyle(Qt::PenCapStyle style) +{ + m_whiskerCapLinePen.setCapStyle(style); +} + +Qt::PenCapStyle JKQTPGraphBoxplotStyleMixin::getWhiskerCapLineCapStyle() const +{ + return m_whiskerCapLinePen.capStyle(); +} + +void JKQTPGraphBoxplotStyleMixin::setWhiskerCapLineBrush(const QBrush &style) +{ + m_whiskerCapLinePen.setBrush(style); +} + +QBrush JKQTPGraphBoxplotStyleMixin::getWhiskerCapLineBrush() const +{ + return m_whiskerCapLinePen.brush(); +} + +QPen JKQTPGraphBoxplotStyleMixin::getWhiskerCapPen(JKQTPEnhancedPainter &painter, JKQTBasePlotter *parent) const +{ + QPen pw=m_whiskerCapLinePen; + pw.setWidthF(qMax(JKQTPlotterDrawinTools::ABS_MIN_LINEWIDTH,parent->pt2px(painter, parent->getLineWidthMultiplier()*whiskerCapLineWidth))); + pw.setJoinStyle(Qt::MiterJoin); + return pw; +} + + + + + + + + + +QPen JKQTPGraphBoxplotStyleMixin::getMedianPen(JKQTPEnhancedPainter &painter, JKQTBasePlotter *parent) const +{ + QPen pw=m_medianLinePen; + pw.setWidthF(qMax(JKQTPlotterDrawinTools::ABS_MIN_LINEWIDTH,parent->pt2px(painter, parent->getLineWidthMultiplier()*medianLineWidth))); + pw.setJoinStyle(Qt::MiterJoin); + pw.setCapStyle(Qt::FlatCap); + return pw; +} + +QPen JKQTPGraphBoxplotStyleMixin::getMeanSymbolPen(JKQTPEnhancedPainter& painter, JKQTBasePlotter* parent) const { + QPen p=m_meanSymbolLinePen; + p.setWidthF(qMax(JKQTPlotterDrawinTools::ABS_MIN_LINEWIDTH,parent->pt2px(painter, parent->getLineWidthMultiplier()*m_meanSymbolLineWidth))); + p.setStyle(Qt::SolidLine); + p.setJoinStyle(Qt::RoundJoin); + p.setCapStyle(Qt::RoundCap); + return p; +} + +QPen JKQTPGraphBoxplotStyleMixin::getMeanLinePen(JKQTPEnhancedPainter& painter, JKQTBasePlotter* parent) const { + QPen p=m_meanSymbolLinePen; + p.setWidthF(qMax(JKQTPlotterDrawinTools::ABS_MIN_LINEWIDTH,parent->pt2px(painter, parent->getLineWidthMultiplier()*m_meanSymbolLineWidth))); + p.setJoinStyle(Qt::MiterJoin); + p.setCapStyle(Qt::FlatCap); + return p; +} + +QBrush JKQTPGraphBoxplotStyleMixin::getMeanSymbolBrush(JKQTPEnhancedPainter& /*painter*/, JKQTBasePlotter* /*parent*/) const { + QBrush b; + b.setColor(m_meanSymbolFillColor); + return b; +} + +void JKQTPGraphBoxplotStyleMixin::plotStyledMeanSymbol(JKQTBasePlotter *parent, JKQTPEnhancedPainter &painter, double x, double y) const +{ + JKQTPPlotSymbol(painter, x, y,m_meanSymbolType, parent->pt2px(painter, m_meanSymbolSize), parent->pt2px(painter, m_meanSymbolLineWidth*parent->getLineWidthMultiplier()), m_meanSymbolLinePen.color(), m_meanSymbolFillColor); +} + + + +void JKQTPGraphBoxplotStyleMixin::plotVerticalBoxplot(JKQTBasePlotter *parent, JKQTPEnhancedPainter &painter, double xp, double xpleft, double xpright, double minp, double q25p, double medianp, double q75p, double maxp, double meanp, double notchLowerp, double notchUpperp) const +{ + if (JKQTPIsOKFloat(xp) ) { + painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();}); + painter.setBrush(Qt::NoBrush); + + + double minstop=q25p; + double maxstop=q75p; + if (!JKQTPIsOKFloat(minstop) && JKQTPIsOKFloat(medianp)) minstop=medianp; + else if (!JKQTPIsOKFloat(minstop) && JKQTPIsOKFloat(meanp)) minstop=meanp; + else if (!JKQTPIsOKFloat(minstop) && JKQTPIsOKFloat(maxp)) minstop=maxp; + if (!JKQTPIsOKFloat(maxstop) && JKQTPIsOKFloat(medianp)) maxstop=medianp; + else if (!JKQTPIsOKFloat(maxstop) && JKQTPIsOKFloat(meanp)) maxstop=meanp; + else if (!JKQTPIsOKFloat(maxstop) && JKQTPIsOKFloat(minp)) maxstop=minp; + const double wl=fabs(xpright-xp); + const double wr=fabs(xpleft-xp); + const double xprightWhisker=xp+wr*getRelativeWhiskerWidth(); + const double xpleftWhisker=xp-wl*getRelativeWhiskerWidth(); + + // whisker lines + painter.setPen(getWhiskerPen(painter, parent)); + if (JKQTPIsOKFloat(minp) && JKQTPIsOKFloat(minstop)) { + painter.drawLine(QLineF(xp, minp, xp, minstop)); + } + if (JKQTPIsOKFloat(maxp) && JKQTPIsOKFloat(maxstop)) { + painter.drawLine(QLineF(xp, maxp, xp, maxstop)); + } + + // whisker caps + if (JKQTPIsOKFloat(xpleftWhisker) && JKQTPIsOKFloat(xprightWhisker)){ + painter.setPen(getWhiskerCapPen(painter, parent)); + if (JKQTPIsOKFloat(minp)) { + painter.drawLine(QLineF(xpleftWhisker, minp, xprightWhisker, minp)); + } + if (JKQTPIsOKFloat(maxp)) { + painter.drawLine(QLineF(xpleftWhisker, maxp, xprightWhisker, maxp)); + } + } + + // draw main box + double medianMin=xpleft; + double medianMax=xpright; + if (JKQTPIsOKFloat(q25p) && JKQTPIsOKFloat(q75p) && getDrawBox()) { + painter.setPen(getLinePenForRects(painter, parent)); + painter.setBrush(getFillBrush(painter, parent)); + if (getDrawBox()) { + QPolygonF poly; + if (JKQTPIsOKFloat(notchLowerp) && JKQTPIsOKFloat(notchUpperp)) { + // notched boxplot + poly<) + + + + 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 +#include +#include "jkqtplottertools/jkqtptools.h" +#include "jkqtplottertools/jkqtp_imexport.h" +#include "jkqtplotter/jkqtpgraphsbase.h" +#include "jkqtplotter/jkqtpgraphsbasestylingmixins.h" + +#ifndef jkqtpgraphsboxplotstylingmixins_H +#define jkqtpgraphsboxplotstylingmixins_H + + + + + +/*! \brief Styling Mix-In for Boxplots + \ingroup jkqtplotter_basegraphs_stylemixins + + + \image html plot_boxplothorizontalelement.png + + The example \ref JKQTPlotterBoxplotStyling discusses different options to style boxplots: + + \image html test_styledboxplot.png + */ +class JKQTP_LIB_EXPORT JKQTPGraphBoxplotStyleMixin: public JKQTPGraphLineStyleMixin, public JKQTPGraphFillStyleMixin { + Q_GADGET + public: + /** \brief class constructor */ + JKQTPGraphBoxplotStyleMixin(); + + void initBoxplotStyle(JKQTBasePlotter* parent, int &parentPlotStyle); + /*! \copydoc boxWidthAbsolute + \see see boxWidthAbsolute for details */ + void setBoxWidthAbsolute(double __value); + /*! \copydoc boxWidthAbsolute + \see see boxWidthAbsolute for details */ + double getBoxWidthAbsolute() const; + + /*! \copydoc drawBox + \see see drawBox for details */ + void setDrawBox(bool __value); + /*! \copydoc drawBox + \see see drawBox for details */ + bool getDrawBox() const; + + /*! \copydoc relativeWhiskerWidth + \see see relativeWhiskerWidth for details */ + void setRelativeWhiskerWidth(double __value); + /*! \copydoc relativeWhiskerWidth + \see see relativeWhiskerWidth for details */ + double getRelativeWhiskerWidth() const; + + /*! \copydoc relativeNotchIndent + \see see relativeNotchIndent for details */ + void setRelativeNotchIndent(double __value); + /*! \copydoc relativeNotchIndent + \see see relativeNotchIndent for details */ + double getRelativeNotchIndent() const; + + + /*! \brief set the line style of whisker lines */ + void setWhiskerLineStyle(Qt::PenStyle __value); + /*! \brief get the line style of whisker lines */ + Qt::PenStyle getWhiskerLineStyle() const; + + /*! \brief set the width [pt] of whisker lines */ + void setWhiskerLineWidth(double __value); + /*! \brief get the width [pt] of whisker lines */ + double getWhiskerLineWidth() const; + + /*! \brief set the color of whisker lines */ + void setWhiskerLineColor(QColor __value); + /*! \brief get the color of whisker lines */ + QColor getWhiskerLineColor() const; + + + /** \brief sets the dash offset for a custom dash style of whisker lines + * \see https://doc.qt.io/qt-5/qpen.html#setDashOffset + */ + void setWhiskerLineDashOffset(qreal offset); + /** \brief returns the dash offset for a custom dash style of whisker lines + * \see https://doc.qt.io/qt-5/qpen.html#setDashOffset + */ + qreal getWhiskerLineDashOffset() const; + /** \brief sets the dash pattern for a custom dash style of whisker lines + * \see https://doc.qt.io/qt-5/qpen.html#setDashPattern + */ + void setWhiskerLineDashPattern(const QVector &pattern); + /** \brief gets the dash pattern for a custom dash style of whisker lines + * \see https://doc.qt.io/qt-5/qpen.html#setDashPattern + */ + QVector getWhiskerLineDashPattern() const; + /** \brief sets the join style of whisker lines + * \see https://doc.qt.io/qt-5/qpen.html#setJoinStyle + */ + void setWhiskerLineJoinStyle(Qt::PenJoinStyle style); + /** \brief returns the join style of whisker lines + * \see https://doc.qt.io/qt-5/qpen.html#setJoinStyle + */ + Qt::PenJoinStyle getWhiskerLineJoinStyle() const; + /** \brief sets the cap style of whisker lines + * \see https://doc.qt.io/qt-5/qpen.html#setCapStyle + */ + void setWhiskerLineCapStyle(Qt::PenCapStyle style); + /** \brief gets the cap style of whisker lines + * \see https://doc.qt.io/qt-5/qpen.html#setCapStyle + */ + Qt::PenCapStyle getWhiskerLineCapStyle() const; + /** \brief sets the brush used to fill the line area of whisker lines + * \see https://doc.qt.io/qt-5/qpen.html#setBrush + */ + void setWhiskerLineBrush(const QBrush& style); + /** \brief gets the brush used to fill the line area of whisker lines + * \see https://doc.qt.io/qt-5/qpen.html#setBrush + */ + QBrush getWhiskerLineBrush() const; + + /** \brief build a pen to be used for drawing whiskers */ + QPen getWhiskerPen(JKQTPEnhancedPainter &painter, JKQTBasePlotter *parent) const; + + + + /*! \brief set the line style of whisker cap lines */ + void setWhiskerCapLineStyle(Qt::PenStyle __value); + /*! \brief get the line style of whisker cap lines */ + Qt::PenStyle getWhiskerCapLineStyle() const; + + /*! \brief set the width [pt] of whisker cap lines */ + void setWhiskerCapLineWidth(double __value); + /*! \brief get the width [pt] of whisker cap lines */ + double getWhiskerCapLineWidth() const; + + /*! \brief set the color of whisker cap lines */ + void setWhiskerCapLineColor(QColor __value); + /*! \brief get the color of whisker cap lines */ + QColor getWhiskerCapLineColor() const; + + + /** \brief sets the dash offset for a custom dash style of whisker cap lines + * \see https://doc.qt.io/qt-5/qpen.html#setDashOffset + */ + void setWhiskerCapLineDashOffset(qreal offset); + /** \brief returns the dash offset for a custom dash style of whisker cap lines + * \see https://doc.qt.io/qt-5/qpen.html#setDashOffset + */ + qreal getWhiskerCapLineDashOffset() const; + /** \brief sets the dash pattern for a custom dash style of whisker cap lines + * \see https://doc.qt.io/qt-5/qpen.html#setDashPattern + */ + void setWhiskerCapLineDashPattern(const QVector &pattern); + /** \brief gets the dash pattern for a custom dash style of whisker cap lines + * \see https://doc.qt.io/qt-5/qpen.html#setDashPattern + */ + QVector getWhiskerCapLineDashPattern() const; + /** \brief sets the join style of whisker cap lines + * \see https://doc.qt.io/qt-5/qpen.html#setJoinStyle + */ + void setWhiskerCapLineJoinStyle(Qt::PenJoinStyle style); + /** \brief returns the join style of whisker cap lines + * \see https://doc.qt.io/qt-5/qpen.html#setJoinStyle + */ + Qt::PenJoinStyle getWhiskerCapLineJoinStyle() const; + /** \brief sets the cap style of whisker cap lines + * \see https://doc.qt.io/qt-5/qpen.html#setCapStyle + */ + void setWhiskerCapLineCapStyle(Qt::PenCapStyle style); + /** \brief gets the cap style of whisker cap lines + * \see https://doc.qt.io/qt-5/qpen.html#setCapStyle + */ + Qt::PenCapStyle getWhiskerCapLineCapStyle() const; + /** \brief sets the brush used to fill the line area of whisker cap lines + * \see https://doc.qt.io/qt-5/qpen.html#setBrush + */ + void setWhiskerCapLineBrush(const QBrush& style); + /** \brief gets the brush used to fill the line area of whisker cap lines + * \see https://doc.qt.io/qt-5/qpen.html#setBrush + */ + QBrush getWhiskerCapLineBrush() const; + + /** \brief build a pen to be used for drawing whisker caps */ + QPen getWhiskerCapPen(JKQTPEnhancedPainter &painter, JKQTBasePlotter *parent) const; + + + + + /** \brief modes of how to draw the mean in a boxplot */ + enum MeanMode { + MeanAsSymbol, /*!< \brief draw mean as a symbol (specified by the settings in JKQTPGraphSymbolStyleMixin) */ + MeanAsLine /*!< \brief draw mean as a lie (specified by the pen settings in JKQTPGraphSymbolStyleMixin) */ + }; + + /*! \copydoc meanMode + \see see meanMode for details */ + void setMeanMode(MeanMode __value); + /*! \copydoc meanMode + \see see meanMode for details */ + MeanMode getMeanMode() const; + + + /*! \brief set the line style of median lines */ + void setMedianLineStyle(Qt::PenStyle __value); + /*! \brief get the line style of median lines */ + Qt::PenStyle getMedianLineStyle() const; + + /*! \brief set the width [pt] of median lines */ + void setMedianLineWidth(double __value); + /*! \brief get the width [pt] of median lines */ + double getMedianLineWidth() const; + + /*! \brief set the color of median lines */ + void setMedianLineColor(QColor __value); + /*! \brief get the color of median lines */ + QColor getMedianLineColor() const; + + + /** \brief sets the dash offset for a custom dash style of median lines + * \see https://doc.qt.io/qt-5/qpen.html#setDashOffset + */ + void setMedianLineDashOffset(qreal offset); + /** \brief returns the dash offset for a custom dash style of median lines + * \see https://doc.qt.io/qt-5/qpen.html#setDashOffset + */ + qreal getMedianLineDashOffset() const; + /** \brief sets the dash pattern for a custom dash style of median lines + * \see https://doc.qt.io/qt-5/qpen.html#setDashPattern + */ + void setMedianLineDashPattern(const QVector &pattern); + /** \brief gets the dash pattern for a custom dash style of median lines + * \see https://doc.qt.io/qt-5/qpen.html#setDashPattern + */ + QVector getMedianLineDashPattern() const; + /** \brief sets the join style of median lines + * \see https://doc.qt.io/qt-5/qpen.html#setJoinStyle + */ + void setMedianLineJoinStyle(Qt::PenJoinStyle style); + /** \brief returns the join style of median lines + * \see https://doc.qt.io/qt-5/qpen.html#setJoinStyle + */ + Qt::PenJoinStyle getMedianLineJoinStyle() const; + /** \brief sets the cap style of median lines + * \see https://doc.qt.io/qt-5/qpen.html#setCapStyle + */ + void setMedianLineCapStyle(Qt::PenCapStyle style); + /** \brief gets the cap style of median lines + * \see https://doc.qt.io/qt-5/qpen.html#setCapStyle + */ + Qt::PenCapStyle getMedianLineCapStyle() const; + /** \brief sets the brush used to fill the line area of median lines + * \see https://doc.qt.io/qt-5/qpen.html#setBrush + */ + void setMedianLineBrush(const QBrush& style); + /** \brief gets the brush used to fill the line area of median lines + * \see https://doc.qt.io/qt-5/qpen.html#setBrush + */ + QBrush getMedianLineBrush() const; + + /** \brief build a pen to be used for drawing medians */ + QPen getMedianPen(JKQTPEnhancedPainter &painter, JKQTBasePlotter *parent) const; + + + + + + /*! \brief set the line style of Mean lines */ + void setMeanLineStyle(Qt::PenStyle __value); + /*! \brief get the line style of Mean lines */ + Qt::PenStyle getMeanLineStyle() const; + /** \brief sets the dash offset for a custom dash style of Mean lines + * \see https://doc.qt.io/qt-5/qpen.html#setDashOffset + */ + void setMeanLineDashOffset(qreal offset); + /** \brief returns the dash offset for a custom dash style of Mean lines + * \see https://doc.qt.io/qt-5/qpen.html#setDashOffset + */ + qreal getMeanLineDashOffset() const; + /** \brief sets the dash pattern for a custom dash style of Mean lines + * \see https://doc.qt.io/qt-5/qpen.html#setDashPattern + */ + void setMeanLineDashPattern(const QVector &pattern); + /** \brief gets the dash pattern for a custom dash style of Mean lines + * \see https://doc.qt.io/qt-5/qpen.html#setDashPattern + */ + QVector getMeanLineDashPattern() const; + /** \brief set the type of the symbol for the mean */ + void setMeanSymbolType(JKQTPGraphSymbols __value); + /** \brief get the type of the symbol for the mean */ + JKQTPGraphSymbols getMeanSymbolType() const; + + /** \brief set the size (=diameter in pt) of the symbol for the mean (in pt) */ + void setMeanSize(double __value); + /** \brief get the size (=diameter in pt) of the symbol for the mean (in pt) */ + double getMeanSize() const; + + /** \brief set the color of the symbol for the mean, or mean line */ + void setMeanColor(const QColor & __value); + /** \brief set the color of the symbol for the mean, or mean line */ + QColor getMeanColor() const; + + /** \brief set the color of filling of the symbol for the mean */ + void setMeanFillColor(const QColor & __value); + /** \brief set the color of filling of the symbol for the mean */ + QColor getMeanFillColor() const; + + /** \brief set the line width of the symbol for the mean outline, or mean line (in pt) */ + void setMeanLineWidth(double __value); + /** \brief get the line width of the symbol for the mean outline, or mean line (in pt) */ + double getMeanLineWidth() const; + + /** \brief constructs a QPen from the line styling properties to draw the mean line */ + QPen getMeanLinePen(JKQTPEnhancedPainter &painter, JKQTBasePlotter* parent) const; + /** \brief constructs a QPen from the line styling properties to draw the mean symbol */ + QPen getMeanSymbolPen(JKQTPEnhancedPainter &painter, JKQTBasePlotter* parent) const; + /** \brief constructs a QPen from the line styling properties */ + QBrush getMeanSymbolBrush(JKQTPEnhancedPainter &painter, JKQTBasePlotter* parent) const; + + /*! \brief set the color of the graph (colors all elements, based on the given color \a c )*/ + void setBoxplotColor(QColor c, JKQTBasePlotter *parent); + + /*! \brief set the color of the graph (colors all elements, based on the given color \a c , sets background colors from \a bc )*/ + void setBoxplotColor(QColor c, QColor bc, JKQTBasePlotter *parent); + + + protected: + /*! \brief plot a symbol at location x,y (in painter coordinates), using the current style + + \param parent parent JKQTBasePlotter of the graph that uses this mix-in (used e.g. for line-width transformation) + \param painter the QPainter to draw to + \param x x-coordinate of the symbol center + \param y y-coordinate of the symbol center + */ + void plotStyledMeanSymbol(JKQTBasePlotter* parent, JKQTPEnhancedPainter &painter, double x, double y) const; + /** \brief draws a vertical boxplot, with all coordinates/sizes given in coordinates of the given painter, + * using the style properties declared in this class. Provide a parameter with \c JKQTP_NAN of you + * don't want it to be drawn, or don't know its value + * + * \param parent parent JKQTBasePlotter of the graph that uses this mix-in (used e.g. for line-width transformation) + * \param painter the QPainter to draw to + * \param xp x-coordinate of the boxplot center + * \param xpleft x-coordinate of the boxplot box left edge + * \param xpright x-coordinate of the boxplot box right edge + * \param minp y-coordinate of the minimum (lower whisker) + * \param q25p y-coordinate of the 25% quartile (lower box border) + * \param medianp y-coordinate the median + * \param q75p y-coordinate of the 75% quartile (upper box border) + * \param maxp y-coordinate of the maximum (upper whisker) + * \param meanp y-coordinate of the mean (symbol or line) + * \param notchLowerp y-coordinate of the lower (near \a qe5p ) end of the notch interval + * \param notchUpperp y-coordinate of the upper (near \a q75p ) end of the notch interval + */ + void plotVerticalBoxplot(JKQTBasePlotter* parent, JKQTPEnhancedPainter &painter, double xp, double xpleft, double xpright, double minp, double q25p, double medianp, double q75p, double maxp, double meanp=JKQTP_NAN, double notchLowerp=JKQTP_NAN, double notchUpperp=JKQTP_NAN) const; + + /** \brief draws a horizontal boxplot, with all coordinates/sizes given in coordinates of the given painter, + * using the style properties declared in this class. Provide a parameter with \c JKQTP_NAN of you + * don't want it to be drawn, or don't know its value + * + * \param parent parent JKQTBasePlotter of the graph that uses this mix-in (used e.g. for line-width transformation) + * \param painter the QPainter to draw to + * \param yp y-coordinate of the boxplot center + * \param ypbottom y-coordinate of the boxplot box bottom edge + * \param yptop y-coordinate of the boxplot box top edge + * \param minp x-coordinate of the minimum (lower whisker) + * \param q25p x-coordinate of the 25% quartile (lower box border) + * \param medianp x-coordinate the median + * \param q75p x-coordinate of the 75% quartile (upper box border) + * \param maxp x-coordinate of the maximum (upper whisker) + * \param meanp x-coordinate of the mean (symbol or line) + * \param notchLowerp x-coordinate of the lower (near \a qe5p ) end of the notch interval + * \param notchUpperp x-coordinate of the upper (near \a q75p ) end of the notch interval + */ + void plotHorizontalBoxplot(JKQTBasePlotter* parent, JKQTPEnhancedPainter &painter, double yp, double ypbottom, double yptop, double minp, double q25p, double medianp, double q75p, double maxp, double meanp=JKQTP_NAN, double notchLowerp=JKQTP_NAN, double notchUpperp=JKQTP_NAN) const; + + /** \brief draw a small, stylized, vertical symbol into \a rect that symbolizes a boxplot, e.g. in a plot legend */ + void plotVerticalKeyMarker(JKQTBasePlotter* parent, JKQTPEnhancedPainter &painter, const QRectF& rect); + + /** \brief draw a small, stylized, horizontal symbol into \a rect that symbolizes a boxplot, e.g. in a plot legend */ + void plotHorizontalKeyMarker(JKQTBasePlotter* parent, JKQTPEnhancedPainter &painter, const QRectF& rect); + private: + /** \brief which symbol to use for the datapoints */ + JKQTPGraphSymbols m_meanSymbolType; + /** \brief size (diameter in pt) of the symbol for the data points, given in pt */ + double m_meanSymbolSize; + /** \brief outline color of the symbol or line pen of the mean-line */ + QPen m_meanSymbolLinePen; + /** \brief color of the symbol filling */ + QColor m_meanSymbolFillColor; + /** \brief width (in pt) of the lines used to plot the symbol for the data points, given in pt */ + double m_meanSymbolLineWidth; + /** \brief line style of the whisker lines */ + QPen m_whiskerLinePen; + /** \brief line width (in pt) of the whisker lines */ + double whiskerLineWidth; + /** \brief line style of the whisker cap lines */ + QPen m_whiskerCapLinePen; + /** \brief line width (in pt) of the whisker cap lines */ + double whiskerCapLineWidth; + /** \brief line style of the median lines */ + QPen m_medianLinePen; + /** \brief line width (in pt) of the median lines */ + double medianLineWidth; + /** \brief width of box in pt. + * + * \note If several boxplots are drawn, the width is typically calculated, + * based on a relative width and the position distances, see JKQTPBoxplotVerticalGraph::boxWidthRelative */ + double boxWidthAbsolute; + /** \brief width of the whiskers, relative to the box width (default: 0.5) */ + double relativeWhiskerWidth; + /** \brief single-sided indention of the notch (if any), relative to the box width (default: 0.25) */ + double relativeNotchIndent; + + /** \brief specifies how to draw the mean (as a line of as a symbol, specified by the function in JKQTPGraphSymbolStyleMixin) */ + MeanMode meanMode; + /** \brief enables/disables drawing of the actual box of the boxplot (\c false leads to Tufte Style boxplots ) */ + bool drawBox; +}; + + + + + +#endif // jkqtpgraphsboxplotstylingmixins_H diff --git a/lib/jkqtplottertools/jkqtptools.h b/lib/jkqtplottertools/jkqtptools.h index 6e2d061f4e..2429e5c650 100644 --- a/lib/jkqtplottertools/jkqtptools.h +++ b/lib/jkqtplottertools/jkqtptools.h @@ -75,6 +75,20 @@ class JKQTPEnhancedPainter; // forward class JKQTBasePlotter; // forward declaration +/** \brief double-value NotANumber + * \ingroup jkqtptools_math + */ +#define JKQTP_DOUBLE_NAN (std::numeric_limits::signaling_NaN()) + +/** \brief float-value NotANumber + * \ingroup jkqtptools_math + */ +#define JKQTP_FLOAT_NAN (std::numeric_limits::signaling_NaN()) + +/** \brief double-value NotANumber + * \ingroup jkqtptools_math + */ +#define JKQTP_NAN JKQTP_DOUBLE_NAN /** \brief C++11 finally construct @@ -110,7 +124,7 @@ private: }; /** \brief C++11 finally construct - * \ingroup jkqtptools + * \ingroup jkqtptools_math * \see JKQTPFinalAct */ template @@ -120,7 +134,7 @@ inline JKQTPFinalAct JKQTPFinally(const F& f) noexcept } /** \brief C++11 finally construct - * \ingroup jkqtptools + * \ingroup jkqtptools_math * \see JKQTPFinalAct */ template @@ -150,13 +164,13 @@ enum JKQTPUserActionMarkerType { /** \brief convert a JKQTPUserActionMarkerType to a QString - * \ingroup jkqtptools + * \ingroup jkqtptools_string * * \see String2JKQTPUserActionMarkerType(), JKQTPUserActionMarkerType */ JKQTP_LIB_EXPORT QString JKQTPUserActionMarkerType2String(JKQTPUserActionMarkerType act); /** \brief convert a QString (created by JKQTPUserActionMarkerType2String() ) to JKQTPUserActionMarkerType - * \ingroup jkqtptools + * \ingroup jkqtptools_string * * \see JKQTPUserActionMarkerType2String(), JKQTPUserActionMarkerType */ @@ -184,13 +198,13 @@ enum JKQTPMouseDragActions { /** \brief convert a JKQTPMouseDragActions to a QString - * \ingroup jkqtptools + * \ingroup jkqtptools_string * * \see String2JKQTPMouseDragActions(), JKQTPMouseDragActions */ JKQTP_LIB_EXPORT QString JKQTPMouseDragActions2String(JKQTPMouseDragActions act); /** \brief convert a QString (created by JKQTPMouseDragActions2String() ) to JKQTPMouseDragActions - * \ingroup jkqtptools + * \ingroup jkqtptools_string * * \see JKQTPMouseDragActions2String(), JKQTPMouseDragActions */ @@ -208,13 +222,13 @@ enum JKQTPMouseDoubleClickActions { }; /** \brief convert a JKQTPMouseDoubleClickActions to a QString - * \ingroup jkqtptools + * \ingroup jkqtptools_string * * \see String2JKQTPMouseDoubleClickActions(), JKQTPMouseDoubleClickActions */ JKQTP_LIB_EXPORT QString JKQTPMouseDoubleClickActions2String(JKQTPMouseDoubleClickActions act); /** \brief convert a QString (created by JKQTPMouseDoubleClickActions2String() ) to JKQTPMouseDoubleClickActions - * \ingroup jkqtptools + * \ingroup jkqtptools_string * * \see JKQTPMouseDoubleClickActions2String(), JKQTPMouseDoubleClickActions */ @@ -229,13 +243,13 @@ enum JKQTPMouseWheelActions { }; /** \brief convert a JKQTPMouseWheelActions to a QString - * \ingroup jkqtptools + * \ingroup jkqtptools_string * * \see String2JKQTPMouseWheelActions(), JKQTPMouseWheelActions */ JKQTP_LIB_EXPORT QString JKQTPMouseWheelActions2String(JKQTPMouseWheelActions act); /** \brief convert a QString (created by JKQTPMouseWheelActions2String() ) to JKQTPMouseWheelActions - * \ingroup jkqtptools + * \ingroup jkqtptools_string * * \see JKQTPMouseWheelActions2String(), JKQTPMouseWheelActions */ @@ -252,13 +266,13 @@ enum JKQTPContextMenuModes { }; /** \brief convert a JKQTPContextMenuModes to a QString - * \ingroup jkqtptools + * \ingroup jkqtptools_string * * \see String2JKQTPContextMenuModes(), JKQTPContextMenuModes */ JKQTP_LIB_EXPORT QString JKQTPContextMenuModes2String(JKQTPContextMenuModes act); /** \brief convert a QString (created by JKQTPContextMenuModes2String() ) to JKQTPContextMenuModes - * \ingroup jkqtptools + * \ingroup jkqtptools_string * * \see JKQTPContextMenuModes2String(), JKQTPContextMenuModes */ @@ -274,21 +288,21 @@ typedef QHash, JKQTPMouseDoubleClic typedef JKQTPMouseDoubleClickActionsHashMap::const_iterator JKQTPMouseDoubleClickActionsHashMapIterator; /** \brief converts a QT::PenStyle into a string - * \ingroup jkqtptools + * \ingroup jkqtptools_string */ JKQTP_LIB_EXPORT QString jkqtp_QPenStyle2String(Qt::PenStyle style); /** \brief converts a QString into a Qt::PenStyle - * \ingroup jkqtptools + * \ingroup jkqtptools_string */ JKQTP_LIB_EXPORT Qt::PenStyle jkqtp_String2QPenStyle(const QString& style); /** \brief converts a QT::BrushStyle into a string - * \ingroup jkqtptools + * \ingroup jkqtptools_string */ JKQTP_LIB_EXPORT QString jkqtp_QBrushStyle2String(Qt::BrushStyle style); /** \brief converts a QString into a Qt::BrushStyle - * \ingroup jkqtptools + * \ingroup jkqtptools_string */ JKQTP_LIB_EXPORT Qt::BrushStyle jkqtp_String2QBrushStyle(const QString& style); @@ -312,14 +326,14 @@ enum JKQTPColorDerivationMode { }; /** \brief use a JKQTPColorDerivationMode to derive a color from \a col as specified - * \ingroup jkqtptools + * \ingroup jkqtptools_drawing * * \see JKQTPColorDerivationMode */ JKQTP_LIB_EXPORT QColor JKQTPGetDerivedColor(JKQTPColorDerivationMode mode, const QColor& col); /** \brief construct a QColor, based on the given \a color, but with alpha set to the specified value \a alphaF - * \ingroup jkqtptools + * \ingroup jkqtptools_drawing * \see QColorWithAlpha() */ inline QColor QColorWithAlphaF(const QColor& color, qreal alphaF) { @@ -329,7 +343,7 @@ inline QColor QColorWithAlphaF(const QColor& color, qreal alphaF) { } /** \brief construct a QColor, based on the given \a color, but with alpha set to the specified value \a alpha - * \ingroup jkqtptools + * \ingroup jkqtptools_drawing * \see QColorWithAlphaF() */ inline QColor QColorWithAlpha(const QColor& color, int alpha) { @@ -339,13 +353,13 @@ inline QColor QColorWithAlpha(const QColor& color, int alpha) { } /** \brief convert a JKQTPColorDerivationMode to a QString - * \ingroup jkqtptools + * \ingroup jkqtptools_string * * \see String2JKQTPColorDerivationMode(), JKQTPColorDerivationMode */ JKQTP_LIB_EXPORT QString JKQTPColorDerivationMode2String(JKQTPColorDerivationMode mode); /** \brief convert a QString (created by JKQTPColorDerivationMode2String() ) to JKQTPColorDerivationMode - * \ingroup jkqtptools + * \ingroup jkqtptools_string * * \see JKQTPColorDerivationMode2String(), JKQTPColorDerivationMode */ @@ -368,34 +382,34 @@ enum JKQTPCADrawMode { }; /** \brief determines whether JKQTPCADrawMode has the line - * \ingroup jkqtptools + * \ingroup jkqtptools_string */ JKQTP_LIB_EXPORT bool JKQTPCADrawModeHasLine(JKQTPCADrawMode pos); /** \brief determines whether JKQTPCADrawMode has ticks - * \ingroup jkqtptools + * \ingroup jkqtptools_string */ JKQTP_LIB_EXPORT bool JKQTPCADrawModeHasTicks(JKQTPCADrawMode pos); /** \brief determines whether JKQTPCADrawMode has tick labels - * \ingroup jkqtptools + * \ingroup jkqtptools_string */ JKQTP_LIB_EXPORT bool JKQTPCADrawModeHasTickLabels(JKQTPCADrawMode pos); /** \brief determines whether JKQTPCADrawMode has the axis label - * \ingroup jkqtptools + * \ingroup jkqtptools_string */ JKQTP_LIB_EXPORT bool JKQTPCADrawModeHasAxisLabel(JKQTPCADrawMode pos); /** \brief converts a JKQTPCADrawMode variable into a human-readable string - * \ingroup jkqtptools + * \ingroup jkqtptools_string */ JKQTP_LIB_EXPORT QString JKQTPCADrawMode2String(JKQTPCADrawMode pos); /** \brief converts a string into a JKQTPCADrawMode - * \ingroup jkqtptools + * \ingroup jkqtptools_string */ JKQTP_LIB_EXPORT JKQTPCADrawMode String2JKQTPCADrawMode(const QString& pos); @@ -422,23 +436,23 @@ enum JKQTPLabelTickMode { }; /** \brief converts a JKQTPLabelTickMode variable into a human-readable string - * \ingroup jkqtptools + * \ingroup jkqtptools_string */ JKQTP_LIB_EXPORT QString JKQTPLabelTickMode2String(JKQTPLabelTickMode pos); /** \brief converts a string into a JKQTPLabelTickMode - * \ingroup jkqtptools + * \ingroup jkqtptools_string */ JKQTP_LIB_EXPORT JKQTPLabelTickMode String2JKQTPLabelTickMode(const QString& pos); /** \brief converts a JKQTPCALabelType variable into a human-readable string - * \ingroup jkqtptools + * \ingroup jkqtptools_string */ JKQTP_LIB_EXPORT QString JKQTPCALabelType2String(JKQTPCALabelType pos); /** \brief converts a string into a JKQTPCALabelType - * \ingroup jkqtptools + * \ingroup jkqtptools_string */ JKQTP_LIB_EXPORT JKQTPCALabelType String2JKQTPCALabelType(const QString& pos); @@ -453,12 +467,12 @@ enum JKQTPLabelPosition { /** \brief converts a JKQTPLabelPosition variable into a human-readable string - * \ingroup jkqtptools + * \ingroup jkqtptools_string */ JKQTP_LIB_EXPORT QString JKQTPLabelPosition2String(JKQTPLabelPosition pos); /** \brief converts a string into a JKQTPLabelPosition - * \ingroup jkqtptools + * \ingroup jkqtptools_string */ JKQTP_LIB_EXPORT JKQTPLabelPosition String2JKQTPLabelPosition(const QString& pos); @@ -482,12 +496,12 @@ enum JKQTPKeyPosition { /** \brief converts a JKQTPLabelPosition variable into a human-readable string - * \ingroup jkqtptools + * \ingroup jkqjkqtptools_stringtptools */ JKQTP_LIB_EXPORT QString JKQTPKeyPosition2String(JKQTPKeyPosition pos); /** \brief converts a string into a JKQTPLabelPosition - * \ingroup jkqtptools + * \ingroup jkqtptools_string */ JKQTP_LIB_EXPORT JKQTPKeyPosition String2JKQTPKeyPosition(const QString& pos); @@ -502,12 +516,12 @@ enum JKQTPKeyLayout { /** \brief converts a JKQTPKeyLayout variable into a human-readable string - * \ingroup jkqtptools + * \ingroup jkqtptools_string */ JKQTP_LIB_EXPORT QString JKQTPKeyLayout2String(JKQTPKeyLayout pos); /** \brief converts a String into a JKQTPKeyLayout - * \ingroup jkqtptools + * \ingroup jkqtptools_string */ JKQTP_LIB_EXPORT JKQTPKeyLayout String2JKQTPKeyLayout(const QString& pos); @@ -549,12 +563,12 @@ enum JKQTPErrorPlotstyle { /** \brief converts a JKQTPErrorPlotstyle variable into a human-readable string - * \ingroup jkqtptools + * \ingroup jkqtptools_string */ JKQTP_LIB_EXPORT QString JKQTPErrorPlotstyle2String(JKQTPErrorPlotstyle pos); /** \brief converts a String into a JKQTPErrorPlotstyle - * \ingroup jkqtptools + * \ingroup jkqtptools_string */ JKQTP_LIB_EXPORT JKQTPErrorPlotstyle String2JKQTPErrorPlotstyle(const QString& pos); @@ -606,22 +620,22 @@ enum JKQTPGraphSymbols { }; /** \brief converts a JKQTPGraphSymbols variable into a identifier string - * \ingroup jkqtptools + * \ingroup jkqtptools_string */ JKQTP_LIB_EXPORT QString JKQTPGraphSymbols2String(JKQTPGraphSymbols pos); /** \brief converts a JKQTPGraphSymbols variable into a human-readable string - * \ingroup jkqtptools + * \ingroup jkqtptools_string */ JKQTP_LIB_EXPORT QString JKQTPGraphSymbols2NameString(JKQTPGraphSymbols pos); /** \brief converts a String into a JKQTPGraphSymbols - * \ingroup jkqtptools + * \ingroup jkqtptools_string */ JKQTP_LIB_EXPORT JKQTPGraphSymbols String2JKQTPGraphSymbols(const QString& pos); /** \brief convert a double to a string, using the loacle "C" - * \ingroup jkqtptools + * \ingroup jkqtptools_string */ inline QString JKQTPCDoubleToQString(double value) { QLocale loc=QLocale::c(); @@ -630,7 +644,7 @@ inline QString JKQTPCDoubleToQString(double value) { } /** \brief convert a double to a string - * \ingroup jkqtptools + * \ingroup jkqtptools_string */ inline QString JKQTPDoubleToQString(double value, int prec = 10, char f = 'g', QChar decimalSeparator='.') { QLocale loc=QLocale::c(); @@ -645,7 +659,7 @@ inline QString JKQTPDoubleToQString(double value, int prec = 10, char f = 'g', Q /** \brief rotate a rectangle by given angle (rotates all points around the center of the rectangle and returns it as a QPolygonF) - * \ingroup jkqtptools + * \ingroup jkqtptools_math */ JKQTP_LIB_EXPORT QPolygonF jkqtpRotateRect(QRectF r, double angle); @@ -867,7 +881,7 @@ JKQTP_LIB_EXPORT std::string jkqtp_floattohtmlstr(double data, int past_comma=5, JKQTP_LIB_EXPORT std::string jkqtp_chartostr(char data); /** \brief wandelt einen Datentyp in einen double um, wird von JKQTPDatastore zur Wandlung benutzt - * \ingroup jkqtptools + * \ingroup jkqtptools_math * * Diese Funktion nutzt per default static_cast(), kann aber für spezielle Datentypen überschrieben werden, etwa für bool */ @@ -879,7 +893,7 @@ inline constexpr double jkqtp_todouble(const T& d) { /** \brief wandelt einen boolean in einen double um, wird von JKQTPDatastore zur Wandlung benutzt, * Spezialisierung für bool (true -> 1.0, false -> 0.0) - * \ingroup jkqtptools */ + * \ingroup jkqtptools_math */ template<> inline constexpr double jkqtp_todouble(const bool& d) { return static_cast((d)?1.0:0.0); @@ -912,7 +926,8 @@ JKQTP_LIB_EXPORT QString JKQTPSpecialLineType2String(JKQTPSpecialLineType pos); */ JKQTP_LIB_EXPORT JKQTPSpecialLineType String2JKQTPSpecialLineType(const QString& pos); -/** \brief round a double using round() and convert it to a specified type T (static_cast!) */ +/** \brief round a double using round() and convert it to a specified type T (static_cast!) + * \ingroup jkqtptools_math */ template inline T jkqtp_roundTo(const double& v) { return static_cast(round(v)); @@ -920,19 +935,22 @@ inline T jkqtp_roundTo(const double& v) { -/** \brief compare two floats \a a and \a b for euqality, where any difference smaller than \a epsilon is seen as equality */ +/** \brief compare two floats \a a and \a b for euqality, where any difference smaller than \a epsilon is seen as equality + * \ingroup jkqtptools_math */ inline bool jkqtp_approximatelyEqual(float a, float b, float epsilon=2.0*std::numeric_limits::epsilon()) { return fabsf(a - b) <= epsilon; } -/** \brief compare two doubles \a a and \a b for euqality, where any difference smaller than \a epsilon is seen as equality */ +/** \brief compare two doubles \a a and \a b for euqality, where any difference smaller than \a epsilon is seen as equality + * \ingroup jkqtptools_math */ inline bool jkqtp_approximatelyEqual(double a, double b, double epsilon=2.0*std::numeric_limits::epsilon()) { return fabs(a - b) <= epsilon; } -/** \brief returns the quare of the value \a v, i.e. \c v*v */ +/** \brief returns the quare of the value \a v, i.e. \c v*v + * \ingroup jkqtptools_math */ template inline T jkqtp_sqr(const T& v) { return v*v; diff --git a/screenshots/jkqtplotter_simpletest_boxplot.png b/screenshots/jkqtplotter_simpletest_boxplot.png index 55f844c8f4..2786aa119c 100644 Binary files a/screenshots/jkqtplotter_simpletest_boxplot.png and b/screenshots/jkqtplotter_simpletest_boxplot.png differ diff --git a/screenshots/jkqtplotter_simpletest_boxplot_small.png b/screenshots/jkqtplotter_simpletest_boxplot_small.png index 11e72a4e40..c7d5ba1b29 100644 Binary files a/screenshots/jkqtplotter_simpletest_boxplot_small.png and b/screenshots/jkqtplotter_simpletest_boxplot_small.png differ diff --git a/screenshots/plot_boxplothorizontalelement.png b/screenshots/plot_boxplothorizontalelement.png deleted file mode 100644 index 6833d4e9b3..0000000000 Binary files a/screenshots/plot_boxplothorizontalelement.png and /dev/null differ diff --git a/screenshots/plot_boxplotverticalelement.png b/screenshots/plot_boxplotverticalelement.png deleted file mode 100644 index 03fdaa7b76..0000000000 Binary files a/screenshots/plot_boxplotverticalelement.png and /dev/null differ diff --git a/screenshots/test_distributionplot.png b/screenshots/test_distributionplot.png index af6ca8f1a4..8892c00324 100644 Binary files a/screenshots/test_distributionplot.png and b/screenshots/test_distributionplot.png differ diff --git a/screenshots/test_distributionplot_small.png b/screenshots/test_distributionplot_small.png index a3ec9440eb..7199186b9a 100644 Binary files a/screenshots/test_distributionplot_small.png and b/screenshots/test_distributionplot_small.png differ diff --git a/screenshots/test_styledboxplot.png b/screenshots/test_styledboxplot.png new file mode 100644 index 0000000000..d20e77b4d4 Binary files /dev/null and b/screenshots/test_styledboxplot.png differ diff --git a/screenshots/test_styledboxplot_small.png b/screenshots/test_styledboxplot_small.png new file mode 100644 index 0000000000..f9e3854c1c Binary files /dev/null and b/screenshots/test_styledboxplot_small.png differ