This release is a pre-release and may not be stable for production use.
NiiVue Streamlit Component
A modern Streamlit component for visualizing neuroimaging data using NiiVue, built with TypeScript, Preact, and Vite.
🚀 Quick Start
Simple Installation & Usage
-
Install the component:
pip install --index-url https://test.pypi.org/simple/ --no-deps niivue-streamlit
-
Use in your Streamlit app:
import streamlit as st from niivue_component import niivue_viewer uploaded_file = st.file_uploader("Choose a NIFTI file", type=["nii", "nii.gz"]) if uploaded_file is not None: result = niivue_viewer( nifti_data=uploaded_file.getvalue(), filename=uploaded_file.name, height=700 ) # Handle click events if result: st.write(f"Clicked voxel: {result['voxel']}, Value: {result['value']}")
✨ Features
- 🎨 Two Component Modes:
StyledViewer: Full-featured viewer with interactive menu and controlsUnstyledCanvas: Minimal canvas-only viewer for embedding
- 🔄 Multiple View Modes:
- Axial, Coronal, Sagittal slices
- 3D render view
- Multiplanar view with render
- 📊 Advanced Capabilities:
- Multiple overlay images with custom colormaps
- Surface mesh rendering (FreeSurfer pial, white, inflated, GIfTI, STL, OBJ, etc.)
- Mesh overlays (curvature, thickness, annotations)
- Combined volume + mesh visualization
- Configurable display settings (crosshair, radiological convention, colorbar, interpolation)
- Bidirectional communication (click events from viewer to Python)
- DICOM support
📖 Advanced Usage
With Overlays
from niivue_component import niivue_viewer
result = niivue_viewer(
nifti_data=main_image_bytes,
filename="brain.nii.gz",
overlays=[
{
"data": overlay_bytes,
"name": "activation.nii.gz",
"colormap": "hot",
"opacity": 0.7
}
],
view_mode="multiplanar",
styled=True,
settings={
"crosshair": True,
"radiological": False,
"colorbar": True,
"interpolation": True
},
height=800
)
With Mesh Surfaces
from niivue_component import niivue_viewer
# Load a FreeSurfer surface mesh
mesh_data = open("lh.pial", "rb").read()
result = niivue_viewer(
meshes=[{
"data": mesh_data,
"name": "lh.pial",
}],
view_mode="3d",
height=700
)
Mesh with Overlays (Curvature, Thickness)
mesh_data = open("lh.pial", "rb").read()
thickness_data = open("lh.thickness", "rb").read()
result = niivue_viewer(
meshes=[{
"data": mesh_data,
"name": "lh.pial",
"overlays": [{
"data": thickness_data,
"name": "lh.thickness",
"colormap": "redyell",
"opacity": 0.7
}]
}],
view_mode="3d",
height=700
)
Volume with Mesh
# Display a volume image alongside a surface mesh
volume_data = open("brain.nii.gz", "rb").read()
mesh_data = open("lh.pial", "rb").read()
result = niivue_viewer(
nifti_data=volume_data,
filename="brain.nii.gz",
meshes=[{
"data": mesh_data,
"name": "lh.pial",
}],
view_mode="3d",
height=700
)
Minimal Viewer (No Menu)
# Perfect for embedding in complex layouts
result = niivue_viewer(
nifti_data=image_bytes,
filename="scan.nii",
styled=False, # Hide menu
view_mode="axial",
height=400
)
⚡ Performance
Because Streamlit re-runs the whole script whenever a component calls
Streamlit.setComponentValue, bidirectional click feedback from the viewer
can become a bottleneck: without care, every mouse event re-reads the file,
re-base64-encodes the NIfTI, and re-transmits it to the iframe. Three knobs
keep the viewer snappy:
@st.fragment— wrap the viewer plus the UI that consumes its return value in a fragment. Clicks re-run only the fragment, not the whole page. Seeapp_bidirectional.py.@st.cache_data— cachePath.read_bytes()so the same bytes aren't re-loaded on every re-run. The component wrapper also caches the base64 encoding internally, keyed on the bytes object's identity, so caching your loader transparently skips re-encoding too.update_interval_ms— controls the throttle on click events sent back to Python (default100ms). PassNoneto disable feedback entirely when the return value isn't used (e.g.app_simple.py,app_overlay.py,app_advanced.py).
Minimal template:
import streamlit as st
from niivue_component import niivue_viewer
from pathlib import Path
@st.cache_data
def load_nifti(path: str) -> bytes:
return Path(path).read_bytes()
image = load_nifti("brain.nii.gz")
@st.fragment
def viewer():
result = niivue_viewer(
nifti_data=image,
filename="brain.nii.gz",
key="viewer",
update_interval_ms=100, # or None to disable feedback
)
if result:
st.write(result)
viewer()
📚 API Reference
niivue_viewer()
Parameters:
nifti_data(bytes, optional): Raw NIFTI file datafilename(str): Displayed filenameoverlays(list[dict], optional): Overlay images listdata(bytes): Overlay dataname(str): Overlay namecolormap(str): Colormap (default: 'red')opacity(float): 0-1 (default: 0.5)
meshes(list[dict], optional): Mesh surfaces listdata(bytes): Mesh file dataname(str): Mesh filename (must include extension, e.g. 'lh.pial', 'brain.gii')overlays(list[dict], optional): Mesh overlays (curvature, thickness, etc.)data(bytes): Overlay dataname(str): Overlay filenamecolormap(str): Colormap (default: 'redyell')opacity(float): 0-1 (default: 0.7)
height(int): Height in pixels (default: 600)view_mode(str): 'axial', 'coronal', 'sagittal', '3d', 'multiplanar' (default)styled(bool): Show menu (default: True)settings(dict, optional):crosshair(bool): default Trueradiological(bool): default Falsecolorbar(bool): default Falseinterpolation(bool): default True
update_interval_ms(int or None): throttle for click events sent back to Python (default: 100 ms).Nonedisables feedback entirely — use it when the return value isn't consumed to avoid any Python round-trip during mouse interaction.key(str, optional): Component key
Returns:
dict or None with click event data:
type: 'voxel_click'voxel: [x, y, z]mm: [x, y, z]value: floatfilename: str
🛠️ Development
Dev mode (live reload)
In dev mode, the Python package points to a local Vite dev server instead of built files.
Terminal 1 — start the frontend dev server (port 3001):
pnpm dev
Terminal 2 — run the example app with the dev flag:
NIIVUE_DEV=1 streamlit run app.py
The frontend hot-reloads on changes.
Production mode (built files)
Build the frontend first, then run Streamlit normally:
pnpm build
streamlit run app.py
_RELEASE = True (the default) serves from niivue_component/frontend/build/.
Running Examples
# Simple example
streamlit run app.py
# Advanced example with all features
streamlit run app_advanced.py
📁 Supported Formats
- Volume-based: NIFTI (.nii, .nii.gz), DICOM (.dcm), MINC (.mnc, .mnc.gz), MHA/MHD, NRRD, MGH/MGZ
- Mesh-based: GIfTI (.gii), FreeSurfer (pial, white, inflated), MZ3 (.mz3), STL (.stl), Wavefront OBJ (.obj), PLY (.ply), BrainSuite DFS (.dfs), Legacy VTK (.vtk)
- Mesh Overlays: GIfTI (.gii), CIfTI-2 (.nii), MZ3 (.mz3), FreeSurfer (CURV, ANNOT), SMP, STC
- Tractography: TCK (.tck), TRK (.trk), TRX (.trx), VTK (.vtk)
🏗️ Architecture
niivue_component/
├── __init__.py # Python API
├── frontend/
│ ├── src/
│ │ ├── components/
│ │ │ ├── StyledViewer.tsx
│ │ │ └── UnstyledCanvas.tsx
│ │ ├── types.ts
│ │ └── utils.ts
│ ├── vite.config.ts
│ └── package.json
└── build/ # Compiled assets (generated, not in git)
🔧 Building for Distribution
Build files are not committed to git. To prepare the Python package for release:
pnpm build
python -m build
This compiles frontend assets into niivue_component/frontend/build/, which is then bundled into the Python package.
📄 License
BSD-2-Clause
🙏 Credits
Built on top of:
Release files for niivue-streamlit 0.3.1.dev111
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| niivue_streamlit-0.3.1.dev111.tar.gz | 787.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| niivue_streamlit-0.3.1.dev111-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 1.6 MB
Release files / niivue_streamlit-0.3.1.dev111.tar.gz
| Download URL | niivue_streamlit-0.3.1.dev111.tar.gz |
|---|---|
| Size | 787.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ac1eae7948f35c4624114489643fb876d05772530e7affe4dcfec7e24118bd0a
|
|
BLAKE2b-256 checksum How to use checksums |
8e50eefac71ae4c0ad58b549d6f90cc0f618f32e9dbe0eef90d17db18f524a9e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.15
|
Release files / niivue_streamlit-0.3.1.dev111-py3-none-any.whl
| Download URL | niivue_streamlit-0.3.1.dev111-py3-none-any.whl |
|---|---|
| Size | 787.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
7f00651ef8d7a04237489d078c5c1a13c64d52c8064e640669890282e0d14d03
|
|
BLAKE2b-256 checksum How to use checksums |
d08023a29ad198a926dbbaf4c18308b80e58a71fc26422e3ca45f7e627cec322
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.15
|