viewer: overlay one plot line per processing run (with editable names)
The dataset-info plot now overlays every run as a separate named line instead of replacing the plot when a snapshot is activated: - Reader gains AllSnapshotDatasets() (every snapshot's dataset, Original first). - The worker owns the run collection: a stable snapshot id plus an editable display label (RunData), emitted as runsChanged(runs, active_id) on file open, snapshot register, activate and rename. RenameRun(id, label) updates the legend label without touching the reader key (decoupled id vs label). - The chart view draws the active run as the primary series (markers, hover, binning, axes) and the other runs as overlay lines sharing its axes, with a legend shown when overlaying (appendSeries factored out for both). - The dataset-info widget holds the run list + the live run, extracts the selected metric from each (ExtractMetric), and unions the available metrics across runs. - The live run is its own "Live" overlay (lightweight per-tick refresh, no combo rebuild); it is cleared on finish so the persisted snapshot takes over. - The processing jobs table gets a "Started" column and an editable Name column; editing a name renames that run's legend label. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -97,6 +97,8 @@ JFJochImageReadingWorker::JFJochImageReadingWorker(const SpotFindingSettings &se
|
||||
qRegisterMetaType<ROIDefinition>("ROIDefinition");
|
||||
qRegisterMetaType<BraggIntegrationSettings>("BraggIntegrationSettings");
|
||||
qRegisterMetaType<ScalingSettings>("ScalingSettings");
|
||||
qRegisterMetaType<RunData>("RunData");
|
||||
qRegisterMetaType<QVector<RunData>>("QVector<RunData>");
|
||||
spot_finding_settings = settings;
|
||||
|
||||
indexing = std::make_unique<IndexerThreadPool>(indexing_settings);
|
||||
@@ -287,6 +289,12 @@ void JFJochImageReadingWorker::LoadFile_i(const QString &filename, qint64 image_
|
||||
|
||||
emit datasetLoaded(dataset);
|
||||
|
||||
// Reset the run collection for the freshly opened file (file mode only has snapshots).
|
||||
run_labels_.clear();
|
||||
if (!http_mode)
|
||||
run_labels_["Original"] = "Original";
|
||||
EmitRuns_i();
|
||||
|
||||
auto end = std::chrono::high_resolution_clock::now();
|
||||
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
|
||||
logger.Info(fmt::format("Loaded file {} in {} ms", filename.toStdString(), duration));
|
||||
@@ -948,6 +956,7 @@ void JFJochImageReadingWorker::ActivateSnapshot_i(const QString &name) {
|
||||
for (const auto &n: file_reader.SnapshotNames())
|
||||
names << QString::fromStdString(n);
|
||||
emit snapshotsChanged(names, QString::fromStdString(file_reader.ActiveSnapshot()));
|
||||
EmitRuns_i();
|
||||
|
||||
if (current_image.has_value()) {
|
||||
// A snapshot carries its own per-image results; just re-read the image against the new
|
||||
@@ -959,17 +968,37 @@ void JFJochImageReadingWorker::ActivateSnapshot_i(const QString &name) {
|
||||
}
|
||||
}
|
||||
|
||||
void JFJochImageReadingWorker::RegisterProcessingSnapshot(QString name, QString master_path) {
|
||||
void JFJochImageReadingWorker::EmitRuns_i() {
|
||||
// Assumes m locked! Build the run list (every snapshot dataset + its display label).
|
||||
QVector<RunData> runs;
|
||||
if (!http_mode) {
|
||||
for (const auto &[id, dataset]: file_reader.AllSnapshotDatasets()) {
|
||||
const auto it = run_labels_.find(id);
|
||||
const QString label = (it != run_labels_.end()) ? it->second : QString::fromStdString(id);
|
||||
runs.push_back(RunData{QString::fromStdString(id), label, dataset});
|
||||
}
|
||||
}
|
||||
emit runsChanged(runs, http_mode ? QString() : QString::fromStdString(file_reader.ActiveSnapshot()));
|
||||
}
|
||||
|
||||
void JFJochImageReadingWorker::RenameRun(QString id, QString label) {
|
||||
QMutexLocker ul(&m);
|
||||
run_labels_[id.toStdString()] = label;
|
||||
EmitRuns_i();
|
||||
}
|
||||
|
||||
void JFJochImageReadingWorker::RegisterProcessingSnapshot(QString id, QString label, QString master_path) {
|
||||
QMutexLocker ul(&m);
|
||||
if (http_mode) {
|
||||
logger.Error("Processing snapshots are only available for files");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
file_reader.RegisterSnapshot(name.toStdString(), master_path.toStdString());
|
||||
ActivateSnapshot_i(name);
|
||||
file_reader.RegisterSnapshot(id.toStdString(), master_path.toStdString());
|
||||
run_labels_[id.toStdString()] = label;
|
||||
ActivateSnapshot_i(id); // activates + emits datasetLoaded / snapshotsChanged / runsChanged
|
||||
} catch (const std::exception &e) {
|
||||
logger.Error("Failed to register snapshot {}: {}", name.toStdString(), e.what());
|
||||
logger.Error("Failed to register snapshot {}: {}", id.toStdString(), e.what());
|
||||
emit fileLoadError("Snapshot error", QString::fromStdString(e.what()));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user