Extending script plot() function

This commit is contained in:
2025-04-23 13:37:47 +02:00
parent e6bab45a89
commit 78f242d808
6 changed files with 273 additions and 37 deletions
+238
View File
@@ -0,0 +1,238 @@
#include "chartgraph.h"
#include <QChartView>
#include <QVBoxLayout>
#include <QLineSeries>
#include <QBarSeries>
#include <QBarSet>
#include <QScatterSeries>
#include <QMenu>
#include <QMenuBar>
#include <QValueAxis>
#include <QFileDialog>
#include <QSettings>
class ChartView : public QChartView
{
QPointF _mousePos;
bool _scroll = false;
public:
ChartView(QWidget *parent) : QChartView(parent)
{
}
protected:
void keyPressEvent(QKeyEvent *event) override
{
switch(event->key())
{
case Qt::Key_Plus:
chart()->zoomIn();
break;
case Qt::Key_Minus:
chart()->zoomOut();
break;
case Qt::Key_Left:
chart()->scroll(-10, 0);
break;
case Qt::Key_Right:
chart()->scroll(10, 0);
break;
case Qt::Key_Up:
chart()->scroll(0, 10);
break;
case Qt::Key_Down:
chart()->scroll(0, -10);
break;
default:
QGraphicsView::keyPressEvent(event);
break;
}
}
void mousePressEvent(QMouseEvent *event) override
{
if(event->button() == Qt::LeftButton)
{
_scroll = true;
_mousePos = event->position();
}
QChartView::mousePressEvent(event);
}
void mouseMoveEvent(QMouseEvent *event) override
{
if(_scroll)
{
QPointF pos = event->position();
chart()->scroll(_mousePos.x() - pos.x(), pos.y() - _mousePos.y());
_mousePos = pos;
}
QChartView::mouseMoveEvent(event);
}
void mouseReleaseEvent(QMouseEvent *event) override
{
_scroll = false;
QChartView::mouseReleaseEvent(event);
}
};
ChartGraph::ChartGraph(QWidget *parent) : QDialog(parent)
{
setAttribute(Qt::WA_DeleteOnClose);
setModal(false);
_chartView = new ChartView(this);
setLayout(new QVBoxLayout);
layout()->addWidget(_chartView);
_chart = new QChart;
_chartView->setChart(_chart);
_chartView->setRenderHint(QPainter::Antialiasing);
resize(1024, 768);
QMenuBar *menuBar = new QMenuBar(this);
menuBar->addAction(tr("Save"), this, &ChartGraph::save);
layout()->setMenuBar(menuBar);
}
void ChartGraph::plot(const QVariant &graph)
{
QVariantMap map = graph.toMap();
_chart->setTitle(map["title"].toString());
if(map.contains("legend"))
{
QVariantMap legend = map["legend"].toMap();
if(legend.contains("visible"))
_chart->legend()->setVisible(legend["visible"].toBool());
QString align = legend["align"].toString();
if(align == "top")
_chart->legend()->setAlignment(Qt::AlignTop);
else if(align == "left")
_chart->legend()->setAlignment(Qt::AlignLeft);
else if(align == "bottom")
_chart->legend()->setAlignment(Qt::AlignBottom);
else if(align == "right")
_chart->legend()->setAlignment(Qt::AlignRight);
}
QBarSeries *barSeries = nullptr;
qreal minY = INFINITY;
qreal maxY = -INFINITY;
for(auto s : map["series"].toList())
{
QVariantMap serie = s.toMap();
QString type = serie["type"].toString();
if(type == "line" || type == "points" || type == "linePoints" || type.isEmpty())
{
QXYSeries *series = nullptr;
if(type == "points")
{
QScatterSeries *scatter = new QScatterSeries(_chart);
series = scatter;
QString shape = serie["shape"].toString();
if(shape == "circle")scatter->setMarkerShape(QScatterSeries::MarkerShapeCircle);
else if(shape == "rectangle")scatter->setMarkerShape(QScatterSeries::MarkerShapeRectangle);
else if(shape == "triangle")scatter->setMarkerShape(QScatterSeries::MarkerShapeTriangle);
else if(shape == "star")scatter->setMarkerShape(QScatterSeries::MarkerShapeStar);
else if(shape == "pentagon")scatter->setMarkerShape(QScatterSeries::MarkerShapePentagon);
}
else
{
series = new QLineSeries(_chart);
}
series->setName(serie["title"].toString());
QVariantList x = serie["x"].toList();
QVariantList y = serie["y"].toList();
if(x.isEmpty())
{
for(int i = 0; i < y.size(); i++)
{
qreal val = y[i].toDouble();
minY = std::min(minY, val);
maxY = std::max(maxY, val);
series->append(i, val);
}
}
else
{
int size = std::min(x.size(), y.size());
for(int i = 0; i < size; i++)
{
qreal val = y[i].toDouble();
minY = std::min(minY, val);
maxY = std::max(maxY, val);
series->append(x[i].toDouble(), val);
}
}
_chart->addSeries(series);
if(serie["bestFit"].toBool())
{
series->setBestFitLineVisible(true);
QPen pen = series->bestFitLinePen();
pen.setColor(series->color());
pen.setStyle(Qt::DashLine);
series->setBestFitLinePen(pen);
}
if(type == "linePoints")
series->setPointsVisible(true);
if(serie.contains("color"))
{
QString color = serie["color"].toString();
if(QColor::isValidColorName(color))series->setColor(QColor::fromString(color));
}
}
else if(type == "bar")
{
if(!barSeries)
{
barSeries = new QBarSeries(_chart);
_chart->addSeries(barSeries);
}
QBarSet *set = new QBarSet(serie["title"].toString());
QVariantList y = serie["y"].toList();
for(int i = 0; i < y.size(); i++)
{
qreal val = y[i].toDouble();
minY = std::min(minY, val);
maxY = std::max(maxY, val);
set->append(val);
}
barSeries->append(set);
if(serie.contains("color"))
{
QString color = serie["color"].toString();
if(QColor::isValidColorName(color))set->setColor(QColor::fromString(color));
}
}
}
_chart->createDefaultAxes();
QValueAxis *yaxis = qobject_cast<QValueAxis*>(_chart->axes(Qt::Vertical).front());
if(yaxis)
{
qreal off = (maxY - minY) * 0.05;
yaxis->setRange(std::min(minY - off, 0.0), maxY + off);
}
show();
}
void ChartGraph::save()
{
QSettings settings;
QString dir = settings.value("mainwindow/lastdir").toString();
QString output = QFileDialog::getSaveFileName(this, tr("Save as"), dir, "PNG (*.png)");
if(!output.isEmpty())
{
QPixmap graph = _chartView->grab();
graph.toImage().save(output);
}
}