NEW: barcharts may hav rounded corners now, via JKQTPBarGraphBase::setRectRadius()

This commit is contained in:
jkriege2 2022-09-27 01:42:54 +02:00
parent 153c80d64b
commit 2da8553e5d
9 changed files with 195 additions and 16 deletions

View File

@ -9,7 +9,6 @@ This page lists several todos and wishes for future version of JKQTPlotter
<li>graph: matrix plots with boxes, labels, ...</li>
<li>graph: text labels at positions/for graphs</li>
<li>plot: secondary axes: independent and dependent (i.e. with transformation function from primary axis)</li>
<li>graphs: rounded rectangles for barcharts (also controllable by styles)</li>
<li>graphs: matrix plots with symbols: symbol-type, color, size should be parametric, cf. scatter plots</li>
<li>styling: color gradients as fill-styles in style-INIs</li>
<li>styling: style.ini with glowing colors in dark background ("techno" or "cyberpunk")</li>
@ -28,7 +27,6 @@ This page lists several todos and wishes for future version of JKQTPlotter
<li>graphic elements: make coordinate systems selectable for all: x/y-axis, 0..1/0..1, topleft/topright... </li>
<li>plot: reqork layouting of legends: there are some inconsistencies/too large gaps ...</li>
<li>plot: legend positioning as combination of 3 values: inside|outside + left|center|right + top|vcenter|bottom</li>
<li>styling/plot: make axes more customizable, e.g. color for each element, font for each element ...</li>
<li>plot: axes with symlog (see http://dx.doi.org/10.1088/0957-0233/24/2/027001) and logit (https://de.m.wikipedia.org/wiki/Logit) scaling? </li>
<li>graphs: add candlestick charts (financial, see https://en.m.wikipedia.org/wiki/Candlestick_chart)</li>
<li>graphs: add OHLC charts (financial, see https://en.m.wikipedia.org/wiki/Open-high-low-close_chart)</li>

View File

@ -60,6 +60,7 @@ Changes, compared to \ref page_whatsnew_V4_0_0 "v4.0.0" include:
<li>NEW: all elements of a coordinate axis may have their own color now </li>
<li>NEW: added possibility to scale the axis ticks by a factor (e.g. pi) to generate axes with ticks <tt>0pi, 1pi, 2pi ...</tt> </li>
<li>NEW: added option to draw a zero axis to JKQTPCoordinateAxis, which draws an axis at the origin of the coordinate system </li>
<li>NEW: barcharts may hav rounded corners now, via JKQTPBarGraphBase::setRectRadius()</li>
</ul></li>
<li>JKQTMathText:<ul>

View File

@ -76,6 +76,35 @@ void JKQTPEnhancedPainter::drawPolylineFast(const QPoint *points, int pointCount
}
}
void JKQTPEnhancedPainter::drawComplexRoundedRect(const QRectF &rin, double rTopLeft, double rTopRight, double rBottomLeft, double rBottomRight, Qt::SizeMode mode)
{
QRectF r=rin;
const double rTLX=(mode==Qt::RelativeSize)?(rTopLeft/100.0*r.width()):rTopLeft;
const double rTLY=(mode==Qt::RelativeSize)?(rTopLeft/100.0*r.height()):rTopLeft;
const double rTRX=(mode==Qt::RelativeSize)?(rTopRight/100.0*r.width()):rTopRight;
const double rTRY=(mode==Qt::RelativeSize)?(rTopRight/100.0*r.height()):rTopRight;
const double rBLX=(mode==Qt::RelativeSize)?(rBottomLeft/100.0*r.width()):rBottomLeft;
const double rBLY=(mode==Qt::RelativeSize)?(rBottomLeft/100.0*r.height()):rBottomLeft;
const double rBRX=(mode==Qt::RelativeSize)?(rBottomRight/100.0*r.width()):rBottomRight;
const double rBRY=(mode==Qt::RelativeSize)?(rBottomRight/100.0*r.height()):rBottomRight;
QPainterPath path;
path.moveTo(r.left()+rTLX,r.top());
path.lineTo(r.right()-rTRX,r.top());
path.quadTo(r.topRight(), QPointF(r.right(),r.top()+rTRY));
path.lineTo(r.right(),r.bottom()-rBRY);
path.quadTo(r.bottomRight(), QPointF(r.right()-rBRX,r.bottom()));
path.lineTo(r.left()+rBLX,r.bottom());
path.quadTo(r.bottomLeft(), QPointF(r.left(),r.bottom()-rBLY));
path.lineTo(r.left(),r.top()+rTLY);
path.quadTo(r.topLeft(), QPointF(r.left()+rTLX,r.top()));
path.closeSubpath();
drawPath(path);
}
JKQTPEnhancedPainter::PainterFlags JKQTPEnhancedPainter::painterFlags() const {
return m_flags;
}

View File

@ -69,6 +69,8 @@ class JKQTCOMMON_LIB_EXPORT JKQTPEnhancedPainter : public QPainter {
drawPolylineFast(polyline.constData(), int(polyline.size()));
}
/** \brief draw a rounded rect, where each corner has a separate radius */
void drawComplexRoundedRect(const QRectF& r, double rTopLeft, double rTopRight, double rBottomLeft, double rBottomRight, Qt::SizeMode mode = Qt::AbsoluteSize);
protected:
void initQEnhacedPainter();
private:

View File

@ -112,13 +112,27 @@ void JKQTPBarVerticalGraph::draw(JKQTPEnhancedPainter& painter) {
double yy=yv0;
//std::cout<<"delta="<<delta<<" x="<<x<<" y="<<y<<" xx="<<xx<<" yy="<<yy<<std::endl;
if (yy<y) { qSwap(y,yy); }
bool swapped=false;
if (yy<y) { qSwap(y,yy); swapped=true; }
if (JKQTPIsOKFloat(x) && JKQTPIsOKFloat(xx) && JKQTPIsOKFloat(y) && JKQTPIsOKFloat(yy)) {
if (yvdirect<getBaseline()) painter.setBrush(b_below);
else painter.setBrush(b);
painter.setPen(p);
const QRectF r(QPointF(x, y), QPointF(xx, yy));
painter.drawRect(r);
const double rAtBaseline=parent->pt2px(painter, rectRadiusAtBaseline);
const double rAtValue=parent->pt2px(painter, rectRadiusAtValue);
//qDebug()<<"r="<<r<<", rectRadiusAtBaseline="<<rectRadiusAtBaseline<<", rectRadiusAtValue="<<rectRadiusAtValue<<", rAtBaseline="<<rAtBaseline<<", rAtValue="<<rAtValue;
if (rAtBaseline+rAtValue>=r.height()+2) {
//qDebug()<<"drawRect";
painter.drawRect(r);
} else {
//qDebug()<<"drawRoundRect swapped="<<swapped;
if (swapped) {
painter.drawComplexRoundedRect(r,rAtBaseline,rAtBaseline,rAtValue,rAtValue,Qt::AbsoluteSize);
} else {
painter.drawComplexRoundedRect(r,rAtValue,rAtValue,rAtBaseline,rAtBaseline,Qt::AbsoluteSize);
}
}
}
}
@ -312,16 +326,26 @@ void JKQTPBarHorizontalGraph::draw(JKQTPEnhancedPainter& painter) {
double y=transformY(yv+shift*delta+width*deltap);
double xx=transformX(xv);
double yy=transformY(yv+shift*delta-width*deltam);
if (x>xx) { qSwap(x,xx); }
bool swapped=false;
if (x>xx) { qSwap(x,xx); swapped=true; }
//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)) {
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);
}
const QRectF r(QPointF(x, y), QPointF(xx, yy));
const double rAtBaseline=parent->pt2px(painter, rectRadiusAtBaseline);
const double rAtValue=parent->pt2px(painter, rectRadiusAtBaseline);
if (rAtBaseline+rAtValue>r.width()+2) {
painter.drawRect(r);
} else {
if (swapped) {
painter.drawComplexRoundedRect(r,rAtBaseline,rAtValue,rAtBaseline,rAtValue,Qt::AbsoluteSize);
} else {
painter.drawComplexRoundedRect(r,rAtValue,rAtBaseline,rAtValue,rAtBaseline,Qt::AbsoluteSize);
}
} }
}
}
}

View File

@ -25,8 +25,6 @@
#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;
@ -37,11 +35,13 @@
JKQTPBarGraphBase::JKQTPBarGraphBase(JKQTBasePlotter* parent):
JKQTPXYBaselineGraph(parent), width(0.9), shift(0), m_fillMode(FillMode::SingleFilling)
JKQTPXYBaselineGraph(parent), width(0.9), shift(0), m_fillMode(FillMode::SingleFilling),rectRadiusAtBaseline(0),rectRadiusAtValue(0)
{
initFillStyle(parent, parentPlotStyle, JKQTPPlotStyleType::Barchart);
initLineStyle(parent, parentPlotStyle, JKQTPPlotStyleType::Barchart);
m_fillStyleBelow.initFillStyleInvertedColor(this);
rectRadiusAtBaseline= parent->getCurrentPlotterStyle().graphsStyle.barchartStyle.defaultRectRadiusAtBaseline;
rectRadiusAtValue= parent->getCurrentPlotterStyle().graphsStyle.barchartStyle.defaultRectRadiusAtValue;
}
@ -157,6 +157,16 @@ JKQTPBarGraphBase::FillMode JKQTPBarGraphBase::getFillMode() const
return m_fillMode;
}
double JKQTPBarGraphBase::getRectRadiusAtValue() const
{
return rectRadiusAtValue;
}
double JKQTPBarGraphBase::getRectRadiusAtBaseline() const
{
return rectRadiusAtBaseline;
}
void JKQTPBarGraphBase::setFillMode(FillMode mode)
{
m_fillMode=mode;
@ -271,3 +281,25 @@ bool JKQTPBarGraphBase::getPositionsMinMax(double &mmin, double &mmax, double &s
return false;
}
void JKQTPBarGraphBase::setRectRadiusAtValue(double __value)
{
rectRadiusAtValue=__value;
}
void JKQTPBarGraphBase::setRectRadiusAtBaseline(double __value)
{
rectRadiusAtBaseline=__value;
}
void JKQTPBarGraphBase::setRectRadius(double all)
{
setRectRadiusAtValue(all);
setRectRadiusAtBaseline(all);
}
void JKQTPBarGraphBase::setRectRadius(double atValue, double atBaseline)
{
setRectRadiusAtValue(atValue);
setRectRadiusAtBaseline(atBaseline);
}

View File

@ -102,6 +102,11 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPBarGraphBase: public JKQTPXYBaselineGraph, pub
const JKQTPGraphFillStyleMixin& fillStyleBelow() const;
/** \copydoc m_fillMode */
FillMode getFillMode() const;
/** \copydoc rectRadiusAtValue */
double getRectRadiusAtValue() const;
/** \copydoc rectRadiusAtBaseline */
double getRectRadiusAtBaseline() const;
public slots:
/** \copydoc m_fillMode */
void setFillMode(JKQTPBarGraphBase::FillMode mode);
@ -123,6 +128,15 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPBarGraphBase: public JKQTPXYBaselineGraph, pub
/** \copydoc width */
void setWidth(double __value);
/** \copydoc rectRadiusAtValue */
void setRectRadiusAtValue(double __value);
/** \copydoc rectRadiusAtBaseline */
void setRectRadiusAtBaseline(double __value);
/** \brief sets the corner radius of the bars for both ends */
void setRectRadius(double all);
/** \brief sets the corner radius of the bars for both ends */
void setRectRadius(double atValue, double atBaseline);
/** \brief set outline and fill color at the same time
* \see setFillColor_and_darkenedColor()
@ -154,6 +168,10 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPBarGraphBase: public JKQTPXYBaselineGraph, pub
* \image html bargraph_basics.png
*/
double shift;
/** \brief corner radius (in pt) for bars at the "value" end */
double rectRadiusAtValue;
/** \brief corner radius (in pt) for bars at the "baseline" end */
double rectRadiusAtBaseline;
/** \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

View File

@ -194,10 +194,11 @@ void JKQTAnnotationsSpecificStyleProperties::saveSettings(QSettings &settings, c
JKQTGraphsBaseStyle::JKQTGraphsBaseStyle(const JKQTBasePlotterStyle& parent):
useAntiAliasingForGraphs(true),
defaultGraphStyle(JKQTPPlotStyleType::Default, parent),
barchartStyle(JKQTPPlotStyleType::Barchart, parent),
barchartStyle(parent),
boxplotStyle(JKQTPPlotStyleType::Boxplot, parent),
filledStyle(JKQTPPlotStyleType::Filled, parent),
impulseStyle(JKQTPPlotStyleType::Impulses, parent),
@ -286,7 +287,7 @@ void JKQTGraphsBaseStyle::loadSettings(const QSettings &settings, const QString
defaultGraphStyle.loadSettings(settings, group+"graphs_base/", JKQTGraphsSpecificStyleProperties(JKQTPPlotStyleType::Default, parent));
barchartStyle.loadSettings(settings, group+"graphs_barchart/", JKQTGraphsSpecificStyleProperties(JKQTPPlotStyleType::Barchart, defaultGraphStyle));
barchartStyle.loadSettings(settings, group+"graphs_barchart/", JKQTBarchartSpecificStyleProperties(parent, defaultGraphStyle));
boxplotStyle.loadSettings(settings, group+"graphs_boxplot/", JKQTGraphsSpecificStyleProperties(JKQTPPlotStyleType::Boxplot, defaultGraphStyle));
filledStyle.loadSettings(settings, group+"graphs_filled/", JKQTGraphsSpecificStyleProperties(JKQTPPlotStyleType::Filled, defaultGraphStyle));
impulseStyle.loadSettings(settings, group+"graphs_impulses/",JKQTGraphsSpecificStyleProperties(JKQTPPlotStyleType::Impulses, defaultGraphStyle));
@ -352,3 +353,37 @@ const JKQTGraphsSpecificStyleProperties &JKQTGraphsBaseStyle::getGraphStyleByTyp
}
return defaultGraphStyle;
}
JKQTBarchartSpecificStyleProperties::JKQTBarchartSpecificStyleProperties(const JKQTBasePlotterStyle& parent):
JKQTGraphsSpecificStyleProperties(JKQTPPlotStyleType::Barchart, parent),
defaultRectRadiusAtValue(0),
defaultRectRadiusAtBaseline(0)
{
}
JKQTBarchartSpecificStyleProperties::JKQTBarchartSpecificStyleProperties(const JKQTBasePlotterStyle& parent, const JKQTGraphsSpecificStyleProperties &other):
JKQTGraphsSpecificStyleProperties(JKQTPPlotStyleType::Barchart, other),
defaultRectRadiusAtValue(0),
defaultRectRadiusAtBaseline(0)
{
}
void JKQTBarchartSpecificStyleProperties::loadSettings(const QSettings &settings, const QString &group, const JKQTBarchartSpecificStyleProperties &defaultStyle)
{
JKQTGraphsSpecificStyleProperties::loadSettings(settings, group, defaultStyle);
defaultRectRadiusAtValue=settings.value(group+"radius_at_value", defaultStyle.defaultRectRadiusAtValue).toDouble();
defaultRectRadiusAtBaseline=settings.value(group+"radius_at_baseline", defaultStyle.defaultRectRadiusAtBaseline).toDouble();
}
void JKQTBarchartSpecificStyleProperties::saveSettings(QSettings &settings, const QString &group) const
{
JKQTGraphsSpecificStyleProperties::saveSettings(settings, group);
settings.setValue(group+"radius_at_value", defaultRectRadiusAtValue);
settings.setValue(group+"radius_at_baseline", defaultRectRadiusAtBaseline);
}

View File

@ -195,8 +195,6 @@ public:
*/
void saveSettings(QSettings& settings, const QString& group) const;
/** \brief defines how to derive a text color for a new graph */
JKQTPColorDerivationMode textColorDerivationMode;
/** \brief default text color in the plot */
QColor defaultTextColor;
/** \brief default font size in the plot [pt] */
@ -208,6 +206,48 @@ public:
};
/** \brief Support Class for JKQTBasePlotter, which summarizes all properties that define the visual styling of barchart elements
* \ingroup jkqtpplotter_styling_classes
*
* \see JKQTBasePlotter, \ref jkqtpplotter_styling
*/
class JKQTPLOTTER_LIB_EXPORT JKQTBarchartSpecificStyleProperties: public JKQTGraphsSpecificStyleProperties {
#ifndef JKQTPLOTTER_WORKAROUND_QGADGET_BUG
Q_GADGET
#endif
public:
JKQTBarchartSpecificStyleProperties(const JKQTBasePlotterStyle& parent);
JKQTBarchartSpecificStyleProperties(const JKQTBasePlotterStyle& parent, const JKQTGraphsSpecificStyleProperties& other);
JKQTBarchartSpecificStyleProperties(const JKQTBarchartSpecificStyleProperties& other)=default;
JKQTBarchartSpecificStyleProperties(JKQTBarchartSpecificStyleProperties&& other)=default;
JKQTBarchartSpecificStyleProperties& operator=(const JKQTBarchartSpecificStyleProperties& other)=default;
JKQTBarchartSpecificStyleProperties& operator=(JKQTBarchartSpecificStyleProperties&& other)=default;
/** \brief loads the plot properties from a <a href="http://doc.qt.io/qt-5/qsettings.html")">QSettings</a> object
*
* \param settings QSettings-object to read from
* \param group Group in the QSettings-object to read from
* \param defaultStyle If a setting cannot be found in \a settings, default values are taken from this object
* By default, this is a default-constructed object
*/
void loadSettings(const QSettings &settings, const QString& group, const JKQTBarchartSpecificStyleProperties &defaultStyle);
/** \brief saves the plot properties into a <a href="http://doc.qt.io/qt-5/qsettings.html")">QSettings</a> object.
*
* \param settings QSettings-object to save to
* \param group Group in the QSettings-object to save to
*/
void saveSettings(QSettings& settings, const QString& group) const;
/** \brief corner radius (in pt) for bars at the "value" end */
double defaultRectRadiusAtValue;
/** \brief corner radius (in pt) for bars at the "baseline" end */
double defaultRectRadiusAtBaseline;
};
/** \brief Support Class for JKQTBasePlotter, which summarizes all properties that define the visual styling of a JKQTBasePlotter
* \ingroup jkqtpplotter_styling_classes
@ -251,7 +291,7 @@ class JKQTPLOTTER_LIB_EXPORT JKQTGraphsBaseStyle {
/** \brief styling options for standard graphs */
JKQTGraphsSpecificStyleProperties defaultGraphStyle;
/** \brief styling options for bargraph graphs */
JKQTGraphsSpecificStyleProperties barchartStyle;
JKQTBarchartSpecificStyleProperties barchartStyle;
/** \brief styling options for boxplots graphs */
JKQTGraphsSpecificStyleProperties boxplotStyle;
/** \brief styling options for filled graphs */