JKQTPlotter: NEW: barcharts (derived from JKQTPBarGraphBase) can be configured to use different fill styles above and below the baseline

This commit is contained in:
jkriege2 2022-09-10 14:35:16 +02:00
parent f11a98779e
commit 40748de442
20 changed files with 211 additions and 7 deletions

View File

@ -125,6 +125,7 @@ if(JKQtPlotter_BUILD_EXAMPLES)
scatter_customsymbol
simpletest
barchart/barchart,barchart_hor
barchart_twocolor/barchart_twocolor,barchart_twocolor_hor
wiggleplots/wiggleplot_x,wiggleplot_y
advplotstyling/advancedlineandfillstyling
boxplot
@ -172,6 +173,7 @@ if(JKQtPlotter_BUILD_EXAMPLES)
scatter/JKQTPXYScatterGraph,JKQTPXYScatterErrorGraph/--smallscreenshotplot
simpletest/JKQTPXYLineGraph/--smallscreenshotplot
barchart/JKQTPBarVerticalGraph,JKQTPBarHorizontalGraph/--smallscreenshotplot
barchart_twocolor/JKQTPBarVerticalGraphTwoColorFilling,JKQTPBarHorizontalGraphTwoColorFilling/--smallscreenshotplot
wiggleplots/JKQTPFilledCurveXGraph_wiggle,JKQTPFilledCurveYGraph_wiggle
contourplot/JKQTPColumnContourPlot/--smallscreenshotplot
filledgraphs/JKQTPFilledCurveXGraph,JKQTPFilledCurveYGraph/--smallscreenshotplot

View File

@ -40,6 +40,9 @@ All test-projects are Qt-projects that use qmake to build. You can load them int
<tr><td> \image html barchart_small.png
<td> \subpage JKQTPlotterBarcharts
<td> `JKQTPBarVerticalGraph` <br> C-style arrays of data
<tr><td> \image html barchart_twocolor_small.png
<td> \subpage JKQTPlotterBarchartsTwoColorFilling
<td> `JKQTPBarVerticalGraph` <br>
<tr><td> \image html stackedbars_small.png
<td> \subpage JKQTPlotterStackedBarChart
<td> `JKQTPBarVerticalStackableGraph`, `JKQTPBarHorizontalStackableGraph` <br> C++-style vectors of data

View File

@ -15,7 +15,6 @@ This page lists several todos and wishes for future version of JKQTPlotter
<li>styling: style.ini with glowing colors in dark background ("techno" or "cyberpunk")</li>
<li>plot: axis labels above/below/centered around tick</li>
<li>plot: elongated grid to left of tick labels</li>
<li>graphs: different styles above/below baseline for barcharts ...</li>
<li>graphs: vector field graph (arrows), variant (x,y,dx,dy), (x,y,alpha,length), (x1,y1,x2,y2) ... different head/tail styles</li>
<li>graphs: gant-chart as simplufier vector field with (x,y1,y2) or (x1,x2,y), or (x,y,dx), (x,y,dy) ... different head/tail style</li>
<li>graphs: barchart/ranges chart with (x,y1,y2) or (x1,x2,y)</li>

View File

@ -47,6 +47,7 @@ Changes, compared to \ref page_whatsnew_V4_0_0 "v4.0.0" include:
<li>NEW: added the option to register a custom symbol using JKQTPRegisterCustomGraphSymbol() </li>
<li>NEW: added property drawLineInForeground to JKQTPXYLineGraph and JKQTPXYParametrizedScatterGraph</li>
<li>NEW: added JKQTPXYGraph::setKeyColumn()/JKQTPXYGraph::getKeyColumn() and JKQTPXYGraph::setValueColumn()/JKQTPXYGraph::getValueColumn() and corresponding functions in other classes. In most graph classes they point to xColumn for key and yColumn for values. These functions are virtual and overwritten in derived classes with horizontally oriented graphs, where they point to yColumn for key and yColumn for value. This way you can write generic code with classes for both orientations.</li>
<li>NEW: barcharts (derived from JKQTPBarGraphBase) can be configured to use different fill styles above and below the baseline, see JKQTPBarGraphBase::FillMode </li>
</ul></li>
<li>JKQTMathText:<ul>

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

