Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support visualisation of morphology only files #398

Merged
merged 4 commits into from
Jun 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 28 additions & 22 deletions pyneuroml/plot/PlotMorphology.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import matplotlib
import numpy
from matplotlib import pyplot as plt
from neuroml import Cell, NeuroMLDocument, SegmentGroup
from neuroml import Cell, Morphology, NeuroMLDocument, SegmentGroup
from neuroml.neuro_lex_ids import neuro_lex_ids

from pyneuroml.pynml import read_neuroml2_file
Expand Down Expand Up @@ -301,6 +301,7 @@ def plot_2D(
if verbose:
print("Plotting %s" % nml_file)

# if it's a file, load it first
if isinstance(nml_file, str):
# load without optimization for older HDF5 API
# TODO: check if this is required: must for MultiscaleISN
Expand All @@ -315,38 +316,43 @@ def plot_2D(
optimized=True,
)
load_minimal_morphplottable__model(nml_model, nml_file)
# note that from this point, the model object is not necessarily valid,
# because we've removed lots of bits.
else:
nml_model = nml_file

# if it isn't a NeuroMLDocument, create one
if isinstance(nml_model, Cell):
logger.info("Got a cell")
plottable_nml_model = NeuroMLDocument(id="newdoc")
plottable_nml_model.add(nml_model)
logger.info(f"plottable cell model is: {plottable_nml_model.cells[0]}")
if title is None:
try:
title = f"{nml_model.networks[0].id} from {nml_file}"
except IndexError:
title = f"{nml_model.cells[0].id} from {nml_file}"

elif isinstance(nml_file, Cell):
nml_model = NeuroMLDocument(id="newdoc")
nml_model.add(nml_file)
title = f"{plottable_nml_model.cells[0].id}"

# if it's only a cell, add it to an empty cell in a document
elif isinstance(nml_model, Morphology):
logger.info("Received morph, adding to a dummy cell")
plottable_nml_model = NeuroMLDocument(id="newdoc")
nml_cell = plottable_nml_model.add(
Cell, id=nml_model.id, morphology=nml_model, validate=False
)
plottable_nml_model.add(nml_cell)
logger.info(f"plottable cell model is: {plottable_nml_model.cells[0]}")
if title is None:
title = f"{nml_model.cells[0].id}"

elif isinstance(nml_file, NeuroMLDocument):
nml_model = nml_file
title = f"{plottable_nml_model.cells[0].id}"
elif isinstance(nml_model, NeuroMLDocument):
plottable_nml_model = nml_model
if title is None:
try:
title = f"{nml_model.networks[0].id} from {nml_file.id}"
except IndexError:
title = f"{nml_model.cells[0].id} from {nml_file.id}"
else:
raise TypeError(
"Passed model is not a NeuroML file path, nor a neuroml.Cell, nor a neuroml.NeuroMLDocument"
)
title = f"{plottable_nml_model.id}"

(
cell_id_vs_cell,
pop_id_vs_cell,
positions,
pop_id_vs_color,
pop_id_vs_radii,
) = extract_position_info(nml_model, verbose)
) = extract_position_info(plottable_nml_model, verbose)

if verbose:
logger.debug(f"positions: {positions}")
Expand Down
60 changes: 34 additions & 26 deletions pyneuroml/plot/PlotMorphologyVispy.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

import numpy
import progressbar
from neuroml import Cell, NeuroMLDocument, SegmentGroup
from neuroml import Cell, Morphology, NeuroMLDocument, SegmentGroup
from neuroml.neuro_lex_ids import neuro_lex_ids
from scipy.spatial.transform import Rotation

Expand Down Expand Up @@ -302,7 +302,7 @@ def vispy_on_key_press(event):


