2018-11-25 21:53:26 +08:00
|
|
|
/*
|
2019-01-20 23:15:10 +08:00
|
|
|
Copyright (c) 2008-2019 Jan W. Krieger (<jan@jkrieger.de>)
|
2018-11-25 21:53:26 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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
|
2019-02-08 00:24:46 +08:00
|
|
|
the Free Software Foundation, either version 2.1 of the License, or
|
2018-11-25 21:53:26 +08:00
|
|
|
(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 <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
2018-12-19 00:13:18 +08:00
|
|
|
#include "jkqtplotter/jkqtpgraphsboxplot.h"
|
2018-11-26 03:25:44 +08:00
|
|
|
#include "jkqtplotter/jkqtpbaseplotter.h"
|
2018-11-25 21:53:26 +08:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <QDebug>
|
|
|
|
#include <iostream>
|
2018-11-26 03:25:44 +08:00
|
|
|
#include "jkqtplottertools/jkqtptools.h"
|
2018-12-19 00:13:18 +08:00
|
|
|
#include "jkqtplotter/jkqtpgraphsimage.h"
|
2018-11-26 03:25:44 +08:00
|
|
|
#include "jkqtplotter/jkqtpbaseelements.h"
|
|
|
|
#include "jkqtplotter/jkqtplotter.h"
|
2018-11-25 21:53:26 +08:00
|
|
|
#define SmallestGreaterZeroCompare_xvsgz() if ((xvsgz>10.0*DBL_MIN)&&((smallestGreaterZero<10.0*DBL_MIN) || (xvsgz<smallestGreaterZero))) smallestGreaterZero=xvsgz;
|
|
|
|
|
|
|
|
|
|
|
|
|
2019-04-22 23:19:52 +08:00
|
|
|
JKQTPGraphBoxplotStyleMixin::JKQTPGraphBoxplotStyleMixin()
|
|
|
|
{
|
2018-11-25 21:53:26 +08:00
|
|
|
|
2019-04-22 23:19:52 +08:00
|
|
|
boxWidth=0.4;
|
2018-11-25 21:53:26 +08:00
|
|
|
|
2019-04-22 23:19:52 +08:00
|
|
|
whiskerLineColor=getLineColor();
|
|
|
|
whiskerLineStyle=getLineStyle();
|
|
|
|
whiskerLineWidth=getLineWidth();
|
2018-11-25 21:53:26 +08:00
|
|
|
|
2019-04-22 23:19:52 +08:00
|
|
|
}
|
2018-11-25 21:53:26 +08:00
|
|
|
|
|
|
|
|
2019-04-22 23:19:52 +08:00
|
|
|
void JKQTPGraphBoxplotStyleMixin::initBoxplotStyle(JKQTBasePlotter *parent, int &parentPlotStyle)
|
2018-11-25 21:53:26 +08:00
|
|
|
{
|
2019-04-22 23:19:52 +08:00
|
|
|
initFillStyle(parent, parentPlotStyle);
|
|
|
|
initLineStyle(parent, parentPlotStyle);
|
|
|
|
initSymbolStyle(parent, parentPlotStyle);
|
|
|
|
if (parent && parentPlotStyle>=0) { // get style settings from parent object
|
2018-11-25 21:53:26 +08:00
|
|
|
parentPlotStyle=parent->getNextStyle();
|
2019-04-22 23:19:52 +08:00
|
|
|
whiskerLineStyle=parent->getPlotStyle(parentPlotStyle).style();
|
|
|
|
whiskerLineWidth=parent->getPlotStyle(parentPlotStyle).widthF();
|
2018-11-25 21:53:26 +08:00
|
|
|
}
|
|
|
|
|
2019-04-22 23:19:52 +08:00
|
|
|
whiskerLineColor=getLineColor();
|
|
|
|
|
2018-11-25 21:53:26 +08:00
|
|
|
}
|
|
|
|
|
2019-04-22 23:19:52 +08:00
|
|
|
void JKQTPGraphBoxplotStyleMixin::setBoxplotColor(QColor c, JKQTBasePlotter *parent)
|
|
|
|
{
|
|
|
|
setLineColor(c);
|
|
|
|
setFillColor(JKQTPGetDerivedColor(parent->getCurrentPlotterStyle().graphFillColorDerivationMode, c));
|
|
|
|
c.setAlphaF(0.5);
|
|
|
|
setHighlightingLineColor(c);
|
|
|
|
setSymbolColor(c);
|
|
|
|
setSymbolFillColor(JKQTPGetDerivedColor(parent->getCurrentPlotterStyle().graphFillColorDerivationMode, c));
|
|
|
|
whiskerLineColor=getLineColor();
|
|
|
|
}
|
2018-11-25 21:53:26 +08:00
|
|
|
|
2019-04-22 23:19:52 +08:00
|
|
|
void JKQTPGraphBoxplotStyleMixin::setWhiskerLineStyle(const Qt::PenStyle &__value)
|
|
|
|
{
|
|
|
|
this->whiskerLineStyle = __value;
|
|
|
|
}
|
|
|
|
|
|
|
|
Qt::PenStyle JKQTPGraphBoxplotStyleMixin::getWhiskerLineStyle() const
|
|
|
|
{
|
|
|
|
return this->whiskerLineStyle;
|
|
|
|
}
|
|
|
|
|
|
|
|
void JKQTPGraphBoxplotStyleMixin::setBoxWidth(double __value)
|
|
|
|
{
|
|
|
|
this->boxWidth = __value;
|
|
|
|
}
|
|
|
|
|
|
|
|
double JKQTPGraphBoxplotStyleMixin::getBoxWidth() const
|
|
|
|
{
|
|
|
|
return this->boxWidth;
|
|
|
|
}
|
|
|
|
|
|
|
|
void JKQTPGraphBoxplotStyleMixin::setWhiskerLineWidth(double __value)
|
|
|
|
{
|
|
|
|
whiskerLineWidth=__value;
|
|
|
|
}
|
|
|
|
|
|
|
|
double JKQTPGraphBoxplotStyleMixin::getWhiskerLineWidth() const
|
|
|
|
{
|
|
|
|
return whiskerLineWidth;
|
|
|
|
}
|
|
|
|
|
|
|
|
void JKQTPGraphBoxplotStyleMixin::setWhiskerLineColor(QColor __value)
|
|
|
|
{
|
|
|
|
whiskerLineColor=__value;
|
|
|
|
}
|
|
|
|
|
|
|
|
QColor JKQTPGraphBoxplotStyleMixin::getWhiskerLineColor() const
|
|
|
|
{
|
|
|
|
return whiskerLineColor;
|
|
|
|
}
|
|
|
|
|
|
|
|
QPen JKQTPGraphBoxplotStyleMixin::getWhiskerPen(JKQTPEnhancedPainter &painter, JKQTBasePlotter *parent) const
|
|
|
|
{
|
|
|
|
QPen pw=getLinePenForRects(painter, parent);
|
|
|
|
pw.setStyle(whiskerLineStyle);
|
|
|
|
pw.setWidthF(whiskerLineWidth);
|
|
|
|
pw.setColor(whiskerLineColor);
|
|
|
|
return pw;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
JKQTPBoxplotVerticalGraph::JKQTPBoxplotVerticalGraph(JKQTBasePlotter* parent):
|
2019-01-20 17:49:29 +08:00
|
|
|
JKQTPGraph(parent)
|
2018-11-25 21:53:26 +08:00
|
|
|
{
|
|
|
|
posColumn=-1;
|
|
|
|
medianColumn=-1;
|
|
|
|
meanColumn=-1;
|
|
|
|
minColumn=-1;
|
|
|
|
maxColumn=-1;
|
|
|
|
percentile25Column=-1;
|
|
|
|
percentile75Column=-1;
|
2019-04-22 23:19:52 +08:00
|
|
|
|
2018-11-25 21:53:26 +08:00
|
|
|
sortData=Unsorted;
|
|
|
|
|
2019-04-22 23:19:52 +08:00
|
|
|
initBoxplotStyle(parent, parentPlotStyle);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
JKQTPBoxplotVerticalGraph::JKQTPBoxplotVerticalGraph(JKQTPlotter* parent):
|
|
|
|
JKQTPBoxplotVerticalGraph(parent->getPlotter())
|
|
|
|
{
|
2018-11-25 21:53:26 +08:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
void JKQTPBoxplotVerticalGraph::draw(JKQTPEnhancedPainter& painter) {
|
2018-11-25 21:53:26 +08:00
|
|
|
#ifdef JKQTBP_AUTOTIMER
|
2019-01-20 17:49:29 +08:00
|
|
|
JKQTPAutoOutputTimer jkaaot("JKQTPBoxplotVerticalGraph::draw");
|
2018-11-25 21:53:26 +08:00
|
|
|
#endif
|
|
|
|
if (parent==nullptr) return;
|
2019-01-20 17:49:29 +08:00
|
|
|
JKQTPDatastore* datastore=parent->getDatastore();
|
2018-11-25 21:53:26 +08:00
|
|
|
if (datastore==nullptr) return;
|
|
|
|
|
|
|
|
drawErrorsBefore(painter);
|
|
|
|
|
|
|
|
|
2019-04-22 23:19:52 +08:00
|
|
|
QPen p=getLinePenForRects(painter, parent);
|
|
|
|
QPen pw=getWhiskerPen(painter, parent);
|
2018-11-25 21:53:26 +08:00
|
|
|
QPen np(Qt::NoPen);
|
2019-04-22 23:19:52 +08:00
|
|
|
QBrush b=getFillBrush(painter, parent);
|
2018-11-25 21:53:26 +08:00
|
|
|
|
|
|
|
int imax=datastore->getColumn(posColumn).getRows();
|
|
|
|
int imin=0;
|
|
|
|
if (imax<imin) {
|
|
|
|
int h=imin;
|
|
|
|
imin=imax;
|
|
|
|
imax=h;
|
|
|
|
}
|
|
|
|
if (imin<0) imin=0;
|
|
|
|
if (imax<0) imax=0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//bool first=false;
|
|
|
|
|
|
|
|
// 1. step find width of boxplots:
|
|
|
|
double boxwidth_real=0;
|
|
|
|
bool bwfirst=true;
|
|
|
|
intSortData();
|
|
|
|
for (int iii=imin+1; iii<imax; iii++) {
|
|
|
|
int i=qBound(imin, getDataIndex(iii), imax);
|
2018-12-28 05:52:00 +08:00
|
|
|
double xv0=transformX(datastore->get(posColumn,i-1));
|
|
|
|
double xv=transformX(datastore->get(posColumn,i));
|
2018-11-25 21:53:26 +08:00
|
|
|
if (posColumn>=0 && JKQTPIsOKFloat(xv) && JKQTPIsOKFloat(xv0)) {
|
|
|
|
if (bwfirst) {
|
|
|
|
boxwidth_real=fabs(xv-xv0);
|
|
|
|
bwfirst=false;
|
|
|
|
} else {
|
|
|
|
if (fabs(xv-xv0)>0) boxwidth_real=qMin(fabs(xv-xv0), boxwidth_real);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// 2. plot:
|
2019-02-08 00:24:46 +08:00
|
|
|
{
|
|
|
|
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
|
|
|
|
for (int i=imin; i<imax; i++) {
|
|
|
|
double xv=datastore->get(posColumn,i);
|
|
|
|
double p25v=datastore->get(percentile25Column,i);
|
|
|
|
double p75v=datastore->get(percentile75Column,i);
|
|
|
|
double minv=datastore->get(minColumn,i);
|
|
|
|
double maxv=datastore->get(maxColumn,i);
|
|
|
|
double medianv=datastore->get(medianColumn,i);
|
|
|
|
double mean=transformY(datastore->get(meanColumn,i));
|
|
|
|
|
|
|
|
QVector<QLineF> lines_p, lines_pw;
|
|
|
|
|
|
|
|
//std::cout<<"(xv, yv) = ( "<<xv<<", "<<yv<<" )\n";
|
|
|
|
if (posColumn>=0 && JKQTPIsOKFloat(xv) && JKQTPIsOKFloat(p25v) &&
|
|
|
|
JKQTPIsOKFloat(p75v) && JKQTPIsOKFloat(minv) &&
|
|
|
|
JKQTPIsOKFloat(maxv) && JKQTPIsOKFloat(medianv) ) {
|
|
|
|
|
|
|
|
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
|
|
|
|
painter.setPen(p);
|
|
|
|
painter.setBrush(b);
|
|
|
|
//std::cout<<"boxplot(med="<<medianv<<", min="<<minv<<", max="<<maxv<<", p25="<<p25v<<", p75="<<p75v<<")\n";
|
|
|
|
double x=transformX(xv);
|
|
|
|
double p25=transformY(p25v);
|
|
|
|
double p75=transformY(p75v);
|
|
|
|
double min=transformY(minv);
|
|
|
|
double max=transformY(maxv);
|
|
|
|
double median=transformY(medianv);
|
|
|
|
|
|
|
|
double xn=x+1;
|
|
|
|
if (i+1<imax) xn=transformX(datastore->get(posColumn,i+1));
|
|
|
|
else if (i-1>=0) xn=transformX(datastore->get(posColumn,i-1));
|
|
|
|
else xn=x+1;
|
|
|
|
|
|
|
|
|
2019-04-22 23:19:52 +08:00
|
|
|
double w=((boxwidth_real>0)?boxwidth_real:(fabs(xn-x)))*getBoxWidth();
|
2019-02-08 00:24:46 +08:00
|
|
|
double minstop=p25;
|
|
|
|
double maxstop=p75;
|
|
|
|
if (percentile25Column<0 && medianColumn>=0) minstop=median;
|
|
|
|
else if (percentile25Column<0 && meanColumn>=0) minstop=mean;
|
|
|
|
else if (percentile25Column<0 && maxColumn>=0) minstop=max;
|
|
|
|
if (percentile75Column<0 && medianColumn>=0) maxstop=median;
|
|
|
|
else if (percentile75Column<0 && meanColumn>=0) maxstop=mean;
|
|
|
|
else if (percentile75Column<0 && minColumn>=0) maxstop=min;
|
|
|
|
double xma=x+w/2.0;
|
|
|
|
double xmi=x-w/2.0;
|
|
|
|
double xma4=x+w/4.0;
|
|
|
|
double xmi4=x-w/4.0;
|
|
|
|
|
|
|
|
if (imax<=0) {
|
2019-04-22 23:19:52 +08:00
|
|
|
xma=transformX(xv+getBoxWidth()/2.0);
|
|
|
|
xmi=transformX(xv-getBoxWidth()/2.0);
|
|
|
|
xma4=transformX(xv+getBoxWidth()/4.0);
|
|
|
|
xmi4=transformX(xv-getBoxWidth()/4.0);
|
2019-02-08 00:24:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (minColumn>=0) {
|
|
|
|
lines_p.append(QLineF(xmi4, min, xma4, min));
|
|
|
|
lines_pw.append(QLineF(x, min, x, minstop));
|
|
|
|
}
|
|
|
|
if (maxColumn>=0) {
|
|
|
|
lines_p.append(QLineF(xmi4, max, xma4, max));
|
|
|
|
lines_pw.append(QLineF(x, max, x, maxstop));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (percentile25Column>=0 && percentile75Column>=0) painter.drawRect(QRectF(xmi, p75, fabs(xma-xmi), fabs(p75-p25)));
|
|
|
|
if (medianColumn>=0) lines_p.append(QLineF(xmi+p.widthF()/2.0, median, xma-p.widthF()/2.0, median));
|
|
|
|
if (meanColumn>=0 && JKQTPIsOKFloat(mean)) {
|
2019-04-22 23:19:52 +08:00
|
|
|
plotStyledSymbol(parent, painter,x,mean);
|
2019-02-08 00:24:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
painter.setPen(p);
|
|
|
|
if (lines_p.size()>0) painter.drawLines(lines_p);
|
|
|
|
painter.setPen(pw);
|
|
|
|
if (lines_pw.size()>0) painter.drawLines(lines_pw);
|
|
|
|
|
|
|
|
|
|
|
|
//first=true;
|
2018-11-25 21:53:26 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
drawErrorsAfter(painter);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
bool JKQTPBoxplotVerticalGraph::getXMinMax(double& minx, double& maxx, double& smallestGreaterZero) {
|
2018-11-25 21:53:26 +08:00
|
|
|
bool start=true;
|
|
|
|
minx=0;
|
|
|
|
maxx=0;
|
|
|
|
smallestGreaterZero=0;
|
|
|
|
|
|
|
|
if (posColumn<0) return false;
|
|
|
|
if (parent==nullptr) return false;
|
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
JKQTPDatastore* datastore=parent->getDatastore();
|
2018-11-25 21:53:26 +08:00
|
|
|
int imin=0;
|
|
|
|
int imax=datastore->getColumn(posColumn).getRows();
|
|
|
|
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 xv=datastore->get(posColumn,i);
|
|
|
|
if (JKQTPIsOKFloat(xv)) {
|
|
|
|
double xn=xv+1;
|
|
|
|
if (i+1<imax) xn=datastore->get(posColumn,i+1);
|
|
|
|
else if (i-1>=0) xn=datastore->get(posColumn,i-1);
|
|
|
|
else xn=xv+1;
|
|
|
|
double delta=fabs(xn-xv);
|
2019-04-22 23:19:52 +08:00
|
|
|
double w=delta*getBoxWidth();
|
2018-11-25 21:53:26 +08:00
|
|
|
double xma=xv+w;
|
|
|
|
double xmi=xv-w;
|
|
|
|
if (start || xma>maxx) maxx=xma;
|
|
|
|
if (start || xmi<minx) minx=xmi;
|
|
|
|
double xvsgz;
|
|
|
|
xvsgz=xmi; SmallestGreaterZeroCompare_xvsgz();
|
|
|
|
xvsgz=xma; SmallestGreaterZeroCompare_xvsgz();
|
|
|
|
start=false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return !start;
|
|
|
|
}
|
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
bool JKQTPBoxplotVerticalGraph::getYMinMax(double& miny, double& maxy, double& smallestGreaterZero) {
|
2018-11-25 21:53:26 +08:00
|
|
|
bool start=true;
|
|
|
|
miny=0;
|
|
|
|
maxy=0;
|
|
|
|
smallestGreaterZero=0;
|
|
|
|
|
|
|
|
if (percentile25Column<0 && percentile75Column<0 && medianColumn<0 && minColumn<0 && maxColumn<0) return false;
|
|
|
|
|
|
|
|
if (parent==nullptr) return false;
|
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
JKQTPDatastore* datastore=parent->getDatastore();
|
2018-11-25 21:53:26 +08:00
|
|
|
int imin=0;
|
|
|
|
int imax=datastore->getColumn(medianColumn).getRows();
|
|
|
|
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 p25=datastore->get(percentile25Column,i);
|
|
|
|
double p75=datastore->get(percentile75Column,i);
|
|
|
|
double min=datastore->get(minColumn,i);
|
|
|
|
double max=datastore->get(maxColumn,i);
|
|
|
|
double median=datastore->get(medianColumn,i);
|
|
|
|
if (JKQTPIsOKFloat(median)) {
|
|
|
|
if (start || median>maxy) maxy=median;
|
|
|
|
if (start || median<miny) miny=median;
|
|
|
|
if (JKQTPIsOKFloat(p25) &&p25>maxy) maxy=p25;
|
|
|
|
if (JKQTPIsOKFloat(p25) &&p25<miny) miny=p25;
|
|
|
|
if (JKQTPIsOKFloat(p75) &&p75>maxy) maxy=p75;
|
|
|
|
if (JKQTPIsOKFloat(p75) &&p75<miny) miny=p75;
|
|
|
|
if (JKQTPIsOKFloat(min) &&min>maxy) maxy=min;
|
|
|
|
if (JKQTPIsOKFloat(min) &&min<miny) miny=min;
|
|
|
|
if (JKQTPIsOKFloat(max) &&max>maxy) maxy=max;
|
|
|
|
if (JKQTPIsOKFloat(max) &&max<miny) miny=max;
|
|
|
|
|
|
|
|
double xvsgz;
|
|
|
|
xvsgz=median; SmallestGreaterZeroCompare_xvsgz();
|
|
|
|
xvsgz=p25; SmallestGreaterZeroCompare_xvsgz();
|
|
|
|
xvsgz=p75; SmallestGreaterZeroCompare_xvsgz();
|
|
|
|
xvsgz=min; SmallestGreaterZeroCompare_xvsgz();
|
|
|
|
xvsgz=max; SmallestGreaterZeroCompare_xvsgz();
|
|
|
|
start=false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return !start;
|
|
|
|
}
|
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
bool JKQTPBoxplotVerticalGraph::usesColumn(int c) const
|
2018-11-25 21:53:26 +08:00
|
|
|
{
|
|
|
|
return (c==meanColumn)||(c==posColumn)||(c==medianColumn)||(c==minColumn)||(c==maxColumn)||(c==percentile25Column)||(c==percentile75Column);
|
|
|
|
}
|
|
|
|
|
2019-04-22 23:19:52 +08:00
|
|
|
void JKQTPBoxplotVerticalGraph::setDataSortOrder(JKQTPBoxplotVerticalGraph::DataSortOrder __value)
|
|
|
|
{
|
|
|
|
this->sortData = __value;
|
|
|
|
}
|
|
|
|
|
|
|
|
JKQTPBoxplotVerticalGraph::DataSortOrder JKQTPBoxplotVerticalGraph::getDataSortOrder() const
|
|
|
|
{
|
|
|
|
return this->sortData;
|
|
|
|
}
|
|
|
|
|
2019-02-03 21:04:48 +08:00
|
|
|
void JKQTPBoxplotVerticalGraph::setDataSortOrder(int __value) {
|
2018-12-28 05:52:00 +08:00
|
|
|
sortData=(DataSortOrder)__value;
|
|
|
|
if (__value>0) sortData=Sorted;
|
|
|
|
}
|
|
|
|
|
2019-04-22 23:19:52 +08:00
|
|
|
void JKQTPBoxplotVerticalGraph::setPositionColumn(int __value)
|
|
|
|
{
|
|
|
|
this->posColumn = __value;
|
|
|
|
}
|
|
|
|
|
|
|
|
int JKQTPBoxplotVerticalGraph::getPositionColumn() const
|
|
|
|
{
|
|
|
|
return this->posColumn;
|
|
|
|
}
|
|
|
|
|
|
|
|
void JKQTPBoxplotVerticalGraph::setPositionColumn(size_t __value) {
|
|
|
|
this->posColumn = static_cast<int>(__value);
|
|
|
|
}
|
|
|
|
|
|
|
|
void JKQTPBoxplotVerticalGraph::setMedianColumn(int __value)
|
|
|
|
{
|
|
|
|
this->medianColumn = __value;
|
|
|
|
}
|
|
|
|
|
|
|
|
int JKQTPBoxplotVerticalGraph::getMedianColumn() const
|
|
|
|
{
|
|
|
|
return this->medianColumn;
|
|
|
|
}
|
|
|
|
|
|
|
|
void JKQTPBoxplotVerticalGraph::setMedianColumn(size_t __value) {
|
|
|
|
this->medianColumn = static_cast<int>(__value);
|
|
|
|
}
|
|
|
|
|
|
|
|
void JKQTPBoxplotVerticalGraph::setMeanColumn(int __value)
|
|
|
|
{
|
|
|
|
this->meanColumn = __value;
|
|
|
|
}
|
|
|
|
|
|
|
|
int JKQTPBoxplotVerticalGraph::getMeanColumn() const
|
|
|
|
{
|
|
|
|
return this->meanColumn;
|
|
|
|
}
|
|
|
|
|
|
|
|
void JKQTPBoxplotVerticalGraph::setMeanColumn(size_t __value) {
|
|
|
|
this->meanColumn = static_cast<int>(__value);
|
|
|
|
}
|
|
|
|
|
|
|
|
void JKQTPBoxplotVerticalGraph::setMinColumn(int __value)
|
|
|
|
{
|
|
|
|
this->minColumn = __value;
|
|
|
|
}
|
|
|
|
|
|
|
|
int JKQTPBoxplotVerticalGraph::getMinColumn() const
|
|
|
|
{
|
|
|
|
return this->minColumn;
|
|
|
|
}
|
|
|
|
|
|
|
|
void JKQTPBoxplotVerticalGraph::setMinColumn(size_t __value) {
|
|
|
|
this->minColumn = static_cast<int>(__value);
|
|
|
|
}
|
|
|
|
|
|
|
|
void JKQTPBoxplotVerticalGraph::setMaxColumn(int __value)
|
|
|
|
{
|
|
|
|
this->maxColumn = __value;
|
|
|
|
}
|
|
|
|
|
|
|
|
int JKQTPBoxplotVerticalGraph::getMaxColumn() const
|
|
|
|
{
|
|
|
|
return this->maxColumn;
|
|
|
|
}
|
|
|
|
|
|
|
|
void JKQTPBoxplotVerticalGraph::setMaxColumn(size_t __value) {
|
|
|
|
this->maxColumn = static_cast<int>(__value);
|
|
|
|
}
|
|
|
|
|
|
|
|
void JKQTPBoxplotVerticalGraph::setPercentile25Column(int __value)
|
|
|
|
{
|
|
|
|
this->percentile25Column = __value;
|
|
|
|
}
|
|
|
|
|
|
|
|
int JKQTPBoxplotVerticalGraph::getPercentile25Column() const
|
|
|
|
{
|
|
|
|
return this->percentile25Column;
|
|
|
|
}
|
|
|
|
|
|
|
|
void JKQTPBoxplotVerticalGraph::setPercentile25Column(size_t __value) {
|
|
|
|
this->percentile25Column = static_cast<int>(__value);
|
|
|
|
}
|
|
|
|
|
|
|
|
void JKQTPBoxplotVerticalGraph::setPercentile75Column(int __value)
|
|
|
|
{
|
|
|
|
this->percentile75Column = __value;
|
|
|
|
}
|
|
|
|
|
|
|
|
int JKQTPBoxplotVerticalGraph::getPercentile75Column() const
|
|
|
|
{
|
|
|
|
return this->percentile75Column;
|
|
|
|
}
|
|
|
|
|
|
|
|
void JKQTPBoxplotVerticalGraph::setPercentile75Column(size_t __value) {
|
|
|
|
this->percentile75Column = static_cast<int>(__value);
|
|
|
|
}
|
|
|
|
|
2018-11-25 21:53:26 +08:00
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
void JKQTPBoxplotVerticalGraph::drawKeyMarker(JKQTPEnhancedPainter& painter, QRectF& rect) {
|
2019-02-08 00:24:46 +08:00
|
|
|
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
|
2019-04-22 23:19:52 +08:00
|
|
|
QPen p=getLinePenForRects(painter, parent);
|
|
|
|
QPen pw=getWhiskerPen(painter, parent);
|
2018-11-25 21:53:26 +08:00
|
|
|
QPen np(Qt::NoPen);
|
2019-04-22 23:19:52 +08:00
|
|
|
QBrush b=getFillBrush(painter, parent);
|
2018-11-25 21:53:26 +08:00
|
|
|
|
2019-04-22 23:19:52 +08:00
|
|
|
p.setWidthF(qMin(1.0, p.widthF()));
|
|
|
|
pw.setWidthF(qMin(1.0, pw.widthF()));
|
2018-11-25 21:53:26 +08:00
|
|
|
|
|
|
|
double x=rect.left()+rect.width()/2.0;
|
|
|
|
double xma=x+rect.width()/2.5;
|
|
|
|
double xmi=x-rect.width()/2.5;
|
|
|
|
double min=rect.bottom();
|
|
|
|
double max=rect.top();
|
|
|
|
double median=max+rect.height()/2.0;
|
|
|
|
double w=rect.width()/1.8;
|
|
|
|
double p25=max+0.75*rect.height();
|
|
|
|
double p75=max+0.25*rect.height();
|
|
|
|
|
|
|
|
painter.setPen(p);
|
2019-02-08 00:24:46 +08:00
|
|
|
{
|
|
|
|
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
|
|
|
|
painter.setBrush(b);
|
|
|
|
painter.drawRect(QRectF(xmi, p75, fabs(xma-xmi), fabs(p75-p25)));
|
|
|
|
}
|
|
|
|
|
2018-11-25 21:53:26 +08:00
|
|
|
painter.drawLine(QLineF(xmi, median, xma, median));
|
|
|
|
painter.drawLine(QLineF(x-w/4.0, max, x+w/4.0, max));
|
|
|
|
painter.drawLine(QLineF(x-w/4.0, min, x+w/4.0, min));
|
|
|
|
painter.setPen(pw);
|
|
|
|
painter.drawLine(QLineF(x, max, x, p75));
|
|
|
|
painter.drawLine(QLineF(x, min, x, p25));
|
2019-02-08 00:24:46 +08:00
|
|
|
|
2018-11-25 21:53:26 +08:00
|
|
|
}
|
|
|
|
|
2019-04-22 19:27:50 +08:00
|
|
|
QColor JKQTPBoxplotVerticalGraph::getKeyLabelColor() const {
|
2019-04-22 23:19:52 +08:00
|
|
|
return getLineColor();
|
|
|
|
}
|
|
|
|
|
|
|
|
void JKQTPBoxplotVerticalGraph::setColor(QColor c)
|
|
|
|
{
|
|
|
|
setBoxplotColor(c, getParent());
|
2018-11-25 21:53:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
void JKQTPBoxplotHorizontalGraph::drawKeyMarker(JKQTPEnhancedPainter& painter, QRectF& rect) {
|
2019-02-08 00:24:46 +08:00
|
|
|
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
|
2019-04-22 23:19:52 +08:00
|
|
|
QPen p=getLinePenForRects(painter, parent);
|
|
|
|
QPen pw=getWhiskerPen(painter, parent);
|
2018-11-25 21:53:26 +08:00
|
|
|
QPen np(Qt::NoPen);
|
2019-04-22 23:19:52 +08:00
|
|
|
QBrush b=getFillBrush(painter, parent);
|
|
|
|
p.setWidthF(qMin(1.0, p.widthF()));
|
|
|
|
pw.setWidthF(qMin(1.0, pw.widthF()));
|
2018-11-25 21:53:26 +08:00
|
|
|
|
|
|
|
|
|
|
|
double y=rect.top()+rect.height()/2.0;
|
|
|
|
double yma=y+rect.height()/2.5;
|
|
|
|
double ymi=y-rect.height()/2.5;
|
|
|
|
double min=rect.left();
|
|
|
|
double max=rect.right();
|
|
|
|
double median=max-rect.width()/2.0;
|
|
|
|
double w=rect.height()/1.8;
|
|
|
|
double p25=min+0.75*rect.width();
|
|
|
|
double p75=min+0.25*rect.width();
|
|
|
|
|
|
|
|
painter.setPen(p);
|
2019-02-08 00:24:46 +08:00
|
|
|
{
|
|
|
|
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
|
|
|
|
painter.setBrush(b);
|
|
|
|
painter.drawRect(QRectF(p75, ymi, fabs(p75-p25), fabs(yma-ymi)));
|
|
|
|
}
|
|
|
|
|
2018-11-25 21:53:26 +08:00
|
|
|
painter.drawLine(QLineF(median, ymi, median, yma));
|
|
|
|
painter.drawLine(QLineF(max, y-w/4.0, max, y+w/4.0));
|
|
|
|
painter.drawLine(QLineF(min, y-w/4.0, min, y+w/4.0));
|
|
|
|
painter.setPen(pw);
|
|
|
|
painter.drawLine(QLineF(max, y, p75, y));
|
|
|
|
painter.drawLine(QLineF(min, y, p25, y));
|
2019-02-08 00:24:46 +08:00
|
|
|
|
2018-11-25 21:53:26 +08:00
|
|
|
}
|
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
bool JKQTPBoxplotHorizontalGraph::getXMinMax(double& miny, double& maxy, double& smallestGreaterZero) {
|
2018-11-25 21:53:26 +08:00
|
|
|
bool start=true;
|
|
|
|
miny=0;
|
|
|
|
maxy=0;
|
|
|
|
smallestGreaterZero=0;
|
|
|
|
|
|
|
|
if (percentile25Column<0 && percentile75Column<0 && medianColumn<0 && minColumn<0 && maxColumn<0) return false;
|
|
|
|
|
|
|
|
if (parent==nullptr) return false;
|
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
JKQTPDatastore* datastore=parent->getDatastore();
|
2018-11-25 21:53:26 +08:00
|
|
|
int imin=0;
|
|
|
|
int imax=datastore->getColumn(medianColumn).getRows();
|
|
|
|
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 p25=datastore->get(percentile25Column,i);
|
|
|
|
double p75=datastore->get(percentile75Column,i);
|
|
|
|
double min=datastore->get(minColumn,i);
|
|
|
|
double max=datastore->get(maxColumn,i);
|
|
|
|
double median=datastore->get(medianColumn,i);
|
|
|
|
if (JKQTPIsOKFloat(median)) {
|
|
|
|
if (start || median>maxy) maxy=median;
|
|
|
|
if (start || median<miny) miny=median;
|
|
|
|
if (JKQTPIsOKFloat(p25)&&p25>maxy) maxy=p25;
|
|
|
|
if (JKQTPIsOKFloat(p25)&&p25<miny) miny=p25;
|
|
|
|
if (JKQTPIsOKFloat(p75)&&p75>maxy) maxy=p75;
|
|
|
|
if (JKQTPIsOKFloat(p75)&&p75<miny) miny=p75;
|
|
|
|
if (JKQTPIsOKFloat(min)&&min>maxy) maxy=min;
|
|
|
|
if (JKQTPIsOKFloat(min)&&min<miny) miny=min;
|
|
|
|
if (JKQTPIsOKFloat(max)&&max>maxy) maxy=max;
|
|
|
|
if (JKQTPIsOKFloat(max)&&max<miny) miny=max;
|
|
|
|
double xvsgz;
|
|
|
|
xvsgz=median; SmallestGreaterZeroCompare_xvsgz();
|
|
|
|
xvsgz=p25; SmallestGreaterZeroCompare_xvsgz();
|
|
|
|
xvsgz=p75; SmallestGreaterZeroCompare_xvsgz();
|
|
|
|
xvsgz=min; SmallestGreaterZeroCompare_xvsgz();
|
|
|
|
xvsgz=max; SmallestGreaterZeroCompare_xvsgz();
|
|
|
|
start=false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return !start;
|
|
|
|
}
|
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
bool JKQTPBoxplotHorizontalGraph::getYMinMax(double& minx, double& maxx, double& smallestGreaterZero) {
|
2018-11-25 21:53:26 +08:00
|
|
|
bool start=true;
|
|
|
|
minx=0;
|
|
|
|
maxx=0;
|
|
|
|
smallestGreaterZero=0;
|
|
|
|
|
|
|
|
if (posColumn<0) return false;
|
|
|
|
if (parent==nullptr) return false;
|
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
JKQTPDatastore* datastore=parent->getDatastore();
|
2018-11-25 21:53:26 +08:00
|
|
|
int imin=0;
|
|
|
|
int imax=datastore->getColumn(posColumn).getRows();
|
|
|
|
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 xv=datastore->get(posColumn,i);
|
|
|
|
double xn=xv+1;
|
|
|
|
if (i+1<imax) xn=datastore->get(posColumn,i+1);
|
|
|
|
else if (i-1>=0) xn=datastore->get(posColumn,i-1);
|
|
|
|
else xn=xv+1;
|
|
|
|
double delta=fabs(xn-xv);
|
2019-04-22 23:19:52 +08:00
|
|
|
double w=delta*getBoxWidth();
|
2018-11-25 21:53:26 +08:00
|
|
|
double xma=xv+w;
|
|
|
|
double xmi=xv-w;
|
|
|
|
if (JKQTPIsOKFloat(xma) && JKQTPIsOKFloat(xmi) ) {
|
|
|
|
if (start || xma>maxx) maxx=xma;
|
|
|
|
if (start || xmi<minx) minx=xmi;
|
|
|
|
double xvsgz;
|
|
|
|
xvsgz=xmi; SmallestGreaterZeroCompare_xvsgz();
|
|
|
|
xvsgz=xma; SmallestGreaterZeroCompare_xvsgz();
|
|
|
|
start=false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return !start;
|
|
|
|
}
|
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
JKQTPBoxplotHorizontalGraph::JKQTPBoxplotHorizontalGraph(JKQTBasePlotter *parent):
|
|
|
|
JKQTPBoxplotVerticalGraph(parent)
|
2018-12-28 05:52:00 +08:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2019-01-20 23:15:10 +08:00
|
|
|
JKQTPBoxplotHorizontalGraph::JKQTPBoxplotHorizontalGraph(JKQTPlotter *parent):
|
2019-04-22 23:19:52 +08:00
|
|
|
JKQTPBoxplotHorizontalGraph(parent->getPlotter())
|
2018-12-28 05:52:00 +08:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
void JKQTPBoxplotHorizontalGraph::draw(JKQTPEnhancedPainter& painter) {
|
2018-11-25 21:53:26 +08:00
|
|
|
#ifdef JKQTBP_AUTOTIMER
|
2019-01-20 17:49:29 +08:00
|
|
|
JKQTPAutoOutputTimer jkaaot("JKQTPBoxplotHorizontalGraph::draw");
|
2018-11-25 21:53:26 +08:00
|
|
|
#endif
|
|
|
|
if (parent==nullptr) return;
|
2019-01-20 17:49:29 +08:00
|
|
|
JKQTPDatastore* datastore=parent->getDatastore();
|
2018-11-25 21:53:26 +08:00
|
|
|
if (datastore==nullptr) return;
|
|
|
|
|
|
|
|
drawErrorsBefore(painter);
|
|
|
|
|
2019-04-22 23:19:52 +08:00
|
|
|
QPen p=getLinePenForRects(painter, parent);
|
|
|
|
QPen pw=getWhiskerPen(painter, parent);
|
2018-11-25 21:53:26 +08:00
|
|
|
QPen np(Qt::NoPen);
|
2019-04-22 23:19:52 +08:00
|
|
|
QBrush b=getFillBrush(painter, parent);
|
2018-11-25 21:53:26 +08:00
|
|
|
|
|
|
|
|
|
|
|
int imax=datastore->getColumn(posColumn).getRows();
|
|
|
|
int imin=0;
|
|
|
|
if (imax<imin) {
|
|
|
|
int h=imin;
|
|
|
|
imin=imax;
|
|
|
|
imax=h;
|
|
|
|
}
|
|
|
|
if (imin<0) imin=0;
|
|
|
|
if (imax<0) imax=0;
|
|
|
|
|
|
|
|
// 1. step find width of boxplots:
|
|
|
|
double boxwidth_real=0;
|
|
|
|
bool bwfirst=true;
|
|
|
|
intSortData();
|
|
|
|
for (int iii=imin+1; iii<imax; iii++) {
|
|
|
|
int i=qBound(imin, getDataIndex(iii), imax);
|
2018-12-28 05:52:00 +08:00
|
|
|
double xv0=transformY(datastore->get(posColumn,i-1));
|
|
|
|
double xv=transformY(datastore->get(posColumn,i));
|
2018-11-25 21:53:26 +08:00
|
|
|
if (posColumn>=0 && JKQTPIsOKFloat(xv) && JKQTPIsOKFloat(xv0)) {
|
|
|
|
if (bwfirst) {
|
|
|
|
boxwidth_real=fabs(xv-xv0);
|
|
|
|
bwfirst=false;
|
|
|
|
} else {
|
|
|
|
if (fabs(xv-xv0)>0) boxwidth_real=qMin(fabs(xv-xv0), boxwidth_real);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// 2. plot:
|
2019-02-08 00:24:46 +08:00
|
|
|
{
|
|
|
|
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
|
|
|
|
|
|
|
|
//bool first=false;
|
|
|
|
for (int i=imin; i<imax; i++) {
|
|
|
|
double yv=datastore->get(posColumn,i);
|
|
|
|
double p25v=datastore->get(percentile25Column,i);
|
|
|
|
double p75v=datastore->get(percentile75Column,i);
|
|
|
|
double minv=datastore->get(minColumn,i);
|
|
|
|
double maxv=datastore->get(maxColumn,i);
|
|
|
|
double medianv=datastore->get(medianColumn,i);
|
|
|
|
double mean=transformX(datastore->get(meanColumn,i));
|
|
|
|
|
|
|
|
QVector<QLineF> lines_p, lines_pw;
|
|
|
|
//std::cout<<"(xv, yv) = ( "<<xv<<", "<<yv<<" )\n";
|
|
|
|
if (posColumn>=0 && JKQTPIsOKFloat(yv) &&
|
|
|
|
JKQTPIsOKFloat(p25v) &&
|
|
|
|
JKQTPIsOKFloat(p75v) &&
|
|
|
|
JKQTPIsOKFloat(minv) &&
|
|
|
|
JKQTPIsOKFloat(maxv) &&
|
|
|
|
JKQTPIsOKFloat(medianv)) {
|
|
|
|
|
|
|
|
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
|
|
|
|
painter.setPen(p);
|
|
|
|
painter.setBrush(b);
|
|
|
|
|
|
|
|
|
|
|
|
double p25=transformX(p25v);
|
|
|
|
double p75=transformX(p75v);
|
|
|
|
double min=transformX(minv);
|
|
|
|
double max=transformX(maxv);
|
|
|
|
double median=transformX(medianv);
|
|
|
|
|
|
|
|
|
|
|
|
//std::cout<<"boxplot(med="<<medianv<<", min="<<minv<<", max="<<maxv<<", p25="<<p25v<<", p75="<<p75v<<")\n";
|
|
|
|
double y=transformY(yv);
|
|
|
|
double minstop=p25;
|
|
|
|
double maxstop=p75;
|
|
|
|
if (percentile25Column<0 && medianColumn>=0) minstop=median;
|
|
|
|
else if (percentile25Column<0 && maxColumn>=0) minstop=max;
|
|
|
|
else if (percentile25Column<0 && meanColumn>=0) minstop=mean;
|
|
|
|
if (percentile75Column<0 && medianColumn>=0) maxstop=median;
|
|
|
|
else if (percentile75Column<0 && minColumn>=0) maxstop=min;
|
|
|
|
else if (percentile75Column<0 && meanColumn>=0) maxstop=mean;
|
|
|
|
|
|
|
|
double yn=y+1;
|
|
|
|
if (i+1<imax) yn=transformY(datastore->get(posColumn,i+1));
|
|
|
|
else if (i-1>=0) yn=transformY(datastore->get(posColumn,i-1));
|
|
|
|
else yn=y+1;
|
|
|
|
double delta=fabs(yn-y);
|
2019-04-22 23:19:52 +08:00
|
|
|
double w=((boxwidth_real>0)?boxwidth_real:(delta))*getBoxWidth();
|
2019-02-08 00:24:46 +08:00
|
|
|
double yma=y-w/2.0;
|
|
|
|
double ymi=y+w/2.0;
|
|
|
|
double yma4=y+w/4.0;
|
|
|
|
double ymi4=y-w/4.0;
|
|
|
|
|
|
|
|
if (imax<=1) {
|
2019-04-22 23:19:52 +08:00
|
|
|
ymi=transformY(yv+getBoxWidth()/2.0);
|
|
|
|
yma=transformY(yv-getBoxWidth()/2.0);
|
|
|
|
yma4=transformY(yv+getBoxWidth()/4.0);
|
|
|
|
ymi4=transformY(yv-getBoxWidth()/4.0);
|
2019-02-08 00:24:46 +08:00
|
|
|
}
|
|
|
|
if (minColumn>=0) {
|
|
|
|
lines_p.append(QLineF(min, ymi4, min, yma4));
|
|
|
|
lines_pw.append(QLineF(min, y, minstop, y));
|
|
|
|
}
|
|
|
|
if (maxColumn>=0) {
|
|
|
|
lines_p.append(QLineF(max, ymi4, max, yma4));
|
|
|
|
lines_pw.append(QLineF(max, y, maxstop, y));
|
|
|
|
}
|
|
|
|
if (percentile25Column>=0 && percentile75Column>=0) painter.drawRect(QRectF(p25, qMin(yma,ymi), fabs(p75-p25), fabs(yma-ymi)));
|
|
|
|
if (medianColumn>=0) lines_p.append(QLineF(median, ymi-p.widthF()/2.0, median, yma+p.widthF()/2.0));
|
|
|
|
|
|
|
|
if (meanColumn>=0 && JKQTPIsOKFloat(mean)) {
|
2019-04-22 23:19:52 +08:00
|
|
|
plotStyledSymbol(parent, painter, mean, y);
|
2019-02-08 00:24:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
//first=true;
|
|
|
|
painter.setPen(p);
|
|
|
|
if (lines_p.size()>0) painter.drawLines(lines_p);
|
|
|
|
painter.setPen(pw);
|
|
|
|
if (lines_pw.size()>0) painter.drawLines(lines_pw);
|
|
|
|
|
2018-11-25 21:53:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
drawErrorsAfter(painter);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
JKQTPBoxplotVerticalElement::JKQTPBoxplotVerticalElement(JKQTBasePlotter* parent):
|
|
|
|
JKQTPPlotObject(parent)
|
2018-11-25 21:53:26 +08:00
|
|
|
{
|
|
|
|
pos=0;
|
|
|
|
median=0;
|
|
|
|
mean=0;
|
|
|
|
min=-1;
|
|
|
|
max=1;
|
|
|
|
drawMean=true;
|
|
|
|
drawMinMax=true;
|
|
|
|
percentile25=-0.75;
|
|
|
|
percentile75=0.75;
|
2019-04-22 23:19:52 +08:00
|
|
|
|
|
|
|
initBoxplotStyle(parent, parentPlotStyle);
|
2018-11-25 21:53:26 +08:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2019-01-20 23:15:10 +08:00
|
|
|
JKQTPBoxplotVerticalElement::JKQTPBoxplotVerticalElement(JKQTPlotter* parent):
|
2019-04-22 23:19:52 +08:00
|
|
|
JKQTPBoxplotVerticalElement(parent->getPlotter())
|
2018-11-25 21:53:26 +08:00
|
|
|
{
|
|
|
|
}
|
2019-04-22 23:19:52 +08:00
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
void JKQTPBoxplotVerticalElement::draw(JKQTPEnhancedPainter& painter) {
|
2018-11-25 21:53:26 +08:00
|
|
|
#ifdef JKQTBP_AUTOTIMER
|
2019-01-20 17:49:29 +08:00
|
|
|
JKQTPAutoOutputTimer jkaaot("JKQTPBoxplotVerticalElement::draw");
|
2018-11-25 21:53:26 +08:00
|
|
|
#endif
|
|
|
|
if (parent==nullptr) return;
|
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
//drawErrorsBefore(painter);
|
2019-02-08 00:24:46 +08:00
|
|
|
{
|
|
|
|
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
|
|
|
|
|
2019-04-22 23:19:52 +08:00
|
|
|
QPen p=getLinePenForRects(painter, parent);
|
|
|
|
QPen pw=getWhiskerPen(painter, parent);
|
2019-02-08 00:24:46 +08:00
|
|
|
QPen np(Qt::NoPen);
|
2019-04-22 23:19:52 +08:00
|
|
|
QBrush b=getFillBrush(painter, parent);
|
2019-02-08 00:24:46 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
double xv=pos;
|
|
|
|
double p25v=percentile25;
|
|
|
|
double p75v=percentile75;
|
|
|
|
double minv=min;
|
|
|
|
double maxv=max;
|
|
|
|
double medianv=median;
|
2018-11-25 21:53:26 +08:00
|
|
|
|
2019-02-08 00:24:46 +08:00
|
|
|
//std::cout<<"(xv, yv) = ( "<<xv<<", "<<yv<<" )\n";
|
|
|
|
if (JKQTPIsOKFloat(xv) && JKQTPIsOKFloat(p25v) &&
|
|
|
|
JKQTPIsOKFloat(p75v) && JKQTPIsOKFloat(minv) &&
|
|
|
|
JKQTPIsOKFloat(maxv) && JKQTPIsOKFloat(medianv) ) {
|
2018-11-25 21:53:26 +08:00
|
|
|
|
2019-02-08 00:24:46 +08:00
|
|
|
//std::cout<<"boxplot(med="<<medianv<<", min="<<minv<<", max="<<maxv<<", p25="<<p25v<<", p75="<<p75v<<")\n";
|
|
|
|
double x=transformX(xv);
|
|
|
|
double p25=transformY(p25v);
|
|
|
|
double p75=transformY(p75v);
|
|
|
|
double min=transformY(minv);
|
|
|
|
double max=transformY(maxv);
|
|
|
|
double median=transformY(medianv);
|
2018-11-25 21:53:26 +08:00
|
|
|
|
2019-04-22 23:19:52 +08:00
|
|
|
double w=getBoxWidth();
|
2019-02-08 00:24:46 +08:00
|
|
|
double xma=x+w/2.0;
|
|
|
|
double xmi=x-w/2.0;
|
2018-11-25 21:53:26 +08:00
|
|
|
|
2019-02-08 00:24:46 +08:00
|
|
|
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
|
|
|
|
painter.setPen(p);
|
|
|
|
{
|
|
|
|
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
|
|
|
|
painter.setBrush(b);
|
|
|
|
painter.drawRect(QRectF(xmi, p75, fabs(xma-xmi), fabs(p75-p25)));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (drawMedian) {
|
|
|
|
painter.drawLine(QLineF(xmi, median, xma, median));
|
|
|
|
}
|
|
|
|
if (drawMinMax) {
|
|
|
|
painter.drawLine(QLineF(x-w/4.0, max, x+w/4.0, max));
|
|
|
|
painter.drawLine(QLineF(x-w/4.0, min, x+w/4.0, min));
|
|
|
|
painter.setPen(pw);
|
|
|
|
painter.drawLine(QLineF(x, max, x, p75));
|
|
|
|
painter.drawLine(QLineF(x, min, x, p25));
|
|
|
|
}
|
|
|
|
|
2018-11-25 21:53:26 +08:00
|
|
|
|
2019-02-08 00:24:46 +08:00
|
|
|
if (drawMean) {
|
|
|
|
double mean=transformY(this->mean);
|
2019-04-22 23:19:52 +08:00
|
|
|
plotStyledSymbol(parent, painter, x, mean);
|
2019-02-08 00:24:46 +08:00
|
|
|
}
|
2018-11-25 21:53:26 +08:00
|
|
|
|
|
|
|
|
2019-02-08 00:24:46 +08:00
|
|
|
}
|
2018-11-25 21:53:26 +08:00
|
|
|
}
|
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
//drawErrorsAfter(painter);
|
2018-11-25 21:53:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
bool JKQTPBoxplotVerticalElement::getXMinMax(double& minx, double& maxx, double& smallestGreaterZero) {
|
2018-11-25 21:53:26 +08:00
|
|
|
minx=0;
|
|
|
|
maxx=0;
|
|
|
|
smallestGreaterZero=0;
|
|
|
|
|
|
|
|
if (parent==nullptr) return false;
|
|
|
|
|
|
|
|
double xv=pos;
|
2019-01-20 23:15:10 +08:00
|
|
|
double w=0;
|
2018-11-25 21:53:26 +08:00
|
|
|
double xma=xv+w;
|
|
|
|
double xmi=xv-w;
|
|
|
|
maxx=xma;
|
|
|
|
minx=xmi;
|
|
|
|
double xvsgz;
|
|
|
|
xvsgz=xmi; SmallestGreaterZeroCompare_xvsgz();
|
|
|
|
xvsgz=xma; SmallestGreaterZeroCompare_xvsgz();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
bool JKQTPBoxplotVerticalElement::getYMinMax(double& miny, double& maxy, double& smallestGreaterZero) {
|
2018-11-25 21:53:26 +08:00
|
|
|
miny=0;
|
|
|
|
maxy=0;
|
|
|
|
smallestGreaterZero=0;
|
|
|
|
|
|
|
|
if (parent==nullptr) return false ;
|
|
|
|
|
|
|
|
|
|
|
|
double p25=percentile25;
|
|
|
|
double p75=percentile75;
|
|
|
|
if (drawMedian) {
|
|
|
|
maxy=median;
|
|
|
|
miny=median;
|
|
|
|
} else {
|
|
|
|
maxy=p75;
|
|
|
|
miny=p25;
|
|
|
|
}
|
|
|
|
if (p25>maxy) maxy=p25;
|
|
|
|
if (p25<miny) miny=p25;
|
|
|
|
if (p75>maxy) maxy=p75;
|
|
|
|
if (p75<miny) miny=p75;
|
|
|
|
if (min>maxy) maxy=min;
|
|
|
|
if (drawMinMax && (min<miny)) miny=min;
|
|
|
|
if (drawMinMax && (max>maxy)) maxy=max;
|
|
|
|
if (drawMinMax && (max<miny)) miny=max;
|
|
|
|
|
|
|
|
double xvsgz;
|
|
|
|
xvsgz=median; SmallestGreaterZeroCompare_xvsgz();
|
|
|
|
xvsgz=p25; SmallestGreaterZeroCompare_xvsgz();
|
|
|
|
xvsgz=p75; SmallestGreaterZeroCompare_xvsgz();
|
|
|
|
xvsgz=min; SmallestGreaterZeroCompare_xvsgz();
|
|
|
|
xvsgz=max; SmallestGreaterZeroCompare_xvsgz();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-04-22 23:19:52 +08:00
|
|
|
void JKQTPBoxplotVerticalElement::setPos(double __value)
|
|
|
|
{
|
|
|
|
this->pos = __value;
|
|
|
|
}
|
|
|
|
|
|
|
|
double JKQTPBoxplotVerticalElement::getPos() const
|
|
|
|
{
|
|
|
|
return this->pos;
|
|
|
|
}
|
|
|
|
|
|
|
|
void JKQTPBoxplotVerticalElement::setMedian(double __value)
|
|
|
|
{
|
|
|
|
if (this->median != __value) {
|
|
|
|
this->median = __value;
|
|
|
|
drawMedian=true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
double JKQTPBoxplotVerticalElement::getMedian() const
|
|
|
|
{
|
|
|
|
return this->median;
|
|
|
|
}
|
|
|
|
|
|
|
|
void JKQTPBoxplotVerticalElement::setMean(double __value)
|
|
|
|
{
|
|
|
|
if (this->mean != __value) {
|
|
|
|
this->mean = __value;
|
|
|
|
drawMean=true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
double JKQTPBoxplotVerticalElement::getMean() const
|
|
|
|
{
|
|
|
|
return this->mean;
|
|
|
|
}
|
|
|
|
|
|
|
|
void JKQTPBoxplotVerticalElement::setMin(double __value)
|
|
|
|
{
|
|
|
|
if (this->min != __value) {
|
|
|
|
this->min = __value;
|
|
|
|
drawMinMax=true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
double JKQTPBoxplotVerticalElement::getMin() const
|
|
|
|
{
|
|
|
|
return this->min;
|
|
|
|
}
|
|
|
|
|
|
|
|
void JKQTPBoxplotVerticalElement::setMax(double __value)
|
|
|
|
{
|
|
|
|
if (this->max != __value) {
|
|
|
|
this->max = __value;
|
|
|
|
drawMinMax=true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
double JKQTPBoxplotVerticalElement::getMax() const
|
|
|
|
{
|
|
|
|
return this->max;
|
|
|
|
}
|
|
|
|
|
|
|
|
void JKQTPBoxplotVerticalElement::setPercentile25(double __value)
|
|
|
|
{
|
|
|
|
this->percentile25 = __value;
|
|
|
|
}
|
|
|
|
|
|
|
|
double JKQTPBoxplotVerticalElement::getPercentile25() const
|
|
|
|
{
|
|
|
|
return this->percentile25;
|
|
|
|
}
|
|
|
|
|
|
|
|
void JKQTPBoxplotVerticalElement::setPercentile75(double __value)
|
|
|
|
{
|
|
|
|
this->percentile75 = __value;
|
|
|
|
}
|
|
|
|
|
|
|
|
double JKQTPBoxplotVerticalElement::getPercentile75() const
|
|
|
|
{
|
|
|
|
return this->percentile75;
|
|
|
|
}
|
|
|
|
|
|
|
|
void JKQTPBoxplotVerticalElement::setDrawMean(bool __value)
|
|
|
|
{
|
|
|
|
this->drawMean = __value;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool JKQTPBoxplotVerticalElement::getDrawMean() const
|
|
|
|
{
|
|
|
|
return this->drawMean;
|
|
|
|
}
|
|
|
|
|
|
|
|
void JKQTPBoxplotVerticalElement::setDrawMedian(bool __value)
|
|
|
|
{
|
|
|
|
this->drawMedian = __value;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool JKQTPBoxplotVerticalElement::getDrawMedian() const
|
|
|
|
{
|
|
|
|
return this->drawMedian;
|
|
|
|
}
|
|
|
|
|
|
|
|
void JKQTPBoxplotVerticalElement::setDrawMinMax(bool __value)
|
|
|
|
{
|
|
|
|
this->drawMinMax = __value;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool JKQTPBoxplotVerticalElement::getDrawMinMax() const
|
|
|
|
{
|
|
|
|
return this->drawMinMax;
|
|
|
|
}
|
|
|
|
|
2018-11-25 21:53:26 +08:00
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
void JKQTPBoxplotVerticalElement::drawKeyMarker(JKQTPEnhancedPainter& painter, QRectF& rect) {
|
2019-02-08 00:24:46 +08:00
|
|
|
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
|
2019-04-22 23:19:52 +08:00
|
|
|
QPen p=getLinePenForRects(painter, parent);
|
|
|
|
QPen pw=getWhiskerPen(painter, parent);
|
2018-11-25 21:53:26 +08:00
|
|
|
QPen np(Qt::NoPen);
|
2019-04-22 23:19:52 +08:00
|
|
|
QBrush b=getFillBrush(painter, parent);
|
|
|
|
p.setWidthF(qMin(1.0, p.widthF()));
|
|
|
|
pw.setWidthF(qMin(1.0, pw.widthF()));
|
2018-11-25 21:53:26 +08:00
|
|
|
|
|
|
|
|
|
|
|
double x=rect.left()+rect.width()/2.0;
|
|
|
|
double xma=x+rect.width()/2.5;
|
|
|
|
double xmi=x-rect.width()/2.5;
|
|
|
|
double min=rect.bottom();
|
|
|
|
double max=rect.top();
|
|
|
|
double median=max+rect.height()/2.0;
|
|
|
|
double w=rect.width()/1.8;
|
|
|
|
double p25=max+0.75*rect.height();
|
|
|
|
double p75=max+0.25*rect.height();
|
|
|
|
|
|
|
|
painter.setPen(p);
|
2019-02-08 00:24:46 +08:00
|
|
|
{
|
|
|
|
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
|
|
|
|
painter.setBrush(b);
|
|
|
|
painter.drawRect(QRectF(xmi, p75, fabs(xma-xmi), fabs(p75-p25)));
|
|
|
|
}
|
|
|
|
|
2018-11-25 21:53:26 +08:00
|
|
|
painter.drawLine(QLineF(xmi, median, xma, median));
|
|
|
|
painter.drawLine(QLineF(x-w/4.0, max, x+w/4.0, max));
|
|
|
|
painter.drawLine(QLineF(x-w/4.0, min, x+w/4.0, min));
|
|
|
|
painter.setPen(pw);
|
|
|
|
painter.drawLine(QLineF(x, max, x, p75));
|
|
|
|
painter.drawLine(QLineF(x, min, x, p25));
|
2019-02-08 00:24:46 +08:00
|
|
|
|
2018-11-25 21:53:26 +08:00
|
|
|
}
|
|
|
|
|
2019-04-22 19:27:50 +08:00
|
|
|
QColor JKQTPBoxplotVerticalElement::getKeyLabelColor() const {
|
2019-04-22 23:19:52 +08:00
|
|
|
return getLineColor();
|
2018-11-25 21:53:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
void JKQTPBoxplotHorizontalElement::drawKeyMarker(JKQTPEnhancedPainter& painter, QRectF& rect) {
|
2019-02-08 00:24:46 +08:00
|
|
|
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
|
2019-04-22 23:19:52 +08:00
|
|
|
QPen p=getLinePenForRects(painter, parent);
|
|
|
|
QPen pw=getWhiskerPen(painter, parent);
|
2018-11-25 21:53:26 +08:00
|
|
|
QPen np(Qt::NoPen);
|
2019-04-22 23:19:52 +08:00
|
|
|
QBrush b=getFillBrush(painter, parent);
|
|
|
|
p.setWidthF(qMin(1.0, p.widthF()));
|
|
|
|
pw.setWidthF(qMin(1.0, pw.widthF()));
|
2018-11-25 21:53:26 +08:00
|
|
|
|
|
|
|
double y=rect.top()+rect.height()/2.0;
|
|
|
|
double yma=y+rect.height()/2.5;
|
|
|
|
double ymi=y-rect.height()/2.5;
|
|
|
|
double min=rect.left();
|
|
|
|
double max=rect.right();
|
|
|
|
double median=max-rect.width()/2.0;
|
|
|
|
double w=rect.height()/1.8;
|
|
|
|
double p25=min+0.75*rect.width();
|
|
|
|
double p75=min+0.25*rect.width();
|
|
|
|
|
|
|
|
painter.setPen(p);
|
2019-02-08 00:24:46 +08:00
|
|
|
{
|
|
|
|
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
|
|
|
|
painter.setBrush(b);
|
|
|
|
painter.drawRect(QRectF(p75, ymi, fabs(p75-p25), fabs(yma-ymi)));
|
|
|
|
}
|
|
|
|
|
2018-11-25 21:53:26 +08:00
|
|
|
painter.drawLine(QLineF(median, ymi, median, yma));
|
|
|
|
painter.drawLine(QLineF(max, y-w/4.0, max, y+w/4.0));
|
|
|
|
painter.drawLine(QLineF(min, y-w/4.0, min, y+w/4.0));
|
|
|
|
painter.setPen(pw);
|
|
|
|
painter.drawLine(QLineF(max, y, p75, y));
|
|
|
|
painter.drawLine(QLineF(min, y, p25, y));
|
2019-02-08 00:24:46 +08:00
|
|
|
|
2018-11-25 21:53:26 +08:00
|
|
|
}
|
|
|
|
|
2019-01-20 23:15:10 +08:00
|
|
|
bool JKQTPBoxplotHorizontalElement::getXMinMax(double& minx, double& maxx, double& smallestGreaterZero) {
|
|
|
|
minx=0;
|
|
|
|
maxx=0;
|
2018-11-25 21:53:26 +08:00
|
|
|
smallestGreaterZero=0;
|
|
|
|
|
|
|
|
if (parent==nullptr) return false;
|
|
|
|
|
|
|
|
|
2019-01-20 23:15:10 +08:00
|
|
|
double p25=percentile25;
|
|
|
|
double p75=percentile75;
|
|
|
|
if (drawMedian) {
|
|
|
|
maxx=median;
|
|
|
|
minx=median;
|
|
|
|
} else {
|
|
|
|
maxx=p75;
|
|
|
|
minx=p25;
|
|
|
|
}
|
|
|
|
if (p25>maxx) maxx=p25;
|
|
|
|
if (p25<minx) minx=p25;
|
|
|
|
if (p75>maxx) maxx=p75;
|
|
|
|
if (p75<minx) minx=p75;
|
|
|
|
if (min>maxx) maxx=min;
|
|
|
|
if (drawMinMax && (min<minx)) minx=min;
|
|
|
|
if (drawMinMax && (max>maxx)) maxx=max;
|
|
|
|
if (drawMinMax && (max<minx)) minx=max;
|
2018-11-25 21:53:26 +08:00
|
|
|
|
2019-01-20 23:15:10 +08:00
|
|
|
double xvsgz;
|
|
|
|
xvsgz=median; SmallestGreaterZeroCompare_xvsgz();
|
|
|
|
xvsgz=p25; SmallestGreaterZeroCompare_xvsgz();
|
|
|
|
xvsgz=p75; SmallestGreaterZeroCompare_xvsgz();
|
|
|
|
xvsgz=min; SmallestGreaterZeroCompare_xvsgz();
|
|
|
|
xvsgz=max; SmallestGreaterZeroCompare_xvsgz();
|
|
|
|
return true;
|
2018-11-25 21:53:26 +08:00
|
|
|
}
|
|
|
|
|
2019-01-20 23:15:10 +08:00
|
|
|
bool JKQTPBoxplotHorizontalElement::getYMinMax(double& miny, double& maxy, double& smallestGreaterZero) {
|
|
|
|
miny=0;
|
|
|
|
maxy=0;
|
2018-11-25 21:53:26 +08:00
|
|
|
smallestGreaterZero=0;
|
|
|
|
|
|
|
|
if (parent==nullptr) return false;
|
|
|
|
|
|
|
|
double xv=pos;
|
2019-01-20 23:15:10 +08:00
|
|
|
double w=0;
|
2018-11-25 21:53:26 +08:00
|
|
|
double xma=xv+w;
|
|
|
|
double xmi=xv-w;
|
2019-01-20 23:15:10 +08:00
|
|
|
maxy=xma;
|
|
|
|
miny=xmi;
|
2018-11-25 21:53:26 +08:00
|
|
|
double xvsgz;
|
|
|
|
xvsgz=xmi; SmallestGreaterZeroCompare_xvsgz();
|
|
|
|
xvsgz=xma; SmallestGreaterZeroCompare_xvsgz();
|
|
|
|
return true;
|
2019-01-20 23:15:10 +08:00
|
|
|
|
2018-11-25 21:53:26 +08:00
|
|
|
}
|
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
JKQTPBoxplotHorizontalElement::JKQTPBoxplotHorizontalElement(JKQTBasePlotter *parent):
|
|
|
|
JKQTPBoxplotVerticalElement(parent)
|
2018-12-28 05:52:00 +08:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2019-01-20 23:15:10 +08:00
|
|
|
JKQTPBoxplotHorizontalElement::JKQTPBoxplotHorizontalElement(JKQTPlotter *parent):
|
2019-04-22 23:19:52 +08:00
|
|
|
JKQTPBoxplotHorizontalElement(parent->getPlotter())
|
2018-12-28 05:52:00 +08:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
void JKQTPBoxplotHorizontalElement::draw(JKQTPEnhancedPainter& painter) {
|
2018-11-25 21:53:26 +08:00
|
|
|
#ifdef JKQTBP_AUTOTIMER
|
2019-01-20 17:49:29 +08:00
|
|
|
JKQTPAutoOutputTimer jkaaot("JKQTPBoxplotHorizontalElement::draw");
|
2018-11-25 21:53:26 +08:00
|
|
|
#endif
|
|
|
|
if (parent==nullptr) return;
|
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
//drawErrorsBefore(painter);
|
2019-02-08 00:24:46 +08:00
|
|
|
{
|
|
|
|
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
|
|
|
|
|
2019-04-22 23:19:52 +08:00
|
|
|
QPen p=getLinePenForRects(painter, parent);
|
|
|
|
QPen pw=getWhiskerPen(painter, parent);
|
2019-02-08 00:24:46 +08:00
|
|
|
QPen np(Qt::NoPen);
|
2019-04-22 23:19:52 +08:00
|
|
|
QBrush b=getFillBrush(painter, parent);
|
2019-02-08 00:24:46 +08:00
|
|
|
double yv=pos;
|
|
|
|
double p25v=percentile25;
|
|
|
|
double p75v=percentile75;
|
|
|
|
double minv=min;
|
|
|
|
double maxv=max;
|
|
|
|
double medianv=median;
|
2018-11-25 21:53:26 +08:00
|
|
|
|
2019-02-08 00:24:46 +08:00
|
|
|
//std::cout<<"(xv, yv) = ( "<<xv<<", "<<yv<<" )\n";
|
|
|
|
if (JKQTPIsOKFloat(yv) &&
|
|
|
|
JKQTPIsOKFloat(p25v) &&
|
|
|
|
JKQTPIsOKFloat(p75v) &&
|
|
|
|
JKQTPIsOKFloat(minv) &&
|
|
|
|
JKQTPIsOKFloat(maxv) &&
|
|
|
|
JKQTPIsOKFloat(medianv)) {
|
2018-11-25 21:53:26 +08:00
|
|
|
|
2019-02-08 00:24:46 +08:00
|
|
|
//std::cout<<"boxplot(med="<<medianv<<", min="<<minv<<", max="<<maxv<<", p25="<<p25v<<", p75="<<p75v<<")\n";
|
|
|
|
double y=transformY(yv);
|
|
|
|
double p25=transformX(p25v);
|
|
|
|
double p75=transformX(p75v);
|
|
|
|
double min=transformX(minv);
|
|
|
|
double max=transformX(maxv);
|
|
|
|
double median=transformX(medianv);
|
2018-11-25 21:53:26 +08:00
|
|
|
|
2019-04-22 23:19:52 +08:00
|
|
|
double w= parent->pt2px(painter, getBoxWidth());
|
2019-02-08 00:24:46 +08:00
|
|
|
double yma=y+w/2.0;
|
|
|
|
double ymi=y-w/2.0;
|
2018-11-25 21:53:26 +08:00
|
|
|
|
2019-02-08 00:24:46 +08:00
|
|
|
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
|
|
|
|
painter.setPen(p);
|
|
|
|
{
|
|
|
|
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
|
|
|
|
painter.setBrush(b);
|
|
|
|
painter.drawRect(QRectF(p25, ymi, fabs(p75-p25), fabs(yma-ymi)));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (drawMedian) {
|
|
|
|
painter.drawLine(QLineF(median, ymi, median, yma));
|
|
|
|
}
|
|
|
|
if (drawMinMax) {
|
|
|
|
painter.drawLine(QLineF(max, y-w/4.0, max, y+w/4.0));
|
|
|
|
painter.drawLine(QLineF(min, y-w/4.0, min, y+w/4.0));
|
|
|
|
painter.setPen(pw);
|
|
|
|
painter.drawLine(QLineF(max, y, p75, y));
|
|
|
|
painter.drawLine(QLineF(min, y, p25, y));
|
|
|
|
}
|
|
|
|
|
2018-11-25 21:53:26 +08:00
|
|
|
|
2019-02-08 00:24:46 +08:00
|
|
|
if (drawMean) {
|
|
|
|
double mean=transformY(this->mean);
|
2019-04-22 23:19:52 +08:00
|
|
|
plotStyledSymbol(parent, painter, mean, y);
|
2019-02-08 00:24:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2018-11-25 21:53:26 +08:00
|
|
|
}
|
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
//drawErrorsAfter(painter);
|
2018-11-25 21:53:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
void JKQTPBoxplotVerticalGraph::intSortData()
|
2018-11-25 21:53:26 +08:00
|
|
|
{
|
|
|
|
sortedIndices.clear();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (parent==nullptr) return ;
|
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
JKQTPDatastore* datastore=parent->getDatastore();
|
2018-11-25 21:53:26 +08:00
|
|
|
int imin=0;
|
|
|
|
int imax=datastore->getColumn(posColumn).getRows();
|
|
|
|
if (imax<imin) {
|
|
|
|
int h=imin;
|
|
|
|
imin=imax;
|
|
|
|
imax=h;
|
|
|
|
}
|
|
|
|
if (imin<0) imin=0;
|
|
|
|
if (imax<0) imax=0;
|
|
|
|
|
|
|
|
QVector<double> datas;
|
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
if (sortData==JKQTPBoxplotVerticalGraph::Sorted) {
|
2018-11-25 21:53:26 +08:00
|
|
|
|
|
|
|
for (int i=0; i<imax; i++) {
|
|
|
|
double xv=datastore->get(posColumn,i);
|
|
|
|
sortedIndices<<i;
|
|
|
|
datas<<xv;
|
|
|
|
}
|
|
|
|
|
|
|
|
jkqtpSort(datas.data(), sortedIndices.data(), datas.size());
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|