/* Copyright (c) 2008-2022 Jan W. Krieger () 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 . */ #include "jkqtplotter/graphs/jkqtpscatter.h" #include "jkqtplotter/jkqtpbaseplotter.h" #include #include #include #include #include "jkqtcommon/jkqtpdrawingtools.h" #include "jkqtplotter/jkqtptools.h" #include "jkqtplotter/jkqtpimagetools.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) || (xvsgzgetPlotter()) { } 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(getXAxis()->getMin()); const double xmax=transformX(getXAxis()->getMax()); const double ymin=transformY(getYAxis()->getMin()); const double ymax=transformY(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; iiiget(static_cast(xColumn),static_cast(i)); const double yv=datastore->get(static_cast(yColumn),static_cast(i)); const double x=transformX(xv); const double y=transformY(yv); //qDebug()<<"JKQTPXYScatterGraph::draw(): (xv, yv) = ( "<pt2px(painter, symbolSize*1.5), parent->pt2px(painter, symbolWidth*parent->getLineWidthMultiplier()), penSelection.color(), penSelection.color()); //} if ((!getXAxis()->isLogAxis() || xv>0.0) && (!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) { painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();}); JKQTPPlotSymbol(painter, rect.left()+rect.width()/2.0, rect.top()+rect.height()/2.0, getSymbolType(), getKeySymbolSizePx(painter, rect, parent), getKeySymbolLineWidthPx(painter, rect, parent), getKeyLabelColor(), getSymbolFillColor(),getSymbolFont()); } 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; iget(static_cast(xColumn),static_cast(i))+getXErrorU(i, datastore); if (JKQTPIsOKFloat(xv)) { if (start || xv>maxx) maxx=xv; if (start || xvget(static_cast(xColumn),static_cast(i))-getXErrorL(i, datastore); if (JKQTPIsOKFloat(xv)) { if (start || xv>maxx) maxx=xv; if (start || xvgetDatastore(); int imax=0; int imin=0; if (getIndexRange(imin, imax)) { for (int i=imin; iget(static_cast(yColumn),static_cast(i))+getYErrorU(i, datastore); if (JKQTPIsOKFloat(yv)) { if (start || yv>maxy) maxy=yv; if (start || yvget(static_cast(yColumn),static_cast(i))-getYErrorL(i, datastore); if (JKQTPIsOKFloat(yv)) { if (start || yv>maxy) maxy=yv; if (start || yvgetCurrentPlotterStyle().graphsStyle.defaultGraphStyle.fillColorDerivationMode; } clearSizeColumnFunctor(); clearSymbolColumnFunctor(); clearLinewidthColumnFunctor(); } JKQTPXYParametrizedScatterGraph::JKQTPXYParametrizedScatterGraph(JKQTPlotter *parent): JKQTPXYParametrizedScatterGraph(parent->getPlotter()) { } void JKQTPXYParametrizedScatterGraph::draw(JKQTPEnhancedPainter &painter) { #ifdef JKQTBP_AUTOTIMER JKQTPAutoOutputTimer jkaaot("JKQTPXYParametrizedScatterGraph::draw"); #endif if (parent==nullptr) return; JKQTPDatastore* datastore=parent->getDatastore(); if (datastore==nullptr) return; cbGetDataMinMax(intColMin, intColMax); drawErrorsBefore(painter); painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();}); const QPen p=getLinePen(painter, parent); const QPen penSelection=getHighlightingLinePen(painter, parent); int imax=0; int imin=0; if (getIndexRange(imin, imax)) { QVector lines; QPolygonF linesP; QVector linecols; QVector linecolss; QVector linewidths; QVector symbols; //qDebug()<<"JKQTPXYLineGraph::draw(): "<<3<<" imin="<(colorval, 2, 1, img, getColorPalette(), double(0.0), double(1.0)); color1=img.pixel(0,0); color2=img.pixel(1,0); } } if (symbolColumn>=0) { symbol1=JKQTPFilledCircle; symbol2=JKQTPFilledRect; JKQTPDatastore* datastore=parent->getDatastore(); if (datastore && datastore->getRows(symbolColumn)>0) { symbol1=getLocalSymbolType(0); symbol2=getLocalSymbolType(datastore->getRows(symbolColumn)-1); } } const double lineWidth=getKeyLineWidthPx(painter, rect, parent)*0.75; painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();}); QPen p=painter.pen(); p.setColor(color1); p.setStyle(getLineStyle()); p.setWidthF(lineWidth); painter.setPen(p); const double x1=rect.left()+symbolSize1/2.0; const double y1=rect.top()+symbolSize1/2.0; const double x2=rect.right()-symbolSize2/2.0; const double y2=rect.bottom()-symbolSize2/2.0; if (drawLine && !drawLineInForeground) painter.drawLine(QLineF(x1,y1, x2,y2)); JKQTPPlotSymbol(painter, x1, y1, symbol1, symbolSize1, getKeySymbolLineWidthPx(painter, rect, parent,0.5), color1, JKQTPGetDerivedColor(symbolFillDerivationMode, color1),getSymbolFont()); JKQTPPlotSymbol(painter, x2, y2, symbol2, symbolSize2, getKeySymbolLineWidthPx(painter, rect, parent,0.5), color2, JKQTPGetDerivedColor(symbolFillDerivationMode, color2),getSymbolFont()); if (drawLine && drawLineInForeground) painter.drawLine(QLineF(x1,y1, x2,y2)); } QColor JKQTPXYParametrizedScatterGraph::getKeyLabelColor() const { return getLocalColor(-1); } void JKQTPXYParametrizedScatterGraph::setSizeColumn(int __value) { this->sizeColumn = __value; } int JKQTPXYParametrizedScatterGraph::getSizeColumn() const { return this->sizeColumn; } void JKQTPXYParametrizedScatterGraph::setSizeColumnFunctor(JKQTPXYParametrizedScatterGraph::FunctorToSize ff) { m_toSizePtFunctor=ff; } void JKQTPXYParametrizedScatterGraph::clearSizeColumnFunctor() { m_toSizePtFunctor=[](double /*x*/, double /*y*/, double sizecolumn)->double {return sizecolumn; }; } JKQTPXYParametrizedScatterGraph::FunctorToSize JKQTPXYParametrizedScatterGraph::getSizeColumnFunctor() { return m_toSizePtFunctor; } void JKQTPXYParametrizedScatterGraph::setSizeColumn(size_t __value) { this->sizeColumn = static_cast(__value); } void JKQTPXYParametrizedScatterGraph::setColorColumn(int __value) { this->colorColumn = __value; } int JKQTPXYParametrizedScatterGraph::getColorColumn() const { return this->colorColumn; } void JKQTPXYParametrizedScatterGraph::setColorColumn(size_t __value) { this->colorColumn = static_cast(__value); } void JKQTPXYParametrizedScatterGraph::setSymbolColumn(int __value) { this->symbolColumn = __value; } int JKQTPXYParametrizedScatterGraph::getSymbolColumn() const { return this->symbolColumn; } void JKQTPXYParametrizedScatterGraph::setSymbolColumn(size_t __value) { this->symbolColumn = static_cast(__value); } void JKQTPXYParametrizedScatterGraph::setSymbolColumnFunctor(JKQTPXYParametrizedScatterGraph::FunctorToSymbol ff) { m_toSymbolFunctor=ff; } void JKQTPXYParametrizedScatterGraph::clearSymbolColumnFunctor() { m_toSymbolFunctor=std::bind([](double /*x*/, double /*y*/, double symbolcolumn, JKQTPXYParametrizedScatterGraph* th)->JKQTPGraphSymbols { int id=static_cast(floor(symbolcolumn)); if (id<0) return th->getSymbolType(); return JKQTPGraphSymbols(id%(JKQTPMaxSymbolID+1)); }, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, this); } JKQTPXYParametrizedScatterGraph::MappedSymbolFunctor::MappedSymbolFunctor(const QMap &mapping_, JKQTPXYParametrizedScatterGraph* graph): mapping(mapping_), parent(graph) { } JKQTPGraphSymbols JKQTPXYParametrizedScatterGraph::MappedSymbolFunctor::operator()(double , double , double symcolumn) const { if (mapping.size()<=0) return parent->getSymbolType(); if (mapping.size()==1) return mapping.first(); if (symcolumn<=mapping.firstKey()) return mapping.first(); if (symcolumn>=mapping.lastKey()) return mapping.last(); auto it=mapping.begin(); it++; auto itlast=it; for (; it!=mapping.end(); ++it) { itlast=it; itlast--; if (symcolumn>=itlast.key() && symcolumn<=it.key()) { if (fabs(symcolumn-itlast.key()) &symmap) { m_toSymbolFunctor=MappedSymbolFunctor(symmap, this); } JKQTPXYParametrizedScatterGraph::FunctorToSymbol JKQTPXYParametrizedScatterGraph::getSymbolColumnFunctor() { return m_toSymbolFunctor; } void JKQTPXYParametrizedScatterGraph::setLinewidthColumn(int __value) { this->linewidthColumn = __value; } int JKQTPXYParametrizedScatterGraph::getLinewidthColumn() const { return this->linewidthColumn; } void JKQTPXYParametrizedScatterGraph::setLinewidthColumn(size_t __value) { this->linewidthColumn = static_cast(__value); } void JKQTPXYParametrizedScatterGraph::setLinewidthColumnFunctor(JKQTPXYParametrizedScatterGraph::FunctorToWidth ff) { m_toWidthPtFunctor=ff; } void JKQTPXYParametrizedScatterGraph::clearLinewidthColumnFunctor() { m_toWidthPtFunctor=[](double /*x*/, double /*y*/, double widthcolumn)->double {return widthcolumn; }; } JKQTPXYParametrizedScatterGraph::FunctorToWidth JKQTPXYParametrizedScatterGraph::getLinewidthColumnFunctor() { return m_toWidthPtFunctor; } void JKQTPXYParametrizedScatterGraph::setColorColumnContainsRGB(bool __value) { this->colorColumnContainsRGB = __value; } bool JKQTPXYParametrizedScatterGraph::getColorColumnContainsRGB() const { return this->colorColumnContainsRGB; } void JKQTPXYParametrizedScatterGraph::setGridModeForSymbolSize(bool __value) { this->gridModeForSymbolSize = __value; } bool JKQTPXYParametrizedScatterGraph::getGridModeForSymbolSize() const { return this->gridModeForSymbolSize; } void JKQTPXYParametrizedScatterGraph::setGridDeltaX(double __value) { this->gridDeltaX = __value; } double JKQTPXYParametrizedScatterGraph::getGridDeltaX() const { return this->gridDeltaX; } void JKQTPXYParametrizedScatterGraph::setGridDeltaY(double __value) { this->gridDeltaY = __value; } double JKQTPXYParametrizedScatterGraph::getGridDeltaY() const { return this->gridDeltaY; } void JKQTPXYParametrizedScatterGraph::setGridSymbolFractionSize(double __value) { this->gridSymbolFractionSize = __value; } double JKQTPXYParametrizedScatterGraph::getGridSymbolFractionSize() const { return this->gridSymbolFractionSize; } JKQTPColorDerivationMode JKQTPXYParametrizedScatterGraph::getSymbolFillDerivationMode() const { return this->symbolFillDerivationMode; } void JKQTPXYParametrizedScatterGraph::setSymbolFillDerivationMode(JKQTPColorDerivationMode m) { this->symbolFillDerivationMode=m; } void JKQTPXYParametrizedScatterGraph::setParent(JKQTBasePlotter *parent) { JKQTPXYGraph::setParent(parent); cbSetParent(parent); } void JKQTPXYParametrizedScatterGraph::getOutsideSize(JKQTPEnhancedPainter &painter, int &leftSpace, int &rightSpace, int &topSpace, int &bottomSpace) { JKQTPXYGraph::getOutsideSize(painter, leftSpace, rightSpace, topSpace, bottomSpace); if (showColorBar&& colorColumn>=0 && !colorColumnContainsRGB) cbGetOutsideSize(painter, leftSpace, rightSpace, topSpace, bottomSpace); } void JKQTPXYParametrizedScatterGraph::drawOutside(JKQTPEnhancedPainter &painter, QRect leftSpace, QRect rightSpace, QRect topSpace, QRect bottomSpace) { JKQTPXYGraph::drawOutside(painter, leftSpace, rightSpace, topSpace, bottomSpace); if (showColorBar&& colorColumn>=0 && !colorColumnContainsRGB) cbDrawOutside(painter, leftSpace, rightSpace, topSpace, bottomSpace); } void JKQTPXYParametrizedScatterGraph::cbGetDataMinMax(double &dmin, double &dmax) { if (autoImageRange) { dmin=dmax=0; if (parent==nullptr) return; JKQTPDatastore* datastore=parent->getDatastore(); if (datastore==nullptr) return; if (colorColumn<0) return; int imax= static_cast(qMin(datastore->getRows(static_cast(xColumn)), datastore->getRows(static_cast(yColumn)))); int imin=0; if (imaxget(colorColumn,i); if (first) { dmin=dmax=xv; first=false; } else { dmin=qMin(xv, dmin); dmax=qMax(xv, dmax); } } } else { dmin=imageMin; dmax=imageMax; } } bool JKQTPXYParametrizedScatterGraph::usesColumn(int c) const { return (c==colorColumn) || (c==sizeColumn) || (c==symbolColumn) || (c==linewidthColumn) || JKQTPXYGraph::usesColumn(c); } void JKQTPXYParametrizedScatterGraph::setDrawLine(bool __value) { drawLine=__value; } bool JKQTPXYParametrizedScatterGraph::getDrawLine() const { return drawLine; } void JKQTPXYParametrizedScatterGraph::setDrawLineInForeground(bool __value) { drawLineInForeground=__value; } bool JKQTPXYParametrizedScatterGraph::getDrawLineInForeground() const { return drawLineInForeground; } void JKQTPXYParametrizedScatterGraph::setColor(QColor c) { setLineColor(c); setSymbolColor(c); setSymbolFillColor(JKQTPGetDerivedColor(parent->getCurrentPlotterStyle().graphsStyle.defaultGraphStyle.fillColorDerivationMode, c)); c.setAlphaF(0.5); setHighlightingLineColor(c); } double JKQTPXYParametrizedScatterGraph::getLocalSymbolSize(int i) { if (parent==nullptr) return getSymbolSize(); JKQTPDatastore* datastore=parent->getDatastore(); if (datastore==nullptr) return getSymbolSize(); if (sizeColumn<0) return getSymbolSize(); if (i>=(int64_t)datastore->getRows(sizeColumn)) return getSymbolSize(); return m_toSizePtFunctor(datastore->get(xColumn,i), datastore->get(yColumn,i), datastore->get(sizeColumn,i)); } double JKQTPXYParametrizedScatterGraph::getLocalLineWidth(int i) { if (parent==nullptr) return getLineWidth(); JKQTPDatastore* datastore=parent->getDatastore(); if (datastore==nullptr) return getLineWidth(); if (linewidthColumn<0) return getLineWidth(); if (i>=(int64_t)datastore->getRows(linewidthColumn)) return getLineWidth(); return m_toWidthPtFunctor(datastore->get(xColumn,i), datastore->get(yColumn,i), datastore->get(linewidthColumn,i)); } QColor JKQTPXYParametrizedScatterGraph::getLocalColor(int i) const { if (parent==nullptr) return getLineColor(); const JKQTPDatastore* datastore=parent->getDatastore(); if (datastore==nullptr) return getLineColor(); if (colorColumn<0) return getLineColor(); if (colorColumnContainsRGB) { if (i<0 || i>=(int64_t)datastore->getRows(colorColumn)) return getLineColor(); //QRgb rgb= return QRgb(round(datastore->get(colorColumn,i))); } else { QImage img; double colorval=0; if (i>=0 && i<(int64_t)datastore->getRows(colorColumn)) colorval=datastore->get(colorColumn,i); double colMin=0; double colMax=0; if (intColMin==intColMax) { colMin=0; colMax=datastore->getRows(colorColumn)-1; } else { colMin=intColMin; colMax=intColMax; } JKQTPImageTools::array2image(&colorval, 1, 1, img, palette, colMin, colMax); return img.pixel(0,0); } } JKQTPGraphSymbols JKQTPXYParametrizedScatterGraph::getLocalSymbolType(int i) { if (parent==nullptr) return getSymbolType(); JKQTPDatastore* datastore=parent->getDatastore(); if (datastore==nullptr) return getSymbolType(); if (symbolColumn<0) return getSymbolType(); if (i>=static_cast(datastore->getRows(symbolColumn))) return getSymbolType(); return m_toSymbolFunctor(datastore->get(xColumn,i), datastore->get(yColumn,i), datastore->get(symbolColumn,i)); } JKQTPXYParametrizedErrorScatterGraph::JKQTPXYParametrizedErrorScatterGraph(JKQTBasePlotter *parent): JKQTPXYParametrizedScatterGraph(parent) { setErrorColorFromGraphColor(getSymbolColor()); initErrorStyle(parent, parentPlotStyle); } JKQTPXYParametrizedErrorScatterGraph::JKQTPXYParametrizedErrorScatterGraph(JKQTPlotter *parent): JKQTPXYParametrizedErrorScatterGraph(parent->getPlotter()) { } bool JKQTPXYParametrizedErrorScatterGraph::getXMinMax(double &minx, double &maxx, double &smallestGreaterZero) { if (xErrorColumn<0 || xErrorStyle==JKQTPNoError) { return JKQTPXYGraph::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; iget(static_cast(xColumn),static_cast(i))+getXErrorU(i, datastore); if (JKQTPIsOKFloat(xv) ) { if (start || xv>maxx) maxx=xv; if (start || xvget(static_cast(xColumn),static_cast(i))-getXErrorL(i, datastore); if (JKQTPIsOKFloat(xvv)) { start=false; if (start || xvv>maxx) maxx=xvv; if (start || xvvgetDatastore(); int imax=0; int imin=0; if (getIndexRange(imin, imax)) { for (int i=imin; iget(static_cast(yColumn),static_cast(i))+getYErrorU(i, datastore); if (JKQTPIsOKFloat(yv)) { if (start || yv>maxy) maxy=yv; if (start || yvget(static_cast(yColumn),static_cast(i))-getYErrorL(i, datastore); if (JKQTPIsOKFloat(yvv) ) { if (start || yvv>maxy) maxy=yvv; if (start || yvv