reworked class hierarchy of bar charts

This commit is contained in:
jkriege2 2020-09-17 16:59:57 +02:00
parent 4c98310147
commit 9dbfd6e173
10 changed files with 855 additions and 522 deletions

View File

@ -25,7 +25,8 @@ Changes, compared to \ref page_whatsnew_V2019_11 "v2019.11" include:
<li>removed/breaking change: removed the overlay elements (derived from JKQTPOverlayElement), which were not very well set up and are more confusing than useful.</li>
<li>improved/breaking change: geometric objects now use an adaptive drawing algorithm to represent curves (before e.g. ellipses were always separated into a fixed number of line-segments)</li>
<li>improved: constructors and access functions for several geometric objects (e.g. more constructors, additional functions to retrieve parameters in diferent forms, iterators for polygons, ...)</li>
<li>improved/breaking change: reworked class hirarchy of parsed function plots and declared several setters as slots.</li>
<li>improved/breaking change: reworked class hierarchy of parsed function plots and declared several setters as slots.</li>
<li>improved/breaking change: reworked class hierarchy of bar charts.</li>
<li>bugfixed/improved: aspect ratio handling in JKQTPlotter.</li>
<li>new: added geometric plot objects JKQTPGeoArrow to draw arrows (aka lines with added line-end decorators, also extended JKQTPGeoLine, JKQTPGeoInfiniteLine, JKQTPGeoPolyLines to draw line-end decorator (aka arrows)</li>
<li>new: all geometric objects can either be drawn as graphic element (i.e. lines are straight line, even on non-linear axes), or as mathematical curve (i.e. on non-linear axes, lines become the appropriate curve representing the linear function, connecting the given start/end-points). The only exceptions are ellipses (and the derived arcs,pies,chords), which are always drawn as mathematical curves</li>

View File

@ -89,8 +89,17 @@ int main(int argc, char* argv[])
return app.exec();
}
```
Note: Here we use the functions `JKQTPBarVerticalGraph::setXColumn()` and `JKQTPBarVerticalGraph::setYColumn()` to set the columns to use for the stack positions (X) and heights (Y). Instead you can also use the semantic version `JKQTPBarGraphBase::setBarPositionColumn()` and `JKQTPBarGraphBase::setBarHeightColumn()`.
The result looks like this:
![barchart](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/barchart.png)
In order to draw horizontal error bars, you have to use `JKQTPBarHorizontalGraph` instead of `JKQTPBarVerticalGraph`:
![barchart](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/barchart_hor.png)

View File

@ -10,16 +10,17 @@
#include "jkqtplotter/graphs/jkqtpbarchart.h"
#define Ndata 5
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
template <class TCHART>
void doExample()
{
// 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
JKQTPDatastore* ds=plot.getDatastore();
JKQTPlotter* plot=new JKQTPlotter();
plot->getPlotter()->setUseAntiAliasingForGraphs(true); // nicer (but slower) plotting
plot->getPlotter()->setUseAntiAliasingForSystem(true); // nicer (but slower) plotting
plot->getPlotter()->setUseAntiAliasingForText(true); // nicer (but slower) text rendering
JKQTPDatastore* ds=plot->getDatastore();
// 2. now we create data for three simple barchart
QString L[Ndata]={ "cat. A", "cat. C", "cat. B", "cat. D", "other"}; // unsorted category axis
@ -41,24 +42,24 @@ int main(int argc, char* argv[])
size_t columnY3=ds->addCopiedColumn(Y3, Ndata, "y3");
// 4. create graphs in the plot, which plots the dataset X/Y1, X/Y2 and X/Y3:
JKQTPBarVerticalGraph* graph1=new JKQTPBarVerticalGraph(&plot);
graph1->setXColumn(columnX);
graph1->setYColumn(columnY1);
TCHART* graph1=new TCHART(plot);
graph1->setBarPositionColumn(columnX);
graph1->setBarHeightColumn(columnY1);
graph1->setTitle(QObject::tr("dataset 1"));
JKQTPBarVerticalGraph* graph2=new JKQTPBarVerticalGraph(&plot);
graph2->setXColumn(columnX);
graph2->setYColumn(columnY2);
TCHART* graph2=new TCHART(plot);
graph2->setBarPositionColumn(columnX);
graph2->setBarHeightColumn(columnY2);
graph2->setTitle(QObject::tr("dataset 2"));
JKQTPBarVerticalGraph* graph3=new JKQTPBarVerticalGraph(&plot);
graph3->setXColumn(columnX);
graph3->setYColumn(columnY3);
TCHART* graph3=new TCHART(plot);
graph3->setBarPositionColumn(columnX);
graph3->setBarHeightColumn(columnY3);
graph3->setTitle(QObject::tr("dataset 3"));
// 5. add the graphs to the plot, so it is actually displayed
plot.addGraph(graph1);
plot.addGraph(graph2);
plot.addGraph(graph3);
plot->addGraph(graph1);
plot->addGraph(graph2);
plot->addGraph(graph3);
// 6. now we set the graphs, so they are plotted side-by-side
// This function searches all JKQTPBarHorizontalGraph in the current
@ -66,29 +67,45 @@ int main(int argc, char* argv[])
// side-by-side groups
graph1->autoscaleBarWidthAndShift(0.75, 1);
// 7. data is grouped into 5 numbere groups (1..5), but we also have string
// labels for these groups (stored in L). In order to display these labels,
// we have to tell the x-Axis to use these special labels:
plot.getXAxis()->addAxisTickLabels(X, L, Ndata);
// also we can rotate the labels a bit (by 45 degree), so they fit better
plot.getXAxis()->setTickLabelAngle(45);
plot.getXAxis()->setTickLabelFontSize(12);
if (dynamic_cast<JKQTPBarVerticalGraph*>(graph1)!=nullptr) {
// 7. data is grouped into 5 numbere groups (1..5), but we also have string
// labels for these groups (stored in L). In order to display these labels,
// we have to tell the x-Axis to use these special labels:
plot->getXAxis()->addAxisTickLabels(X, L, Ndata);
// also we can rotate the labels a bit (by 45 degree), so they fit better
plot->getXAxis()->setTickLabelAngle(45);
plot->getXAxis()->setTickLabelFontSize(12);
} else {
// 7. data is grouped into 5 numbere groups (1..5), but we also have string
// labels for these groups (stored in L). In order to display these labels,
// we have to tell the x-Axis to use these special labels:
plot->getYAxis()->addAxisTickLabels(X, L, Ndata);
plot->getYAxis()->setTickLabelFontSize(12);
}
// 8. finally we move the plot key/legend to the outside, top-right
// and lay it out as a single row
// NOTE: plot is a descendent of QWidget, which uses an internal object of
// type JKQTBasePlotter, which does the actual plotting.
// So many properties of the plot are only available in this internal
// object, which you can access by plot.getPlotter().
plot.getPlotter()->setKeyPosition(JKQTPKeyOutsideTopRight);
plot.getPlotter()->setKeyLayout(JKQTPKeyLayoutOneRow);
// object, which you can access by plot->getPlotter().
plot->getPlotter()->setKeyPosition(JKQTPKeyOutsideTopRight);
plot->getPlotter()->setKeyLayout(JKQTPKeyLayoutOneRow);
// 9 autoscale the plot so the graph is contained
plot.zoomToFit();
plot->zoomToFit();
// show plotter and make it a decent size
plot.show();
plot.resize(600,400);
plot->show();
plot->resize(600,400);
}
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
doExample<JKQTPBarVerticalGraph>();
doExample<JKQTPBarHorizontalGraph>();
return app.exec();
}

View File

@ -48,6 +48,7 @@ isEmpty(JKQTP_PLOTTER_PRI_INCLUDED) {
$$PWD/jkqtplotter/graphs/jkqtpscatter.h \
$$PWD/jkqtplotter/graphs/jkqtprange.h \
$$PWD/jkqtplotter/graphs/jkqtpspecialline.h \
$$PWD/jkqtplotter/graphs/jkqtpbarchartbase.h \
$$PWD/jkqtplotter/graphs/jkqtpbarchart.h \
$$PWD/jkqtplotter/graphs/jkqtpevaluatedparametriccurve.h \
$$PWD/jkqtplotter/gui/jkqtpcomboboxes.h \
@ -97,6 +98,7 @@ isEmpty(JKQTP_PLOTTER_PRI_INCLUDED) {
$$PWD/jkqtplotter/graphs/jkqtpscatter.cpp \
$$PWD/jkqtplotter/graphs/jkqtprange.cpp \
$$PWD/jkqtplotter/graphs/jkqtpspecialline.cpp \
$$PWD/jkqtplotter/graphs/jkqtpbarchartbase.cpp \
$$PWD/jkqtplotter/graphs/jkqtpbarchart.cpp \
$$PWD/jkqtplotter/graphs/jkqtpevaluatedparametriccurve.cpp \
$$PWD/jkqtplotter/gui/jkqtpcomboboxes.cpp \

View File

@ -40,6 +40,7 @@ set(SOURCES_GRAPHS
graphs/jkqtpscatter.cpp
graphs/jkqtprange.cpp
graphs/jkqtpspecialline.cpp
graphs/jkqtpbarchartbase.cpp
graphs/jkqtpbarchart.cpp
graphs/jkqtpboxplot.cpp
graphs/jkqtpboxplotstylingmixins.cpp
@ -115,6 +116,7 @@ set(HEADERS_GRAPHS
graphs/jkqtpscatter.h
graphs/jkqtprange.h
graphs/jkqtpspecialline.h
graphs/jkqtpbarchartbase.h
graphs/jkqtpbarchart.h
graphs/jkqtpevaluatedparametriccurve.h
)

View File

@ -37,14 +37,9 @@
JKQTPBarVerticalGraph::JKQTPBarVerticalGraph(JKQTBasePlotter* parent):
JKQTPXYGraph(parent)
JKQTPBarGraphBase(parent)
{
baseline=0.0;
width=0.9;
shift=0;
initFillStyle(parent, parentPlotStyle);
initLineStyle(parent, parentPlotStyle);
}
@ -53,23 +48,6 @@ JKQTPBarVerticalGraph::JKQTPBarVerticalGraph(JKQTPlotter* parent):
{
}
void JKQTPBarVerticalGraph::drawKeyMarker(JKQTPEnhancedPainter& painter, QRectF& rect) {
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
QPen p=getLinePenForRects(painter, parent);
QPen np(Qt::NoPen);
QBrush b=getFillBrush(painter, parent);
//int y=rect.top()+rect.height()/2.0;
painter.setPen(p);
painter.setBrush(b);
painter.drawRect(rect);
}
QColor JKQTPBarVerticalGraph::getKeyLabelColor() const {
return getFillColor();
}
void JKQTPBarVerticalGraph::draw(JKQTPEnhancedPainter& painter) {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaaot("JKQTPBarHorizontalGraph::draw");
@ -158,139 +136,46 @@ void JKQTPBarVerticalGraph::draw(JKQTPEnhancedPainter& painter) {
}
bool JKQTPBarVerticalGraph::getXMinMax(double& minx, double& maxx, double& smallestGreaterZero) {
bool start=true;
minx=0;
maxx=0;
smallestGreaterZero=0;
if (parent==nullptr) return false;
JKQTPDatastore* datastore=parent->getDatastore();
int imin=0;
int imax=static_cast<int>(qMin(datastore->getRows(static_cast<size_t>(xColumn)), datastore->getRows(static_cast<size_t>(yColumn))));
if (imax<imin) {
int h=imin;
imin=imax;
imax=h;
}
if (imin<0) imin=0;
if (imax<0) imax=0;
for (int i=imin; i<imax; i++) {
double xv=datastore->get(static_cast<size_t>(xColumn),static_cast<size_t>(i));
int sr=datastore->getNextLowerIndex(xColumn, i);
int lr=datastore->getNextHigherIndex(xColumn, i);
double delta, deltap, deltam;
if (sr<0 && lr<0) { // only one x-value
deltam=0.5;
deltap=0.5;
} else if (lr<0) { // the right-most x-value
deltap=deltam=fabs(xv-datastore->get(xColumn,sr))/2.0;
} else if (sr<0) { // the left-most x-value
deltam=deltap=fabs(datastore->get(xColumn,lr)-xv)/2.0;
} else {
deltam=fabs(xv-datastore->get(xColumn,sr))/2.0;
deltap=fabs(datastore->get(xColumn,lr)-xv)/2.0;
}
delta=deltap+deltam;
if (JKQTPIsOKFloat(xv) && JKQTPIsOKFloat(delta) ) {
if (start || xv+shift*delta+width*delta/2.0>maxx) maxx=xv+shift*delta+width*delta/2.0;
if (start || xv+shift*delta-width*delta/2.0<minx) minx=xv+shift*delta-width*delta/2.0;
double xvsgz;
xvsgz=xv+shift*delta+width*delta/2.0; SmallestGreaterZeroCompare_xvsgz();
xvsgz=xv+shift*delta-width*delta/2.0; SmallestGreaterZeroCompare_xvsgz();
start=false;
}
}
return !start;
return getPositionsMinMax(minx, maxx, smallestGreaterZero);
}
bool JKQTPBarVerticalGraph::getYMinMax(double& miny, double& maxy, double& smallestGreaterZero) {
miny=0;
maxy=0;
smallestGreaterZero=0;
if (baseline>0) {
smallestGreaterZero=baseline;
miny=baseline;
maxy=baseline;
}
if (parent==nullptr) return false;
JKQTPDatastore* datastore=parent->getDatastore();
int imin=0;
int imax=static_cast<int>(qMin(datastore->getRows(static_cast<size_t>(xColumn)), datastore->getRows(static_cast<size_t>(yColumn))));
if (imax<imin) {
int h=imin;
imin=imax;
imax=h;
}
if (imin<0) imin=0;
if (imax<0) imax=0;
for (int i=imin; i<imax; i++) {
double stack=0;
double yv=baseline;
if (!isHorizontal()) {
stack=getParentStackedMax(i);
yv=stack;
}
if (JKQTPIsOKFloat(yv)) {
if (yv>maxy) maxy=yv;
if (yv<miny) miny=yv;
double xvsgz;
xvsgz=yv; SmallestGreaterZeroCompare_xvsgz();
}
yv=stack+datastore->get(static_cast<size_t>(yColumn),static_cast<size_t>(i));
if (JKQTPIsOKFloat(yv)) {
if (yv>maxy) maxy=yv;
if (yv<miny) miny=yv;
double xvsgz;
xvsgz=yv; SmallestGreaterZeroCompare_xvsgz();
}
}
return true;
return getValuesMinMax(miny, maxy, smallestGreaterZero);
}
void JKQTPBarVerticalGraph::autoscaleBarWidthAndShift(double maxWidth, double shrinkFactor)
int JKQTPBarVerticalGraph::getBarPositionColumn() const
{
if (parent) {
double cntH=0;
for (size_t i=0; i<parent->getGraphCount(); i++) {
JKQTPPlotElement* g=parent->getGraph(i);
JKQTPBarVerticalGraph* gb=qobject_cast<JKQTPBarVerticalGraph*>(g);
if (gb && gb->isHorizontal()==isHorizontal()) {
cntH++;
}
}
double widthH=1.0/cntH*maxWidth*shrinkFactor;
double dH=maxWidth/(cntH);
double h=0.1+dH/2.0;
for (size_t i=0; i<parent->getGraphCount(); i++) {
JKQTPPlotElement* g=parent->getGraph(i);
JKQTPBarVerticalGraph* gb=qobject_cast<JKQTPBarVerticalGraph*>(g);
if (gb && gb->isHorizontal()==isHorizontal()) {
if (cntH>1) {
gb->width=widthH;
gb->shift=h-0.5;
h=h+dH;
} else {
gb->width=maxWidth;
gb->shift=0.0;
}
}
}
}
return xColumn;
}
void JKQTPBarVerticalGraph::autoscaleBarWidthAndShiftSeparatedGroups(double groupWidth) {
autoscaleBarWidthAndShift(groupWidth, 1);
int JKQTPBarVerticalGraph::getBarHeightColumn() const
{
return yColumn;
}
void JKQTPBarVerticalGraph::setBarPositionColumn(int column)
{
xColumn=column;
}
void JKQTPBarVerticalGraph::setBarPositionColumn(size_t column)
{
xColumn=column;
}
void JKQTPBarVerticalGraph::setBarHeightColumn(int column)
{
yColumn=column;
}
void JKQTPBarVerticalGraph::setBarHeightColumn(size_t column)
{
yColumn=column;
}
bool JKQTPBarVerticalGraph::considerForAutoscaling(JKQTPBarGraphBase *other) const
{
return (dynamic_cast<JKQTPBarVerticalGraph*>(other)!=nullptr);
}
@ -303,7 +188,7 @@ void JKQTPBarVerticalGraph::autoscaleBarWidthAndShiftSeparatedGroups(double grou
JKQTPBarHorizontalGraph::JKQTPBarHorizontalGraph(JKQTBasePlotter *parent):
JKQTPBarVerticalGraph(parent)
JKQTPBarGraphBase(parent)
{
}
@ -314,6 +199,41 @@ JKQTPBarHorizontalGraph::JKQTPBarHorizontalGraph(JKQTPlotter *parent):
}
int JKQTPBarHorizontalGraph::getBarPositionColumn() const
{
return yColumn;
}
int JKQTPBarHorizontalGraph::getBarHeightColumn() const
{
return xColumn;
}
void JKQTPBarHorizontalGraph::setBarPositionColumn(int column)
{
yColumn=column;
}
void JKQTPBarHorizontalGraph::setBarPositionColumn(size_t column)
{
yColumn=column;
}
void JKQTPBarHorizontalGraph::setBarHeightColumn(int column)
{
xColumn=column;
}
void JKQTPBarHorizontalGraph::setBarHeightColumn(size_t column)
{
xColumn=column;
}
bool JKQTPBarHorizontalGraph::considerForAutoscaling(JKQTPBarGraphBase *other) const
{
return (dynamic_cast<JKQTPBarHorizontalGraph*>(other)!=nullptr);
}
void JKQTPBarHorizontalGraph::draw(JKQTPEnhancedPainter& painter) {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaaot("JKQTPBarVerticalGraph::draw");
@ -401,180 +321,18 @@ void JKQTPBarHorizontalGraph::draw(JKQTPEnhancedPainter& painter) {
}
bool JKQTPBarHorizontalGraph::getXMinMax(double& minx, double& maxx, double& smallestGreaterZero) {
minx=0;
maxx=0;
smallestGreaterZero=0;
if (baseline>0) {
smallestGreaterZero=baseline;
minx=baseline;
maxx=baseline;
}
if (parent==nullptr) return false;
JKQTPDatastore* datastore=parent->getDatastore();
int imin=0;
int imax=static_cast<int>(qMin(datastore->getRows(static_cast<size_t>(xColumn)), datastore->getRows(static_cast<size_t>(yColumn))));
if (imax<imin) {
int h=imin;
imin=imax;
imax=h;
}
if (imin<0) imin=0;
if (imax<0) imax=0;
for (int i=imin; i<imax; i++) {
double stack=0;
double xv=baseline;
if (isHorizontal()) {
stack=getParentStackedMax(i);
xv=stack;
}
if (JKQTPIsOKFloat(xv)) {
if (xv>maxx) maxx=xv;
if (xv<minx) minx=xv;
double xvsgz;
xvsgz=xv; SmallestGreaterZeroCompare_xvsgz();
}
xv=stack+datastore->get(static_cast<size_t>(xColumn),static_cast<size_t>(i));
if (JKQTPIsOKFloat(xv)) {
if (xv>maxx) maxx=xv;
if (xv<minx) minx=xv;
double xvsgz;
xvsgz=xv; SmallestGreaterZeroCompare_xvsgz();
}
}
return true;
return getValuesMinMax(minx, maxx, smallestGreaterZero);
}
bool JKQTPBarHorizontalGraph::getYMinMax(double& miny, double& maxy, double& smallestGreaterZero) {
bool start=true;
miny=0;
maxy=0;
smallestGreaterZero=0;
return getPositionsMinMax(miny, maxy, smallestGreaterZero);
if (parent==nullptr) return false;
JKQTPDatastore* datastore=parent->getDatastore();
int imin=0;
int imax=static_cast<int>(qMin(datastore->getRows(static_cast<size_t>(xColumn)), datastore->getRows(static_cast<size_t>(yColumn))));
if (imax<imin) {
int h=imin;
imin=imax;
imax=h;
}
if (imin<0) imin=0;
if (imax<0) imax=0;
for (int i=imin; i<imax; i++) {
double yv=datastore->get(static_cast<size_t>(yColumn),static_cast<size_t>(i));
double delta, deltap, deltam;
int sr=datastore->getNextLowerIndex(yColumn, i);
int lr=datastore->getNextHigherIndex(yColumn, i);
if (sr<0 && lr<0) { // only one y-value
deltam=0.5;
deltap=0.5;
} else if (lr<0) { // the right-most y-value
deltap=deltam=fabs(yv-datastore->get(yColumn,sr))/2.0;
} else if (sr<0) { // the left-most y-value
deltam=deltap=fabs(datastore->get(yColumn,lr)-yv)/2.0;
} else {
deltam=fabs(yv-datastore->get(yColumn,sr))/2.0;
deltap=fabs(datastore->get(yColumn,lr)-yv)/2.0;
}
delta=deltap+deltam;
if (JKQTPIsOKFloat(yv) && JKQTPIsOKFloat(delta) ) {
if (start || yv+shift*delta+width*delta/2.0>maxy) maxy=yv+shift*delta+width*delta/2.0;
if (start || yv+shift*delta-width*delta/2.0<miny) miny=yv+shift*delta-width*delta/2.0;
double xvsgz;
xvsgz=yv+shift*delta+width*delta/2.0; SmallestGreaterZeroCompare_xvsgz();
xvsgz=yv+shift*delta-width*delta/2.0; SmallestGreaterZeroCompare_xvsgz();
start=false;
}
}
return !start;
}
bool JKQTPBarHorizontalGraph::isHorizontal() const
{
return true;
}
double JKQTPBarVerticalGraph::getParentStackedMax(int /*index*/) const
{
return false;
}
bool JKQTPBarVerticalGraph::hasStackParent() const
{
return false;
}
double JKQTPBarVerticalGraph::getStackedMax(int /*index*/) const
{
return baseline;
}
bool JKQTPBarVerticalGraph::isHorizontal() const
{
return false;
}
void JKQTPBarVerticalGraph::setColor(QColor c)
{
setLineColor(c);
setFillColor(JKQTPGetDerivedColor(parent->getCurrentPlotterStyle().graphFillColorDerivationMode, c));
c.setAlphaF(0.5);
setHighlightingLineColor(c);
}
void JKQTPBarVerticalGraph::setShift(double __value)
{
this->shift = __value;
}
double JKQTPBarVerticalGraph::getShift() const
{
return this->shift;
}
void JKQTPBarVerticalGraph::setWidth(double __value)
{
this->width = __value;
}
double JKQTPBarVerticalGraph::getWidth() const
{
return this->width;
}
void JKQTPBarVerticalGraph::setBaseline(double __value)
{
this->baseline = __value;
}
double JKQTPBarVerticalGraph::getBaseline() const
{
return this->baseline;
}
void JKQTPBarVerticalGraph::setFillColor_and_darkenedColor(QColor fill, int colorDarker)
{
setFillColor(fill);
setLineColor(fill.darker(colorDarker));
}
JKQTPBarHorizontalErrorGraph::JKQTPBarHorizontalErrorGraph(JKQTBasePlotter *parent):
JKQTPBarHorizontalGraph(parent)
{
@ -641,6 +399,38 @@ void JKQTPBarHorizontalErrorGraph::drawErrorsAfter(JKQTPEnhancedPainter &painter
else plotErrorIndicators(painter, parent, this, xColumn, yColumn, 0.0, shift, &sortedIndices);
}
int JKQTPBarHorizontalErrorGraph::getBarErrorColumn() const
{
return getXErrorColumn();
}
int JKQTPBarHorizontalErrorGraph::getBarLowerErrorColumn() const
{
return getXErrorColumnLower();
}
void JKQTPBarHorizontalErrorGraph::setBarErrorColumn(int column)
{
setXErrorColumn(column);
}
void JKQTPBarHorizontalErrorGraph::setBarErrorColumn(size_t column)
{
setXErrorColumn(column);
}
void JKQTPBarHorizontalErrorGraph::setBarLowerErrorColumn(int column)
{
setXErrorColumnLower(column);
}
void JKQTPBarHorizontalErrorGraph::setBarLowerErrorColumn(size_t column)
{
setXErrorColumnLower(column);
}
JKQTPBarVerticalErrorGraph::JKQTPBarVerticalErrorGraph(JKQTBasePlotter *parent):
JKQTPBarVerticalGraph(parent)
{
@ -745,6 +535,36 @@ bool JKQTPBarVerticalErrorGraph::getYMinMax(double &miny, double &maxy, double &
}
}
int JKQTPBarVerticalErrorGraph::getBarErrorColumn() const
{
return getYErrorColumn();
}
int JKQTPBarVerticalErrorGraph::getBarLowerErrorColumn() const
{
return getYErrorColumnLower();
}
void JKQTPBarVerticalErrorGraph::setBarErrorColumn(int column)
{
setYErrorColumn(column);
}
void JKQTPBarVerticalErrorGraph::setBarErrorColumn(size_t column)
{
setYErrorColumn(column);
}
void JKQTPBarVerticalErrorGraph::setBarLowerErrorColumn(int column)
{
setYErrorColumnLower(column);
}
void JKQTPBarVerticalErrorGraph::setBarLowerErrorColumn(size_t column)
{
setYErrorColumnLower(column);
}
void JKQTPBarVerticalErrorGraph::drawErrorsAfter(JKQTPEnhancedPainter &painter)
{
//plotErrorIndicators(painter, parent, this, xColumn, yColumn, shift, 0.0);
@ -752,6 +572,17 @@ void JKQTPBarVerticalErrorGraph::drawErrorsAfter(JKQTPEnhancedPainter &painter)
else plotErrorIndicators(painter, parent, this, xColumn, yColumn, shift, 0, &sortedIndices);
}
JKQTPBarVerticalStackableGraph::JKQTPBarVerticalStackableGraph(JKQTBasePlotter *parent):
JKQTPBarVerticalGraph(parent), stackParent(nullptr)
{
@ -779,7 +610,7 @@ double JKQTPBarVerticalStackableGraph::getParentStackedMax(int index) const
if (stackParent) {
return stackParent->getStackedMax(index);
} else {
return 0.0;
return baseline;
}
}
@ -793,7 +624,10 @@ const JKQTPBarVerticalStackableGraph *JKQTPBarVerticalStackableGraph::getStackPa
return stackParent;
}
JKQTPBarVerticalStackableGraph *JKQTPBarVerticalStackableGraph::getStackParent()
{
return stackParent;
}
double JKQTPBarVerticalStackableGraph::getStackedMax(int index) const
{
@ -836,6 +670,11 @@ const JKQTPBarHorizontalStackableGraph *JKQTPBarHorizontalStackableGraph::getSta
return stackParent;
}
JKQTPBarHorizontalStackableGraph *JKQTPBarHorizontalStackableGraph::getStackParent()
{
return stackParent;
}
double JKQTPBarHorizontalStackableGraph::getStackedMax(int index) const
{
@ -856,7 +695,7 @@ double JKQTPBarHorizontalStackableGraph::getParentStackedMax(int index) const
if (stackParent) {
return stackParent->getStackedMax(index);
} else {
return 0.0;
return baseline;
}
}

View File

@ -26,12 +26,13 @@
#include "jkqtplotter/jkqtpgraphsbase.h"
#include "jkqtplotter/jkqtpgraphsbaseerrors.h"
#include "jkqtplotter/jkqtpgraphsbasestylingmixins.h"
#include "jkqtplotter/graphs/jkqtpbarchartbase.h"
#ifndef jkqtpgraphsbarchart_H
#define jkqtpgraphsbarchart_H
/*! \brief This implements a bar graph with bars starting at \f$ y=0 \f$ to \f$ y=f(x) \f$
/*! \brief This implements a bar graph with bars starting at \f$ yoverride \f$ to \f$ y=f(x) \f$
\ingroup jkqtplotter_barssticks
This class plots a bargraph. This image explains the parameters:
@ -43,7 +44,7 @@
to plot multiple bars for every x-value, by having on JKQTPSpecialLineHorizontalGraph object per
set of bars that belong together. For example for three bars per x-value one would set:
\verbatim
width=0.3
widthoverride.3
shift=-0.3 / 0 / +0.3
\endverbatim
This results in a bargraph, as shown here:
@ -56,7 +57,7 @@
\see JKQTPBarHorizontalGraph, \ref JKQTPlotterBarcharts, jkqtpstatAddHHistogram1D(), jkqtpstatAddHHistogram1DAutoranged()
*/
class JKQTPLOTTER_LIB_EXPORT JKQTPBarVerticalGraph: public JKQTPXYGraph, public JKQTPGraphLineStyleMixin, public JKQTPGraphFillStyleMixin {
class JKQTPLOTTER_LIB_EXPORT JKQTPBarVerticalGraph: public JKQTPBarGraphBase {
Q_OBJECT
public:
/** \brief class constructor */
@ -66,10 +67,6 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPBarVerticalGraph: public JKQTPXYGraph, public
/** \brief plots the graph to the plotter object specified as parent */
virtual void draw(JKQTPEnhancedPainter& painter) override;
/** \brief plots a key marker inside the specified rectangle \a rect */
virtual void drawKeyMarker(JKQTPEnhancedPainter& painter, QRectF& rect) override;
/** \brief returns the color to be used for the key label */
virtual QColor getKeyLabelColor() const override;
/** \brief get the maximum and minimum x-value of the graph
*
@ -81,132 +78,35 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPBarVerticalGraph: public JKQTPXYGraph, public
* The result is given in the two parameters which are call-by-reference parameters!
*/
virtual bool getYMinMax(double& miny, double& maxy, double& smallestGreaterZero) override;
/** \brief returns xColumn or yColumn, whichever is used for the position of the bars (depending on whether the barchart is vertical or horizontal \see getBarHeightColumn(), xColumn, yColumn */
virtual int getBarPositionColumn() const override;
/** \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 override;
/** \brief finds all bar charts of the same orientation and determines width and shift, so they stand side by side
*
* \param maxWidth the maximum (relative) width, that all bars will span of the (doubled) inter-bar distance
* \param shrinkFactor factor, by which the bar are shrinked compared to the available space
*
* \note This function will scale ALL graphs of the parent plot, which were derived from JKQTPBarHorizontalGraph, that match in orientation (as returned by isHorizontal() ).
*/
virtual void autoscaleBarWidthAndShift(double maxWidth=0.9, double shrinkFactor=0.8);
public slots:
/** \brief returns xColumn or yColumn, whichever is used for the position of the bars (depending on whether the barchart is vertical or horizontal \see getBarHeightColumn(), xColumn, yColumn */
virtual void setBarPositionColumn(int column) override;
/** \brief returns xColumn or yColumn, whichever is used for the position of the bars (depending on whether the barchart is vertical or horizontal \see getBarHeightColumn(), xColumn, yColumn */
virtual void setBarPositionColumn(size_t column) override;
/** \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 void setBarHeightColumn(int column) override;
/** \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 void setBarHeightColumn(size_t column) override;
/** \brief equivalent to \c autoscaleBarWidthAndShift(groupWidth,1);
*/
void autoscaleBarWidthAndShiftSeparatedGroups(double groupWidth=0.75);
/** \brief retruns \c true, if the bars are horizontal (JKQTPBarHorizontalGraph) and \c false if they are vertical (JKQTPBarVerticalGraph) */
virtual bool isHorizontal() const;
/** \brief set outline and fill color at the same time
* \see setFillColor_and_darkenedColor()
*/
virtual void setColor(QColor c);
/*! \copydoc shift */
void setShift(double __value);
/*! \copydoc shift */
double getShift() const;
/*! \copydoc width */
void setWidth(double __value);
/*! \copydoc width */
double getWidth() const;
/*! \copydoc baseline */
void setBaseline(double __value);
/*! \copydoc baseline */
double getBaseline() const;
/** \brief sets the fill color and the color together, where fillColor is set to \a fill and the line-color is set to \c fill.darker(colorDarker)
* \see setColor()
*/
void setFillColor_and_darkenedColor(QColor fill, int colorDarker=200);
protected:
/** \brief the width of the bargraphs, relative to the distance between the current and the next x-value
*
* See the following graphic to understand this concept:
* \image html bargraph_basics.png
*/
double width;
/** \brief the shift of the bargraphs, relative to the distance between the current and the next x-value
*
* See the following graphic to understand this concept:
* \image html bargraph_basics.png
*/
double shift;
/** \brief baseline of the plot (NOTE: 0 is interpreted as until plot border in log-mode!!!)
*/
double baseline;
/** \brief used to generate stacked plots: returns the upper boundary of this plot in a stack, for the index-th datapoint
*
* \note This function returns \a baseline in this implementation. It is implemented in the derived classes JKQTPBarVerticalStackableGraph
* and JKQTPBarHorizontalStackableGraph. The function is placed here, so the plotting does not have to be reimplemented in the
* derived classes that allow for stacking, but can be implemented once centrally.
*/
virtual double getStackedMax(int index) const;
/** \brief calls getStackedMax() on the stack parent (if available)
*
* \note This function returns \c 0.0 in this implementation. It is implemented in the derived classes JKQTPBarVerticalStackableGraph
* and JKQTPBarHorizontalStackableGraph. The function is placed here, so the plotting does not have to be reimplemented in the
* derived classes that allow for stacking, but can be implemented once centrally.
*/
virtual double getParentStackedMax(int index) const;
/** \brief returns \c true, if a stack parent is set (if available)
*
* \note This function returns \c false in this implementation. It is implemented in the derived classes JKQTPBarVerticalStackableGraph
* and JKQTPBarHorizontalStackableGraph. The function is placed here, so the plotting does not have to be reimplemented in the
* derived classes that allow for stacking, but can be implemented once centrally.
*/
virtual bool hasStackParent() const;
/** \brief this function is used by autoscaleBarWidthAndShift() to determine whether a given graph shall be taken into account when autoscaling.
* Typically this returns \c true for all JKQTPBarGraphBase-derved objects with the same orientation (horizontal or vertical) */
virtual bool considerForAutoscaling( JKQTPBarGraphBase* other) const override;
};
/*! \brief This implements a bar graph with bars starting at \f$ y=0 \f$ to \f$ y=f(x) \f$
* Optionally several graphs of this type may be stacked on top of each other
* \ingroup jkqtplotter_barssticks
*
* Draw stacked barcharts by connecting several plots by calling \c setStackedParent(belowPlot) for each plot
* \image html JKQTPBarVerticalGraphStacked.png
*
* \see JKQTPBarVerticalGraph, \ref JKQTPlotterStackedBarChart
*/
class JKQTPLOTTER_LIB_EXPORT JKQTPBarVerticalStackableGraph: public JKQTPBarVerticalGraph {
Q_OBJECT
public:
/** \brief class constructor */
JKQTPBarVerticalStackableGraph(JKQTBasePlotter* parent=nullptr);
/** \brief class constructor */
JKQTPBarVerticalStackableGraph(JKQTPlotter* parent);
/** \brief stacks this barchart upon the given \a parentGraph */
void stackUpon(JKQTPBarVerticalStackableGraph* parentGraph);
/** \brief unstacks this graph (i.e. deletes the parent graph in the stack) */
void dontStackUpon();
/** \brief returns the stack parent graph, or \c nullptr */
const JKQTPBarVerticalStackableGraph* getStackParent() const;
protected:
/** \brief if set (!=nullptr), the current plot is drawn stacked onto this plot
*
* draw stacked barcharts by connecting several plots by calling \c setStackedParent(belowPlot) for each plot
*/
JKQTPBarVerticalStackableGraph* stackParent;
/** \brief used to generate stacked plots: returns the upper boundary of this plot in a stack, for the index-th datapoint */
virtual double getStackedMax(int index) const override;
/** \brief calls getStackedMax() on the stack parent (if available), or \c 0.0 */
virtual double getParentStackedMax(int index) const override;
/** \brief returns \c true, if a stack parent is set (if available) */
virtual bool hasStackParent() const override;
};
/*! \brief This implements a bar graph with bars starting at \f$ y=0 \f$ to \f$ y=f(x) \f$
/*! \brief This implements a bar graph with bars starting at \f$ yoverride \f$ to \f$ y=f(x) \f$
* and error indicator
* \ingroup jkqtplotter_barssticks
*
@ -231,6 +131,22 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPBarVerticalErrorGraph: public JKQTPBarVertical
*/
virtual bool getYMinMax(double& miny, double& maxy, double& smallestGreaterZero) override;
/** \brief returns the column that contains the bar height errors */
int getBarErrorColumn() const;
/** \brief returns the column that contains the lower bar height errors */
int getBarLowerErrorColumn() const;
public slots:
/** \brief sets the column that contains the bar height errors */
void setBarErrorColumn(int column) ;
/** \brief sets the column that contains the bar height errors */
void setBarErrorColumn(size_t column) ;
/** \brief sets the column that contains the bar height errors */
void setBarLowerErrorColumn(int column) ;
/** \brief sets the column that contains the bar height errors */
void setBarLowerErrorColumn(size_t column) ;
protected:
/** \brief this function is used to plot error inidcators before plotting the graphs. */
virtual void drawErrorsAfter(JKQTPEnhancedPainter& painter) override;
@ -239,7 +155,8 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPBarVerticalErrorGraph: public JKQTPBarVertical
/*! \brief This implements a bar graph with bars starting at \f$ x=0 \f$ to \f$ x=f(y) \f$
/*! \brief This implements a bar graph with bars starting at \f$ xoverride \f$ to \f$ x=f(y) \f$
\ingroup jkqtplotter_barssticks
This works much the same as JKQTPBarHorizontalGraph. Here is an example output:
@ -249,7 +166,7 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPBarVerticalErrorGraph: public JKQTPBarVertical
\see \ref JKQTPlotterBarcharts, jkqtpstatAddVHistogram1D(), jkqtpstatAddVHistogram1DAutoranged()
*/
class JKQTPLOTTER_LIB_EXPORT JKQTPBarHorizontalGraph: public JKQTPBarVerticalGraph {
class JKQTPLOTTER_LIB_EXPORT JKQTPBarHorizontalGraph: public JKQTPBarGraphBase {
Q_OBJECT
public:
/** \brief class constructor */
@ -271,54 +188,34 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPBarHorizontalGraph: public JKQTPBarVerticalGra
*/
virtual bool getYMinMax(double& miny, double& maxy, double& smallestGreaterZero) override;
virtual bool isHorizontal() const override;
/** \brief returns xColumn or yColumn, whichever is used for the position of the bars (depending on whether the barchart is vertical or horizontal \see getBarHeightColumn(), xColumn, yColumn */
virtual int getBarPositionColumn() const override;
/** \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 override;
public slots:
/** \brief sets xColumn or yColumn, whichever is used for the position of the bars (depending on whether the barchart is vertical or horizontal \see getBarHeightColumn(), xColumn, yColumn */
virtual void setBarPositionColumn(int column) override;
/** \brief sets xColumn or yColumn, whichever is used for the position of the bars (depending on whether the barchart is vertical or horizontal \see getBarHeightColumn(), xColumn, yColumn */
virtual void setBarPositionColumn(size_t column) override;
/** \brief sets 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 void setBarHeightColumn(int column) override;
/** \brief sets 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 void setBarHeightColumn(size_t column) override;
protected:
/** \brief this function is used by autoscaleBarWidthAndShift() to determine whether a given graph shall be taken into account when autoscaling.
* Typically this returns \c true for all JKQTPBarGraphBase-derved objects with the same orientation (horizontal or vertical) */
virtual bool considerForAutoscaling( JKQTPBarGraphBase* other) const override;
};
/*! \brief This implements a bar graph with bars starting at \f$ y=0 \f$ to \f$ y=f(x) \f$
* Optionally several graphs of this type may be stacked on top of each other
* \ingroup jkqtplotter_barssticks
*
* Draw stacked barcharts by connecting several plots by calling \c setStackedParent(belowPlot) for each plot
* \image html JKQTPBarHorizontalGraphStacked.png
*
*
* \see JKQTPBarHorizontalGraph, \ref JKQTPlotterStackedBarChart
*/
class JKQTPLOTTER_LIB_EXPORT JKQTPBarHorizontalStackableGraph: public JKQTPBarHorizontalGraph {
Q_OBJECT
public:
/** \brief class constructor */
JKQTPBarHorizontalStackableGraph(JKQTBasePlotter* parent=nullptr);
/** \brief class constructor */
JKQTPBarHorizontalStackableGraph(JKQTPlotter* parent);
/** \brief stacks this barchart upon the given \a parentGraph */
void stackUpon(JKQTPBarHorizontalStackableGraph* parentGraph);
/** \brief unstacks this graph (i.e. deletes the parent graph in the stack) */
void dontStackUpon();
/** \brief returns the stack parent graph, or \c nullptr */
const JKQTPBarHorizontalStackableGraph* getStackParent() const;
protected:
/** \brief if set (!=nullptr), the current plot is drawn stacked onto this plot
*
* draw stacked barcharts by connecting several plots by calling \c setStackedParent(belowPlot) for each plot
*/
JKQTPBarHorizontalStackableGraph* stackParent;
/** \brief used to generate stacked plots: returns the upper boundary of this plot in a stack, for the index-th datapoint */
virtual double getStackedMax(int index) const override;
/** \brief calls getStackedMax() on the stack parent (if available), or \c 0.0 */
virtual double getParentStackedMax(int index) const override;
/** \brief returns \c true, if a stack parent is set (if available) */
virtual bool hasStackParent() const override;
};
/*! \brief This implements a bar graph with bars starting at \f$ x=0 \f$ to \f$ x=f(y) \f$
/*! \brief This implements a bar graph with bars starting at \f$ xoverride \f$ to \f$ x=f(y) \f$
* and error indicator
* \ingroup jkqtplotter_barssticks
*
@ -344,6 +241,22 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPBarHorizontalErrorGraph: public JKQTPBarHorizo
*/
virtual bool getXMinMax(double& minx, double& maxx, double& smallestGreaterZero) override;
/** \brief returns the column that contains the bar height errors */
int getBarErrorColumn() const;
/** \brief returns the column that contains the lower bar height errors */
int getBarLowerErrorColumn() const;
public slots:
/** \brief sets the column that contains the bar height errors */
void setBarErrorColumn(int column) ;
/** \brief sets the column that contains the bar height errors */
void setBarErrorColumn(size_t column) ;
/** \brief sets the column that contains the bar height errors */
void setBarLowerErrorColumn(int column) ;
/** \brief sets the column that contains the bar height errors */
void setBarLowerErrorColumn(size_t column) ;
protected:
/** \brief this function is used to plot error inidcators before plotting the graphs. */
virtual void drawErrorsAfter(JKQTPEnhancedPainter& painter) override;
@ -355,4 +268,109 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPBarHorizontalErrorGraph: public JKQTPBarHorizo
/*! \brief This implements a bar graph with bars starting at \f$ yoverride \f$ to \f$ y=f(x) \f$
* Optionally several graphs of this type may be stacked on top of each other
* \ingroup jkqtplotter_barssticks
*
* Draw stacked barcharts by connecting several plots by calling \c setStackedParent(belowPlot) for each plot
* \image html JKQTPBarVerticalGraphStacked.png
*
* \see JKQTPBarVerticalGraph, \ref JKQTPlotterStackedBarChart
*/
class JKQTPLOTTER_LIB_EXPORT JKQTPBarVerticalStackableGraph: public JKQTPBarVerticalGraph {
Q_OBJECT
public:
/** \brief class constructor */
JKQTPBarVerticalStackableGraph(JKQTBasePlotter* parent=nullptr);
/** \brief class constructor */
JKQTPBarVerticalStackableGraph(JKQTPlotter* parent);
/** \brief stacks this barchart upon the given \a parentGraph */
void stackUpon(JKQTPBarVerticalStackableGraph* parentGraph);
/** \brief unstacks this graph (i.e. deletes the parent graph in the stack) */
void dontStackUpon();
/** \brief returns the stack parent graph, or \c nullptr */
const JKQTPBarVerticalStackableGraph* getStackParent() const;
/** \brief returns the stack parent graph, or \c nullptr */
JKQTPBarVerticalStackableGraph* getStackParent();
protected:
/** \brief if set (!=nullptr), the current plot is drawn stacked onto this plot
*
* draw stacked barcharts by connecting several plots by calling \c setStackedParent(belowPlot) for each plot
*/
JKQTPBarVerticalStackableGraph* stackParent;
/** \brief used to generate stacked plots: returns the upper boundary of the parent plot in a stack, for the index-th datapoint */
double getParentStackedMax(int index) const ;
/** \brief returns \c true, if a stack parent is set (if available) */
bool hasStackParent() const ;
/** \brief used to generate stacked plots: returns the upper boundary of this plot in a stack, for the index-th datapoint */
double getStackedMax(int index) const;
};
/*! \brief This implements a bar graph with bars starting at \f$ yoverride \f$ to \f$ y=f(x) \f$
* Optionally several graphs of this type may be stacked on top of each other
* \ingroup jkqtplotter_barssticks
*
* Draw stacked barcharts by connecting several plots by calling \c setStackedParent(belowPlot) for each plot
* \image html JKQTPBarHorizontalGraphStacked.png
*
*
* \see JKQTPBarHorizontalGraph, \ref JKQTPlotterStackedBarChart
*/
class JKQTPLOTTER_LIB_EXPORT JKQTPBarHorizontalStackableGraph: public JKQTPBarHorizontalGraph {
Q_OBJECT
public:
/** \brief class constructor */
JKQTPBarHorizontalStackableGraph(JKQTBasePlotter* parent=nullptr);
/** \brief class constructor */
JKQTPBarHorizontalStackableGraph(JKQTPlotter* parent);
/** \brief stacks this barchart upon the given \a parentGraph */
void stackUpon(JKQTPBarHorizontalStackableGraph* parentGraph);
/** \brief unstacks this graph (i.e. deletes the parent graph in the stack) */
void dontStackUpon();
/** \brief returns the stack parent graph, or \c nullptr */
const JKQTPBarHorizontalStackableGraph* getStackParent() const;
/** \brief returns the stack parent graph, or \c nullptr */
JKQTPBarHorizontalStackableGraph* getStackParent() ;
protected:
/** \brief if set (!=nullptr), the current plot is drawn stacked onto this plot
*
* draw stacked barcharts by connecting several plots by calling \c setStackedParent(belowPlot) for each plot
*/
JKQTPBarHorizontalStackableGraph* stackParent;
/** \brief used to generate stacked plots: returns the upper boundary of the parent plot in a stack, for the index-th datapoint */
virtual double getParentStackedMax(int index) const override;
/** \brief returns \c true, if a stack parent is set (if available) */
virtual bool hasStackParent() const override;
/** \brief used to generate stacked plots: returns the upper boundary of this plot in a stack, for the index-th datapoint */
double getStackedMax(int index) const;
};
#endif // jkqtpgraphsbarchart_H

View File

@ -0,0 +1,273 @@
/*
Copyright (c) 2008-2020 Jan W. Krieger (<jan@jkrieger.de>)
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 <http://www.gnu.org/licenses/>.
*/
#include "jkqtplotter/graphs/jkqtpbarchartbase.h"
#include "jkqtplotter/jkqtpbaseplotter.h"
#include <stdlib.h>
#include <QDebug>
#include <iostream>
#include "jkqtplotter/jkqtptools.h"
#include "jkqtplotter/graphs/jkqtpimage.h"
#include "jkqtplotter/jkqtpbaseelements.h"
#include "jkqtplotter/jkqtplotter.h"
#define SmallestGreaterZeroCompare_xvsgz() if ((xvsgz>10.0*DBL_MIN)&&((smallestGreaterZero<10.0*DBL_MIN) || (xvsgz<smallestGreaterZero))) smallestGreaterZero=xvsgz;
JKQTPBarGraphBase::JKQTPBarGraphBase(JKQTBasePlotter* parent):
JKQTPXYGraph(parent), width(0.9), shift(0), baseline(0.0)
{
initFillStyle(parent, parentPlotStyle);
initLineStyle(parent, parentPlotStyle);
}
JKQTPBarGraphBase::JKQTPBarGraphBase(JKQTPlotter* parent):
JKQTPBarGraphBase(parent->getPlotter())
{
}
void JKQTPBarGraphBase::drawKeyMarker(JKQTPEnhancedPainter& painter, QRectF& rect) {
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
QPen p=getLinePenForRects(painter, parent);
QPen np(Qt::NoPen);
QBrush b=getFillBrush(painter, parent);
//int y=rect.top()+rect.height()/2.0;
painter.setPen(p);
painter.setBrush(b);
painter.drawRect(rect);
}
QColor JKQTPBarGraphBase::getKeyLabelColor() const {
return getFillColor();
}
void JKQTPBarGraphBase::autoscaleBarWidthAndShift(double maxWidth, double shrinkFactor)
{
if (parent) {
double cntH=0;
for (size_t i=0; i<parent->getGraphCount(); i++) {
JKQTPPlotElement* g=parent->getGraph(i);
JKQTPBarGraphBase* gb=qobject_cast<JKQTPBarGraphBase*>(g);
if (gb && considerForAutoscaling(gb)) {
cntH++;
}
}
double widthH=1.0/cntH*maxWidth*shrinkFactor;
double dH=maxWidth/(cntH);
double h=0.1+dH/2.0;
for (size_t i=0; i<parent->getGraphCount(); i++) {
JKQTPPlotElement* g=parent->getGraph(i);
JKQTPBarGraphBase* gb=qobject_cast<JKQTPBarGraphBase*>(g);
if (gb && considerForAutoscaling(gb)) {
if (cntH>1) {
gb->width=widthH;
gb->shift=h-0.5;
h=h+dH;
} else {
gb->width=maxWidth;
gb->shift=0.0;
}
}
}
}
}
void JKQTPBarGraphBase::autoscaleBarWidthAndShiftSeparatedGroups(double groupWidth) {
autoscaleBarWidthAndShift(groupWidth, 1);
}
void JKQTPBarGraphBase::setColor(QColor c)
{
setLineColor(c);
setFillColor(JKQTPGetDerivedColor(parent->getCurrentPlotterStyle().graphFillColorDerivationMode, c));
c.setAlphaF(0.5);
setHighlightingLineColor(c);
}
void JKQTPBarGraphBase::setShift(double __value)
{
this->shift = __value;
}
double JKQTPBarGraphBase::getShift() const
{
return this->shift;
}
void JKQTPBarGraphBase::setWidth(double __value)
{
this->width = __value;
}
double JKQTPBarGraphBase::getWidth() const
{
return this->width;
}
void JKQTPBarGraphBase::setBaseline(double __value)
{
this->baseline = __value;
}
double JKQTPBarGraphBase::getBaseline() const
{
return this->baseline;
}
void JKQTPBarGraphBase::setFillColor_and_darkenedColor(QColor fill, int colorDarker)
{
setFillColor(fill);
setLineColor(fill.darker(colorDarker));
}
double JKQTPBarGraphBase::getParentStackedMax(int /*index*/) const
{
return baseline;
}
bool JKQTPBarGraphBase::hasStackParent() const
{
return false;
}
bool JKQTPBarGraphBase::getValuesMinMax(double &mmin, double &mmax, double &smallestGreaterZero)
{
mmin=0;
mmax=0;
smallestGreaterZero=0;
if (baseline>0) {
smallestGreaterZero=baseline;
mmin=baseline;
mmax=baseline;
}
if (getBarPositionColumn()<0 || getBarHeightColumn()<0) return false;
const size_t poscol=static_cast<size_t>(getBarPositionColumn());
const size_t datacol=static_cast<size_t>(getBarHeightColumn());
if (parent==nullptr) return false;
JKQTPDatastore* datastore=parent->getDatastore();
int imin=0;
int imax=static_cast<int>(qMin(datastore->getRows(poscol), datastore->getRows(datacol)));
if (imax<imin) {
int h=imin;
imin=imax;
imax=h;
}
if (imin<0) imin=0;
if (imax<0) imax=0;
for (int i=imin; i<imax; i++) {
double stack=0;
double yv=baseline;
const double boxstart=getParentStackedMax(i);
if (hasStackParent()) {
stack=boxstart;
yv=stack;
}
if (JKQTPIsOKFloat(yv)) {
if (yv>mmax) mmax=yv;
if (yv<mmin) mmin=yv;
double xvsgz;
xvsgz=yv; SmallestGreaterZeroCompare_xvsgz();
}
yv=stack+datastore->get(datacol,static_cast<size_t>(i));
if (JKQTPIsOKFloat(yv)) {
if (yv>mmax) mmax=yv;
if (yv<mmin) mmin=yv;
double xvsgz;
xvsgz=yv; SmallestGreaterZeroCompare_xvsgz();
}
}
return true;
}
bool JKQTPBarGraphBase::getPositionsMinMax(double &mmin, double &mmax, double &smallestGreaterZero)
{
bool start=true;
mmin=0;
mmax=0;
smallestGreaterZero=0;
if (getBarPositionColumn()<0 || getBarHeightColumn()<0) return false;
const size_t poscol=static_cast<size_t>(getBarPositionColumn());
const size_t datacol=static_cast<size_t>(getBarHeightColumn());
if (parent==nullptr) return false;
JKQTPDatastore* datastore=parent->getDatastore();
int imin=0;
int imax=static_cast<int>(qMin(datastore->getRows(poscol), datastore->getRows(datacol)));
if (imax<imin) {
int h=imin;
imin=imax;
imax=h;
}
if (imin<0) imin=0;
if (imax<0) imax=0;
for (int i=imin; i<imax; i++) {
double xv=datastore->get(poscol,static_cast<size_t>(i));
int sr=datastore->getNextLowerIndex(poscol, i);
int lr=datastore->getNextHigherIndex(poscol, i);
double delta, deltap, deltam;
if (sr<0 && lr<0) { // only one x-value
deltam=0.5;
deltap=0.5;
} else if (lr<0) { // the right-most x-value
deltap=deltam=fabs(xv-datastore->get(poscol,sr))/2.0;
} else if (sr<0) { // the left-most x-value
deltam=deltap=fabs(datastore->get(poscol,lr)-xv)/2.0;
} else {
deltam=fabs(xv-datastore->get(poscol,sr))/2.0;
deltap=fabs(datastore->get(poscol,lr)-xv)/2.0;
}
delta=deltap+deltam;
if (JKQTPIsOKFloat(xv) && JKQTPIsOKFloat(delta) ) {
if (start || xv+shift*delta+width*delta/2.0>mmax) mmax=xv+shift*delta+width*delta/2.0;
if (start || xv+shift*delta-width*delta/2.0<mmin) mmin=xv+shift*delta-width*delta/2.0;
double xvsgz;
xvsgz=xv+shift*delta+width*delta/2.0; SmallestGreaterZeroCompare_xvsgz();
xvsgz=xv+shift*delta-width*delta/2.0; SmallestGreaterZeroCompare_xvsgz();
start=false;
}
}
return !start;
}

View File

@ -0,0 +1,172 @@
/*
Copyright (c) 2008-2020 Jan W. Krieger (<jan@jkrieger.de>)
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 <http://www.gnu.org/licenses/>.
*/
#include <QString>
#include <QPainter>
#include <QPair>
#include "jkqtplotter/jkqtptools.h"
#include "jkqtplotter/jkqtplotter_imexport.h"
#include "jkqtplotter/jkqtpimagetools.h"
#include "jkqtplotter/jkqtpgraphsbase.h"
#include "jkqtplotter/jkqtpgraphsbaseerrors.h"
#include "jkqtplotter/jkqtpgraphsbasestylingmixins.h"
#ifndef jkqtpgraphsbarchartbase_H
#define jkqtpgraphsbarchartbase_H
/** \brief This is a base-class for all bar graphs with vertical or horizontal orientation (the orientation is implemented in dervied classes!)
* \ingroup jkqtplotter_barssticks
*
* This class plots a bargraph. This image explains the parameters:
*
* \image html bargraph_basics.png
*
* By default the sift parameter is, so the bar is centered at the x-value. The width is 0.9,
* so adjacent bars are plotted with a small distance between them. It is possible to use these two parameters
* to plot multiple bars for every x-value, by having on JKQTPSpecialLineHorizontalGraph object per
* set of bars that belong together. For example for three bars per x-value one would set:
* \verbatim
* width=0.3
* shift=-0.3 / 0 / +0.3
* \endverbatim
* This results in a bargraph, as shown here:
*
* \image html plot_bargraphverplot.png
*
*
*
* \see JKQTPBarHorizontalGraph, JKQTPBarVerticalGraph
*/
class JKQTPLOTTER_LIB_EXPORT JKQTPBarGraphBase: public JKQTPXYGraph, public JKQTPGraphLineStyleMixin, public JKQTPGraphFillStyleMixin {
Q_OBJECT
public:
/** \brief class constructor */
JKQTPBarGraphBase(JKQTBasePlotter* parent=nullptr);
/** \brief class constructor */
JKQTPBarGraphBase(JKQTPlotter* parent);
/** \brief plots a key marker inside the specified rectangle \a rect */
virtual void drawKeyMarker(JKQTPEnhancedPainter& painter, QRectF& rect) override;
/** \brief returns the color to be used for the key label */
virtual QColor getKeyLabelColor() const override;
/*! \copydoc shift */
double getShift() const;
/*! \copydoc width */
double getWidth() const;
/*! \copydoc baseline */
double getBaseline() const;
/** \brief sets the fill color and the color together, where fillColor is set to \a fill and the line-color is set to \c fill.darker(colorDarker)
* \see setColor()
*/
void setFillColor_and_darkenedColor(QColor fill, int colorDarker=200);
/** \brief returns xColumn or yColumn, whichever is used for the position of the bars (depending on whether the barchart is vertical or horizontal \see getBarHeightColumn(), xColumn, yColumn */
virtual int getBarPositionColumn() const =0;
/** \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;
public slots:
/** \brief finds all bar charts of the same orientation and determines width and shift, so they stand side by side
*
* \param maxWidth the maximum (relative) width, that all bars will span of the (doubled) inter-bar distance
* \param shrinkFactor factor, by which the bar are shrinked compared to the available space
*
* \note This function will scale ALL graphs of the parent plot, which were derived from JKQTPBarHorizontalGraph, that match in orientation (as returned by isHorizontal() ).
*/
virtual void autoscaleBarWidthAndShift(double maxWidth=0.9, double shrinkFactor=0.8);
/** \brief equivalent to \c autoscaleBarWidthAndShift(groupWidth,1);
*/
void autoscaleBarWidthAndShiftSeparatedGroups(double groupWidth=0.75);
/*! \copydoc shift */
void setShift(double __value);
/*! \copydoc width */
void setWidth(double __value);
/*! \copydoc baseline */
void setBaseline(double __value);
/** \brief set outline and fill color at the same time
* \see setFillColor_and_darkenedColor()
*/
virtual void setColor(QColor c);
/** \brief returns xColumn or yColumn, whichever is used for the position of the bars (depending on whether the barchart is vertical or horizontal \see getBarHeightColumn(), xColumn, yColumn */
virtual void setBarPositionColumn(int column) =0;
/** \brief returns xColumn or yColumn, whichever is used for the position of the bars (depending on whether the barchart is vertical or horizontal \see getBarHeightColumn(), xColumn, yColumn */
virtual void setBarPositionColumn(size_t column) =0;
/** \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 void setBarHeightColumn(int column) =0;
/** \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 void setBarHeightColumn(size_t column) =0;
protected:
/** \brief the width of the bargraphs, relative to the distance between the current and the next x-value
*
* See the following graphic to understand this concept:
* \image html bargraph_basics.png
*/
double width;
/** \brief the shift of the bargraphs, relative to the distance between the current and the next x-value
*
* See the following graphic to understand this concept:
* \image html bargraph_basics.png
*/
double shift;
/** \brief baseline of the plot (NOTE: 0 is interpreted as until plot border in log-mode!!!)
*/
double baseline;
/** \brief this function is used by autoscaleBarWidthAndShift() to determine whether a given graph shall be taken into account when autoscaling.
* Typically this returns \c true for all JKQTPBarGraphBase-derved objects with the same orientation (horizontal or vertical) */
virtual bool considerForAutoscaling( JKQTPBarGraphBase* other) const=0;
/** \brief used to generate stacked plots: returns the upper boundary of the parent plot in a stack, for the index-th datapoint */
virtual double getParentStackedMax(int index) const ;
/** \brief returns \c true, if a stack parent is set (if available) */
virtual bool hasStackParent() const ;
/** \brief get the maximum and minimum value in the box-elongation (i.e. value) direction of the graph
*
* The result is given in the two parameters which are call-by-reference parameters!
*/
bool getValuesMinMax(double& mmin, double& mmax, double& smallestGreaterZero) ;
/** \brief get the maximum and minimum value of the box positions of the graph
*
* The result is given in the two parameters which are call-by-reference parameters!
*/
bool getPositionsMinMax(double& mmin, double& mmax, double& smallestGreaterZero) ;
};
#endif // jkqtpgraphsbarchartbase_H

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB