/* Copyright (c) 2008-2020 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 "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()) { } JKQTPXYLineGraph::JKQTPXYLineGraph(JKQTBasePlotter* parent): JKQTPXYGraph(parent) { sortData=JKQTPXYGraph::Unsorted; drawLine=true; initLineStyle(parent, parentPlotStyle); initSymbolStyle(parent, parentPlotStyle); } void JKQTPXYLineGraph::draw(JKQTPEnhancedPainter& painter) { #ifdef JKQTBP_AUTOTIMER JKQTPAutoOutputTimer jkaaot("JKQTPXYLineGraph::draw"); #endif if (parent==nullptr) return; JKQTPDatastore* datastore=parent->getDatastore(); if (datastore==nullptr) return; //qDebug()<<"JKQTPXYLineGraph::draw();"; drawErrorsBefore(painter); { //qDebug()<<"JKQTPXYLineGraph::draw(): "<<1; painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();}); //qDebug()<<"JKQTPXYLineGraph::draw(): "<<2; QPen p=getLinePen(painter, parent); QPen penSelection=getHighlightingLinePen(painter, parent); int imax= static_cast(qMin(datastore->getRows(static_cast(xColumn)), datastore->getRows(static_cast(yColumn)))); int imin=0; if (imax vec_linesP; vec_linesP.push_back(QPolygonF()); intSortData(); for (int iii=imin; iiiget(static_cast(xColumn),static_cast(i)); double yv=datastore->get(static_cast(yColumn),static_cast(i)); double x=transformX(xv); double y=transformY(yv); //qDebug()<<"JKQTPXYLineGraph::draw(): (xv, yv) = ( "<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) ) { plotStyledSymbol(parent, painter, x, y); if (drawLine) { vec_linesP[vec_linesP.size()-1] << QPointF(x,y); } } else { vec_linesP.push_back(QPolygonF()); } } } //qDebug()<<"JKQTPXYLineGraph::draw(): "<<4<<" lines="<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; double lineWidth=parent->pt2px(painter, this->getLineWidth()*parent->getLineWidthMultiplier()); if (lineWidth>0.5*maxSize) lineWidth=0.5*maxSize; painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();}); QPen p=getLinePen(painter, parent); p.setColor(getKeyLabelColor()); p.setStyle(getLineStyle()); p.setWidthF(lineWidth); painter.setPen(p); double y=rect.top()+rect.height()/2.0; if (drawLine) painter.drawLine(QLineF(rect.left(), y, rect.right(), y)); JKQTPPlotSymbol(painter, rect.left()+rect.width()/2.0, rect.top()+rect.height()/2.0, getSymbolType(), symbolSize, symbolWidth, getKeyLabelColor(), getSymbolFillColor()); } QColor JKQTPXYLineGraph::getKeyLabelColor() const { return getSymbolColor(); } void JKQTPXYLineGraph::setDrawLine(bool __value) { this->drawLine = __value; } bool JKQTPXYLineGraph::getDrawLine() const { return this->drawLine; } void JKQTPXYLineGraph::setColor(QColor c) { setLineColor(c); setSymbolColor(c); setSymbolFillColor(JKQTPGetDerivedColor(parent->getCurrentPlotterStyle().graphFillColorDerivationMode, c)); c.setAlphaF(0.5); setHighlightingLineColor(c); } JKQTPXYLineErrorGraph::JKQTPXYLineErrorGraph(JKQTBasePlotter *parent): JKQTPXYLineGraph(parent) { setErrorColorFromGraphColor(getSymbolColor()); initErrorStyle(parent, parentPlotStyle); } JKQTPXYLineErrorGraph::JKQTPXYLineErrorGraph(JKQTPlotter *parent): JKQTPXYLineErrorGraph(parent->getPlotter()) { } bool JKQTPXYLineErrorGraph::getXMinMax(double &minx, double &maxx, double &smallestGreaterZero) { if (xErrorColumn<0 || xErrorStyle==JKQTPNoError) { return JKQTPXYLineGraph::getXMinMax(minx, maxx, smallestGreaterZero); } else { 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(qMin(datastore->getRows(static_cast(xColumn)), datastore->getRows(static_cast(yColumn)))); if (imaxget(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 imin=0; int imax= static_cast(qMin(datastore->getRows(static_cast(xColumn)), datastore->getRows(static_cast(yColumn)))); if (imaxget(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().graphFillColorDerivationMode; } 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();}); QPen p=getLinePen(painter, parent); QPen penSelection=getHighlightingLinePen(painter, parent); int imax= static_cast(qMin(datastore->getRows(static_cast(xColumn)), datastore->getRows(static_cast(yColumn)))); int imin=0; if (imax lines; QPolygonF linesP; QVector linecols; QVector linecolss; QVector linewidths; //qDebug()<<"JKQTPXYLineGraph::draw(): "<<3<<" imin="<(colorval, 2, 1, img, getPalette(), double(0.0), double(1.0)); color1=img.pixel(0,0); color2=img.pixel(1,0); } } if (symbolColumn>=0) { symbol1=JKQTPFilledCircle; symbol2=JKQTPFilledRect; } double symbolWidth=parent->pt2px(painter, this->getSymbolLineWidth()*0.7*parent->getLineWidthMultiplier()); if (symbolWidth>0.2*getSymbolLineWidth()) symbolWidth=0.3*getSymbolLineWidth(); double lineWidth=parent->pt2px(painter, this->getSymbolLineWidth()*0.7*parent->getLineWidthMultiplier()); if (lineWidth>0.1*maxSize) lineWidth=0.1*maxSize; painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();}); QPen p=painter.pen(); p.setColor(color1); p.setStyle(getLineStyle()); p.setWidthF(lineWidth); painter.setPen(p); double x1=rect.left()+symbolSize1/2.0; double y1=rect.top()+symbolSize1/2.0; double x2=rect.right()-symbolSize2/2.0; double y2=rect.bottom()-symbolSize2/2.0; JKQTPPlotSymbol(painter, x1, y1, symbol1, symbolSize1, symbolWidth, color1, JKQTPGetDerivedColor(symbolFillDerivationMode, color1)); JKQTPPlotSymbol(painter, x2, y2, symbol2, symbolSize2, symbolWidth, color2, JKQTPGetDerivedColor(symbolFillDerivationMode, color2)); if (drawLine) 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) { JKQTPXYLineGraph::setParent(parent); cbSetParent(parent); } void JKQTPXYParametrizedScatterGraph::getOutsideSize(JKQTPEnhancedPainter &painter, int &leftSpace, int &rightSpace, int &topSpace, int &bottomSpace) { JKQTPXYLineGraph::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) { JKQTPXYLineGraph::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) || JKQTPXYLineGraph::usesColumn(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 JKQTPXYLineGraph::getXMinMax(minx, maxx, smallestGreaterZero); } else { 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(qMin(datastore->getRows(static_cast(xColumn)), datastore->getRows(static_cast(yColumn)))); if (imaxget(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 imin=0; int imax= static_cast(qMin(datastore->getRows(static_cast(xColumn)), datastore->getRows(static_cast(yColumn)))); if (imaxget(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