Add DIMS imaging support and improve imaging workflow#753
Open
YukiMatsuzawa wants to merge 12 commits into
Open
Add DIMS imaging support and improve imaging workflow#753YukiMatsuzawa wants to merge 12 commits into
YukiMatsuzawa wants to merge 12 commits into
Conversation
Refactored core imaging classes to use asynchronous methods for loading and processing pixel intensity data. Replaced synchronous calls with async counterparts, updated method signatures, and added CancellationToken support. Enhanced ViewModels to observe async loading states, improving UI responsiveness and scalability for long-running operations. Console/test code updated for compatibility.
Refactored AccumulatedIntensity to remove lazy async logic from the getter and made calculation explicit via a public method. Updated XAML bindings to use .Value for correct data binding. Made SelectedRoiPeakSummary nullable and trigger intensity calculation on selection. Simplified property binding and delegated calculation in the ViewModel.
Introduce thread-safe ConcurrentLruCache and IntensityImagePlaceholderModel for intensity image caching and retrieval. Update BitmapImageModel for async, thread-safe bitmap loading. Refactor models and viewmodels to use the new placeholder mechanism, replacing direct IntensityImageModel selection. Update SaveImagesModel and XAML bindings to support async image loading and improved null handling. Improve thread-safety and property change notifications throughout.
- Allow internal updates to BitmapImageModel.Title property - Dynamically set image titles based on m/z, mobility, and peak name - Ensure IntensityImagePlaceholderModel updates image titles as needed - Display current image title in ImagingMainView.xaml above the image - Add grid row in XAML to support image title display
Introduce ExportIntensitiesAsync to export only image intensities. Add ExportIntensitiesCommand to the view model and update the UI to use the new command. Change export button bindings from OneTime to OneWay for improved responsiveness.
Contributor
There was a problem hiding this comment.
Pull request overview
This PR extends MSDIAL5’s imaging capabilities by adding DIMS imaging UI entry points (Ribbon/tab) and refactoring the imaging pipeline toward async, cached/placeholder-based image/intensity loading, alongside new DIMS provider options and export/save workflow updates.
Changes:
- Added DIMS imaging Ribbon/Tab UI and new commands (ROI save/load, intensity export) for the imaging workflow.
- Refactored imaging image/intensity generation toward async loading with placeholder/caching models and updated bindings.
- Added a new “Accumulate/Sum MS1 spectra by m/z” data provider option for DIMS and tightened peak conversion mass range usage.
Reviewed changes
Copilot reviewed 41 out of 41 changed files in this pull request and generated 14 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/MSDIAL5/MsdialCoreTestApp/Process/MaldiMsProcessTest.cs | Updates pixel feature retrieval calls to async API in test app. |
| src/MSDIAL5/MsdialImmsImagingCore/Process/FileProcess.cs | Switches raw pixel spectra retrieval to async method. |
| src/MSDIAL5/MsdialGuiApp/ViewModel/ImagingImms/WholeImageResultViewModel.cs | Replaces selected intensity VM wiring with placeholder-based binding. |
| src/MSDIAL5/MsdialGuiApp/ViewModel/ImagingImms/ImagingImmsImageViewModel.cs | Adds Save ROI command wiring. |
| src/MSDIAL5/MsdialGuiApp/ViewModel/ImagingDims/WholeImageResultViewModel.cs | Mirrors IMMS placeholder-based binding for DIMS. |
| src/MSDIAL5/MsdialGuiApp/ViewModel/ImagingDims/ImagingDimsImageViewModel.cs | Adds Save ROI + Export intensities commands for DIMS imaging. |
| src/MSDIAL5/MsdialGuiApp/ViewModel/Imaging/RoiPeakSummaryViewModel.cs | Makes accumulated intensity reactive + async triggerable. |
| src/MSDIAL5/MsdialGuiApp/ViewModel/Imaging/ImagingRoiViewModel.cs | Triggers async accumulated-intensity computation on selection. |
| src/MSDIAL5/MsdialGuiApp/ViewModel/Dims/DimsDataCollectionSettingViewModel.cs | Adds VM binding for new accumulate-MS1 option. |
| src/MSDIAL5/MsdialGuiApp/ViewModel/Chart/BitmapImageViewModel.cs | Exposes BitmapSource as reactive + async ensure method. |
| src/MSDIAL5/MsdialGuiApp/View/Setting/DatasetFileSettingView.xaml.cs | Adds imzML to supported dataset file selection UI. |
| src/MSDIAL5/MsdialGuiApp/View/Setting/DataCollectionSettingView.xaml | Adds “Sum MS1 spectra by m/z” UI option and adjusts wording. |
| src/MSDIAL5/MsdialGuiApp/View/ImagingImms/ImagingMainView.xaml | Updates imaging view to use placeholder image binding + layout adjustments. |
| src/MSDIAL5/MsdialGuiApp/View/ImagingDims/ImagingTab.xaml.cs | New RibbonTab code-behind for DIMS imaging tab. |
| src/MSDIAL5/MsdialGuiApp/View/ImagingDims/ImagingTab.xaml | New DIMS imaging RibbonTab UI definition. |
| src/MSDIAL5/MsdialGuiApp/View/ImagingDims/ImagingMainView.xaml | Updates DIMS imaging view to use placeholder image binding + layout adjustments. |
| src/MSDIAL5/MsdialGuiApp/View/ImagingDims/DimsImagingRibbon.xaml | Adds contextual “Imaging” tab group and inserts the new DIMS imaging tab. |
| src/MSDIAL5/MsdialGuiApp/View/Chart/BitmapImageView.xaml | Updates binding path to reactive BitmapSource.Value. |
| src/MSDIAL5/MsdialGuiApp/Model/Loader/MsDecSpectrumFromFileLoader.cs | Adds exception handling/fallback behavior when loading MSDec results. |
| src/MSDIAL5/MsdialGuiApp/Model/ImagingImms/WholeImageResultModel.cs | Introduces placeholder model and selection-driven async image update (IMMS). |
| src/MSDIAL5/MsdialGuiApp/Model/ImagingImms/ImagingImmsMethodModel.cs | Saves imaging results across all image models rather than a single image. |
| src/MSDIAL5/MsdialGuiApp/Model/ImagingImms/ImagingImmsImageModel.cs | Adds folder-select ROI save behavior and returns success status. |
| src/MSDIAL5/MsdialGuiApp/Model/ImagingDims/WholeImageResultModel.cs | Introduces placeholder model + adds “save intensities to chosen file” workflow (DIMS). |
| src/MSDIAL5/MsdialGuiApp/Model/ImagingDims/ImagingDimsMethodModel.cs | Updates provider factory creation and saves imaging results across all images. |
| src/MSDIAL5/MsdialGuiApp/Model/ImagingDims/ImagingDimsImageModel.cs | Adds folder-select ROI save + explicit “Export intensities” method. |
| src/MSDIAL5/MsdialGuiApp/Model/Imaging/SaveImagesModel.cs | Updates image export to use placeholder image and prompts for output path. |
| src/MSDIAL5/MsdialGuiApp/Model/Imaging/RoiPeakSummaryModel.cs | Makes accumulated intensity computation async with loading state. |
| src/MSDIAL5/MsdialGuiApp/Model/Imaging/RoiModel.cs | Converts raw pixel spectra retrieval to async API. |
| src/MSDIAL5/MsdialGuiApp/Model/Imaging/RoiAccess.cs | Adds fast-path when ROI index mapping is identity. |
| src/MSDIAL5/MsdialGuiApp/Model/Imaging/RawIntensityOnPixelsLoader.cs | Refactors intensity loading to async and introduces a shared RawDataAccess field. |
| src/MSDIAL5/MsdialGuiApp/Model/Imaging/IWholeImageResultModel.cs | Switches interface from selected-intensity to placeholder image model. |
| src/MSDIAL5/MsdialGuiApp/Model/Imaging/IntensityImagePlaceholderModel.cs | New cached/placeholder image model for async intensity image generation. |
| src/MSDIAL5/MsdialGuiApp/Model/Imaging/IntensityImageModel.cs | Makes peak index accessible and shifts intensity load to async API usage. |
| src/MSDIAL5/MsdialGuiApp/Model/Imaging/ImagingRoiModel.cs | Saves ROI position CSV into a user-selected directory. |
| src/MSDIAL5/MsdialGuiApp/Model/Dims/DimsDataCollectionSettingModel.cs | Adds accumulate-MS1 option and parameter (de)serialization logic. |
| src/MSDIAL5/MsdialGuiApp/Model/Chart/BitmapImageModel.cs | Adds async bitmap realization with a loading flag and semaphore. |
| src/MSDIAL5/MsdialDimsCore/ProcessFile.cs | Applies mass range bounds when converting MS1 peaks. |
| src/MSDIAL5/MsdialDimsCore/Parameter/DimsProviderFactoryParameter.cs | Adds MessagePack union/parameter type for accumulate-MS1 provider. |
| src/MSDIAL5/MsdialDimsCore/Algorithm/DimsDataProvider.cs | Implements accumulate-MS1 provider and factory. |
| src/MSDIAL5/MsdialCore/Enum/SupportFormat.cs | Adds imzML to supported raw data extensions enum. |
| src/Common/CommonStandard/DataStructure/ConcurrentLruCache.cs | Adds a thread-safe wrapper around LruCache (currently with lock-mode issues). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+21
to
+29
| public TValue Get(TKey key) { | ||
| _locker.EnterReadLock(); | ||
| try { | ||
| return _cache.Get(key); | ||
| } | ||
| finally { | ||
| _locker.ExitReadLock(); | ||
| } | ||
| } |
Comment on lines
+51
to
+64
| public bool TryGet(TKey key, out TValue value) { | ||
| _locker.EnterReadLock(); | ||
| try { | ||
| if (_cache.ContainsKey(key)) { | ||
| value = _cache.Get(key); | ||
| return true; | ||
| } | ||
| value = default; | ||
| return false; | ||
| } | ||
| finally { | ||
| _locker.ExitReadLock(); | ||
| } | ||
| } |
Comment on lines
+15
to
19
| private readonly RawDataAccess _rawDataAccess; | ||
|
|
||
| public RawIntensityOnPixelsLoader(List<Raw2DElement> targets, AnalysisFileBeanModel file, MaldiFrames frames) | ||
| { | ||
| _targets = targets; |
Comment on lines
+42
to
+60
| public async Task EnsureBitmapSourceAsync() { | ||
| if (_bitmapSource is not null || LoadingBitmap) { | ||
| return; | ||
| } | ||
|
|
||
| await _semaphoreSlim.WaitAsync().ConfigureAwait(false); | ||
|
|
||
| try { | ||
| if (_bitmapSource is not null || LoadingBitmap) { | ||
| return; | ||
| } | ||
| LoadingBitmap = true; | ||
| BitmapSource = await Task.Run(() => _bitmapSourceFactory!.Invoke()).ConfigureAwait(false); | ||
| LoadingBitmap = false; | ||
| } | ||
| finally { | ||
| _semaphoreSlim.Release(); | ||
| } | ||
| } |
Comment on lines
113
to
+131
| using var sem = new SemaphoreSlim(8, 8); | ||
| var tasks = new List<Task>(Intensities.Count); | ||
| foreach (var ints in Intensities) { | ||
| tasks.Add(Task.Run(async () => { | ||
| await sem.WaitAsync().ConfigureAwait(false); | ||
| try { | ||
| await ints.SaveAsync(writer, skipUnknownPeaks: false, token: token); | ||
| } | ||
| finally { | ||
| sem.Release(); | ||
| } | ||
| }, token)); | ||
| } | ||
| await Task.WhenAll(tasks).ConfigureAwait(false); | ||
| var task = Task.CompletedTask; | ||
| await task; | ||
| task.Wait(); | ||
|
|
||
| return true; |
Comment on lines
+104
to
+110
| case DimsAccumulateDataProviderFactoryParameter accumulateParameter: | ||
| UseMs1WithHighestTic = false; | ||
| UseAccumulateMs1 = true; | ||
| TimeBegin = accumulateParameter.TimeBegin; | ||
| TimeEnd = accumulateParameter.TimeEnd; | ||
| MassTolerance = accumulateParameter.MassTolerance; | ||
| break; |
Comment on lines
204
to
206
| <Rectangle.ToolTip> | ||
| <TextBlock Text="{Binding SelectedRoiPeakSummary.Value.AccumulatedIntensity, StringFormat=Average intensity: {0:F0}}"/> | ||
| <TextBlock Text="{Binding SelectedRoiPeakSummary.Value.AccumulatedIntensity.Value, StringFormat=Average intensity: {0:F0}}"/> | ||
| </Rectangle.ToolTip> |
Comment on lines
194
to
196
| <Rectangle.ToolTip> | ||
| <TextBlock Text="{Binding SelectedRoiPeakSummary.Value.AccumulatedIntensity, StringFormat=Average intensity: {0:F0}}"/> | ||
| <TextBlock Text="{Binding SelectedRoiPeakSummary.Value.AccumulatedIntensity.Value, StringFormat=Average intensity: {0:F0}}"/> | ||
| </Rectangle.ToolTip> |
Comment on lines
210
to
213
| Console.WriteLine("Reading data..."); | ||
| using (var access = new RawDataAccess(filepath, 0, false, true, false)) { | ||
| pixelData = access.GetRawPixelFeatures(featureElements, null); | ||
| pixelData = access.GetRawPixelFeaturesAsync(featureElements, null).Result; | ||
| } |
Comment on lines
304
to
308
| var featureElements = features.Select(n => new Raw2DElement() { Mz = n.PeakFeature.Mass }).ToList(); | ||
| Console.WriteLine("Reading data..."); | ||
| using (var access = new RawDataAccess(filepath, 0, false, true, false)) { | ||
| pixelData = access.GetRawPixelFeatures(featureElements, null); | ||
| pixelData = access.GetRawPixelFeaturesAsync(featureElements, null).Result; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR adds and refines the DIMS imaging flow, including the new imaging tab/ribbon UI, async pixel intensity loading, placeholder handling, and export support. It also updates the underlying data providers, image models, and DIMS/IMMS imaging view models to align the UI and processing pipeline.
Key changes: