NEW: added scatter graph JKQTPXYScatterGraph and JKQTPXYScatterErrorGraph

This commit is contained in:
jkriege2 2022-08-26 12:41:42 +02:00
parent 02fbabff5c
commit b156fc7e40
6 changed files with 291 additions and 3 deletions

View File

@ -283,6 +283,9 @@ This group assembles graphs that show their data with symbols and optionally wit
<tr>
<td>\image html beeswarmplot_small.png
<td> JKQTPSingleColumnSymbolsGraph
<tr>
<td>\image html scatter_small.png
<td> JKQTPXYScatterGraph, JKQTPXYScatterErrorGraph
<tr>
<td>\image html symbols_and_styles_small.png
<td> JKQTPXYLineGraph, JKQTPXYLineErrorGraph

View File

@ -37,6 +37,7 @@ Changes, compared to \ref page_whatsnew_V4_0_0 "v4.0.0" include:
<li>NEW: improved plotting speed for scatter-graphs by not calling draw functions for symbols outside the plot window (e.g. in JKQTPXYLineGraph)</li>
<li>NEW: added JKQTBasePlotter::grabPixelImage() and JKQTPlotter::grabPixelImage(), which grab the plotter into a QImage</li>
<li>NEW: added option to not display the preview dialog to JKQTBasePlotter::copyPixelImage() and JKQTPlotter::copyPixelImage()</li>
<li>NEW: added simple scatter plot JKQTPXYScatterGraph</li>
</ul></li>
<li>JKQTMathText:<ul>

View File

@ -48,6 +48,211 @@
JKQTPXYScatterGraph::JKQTPXYScatterGraph(JKQTPlotter* parent):
JKQTPXYScatterGraph(parent->getPlotter())
{
}
JKQTPXYScatterGraph::JKQTPXYScatterGraph(JKQTBasePlotter* parent):
JKQTPXYGraph(parent)
{
sortData=JKQTPXYGraph::Unsorted;
initSymbolStyle(parent, parentPlotStyle, JKQTPPlotStyleType::Default);
}
void JKQTPXYScatterGraph::draw(JKQTPEnhancedPainter& painter) {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaaot("JKQTPXYScatterGraph::draw");
#endif
if (parent==nullptr) return;
const JKQTPDatastore* datastore=parent->getDatastore();
if (datastore==nullptr) return;
//qDebug()<<"JKQTPXYScatterGraph::draw();";
drawErrorsBefore(painter);
{
//qDebug()<<"JKQTPXYScatterGraph::draw(): "<<1;
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
//qDebug()<<"JKQTPXYScatterGraph::draw(): "<<2;
const auto symType=getSymbolType();
const double xmin=transformX(parent->getXAxis()->getMin());
const double xmax=transformX(parent->getXAxis()->getMax());
const double ymin=transformY(parent->getYAxis()->getMin());
const double ymax=transformY(parent->getYAxis()->getMax());
const double symbolSize=parent->pt2px(painter, getSymbolSize());
const QMarginsF clipMargins=(symType==JKQTPNoSymbol)?QMarginsF(0,0,0,0):QMarginsF(symbolSize,symbolSize,symbolSize,symbolSize);
const QRectF cliprect=QRectF(qMin(xmin,xmax),qMin(ymin,ymax),fabs(xmax-xmin),fabs(ymax-ymin))+clipMargins;
int imax=0;
int imin=0;
if (getIndexRange(imin, imax)) {
for (int iii=imin; iii<imax; iii++) {
const 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 x=transformX(xv);
const double y=transformY(yv);
//qDebug()<<"JKQTPXYScatterGraph::draw(): (xv, yv) = ( "<<xv<<", "<<yv<<" )";
if (JKQTPIsOKFloat(xv) && JKQTPIsOKFloat(yv) && JKQTPIsOKFloat(x) && JKQTPIsOKFloat(y)) {
//if (isHighlighted() && getSymbolType()!=JKQTPNoSymbol) {
//JKQTPPlotSymbol(painter, x, y, JKQTPFilledCircle, parent->pt2px(painter, symbolSize*1.5), parent->pt2px(painter, symbolWidth*parent->getLineWidthMultiplier()), penSelection.color(), penSelection.color());
//}
if ((!parent->getXAxis()->isLogAxis() || xv>0.0) && (!parent->getYAxis()->isLogAxis() || yv>0.0) ) {
if (symType!=JKQTPNoSymbol && cliprect.contains(x,y)) plotStyledSymbol(parent, painter, x, y);
}
}
}
}
}
//qDebug()<<"JKQTPXYScatterGraph::draw(): "<<7;
drawErrorsAfter(painter);
//qDebug()<<"JKQTPXYScatterGraph::draw() ... done";
}
void JKQTPXYScatterGraph::drawKeyMarker(JKQTPEnhancedPainter& painter, QRectF& rect) {
const double minSize=qMin(rect.width(), rect.height());
const double maxSize=qMax(rect.width(), rect.height());
double symbolSize=parent->pt2px(painter, this->getSymbolSize());
if (symbolSize>minSize*0.9) symbolSize=minSize*0.9;
double symbolWidth=parent->pt2px(painter, this->getSymbolLineWidth()*parent->getLineWidthMultiplier());
if (symbolWidth>0.3*symbolSize) symbolWidth=0.3*symbolSize;
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
double y=rect.top()+rect.height()/2.0;
JKQTPPlotSymbol(painter, rect.left()+rect.width()/2.0, rect.top()+rect.height()/2.0, getSymbolType(), symbolSize, symbolWidth, getKeyLabelColor(), getSymbolFillColor());
}
QColor JKQTPXYScatterGraph::getKeyLabelColor() const {
return getSymbolColor();
}
void JKQTPXYScatterGraph::setColor(QColor c)
{
setSymbolColor(c);
setSymbolFillColor(JKQTPGetDerivedColor(parent->getCurrentPlotterStyle().graphsStyle.defaultGraphStyle.fillColorDerivationMode, c));
c.setAlphaF(0.5);
}
JKQTPXYScatterErrorGraph::JKQTPXYScatterErrorGraph(JKQTBasePlotter *parent):
JKQTPXYScatterGraph(parent)
{
setErrorColorFromGraphColor(getSymbolColor());
initErrorStyle(parent, parentPlotStyle);
}
JKQTPXYScatterErrorGraph::JKQTPXYScatterErrorGraph(JKQTPlotter *parent):
JKQTPXYScatterErrorGraph(parent->getPlotter())
{
}
bool JKQTPXYScatterErrorGraph::getXMinMax(double &minx, double &maxx, double &smallestGreaterZero) {
if (xErrorColumn<0 || xErrorStyle==JKQTPNoError) {
return JKQTPXYScatterGraph::getXMinMax(minx, maxx, smallestGreaterZero);
} else {
bool start=true;
minx=0;
maxx=0;
smallestGreaterZero=0;
if (parent==nullptr) return false;
const JKQTPDatastore* datastore=parent->getDatastore();
int imax=0;
int imin=0;
if (getIndexRange(imin, imax)) {
for (int i=imin; i<imax; i++) {
double xv=datastore->get(static_cast<size_t>(xColumn),static_cast<size_t>(i))+getXErrorU(i, datastore);
if (JKQTPIsOKFloat(xv)) {
if (start || xv>maxx) maxx=xv;
if (start || xv<minx) minx=xv;
const double xvsgz=xv; SmallestGreaterZeroCompare_xvsgz();
start=false;
}
xv=datastore->get(static_cast<size_t>(xColumn),static_cast<size_t>(i))-getXErrorL(i, datastore);
if (JKQTPIsOKFloat(xv)) {
if (start || xv>maxx) maxx=xv;
if (start || xv<minx) minx=xv;
const double xvsgz=xv; SmallestGreaterZeroCompare_xvsgz();
start=false;
}
}
return !start;
}
}
return false;
}
bool JKQTPXYScatterErrorGraph::getYMinMax(double &miny, double &maxy, double &smallestGreaterZero) {
if (yErrorColumn<0 || yErrorStyle==JKQTPNoError) {
return JKQTPXYScatterGraph::getYMinMax(miny, maxy, smallestGreaterZero);
} else {
bool start=true;
miny=0;
maxy=0;
smallestGreaterZero=0;
if (parent==nullptr) return false;
const JKQTPDatastore* datastore=parent->getDatastore();
int imax=0;
int imin=0;
if (getIndexRange(imin, imax)) {
for (int i=imin; i<imax; i++) {
double yv=datastore->get(static_cast<size_t>(yColumn),static_cast<size_t>(i))+getYErrorU(i, datastore);
if (JKQTPIsOKFloat(yv)) {
if (start || yv>maxy) maxy=yv;
if (start || yv<miny) miny=yv;
const double xvsgz=yv; SmallestGreaterZeroCompare_xvsgz();
start=false;
}
yv=datastore->get(static_cast<size_t>(yColumn),static_cast<size_t>(i))-getYErrorL(i, datastore);
if (JKQTPIsOKFloat(yv)) {
if (start || yv>maxy) maxy=yv;
if (start || yv<miny) miny=yv;
const double xvsgz=yv; SmallestGreaterZeroCompare_xvsgz();
start=false;
}
}
return !start;
}
}
return false;
}
bool JKQTPXYScatterErrorGraph::usesColumn(int c) const
{
return JKQTPXYScatterGraph::usesColumn(c)||JKQTPXYGraphErrors::errorUsesColumn(c);
}
void JKQTPXYScatterErrorGraph::drawErrorsBefore(JKQTPEnhancedPainter &painter)
{
intSortData();
if (sortData==JKQTPXYGraph::Unsorted) plotErrorIndicators(painter, parent, this, xColumn, yColumn);
else plotErrorIndicators(painter, parent, this, xColumn, yColumn, 0, 0, &sortedIndices);
}