View File

@ -48,6 +48,7 @@ add_subdirectory(jkqtplot_test)
add_subdirectory(advplotstyling)
add_subdirectory(barchart)
add_subdirectory(boxplot)
add_subdirectory(barchart_twocolor)
add_subdirectory(contourplot)
add_subdirectory(datastore)
add_subdirectory(datastore_groupedstat)

View File

@ -0,0 +1,34 @@
cmake_minimum_required(VERSION 3.16)
set(EXAMPLE_NAME barchart_twocolor)
set(EXENAME jkqtptest_${EXAMPLE_NAME})
message( STATUS ".. Building Example ${EXAMPLE_NAME}" )
# Set up source files
set(SOURCES barchart_twocolor.cpp )
set(HEADERS )
set(RESOURCES )
set(UIS )
add_executable(${EXENAME} WIN32 ${SOURCES} ${HEADERS} ${RESOURCES} ${UIS})
target_link_libraries(${EXENAME} JKQTPExampleToolsLib)
target_include_directories(${EXENAME} PRIVATE ../../lib)
if(JKQtPlotter_BUILD_STATIC_LIBS)
target_link_libraries(${EXENAME} JKQTPlotterLib)
elseif(JKQtPlotter_BUILD_SHARED_LIBS)
target_link_libraries(${EXENAME} JKQTPlotterSharedLib)
endif()
# precomiled headers to speed up compilation
if (JKQtPlotter_BUILD_WITH_PRECOMPILED_HEADERS)
target_precompile_headers(${EXENAME} REUSE_FROM jkqtptest_simpletest)
endif (JKQtPlotter_BUILD_WITH_PRECOMPILED_HEADERS)
# Installation
install(TARGETS ${EXENAME} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
#Installation of Qt DLLs on Windows
jkqtplotter_deployqt(${EXENAME})

View File

@ -0,0 +1,44 @@
# Example (JKQTPlotter): Barchart With Two-Color Fill-Mode {#JKQTPlotterBarchartsTwoColorFilling}
This project (see [`barchart_twocolor`](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/barchart_twocolor) shows how to draw barcharts, where the bars are filled differently if their value is above or below the baseline.
The source code of the main application is (see [`barchart_twocolor.cpp`](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/barchart_twocolor/barchart_twocolor.cpp):
```.cpp
// 1. create a plotter window and get a pointer to the internal datastore (for convenience)
JKQTPlotter plot;
JKQTPDatastore* ds=plot.getDatastore();
// 2. now we create two columns for key and value
size_t columnK=ds->addLinearColumn(10, 0, 2.0*JKQTPSTATISTICS_PI,"k");
size_t columnV=ds->addColumnCalculatedFromColumn(columnK, &cos, "v");
// 3. create graph in the plot, which plots the dataset:
JKQTPBarGraphBase* graph=new JKQTPBarVerticalGraph(&plot);
graph->setKeyColumn(columnK);
graph->setValueColumn(columnV);
// set TwoColor fill Mode
graph->setFillMode(JKQTPBarGraphBase::FillMode::TwoColorFilling);
graph->setFillColor(QColor("green"));
graph->fillStyleBelow().setFillColor(QColor("red"));
plot.addGraph(graph);
// 4 autoscale the plot so the graph is contained
plot.zoomToFit();
// 5. show plotter and make it a decent size
plot.setWindowTitle(title);
plot.show();
plot.resize(400,400);
```
The result looks like this:
![barchart_twocolor](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/barchart_twocolor.png)
In order to draw horizontal error bars, you have to use `JKQTPBarHorizontalGraph` instead of `JKQTPBarVerticalGraph`:
![barchart_twocolor_hor](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/barchart_twocolor_hor.png)

View File

@ -0,0 +1,58 @@
/** \example barchart_twocolor.cpp
* Shows how to draw Barcharts with different colors above and below the baseline in a JKQTPlotter
*
* \ref JKQTPlotterBarchartsTwoColorFilling
*/
#include "jkqtpexampleapplication.h"
#include <QApplication>
#include "jkqtplotter/jkqtplotter.h"
#include "jkqtplotter/graphs/jkqtpscatter.h"
#include "jkqtplotter/graphs/jkqtpbarchart.h"
#include "jkqtpexampleapplication.h"
#include "jkqtcommon/jkqtpmathtools.h"
template <class TCHART>
void doExample(JKQTPlotter& plot, const QString& title)
{
// 1. create a plotter window and get a pointer to the internal datastore (for convenience)
JKQTPDatastore* ds=plot.getDatastore();
// 2. now we create two columns for key and value
size_t columnK=ds->addLinearColumn(15, 0.5*JKQTPSTATISTICS_PI, 3.0*JKQTPSTATISTICS_PI,"k");
size_t columnV=ds->addColumnCalculatedFromColumn(columnK, &cos, "v");
// 3. create graph in the plot, which plots the dataset:
JKQTPBarGraphBase* graph=new TCHART(&plot);
graph->setKeyColumn(columnK);
graph->setValueColumn(columnV);
// set TwoColor fill Mode
graph->setFillMode(JKQTPBarGraphBase::FillMode::TwoColorFilling);
graph->setFillColor(QColor("green"));
graph->fillStyleBelow().setFillColor(QColor("red"));
plot.addGraph(graph);
// 4 autoscale the plot so the graph is contained
plot.zoomToFit();
// 5. show plotter and make it a decent size
plot.setWindowTitle(title);
plot.show();
plot.resize(400,400);
}
int main(int argc, char* argv[])
{
JKQTPAppSettingController highDPIController(argc,argv);
JKQTPExampleApplication app(argc, argv);
JKQTPlotter plotV, plotH;
doExample<JKQTPBarVerticalGraph>(plotV, "1: JKQTPBarVerticalGraph");
doExample<JKQTPBarHorizontalGraph>(plotH, "2: JKQTPBarHorizontalGraph");
return app.exec();
}

View File

@ -60,6 +60,7 @@ void JKQTPBarVerticalGraph::draw(JKQTPEnhancedPainter& painter) {
const QPen p=getLinePenForRects(painter, parent);
const QBrush b=getFillBrush(painter, parent);
const QBrush b_below=(getFillMode()==FillMode::TwoColorFilling)?fillStyleBelow().getFillBrush(painter, parent):b;
int imax=0;
int imin=0;
@ -80,7 +81,8 @@ void JKQTPBarVerticalGraph::draw(JKQTPEnhancedPainter& painter) {
const double xv=datastore->get(static_cast<size_t>(xColumn),static_cast<size_t>(i));
const int sr=datastore->getNextLowerIndex(xColumn, i);
const int lr=datastore->getNextHigherIndex(xColumn, i);
double yv=datastore->get(static_cast<size_t>(yColumn),static_cast<size_t>(i));
const double yvdirect=datastore->get(static_cast<size_t>(yColumn),static_cast<size_t>(i));
double yv=yvdirect;
double yv0=y0;
if (!qFuzzyIsNull(getBaseline())) yv0=transformY(getBaseline());
if (hasStackPar) {
@ -112,9 +114,10 @@ void JKQTPBarVerticalGraph::draw(JKQTPEnhancedPainter& painter) {
//std::cout<<"delta="<<delta<<" x="<<x<<" y="<<y<<" xx="<<xx<<" yy="<<yy<<std::endl;
if (yy<y) { qSwap(y,yy); }
if (JKQTPIsOKFloat(x) && JKQTPIsOKFloat(xx) && JKQTPIsOKFloat(y) && JKQTPIsOKFloat(yy)) {
painter.setBrush(b);
if (yvdirect<getBaseline()) painter.setBrush(b_below);
else painter.setBrush(b);
painter.setPen(p);
QRectF r(QPointF(x, y), QPointF(xx, yy));
const QRectF r(QPointF(x, y), QPointF(xx, yy));
painter.drawRect(r);
}
@ -256,6 +259,7 @@ void JKQTPBarHorizontalGraph::draw(JKQTPEnhancedPainter& painter) {
const QPen p=getLinePenForRects(painter, parent);
const QBrush b=getFillBrush(painter, parent);
const QBrush b_below=(getFillMode()==FillMode::TwoColorFilling)?fillStyleBelow().getFillBrush(painter, parent):b;
int imax=0;
int imin=0;
@ -274,7 +278,8 @@ void JKQTPBarHorizontalGraph::draw(JKQTPEnhancedPainter& painter) {
double deltam=0;
for (int iii=imin; iii<imax; iii++) {
int i=qBound(imin, getDataIndex(iii), imax);
double xv=datastore->get(static_cast<size_t>(xColumn),static_cast<size_t>(i));
const double xvdirect=datastore->get(static_cast<size_t>(xColumn),static_cast<size_t>(i));
double xv=xvdirect;
double yv=datastore->get(static_cast<size_t>(yColumn),static_cast<size_t>(i));
int sr=datastore->getNextLowerIndex(yColumn, i);
int lr=datastore->getNextHigherIndex(yColumn, i);
@ -311,7 +316,8 @@ void JKQTPBarHorizontalGraph::draw(JKQTPEnhancedPainter& painter) {
//qDebug()<<"delta="<<delta<<" x="<<x<<" y="<<y<<" xx="<<xx<<" yy="<<yy;
//qDebug()<<"xv="<<xv<<" x0="<<x0<<" x="<<x<<"..."<<xx;
if (JKQTPIsOKFloat(x) && JKQTPIsOKFloat(xx) && JKQTPIsOKFloat(y) && JKQTPIsOKFloat(yy)) {
painter.setBrush(b);
if (xvdirect<getBaseline()) painter.setBrush(b_below);
else painter.setBrush(b);
painter.setPen(p);
QRectF r(QPointF(x, y), QPointF(xx, yy));
painter.drawRect(r);

View File

@ -53,6 +53,11 @@
\image html JKQTPBarVerticalGraph.png
You can also set JKQTPBarGraphBase::FillMode::TwoColorFilling, which uses different fill styles for bars above and below
the baseline of the graph:
\image html JKQTPBarVerticalGraphTwoColorFilling.png
You can use JKQTPlotter::addHorizontalBargraph() to add a series of bargraphs, where the width and shift are determined
automatically. The y-columns are given as a QVector<int> to this function.
@ -164,6 +169,10 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPBarVerticalErrorGraph: public JKQTPBarVertical
\image html JKQTPBarHorizontalGraph.png
You can also set JKQTPBarGraphBase::FillMode::TwoColorFilling, which uses different fill styles for bars above and below
the baseline of the graph:
\image html JKQTPBarHorizontalGraphTwoColorFilling.png
\see \ref JKQTPlotterBarcharts, jkqtpstatAddVHistogram1D(), jkqtpstatAddVHistogram1DAutoranged()
*/

View File

@ -37,10 +37,11 @@
JKQTPBarGraphBase::JKQTPBarGraphBase(JKQTBasePlotter* parent):
JKQTPXYBaselineGraph(parent), width(0.9), shift(0)
JKQTPXYBaselineGraph(parent), width(0.9), shift(0), m_fillMode(FillMode::SingleFilling)
{
initFillStyle(parent, parentPlotStyle, JKQTPPlotStyleType::Barchart);
initLineStyle(parent, parentPlotStyle, JKQTPPlotStyleType::Barchart);
m_fillStyleBelow.initFillStyleInvertedColor(this);
}
@ -112,6 +113,7 @@ void JKQTPBarGraphBase::setColor(QColor c)
setFillColor(JKQTPGetDerivedColor(parent->getCurrentPlotterStyle().graphsStyle.barchartStyle.fillColorDerivationMode, c));
c.setAlphaF(0.5);
setHighlightingLineColor(c);
m_fillStyleBelow.initFillStyleInvertedColor(this);
}
void JKQTPBarGraphBase::setShift(double __value)
@ -140,6 +142,26 @@ void JKQTPBarGraphBase::setFillColor_and_darkenedColor(QColor fill, int colorDar
setLineColor(fill.darker(colorDarker));
}
JKQTPGraphFillStyleMixin &JKQTPBarGraphBase::fillStyleBelow()
{
return m_fillStyleBelow;
}
const JKQTPGraphFillStyleMixin &JKQTPBarGraphBase::fillStyleBelow() const
{
return m_fillStyleBelow;
}
JKQTPBarGraphBase::FillMode JKQTPBarGraphBase::getFillMode() const
{
return m_fillMode;
}
void JKQTPBarGraphBase::setFillMode(FillMode mode)
{
m_fillMode=mode;
}
double JKQTPBarGraphBase::getParentStackedMax(int /*index*/) const
{
return getBaseline();

View File

@ -50,13 +50,25 @@
*
* \image html JKQTPBarVerticalGraph.png
*
* You can also set FillMode::TwoColorFilling, which uses different fill styles for bars above and below
* the baseline of the graph:
*
* \image html JKQTPBarVerticalGraphTwoColorFilling.png
*
* \see JKQTPBarHorizontalGraph, JKQTPBarVerticalGraph
*/
class JKQTPLOTTER_LIB_EXPORT JKQTPBarGraphBase: public JKQTPXYBaselineGraph, public JKQTPGraphLineStyleMixin, public JKQTPGraphFillStyleMixin {
Q_OBJECT
public:
/** \brief specifies how the area below the graph is filled
*
* \see setFillMode(), getFillMode(), fillStyleBelow(), \ref JKQTPlotterWigglePlots
*/
enum FillMode {
SingleFilling=0, /*!< \brief the whole area is filled with the same color/pattern \image html JKQTPBarVerticalGraph.png */
TwoColorFilling=1 /*!< \brief the area above and below baseline with the two different colors/pattern \image html JKQTPBarVerticalGraphTwoColorFilling.png */
};
Q_ENUM(FillMode)
/** \brief class constructor */
JKQTPBarGraphBase(JKQTBasePlotter* parent=nullptr);
/** \brief class constructor */
@ -84,7 +96,15 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPBarGraphBase: public JKQTPXYBaselineGraph, pub
/** \brief returns xColumn or yColumn, whichever is used for the height of the bars (depending on whether the barchart is vertical or horizontal \see getBarPositionColumn(), xColumn, yColumn */
virtual int getBarHeightColumn() const =0;
/** \copydoc m_fillStyleBelow */
JKQTPGraphFillStyleMixin &fillStyleBelow();
/** \copydoc m_fillStyleBelow */
const JKQTPGraphFillStyleMixin& fillStyleBelow() const;
/** \copydoc m_fillMode */
FillMode getFillMode() const;
public slots:
/** \copydoc m_fillMode */
void setFillMode(JKQTPBarGraphBase::FillMode mode);
/** \brief finds all bar charts of the same orientation and determines width and shift, so they stand side by side
*
@ -134,6 +154,11 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPBarGraphBase: public JKQTPXYBaselineGraph, pub
* \image html bargraph_basics.png
*/
double shift;
/** \brief specifies how the area of the graph is filles */
FillMode m_fillMode;
/** \brief if m_fillMode \c ==FillAboveAndBelowDifferently then this fill style is used below the baseline and
* the default fill style is used above */
JKQTPGraphFillStyleMixin m_fillStyleBelow;
/** \brief this function is used by autoscaleBarWidthAndShift() to determine whether a given graph shall be taken into account when autoscaling.

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB