Mass spectrometry imaging-based explainable machine learning reveals the biochemical landscapes of the mouse brain.
The 4 matches
- [1] § Materials and methods › Modeling › Model-based selection of m/z markers for each brain region ↔ notebooks/linear.ipynb, lines 28–124 · score 0.78 · noise feature, permuted features, linear model, thresholds, selection, subsampling
- [2] § Materials and methods › Modeling › Model-based selection of m/z markers for each brain region ↔ msi_atlas/mapping.py, lines 19–83 · score 0.69 · permuted features, linear model, thresholds, selection, subsampling, noise
- [3] § Materials and methods › Visualizations › Virtual Pathology Stain (VPS) ↔ notebooks/linear.ipynb, lines 376–450 · score 0.68 · grayscale, 0–1, RGB, stain, pixels, IHC
- [4] § Materials and methods › Modeling › Machine learning-based classification of pixel categories ↔ msi_atlas/atlas_linear_model.py, lines 17–147 · score 0.52 · sampled weights, Pyro, uncertainty, linear, predictive, model
Paper
Loaded from Europe PMC by your browser, not stored by OSCR: doi.org · Europe PMC
The paper is loaded when this pane is shown.
The authors' code
Jupyter notebook · 494 lines · 17 KB · MIT · 2 matches
- # %%
- from msi_visual.normalization import total_ion_count, spatial_total_ion_count
- from msi_atlas.annotations import get_dataset
- import numpy as np
- from argparse import Namespace
- from pathlib import Path
- import joblib
- array = np.array
- import os
- path = r"/home/jacob/Desktop/atlas_verification"
- extraction_args = eval(
- open(
- Path(path) /
- "args.txt").read())
- extraction_mzs = extraction_args.mzs
- paths = [(Path(path) / "0.npy", 1),
- (Path(path) / "2.npy", 0),
- (Path(path) / "1.npy", 2),
- (Path(path) / "3.npy", 3)]
- paths = [(str(path[0]), path[1]) for path in paths]
- X, y, slide_labels, label_encoder = get_dataset(r"NRL4485-s2_reannotation_23-12-24_PAHJ.json",
- paths, subsample=1, normalization=total_ion_count)
- # %%
- from msi_atlas.atlas_linear_model import AtlasLinearModel
- import torch
- def permute_features(X, noise_dim, random_state=None):
- """
- Creates noise features by randomly selecting columns from X and permuting their values.
- """
- rng = np.random.default_rng(random_state)
- n_samples, n_features = X.shape
- noise_indices = rng.choice(n_features, size=noise_dim, replace=True)
- noise = np.zeros((n_samples, noise_dim))
- for i, col_idx in enumerate(noise_indices):
- noise[:, i] = rng.permutation(X[:, col_idx])
- return noise
- def feature_stability_with_noise(X, y,
- num_runs=30,
- reg_strengths=[1e-2, 1e-3],
- noise_dim=20,
- subsample_ratio=0.8,
- weight_threshold=1e-4,
- random_state=None):
- """
- Estimates feature stability using subsampling and permuted real features for FDR control.
- Returns:
- - selected_features: boolean mask for real features
- - stability: array of shape (n_features + noise_dim,) with selection frequencies
- - noise_threshold: max stability among permuted (noise) features
- """
- rng = np.random.default_rng(random_state)
- n_samples, n_features = X.shape
- total_features = n_features + noise_dim
- stability = np.zeros((y.max()+1, total_features))
- all_weights = []
- balanced_accs = []
- accs = []
- for _ in range(num_runs):
- idx = rng.choice(n_samples, int(subsample_ratio * n_samples), replace=False)
- X_sub, y_sub = X[idx], y[idx]
- X_test, y_test = X[~idx], y[~idx]
- noise = permute_features(X_sub, noise_dim, random_state=rng)
- X_aug = np.hstack([X_sub, noise])
- X_test_aug = np.hstack([X_test, noise])
- for reg in reg_strengths:
- model = AtlasLinearModel(lr=0.1, C=y.max()+1)
- model.fit(X_aug, y_sub, early_stop_acc=0.8)
- # Get balanced test accuracy
- y_pred = model.predict(torch.tensor(X_test_aug, dtype=torch.float32).cuda())
- # Get overall test accuracy
- acc = (y_pred == y_test).mean()
- class_accuracies = []
- for c in np.unique(y_test):
- mask = y_test == c
- if mask.sum() > 0: # Only calculate if class exists in test set
- class_acc = (y_pred[mask] == y_test[mask]).mean()
- class_accuracies.append(class_acc)
- balanced_acc = np.mean(class_accuracies)
- balanced_accs.append(balanced_acc)
- accs.append(acc)
- weights = model.coef_ # shape: (total_features,)
- weights = weights.detach().cpu().numpy()
- all_weights.append(weights)
- max_noise_weight = np.max(weights[:, -noise_dim:], axis=-1)
- weight_threshold = max_noise_weight * 1.1
- selected = (weights > weight_threshold[:, None]).astype(float)
- stability += selected
- stability /= (num_runs * len(reg_strengths))
- print("Accuracy: ", np.mean(accs))
- print("Balanced Accuracy: ", np.mean(balanced_accs))
- return stability, all_weights
- y = np.array(y)
- stability, all_weights_specific = feature_stability_with_noise(X, y, 200, subsample_ratio=0.5, reg_strengths=[0], noise_dim=50)
- import joblib
- # # Save stability and weights
- # joblib.dump(stability, 'stability.joblib')
- # joblib.dump(all_weights_specific, 'all_weights_specific.joblib')
- # %%
- from collections import defaultdict
- shared_counter = defaultdict(int)
- categories = defaultdict(list)
- mzs_per_category = defaultdict(list)
- weight = {}
- for category_index in range(stability.shape[0]):
- for i in range(stability.shape[1]):
- if stability[category_index, i] > 0.95:
- shared_counter[extraction_mzs[i]] += 1
- categories[extraction_mzs[i]].append(category_index)
- weight[extraction_mzs[i]] = float(np.array(all_weights_specific)[:, category_index, i].mean())
- mzs_per_category[category_index].append((extraction_mzs[i], weight[extraction_mzs[i]]))
- category_index = 102
- shared_mzs = []
- specific_mzs = []
- specific_indices = []
- shared_indices = []
- for i in range(stability.shape[1] -50):
- weight[extraction_mzs[i]] = float(np.array(all_weights_specific)[:, category_index, i].mean())
- if stability[category_index, i] > 0.95:
- specific_indices.append(i)
- specific_mzs.append(extraction_mzs[i])
- weight[extraction_mzs[i]] = float(np.array(all_weights_specific)[:, category_index, i].mean())
- elif stability[category_index, i] > 0.5:
- shared_indices.append(i)
- shared_mzs.append(extraction_mzs[i])
- print(specific_mzs)
- mzs_per_category_with_model = {}
- for category in mzs_per_category:
- mzs_per_category_with_model[category] = [x[0] for x in sorted(mzs_per_category[category], key=lambda x: x[1], reverse=True)]
- # %%
- import pandas as pd
- from collections import defaultdict
- model_mzs_and_stabilities = {"category": []}
- for i in range(200):
- model_mzs_and_stabilities[f"mz_{i}"] = []
- model_mzs_and_stabilities[f"stability_{i}"] = []
- frequencies = stability[:, :-50]
- mzs_per_category_with_model_80 = defaultdict(list)
- mzs_per_category_with_model_100 = defaultdict(list)
- for category_index in range(frequencies.shape[0]):
- sorted_indices = np.argsort(frequencies[category_index])[::-1]
- mzs = [extraction_mzs[i] for i in sorted_indices]
- category_stabilities = frequencies[category_index, sorted_indices]
- model_mzs_and_stabilities["category"].append(label_encoder.classes_[category_index])
- for i, (mz, f) in enumerate(zip(mzs[:200], category_stabilities[:200])):
- model_mzs_and_stabilities[f"mz_{i}"].append(mz)
- model_mzs_and_stabilities[f"stability_{i}"].append(f)
- if f > 0.8:
- mzs_per_category_with_model_80[label_encoder.classes_[category_index]].append(mz)
- if f == 1.0:
- mzs_per_category_with_model_100[label_encoder.classes_[category_index]].append(mz)
- model_mzs_and_stabilities = pd.DataFrame(model_mzs_and_stabilities)
- model_mzs_and_stabilities.to_csv("model_mzs_and_stabilities.csv", index=False)
- # %%
- print([str(a) for a in list(label_encoder.inverse_transform(categories[1179.73081311]))])
- print([str(a) for a in list(label_encoder.inverse_transform(categories[1207.75938587]))])
- print([str(a) for a in list(label_encoder.inverse_transform(categories[808.12340284]))])
- label_encoder.transform(["BG_ARTEFACT_ARTEFACT"])
- sorted_counter = sorted(shared_counter.items(), key=lambda x: x[1], reverse=True)
- print(sorted_counter)
- # %%
- mzs = joblib.load("/home/jacob/Desktop/auc_mzs.joblib")
- auc_mzs_per_category = {}
- for category, category_name in enumerate(label_encoder.classes_):
- auc_mzs_per_category[category] = mzs["unique"][category_name] + mzs["common"][category_name]
- auc_mzs_per_category[category] = [x[0] for x in sorted(auc_mzs_per_category[category], key=lambda x: x[1], reverse=True)]
- #auc_mzs_per_category[102]
- # %%
- import pandas as pd
- # Create empty DataFrame with 50 columns
- df = pd.DataFrame(index=label_encoder.classes_, columns=range(250))
- # Fill DataFrame with m/z values for each category
- for category in auc_mzs_per_category:
- category_name = label_encoder.classes_[category]
- mzs = [x for x in auc_mzs_per_category[category][:250]] # Get top 50 m/z values
- # Pad with NaN if less than 50 m/z values
- mzs.extend([float('nan')] * (250 - len(mzs)))
- df.loc[category_name] = mzs
- # Save to CSV
- df.to_csv('MZ_AUC.csv')
- # Create empty DataFrame with 50 columns
- df = pd.DataFrame(index=label_encoder.classes_, columns=range(250))
- # Fill DataFrame with m/z values for each category
- for category in mzs_per_category:
- category_name = label_encoder.classes_[category]
- mzs = mzs_per_category_with_model[category][:250] # Get top 50 m/z values
- # Pad with NaN if less than 50 m/z values
- mzs.extend([float('nan')] * (250 - len(mzs)))
- df.loc[category_name] = mzs
- # Save to CSV
- df.to_csv('MZ_MODEL_TIC.csv')
- # %%
- from venn import venn
- from matplotlib import pyplot as plt
- %matplotlib inline
- parent_categories = list(set([name.split("_")[0].replace("#", '') for name in label_encoder.classes_]))
- mzs_per_parent = defaultdict(list)
- for category in mzs_per_category_with_model_80:
- parent = category.split("_")[0].replace("#", '')
- mzs = mzs_per_category_with_model_80[category]
- mzs = [mz for mz in mzs if mz not in auc_mzs_per_category[0]]
- mzs_per_parent[parent].extend(mzs)
- # Convert lists to sets for each parent category
- mz_sets = {parent: set(mzs) for parent, mzs in mzs_per_parent.items() if parent in ['BST', 'CNU', 'CTX', 'WM']}
- venn(mz_sets)
- plt.rcParams.update({'font.size': 10}) # Increase font size for all text elements
- plt.title("Venn diagram for m/z values identified by the model", y=-0.1)
- # %%
- from venn import venn
- from matplotlib import pyplot as plt
- %matplotlib inline
- parent_categories = list(set([name.split("_")[0].replace("#", '') for name in label_encoder.classes_]))
- mzs_per_parent = defaultdict(list)
- for category in auc_mzs_per_category:
- parent = label_encoder.classes_[category].split("_")[0].replace("#", '')
- mzs = auc_mzs_per_category[category]
- mzs = [mz for mz in mzs if mz not in auc_mzs_per_category[0]]
- mzs_per_parent[parent].extend(mzs)
- # Convert lists to sets for each parent category
- mz_sets = {parent: set(mzs) for parent, mzs in mzs_per_parent.items() if parent in ['BST', 'CNU', 'CTX', 'WM']}
- venn(mz_sets)
- plt.title("Venn diagram for m/z values identified by mPAUC")
- # %%
- # Count occurrences of each m/z value across all parent categories
- mz_counts = defaultdict(list)
- for parent, mzs in mzs_per_parent.items():
- if parent == 'BG':
- continue
- for mz in set(mzs):
- mz_counts[mz].append(parent)
- # Sort by number of occurrences (most frequent first)
- sorted_mzs = sorted(mz_counts.items(), key=lambda x: len(x[1]), reverse=True)
- print("Most common m/z values and their parent categories:")
- for mz, parents in sorted_mzs[:150]: # Show top 20
- print(f"m/z {mz:.5f} {', '.join(parents)}")
- # %%
- joblib.dump({"stability": stability, "all_weights_specific": all_weights_specific, "label_encoder": label_encoder}, "spatial_tic_model.joblib")
- # %%
- # Count category frequencies for m/z values in category 102
- category_counts = defaultdict(int)
- for mz in auc_mzs_per_category[102]:
- found = False
- # Find all categories this m/z appears in
- for cat_idx, mzs in auc_mzs_per_category.items():
- if mz in mzs and cat_idx != 102: # Exclude self-comparison
- cat_name = label_encoder.classes_[cat_idx].replace("_ARTEFACT", "")
- category_counts[cat_name] += 1
- found = True
- if not found:
- category_counts["unique"] += 1
- # Get top 10 categories by frequency
- top_10_categories = dict(sorted(category_counts.items(), key=lambda x: x[1], reverse=True)[:10])
- # Create pie chart
- plt.figure(figsize=(20, 20), dpi=200)
- plt.rcParams.update({'font.size': 30}) # Increase font size for all text elements
- plt.pie(top_10_categories.values(), labels=top_10_categories.keys(), autopct='%5.1f%%')
- plt.title(f"Frequencies of m/z's shared with other categories for {label_encoder.classes_[102].replace('_ARTEFACT', '')}", y=-0.1)
- plt.axis('equal')
- plt.show()
- # %%
- # Count category frequencies for m/z values in category 102
- category_counts = defaultdict(int)
- for mz in mzs_per_category_with_model_80[label_encoder.classes_[102]]:
- found = False
- # Find all categories this m/z appears in
- for cat_name, mzs in mzs_per_category_with_model_80.items():
- if mz in mzs and cat_name != label_encoder.classes_[102]: # Exclude self-comparison
- cat_name = cat_name.replace("_ARTEFACT", "")
- category_counts[cat_name] += 1
- found = True
- if not found:
- category_counts["unique"] += 1
- # Get top 10 categories by frequency
- top_10_categories = dict(sorted(category_counts.items(), key=lambda x: x[1], reverse=True)[:10])
- # Create pie chart
- plt.figure(figsize=(10, 10))
- plt.pie(top_10_categories.values(), labels=top_10_categories.keys(), autopct='%1.1f%%', textprops={'fontsize': 14})
- plt.title(f"Frequencies of m/z's shared with other categories for {label_encoder.classes_[102].replace('_ARTEFACT', '')} (Top 10)\nTIC model mapping")
- plt.axis('equal')
- plt.show()
- # %%
- import cv2
- from PIL import Image
- def get_ihc_image(img, mzs, category, intensity=None):
- indices = [extraction_mzs.index(float(mz)) for mz in mzs]
- mask = img.max(axis=-1)
- img = img / np.max(img, axis=(0, 1))
- ion = img[:, :, indices].mean(axis=-1)
- if intensity is None:
- ion = ion / ion.max()
- else:
- ion = ion / intensity
- ion = ion / np.percentile(ion, 99.7)
- ion[ion > 1] = 1
- # Apply non-linear stretching to emphasize larger values
- # Using power function with exponent < 1 to compress lower values and stretch higher ones
- ion = np.power(ion, 2) # Adjust exponent as needed (smaller = more stretching)
- ion = np.uint8((ion / ion.max()) * 255) # Rescale back to 0-255 range
- #ion = np.uint8(ion* 255) # Rescale back to 0-255 range
- #display(Image.fromarray(ion))
- # Convert grayscale to RGB IHC-like coloring
- # Create RGB image with brown for high values and light pink for low values
- rgb = np.zeros((ion.shape[0], ion.shape[1], 3), dtype=np.uint8)
- # Brown color (RGB: 139, 69, 19) for high values
- # Light pink (RGB: 255, 228, 225) for low values
- rgb[:,:,0] = np.uint8(255 - ion * 0.45) # R channel
- rgb[:,:,1] = np.uint8(228 - ion * 0.62) # G channel
- rgb[:,:,2] = np.uint8(225 - ion * 0.81) # B channel
- # Create a colormap from white to brown
- white = np.array([255, 255, 255])
- brown = np.array([139, 69, 19])
- # Create normalized intensity values between 0 and 1
- norm_ion = ion.astype(float) / 255
- # For each pixel, interpolate between white and brown based on intensity
- for i in range(3): # RGB channels
- rgb[:,:,i] = np.uint8(white[i] + (brown[i] - white[i]) * norm_ion)
- rgb[mask == 0] = 0
- # This creates a brownish-purple tone typical of IHC staining
- ion = rgb
- # Add text overlay with category name
- font = cv2.FONT_HERSHEY_SIMPLEX
- font_scale = 0.8
- font_color = (255, 50, 60) # White text
- font_thickness = 2
- text_size = cv2.getTextSize(category, font, font_scale, font_thickness)[0] * 2
- # Position text at top center
- ##text_x = (ion.shape[1]) // 2
- text_x = 10
- text_y = text_size[1] + 10 # Add some padding from top
- # Rotate image 90 degrees counterclockwise
- ion = cv2.rotate(ion, cv2.ROTATE_90_COUNTERCLOCKWISE)
- ion_no_text = ion.copy()
- # Add text to image
- category = category.replace("_ARTEFACT", "")
- cv2.putText(ion, category, (text_x, text_y), font, font_scale, font_color, font_thickness)
- return ion, ion_no_text
- # %%
- import json
- categories_per_mz = defaultdict(list)
- for mz in mzs_per_category_with_model[102]:
- for cat_idx, mzs in mzs_per_category_with_model.items():
- if mz in mzs and cat_idx != 102: # Exclude self-comparison
- cat_name = label_encoder.classes_[cat_idx].replace("_ARTEFACT", "")
- categories_per_mz[mz].append(cat_name)
- # Create folder for this m/z value if it doesn't exist
- mz_folder = f"mz_{mz:.4f}"
- for path in paths:
- img = total_ion_count(np.load(path[0]))
- _, ion_no_text = get_ihc_image(img, [mz], '')
- Image.fromarray(ion_no_text).save(f"{mz_folder}_{path[1]}.png")
- # Save categories per m/z as JSON
- with open(f"categories.json", "w") as f:
- json.dump(categories_per_mz, f, indent=4)
- # %%
- import pandas as pd
- csv = pd.read_csv("MZ_MODEL_TIC.csv")
- # %%
- cnu_mzs = mzs_per_parent['CNU']
- cnu_mzs = [x for x in cnu_mzs if x not in mzs_per_parent['BST']]
- cnu_mzs = [x for x in cnu_mzs if x not in mzs_per_parent['CTX']]
- cnu_mzs = [x for x in cnu_mzs if x not in mzs_per_parent['WM']]
- cnu_mzs = [x for x in cnu_mzs if x not in mzs_per_parent['BG']]
- print(cnu_mzs)
- # %%
linear.ipynb at commit de9d453, under MIT · at the source
Overview
- Pahnke Lab, www.pahnkelab.eu
- Proteomics Core Facility, Department of Immunology, Department of Clinical Medicine (KlinMed), Medical Faculty, University of Oslo (UiO) and Division of Laboratory Medicine (KLM), Oslo University Hospital (OUS), Oslo, Norway
- Translational Neurodegeneration Research and Neuropathology Lab, Department of Clinical Medicine, Medical Faculty, University of Oslo, Oslo, Norway
- Section of Neuropathology Research, Department of Pathology, Division of Laboratory Medicine, Oslo University Hospital, Oslo, Norway
- Institute of Nutritional Medicine, University of Lübeck and University Medical Center Schleswig-Holstein, Lübeck, Germany
- Department of Neuromedicine and Neuroscience, The Faculty of Medicine and Life Sciences, University of Latvia, Rīga, Latvia
- Department of Neurobiology, School of Neurobiology, Biochemistry and Biophysics, The Georg S. Wise Faculty of Life Sciences, University of Tel Aviv, Ramat Aviv, Israel
Abstract
Recent computational advances in mass spectrometry imaging (MSI) now enable unprecedented insight into organ-wide molecular composition and functional architecture. Here, we present the first high-resolution molecular-computational atlas of specific mouse brain lipids and metabolites, acquired using a NEDC matrix and negative-mode MSI, covering 123 anatomically defined regions and 191 polygonal annotations derived solely from MSI data, without auxiliary imaging. To overcome annotation ambiguity and MSI complexity, we introduced the Computational Brain Lipid Atlas (CBLA), a graph-based visual-explainability framework that generates Virtual Landscape Visualizations (VLVs) of specific lipid distributions across brain substructures. The CBLA integrates dimensionality reduction and ensembles of supervised models to (i) refine annotations, (ii) elucidate interregional relationships, (iii) interpret model behavior, and (iv) formulate biologically testable hypotheses. The CBLA revealed novel lipid distribution patterns, functional integrations, anatomical connections – the brain's telephone cables, and region-specific disease signatures – index lipids, including disease networks in the basal ganglia. It further identified index lipids that trace extrapyramidal nuclei and their cortical-brainstem connections, highlighting network-level molecular organization. A new algorithm decomposes annotated regions into precise mass-to-charge (m/
Reproduced under the paper's license (CC BY), from the paper cited above.
Repository
Its files are read in the Code ↔ Paper reader above, with 4 matches between paragraphs and lines of code.
jacobgil/msi-atlas
de9d453840f91e8383052ada42322e99547bd95e, 23 May 2025Availability: 1 check, the latest on 30 September 2026: the link answers
- 30 September 2026: the link answers
7 files
- msi_atlas/
annotations.py , Python, 155 lines - msi_atlas/
atlas.py , Python, 308 lines - msi_atlas/
atlas_linear_model.py , Python, 147 lines, 1 match - msi_atlas/
mapping.py , Python, 84 lines, 1 match - notebooks/
linear.ipynb , Jupyter, 494 lines, 2 matches - LICENSE, License, 21 lines
- README.md, Text, 53 lines
Availability of code
Code is available as an open-source package on GitHub. https://
Reproduced under the paper's license (CC BY), from the paper cited above.
Tracing map
Proposed by the machine: these links were found in the paper and verified at the source, without human review. The map will receive a Zenodo DOI once one of the paper's authors has validated it with their ORCID.
What the map holds:
- 1 repository of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
- 5 scripts, each with its path and the digest of its content;
- 4 matches between paragraphs of the paper and lines of the code (method lexical-v1);
- neither the text of the paper nor the code itself.
Its JSON (tracing-map.json) is deposited on Zenodo with its DOI once the map is validated.
Data
No dataset and no data link were found in the paper.
Availability of data and material
The datasets generated and analyzed during the current study are available in the ProteomeXchange PRIDE repository under accession number PXD056609.
Reproduced under the paper's license (CC BY), from the paper cited above.
Versions
The history of this record: each version stored by the harvester or made by a correction of its authors or of the maintainers of its code, and what changed in its facts. The texts of the paper (its abstract, its availability statements) are not part of it; versions that changed only those are not listed.
Version 1, 30 September 2026: the first record
Recorded: type, language, journal, volume, pages, dates, 3 authors, 14 keywords, 43 references.
Cite
This paper
Gildenblat, J., Stamnas, J., & Pahnke, J. (2026). Mass spectrometry imaging-based explainable machine learning reveals the biochemical landscapes of the mouse brain. Free neuropathology, 7, 9. https://
BibTeX
@article{gildenblat2026m
author = {Gildenblat, Jacob and Stamnas, Jorunn and Pahnke, Jens},
title = {{Mass spectrometry imaging-based explainable machine learning reveals the biochemical landscapes of the mouse brain}},
journal = {Free neuropathology},
year = {2026},
month = apr,
volume = {7},
pages = {9},
publisher = {Free Neuropathology General Assembly},
issn = {2699-4445},
doi = {10.17879/
url = {https://
pmid = {42078793},
pmcid = {PMC13129809}
}
RIS
TY - JOUR
AU - Gildenblat, Jacob
AU - Stamnas, Jorunn
AU - Pahnke, Jens
TI - Mass spectrometry imaging-based explainable machine learning reveals the biochemical landscapes of the mouse brain
T2 - Free neuropathology
J2 - Free Neuropathol
PY - 2026
DA - 2026/
VL - 7
SP - 9
SN - 2699-4445
PB - Free Neuropathology General Assembly
DO - 10.17879/
UR - https://
LA - en
ER -
CSL-JSON
{
"id": "10.17879/
"type": "article-journal",
"title": "Mass spectrometry imaging-based explainable machine learning reveals the biochemical landscapes of the mouse brain",
"container-title": "Free neuropathology",
"author": [
{
"family": "Gildenblat",
"given": "Jacob"
},
{
"family": "Stamnas",
"given": "Jorunn"
},
{
"family": "Pahnke",
"given": "Jens"
}
],
"container-title-short":
"volume": "7",
"page": "9",
"DOI": "10.17879/
"PMID": "42078793",
"PMCID": "PMC13129809",
"ISSN": "2699-4445",
"publisher": "Free Neuropathology General Assembly",
"URL": "https://
"language": "en",
"issued": {
"date-parts": [
[
2026,
4,
28
]
]
}
}
The tracing map gets a citation of its own once an author has validated it and it has a DOI.
Similar papers
The papers with a page that share the most with this one: the tools found in their code, their categories, datasets, cited references and authors, the rarest counting most.
- [1] doi:10.1126/sciadv.aed3650 [code]
- Truthful visualizations for mass spectrometry imaging enable high-spatial-resolution interactive &
lt;i& gt;m/ z& lt;/ i& gt; mapping and exploration. Journal: Science advancesIn common: NetworkX, OpenCV, Pillow, 5 other tools, other, methods / tools, genetics / omics, 1 other category, 13 references, 2 authors - [2] doi:10.1371/journal.pcbi.1013499 [code]
- VesiclePy: A machine learning vesicle analysis toolbox for volume electron microscopy.Journal: PLoS computational biologyIn common: Pyro, OpenCV, Pillow, 5 other tools, methods / tools
- [3] doi:10.1038/s41598-026-57519-w [code]
- Automated segmentation of neurons and spinal cord structures in immunofluorescence images using SpineDL.Journal: Scientific reportsIn common: NetworkX, OpenCV, Pillow, 5 other tools, methods / tools, mouse
- [4] doi:10.1038/s41598-026-61605-4 [code]
- Learning precise segmentation of neurofibrillary tangles from rapid manual point annotations.Journal: Scientific reportsIn common: OpenCV, Pillow, PyTorch, 4 other tools, methods / tools, Alzheimer's / dementia, 1 reference
- [5] doi:10.1038/s42003-026-10259-z [code]
- Spatial transcriptomic profiling of developing mouse hearts reveals a spatially patterned signaling environment.Journal: Communications biologyIn common: Pyro, OpenCV, PyTorch, 4 other tools, genetics / omics, mouse
- [6] doi:10.1016/j.isci.2026.116825 [code]
- Social hierarchy shapes behavioral and transcriptional responses to chronic stress and ketamine in male mice.Journal: iScienceIn common: NetworkX, OpenCV, Pillow, 5 other tools, genetics / omics, mouse
- [7] doi:10.1093/bioinformatics/btag652 [code]
- mmVelo: a deep generative model for estimating cell state-dependent dynamics across multiple modalities.Journal: Bioinformatics (Oxford, England)In common: Pyro, Pillow, PyTorch, 4 other tools, genetics / omics, mouse
- [8] doi:10.1002/hbm.70469 [code]
- VarCoNet: A Variability-Aware Self-Supervised Framework for Functional Connectome Extraction From Resting-State fMRI.Journal: Human brain mappingIn common: NetworkX, OpenCV, Pillow, 5 other tools, methods / tools
- [9] doi:10.1038/s41398-026-03965-z [code]
- Disentangling individual heterogeneity reveals robust network and molecular signatures of major depressive disorder with suicidal ideation.Journal: Translational psychiatryIn common: NetworkX, OpenCV, Pillow, 5 other tools, genetics / omics
- [10] doi:10.1038/s42003-026-10957-8 [code]
- Brain defence by the extracellular matrix protein Cochlin.Journal: Communications biologyIn common: NetworkX, OpenCV, Pillow, 5 other tools, mouse
Contribute
The authors of this paper can claim it, correct its record and validate its tracing map, and the maintainers of its code (its owner, or a public member of its organization) correct what it says of their repository; anyone signed in can ask for its removal. Every request goes to OSCR's own machine, which answers it; your account page follows them.
Sign in with ORCID to claim this paper as one of its authors, correct its record or validate its tracing map: when the paper's metadata lists your ORCID iD, you are recognized at once. Maintainers of its code: sign in with GitHub, then claim the repository on your account page.
Claim this paper
Correct its record
Say what each link of this record is, remove the ones that are not the paper's, add the ones that are missing. The correction becomes a new version of the record, in its Versions section.
Validate its tracing map
You validate the map as this page shows it: 1 repository of the authors' code, each at its verified commit and with its license, 5 scripts, and 4 matches between paragraphs and code (see the Code and Map sections). It then receives a DOI on Zenodo, with you (your ORCID iD) and OSCR as its creators; the code itself is not deposited.
The map's fingerprint: sha256:6de8e228a8eab468…
Add the badge to its README
The badge links the code to this page. Copy one of these into the README of the paper's code: only you decide where it goes, and nothing is changed for you.
Markdown
[, paste the snippet at the top, then “Commit changes…” and, to review it first, “Create a new branch and start a pull request”. You open the pull request; OSCR asks for no permission.
Request its removal
To ask OSCR to remove this record, the copies of its authors' scripts or its tracing map, use the removal request page: signed in, you say who you are, what to remove and why, then review and confirm the request. Published rules decide every request (how).
Discussion, reproductions, activity
Discussion: questions and error reports about this paper and its code, from signed-in readers and its authors. It opens with sign-in.
Reproductions: reports from readers who ran the authors' code: what they reproduced, with which environment, commit and data. It opens with sign-in.
Activity: what happens around this paper: new versions of its record, its map's validation, discussions and reproductions. It opens with sign-in.
