- improved/breaking change: reworked class hierarchy of range charts.

- new: added JKQTPFilledHorizontalRangeGraph, complementing JKQTPFilledVerticalRangeGraph
This commit is contained in:
jkriege2 2020-09-19 14:41:53 +02:00
parent 8cee70bdca
commit 6875e0ae6c
9 changed files with 265 additions and 166 deletions

View File

@ -343,7 +343,7 @@ This group assembles graphs that show their data with symbols and optionally wit
<td> JKQTPFilledCurveXErrorGraph, JKQTPFilledCurveYErrorGraph
<tr>
<td>\image html JKQTPfilledVerticalRangeGraph_WithLines_small.png
<td> JKQTPFilledVerticalRangeGraph
<td> JKQTPFilledVerticalRangeGraph, JKQTPFilledHorizontalRangeGraph
</table>
\defgroup jkqtplotter_functiongraphs Function Graphs

View File

@ -27,6 +27,7 @@ Changes, compared to \ref page_whatsnew_V2019_11 "v2019.11" include:
<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 hierarchy of parsed function plots and declared several setters as slots.</li>
<li>improved/breaking change: reworked class hierarchy of bar charts.</li>
<li>improved/breaking change: reworked class hierarchy of range charts.</li>
<li>improved/breaking change: reworked graph Base-Classes (promoted several setters to slots, added Q_PROPERTY- and Q_ENUM-declarations...)</li>
<li>improved/breaking change: made more functions and function parameters const</li>
<li>bugfixed/improved: aspect ratio handling in JKQTPlotter.</li>
@ -34,7 +35,8 @@ Changes, compared to \ref page_whatsnew_V2019_11 "v2019.11" include:
<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>
<li>new: a new graph class JKQTPXYFunctionLineGraph draws parametric 2D curves ( \f$ [x,y] = f(t) \f$ ), see \ref JKQTPlotterEvalCurves for an example</li>
<li>new: added several new copy/set-functions to JKQTPDatastore</li>
<li>new: added JPQTPlotter signal, when widget was resized</li>
<li>new: added JKQTPlotter signal, when widget was resized</li>
<li>new: added JKQTPFilledHorizontalRangeGraph, complementing JKQTPFilledVerticalRangeGraph</li>
</ul>
\subsection page_whatsnew_TRUNK_DOWNLOAD trunk: Download

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

View File