def plot_interactive_3D(
nml_file: typing.Union[str, Cell, NeuroMLDocument],
nml_file: typing.Union[str, Cell, Morphology, NeuroMLDocument],
min_width: float = DEFAULTS["minWidth"],
verbose: bool = False,
plot_type: str = "constant",
Expand Down Expand Up @@ -335,8 +335,10 @@ def plot_interactive_3D(


:param nml_file: path to NeuroML cell file or
:py:class:`neuroml.NeuroMLDocument` or :py:class:`neuroml.Cell` object
:type nml_file: str or neuroml.NeuroMLDocument or neuroml.Cell
:py:class:`neuroml.NeuroMLDocument` or :py:class:`neuroml.Cell`
or :py:class:`neuroml.Morphology` object
:type nml_file: str or neuroml.NeuroMLDocument or neuroml.Cell or
neuroml.Morphology
:param min_width: minimum width for segments (useful for visualising very
thin segments): default 0.8um
:type min_width: float
Expand Down Expand Up @@ -449,6 +451,7 @@ def plot_interactive_3D(
if verbose:
logger.info(f"Visualising {nml_file}")

# if it's a file, load it first
if isinstance(nml_file, str):
# load without optimization for older HDF5 API
# TODO: check if this is required: must for MultiscaleISN
Expand All @@ -463,38 +466,43 @@ def plot_interactive_3D(
optimized=True,
)
load_minimal_morphplottable__model(nml_model, nml_file)
# note that from this point, the model object is not necessarily valid,
# because we've removed lots of bits.
else:
nml_model = nml_file

# if it isn't a NeuroMLDocument, create one
if isinstance(nml_model, Cell):
logger.info("Got a cell")
plottable_nml_model = NeuroMLDocument(id="newdoc")
plottable_nml_model.add(nml_model)
logger.info(f"plottable cell model is: {plottable_nml_model.cells[0]}")
if title is None:
try:
title = f"{nml_model.networks[0].id} from {nml_file}"
except IndexError:
title = f"{nml_model.cells[0].id} from {nml_file}"

elif isinstance(nml_file, Cell):
nml_model = NeuroMLDocument(id="newdoc")
nml_model.add(nml_file)
title = f"{plottable_nml_model.cells[0].id}"

# if it's only a cell, add it to an empty cell in a document
elif isinstance(nml_model, Morphology):
logger.info("Received morph, adding to a dummy cell")
plottable_nml_model = NeuroMLDocument(id="newdoc")
nml_cell = plottable_nml_model.add(
Cell, id=nml_model.id, morphology=nml_model, validate=False
)
plottable_nml_model.add(nml_cell)
logger.info(f"plottable cell model is: {plottable_nml_model.cells[0]}")
if title is None:
title = f"{nml_model.cells[0].id}"

elif isinstance(nml_file, NeuroMLDocument):
nml_model = nml_file
title = f"{plottable_nml_model.cells[0].id}"
elif isinstance(nml_model, NeuroMLDocument):
plottable_nml_model = nml_model
if title is None:
try:
title = f"{nml_model.networks[0].id} from {nml_file.id}"
except IndexError:
title = f"{nml_model.cells[0].id} from {nml_file.id}"
else:
raise TypeError(
"Passed model is not a NeuroML file path, nor a neuroml.Cell, nor a neuroml.NeuroMLDocument"
)
title = f"{plottable_nml_model.id}"

(
cell_id_vs_cell,
pop_id_vs_cell,
positions,
pop_id_vs_color,
pop_id_vs_radii,
) = extract_position_info(nml_model, verbose)
) = extract_position_info(plottable_nml_model, verbose)

logger.debug(f"positions: {positions}")
logger.debug(f"pop_id_vs_cell: {pop_id_vs_cell}")
Expand Down Expand Up @@ -726,7 +734,7 @@ def plot_interactive_3D(
f"More meshes than threshold ({len(meshdata.keys())}/{precision[1]}), reducing precision to {precision[0]} and re-calculating."
)
plot_interactive_3D(
nml_file=nml_model,
nml_file=plottable_nml_model,
min_width=min_width,
verbose=verbose,
plot_type=plot_type,
Expand Down
12 changes: 10 additions & 2 deletions pyneuroml/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@

import neuroml
import numpy
import pyneuroml.utils.misc
from lems.model.model import Model
from neuroml.loaders import read_neuroml2_file

import pyneuroml.utils.misc
from pyneuroml.errors import UNKNOWN_ERR
from pyneuroml.utils.plot import get_next_hex_color


logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)

Expand Down Expand Up @@ -86,12 +86,20 @@ def extract_position_info(
pop_id_vs_color = {}
pop_id_vs_radii = {}

morph_elements = []
cell_elements = []
popElements = []

cell_elements.extend(nml_model.cells)
cell_elements.extend(nml_model.cell2_ca_poolses)

# handle morphology elements by adding them into dummy cells
ctr = 1
morph_elements.extend(nml_model.morphology)
for m in morph_elements:
cell_elements.append(neuroml.Cell(id=f"Dummy cell {ctr}", morphology=m))
ctr += 1

# if the model does not include a network, plot all the cells in the
# model in new dummy populations
if len(nml_model.networks) == 0:
Expand Down
6 changes: 5 additions & 1 deletion pyneuroml/utils/plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,7 @@ def load_minimal_morphplottable__model(
required_members = [
"id",
"cells",
"morphology",
"cell2_ca_poolses",
"networks",
"populations",
Expand All @@ -360,6 +361,7 @@ def load_minimal_morphplottable__model(
for m in model_members:
if m not in required_members:
setattr(nml_model, m, None)
logger.debug(f"Dropped {m}")

# if the model contains a network, use it
if len(nml_model.networks) > 0:
Expand All @@ -385,11 +387,13 @@ def load_minimal_morphplottable__model(
acell.biophysical_properties = None
nml_model.add(acell)
else:
# add any included cells to the main document
# add any included cells or morphologies to the main document
for inc in nml_model.includes:
incl_loc = os.path.abspath(os.path.join(base_path, inc.href))
if os.path.isfile(incl_loc):
inc = read_neuroml2_file(incl_loc)
for acell in inc.cells:
acell.biophysical_properties = None
nml_model.add(acell)
for morph in inc.morphology:
nml_model.add(morph)
Loading
Loading