124 lines
4.3 KiB
C++
124 lines
4.3 KiB
C++
// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
#include "JFJochSimpleChartView.h"
|
|
|
|
#include <QMenu>
|
|
#include <QClipboard>
|
|
#include <QApplication>
|
|
#include <QCategoryAxis>
|
|
|
|
JFJochSimpleChartView::JFJochSimpleChartView(QWidget *parent)
|
|
: QChartView(new QChart(), parent) {
|
|
chart()->legend()->hide();
|
|
setFixedHeight(200);
|
|
setRenderHint(QPainter::Antialiasing);
|
|
//setRubberBand(QChartView::RubberBand::HorizontalRubberBand);
|
|
}
|
|
|
|
void JFJochSimpleChartView::UpdateData(const std::vector<float> &in_x, const std::vector<float> &in_y, bool one_over_x) {
|
|
x = in_x; y = in_y;
|
|
chart()->removeAllSeries();
|
|
// Remove all axes to avoid duplicates
|
|
for (auto ax : chart()->axes()) chart()->removeAxis(ax);
|
|
|
|
if (x.empty() || x.size() != y.size()) return;
|
|
|
|
auto* series = new QLineSeries(this);
|
|
for (size_t i = 0; i < x.size(); ++i) series->append(x[i], y[i]);
|
|
chart()->addSeries(series);
|
|
|
|
auto* axY = new QValueAxis();
|
|
chart()->addAxis(axY, Qt::AlignLeft);
|
|
series->attachAxis(axY);
|
|
|
|
// Build X range
|
|
auto [minXIt, maxXIt] = std::minmax_element(x.begin(), x.end());
|
|
const double xmin = *minXIt, xmax = *maxXIt;
|
|
|
|
if (one_over_x) {
|
|
// Hidden X value axis on top for grid/range
|
|
auto* axXTop = new QValueAxis();
|
|
axXTop->setRange(xmin, xmax);
|
|
axXTop->setTickCount(5);
|
|
axXTop->setLabelsVisible(false);
|
|
chart()->addAxis(axXTop, Qt::AlignTop);
|
|
series->attachAxis(axXTop);
|
|
|
|
// Visible category axis at bottom for 1/x labels
|
|
auto* axXcat = new QCategoryAxis();
|
|
axXcat->setLabelsPosition(QCategoryAxis::AxisLabelsPositionOnValue);
|
|
axXcat->setGridLineVisible(false);
|
|
axXcat->setMinorGridLineVisible(false);
|
|
|
|
const int tickCount = axXTop->tickCount();
|
|
const double step = (tickCount > 1) ? (xmax - xmin) / (tickCount - 1) : 0.0;
|
|
for (int i = 0; i < tickCount; ++i) {
|
|
const double xv = xmin + i * step;
|
|
const QString lab = (std::abs(xv) < 1e-12)
|
|
? QStringLiteral("∞")
|
|
: QString::number(1.0 / xv, 'g', 4);
|
|
axXcat->append(lab, xv);
|
|
}
|
|
chart()->addAxis(axXcat, Qt::AlignBottom);
|
|
series->attachAxis(axXcat);
|
|
} else {
|
|
// Normal value axis at bottom
|
|
auto* axX = new QValueAxis();
|
|
axX->setRange(xmin, xmax);
|
|
chart()->addAxis(axX, Qt::AlignBottom);
|
|
series->attachAxis(axX);
|
|
}
|
|
}
|
|
|
|
void JFJochSimpleChartView::ClearData() {
|
|
chart()->removeAllSeries();
|
|
}
|
|
|
|
void JFJochSimpleChartView::contextMenuEvent(QContextMenuEvent *event) {
|
|
QMenu menu(this);
|
|
QAction *copyXY = menu.addAction("Copy (x y) points");
|
|
copyXY->setEnabled(!x.empty() && x.size() == y.size());
|
|
|
|
QAction *chosen = menu.exec(event->globalPos());
|
|
if (chosen == copyXY) {
|
|
QString out;
|
|
out.reserve(static_cast<int>(x.size() * 16)); // rough prealloc
|
|
for (size_t i = 0; i < x.size() && i < y.size(); ++i) {
|
|
out.append(QString::number(x[i], 'g', 10));
|
|
out.append(' ');
|
|
out.append(QString::number(y[i], 'g', 10));
|
|
if (i + 1 < x.size()) out.append('\n');
|
|
}
|
|
QClipboard *cb = QApplication::clipboard();
|
|
cb->setText(out);
|
|
}
|
|
}
|
|
|
|
void JFJochSimpleChartView::applyInverseXLabels(QValueAxis* axX, QLineSeries* s) {
|
|
axX->setTickCount(5); // adjust as needed
|
|
axX->setLabelsVisible(false); // hide default numeric labels
|
|
|
|
auto* axXcat = new QCategoryAxis();
|
|
axXcat->setLabelsPosition(QCategoryAxis::AxisLabelsPositionOnValue);
|
|
axXcat->setGridLineVisible(false);
|
|
axXcat->setMinorGridLineVisible(false);
|
|
|
|
const int tickCount = axX->tickCount();
|
|
const double min = axX->min();
|
|
const double max = axX->max();
|
|
const double step = (tickCount > 1) ? (max - min) / (tickCount - 1) : 0.0;
|
|
|
|
for (int i = 0; i < tickCount; ++i) {
|
|
const double xv = min + i * step;
|
|
if (std::abs(xv) < 1e-12) {
|
|
axXcat->append("∞", xv);
|
|
} else {
|
|
const double inv = 1.0 / xv;
|
|
axXcat->append(QString::number(inv, 'g', 4), xv);
|
|
}
|
|
}
|
|
|
|
chart()->addAxis(axXcat, Qt::AlignBottom);
|
|
s->attachAxis(axXcat);
|
|
} |