@ -124,9 +124,8 @@ void JKQTPFilledCurveYErrorGraph::drawErrorsAfter(JKQTPEnhancedPainter &painter)
JKQTPFilledVerticalRangeGraph::JKQTPFilledVerticalRangeGraph(JKQTBasePlotter *parent):
JKQTPXYGraph(parent)
JKQTPXYYGraph(parent)
{
drawLine=true;
initFillStyle(parent, parentPlotStyle);
initLineStyle(parent, parentPlotStyle);
}
@ -137,52 +136,6 @@ JKQTPFilledVerticalRangeGraph::JKQTPFilledVerticalRangeGraph(JKQTPlotter *parent
}
bool JKQTPFilledVerticalRangeGraph::getYMinMax(double &miny, double &maxy, double &smallestGreaterZero)
{
bool start=true;
miny=0;
maxy=0;
smallestGreaterZero=0;
if (parent==nullptr) return false;
JKQTPDatastore* datastore=parent->getDatastore();
int imin=0;
int imax=static_cast<int>(qMin(qMin(datastore->getRows(static_cast<size_t>(xColumn)), datastore->getRows(static_cast<size_t>(yColumn))), datastore->getRows(static_cast<size_t>(yColumn2))));
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 yv2=datastore->get(static_cast<size_t>(yColumn2),static_cast<size_t>(i));
if (JKQTPIsOKFloat(yv)) {
if (start || yv>maxy) maxy=yv;
if (start || yv<miny) miny=yv;
double xvsgz;
xvsgz=yv; SmallestGreaterZeroCompare_xvsgz();
start=false;
}
if (JKQTPIsOKFloat(yv2)) {
if (start || yv2>maxy) maxy=yv2;
if (start || yv2<miny) miny=yv2;
double xvsgz;
xvsgz=yv2; SmallestGreaterZeroCompare_xvsgz();
start=false;
}
}
return !start;
}
bool JKQTPFilledVerticalRangeGraph::usesColumn(int column) const
{
return JKQTPXYGraph::usesColumn(column)||(column==yColumn2);
}
void JKQTPFilledVerticalRangeGraph::draw(JKQTPEnhancedPainter &painter)
{
#ifdef JKQTBP_AUTOTIMER
@ -202,64 +155,59 @@ void JKQTPFilledVerticalRangeGraph::draw(JKQTPEnhancedPainter &painter)
QBrush b=getFillBrush(painter, parent);
int imax=static_cast<int>(qMin(qMin(datastore->getRows(static_cast<size_t>(xColumn)), datastore->getRows(static_cast<size_t>(yColumn))), datastore->getRows(static_cast<size_t>(yColumn2))));
int imax=0;
int imin=0;
if (imax<imin) {
int h=imin;
imin=imax;
imax=h;
}
if (imin<0) imin=0;
if (imax<0) imax=0;
if (getIndexRange(imin, imax)) {
// upper points are added to poly_all, lower points to plow
// then plow points are added to poly_all in vewerse order
// then the whole thing is drawn
QPolygonF poly_all, phigh, plow;
// upper points are added to poly_all, lower points to plow
// then plow points are added to poly_all in vewerse order
// then the whole thing is drawn
QPolygonF poly_all, phigh, plow;
intSortData();
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));
double yv=datastore->get(static_cast<size_t>(yColumn),static_cast<size_t>(i));
double yv2=datastore->get(static_cast<size_t>(yColumn2),static_cast<size_t>(i));
//std::cout<<"(xv, yv) = ( "<<xv<<", "<<yv<<" )\n";
if (JKQTPIsOKFloat(xv)) {
double x=transformX(xv); bool xok=JKQTPIsOKFloat(x);
double y=transformY(yv); bool yok=JKQTPIsOKFloat(y);
double y2=transformY(yv2); bool y2ok=JKQTPIsOKFloat(y2);
intSortData();
for (int iii=imin; iii<imax; iii++) {
int i=qBound(imin, getDataIndex(iii), imax);
const double xv=datastore->get(static_cast<size_t>(xColumn),static_cast<size_t>(i));
const double yv=datastore->get(static_cast<size_t>(yColumn),static_cast<size_t>(i));
const double yv2=datastore->get(static_cast<size_t>(yColumn2),static_cast<size_t>(i));
//std::cout<<"(xv, yv) = ( "<<xv<<", "<<yv<<" )\n";
if (JKQTPIsOKFloat(xv)) {
const double x=transformX(xv); const bool xok=JKQTPIsOKFloat(x);
const double y=transformY(yv); const bool yok=JKQTPIsOKFloat(y);
const double y2=transformY(yv2); const bool y2ok=JKQTPIsOKFloat(y2);
if (xok&&yok) phigh.append(QPointF(x,y));
if (xok&&yok) poly_all.append(QPointF(x,y));
if (xok&&y2ok) plow.append(QPointF(x,y2));
if (xok&&yok) phigh.append(QPointF(x,y));
if (xok&&yok) poly_all.append(QPointF(x,y));
if (xok&&y2ok) plow.append(QPointF(x,y2));
}
}
}
if (plow.size()>0) {
for (int i=plow.size()-1; i>=0; i--) {
poly_all.append(plow[i]);
if (plow.size()>0) {
for (int i=plow.size()-1; i>=0; i--) {
poly_all.append(plow[i]);
}
}
}
painter.setBrush(b);
painter.setPen(np);
painter.drawPolygon(poly_all);
painter.setBrush(b);
painter.setPen(np);
painter.drawPolygon(poly_all);
if (drawLine) {
painter.save(); auto __finalpaintline=JKQTPFinally([&painter]() {painter.restore();});
if (getDrawLine()) {
painter.save(); auto __finalpaintline=JKQTPFinally([&painter]() {painter.restore();});
if (isHighlighted()) {
if (isHighlighted()) {
painter.setPen(ps);
painter.setPen(ps);
painter.drawPolyline(phigh);
painter.drawPolyline(plow);
}
painter.setPen(p);
painter.drawPolyline(phigh);
painter.drawPolyline(plow);
}
painter.setPen(p);
painter.drawPolyline(phigh);
painter.drawPolyline(plow);
}
}
drawErrorsAfter(painter);
@ -272,7 +220,7 @@ void JKQTPFilledVerticalRangeGraph::drawKeyMarker(JKQTPEnhancedPainter &painter,
r.setHeight(r.height()/2.0);
r.moveTo(r.x(), r.y()+r.height()-1);
painter.fillRect(r, getFillBrush(painter, parent));
if (drawLine) {
if (getDrawLine()) {
painter.setPen(getLinePen(painter, parent));
painter.drawLine(QLineF(r.topLeft(), r.topRight()));
}
@ -284,26 +232,114 @@ QColor JKQTPFilledVerticalRangeGraph::getKeyLabelColor() const
return getLineColor();
}
void JKQTPFilledVerticalRangeGraph::setYColumn2(int __value)
JKQTPFilledHorizontalRangeGraph::JKQTPFilledHorizontalRangeGraph(JKQTBasePlotter *parent):
JKQTPXXYGraph(parent)
{
this->yColumn2 = __value;
initFillStyle(parent, parentPlotStyle);
initLineStyle(parent, parentPlotStyle);
}
int JKQTPFilledVerticalRangeGraph::getYColumn2() const
JKQTPFilledHorizontalRangeGraph::JKQTPFilledHorizontalRangeGraph(JKQTPlotter *parent):
JKQTPFilledHorizontalRangeGraph(parent->getPlotter())
{
return this->yColumn2;
}
void JKQTPFilledVerticalRangeGraph::setYColumn2(size_t __value) {
this->yColumn2 = static_cast<int>(__value);
void JKQTPFilledHorizontalRangeGraph::draw(JKQTPEnhancedPainter &painter)
{
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaaot("JKQTPFilledCurveXGraph::draw");
#endif
if (parent==nullptr) return;
JKQTPDatastore* datastore=parent->getDatastore();
if (datastore==nullptr) return;
drawErrorsBefore(painter);
{
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
QPen p=getLinePen(painter, parent);
QPen ps=getHighlightingLinePen(painter, parent);
QPen np(Qt::NoPen);
QBrush b=getFillBrush(painter, parent);
int imax=0;
int imin=0;
if (getIndexRange(imin, imax)) {
// upper points are added to poly_all, lower points to plow
// then plow points are added to poly_all in vewerse order
// then the whole thing is drawn
QPolygonF poly_all, phigh, plow;
intSortData();
for (int iii=imin; iii<imax; iii++) {
int i=qBound(imin, getDataIndex(iii), imax);
const double xv=datastore->get(static_cast<size_t>(xColumn),static_cast<size_t>(i));
const double yv=datastore->get(static_cast<size_t>(yColumn),static_cast<size_t>(i));
const double xv2=datastore->get(static_cast<size_t>(xColumn2),static_cast<size_t>(i));
//std::cout<<"(xv, yv) = ( "<<xv<<", "<<yv<<" )\n";
if (JKQTPIsOKFloat(xv)) {
const double x=transformX(xv); const bool xok=JKQTPIsOKFloat(x);
const double y=transformY(yv); const bool yok=JKQTPIsOKFloat(y);
const double x2=transformX(xv2); const bool x2ok=JKQTPIsOKFloat(x2);
if (xok&&yok) phigh.append(QPointF(x,y));
if (xok&&yok) poly_all.append(QPointF(x,y));
if (xok&&x2ok) plow.append(QPointF(x2,y));
}
}
if (plow.size()>0) {
for (int i=plow.size()-1; i>=0; i--) {
poly_all.append(plow[i]);
}
}
painter.setBrush(b);
painter.setPen(np);
painter.drawPolygon(poly_all);
if (getDrawLine()) {
painter.save(); auto __finalpaintline=JKQTPFinally([&painter]() {painter.restore();});
if (isHighlighted()) {
painter.setPen(ps);
painter.drawPolyline(phigh);
painter.drawPolyline(plow);
}
painter.setPen(p);
painter.drawPolyline(phigh);
painter.drawPolyline(plow);
}
}
}
drawErrorsAfter(painter);
}
void JKQTPFilledVerticalRangeGraph::setDrawLine(bool __value)
void JKQTPFilledHorizontalRangeGraph::drawKeyMarker(JKQTPEnhancedPainter &painter, QRectF &rect)
{
drawLine=__value;
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
QRectF r=rect;
r.setHeight(r.height()/2.0);
r.moveTo(r.x(), r.y()+r.height()-1);
painter.fillRect(r, getFillBrush(painter, parent));
if (getDrawLine()) {
painter.setPen(getLinePen(painter, parent));
painter.drawLine(QLineF(r.topLeft(), r.topRight()));
}
}
bool JKQTPFilledVerticalRangeGraph::getDrawLine() const
QColor JKQTPFilledHorizontalRangeGraph::getKeyLabelColor() const
{
return drawLine;
return getLineColor();
}

View File

@ -137,23 +137,15 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPFilledCurveYErrorGraph: public JKQTPFilledCurv
*
* \image html JKQTPfilledVerticalRangeGraph_WithLines.png
*
* \see \ref JKQTPlotterDateTimeAxes
* \see JKQTPFilledHorizontalRangeGraph, \ref JKQTPlotterDateTimeAxes
*/
class JKQTPLOTTER_LIB_EXPORT JKQTPFilledVerticalRangeGraph: public JKQTPXYGraph, public JKQTPGraphLineStyleMixin, public JKQTPGraphFillStyleMixin {
class JKQTPLOTTER_LIB_EXPORT JKQTPFilledVerticalRangeGraph: public JKQTPXYYGraph, public JKQTPGraphLineAndFillStyleMixin {
Q_OBJECT
public:
/** \brief class constructor */
JKQTPFilledVerticalRangeGraph(JKQTBasePlotter* parent=nullptr);
/** \brief class constructor */
JKQTPFilledVerticalRangeGraph(JKQTPlotter* parent);
/** \brief get the maximum and minimum y-value of the graph
*
* The result is given in the two parameters which are call-by-reference parameters!
*/
virtual bool getYMinMax(double& miny, double& maxy, double& smallestGreaterZero) override;
/** \copydoc JKQTPGraph::usesColumn() */
virtual bool usesColumn(int column) const override;
/** \brief plots the graph to the plotter object specified as parent */
virtual void draw(JKQTPEnhancedPainter& painter) override;
@ -162,26 +154,49 @@ public:
/** \brief returns the color to be used for the key label */
virtual QColor getKeyLabelColor() const override;
/*! \copydoc yColumn2 */
void setYColumn2(int __value);
/*! \copydoc yColumn2 */
int getYColumn2() const;
/*! \copydoc yColumn2 */
void setYColumn2 (size_t __value);
/*! \copydoc drawLine */
void setDrawLine(bool __value);
/*! \copydoc drawLine */
bool getDrawLine() const;
protected:
};
/** \brief This implements filled curve plots where the area is filled between two data columns for each y-value
* \ingroup jkqtplotter_filledgraphs
*
* With \c setDrawlines(false):
*
* \image html JKQTPFilledHorizontalRangeGraph.png
*
* With \c setDrawlines(true):
*
* \image html JKQTPFilledHorizontalRangeGraph_WithLines.png
*
* \see JKQTPFilledVerticalRangeGraph, \ref JKQTPlotterDateTimeAxes
*/
class JKQTPLOTTER_LIB_EXPORT JKQTPFilledHorizontalRangeGraph: public JKQTPXXYGraph, public JKQTPGraphLineAndFillStyleMixin {
Q_OBJECT
public:
/** \brief class constructor */
JKQTPFilledHorizontalRangeGraph(JKQTBasePlotter* parent=nullptr);
/** \brief class constructor */
JKQTPFilledHorizontalRangeGraph(JKQTPlotter* parent);
/** \brief plots the graph to the plotter object specified as parent */
virtual void draw(JKQTPEnhancedPainter& painter) override;
/** \brief plots a key marker inside the specified rectangle \a rect */
virtual void drawKeyMarker(JKQTPEnhancedPainter& painter, QRectF& rect) override;
/** \brief returns the color to be used for the key label */
virtual QColor getKeyLabelColor() const override;
protected:
/** \brief the column that contains the second y-component of the range */
int yColumn2;
/** \brief indicates whether to draw a line on the circumference of the described area (i.e. along the data points from \c xColumn and \c yColumn as well as \c xColumn and \c yColumn2 or not */
bool drawLine;
};

View File

@ -711,28 +711,30 @@ bool JKQTPXYYGraph::getYMinMax(double &miny, double &maxy, double &smallestGreat
const JKQTPDatastore* datastore=parent->getDatastore();
int imin=0;
int imax=0;
getIndexRange(imin, imax);
if (getIndexRange(imin, imax)) {
for (int i=imin; i<imax; i++) {
const double yv=datastore->get(static_cast<size_t>(yColumn),static_cast<size_t>(i));
if (JKQTPIsOKFloat(yv)) {
if (start || yv>maxy) maxy=yv;
if (start || yv<miny) miny=yv;
double xvsgz;
xvsgz=yv; SmallestGreaterZeroCompare_xvsgz();
start=false;
}
const double yv2=datastore->get(static_cast<size_t>(yColumn2),static_cast<size_t>(i));
if (JKQTPIsOKFloat(yv2)) {
if (start || yv2>maxy) maxy=yv2;
if (start || yv2<miny) miny=yv2;
double xvsgz;
xvsgz=yv2; SmallestGreaterZeroCompare_xvsgz();
start=false;
for (int i=imin; i<imax; i++) {
const double yv=datastore->get(static_cast<size_t>(yColumn),static_cast<size_t>(i));
if (JKQTPIsOKFloat(yv)) {
if (start || yv>maxy) maxy=yv;
if (start || yv<miny) miny=yv;
double xvsgz;
xvsgz=yv; SmallestGreaterZeroCompare_xvsgz();
start=false;
}
const double yv2=datastore->get(static_cast<size_t>(yColumn2),static_cast<size_t>(i));
if (JKQTPIsOKFloat(yv2)) {
if (start || yv2>maxy) maxy=yv2;
if (start || yv2<miny) miny=yv2;
double xvsgz;
xvsgz=yv2; SmallestGreaterZeroCompare_xvsgz();
start=false;
}
}
return !start;
}
return !start;
return false;
}
bool JKQTPXYYGraph::usesColumn(int column) const
@ -852,28 +854,30 @@ bool JKQTPXXYGraph::getXMinMax(double &minx, double &maxx, double &smallestGreat
const JKQTPDatastore* datastore=parent->getDatastore();
int imin=0;
int imax=0;
getIndexRange(imin, imax);
if (getIndexRange(imin, imax)) {
for (int i=imin; i<imax; i++) {
const double xv=datastore->get(static_cast<size_t>(xColumn),static_cast<size_t>(i));
if (JKQTPIsOKFloat(xv)) {
if (start || xv>maxx) maxx=xv;
if (start || xv<minx) minx=xv;
double xvsgz;
xvsgz=xv; SmallestGreaterZeroCompare_xvsgz();
start=false;
}
const double xv2=datastore->get(static_cast<size_t>(xColumn2),static_cast<size_t>(i));
if (JKQTPIsOKFloat(xv2)) {
if (start || xv2>maxx) maxx=xv2;
if (start || xv2<minx) minx=xv2;
double xvsgz;
xvsgz=xv2; SmallestGreaterZeroCompare_xvsgz();
start=false;
for (int i=imin; i<imax; i++) {
const double xv=datastore->get(static_cast<size_t>(xColumn),static_cast<size_t>(i));
if (JKQTPIsOKFloat(xv)) {
if (start || xv>maxx) maxx=xv;
if (start || xv<minx) minx=xv;
double xvsgz;
xvsgz=xv; SmallestGreaterZeroCompare_xvsgz();
start=false;
}
const double xv2=datastore->get(static_cast<size_t>(xColumn2),static_cast<size_t>(i));
if (JKQTPIsOKFloat(xv2)) {
if (start || xv2>maxx) maxx=xv2;
if (start || xv2<minx) minx=xv2;
double xvsgz;
xvsgz=xv2; SmallestGreaterZeroCompare_xvsgz();
start=false;
}
}
return !start;
}
return !start;
return false;
}
bool JKQTPXXYGraph::usesColumn(int column) const

View File

@ -565,3 +565,24 @@ double JKQTPGraphDecoratedHeadLineStyleMixin::calcHeadDecoratorSize(double line_
}
JKQTPGraphLineAndFillStyleMixin::JKQTPGraphLineAndFillStyleMixin():
m_drawLine(true)
{
}
void JKQTPGraphLineAndFillStyleMixin::setDrawLine(bool __value)
{
m_drawLine=__value;
}
bool JKQTPGraphLineAndFillStyleMixin::getDrawLine() const
{
return m_drawLine;
}
bool JKQTPGraphLineAndFillStyleMixin::doDrawLine() const
{
return m_drawLine;
}

View File

@ -446,6 +446,27 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPGraphFillStyleMixin {
/** \brief This Mix-In class provides setter/getter methods, storage and other facilities for the graph line and fill style
* \ingroup jkqtplotter_basegraphs_stylemixins
*/
class JKQTPLOTTER_LIB_EXPORT JKQTPGraphLineAndFillStyleMixin: public JKQTPGraphFillStyleMixin, public JKQTPGraphLineStyleMixin {
Q_GADGET
public:
/** \brief class constructor */
JKQTPGraphLineAndFillStyleMixin();
/*! \copydoc m_drawLine */
void setDrawLine(bool __value);
/*! \copydoc m_drawLine */
bool getDrawLine() const;
/*! \copydoc m_drawLine */
bool doDrawLine() const;
Q_PROPERTY(bool drawLine MEMBER m_drawLine READ getDrawLine WRITE setDrawLine)
private:
/** \brief indicates whether to draw a line on the circumference of the described area (i.e. along the data points from \c xColumn and \c yColumn as well as \c xColumn and \c yColumn2 or not */
bool m_drawLine;
};
/*! \brief This Mix-In class provides setter/getter methods, storage and other facilities for text in graphs