jfjoch_viewer: Resolution estimate plot uses 1/d^2 as Y-axis
This commit is contained in:
@@ -80,7 +80,7 @@ void JFJochViewerDatasetInfo::datasetLoaded(std::shared_ptr<const JFJochReaderDa
|
||||
if (dataset) {
|
||||
UpdatePlot();
|
||||
} else {
|
||||
chart_view->loadValues<float>({}, 0);
|
||||
chart_view->loadValues<float>({}, 0, false);
|
||||
grid_scan_image->clear();
|
||||
}
|
||||
}
|
||||
@@ -127,7 +127,7 @@ void JFJochViewerDatasetInfo::UpdatePlot() {
|
||||
else if (val == 8)
|
||||
data = dataset->b_factor;
|
||||
|
||||
chart_view->loadValues(data, image_number);
|
||||
chart_view->loadValues(data, image_number, val == 7);
|
||||
if (dataset->experiment.GetGridScan()) {
|
||||
stack->setCurrentWidget(grid_scan_image);
|
||||
grid_scan_image->loadData(data, dataset->experiment.GetGridScan().value());
|
||||
|
||||
@@ -4,11 +4,12 @@
|
||||
#include <QMenu>
|
||||
#include <QApplication>
|
||||
#include <QClipboard>
|
||||
#include <QCategoryAxis>
|
||||
|
||||
#include "JFJochChartView.h"
|
||||
|
||||
JFJochChartView::JFJochChartView(QWidget *parent)
|
||||
: QChartView(new QChart(), parent) {
|
||||
: QChartView(new QChart(), parent) {
|
||||
chart()->legend()->hide();
|
||||
setRenderHint(QPainter::Antialiasing);
|
||||
setRubberBand(QChartView::RubberBand::RectangleRubberBand);
|
||||
@@ -17,7 +18,6 @@ JFJochChartView::JFJochChartView(QWidget *parent)
|
||||
m_hoverLoadTimer = new QTimer(this);
|
||||
m_hoverLoadTimer->setSingleShot(true);
|
||||
connect(m_hoverLoadTimer, &QTimer::timeout, this, &JFJochChartView::onHoverLoadTimeout);
|
||||
|
||||
}
|
||||
|
||||
void JFJochChartView::setImage(int64_t val) {
|
||||
@@ -107,7 +107,7 @@ void JFJochChartView::updateChart() {
|
||||
chart()->createDefaultAxes();
|
||||
|
||||
// Set Y-axis behavior according to options
|
||||
QValueAxis *axisY = qobject_cast<QValueAxis*>(chart()->axisY(series));
|
||||
QValueAxis *axisY = qobject_cast<QValueAxis *>(chart()->axisY(series));
|
||||
if (axisY) {
|
||||
if (std::isfinite(dispMin) && std::isfinite(dispMax)) {
|
||||
if (m_minYZeroEnabled) {
|
||||
@@ -123,6 +123,51 @@ void JFJochChartView::updateChart() {
|
||||
axisY->setRange(dispMin, dispMax);
|
||||
}
|
||||
}
|
||||
|
||||
// If Y is in 1/d^2, hide numeric labels and add a category axis with d labels
|
||||
if (m_yOneOverD) {
|
||||
axisY->setLabelsVisible(false); // keep grid/ticks from value axis
|
||||
|
||||
// Build a mirrored visible axis with labels in d (Å)
|
||||
auto *axYcat = new QCategoryAxis();
|
||||
axYcat->setLabelsPosition(QCategoryAxis::AxisLabelsPositionOnValue);
|
||||
axYcat->setGridLineVisible(false);
|
||||
axYcat->setMinorGridLineVisible(false);
|
||||
axYcat->setTitleText(QStringLiteral("d (Å)"));
|
||||
|
||||
const int tickCountY = std::max(2, axisY->tickCount());
|
||||
const double ymin = axisY->min();
|
||||
const double ymax = axisY->max();
|
||||
const double ystep = (tickCountY > 1) ? (ymax - ymin) / (tickCountY - 1) : 0.0;
|
||||
|
||||
for (int i = 0; i < tickCountY; ++i) {
|
||||
const double yv = (i == tickCountY - 1) ? ymax : (ymin + i * ystep);
|
||||
QString lab;
|
||||
if (!(yv > 0.0)) {
|
||||
lab = QStringLiteral("—"); // invalid for d
|
||||
} else if (std::abs(yv) < 1e-300) {
|
||||
lab = QStringLiteral("∞");
|
||||
} else {
|
||||
const double d = 1.0 / std::sqrt(yv);
|
||||
lab = QString("%1 Å").arg(d, 0, 'f', 2);
|
||||
}
|
||||
axYcat->append(lab, yv);
|
||||
}
|
||||
chart()->addAxis(axYcat, Qt::AlignLeft);
|
||||
series->attachAxis(axYcat);
|
||||
currentSeries->attachAxis(axYcat);
|
||||
|
||||
// Give a bit more room on the left so labels are not clipped
|
||||
QMargins m = chart()->margins();
|
||||
if (m.left() < 12) {
|
||||
m.setLeft(12);
|
||||
chart()->setMargins(m);
|
||||
}
|
||||
} else {
|
||||
// Normal numeric labels
|
||||
axisY->setTitleText(QString());
|
||||
axisY->setLabelsVisible(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -192,9 +237,22 @@ void JFJochChartView::mouseMoveEvent(QMouseEvent *event) {
|
||||
ptOnChart.x(), plotArea.bottom()));
|
||||
|
||||
// Status bar text
|
||||
QString text = QString("image = %1, value = %2")
|
||||
.arg(idx)
|
||||
.arg(values[static_cast<size_t>(idx)], 0, 'g', 6);
|
||||
const double yv = values[static_cast<size_t>(idx)];
|
||||
QString text;
|
||||
if (m_yOneOverD) {
|
||||
if (std::isfinite(yv) && yv > 0.0) {
|
||||
const double d = 1.0 / std::sqrt(yv);
|
||||
text = QString("image = %1, d = %2 Å")
|
||||
.arg(idx)
|
||||
.arg(d, 0, 'f', 2);
|
||||
} else {
|
||||
text = QString("image = %1, no resolution estimate").arg(idx);
|
||||
}
|
||||
} else {
|
||||
text = QString("image = %1, value = %2")
|
||||
.arg(idx)
|
||||
.arg(yv, 0, 'g', 6);
|
||||
}
|
||||
emit writeStatusBar(text, 6000);
|
||||
|
||||
// Debounced image load on hover when Shift is pressed
|
||||
|
||||
@@ -25,6 +25,7 @@ class JFJochChartView : public QChartView {
|
||||
int64_t curr_image = 0;
|
||||
|
||||
bool m_minYZeroEnabled = true;
|
||||
bool m_yOneOverD = false;
|
||||
|
||||
void updateChart();
|
||||
|
||||
@@ -51,10 +52,21 @@ public slots:
|
||||
|
||||
public:
|
||||
template<class T>
|
||||
void loadValues(const std::vector<T> &input, int64_t image) {
|
||||
void loadValues(const std::vector<T> &input, int64_t image, bool one_over_d2) {
|
||||
m_yOneOverD = one_over_d2;
|
||||
|
||||
values.resize(input.size());
|
||||
for (int i = 0; i < input.size(); i++)
|
||||
values[i] = static_cast<float>(input[i]);
|
||||
for (int i = 0; i < input.size(); i++) {
|
||||
if (one_over_d2) {
|
||||
|
||||
float d = static_cast<float>(input[i]);
|
||||
if (!std::isfinite(d))
|
||||
values[i] = 0.0f;
|
||||
else
|
||||
values[i] = 1.0f / (d * d);
|
||||
} else
|
||||
values[i] = static_cast<float>(input[i]);
|
||||
}
|
||||
curr_image = image;
|
||||
updateChart();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user