Critical point drying of brain tissue for X-ray phase-contrast imaging.
Paper
Loaded from Europe PMC by your browser; OSCR does not store it: doi.org · Europe PMC
The paper is loaded when this pane is shown.
The authors' code
Jupyter notebook · 221 lines · 6.8 KB · MIT
- # %% [markdown]
- # # ID16A Line-Profile Processing (Example)
- #
- # This notebook demonstrates the workflow for a **single** ID16A dataset (one CSV):
- # 1. Plot the **raw** line profiles.
- # 2. Compute and apply a **baseline correction** using specified baseline windows.
- # 3. Plot the **averaged corrected** line profile with ±1 standard deviation.
- # 4. Export the averaged profile + std to CSV.
- #
- # - Column 0: distance in **pixels** → converted to µm using `0.100 µm/pixel`.
- # - Intensity columns: every other column starting from column 1.
- # %%
- import os
- import numpy as np
- import pandas as pd
- import matplotlib.pyplot as plt
- from matplotlib.ticker import ScalarFormatter
- # ==== Parameters ====
- FILE_PATH = "data/ID16A/ID16A_Epon_lineprofiles_SK186_p2_n100.csv" # <-- set this to one CSV file
- PIXELS_TO_UM = 0.100 # µm per pixel for ID16A (100 nm)
- SAVE_FIGS = True
- FIG_DPI = 300
- EPS = 1e-12 # small number to avoid division-by-zero if ever needed
- # %%
- # defaults
- plt.rcParams.update({
- "font.size": 14,
- "xtick.direction": "in",
- "ytick.direction": "in",
- "xtick.top": True,
- "ytick.right": True,
- "axes.linewidth": 1.5,
- "figure.dpi": 150
- })
- # %%
- def safe_read_csv(file_path):
- """Safely read a CSV file with basic error handling."""
- if not os.path.exists(file_path):
- raise FileNotFoundError(f"File not found: {file_path}")
- return pd.read_csv(file_path, header=None, low_memory=False)
- def build_baseline_mask(dist_um):
- """Return a boolean mask for baseline regions with fixed windows in µm."""
- baseline_windows_um = [(0, 1.8), (6.2, 8)]
- mask = np.zeros_like(dist_um, dtype=bool)
- for lo, hi in baseline_windows_um:
- mask |= (dist_um >= lo) & (dist_um <= hi)
- return mask
- def extract_profiles(df, pixels_to_um=0.100):
- """
- From a raw dataframe:
- - Convert the first column (pixels) -> distance in µm
- - Take every other column starting at col 1 as profiles
- - Multiply profiles by conversion factor to match P14 units (rad/voxel)
- Returns: dist_um (N,), profiles (N, M) in P14 units
- """
- dist_um = df.iloc[:, 0].to_numpy(dtype=float) * pixels_to_um
- profiles = df.iloc[:, 1::2].to_numpy(dtype=float)
- # --- Conversion factor (per cm → rad/voxel as in P14 units) [see text below]---
- conversion_factor = 0.512 * 0.325 * 1e-4
- profiles = profiles * conversion_factor
- return dist_um, profiles
- def baseline_correct_profiles(dist_um, profiles):
- """
- Subtract per-profile baseline mean using fixed windows:
- - 0 → 1.8 µm
- - 6.2 → 8 µm
- Returns: corrected_profiles (N, M), baseline_means (M,)
- """
- base_mask = build_baseline_mask(dist_um)
- corrected = np.empty_like(profiles)
- baseline_means = np.empty(profiles.shape[1])
- for i in range(profiles.shape[1]):
- base_mean = np.mean(profiles[base_mask, i])
- baseline_means[i] = base_mean
- corrected[:, i] = profiles[:, i] - base_mean
- return corrected, baseline_means
- def compute_avg_and_std(corrected_profiles):
- """Compute mean and std across profiles (axis=1)."""
- mean_profile = np.mean(corrected_profiles, axis=1)
- std_profile = np.std(corrected_profiles, axis=1, ddof=0)
- return mean_profile, std_profile
- # %% [markdown]
- # ### Unit Conversion (ID16A → P14)
- #
- # At ID16A, the holotomographic reconstruction provides values as:
- #
- # $$
- # \omega = - \frac{2\pi}{\lambda} \, \delta
- # $$
- #
- # in units of **cm$^{-1}$**.
- #
- # To compare directly with P14 (which reports in **rad/voxel**), each line profile
- # is multiplied by the conversion factor:
- #
- # $$
- # \text{factor} = 0.512 \times 0.325 \times 10^{-4}
- # $$
- #
- # where 0.512 arrises from the the ratio of the X-ray wavelength (energies) at P14 to ID16A, and 0.325 $\times 10^{-4}$ is the pixel size at P14 in per cm units.
- #
- # This converts ID16A values into the same effective units as P14.
- # %%
- df = safe_read_csv(FILE_PATH)
- dist_um, profiles = extract_profiles(df, pixels_to_um=PIXELS_TO_UM)
- print(f"Loaded: {FILE_PATH}")
- print(f"Distance array length: {dist_um.size}, profiles shape: {profiles.shape}")
- # %%
- fig, ax = plt.subplots(figsize=(7, 5))
- for i in range(profiles.shape[1]):
- ax.plot(dist_um, profiles[:, i], alpha=0.3, linewidth=1)
- ax.axhline(0, linestyle='--', linewidth=1)
- ax.set_xlabel("Distance (µm)")
- ax.set_ylabel("relative phase-shift (rad/voxel) [raw signal]")
- ax.set_xlim(0, 8)
- ax.set_ylim(-1e-2, 1e-3)
- # Force scientific notation on y-axis if needed
- fmt = ScalarFormatter(useMathText=True)
- fmt.set_scientific(True)
- fmt.set_powerlimits((0, 0))
- ax.yaxis.set_major_formatter(fmt)
- ax.tick_params(axis='both', length=6, width=1.5)
- for spine in ax.spines.values():
- spine.set_linewidth(1.5)
- plt.tight_layout()
- if SAVE_FIGS:
- plt.savefig("ID16A_raw_profiles.svg", format='svg', dpi=FIG_DPI, bbox_inches='tight')
- plt.show()
- # %%
- corrected_profiles, baseline_means = baseline_correct_profiles(dist_um, profiles)
- print(f"Computed baseline means for {profiles.shape[1]} profiles. "
- f"Example (first 5): {baseline_means[:5]}")
- # %%
- fig, ax = plt.subplots(figsize=(7, 5))
- for i in range(corrected_profiles.shape[1]):
- ax.plot(dist_um, corrected_profiles[:, i], alpha=0.3, linewidth=1)
- ax.axhline(0, linestyle='--', linewidth=1)
- ax.set_xlabel("Distance (µm)")
- ax.set_ylabel("Corrected phase-shift (rad/voxel)")
- ax.set_xlim(0, 8)
- ax.set_ylim(-1e-2, 1e-3)
- fmt = ScalarFormatter(useMathText=True)
- fmt.set_scientific(True)
- fmt.set_powerlimits((0, 0))
- ax.yaxis.set_major_formatter(fmt)
- ax.tick_params(axis='both', length=6, width=1.5)
- for spine in ax.spines.values():
- spine.set_linewidth(1.5)
- plt.tight_layout()
- if SAVE_FIGS:
- plt.savefig("ID16A_corrected_profiles.svg", format='svg', dpi=FIG_DPI, bbox_inches='tight')
- plt.show()
- # %%
- mean_profile, std_profile = compute_avg_and_std(corrected_profiles)
- fig, ax = plt.subplots(figsize=(7, 5))
- ax.plot(dist_um, mean_profile, linewidth=2, label='Mean profile')
- ax.fill_between(dist_um, mean_profile - std_profile, mean_profile + std_profile,
- alpha=0.15, label='±1σ')
- ax.axhline(0, linestyle='--', linewidth=1)
- ax.set_xlabel("Distance (µm)")
- ax.set_ylabel("Corrected phase-shift (rad/voxel)")
- ax.set_xlim(0, 8)
- ax.set_ylim(-1e-2, 1e-3)
- fmt = ScalarFormatter(useMathText=True)
- fmt.set_scientific(True)
- fmt.set_powerlimits((0, 0))
- ax.yaxis.set_major_formatter(fmt)
- ax.legend(frameon=False)
- ax.tick_params(axis='both', length=6, width=1.5)
- for spine in ax.spines.values():
- spine.set_linewidth(1.5)
- plt.tight_layout()
- if SAVE_FIGS:
- plt.savefig("ID16A_corrected_mean_with_std.svg", format='svg', dpi=FIG_DPI, bbox_inches='tight')
- plt.show()
- # %%
- export_df = pd.DataFrame({
- 'Distance (µm)': dist_um,
- 'Mean Corrected Profile': mean_profile,
- 'Standard Deviation': std_profile
- })
- out_csv = "ID16A_averaged_corrected_profile.csv"
- export_df.to_csv(out_csv, index=False)
- print(f"Saved: {out_csv}")
ID16A_Analysing_LineProfile_CPD-Paper.ipynb at commit 7087f77, under MIT · at the source
Overview
- Sensory Circuits and Neurotechnology Laboratory The Francis Crick Institute London United Kingdom
- European Molecular Biology Laboratory Hamburg Unit c/o DESY Hamburg Germany
- ESRF – The European Synchrotron, Grenoble, France
- Department of Bioengineering Imperial College London London United Kingdom
- Department of Materials Imperial College London London United Kingdom
- Department of Neuroscience, Physiology and Pharmacology University College London United Kingdom
Abstract
X-ray phase-contrast tomography can efficiently image brain tissue at subcellular resolution. However, current sample preparation methods are not optimized to exploit the full potential of X-ray contrast mechanisms. Here we propose to replace interstitial material by air to enhance X-ray phase contrast of the ultrastructural features. Critical point drying (CPD) of heavy-metal-stained mouse brain tissue produced samples with preserved ultrastructure, a nanofoam-like material that remains compatible with follow-up conventional resin embedding. Using two synchrotron-based setups, namely, a high-throughput microtomography beamline and a nanoscale holographic tomography beamline, we found that CPD samples consistently showed 2–4× stronger phase-shift signal than samples embedded in resin. CPD offers a versatile route for preparing tissue for subcellular and ultrastructural-resoluti
Reproduced under the paper's license (CC BY), from the paper cited above.
Repositories
Its files are read in the Code ↔ Paper reader above.
safekhan/CPDtissuesXray
7087f77b5bdf06a5074a5cd9bbf12e0427babade, 18 March 2026Availability: 1 check, the latest on 30 September 2026: the link answers
- 30 September 2026: the link answers
6 files
- notebooks/
ID16A_Analysing_LineProf , Jupyter, 221 linesile_CPD-Paper.ipynb - notebooks/
ID16A_reproduce_Supp_Fig , Jupyter, 122 lines_S6.ipynb - notebooks/
P14_Analysing_LineProfil , Jupyter, 214 linese_CPD-Paper.ipynb - notebooks/
P14_reproduce_Supp_Fig_S , Jupyter, 136 lines5.ipynb - LICENSE, License, 21 lines
- README.md, Text, 32 lines
Zenodo 17035301
Availability: 1 check, the latest on 30 September 2026: the link answers (HTTP 200)
- 30 September 2026: the link answers (HTTP 200)
6 files
- notebooks/
ID16A_Analysing_LineProf , Jupyter, 221 linesile_CPD-Paper.ipynb - notebooks/
ID16A_reproduce_Supp_Fig , Jupyter, 122 lines_S6.ipynb - notebooks/
P14_Analysing_LineProfil , Jupyter, 214 linese_CPD-Paper.ipynb - notebooks/
P14_reproduce_Supp_Fig_S , Jupyter, 136 lines5.ipynb - LICENSE, License, 21 lines
- README.md, Text, 29 lines
The paper's code and data availability statement is in the Data section.
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:
- 2 repositories of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
- 8 scripts, each with its path and the digest of its content;
- no match between paragraphs and code yet;
- 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.
Data availability
All 3D-reconstructed tomograms reported in this study and tables containing source data for all quantitative analyses are accessible through the associated code repository. Analysis code is available from https://
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, issue, pages, dates, 16 authors, 5 keywords, 5 MeSH terms, 8 funders, 23 references.
Cite
This paper
Khan, S., Albers, J., Vorobyev, A., Zhang, Y., Reichmann, J., Svetlove, A., De Marco, F., Denisova, K., Yang, Y., Seichepine, F., Douglas, J. O., Duke, E., Cloetens, P., Pacureanu, A., Schaefer, A. T., & Bosch, C. (2026). Critical point drying of brain tissue for X-ray phase-contrast imaging. Journal of synchrotron radiation, 33(Pt 3), 759-768. https://
BibTeX
@article{khan2026critica
author = {Khan, Safe and Albers, Jonas and Vorobyev, Artem and Zhang, Yuxin and Reichmann, Jakob and Svetlove, Angelika and De Marco, Fabio and Denisova, Ksenia and Yang, Yikai and Seichepine, Florent and Douglas, James O. and Duke, Elizabeth and Cloetens, Peter and Pacureanu, Alexandra and Schaefer, Andreas T. and Bosch, Carles},
title = {{Critical point drying of brain tissue for X-ray phase-contrast imaging}},
journal = {Journal of synchrotron radiation},
year = {2026},
month = mar,
volume = {33},
number = {Pt 3},
pages = {759--768},
publisher = {International Union of Crystallography},
issn = {0909-0495},
doi = {10.1107/
url = {https://
pmid = {41871047},
pmcid = {PMC13148618}
}
RIS
TY - JOUR
AU - Khan, Safe
AU - Albers, Jonas
AU - Vorobyev, Artem
AU - Zhang, Yuxin
AU - Reichmann, Jakob
AU - Svetlove, Angelika
AU - De Marco, Fabio
AU - Denisova, Ksenia
AU - Yang, Yikai
AU - Seichepine, Florent
AU - Douglas, James O.
AU - Duke, Elizabeth
AU - Cloetens, Peter
AU - Pacureanu, Alexandra
AU - Schaefer, Andreas T.
AU - Bosch, Carles
TI - Critical point drying of brain tissue for X-ray phase-contrast imaging
T2 - Journal of synchrotron radiation
J2 - J Synchrotron Radiat
PY - 2026
DA - 2026/
VL - 33
IS - Pt 3
SP - 759
EP - 768
SN - 0909-0495
PB - International Union of Crystallography
DO - 10.1107/
UR - https://
LA - en
ER -
CSL-JSON
{
"id": "10.1107/
"type": "article-journal",
"title": "Critical point drying of brain tissue for X-ray phase-contrast imaging",
"container-title": "Journal of synchrotron radiation",
"author": [
{
"family": "Khan",
"given": "Safe"
},
{
"family": "Albers",
"given": "Jonas"
},
{
"family": "Vorobyev",
"given": "Artem"
},
{
"family": "Zhang",
"given": "Yuxin"
},
{
"family": "Reichmann",
"given": "Jakob"
},
{
"family": "Svetlove",
"given": "Angelika"
},
{
"family": "De Marco",
"given": "Fabio"
},
{
"family": "Denisova",
"given": "Ksenia"
},
{
"family": "Yang",
"given": "Yikai"
},
{
"family": "Seichepine",
"given": "Florent"
},
{
"family": "Douglas",
"given": "James O."
},
{
"family": "Duke",
"given": "Elizabeth"
},
{
"family": "Cloetens",
"given": "Peter"
},
{
"family": "Pacureanu",
"given": "Alexandra"
},
{
"family": "Schaefer",
"given": "Andreas T."
},
{
"family": "Bosch",
"given": "Carles"
}
],
"container-title-short":
"volume": "33",
"issue": "Pt 3",
"page": "759-768",
"DOI": "10.1107/
"PMID": "41871047",
"PMCID": "PMC13148618",
"ISSN": "0909-0495",
"publisher": "International Union of Crystallography",
"URL": "https://
"language": "en",
"issued": {
"date-parts": [
[
2026,
3,
23
]
]
}
}
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.1364/boe.559263 [code]
- Scaling up X-ray holographic nanotomography for neuronal tissue imaging.Journal: Biomedical optics expressIn common: Matplotlib, NumPy, 7 references, 4 authors
- [2] doi:10.1038/s41592-025-02891-0 [code]
- Nondestructive X-ray tomography of brain tissue ultrastructure.Journal: Nature methodsIn common: mouse, 7 references, 4 authors
- [3] doi:10.1242/jcs.261953 [code]
- Synchrotron X-ray imaging of soft biological tissues - principles, applications and future prospects.Journal: Journal of cell scienceIn common: pandas, NumPy, 5 references, 3 authors
- [4] doi:10.3389/fcell.2022.880696 [code]
- Sample Preparation and Warping Accuracy for Correlative Multimodal Imaging in the Mouse Olfactory Bulb Using 2-Photon, Synchrotron X-Ray and Volume Electron Microscopy.Journal: Frontiers in cell and developmental biologyIn common: mouse, 4 references, 4 authors
- [5] doi:10.1101/2023.11.16.567403 [code]
- Non-destructive X-ray tomography of brain tissue ultrastructureJournal: bioRxiv (preprint)In common: 4 authors
- [6] doi:10.1111/bpa.70044 [code]
- 3D imaging of neuronal inclusions and protein aggregates in human neurodegeneration by multiscale x-ray phase-contrast tomography.Journal: Brain pathology (Zurich, Switzerland)In common: pandas, Matplotlib, NumPy, 5 references, author Jakob Reichmann
- [7] doi:10.1002/advs.202416879 [code]
- Synchrotron Radiation-Based Tomography of an Entire Mouse Brain with Sub-Micron Voxels: Augmenting Interactive Brain Atlases with Terabyte Data.Journal: Advanced science (Weinheim, Baden-Wurttemberg, Germany)In common: pandas, NumPy, mouse, 4 references
- [8] doi:10.1371/journal.pbio.3002837 [code]
- Functional networks of inhibitory neurons orchestrate synchrony in the hippocampus.Journal: PLoS biologyIn common: pandas, Matplotlib, NumPy, mouse, author Artem Vorobyev
- [9] doi:10.1101/2025.05.14.653752 [code]
- Mice discriminate odour source distance via sub-sniff temporal features of odour plumesJournal: bioRxiv (preprint)In common: pandas, Matplotlib, NumPy, mouse, author Andreas T. Schaefer
- [10] doi:10.1371/journal.pone.0297754 [code]
- Quantifying spectral information about source separation in multisource odour plumes.Journal: PloS oneIn common: pandas, Matplotlib, NumPy, mouse, author Andreas T. Schaefer
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: 2 repositories of the authors' code, each at its verified commit and with its license, 8 scripts, and 0 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:36f86d301860e47b…
Add the badge to the code's README
If you are an author or a maintainer of this paper's code, you can add this badge. It says what OSCR knows of the paper (its code, its validated tracing map) and links the code to this page. Paste one of these snippets under the README's title. Keep the two marks around it, so that the badge can be replaced in place and is never added twice. OSCR changes nothing in your repository.
Markdown
<!-- oscr-badge:start -->
[](https://openscicode.org/badge/doi/10.1107/s1600577526001402)
<!-- oscr-badge:end -->reStructuredText
.. oscr-badge:start
.. image:: https://openscicode.org/badge/doi/10.1107/s1600577526001402.svg
:target: https://openscicode.org/badge/doi/10.1107/s1600577526001402
:alt: OSCR
.. oscr-badge:endHTML
<!-- oscr-badge:start -->
<a href="https://openscicode.org/badge/doi/10.1107/s1600577526001402"><img src="https://openscicode.org/badge/doi/10.1107/s1600577526001402.svg" alt="OSCR"></a>
<!-- oscr-badge:end -->On GitHub, open the README, choose Edit (the pencil), paste the snippet under the title, then "Commit changes".
If you choose to, you can have the badge kept up to date for you, with oscr badge --write from the command line or with the GitHub Action in your repository's workflows. Every other form and option (a card, AsciiDoc, LaTeX, shields.io) is on the badge page.
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: code errors and mismatches between the code and the paper about this paper and its code, from readers and its authors, beside the paper and its tracing map.
Report a mismatch between the code and the paper · Report a code error (signed in)
Reproductions: reports from readers who ran the authors' code and did not get the paper's result, what they ran, with which environment, commit and data.
Report a reproduction failure (signed in)
Versions of its code: the releases of its code tied to a version of this paper (the preprint, the accepted manuscript, the version of record…), each with the tracing map versioned with it.
Activity: what happens around this paper: new versions of its record, its map's validation, discussions and reproductions. It opens with sign-in.
