diff --git a/viewer/JFJochViewerDatasetInfo.cpp b/viewer/JFJochViewerDatasetInfo.cpp index d27f8ecc..1aec8ef3 100644 --- a/viewer/JFJochViewerDatasetInfo.cpp +++ b/viewer/JFJochViewerDatasetInfo.cpp @@ -80,7 +80,7 @@ void JFJochViewerDatasetInfo::datasetLoaded(std::shared_ptrloadValues({}, 0); + chart_view->loadValues({}, 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()); diff --git a/viewer/charts/JFJochChartView.cpp b/viewer/charts/JFJochChartView.cpp index 942c4330..3d4ffe3b 100644 --- a/viewer/charts/JFJochChartView.cpp +++ b/viewer/charts/JFJochChartView.cpp @@ -4,11 +4,12 @@ #include #include #include +#include #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(chart()->axisY(series)); + QValueAxis *axisY = qobject_cast(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(idx)], 0, 'g', 6); + const double yv = values[static_cast(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 diff --git a/viewer/charts/JFJochChartView.h b/viewer/charts/JFJochChartView.h index d3a50b20..85dfd108 100644 --- a/viewer/charts/JFJochChartView.h +++ b/viewer/charts/JFJochChartView.h @@ -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 - void loadValues(const std::vector &input, int64_t image) { + void loadValues(const std::vector &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(input[i]); + for (int i = 0; i < input.size(); i++) { + if (one_over_d2) { + + float d = static_cast(input[i]); + if (!std::isfinite(d)) + values[i] = 0.0f; + else + values[i] = 1.0f / (d * d); + } else + values[i] = static_cast(input[i]); + } curr_image = image; updateChart(); }