View File

@ -45,9 +45,88 @@ class JKQTPDatastore;
/*! \brief This implements xy scatter plots. This also alows to draw symbols at the data points.
\ingroup jkqtplotter_linesymbolgraphs_simple
\image html plot_scatterplots.png
\note This classes can (and does by default) apply a line-compression strategy that improves plotting speed
but reduces accuracy a bit. See JKQTPGraphLinesCompressionMixin for details.
\see JKQTPXYScatterErrorGraph for a version with error indicators and JKQTPXYParametrizedScatterGraph for a more feature-rich version
that allows to also change the color/size of the symbols from data
*/
class JKQTPLOTTER_LIB_EXPORT JKQTPXYScatterGraph: public JKQTPXYGraph, public JKQTPGraphSymbolStyleMixin {
Q_OBJECT
public:
/** \brief class constructor */
explicit JKQTPXYScatterGraph(JKQTBasePlotter* parent=nullptr);
/** \brief class constructor */
JKQTPXYScatterGraph(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;
/** \brief set color of line and symbol */
void setColor(QColor c);
protected:
/*! \brief This implements xy scatter plots (like JKQTPXYLineGraph), but the color and size of the symbols may be taken from a column.
};
/*! \brief This implements xy scatter plots with x and y error indicators.
\ingroup jkqtplotter_linesymbolgraphs_simple
\image html plot_errorbarscatterlots.png
\see JKQTPXYScatterGraph, JKQTPXYGraphErrors
*/
class JKQTPLOTTER_LIB_EXPORT JKQTPXYScatterErrorGraph: public JKQTPXYScatterGraph, public JKQTPXYGraphErrors {
Q_OBJECT
public:
/** \brief class constructor */
JKQTPXYScatterErrorGraph(JKQTBasePlotter* parent=nullptr);
/** \brief class constructor */
JKQTPXYScatterErrorGraph(JKQTPlotter* parent);
/** \brief get the maximum and minimum x-value of the graph
*
* The result is given in the two parameters which are call-by-reference parameters!
*/
virtual bool getXMinMax(double& minx, double& maxx, double& smallestGreaterZero) override;
/** \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 c) const override;
protected:
/** \brief this function is used to plot error inidcators before plotting the graphs. */
virtual void drawErrorsBefore(JKQTPEnhancedPainter& painter) override;
};
/*! \brief This implements xy scatter plots (like JKQTPXYScatterGraph), but the color and size of the symbols may be taken from a column.
\ingroup jkqtplotter_linesymbolgraphs_param
set the properties sizeColumn and/or colorColumn to change the size and/or color of the symbols according to the values in the column.
@ -55,7 +134,7 @@ class JKQTPDatastore;
\image html paramscatterplot.png "Different Styles of Parametrized Scatter/Line Graphs"
\note This classes is meant for cases where you want to change the color/size/... of single symbols, in dependence
of data. If you are looking for a simple scatter-plot without data-dependent properties, use JKQTPXYLineGraph
of data. If you are looking for a simple scatter-plot without data-dependent properties, use JKQTPXYScatterGraph
instead, which is faster.
\note For the size, line width and symbol type columns, you can also set a functor, which converts the column value (optionally based
@ -331,7 +410,7 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPXYParametrizedScatterGraph: public JKQTPXYGrap
/*! \brief This implements xy scatter plots (like JKQTPXYLineGraph), but the color and size of the symbols may be taken from a column. with errorbars
/*! \brief This implements xy scatter plots (like JKQTPXYScatterGraph), but the color and size of the symbols may be taken from a column. with errorbars
\ingroup jkqtplotter_linesymbolgraphs_param
set the properties sizeColumn and/or colorColumn to change the size and/or color of the symbols according to the values in the column.

BIN
screenshots/scatter.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB