diff --git a/.github/workflows/apple.yml b/.github/workflows/apple.yml
index 125aa37..8560036 100644
--- a/.github/workflows/apple.yml
+++ b/.github/workflows/apple.yml
@@ -7,7 +7,7 @@ run-name: ${{ github.actor }}::pytest pcdl library on mac os x; the latest pytho
on:
push:
- branches: ["utest", "master"] # ["v3", "v4"]
+ branches: ["master"]
pull_request:
branches: ["development", "master"]
@@ -22,7 +22,7 @@ jobs:
env:
MPLBACKEND: Agg # https://github.com/orgs/community/discussions/26434
- PYTHONPATH: /Users/runner/work/physicelldataloader/physicelldataloader
+ PYTHONPATH: ${{ github.workspace }}
steps:
- uses: actions/checkout@main
@@ -34,8 +34,8 @@ jobs:
run: |
brew install ffmpeg imagemagick
python -m pip install --upgrade pip
- python -m pip install flake8 pytest anndata bioio bioio-ome-tiff geopandas matplotlib networkx neuroglancer numpy pandas requests scikit-image scipy shapely spatialdata vtk
- python -m pip install /Users/runner/work/physicelldataloader/physicelldataloader -v
+ python -m pip install flake8 pytest anndata bioio bioio-ome-tiff geopandas matplotlib networkx neuroglancer numpy pandas requests scikit-image scipy shapely simulariumio spatialdata vtk
+ python -m pip install . -v
#if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
- name: lint with flake8
run: |
diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml
index 5bc0a9c..f99d4e0 100644
--- a/.github/workflows/linux.yml
+++ b/.github/workflows/linux.yml
@@ -7,7 +7,7 @@ run-name: ${{ github.actor }}::pytest pcdl library on linux os; all python3 vers
on:
push:
- branches: ["utest", "master"] # ["v3","v4"]
+ branches: ["master"]
pull_request:
branches: ["development", "master"]
@@ -22,7 +22,7 @@ jobs:
env:
MPLBACKEND: Agg # https://github.com/orgs/community/discussions/26434
- PYTHONPATH: /home/runner/work/physicelldataloader/physicelldataloader
+ PYTHONPATH: ${{ github.workspace }}
steps:
- uses: actions/checkout@main
@@ -35,8 +35,8 @@ jobs:
sudo apt update
sudo apt install ffmpeg imagemagick
python -m pip install --upgrade pip
- python -m pip install flake8 pytest anndata bioio bioio-ome-tiff geopandas matplotlib networkx neuroglancer numpy pandas requests scikit-image scipy shapely spatialdata vtk
- python -m pip install /home/runner/work/physicelldataloader/physicelldataloader -v
+ python -m pip install flake8 pytest anndata bioio bioio-ome-tiff geopandas matplotlib networkx neuroglancer numpy pandas requests scikit-image scipy shapely simulariumio spatialdata vtk
+ python -m pip install . -v
#if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
- name: lint with flake8
run: |
diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml
index ecb7338..ddb8c83 100644
--- a/.github/workflows/windows.yml
+++ b/.github/workflows/windows.yml
@@ -7,7 +7,7 @@ run-name: ${{ github.actor }}::pytest pcdl library on windows os; the latest pyt
on:
push:
- branches: ["utest", "master"] # ["v3", "v4"]
+ branches: ["master"]
pull_request:
branches: ["development", "master"]
@@ -22,7 +22,7 @@ jobs:
env:
MPLBACKEND: Agg # https://github.com/orgs/community/discussions/26434
- PYTHONPATH: D:\a\physicelldataloader\physicelldataloader
+ PYTHONPATH: ${{ github.workspace }}
steps:
- uses: actions/checkout@main
@@ -34,8 +34,8 @@ jobs:
run: |
choco install ffmpeg imagemagick
python -m pip install --upgrade pip
- python -m pip install flake8 pytest anndata bioio bioio-ome-tiff geopandas matplotlib networkx neuroglancer numpy pandas requests scikit-image scipy shapely spatialdata vtk
- python -m pip install D:\a\physicelldataloader\physicelldataloader -v
+ python -m pip install flake8 pytest anndata bioio bioio-ome-tiff geopandas matplotlib networkx neuroglancer numpy pandas requests scikit-image scipy shapely simulariumio spatialdata vtk
+ python -m pip install . -v
#echo 'set PYTHONPATH=D:\a\physicelldataloader\physicelldataloader' >> $GITHUB_ENV
#if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
- name: lint with flake8
diff --git a/README.md b/README.md
index 117e170..e8068a0 100644
--- a/README.md
+++ b/README.md
@@ -2,13 +2,14 @@
## Abstract:
-physicell data loader (pcdl) provides a platform-independent (Windows, MacOSX, Linux), python3 based, [pip](https://en.wikipedia.org/wiki/Pip_(package_manager))-installable set of commands
+physicell data loader (pcdl) provides a platform-independent (Windows, MacOSX, Linux), python3 based, [pip](https://en.wikipedia.org/wiki/Pip_(package_manager))-installable set of commands,
to load output, generated with the [PhysiCell](https://github.com/MathCancer/PhysiCell) agent-based modeling and diffusion solver framework,
-into [python3](https://en.wikipedia.org/wiki/Python_(programming_language)) or transform PhysiCell output into more widely used data formats.
-pcdl can be loaded as a python3 module or run straight from the command line.
+into [python3](https://en.wikipedia.org/wiki/Python_(programming_language)) or transform PhysiCell output into more widely used data formats,
+straight on the command line.

+
-
-## Header:
+## Software Specification:
+ Language: python [>= 3.11](https://devguide.python.org/versions/)
-+ Library dependencies: anndata, bioio, geopandas, matplotlib, networkx, neuroglancer, numpy, pandas, (requests), scikit-image, scipy, shapely, spatialdata, vtk
++ Library core dependencies: matplotlib, numpy, pandas, scipy
++ Library optional dependencies: anndata, bioio, geopandas, networkx, neuroglancer, requests, scikit-image, shapely, simulariumio, spatialdata, vtk
+ Date of origin original PhysiCell-Tools python-loader: 2019-09-02
+ Date of origin pcdl fork: 2022-08-30
+ Doi: https://doi.org/10.5281/ZENODO.8176399
@@ -47,15 +49,16 @@ Basics Tutorials:
1. [pcdl from the command line](https://github.com/elmbeech/physicelldataloader/tree/master/man/TUTORIAL_commandline.md)
Extras tutorials python3 language:
+
++ [pcdl and python3 and graphs](https://github.com/elmbeech/physicelldataloader/tree/master/man/TUTORIAL_python3_graph.md)
+ [pcdl and python3 and json](https://github.com/elmbeech/physicelldataloader/blob/master/man/TUTORIAL_python3_json.md)
++ [pcdl and python3 and matplotlib](https://github.com/elmbeech/physicelldataloader/tree/master/man/TUTORIAL_python3_matplotlib.md)
++ [pcdl and python3 and muspan](https://github.com/elmbeech/physicelldataloader/tree/master/man/TUTORIAL_python3_muspan.md)
++ [pcdl and python3 and napari](https://github.com/elmbeech/physicelldataloader/tree/master/man/TUTORIAL_python3_napari.md)
++ [pcdl and python3 and ome.tiff, tiff, png, and jpeg](https://github.com/elmbeech/physicelldataloader/tree/master/man/TUTORIAL_python3_ometiff.md)
+ [pcdl and python3 and pandas](https://github.com/elmbeech/physicelldataloader/tree/master/man/TUTORIAL_python3_pandas.md)
+ [pcdl and python3 and scanpy and squidpy](https://github.com/elmbeech/physicelldataloader/tree/master/man/TUTORIAL_python3_scverse.md)
-+ [pcdl and python3 and muspan](https://github.com/elmbeech/physicelldataloader/tree/master/man/TUTORIAL_python3_muspan.md)
-+ [pcdl and python3 and graphs](https://github.com/elmbeech/physicelldataloader/tree/master/man/TUTORIAL_python3_graph.md)
-+ [pcdl and python3 and matplotlib](https://github.com/elmbeech/physicelldataloader/tree/master/man/TUTORIAL_python3_matplotlib.md)
+ [pcdl and python3 and vtk](https://github.com/elmbeech/physicelldataloader/tree/master/man/TUTORIAL_python3_vtk.md)
-+ [pcdl and python3 and ome.tiff, tiff, png, and jpeg](https://github.com/elmbeech/physicelldataloader/tree/master/man/TUTORIAL_python3_ometiff.md)
-+ [pcdl and python3 and napari](https://github.com/elmbeech/physicelldataloader/tree/master/man/TUTORIAL_python3_napari.md)
Extras tutorials for other languages than python3:
@@ -66,14 +69,13 @@ Extras tutorials for other languages than python3:
Extras tutorials for GUI software:
+ [pcdl and paraview](https://github.com/elmbeech/physicelldataloader/tree/master/man/TUTORIAL_paraview.md)
+
+ [pcdl and blender](https://github.com/elmbeech/physicelldataloader/tree/master/man/TUTORIAL_blender.md)
-+ [pcdl and napari](https://github.com/elmbeech/physicelldataloader/tree/master/man/TUTORIAL_python3_napari.md)
+ [pcdl and fiji imagej, icy, qupath](https://github.com/elmbeech/physicelldataloader/tree/master/man/TUTORIAL_fijiimagej.md)
++ [pcdl and galaxy](https://github.com/elmbeech/physicelldataloader/tree/master/man/TUTORIAL_galaxy.md)
++ [pcdl and napari](https://github.com/elmbeech/physicelldataloader/tree/master/man/TUTORIAL_python3_napari.md)
+ [pcdl and neuroglancer](https://github.com/elmbeech/physicelldataloader/tree/master/man/TUTORIAL_neuroglancer.md)
-
-Slides:
-
-+ [presentations given](https://github.com/elmbeech/physicelldataloader/tree/master/man/lecture)
++ [pcdl and simularium](https://github.com/elmbeech/physicelldataloader/tree/master/man/TUTORIAL_simularium.md)
## ✨ Reference Manual:
@@ -83,31 +85,13 @@ Slides:
## Discussion:
-To be developed.
-
++ [presentations given](https://github.com/elmbeech/physicelldataloader/tree/master/man/lecture)
+
## Cite:
@@ -124,293 +108,26 @@ Developers, please make pull requests to the https://github.com/elmbeech/physice
```
-## Road Map:
-
-+ evt generate lineage tree graph output files.
-
+## Contributions:
-## Release Notes:
++ original PhysiCell-Tools python-loader implementation: Patrick Wall, Randy Heiland, Paul Macklin
++ fork pcdl implementation: Elmar Bucher
++ fork pcdl co-programmer: Furkan Kurtoglu, Heber Rocha, Jennifer Eng
++ fork pcdl continuous testing and feedbacks: Aneequa Sundus (python), John Metzcar (python), Raquel Arroya (matlab)
++ student prj on pcdl:
+ Benjamin Jacobs (make\_graph\_gml),
+ Jason Lu (render\_neuroglancer),
+ Katie Pletz (beta testing),
+ Leena Sohail (beta testing),
+ Marshal Gress (plot\_scatter),
+ Nick Oldfather (unit test model),
+ Thierry-Pascal Fleurant (plot\_timeseries),
+ Viviana Kwong (render\_neuroglancer)
-+ version 4.1.8 (2026-08-26): elmbeech/physicelldataloader
- + branch v4 compatible with bioconda and galaxy.
-+ version 4.1.7 (2026-08-21): elmbeech/physicelldataloader
- + compatible with pandas v3.0.0.
+## Develoment:
-+ version 4.1.6 (2026-08-20): elmbeech/physicelldataloader
- + pcdl installs now by default lightweight with only the core dependencies; users are prompted to install optional libraries if necessary. special thanks to Heber Rocha!
++ [Road Map](https://github.com/elmbeech/physicelldataloader/tree/master/man/ROADMAP.md)
++ [Release Notes](https://github.com/elmbeech/physicelldataloader/tree/master/man/RELEASENOTES.md)
-+ version 4.1.5 (2026-04-05): elmbeech/physicelldataloader
- + bugfix library dependencies and library versions.
-
-+ version 4.1.4 (2026-04-04): elmbeech/physicelldataloader
- + pyMCDSts **mcdsts.make_contour** extrema parameter is replaced by vmin and vmax to be compatible with mcds.make\_contour and plt.contour.
- + **make_cell_vtk** and **make_conc_vtk** now offer an ext parameter, allowing to manually specify the exact file extension. special thanks to Danyon Gedris!
- + new **make_muspan** TimeStep class and TimeSeris class function and **pcdl_get_muspan** command line command. special thanks to Joshua Moore and Joshua Bull!
-
-+ version 4.1.3 (2026-03-21): elmbeech/physicelldataloader
- + new **pcdl.pccmap** color map. this is an adaptation of the physicell pathology paint by number color map.
- + new TimeStep **get_pcdl_version** function.
-
-+ version 4.1.2 (2026-03-06): elmbeech/physicelldataloader
- + new **custom_data_astype** TimeStep class and TimeSeries class function to set the dtype of custom\_data variables even after the timestep or timeseries is loaded.
- + TimeSeries \_\_init\_\_ function can now handle a list of TimeStep objects as input instead of a path.
-
-+ version 4.1.1 (2026-02-28): elmbeech/physicelldataloader
- + reduced memory footprint.
-
-+ version 4.1.0 (2025-12-31): elmbeech/physicelldataloader
- + new **get_spatialdata** TimeStep class and TimeSeris class function and **pcdl_get_spatialdata** command line command. special thanks to Luca Marconato!
- + with this release, pcdl officially became an [scverse ecosystem](https://scverse.org/packages/#ecosystem) package.
-
-+ version 4.0.5 (2025-10-22): elmbeech/physicelldataloader
- + **settingxml** default is now set to False, because the cell\_type id label mapping can, in recent PhysiCell output, be retrieved from output\*.xml too.
- + **plot_scatter** and **plot_timeseries** now additionally have a cat\_drop and cat\_keep argument to filter categorical data.
- + **plot_timeseries(frame=conc)** now plots by default all substrate concentrations over time.
- + **plot_timeseries(ext=)** parameter offers to return a dataframe object, dafaframe csv file, image file, or a matplotlib fig object. special thanks to John Nardini and Edward Young!
-
-+ version 4.0.4 (2025-07-23): elmbeech/physicelldataloader
- + command line commands now return **error code 0** if the command runs successfully.
-
-+ version 4.0.3 (2025-07-20): elmbeech/physicelldataloader
- + TimeStep and TimeSeris **plot_contour**, **plot_scatter**, and **plot_timeseries** handle now **kwargs** arguments.
- + minor bugfixes.
-
-+ version 4.0.2 (2025-06-29): elmbeech/physicelldataloader
- + minor bugfixes.
-
-+ version 4.0.1 (2025-06-24): elmbeech/physicelldataloader
- + man updated.
- + minor bugfixes.
-
-+ version 4.0.0 (2025-05-13): elmbeech/physicelldataloader
- + v4 was forked from v3.3.4!
- + **mcds.data** struct was rewritten in more python less c++ way.
- + pyMCDS.py and part of pyAnnData.py was fused to **timestep.py**.
- + pyMCDSts.py and part of pyAnnData.py was fused to **timeseries.py**.
- + pyCLI.py was renames to **commandline.py**.
- + data\_timeseries.py was renamed to **output_data.py**.
- + TimeStep function **get_concentration** was deprecated because pandas already has this functionlity.
- + TimeStep function **get_concentration_at** was deprecated because pandas already has this functionlity.
- + TimeStep function **get_cell_df_at** was deprecated because pandas already has this functionlity.
- + **make_conc_vtk** and **make_cell_vtk** on the fly visualization was removed because paraview is good enough.
- + new TimeStep **get_cell_attribute_list** function, to retrieve a list of all tracked cell attribute labels.
- + new **pcdl_get_cell_attribute_list** function, to retrieve a list of all tracked cell attribute labels.
- + new **render_neuroglancer** function, to render ome tiff image into neuroglancer.
- + new **pcdl_render_neuroglancer** function, to render ome tiff images into neuroglancer.
-
-+ version 3.3.8 (2025-07-23): elmbeech/physicelldataloader
- + command line commands now return **error code 0** if the command runs successfully.
-
-+ version 3.3.7 (2025-06-01): elmbeech/physicelldataloader
- + compatible with current (non end-of-life cycle) python versions.
- + minor bugfixes.
-
-+ version 3.3.6 (2025-05-13): elmbeech/physicelldataloader
- + compatible with numpy >= 2.0.0 and current (non end-of-life cycle) python versions.
-
-+ version 3.3.5 (2025-05-13): elmbeech/physicelldataloader
- + compatible with numpy < 2.0.0 and current (non end-of-life cycle) python versions.
- + remove pyMCDS and pyMCDSts **make_ome_tiff** and pyCLI **pcdl_make_ome_tiff** to make pyMCS.py stand alone again.
- + new TimeStep **get_cell_attribute_list** function, to retrieve a list of all tracked cell attribute labels.
- + new **pcdl_get_cell_attribute_list** function, to retrieve a list of all tracked cell attribute labels.
-
-+ version 3.3.4 (2025-03-07): elmbeech/physicelldataloader
- + replace the **aicsimageio** library dependency with its successor **bioio**. special thanks to Joel Eliason!
- + **make_ome_tiff** can now handel generated file names with > 255 characters. special thank to Genevieve Stein-O'Brien and DanielBergman!
- + **get_mesh_spacing** handels now an edge case correctly that would have resulted in a division by zero. special thanks to Randy Heiland!
-
-+ version 3.3.3 (2025-01-10): elmbeech/physicelldataloader
- + bug fix **plot_contour** plot orientation. special thanks to Marco Ruscone!
- + add test data for new improved **unittest physicell model**. special thanks to Nick Oldfather!
- + add pyMCDS **make_conc_vtk** on the fly visualization. special thanks to Randy Heiland and Nick Oldfather!
- + pyMCDS and pyMCDSts **make_graph_gml** and pyAnnData **get_anndata** handles now spring\_attached\_cells graph too.
-
-+ version 3.3.2 (2024-11-24): elmbeech/physicelldataloader
- + **Warnings** will no longer be piped to standard output if verbose is set to False.
- + pyMCDS **make_ome_tiff** function rewriten to be less RAM hungry and more versatile.
-
-+ version 3.3.1 (2024-09-22): elmbeech/physicelldataloader
- + bugfix pyMCDS custom vectors loading.
-
-+ version 3.3.0 (2024-08-22): elmbeech/physicelldataloader
- + **pip install pcdl**: will again install all library dependencies. The fine-tuned version was too confssing.
- + pyMCDS handels now intracellular **physinboss** data too; data is stored in cell\_df.
- + rename pyMCDS get\_cell\_variables to **get_celltype_list** for conciseness and order list by ID.
- + rename pyMCDS get\_substrate\_names to **get_substrate_list** for conciseness and order list by ID.
- + rename pyMCDS get\_scatter to **plot_scatter** for conciseness.
- + rename pyMCDS get\_contour to **plot_contour** for conciseness.
- + rename pyMCDSts make\_imgcell to **plot_scatter** for conciseness.
- + rename pyMCDSts make\_imgconc to **plot_contour** for conciseness.
- + rename pyMCDSts get\_cell\_df\_states to **get_cell_attribute** for conciseness.
- + rename pyMCDSts get\_conc\_df\_states to **get_conc_attribute** for conciseness.
- + rewrite pyMCDS mcds.get\_unit\_se into **mcds.get_unit_dict**.
- + new pyCLI **pcdl_get_anndata** command line interface function.
- + new pyCLI **pcdl_get_celltype_list** command line interface function.
- + new pyCLI **pcdl_get_cell_attribute** command line interface function.
- + new pyCLI **pcdl_get_cell_df** command line interface function.
- + new pyCLI **pcdl_get_substrate_list** command line interface function.
- + new pyCLI **pcdl_get_conc_attribute** command line interface function.
- + new pyCLI **pcdl_get_conc_df** command line interface function.
- + new pyCLI **pcdl_get_graph_gml** command line interface function.
- + new pyCLI **pcdl_get_unit_dict** command line interface function.
- + new pyCLI **pcdl_get_version** command line interface function.
- + new pyCLI **pcdl_make_cell_vtk** command line interface function.
- + new pyCLI **pcdl_make_conc_vtk** command line interface function.
- + new pyCLI **pcdl_make_gif** command line interface function.
- + new pyCLI **pcdl_make_movie** command line interface function.
- + new pyCLI **pcdl_make_ome_tiff** command line interface function.
- + new pyCLI **pcdl_plot_contour** command line interface function.
- + new pyCLI **pcdl_plot_scatter** command line interface function.
- + new pyCLI **pcdl_plot_timeseries** command line interface function.
- + new pyMCDS **mcds.get_mesh_mnp** function, the mesh version from mcds.get\_voxel\_ijk.
- + new pyMCDS **make_conc_vtk** function, to save substrate data as rectilinear grid vtk file.
- + new pyMCDS **make_cell_vtk** function, to save cell data as glyph vtk file.
- + new pyMCDS **make_graph_gml** function, to save graphs in a networkx and igraph compatible file format.
- + new pyMCDS **make_ome_tiff** function, to save the output data in ome tiff file format.
- + new pyMCDS **set_verbosity_true** function, to complete pcdl.TimeStep(verbosity=True/False) experience.
- + new pyMCDS **set_verbosity_false** function, to complete pcdl.TimeStep(verbosity=True/False) experience.
- + new pyMCDSts **get_cell_df** function, to extract one big dataframe or a list of dataframes from the whole time series.
- + new pyMCDSts **get_conc_df** function, to extract one big dataframe or a list of dataframes from the whole time series.
- + new pyMCDSts **make_cell_vtk** function, to save substrate data as rectilinear grid vtk files. special thanks to Furkan Kurtoglu!
- + new pyMCDSts **make_conc_vtk** function, to save cell data as glyph vtk files. special thanks to Furkan Kurtoglu!
- + new pyMCDSts **make_graph_gml** function, to save graphs in a networkx and igraph compatible files format. special thanks to Benjamin Jacobs!
- + new pyMCDSts **make_ome_tiff** function, to save the output data in ome tiff file format.
- + new pyMCDSts **plot_timeseries** function, to plot time series. special thanks to Thierry-Pascal Fleurant!
- + new pyMCDSts **set_verbosity_true** function, to complete the pcdl.TimeSeries(verbosity=True/False) experience.
- + new pyMCDSts **set_verbosity_false** function to complete the pcdl.TimeSeries(verbosity=True/False) experience.
-
-+ version 3.2.13 (2023-09-18): elmbeech/physicelldataloader
- + rename pyMCDSts make\_imgsubs to **make_imgconc** for consistency.
- + add **man/lecture/20230917_pcdl_repl_programming_analysis_plots.pdf** slide deck.
-
-+ version 3.2.12 (2023-08-12): elmbeech/physicelldataloader
- + add **man/jupyter/pcdl_repl_programming.ipynb** : Jupyter notebook to give an idea about how to work with pcdl in a python3 REPL.
- + add **man/lecture/20230808_pcws2023_session07_pcdl.pdf** slide deck.
- + add github **continuous integration** for all supported python3 versions, all supported operating systems.
-
-+ version 3.2.11 (2023-08-08): elmbeech/physicelldataloader
- + **pip install pcdl**: will only install the bare minimum library dependencies.
- + **pip install pcdl[data]**: will install the minimum dependencies plus the dependencies to download the test dataset.
- + **pip install pcdl[scverse]**: will install the minimum dependencies plus the dependencies needed to generate an anndata object.
- + **pip install pcdl[all]**: will always install all dependencies.
- + new TimeSeries **get_annmcds_list** function, which points to the self.l\_annmcds object.
- + new pyMCDS **get_scatter** function is split off from pyMCDSts make\_imgcell.
- + pyMCDSts **make_imgcell** and **make_imgsubs** bug fixes.
- + TimeStep and TimeSeries **get_anndata** evolution.
-
-+ version 3.2.10 (2023-07-24): elmbeech/physicelldataloader
- + rename pyMCDSts get\_cell\_df\_columns\_states to **get_cell_df_states** for conciseness.
- + rename pyMCDSts get\_conc\_df\_columns\_states to **get_conc_df_states** for conciseness.
-
-+ version 3.2.9 (2023-07-23): elmbeech/physicelldataloader
- + new class **TimeStep** can do everything pyMCDS can do and more.
- + new class **TimeSeries** can do everything pyMCDSts can do and more.
- + new TimeStep **get_anndata** function to transform physicell output into [AnnData](https://anndata.readthedocs.io/en/latest/) objects.
- + new TimeSeries **get_anndata** function to transform physicell output into [AnnData](https://anndata.readthedocs.io/en/latest/) objects.
- + internal pyAnnData **scaler** function.
- + internal pyAnnData **\_anndextract** function.
- + pyMCDS **_\_init__** seetingxml parameter changed from boolean to string to accept other PhysiCell\_settings.xml filenames than the default.
- + pyMCDS **get_cell_df** drop and keep parameters to declare a set of columns to be dropped or kept.
- + pyMCDS **get_conc_df** drop and keep parameters to declare a set of columns to be dropped or kept.
- + new pyMCDS **get_conc_df** shorthand for get\_concentration\_df.
- + pyMCDSts get\_cell\_minstate\_col reimplementation as **get_cell_df_columns_states** function.
- + pyMCDSts get\_concentartion\_minstate\_col reimplementation as **get_conc_df_columns_states** function.
- + new pyMCDSts **get_mcds_list** function which points to the self.l\_mcds object.
-
-+ version 3.2.8 (2023-06-21): elmbeech/physicelldataloader
- + pyMCDS **get_concentration_df** states parameter to filter out non-informative variables.
- + pyMCDS **get_cell_df** states parameter to filter out non-informative variables.
- + pyMCDSts **_\_init__** load parameter to specify if the whole time series data straight at object initialization should be loaded.
- + new pyMCDSts **get_cell_minstate_col** function to scan the whole time series for informative attributes.
- + new pyMCDSts **get_concentartion_minstate_col** function to scan the whole time series for informative attributes.
-
-+ version 3.2.7 (2023-06-20): elmbeech/physicelldataloader
- + pyMCDS and pyMCDSts **_\_init__** custom\_type parameter to specify other custom\_data variable types (int, bool, str) then the generic float.
-
-+ version 3.2.5 (2023-06-19): elmbeech/physicelldataloader
- + pyMCDS resolves incompatibility with earlier PhysiCell and MultiCellDS versions.
-
-+ version 3.2.4 (2023-06-17): elmbeech/physicelldataloader
- + pyMCDS **_\_init__** seetingxml parameter for cases where in the output folder no PhysiCell\_settings.xml can be found.
- + pyMCDSts **mcdsts.make_imgcell** extrema parameter is replaced by the z\_axis parameter to account for numerical and categorical variable types.
-
-+ version 3.2.2 (2023-06-16): elmbeech/physicelldataloader
- + pyMCDS **mcds.get_cell_df** sets distinct boolean, categorical, integer number, and real number variable types. categorical number codes are translated. for all spatial variables, the vector length value is calculated and added automatically.
- + new pyMCDS **mcds.get_celltype_dict** function.
- + new pyMCDS **mcds.get_substrate_dict** function.
- + pyMCDSts **mcdsts.make_imgcell** and **mcdsts.make_imgsubs** functions improved.
-
-+ version 3.2.1 (2023-06-12): elmbeech/physicelldataloader
- + pypa odyssey is coming to an end.
- + change build system from setuptools to hatching.
- + change the library name from pcDataLoader to pcdl.
- + to make the library installation more lightweight, test data was excluded from the basic installation.
- given the computer is connected to the internet, test data can easily be installed and removed with the **pcdl.install_data()** and **pcdl.uninstall_data()** functions now.
-
-+ version 3.0.7 (2023-06-08): elmbeech/physicelldataloader
- + pyMCDSts: replaces the svg dependent **mcdsts.make_jpeg**, **mcdsts.make_png**, and **mcdsts.make_tiff** with **mcdsts.make_imgcell** and **mcdsts.make_imgsubs** which generate images straight out of the loaded data. the **mcdsts.make_gif** and **mcdsts.make_movie** functions were adjusted accordingly. special thanks to Marshal Gress!
- + pyMCDSts: **mcdsts.read_mcds** loads now automatically all mcds snapshots if no xmlfile\_list is provided (default).
-
-+ version 3.0.6 (2023-04-29): elmbeech/physicelldataloader
- + pyMCDS **\_read_xml** is now able to load time steps with zero cells.
- + pyMCDS **mcds.get_contour** can handle more input parameters.
-
-+ version 3.0.5 (2023-02-26): elmbeech/physicelldataloader pyMCDS **mcds.get_contour** plots span now the whole domain and not only to the border voxel centers.
-+ version 3.0.4 (2023-02-21): elmbeech/physicelldataloader pyMCDS **mcds.get_contour** function, to easily generate for substrates matplotlib contourf and contour plots because they do not exist as pandas plots.
-+ version 3.0.3 (2023-02-19): elmbeech/physicelldataloader branch 3 has no longer anndata and, as such, hdf5 dependency.
-+ version 3.0.2 (2023-01-06): elmbeech/physicelldataloader bugfix installing package data.
-+ version 3.0.0 (2023-01-06): elmbeech/physicelldataloader
- + **pyMCDS** parameter **xml_file** can now handle path/file.xml (unix) or path\file.xml (dos) input, as long output_path is the default.
- + **pyMCDS** has a new additional boolean **microenv** parameter, to specify if the microenvironment (substrates) should be read (for completeness) or not (for speed increase and less memory usage).
- + **pyMCDS** has a new additional boolean **graph** parameter, to specify if the attached and neighbor graph should be read.
- + **pyMCDS** has a new additional boolean **verbose** parameter, to specify if there should be text output while processing.
- + pyMCDS **mcds.get_2D_mesh** was renamed to **mcds.get_mesh_2D** for consistency.
- + pyMCDS **mcds.get_linear_voxels** was renamed to **mcds.get_mesh_coordinate** for consistency.
- + pyMCDS **mcds.get_containing_voxel_ijk** was renamed to **mcds.get_voxel_ijk** for briefness.
- + pyMCDS **mcds.get_voxel_spacing** returns now 3 specific values, one for x, y, and z, instead of 1 general value.
- + pyMCDS **mcds.get_concentrations** was renamed to **mcds.get_concentration** for consistency
- + pyMCDS **mcds.get_concentrations_at** was renamed to **mcds.get_concentration_at** for consistency
- + pyMCDS **mcds.get_concentration_at** if z_slice is not a mesh center value, the function will by default adjust to the nearest and no longer break.
- + pyMCDS **mcds.get_cell_variables** and **mcds.get_substrate_names** return now a strictly alphabetically ordered list.
- + pyMCDS **mcds.get_cell_df** returns now a pandas dataframe with the cell IDs as the index and not as a column.
- additionally, this dataframe contains now voxel, mesh_center, substrate parameter, substrate concentration, and cell density information too.
- + new pyMCDS **mcds.get_concentration_df** function.
- + new pyMCDS **mcds.get_substrate_df** function.
- + new pyMCDS **mcds.get_unit_se** function.
- + new pyMCDS **mcds.get_multicellds_version** function.
- + new pyMCDS **mcds.get_physicell_version** function.
- + new pyMCDS **mcds.get_runtime** function.
- + new pyMCDS **mcds.get_timestamp** function.
- + new pyMCDS **mcds.get_voxel_ijk_range** function.
- + new pyMCDS **mcds.get_voxel_ijk_axis** function.
- + new pyMCDS **mcds.get_voxel_spacing** function.
- + new pyMCDS **mcds.get_voxel_volume** function.
- + new pyMCDS **mcds.get_mesh_mnp_range** function.
- + new pyMCDS **mcds.get_mesh_mnp_axis** function.
- + new pyMCDS **mcds.get_xyz_range** function.
- + new pyMCDS **mcds.is_in_mesh** function.
- + new pyMCDS **mcds.get_attached_graph_dict** function.
- + new pyMCDS **mcds.get_neigbor_graph_dict** function.
- + class **pyMCDS_timeseries** was renamed to **pyMCDSts** and completely rewritten.
- + new pyMCDSts **get_xmlfile_list** function.
- + new pyMCDSts **read_mcds** function.
- + new pyMCDSts **make_jpeg** function.
- + new pyMCDSts **make_png** function.
- + new pyMCDSts **make_tiff** function.
- + new pyMCDSts **make_gif** function.
- + new pyMCDSts **make_movie** function.
- + all **plotting** functions were removed because pcdl only focuses on making the raw data in python3 easy to access for in-depth analysis.
- + cell position coordinates are now constantly labeled as **x,y,z**, mesh center coordinates as **m,n,p**, and voxel coordinates as **i,j,k**.
- + the underling [mcds object data dictionary structure](https://github.com/elmbeech/physicelldataloader/tree/master/man/img/physicelldataloader_data_dictionary_v3.0.0.png) has changed.
- + [pytest](https://en.wikipedia.org/wiki/Pytest) unit tests exist now for all pyMCDS and pyMCDSts functions.
-
-+ version 2.0.3 (2023-06-16): elmbeech/physicelldataloader pypa odyssey is coming to an end.
-+ version 2.0.2 (2023-01-06): elmbeech/physicelldataloader reset patch voxel spacing bugfix, so that branch2 is full compatible with branch1 again. use branch3 for a bugfixed version!
-+ version 2.0.1 (2022-11-08): elmbeech/physicelldataloader beta release patch voxel spacing bugfix.
-+ version 2.0.0 (2022-08-30): elmbeech/physicelldataloader pip installable release, derived from and compatible with PhysiCell-Tools/python-loader release 1.1.0 (2022-07-20).
-
-+ version 1.1.1 (2022-07-01): elmbeech/physicelldataloader deprecated np.float replaced with np.float64.
-+ version 1.1.0 (2022-05-09): Physicell-Tools/python-loader release compatible with pre-v1.10.x of PhysiCell.
-+ version 1.0.1 (2020-01-25): Physicell-Tools/python-loader time-series related bug fix.
-+ version 1.0.0 (2019-09-28): Physicell-Tools/python-loader first public release!
+Developers, please make pull requests to the https://github.com/elmbeech/physicelldataloader/tree/development branch. Thanks!
diff --git a/jakku/biocondarecipes_recipes/pcdl/meta.yaml b/jakku/biocondarecipes_recipes/pcdl/meta.yaml
index 29e4887..b199787 100644
--- a/jakku/biocondarecipes_recipes/pcdl/meta.yaml
+++ b/jakku/biocondarecipes_recipes/pcdl/meta.yaml
@@ -88,4 +88,4 @@ extra:
recipe-maintainers:
- elmbeech
autobump:
- enable: False # see https://github.com/bioconda/bioconda-recipes/pull/57971
+ enable: True # see https://github.com/bioconda/bioconda-recipes/pull/57971
diff --git a/jakku/toolsiuc_tools/pcdl/pcdl_get_anndata.xml b/jakku/toolsiuc_tools/pcdl/pcdl_get_anndata.xml
index 57da49d..5b80cea 100644
--- a/jakku/toolsiuc_tools/pcdl/pcdl_get_anndata.xml
+++ b/jakku/toolsiuc_tools/pcdl/pcdl_get_anndata.xml
@@ -115,8 +115,8 @@
Function to transform mcds time steps into one or many anndata objects for downstream analysis.
Scale parameter details: Possible values are None, maxabs, minmax, std.
-None: no scaling. Set scale to None if you would like to have raw data or entirely scale, transform, and normalize the data later.
-Maxabs: maximum absolute value distance scaler will linearly map all values into a [-1, 1] interval. If the original data has no negative values, the result will be the same as with the minmax scaler (except with attributes with only one value). If the attribute has only zeros, the value will be set to 0.
+None: no scaling. Set scale to None if you would like to have raw data or entirely scale, transform, and normalize the data later.
+Maxabs: maximum absolute value distance scaler will linearly map all values into a [-1, 1] interval. If the original data has no negative values, the result will be the same as with the minmax scaler (except with attributes with only one value). If the attribute has only zeros, the value will be set to 0.
Minmax: minimum maximum distance scaler will map all values linearly into a [0, 1] interval. If the attribute has only one value, the value will be set to 0.
Std: standard deviation scaler will result in sigmas. Each attribute will be mean centered around 0. Ddof delta degree of freedom is set to 1 because it is assumed that the values are samples out of the population and not the entire population. It is incomprehensible to me that the equivalent sklearn method has ddof set to 0. If the attribute has only one value, the value will be set to 0.
diff --git a/jakku/toolsiuc_tools/pcdl/pcdl_macros.xml b/jakku/toolsiuc_tools/pcdl/pcdl_macros.xml
index ac6b555..dd88505 100644
--- a/jakku/toolsiuc_tools/pcdl/pcdl_macros.xml
+++ b/jakku/toolsiuc_tools/pcdl/pcdl_macros.xml
@@ -229,18 +229,19 @@
+
+
+
+ -->
-
+
^[a-zA-Z0-9_\-.]*\.vtp$
-
+
^[a-zA-Z0-9_\-.]*\.vtr$
diff --git a/man/HOWTO.md b/man/HOWTO.md
index 16bc416..85e726b 100644
--- a/man/HOWTO.md
+++ b/man/HOWTO.md
@@ -152,8 +152,10 @@ Now you're rolling!
pyMCDS.py and the pyMCDS class is very lightweight.
Besides the python3 core library, this code has only matplotlib, numpy, pandas, scipy, and vtk library dependencies.\
-The pyMCDS class evolved into the pcdl.TimeStep class, which has additionally anndata dependency, which makes the library slightly heavier but much more powerful for downstream data analysis.
+The pyMCDS class evolved into the pcdl.TimeStep class, which has additionally dependency (like anndata, muspan, and spatialdata), which makes the library slightly heavier but much more powerful for downstream data analysis.
Apart from that, pcdl offers the pcdl.TimeSeries class to handle the mcds snapshots from an entire PhysiCell run, and a set of functions that can be run straight from the command line, without even having to fire up a python3 shell.
Finally, branch version 4 broke with this ancient library structure because it is just out of time to run the code like this.\
+
diff --git a/man/REFERENCE.md b/man/REFERENCE.md
index 06d04c3..2395a81 100644
--- a/man/REFERENCE.md
+++ b/man/REFERENCE.md
@@ -38,15 +38,18 @@ Basically, there are four types of functions:
+ plot_ : plot functions generate a matplotlib figure, or axis object, or file output (jpeg, png, tiff), depending on your parameter settings.
### TimeStep initialize
+
+ [help(pcdl.TimeStep.\_\_init\_\_)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcds.__init__.md) #! workhorse function
+ [help(mcds.custom_data_astype)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcds.custom_data_astype.md) #! workhorse function
+ [help(mcds.set_verbose_false)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcds.set_verbose_false.md) #! workhorse function
+ [help(mcds.set_verbose_true)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcds.set_verbose_true.md) #! workhorse function
++ [help(mcds.render_neuroglancer)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcds.render_neuroglancer.md)
### TimeStep medata
+
*version*
+ [help(mcds.get_multicellds_version)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcds.get_multicellds_version.md) #! workhorse function
-+ [help(mcds.get_pcdl_version)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcds.get_pcdl_version.md) #! workhorse function
++ [help(mcds.get_pcdl_version)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcds.get_pcdl_version.md)
+ [help(mcds.get_physicell_version)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcds.get_physicell_version.md) #! workhorse function
*time*
@@ -58,6 +61,7 @@ Basically, there are four types of functions:
+ [help(mcds.get_unit_dict)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcds.get_unit_dict.md)
### TimeStep mesh
+
*range and axis*
+ [help(mcds.get_voxel_ijk_range)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcds.get_voxel_ijk_range.md)
+ [help(mcds.get_mesh_mnp_range)](https://github.com/elmbeech/physicelldataloader/blob/master/man/docstring/mcds.get_mesh_mnp_range.md)
@@ -78,7 +82,8 @@ Basically, there are four types of functions:
+ [help(mcds.get_voxel_volume)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcds.get_voxel_volume.md)
+ [help(mcds.get_voxel_ijk)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcds.get_voxel_ijk.md)
-### TimeStep microenvironment
+### TimeStep substarte
+
+ [help(mcds.get_substrate_list)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcds.get_substrate_list.md) #! workhorse function
+ [help(mcds.get_substrate_dict)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcds.get_substrate_dict.md)
+ [help(mcds.get_substrate_df)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcds.get_substrate_df.md)
@@ -87,30 +92,30 @@ Basically, there are four types of functions:
+ [help(mcds.make_conc_vtk)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcds.make_conc_vtk.md) #! workhorse function
### TimeStep cells
+
+ [help(mcds.get_celltype_list)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcds.get_celltype_list.md) #! workhorse function
+ [help(mcds.get_celltype_dict)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcds.get_celltype_dict.md)
+ [help(mcds.get_cell_df)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcds.get_cell_df.md) #! workhorse function
-+ [help(mcds.plot_scatter)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcds.plot_scatter.md) #! workhorse function
-+ [help(mcds.make_cell_vtk)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcds.make_cell_vtk.md) #! workhorse function
++ [help(mcds.get_cell_attribute_list)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcdsts.get_cell_attribute_list.md) #! workhorse function
+ [help(mcds.get_anndata)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcds.get_anndata.md) #! workhorse function
-
-### TimeStep cell graph
+ [help(mcds.get_attached_graph_dict)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcds.get_attached_graph_dict.md)
+ [help(mcds.get_neighbor_graph_dict)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcds.get_neighbor_graph_dict.md)
++ [help(mcds.get_spring_graph_dict)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcds.get_spring_graph_dict.md)
++ [help(mcds.plot_scatter)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcds.plot_scatter.md) #! workhorse function
++ [help(mcds.make_cell_vtk)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcds.make_cell_vtk.md) #! workhorse function
+ [help(mcds.make_graph_gml)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcds.make_graph_gml.md) #! workhose function
-### TimeStep microenvironment and cells
+### TimeStep substarte and cells
+
+ [help(mcds.get_muspan)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcds.get_muspan.md) #! workhose function
+ [help(mcds.get_spatialdata)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcds.get_spatialdata.md) #! workhose function
+ [help(mcds.make_ome_tiff)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcds.make_ome_tiff.md) #! workhose function
-+ [help(mcds.make_neuroglancer)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcds.make_neuroglancer.md) #! workhose function
### TimeStep internal functions
-+ [help(pcdl.scaler)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/pcdl.scaler.md) # anndata
-+ [help(pcdl.graphfile_parser)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/pcdl.graphfile_parser.md) # mcds
+
```python3
-help(pcdl.TimeStep._read_xml)
help(pcdl.TimeStep._anndextract)
+help(pcdl.TimeStep._read_xml)
```
@@ -119,63 +124,76 @@ help(pcdl.TimeStep._anndextract)
Basically, there are four types of functions:
+ set_ : set a python3 variable.
+ get_ : recall a python3 variable.
-+ make_ : make functions generate file output (gif, gml, mp4, ome.tiff, vtk).
++ make_ : make functions generate file output (gif, gml, mp4, ome.tiff, simularium, vtk).
+ plot_ : plot functions generate a matplotlib figure, or axis object, or file output (jpeg, png, tiff), depending on your parameter settings.
### TimeSeries initialization
+ [help(pcdl.TimeSeries.\_\_init\_\_)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcdsts.__init__.md) #! workhosefunction
-+ [help(mcdsts.get_xmlfile_list)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcdsts.get_xmlfile_list.md) #! workhosefunction
-+ [help(mcdsts.read_mcds)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcdsts.read_mcds.md)
-+ [help(mcdsts.get_mcds_list)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcdsts.get_mcds_list.md) #! workhose function
-+ [help(mcdsts.get_annmcds_list)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcdsts.get_annmcds_list.md) #! workhose function
+ [help(mcdsts.custom_data_astype)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcdsts.custom_data_astype.md) #! workhorse function
+ [help(mcdsts.set_verbose_false)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcdsts.set_verbose_false.md) #! workhorse function
+ [help(mcdsts.set_verbose_true)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcdsts.set_verbose_true.md) #! workhorse function
++ [help(mcdsts.render_neuroglancer)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcdsts.render_neuroglancer.md)
+
+### TimeSeries load data
+
++ [help(mcdsts.get_xmlfile_list)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcdsts.get_xmlfile_list.md) #! workhosefunction
++ [help(mcdsts.read_mcds)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcdsts.read_mcds.md)
++ [help(mcdsts.get_mcds_list)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcdsts.get_mcds_list.md) #! workhose function
+
+### TimeSeries substrate
-### TimeSeries microenvironment
+ [help(mcdsts.get_conc_df)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcdsts.get_conc_df.md) #! workhorse function
+ [help(mcdsts.get_conc_attribute)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcdsts.get_conc_attribute.md) #! workhorse function
+ [help(mcdsts.plot_contour)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcdsts.plot_contour.md) # !workhorse function
+ [help(mcdsts.make_conc_vtk)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcdsts.make_conc_vtk.md) #! workhorse function
### TimeSeries cells
+
+ [help(mcdsts.get_cell_df)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcdsts.get_cell_df.md) #! workhorse function
+ [help(mcdsts.get_cell_attribute)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcdsts.get_cell_attribute.md) #! workhorse function
++ [help(mcdsts.get_anndata)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcdsts.get_anndata.md) #! workhorse function
++ [help(mcdsts.get_annmcds_list)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcdsts.get_annmcds_list.md) #! workhose function
+ [help(mcdsts.plot_scatter)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcdsts.plot_scatter.md) # !workhorse function
+ [help(mcdsts.make_cell_vtk)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcdsts.make_cell_vtk.md) #! workhorse function
-+ [help(mcdsts.get_anndata)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcdsts.get_anndata.md) #! workhorse function
++ [help(mcdsts.make_graph_gml)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcdsts.make_graph_gml.md) #! workhose function
++ [help(mcdsts.make_simularium)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcdsts.make_simularium.md)
-### TimeSeries cell graph
-+ [help(mcdsts.get_graph_gml)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcdsts.make_graph_gml.md) #! workhose function
+### TimeSteries substrate and cells
-### TimeSteries microenvironment and cells
+ [help(mcdsts.get_muspan)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcdsts.get_muspan.md) #! workhose function
+ [help(mcdsts.get_spatialdata)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcdsts.get_spatialdata.md) #! workhose function
-+ [help(mcdsts.make_ome_tiff)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcdsts.make_ome_tiff.md) #! workhose function
-+ [help(mcdsts.make_neuroglancer)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcdsts.make_neuroglancer.md) #! workhose function
-
-### Timeseries timeseries
++ [help(mcdsts.get_sdmcds_list)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcdsts.get_sdmcds_list.md) #! workhose function
+ [help(mcdsts.plot_timeseries)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcdsts.plot_timeseries.md) #! workhorse function
++ [help(mcdsts.make_ome_tiff)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/mcdsts.make_ome_tiff.md) #! workhose function
### TimeSeries making movies
-+ [help(pcdl.make_gif)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/pcdl.make_gif.md) # ! workhorse function
-+ [help(pcdl.make_movie)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/pcdl.make_movie.md) # ! workhorse function
-+ [help(mcdsts.make_gif)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/pcdl.make_gif.md) # ! workhorse function
-+ [help(mcdsts.make_movie)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/pcdl.make_movie.md) # ! workhorse function
+
++ [help(mcdsts.make_gif)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/pcdl.make_gif.md) # physicell basics
++ [help(mcdsts.make_movie)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/pcdl.make_movie.md) # physicell basics
### TimeSeries internal functions
-+ [help(pcdl.scaler)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/pcdl.scaler.md) # anndata
```python3
help(pcdl.TimeSeries._handle_magick)
-help(pcdl.TimeSeries._anndextract)
```
+### pcdl module level ###
+
++ pcdl.\_\_version\_\_ # loaded pcdl version
++ [help(pcdl.graphfile_parser)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/pcdl.graphfile_parser.md) # mcds
++ [help(pcdl.make_gif)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/pcdl.make_gif.md) # physicell basics
++ [help(pcdl.make_movie)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/pcdl.make_movie.md) # physicell basics
++ pcdl.pccmap # officical PhysiCell color map
++ [help(pcdl.render_neuroglancer)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/ocdl.render_neuroglancer.md)
++ [help(pcdl.scaler)](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/pcdl.scaler.md) # anndata
+
+
# Command line
The command line interface functions mimic the name and parameter arguments as closely as possible to the related python3 functions.
### Command line metadata
+
*version*
+ [pcdl_get_version --help](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/pcdl_get_version.md) #! workhorse function
@@ -183,33 +201,35 @@ The command line interface functions mimic the name and parameter arguments as c
+ [pcdl_get_unit_dict --help](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/pcdl_get_unit_dict.md)
### Command line microenvironment
+
+ [pcdl_get_substrate_list --help](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/pcdl_get_substrate_list.md) #! workhorse function
-+ [pcdl_get_conc_attribute --help](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/pcdl_get_conc_attribute.md) #! workhorse function
+ [pcdl_get_conc_df --help](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/pcdl_get_conc_df.md) #! workhorse function
++ [pcdl_get_conc_attribute --help](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/pcdl_get_conc_attribute.md) #! workhorse function
+ [pcdl_plot_contour --help](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/pcdl_plot_contour.md) #! workhorse function
+ [pcdl_make_conc_vtk --help](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/pcdl_make_conc_vtk.md) #! workhorse function
### Command line cells
+
+ [pcdl_get_celltype_list --help](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/pcdl_get_celltype_list.md) #! workhorse function
-+ [pcdl_get_cell_attribute --help](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/pcdl_get_cell_attribute.md) #! workhorse function
+ [pcdl_get_cell_df --help](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/pcdl_get_cell_df.md) #! workhorse function
++ [pcdl_get_cell_attribute --help](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/pcdl_get_cell_attribute.md) #! workhorse function
++ [pcdl_get_cell_attribute_list --help](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/pcdl_get_cell_attribute_list.md) #! workhorse function
+ [pcdl_get_anndata --help](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/pcdl_get_anndata.md) #! workhorse function
+ [pcdl_plot_scatter --help](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/pcdl_plot_scatter.md) #! workhorse function
+ [pcdl_make_cell_vtk --help](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/pcdl_make_cell_vtk.md) #! workhorse function
-
-### Command line cell graph
+ [pcdl_make_graph_gml --help](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/pcdl_make_graph_gml.md) #! workhorse function
++ [pcdl_make_simularium --help](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/pcdl_make_simularium.md)
### Command line cells and microenvironment
+
+ [pcdl_get_muspan --help](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/pcdl_get_muspan.md) #! workhorse function
+ [pcdl_get_spatialdata --help](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/pcdl_get_spatialdata.md) #! workhorse function
-+ [pcdl_make_ome_tiff --help](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/pcdl_make_ome_tiff.md) #! workhorse function
-+ [pcdl_make_neuroglancer --help](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/pcdl_make_neuroglancer.md) #! workhorse function
-
-### Command line timeseries
+ [pcdl_plot_timeseries --help](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/pcdl_plot_timeseries.md) #! workhorse function
++ [pcdl_make_ome_tiff --help](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/pcdl_make_ome_tiff.md) #! workhorse function
### Command line making movies
-+ [pcdl_make_gif --help](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/pcdl_make_gif.md) #! workhorse function
-+ [pcdl_make_movie --help](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/pcdl_make_movie.md) #! workhorse function
+
++ [pcdl_make_gif --help](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/pcdl_make_gif.md) #! physicell basics
++ [pcdl_make_movie --help](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/pcdl_make_movie.md) #! physicell basics
++ [pcdl_render_neuroglancer --help](https://github.com/elmbeech/physicelldataloader/tree/master/man/docstring/pcdl_render_neuroglancer.md)
diff --git a/man/RELEASENOTES.md b/man/RELEASENOTES.md
new file mode 100644
index 0000000..bc17bc4
--- /dev/null
+++ b/man/RELEASENOTES.md
@@ -0,0 +1,299 @@
+## Release Notes:
+
++ branch v4: active feature development, bug fixes, and security maintenance.
+
++ version 4.1.9 (2026-08-28): elmbeech/physicelldataloader
+ + new TimeSeries **make_simularium** and **pcdl_make_simularium** function. special thanks to Randy Heiland!
+
++ version 4.1.8 (2026-08-26): elmbeech/physicelldataloader
+ + branch v4 compatible with bioconda and galaxy. special thanks to Björn Grüning!
+
++ version 4.1.7 (2026-08-21): elmbeech/physicelldataloader
+ + compatible with pandas v3.0.0.
+
++ version 4.1.6 (2026-08-20): elmbeech/physicelldataloader
+ + pcdl installs now by default lightweight with only the core dependencies; users are prompted to install optional libraries if necessary. special thanks to Heber Rocha!
+
++ version 4.1.5 (2026-04-05): elmbeech/physicelldataloader
+ + bugfix library dependencies and library versions.
+
++ version 4.1.4 (2026-04-04): elmbeech/physicelldataloader
+ + TimeSeries **mcdsts.make_contour** extrema parameter is replaced by vmin and vmax to be compatible with mcds.make\_contour and plt.contour.
+ + **make_cell_vtk** and **make_conc_vtk** now offer an ext parameter, allowing to manually specify the exact file extension. special thanks to Danyon Gedris!
+ + new **make_muspan** TimeStep class and TimeSeries class function and **pcdl_get_muspan** command line command. special thanks to Joshua Moore and Joshua Bull!
+
++ version 4.1.3 (2026-03-21): elmbeech/physicelldataloader
+ + new **pcdl.pccmap** color map. this is an adaptation of the physicell pathology paint by number color map.
+ + new TimeStep **get_pcdl_version** function.
+
++ version 4.1.2 (2026-03-06): elmbeech/physicelldataloader
+ + new **custom_data_astype** TimeStep class and TimeSeries class function to set the dtype of custom\_data variables even after the timestep or timeseries is loaded.
+ + TimeSeries \_\_init\_\_ function can now handle a list of TimeStep objects as input instead of a path.
+
++ version 4.1.1 (2026-02-28): elmbeech/physicelldataloader
+ + reduced memory footprint.
+
++ version 4.1.0 (2025-12-31): elmbeech/physicelldataloader
+ + new **get_spatialdata** TimeStep class and TimeSeries class function and **pcdl_get_spatialdata** command line command. special thanks to Luca Marconato!
+ + with this release, pcdl officially became an [scverse ecosystem](https://scverse.org/packages/#ecosystem) package.
+
++ version 4.0.5 (2025-10-22): elmbeech/physicelldataloader
+ + **settingxml** default is now set to False, because the cell\_type id label mapping can, in recent PhysiCell output, be retrieved from output\*.xml too.
+ + **plot_scatter** and **plot_timeseries** now additionally have a cat\_drop and cat\_keep argument to filter categorical data.
+ + **plot_timeseries(frame=conc)** now plots by default all substrate concentrations over time.
+ + **plot_timeseries(ext=)** parameter offers to return a dataframe object, dafaframe csv file, image file, or a matplotlib fig object. special thanks to John Nardini and Edward Young!
+
++ version 4.0.4 (2025-07-23): elmbeech/physicelldataloader
+ + command line commands now return **error code 0** if the command runs successfully.
+
++ version 4.0.3 (2025-07-20): elmbeech/physicelldataloader
+ + TimeStep and TimeSeries **plot_contour**, **plot_scatter**, and **plot_timeseries** handle now **kwargs** arguments.
+ + minor bugfixes.
+
++ version 4.0.2 (2025-06-29): elmbeech/physicelldataloader
+ + minor bugfixes.
+
++ version 4.0.1 (2025-06-24): elmbeech/physicelldataloader
+ + man updated.
+ + minor bugfixes.
+
++ version 4.0.0 (2025-05-13): elmbeech/physicelldataloader
+ + v4 was forked from v3.3.4!
+ + **mcds.data** struct was rewritten in more python less c++ way.
+ + pyMCDS.py and part of pyAnnData.py was fused to **timestep.py**.
+ + pyMCDSts.py and part of pyAnnData.py was fused to **timeseries.py**.
+ + pyCLI.py was renames to **commandline.py**.
+ + data\_timeseries.py was renamed to **output_data.py**.
+ + TimeStep function **get_concentration** was deprecated because pandas already has this functionlity.
+ + TimeStep function **get_concentration_at** was deprecated because pandas already has this functionlity.
+ + TimeStep function **get_cell_df_at** was deprecated because pandas already has this functionlity.
+ + **make_conc_vtk** and **make_cell_vtk** on the fly visualization was removed because paraview is good enough.
+ + new TimeStep **get_cell_attribute_list** function, to retrieve a list of all tracked cell attribute labels.
+ + new **pcdl_get_cell_attribute_list** function, to retrieve a list of all tracked cell attribute labels.
+ + new **render_neuroglancer** function, to render ome tiff image into neuroglancer.
+ + new **pcdl_render_neuroglancer** function, to render ome tiff images into neuroglancer.
+
+
++ branch v3: end-of-life reached.
+
++ version 3.3.8 (2025-07-23): elmbeech/physicelldataloader
+ + command line commands now return **error code 0** if the command runs successfully.
+
++ version 3.3.7 (2025-06-01): elmbeech/physicelldataloader
+ + compatible with current (non end-of-life cycle) python versions.
+ + minor bugfixes.
+
++ version 3.3.6 (2025-05-13): elmbeech/physicelldataloader
+ + compatible with numpy >= 2.0.0 and current (non end-of-life cycle) python versions.
+
++ version 3.3.5 (2025-05-13): elmbeech/physicelldataloader
+ + compatible with numpy < 2.0.0 and current (non end-of-life cycle) python versions.
+ + remove pyMCDS and pyMCDSts **make_ome_tiff** and pyCLI **pcdl_make_ome_tiff** to make pyMCS.py stand alone again.
+ + new TimeStep **get_cell_attribute_list** function, to retrieve a list of all tracked cell attribute labels.
+ + new **pcdl_get_cell_attribute_list** function, to retrieve a list of all tracked cell attribute labels.
+
++ version 3.3.4 (2025-03-07): elmbeech/physicelldataloader
+ + replace the **aicsimageio** library dependency with its successor **bioio**. special thanks to Joel Eliason!
+ + **make_ome_tiff** can now handel generated file names with > 255 characters. special thank to Genevieve Stein-O'Brien and DanielBergman!
+ + **get_mesh_spacing** handels now an edge case correctly that would have resulted in a division by zero. special thanks to Randy Heiland!
+
++ version 3.3.3 (2025-01-10): elmbeech/physicelldataloader
+ + bug fix **plot_contour** plot orientation. special thanks to Marco Ruscone!
+ + add test data for new improved **unittest physicell model**. special thanks to Nick Oldfather!
+ + add pyMCDS **make_conc_vtk** on the fly visualization. special thanks to Randy Heiland and Nick Oldfather!
+ + pyMCDS and pyMCDSts **make_graph_gml** and pyAnnData **get_anndata** handles now spring\_attached\_cells graph too.
+
++ version 3.3.2 (2024-11-24): elmbeech/physicelldataloader
+ + **Warnings** will no longer be piped to standard output if verbose is set to False.
+ + pyMCDS **make_ome_tiff** function rewriten to be less RAM hungry and more versatile.
+
++ version 3.3.1 (2024-09-22): elmbeech/physicelldataloader
+ + bugfix pyMCDS custom vectors loading.
+
++ version 3.3.0 (2024-08-22): elmbeech/physicelldataloader
+ + **pip install pcdl**: will again install all library dependencies. The fine-tuned version was too confssing.
+ + pyMCDS handels now intracellular **physinboss** data too; data is stored in cell\_df.
+ + rename pyMCDS get\_cell\_variables to **get_celltype_list** for conciseness and order list by ID.
+ + rename pyMCDS get\_substrate\_names to **get_substrate_list** for conciseness and order list by ID.
+ + rename pyMCDS get\_scatter to **plot_scatter** for conciseness.
+ + rename pyMCDS get\_contour to **plot_contour** for conciseness.
+ + rename pyMCDSts make\_imgcell to **plot_scatter** for conciseness.
+ + rename pyMCDSts make\_imgconc to **plot_contour** for conciseness.
+ + rename pyMCDSts get\_cell\_df\_states to **get_cell_attribute** for conciseness.
+ + rename pyMCDSts get\_conc\_df\_states to **get_conc_attribute** for conciseness.
+ + rewrite pyMCDS mcds.get\_unit\_se into **mcds.get_unit_dict**.
+ + new pyCLI **pcdl_get_anndata** command line interface function.
+ + new pyCLI **pcdl_get_celltype_list** command line interface function.
+ + new pyCLI **pcdl_get_cell_attribute** command line interface function.
+ + new pyCLI **pcdl_get_cell_df** command line interface function.
+ + new pyCLI **pcdl_get_substrate_list** command line interface function.
+ + new pyCLI **pcdl_get_conc_attribute** command line interface function.
+ + new pyCLI **pcdl_get_conc_df** command line interface function.
+ + new pyCLI **pcdl_get_graph_gml** command line interface function.
+ + new pyCLI **pcdl_get_unit_dict** command line interface function.
+ + new pyCLI **pcdl_get_version** command line interface function.
+ + new pyCLI **pcdl_make_cell_vtk** command line interface function.
+ + new pyCLI **pcdl_make_conc_vtk** command line interface function.
+ + new pyCLI **pcdl_make_gif** command line interface function.
+ + new pyCLI **pcdl_make_movie** command line interface function.
+ + new pyCLI **pcdl_make_ome_tiff** command line interface function.
+ + new pyCLI **pcdl_plot_contour** command line interface function.
+ + new pyCLI **pcdl_plot_scatter** command line interface function.
+ + new pyCLI **pcdl_plot_timeseries** command line interface function.
+ + new pyMCDS **mcds.get_mesh_mnp** function, the mesh version from mcds.get\_voxel\_ijk.
+ + new pyMCDS **make_conc_vtk** function, to save substrate data as rectilinear grid vtk file.
+ + new pyMCDS **make_cell_vtk** function, to save cell data as glyph vtk file.
+ + new pyMCDS **make_graph_gml** function, to save graphs in a networkx and igraph compatible file format.
+ + new pyMCDS **make_ome_tiff** function, to save the output data in ome tiff file format.
+ + new pyMCDS **set_verbosity_true** function, to complete pcdl.TimeStep(verbosity=True/False) experience.
+ + new pyMCDS **set_verbosity_false** function, to complete pcdl.TimeStep(verbosity=True/False) experience.
+ + new pyMCDSts **get_cell_df** function, to extract one big dataframe or a list of dataframes from the whole time series.
+ + new pyMCDSts **get_conc_df** function, to extract one big dataframe or a list of dataframes from the whole time series.
+ + new pyMCDSts **make_cell_vtk** function, to save substrate data as rectilinear grid vtk files. special thanks to Furkan Kurtoglu!
+ + new pyMCDSts **make_conc_vtk** function, to save cell data as glyph vtk files. special thanks to Furkan Kurtoglu!
+ + new pyMCDSts **make_graph_gml** function, to save graphs in a networkx and igraph compatible files format. special thanks to Benjamin Jacobs!
+ + new pyMCDSts **make_ome_tiff** function, to save the output data in ome tiff file format.
+ + new pyMCDSts **plot_timeseries** function, to plot time series. special thanks to Thierry-Pascal Fleurant!
+ + new pyMCDSts **set_verbosity_true** function, to complete the pcdl.TimeSeries(verbosity=True/False) experience.
+ + new pyMCDSts **set_verbosity_false** function to complete the pcdl.TimeSeries(verbosity=True/False) experience.
+
++ version 3.2.13 (2023-09-18): elmbeech/physicelldataloader
+ + rename pyMCDSts make\_imgsubs to **make_imgconc** for consistency.
+ + add **man/lecture/20230917_pcdl_repl_programming_analysis_plots.pdf** slide deck.
+
++ version 3.2.12 (2023-08-12): elmbeech/physicelldataloader
+ + add **man/jupyter/pcdl_repl_programming.ipynb** : Jupyter notebook to give an idea about how to work with pcdl in a python3 REPL.
+ + add **man/lecture/20230808_pcws2023_session07_pcdl.pdf** slide deck.
+ + add github **continuous integration** for all supported python3 versions, all supported operating systems.
+
++ version 3.2.11 (2023-08-08): elmbeech/physicelldataloader
+ + **pip install pcdl**: will only install the bare minimum library dependencies.
+ + **pip install pcdl[data]**: will install the minimum dependencies plus the dependencies to download the test dataset.
+ + **pip install pcdl[scverse]**: will install the minimum dependencies plus the dependencies needed to generate an anndata object.
+ + **pip install pcdl[all]**: will always install all dependencies.
+ + new TimeSeries **get_annmcds_list** function, which points to the self.l\_annmcds object.
+ + new pyMCDS **get_scatter** function is split off from pyMCDSts make\_imgcell.
+ + pyMCDSts **make_imgcell** and **make_imgsubs** bug fixes.
+ + TimeStep and TimeSeries **get_anndata** evolution.
+
++ version 3.2.10 (2023-07-24): elmbeech/physicelldataloader
+ + rename pyMCDSts get\_cell\_df\_columns\_states to **get_cell_df_states** for conciseness.
+ + rename pyMCDSts get\_conc\_df\_columns\_states to **get_conc_df_states** for conciseness.
+
++ version 3.2.9 (2023-07-23): elmbeech/physicelldataloader
+ + new class **TimeStep** can do everything pyMCDS can do and more.
+ + new class **TimeSeries** can do everything pyMCDSts can do and more.
+ + new TimeStep **get_anndata** function to transform physicell output into [AnnData](https://anndata.readthedocs.io/en/latest/) objects.
+ + new TimeSeries **get_anndata** function to transform physicell output into [AnnData](https://anndata.readthedocs.io/en/latest/) objects.
+ + internal pyAnnData **scaler** function.
+ + internal pyAnnData **\_anndextract** function.
+ + pyMCDS **_\_init__** seetingxml parameter changed from boolean to string to accept other PhysiCell\_settings.xml filenames than the default.
+ + pyMCDS **get_cell_df** drop and keep parameters to declare a set of columns to be dropped or kept.
+ + pyMCDS **get_conc_df** drop and keep parameters to declare a set of columns to be dropped or kept.
+ + new pyMCDS **get_conc_df** shorthand for get\_concentration\_df.
+ + pyMCDSts get\_cell\_minstate\_col reimplementation as **get_cell_df_columns_states** function.
+ + pyMCDSts get\_concentartion\_minstate\_col reimplementation as **get_conc_df_columns_states** function.
+ + new pyMCDSts **get_mcds_list** function which points to the self.l\_mcds object.
+
++ version 3.2.8 (2023-06-21): elmbeech/physicelldataloader
+ + pyMCDS **get_concentration_df** states parameter to filter out non-informative variables.
+ + pyMCDS **get_cell_df** states parameter to filter out non-informative variables.
+ + pyMCDSts **_\_init__** load parameter to specify if the whole time series data straight at object initialization should be loaded.
+ + new pyMCDSts **get_cell_minstate_col** function to scan the whole time series for informative attributes.
+ + new pyMCDSts **get_concentartion_minstate_col** function to scan the whole time series for informative attributes.
+
++ version 3.2.7 (2023-06-20): elmbeech/physicelldataloader
+ + pyMCDS and pyMCDSts **_\_init__** custom\_type parameter to specify other custom\_data variable types (int, bool, str) then the generic float.
+
++ version 3.2.5 (2023-06-19): elmbeech/physicelldataloader
+ + pyMCDS resolves incompatibility with earlier PhysiCell and MultiCellDS versions.
+
++ version 3.2.4 (2023-06-17): elmbeech/physicelldataloader
+ + pyMCDS **_\_init__** seetingxml parameter for cases where in the output folder no PhysiCell\_settings.xml can be found.
+ + pyMCDSts **mcdsts.make_imgcell** extrema parameter is replaced by the z\_axis parameter to account for numerical and categorical variable types.
+
++ version 3.2.2 (2023-06-16): elmbeech/physicelldataloader
+ + pyMCDS **mcds.get_cell_df** sets distinct boolean, categorical, integer number, and real number variable types. categorical number codes are translated. for all spatial variables, the vector length value is calculated and added automatically.
+ + new pyMCDS **mcds.get_celltype_dict** function.
+ + new pyMCDS **mcds.get_substrate_dict** function.
+ + pyMCDSts **mcdsts.make_imgcell** and **mcdsts.make_imgsubs** functions improved.
+
++ version 3.2.1 (2023-06-12): elmbeech/physicelldataloader
+ + pypa odyssey is coming to an end.
+ + change build system from setuptools to hatching.
+ + change the library name from pcDataLoader to pcdl.
+ + to make the library installation more lightweight, test data was excluded from the basic installation.
+ given the computer is connected to the internet, test data can easily be installed and removed with the **pcdl.install_data()** and **pcdl.uninstall_data()** functions now.
+
++ version 3.0.7 (2023-06-08): elmbeech/physicelldataloader
+ + pyMCDSts: replaces the svg dependent **mcdsts.make_jpeg**, **mcdsts.make_png**, and **mcdsts.make_tiff** with **mcdsts.make_imgcell** and **mcdsts.make_imgsubs** which generate images straight out of the loaded data. the **mcdsts.make_gif** and **mcdsts.make_movie** functions were adjusted accordingly. special thanks to Marshal Gress!
+ + pyMCDSts: **mcdsts.read_mcds** loads now automatically all mcds snapshots if no xmlfile\_list is provided (default).
+
++ version 3.0.6 (2023-04-29): elmbeech/physicelldataloader
+ + pyMCDS **\_read_xml** is now able to load time steps with zero cells.
+ + pyMCDS **mcds.get_contour** can handle more input parameters.
+
++ version 3.0.5 (2023-02-26): elmbeech/physicelldataloader pyMCDS **mcds.get_contour** plots span now the whole domain and not only to the border voxel centers.
++ version 3.0.4 (2023-02-21): elmbeech/physicelldataloader pyMCDS **mcds.get_contour** function, to easily generate for substrates matplotlib contourf and contour plots because they do not exist as pandas plots.
++ version 3.0.3 (2023-02-19): elmbeech/physicelldataloader branch 3 has no longer anndata and, as such, hdf5 dependency.
++ version 3.0.2 (2023-01-06): elmbeech/physicelldataloader bugfix installing package data.
++ version 3.0.0 (2023-01-06): elmbeech/physicelldataloader
+ + **pyMCDS** parameter **xml_file** can now handle path/file.xml (unix) or path\file.xml (dos) input, as long output_path is the default.
+ + **pyMCDS** has a new additional boolean **microenv** parameter, to specify if the microenvironment (substrates) should be read (for completeness) or not (for speed increase and less memory usage).
+ + **pyMCDS** has a new additional boolean **graph** parameter, to specify if the attached and neighbor graph should be read.
+ + **pyMCDS** has a new additional boolean **verbose** parameter, to specify if there should be text output while processing.
+ + pyMCDS **mcds.get_2D_mesh** was renamed to **mcds.get_mesh_2D** for consistency.
+ + pyMCDS **mcds.get_linear_voxels** was renamed to **mcds.get_mesh_coordinate** for consistency.
+ + pyMCDS **mcds.get_containing_voxel_ijk** was renamed to **mcds.get_voxel_ijk** for briefness.
+ + pyMCDS **mcds.get_voxel_spacing** returns now 3 specific values, one for x, y, and z, instead of 1 general value.
+ + pyMCDS **mcds.get_concentrations** was renamed to **mcds.get_concentration** for consistency
+ + pyMCDS **mcds.get_concentrations_at** was renamed to **mcds.get_concentration_at** for consistency
+ + pyMCDS **mcds.get_concentration_at** if z_slice is not a mesh center value, the function will by default adjust to the nearest and no longer break.
+ + pyMCDS **mcds.get_cell_variables** and **mcds.get_substrate_names** return now a strictly alphabetically ordered list.
+ + pyMCDS **mcds.get_cell_df** returns now a pandas dataframe with the cell IDs as the index and not as a column.
+ additionally, this dataframe contains now voxel, mesh_center, substrate parameter, substrate concentration, and cell density information too.
+ + new pyMCDS **mcds.get_concentration_df** function.
+ + new pyMCDS **mcds.get_substrate_df** function.
+ + new pyMCDS **mcds.get_unit_se** function.
+ + new pyMCDS **mcds.get_multicellds_version** function.
+ + new pyMCDS **mcds.get_physicell_version** function.
+ + new pyMCDS **mcds.get_runtime** function.
+ + new pyMCDS **mcds.get_timestamp** function.
+ + new pyMCDS **mcds.get_voxel_ijk_range** function.
+ + new pyMCDS **mcds.get_voxel_ijk_axis** function.
+ + new pyMCDS **mcds.get_voxel_spacing** function.
+ + new pyMCDS **mcds.get_voxel_volume** function.
+ + new pyMCDS **mcds.get_mesh_mnp_range** function.
+ + new pyMCDS **mcds.get_mesh_mnp_axis** function.
+ + new pyMCDS **mcds.get_xyz_range** function.
+ + new pyMCDS **mcds.is_in_mesh** function.
+ + new pyMCDS **mcds.get_attached_graph_dict** function.
+ + new pyMCDS **mcds.get_neigbor_graph_dict** function.
+ + class **pyMCDS_timeseries** was renamed to **pyMCDSts** and completely rewritten.
+ + new pyMCDSts **get_xmlfile_list** function.
+ + new pyMCDSts **read_mcds** function.
+ + new pyMCDSts **make_jpeg** function.
+ + new pyMCDSts **make_png** function.
+ + new pyMCDSts **make_tiff** function.
+ + new pyMCDSts **make_gif** function.
+ + new pyMCDSts **make_movie** function.
+ + all **plotting** functions were removed because pcdl only focuses on making the raw data in python3 easy to access for in-depth analysis.
+ + cell position coordinates are now constantly labeled as **x,y,z**, mesh center coordinates as **m,n,p**, and voxel coordinates as **i,j,k**.
+ + the underling [mcds object data dictionary structure](https://github.com/elmbeech/physicelldataloader/tree/master/man/img/physicelldataloader_data_dictionary_v3.0.0.png) has changed.
+ + [pytest](https://en.wikipedia.org/wiki/Pytest) unit tests exist now for all pyMCDS and pyMCDSts functions.
+
+
++ branch v2: end-of-life reached.
+
++ version 2.0.3 (2023-06-16): elmbeech/physicelldataloader pypa odyssey is coming to an end.
++ version 2.0.2 (2023-01-06): elmbeech/physicelldataloader reset patch voxel spacing bugfix, so that branch2 is full compatible with branch1 again. use branch3 for a bugfixed version!
++ version 2.0.1 (2022-11-08): elmbeech/physicelldataloader beta release patch voxel spacing bugfix.
++ version 2.0.0 (2022-08-30): elmbeech/physicelldataloader pip installable release, derived from and compatible with PhysiCell-Tools/python-loader release 1.1.0 (2022-07-20).
+
+
++ branch v1: end-of-life reached.
+
++ version 1.1.1 (2022-07-01): elmbeech/physicelldataloader deprecated np.float replaced with np.float64.
++ version 1.1.0 (2022-05-09): Physicell-Tools/python-loader release compatible with pre-v1.10.x of PhysiCell.
++ version 1.0.1 (2020-01-25): Physicell-Tools/python-loader time-series related bug fix.
++ version 1.0.0 (2019-09-28): Physicell-Tools/python-loader first public release!
diff --git a/man/ROADMAP.md b/man/ROADMAP.md
new file mode 100644
index 0000000..a71ae3a
--- /dev/null
+++ b/man/ROADMAP.md
@@ -0,0 +1,4 @@
+## Road Map:
+
++ [issue #12](https://github.com/elmbeech/physicelldataloader/issues/12): downcast, read, and save to\_pcd functions.
++ [issue #16](https://github.com/elmbeech/physicelldataloader/issues/16): lineage tree graph output files.
diff --git a/man/TUTORIAL_commandline.md b/man/TUTORIAL_commandline.md
index c82d3c9..45b600a 100644
--- a/man/TUTORIAL_commandline.md
+++ b/man/TUTORIAL_commandline.md
@@ -77,51 +77,51 @@ pcdl_get_substrate_list output/output00000000.xml
pcdl_get_substrate_list -h
```
-### ✨ pcdl\_get\_conc\_attribute
+### ✨ pcdl\_get\_conc\_df
-Generate a [json](https://en.wikipedia.org/wiki/JSON) file, that lists all substrate attributes.
-For each such attribute the min and the max value are listed.
+Generate a dataframe [csv](https://en.wikipedia.org/wiki/Comma-separated_values) file that lists one voxel per row,
+all substrate concentrations.
-In the example below:
-+ all substrates attributes are listed, that over the whole time series have at least 2 diffrent values.
-+ all substrates attributes are listed, that in this particular time step have at least 2 different values.
+In the example below, the generated csv contains:
++ all substrate concentration values over the whole time series.
++ all substrate that within this particular time step have more than 2 different concentration values.
```bash
-pcdl_get_conc_attribute output 2
+pcdl_get_conc_df output
```
```bash
-pcdl_get_conc_attribute output/output00000000.xml 2
+pcdl_get_conc_df output/output00000000.xml 2
```
```bash
-pcdl_get_conc_attribute -h
+pcdl_get_conc_df -h
```
Further readings:
-+ [TUTORIAL_python3_json.md](https://github.com/elmbeech/physicelldataloader/blob/master/man/TUTORIAL_python3_json.md)
++ [TUTORIAL_python3_pandas.md](https://github.com/elmbeech/physicelldataloader/blob/master/man/TUTORIAL_python3_pandas.md)
+ [TUTORIAL_r.md](https://github.com/elmbeech/physicelldataloader/blob/master/man/TUTORIAL_r.md)
+ [TUTORIAL_julia.md](https://github.com/elmbeech/physicelldataloader/blob/master/man/TUTORIAL_julia.md)
-### ✨ pcdl\_get\_conc\_df
+### ✨ pcdl\_get\_conc\_attribute
-Generate a dataframe [csv](https://en.wikipedia.org/wiki/Comma-separated_values) file that lists one voxel per row,
-all substrate concentrations.
+Generate a [json](https://en.wikipedia.org/wiki/JSON) file, that lists all substrate attributes.
+For each such attribute the min and the max value are listed.
-In the example below, the generated csv contains:
-+ all substrate concentration values over the whole time series.
-+ all substrate that within this particular time step have more than 2 different concentration values.
+In the example below:
++ all substrates attributes are listed, that over the whole time series have at least 2 diffrent values.
++ all substrates attributes are listed, that in this particular time step have at least 2 different values.
```bash
-pcdl_get_conc_df output
+pcdl_get_conc_attribute output 2
```
```bash
-pcdl_get_conc_df output/output00000000.xml 2
+pcdl_get_conc_attribute output/output00000000.xml 2
```
```bash
-pcdl_get_conc_df -h
+pcdl_get_conc_attribute -h
```
Further readings:
-+ [TUTORIAL_python3_pandas.md](https://github.com/elmbeech/physicelldataloader/blob/master/man/TUTORIAL_python3_pandas.md)
++ [TUTORIAL_python3_json.md](https://github.com/elmbeech/physicelldataloader/blob/master/man/TUTORIAL_python3_json.md)
+ [TUTORIAL_r.md](https://github.com/elmbeech/physicelldataloader/blob/master/man/TUTORIAL_r.md)
+ [TUTORIAL_julia.md](https://github.com/elmbeech/physicelldataloader/blob/master/man/TUTORIAL_julia.md)
@@ -183,20 +183,30 @@ pcdl_get_celltype_list output/output00000000.xml
pcdl_get_celltype_list -h
```
-### ✨ pcdl\_get\_cell\_attrribute\_list
+### ✨ pcdl\_get\_cell\_df
-Output all recorded cell attributes.
+Generate a dataframe [csv](https://en.wikipedia.org/wiki/Comma-separated_values) file that lists one cell per row,
+all attributes.
+
+In the example below, the generated csv contains:
++ all cell attributes, that over the whole time series have more than 2 different values.
++ from that particular time step all cell attributes available.
```bash
-pcdl_get_cell_attribute_list output
+pcdl_get_cell_df output 2
```
```bash
-pcdl_get_cell_attribute_list output/output00000000.xml
+pcdl_get_cell_df output/output00000000.xml
```
```bash
-pcdl_get_cell_attribute_list -h
+pcdl_get_cell_df -h
```
+Further readings:
++ [TUTORIAL_python3_pandas.md](https://github.com/elmbeech/physicelldataloader/blob/master/man/TUTORIAL_python3_pandas.md)
++ [TUTORIAL_r.md](https://github.com/elmbeech/physicelldataloader/blob/master/man/TUTORIAL_r.md)
++ [TUTORIAL_julia.md](https://github.com/elmbeech/physicelldataloader/blob/master/man/TUTORIAL_julia.md)
+
### ✨ pcdl\_get\_cell\_attribute
Generate a [json](https://en.wikipedia.org/wiki/JSON) file, that lists all cell attributes.
@@ -221,30 +231,20 @@ Further readings:
+ [TUTORIAL_r.md](https://github.com/elmbeech/physicelldataloader/blob/master/man/TUTORIAL_r.md)
+ [TUTORIAL_julia.md](https://github.com/elmbeech/physicelldataloader/blob/master/man/TUTORIAL_julia.md)
-### ✨ pcdl\_get\_cell\_df
-
-Generate a dataframe [csv](https://en.wikipedia.org/wiki/Comma-separated_values) file that lists one cell per row,
-all attributes.
+### ✨ pcdl\_get\_cell\_attrribute\_list
-In the example below, the generated csv contains:
-+ all cell attributes, that over the whole time series have more than 2 different values.
-+ from that particular time step all cell attributes available.
+Output all recorded cell attributes.
```bash
-pcdl_get_cell_df output 2
+pcdl_get_cell_attribute_list output
```
```bash
-pcdl_get_cell_df output/output00000000.xml
+pcdl_get_cell_attribute_list output/output00000000.xml
```
```bash
-pcdl_get_cell_df -h
+pcdl_get_cell_attribute_list -h
```
-Further readings:
-+ [TUTORIAL_python3_pandas.md](https://github.com/elmbeech/physicelldataloader/blob/master/man/TUTORIAL_python3_pandas.md)
-+ [TUTORIAL_r.md](https://github.com/elmbeech/physicelldataloader/blob/master/man/TUTORIAL_r.md)
-+ [TUTORIAL_julia.md](https://github.com/elmbeech/physicelldataloader/blob/master/man/TUTORIAL_julia.md)
-
### ✨ pcdl\_get\_anndata
From the whole time series or from a single time step, generate h5ad [anndata](https://anndata.readthedocs.io/en/latest/) [hd5](https://en.wikipedia.org/wiki/Hierarchical_Data_Format) files.
@@ -267,28 +267,6 @@ Further readings:
+ [TUTORIAL_r.md](https://github.com/elmbeech/physicelldataloader/blob/master/man/TUTORIAL_r.md)
+ [TUTORIAL_julia.md](https://github.com/elmbeech/physicelldataloader/blob/master/man/TUTORIAL_julia.md)
-### ✨ pcdl\_make\_graph\_gml
-
-Generate [gml](https://github.com/elmbeech/physicelldataloader/blob/master/man/publication/himsolt1996gml_a_portable_graph_file_format.pdf) files.
-One gml file per time step.
-
-Gml files can be read by graph analysis libraries like [networkx](https://networkx.org/) and [igraph](https://igraph.org/).
-
-```bash
-pcdl_make_graph_gml output/output00000000.xml --node_attribute cell_type dead oxygen pressure
-```
-```bash
-pcdl_make_graph_gml output
-```
-```bash
-pcdl_make_graph_gml -h
-```
-
-Further readings:
-+ [TUTORIAL_python3_graph.md](https://github.com/elmbeech/physicelldataloader/blob/master/man/TUTORIAL_python3_graph.md)
-+ [TUTORIAL_r.md](https://github.com/elmbeech/physicelldataloader/blob/master/man/TUTORIAL_r.md)
-+ [TUTORIAL_julia.md](https://github.com/elmbeech/physicelldataloader/blob/master/man/TUTORIAL_julia.md)
-
### ✨ pcdl\_plot\_scatter
Generate a [jpeg](https://en.wikipedia.org/wiki/JPEG) file that displaying all cells.
@@ -334,6 +312,51 @@ Further readings:
+ [TUTORIAL_python3_vtk.md](https://github.com/elmbeech/physicelldataloader/blob/master/man/TUTORIAL_python3_vtk.md)
+ [TUTORIAL_julia.md](https://github.com/elmbeech/physicelldataloader/blob/master/man/TUTORIAL_julia.md)
+### ✨ pcdl\_make\_graph\_gml
+
+Generate [gml](https://github.com/elmbeech/physicelldataloader/blob/master/man/publication/himsolt1996gml_a_portable_graph_file_format.pdf) files.
+One gml file per time step.
+
+Gml files can be read by graph analysis libraries like [networkx](https://networkx.org/) and [igraph](https://igraph.org/).
+
+```bash
+pcdl_make_graph_gml output/output00000000.xml --node_attribute cell_type dead oxygen pressure
+```
+```bash
+pcdl_make_graph_gml output
+```
+```bash
+pcdl_make_graph_gml -h
+```
+
+Further readings:
++ [TUTORIAL_python3_graph.md](https://github.com/elmbeech/physicelldataloader/blob/master/man/TUTORIAL_python3_graph.md)
++ [TUTORIAL_r.md](https://github.com/elmbeech/physicelldataloader/blob/master/man/TUTORIAL_r.md)
++ [TUTORIAL_julia.md](https://github.com/elmbeech/physicelldataloader/blob/master/man/TUTORIAL_julia.md)
+
+### ✨ pcdl\_make\_simularium
+
+Generate [simularium](https://simularium.allencell.org/) trajectory viewer files from time series,
+with categorical information from up to two attributes for the attributes listed.
+The default attributes listed is cell\_type and current\_phase.
+
+These simularium files can be analyzed with the online simularium viewer
+as described in the extra tutorials.
++ https://simularium.allencell.org/
+
+```bash
+pcdl_make_simularium output
+```
+```bash
+pcdl_make_simularium output cell_type dead --tt helloworld
+```
+```bash
+pcdl_make_simularium -h
+```
+
+Further readings:
++ [TUTORIAL_simularium.md](https://github.com/elmbeech/physicelldataloader/blob/master/man/TUTORIAL_simularium.md)
+
## Microenvironment and cell agent related commands
diff --git a/man/TUTORIAL_galaxy.md b/man/TUTORIAL_galaxy.md
index e69de29..3136da0 100644
--- a/man/TUTORIAL_galaxy.md
+++ b/man/TUTORIAL_galaxy.md
@@ -0,0 +1,73 @@
+# PhysiCell Data Loader Tutorial: pcdl and Galaxy
+
+[Galaxy](https://en.wikipedia.org/wiki/Galaxy_(computational_biology)) is an open-source, web-based platform for bioinformatics analysis.
+
+There a hand full of galaxy server instances around the world (USA, Europe, France, Australia, possibly others).
+We here focus on [the European instance of Galaxy](https://usegalaxy.eu/) since it has pcdl tools installed.
+
+Special thanks to Björn Grüning, who helped me to port pcdl into Galaxy!
+
+
+## ✨ Run PhysiCell Studio on Galaxy and save the output
+
+1. Point your web browser to the European instance of Galaxy: https://usegalaxy.eu/
+1. Required! Log into your user account. Create one if you do not already have one.
+1. On the left-side panel, click "Interactive Tools".
+1. Near the left-side top corner, in the "Tools" search bar, type "physicell studio".
+1. Choose "PhysiCell Studio".
+1. On the center panel, click on one of the "Run Tool" buttons.
+1. On the left-side panel, after a while, "Active Interactive Tools" should pop up.
+1. Under "Active Interactive Tools" click "PhysiCell Studio".
+1. Run a simmulation: In brief, in the middle panel, click the "Run" tab, then click the "Run simmulation", then wait until on the screen output "Processed finish" shows up.
+1. On the center panel menu bar, choose "Misc > put on History > all output.zip".
+1. On the right-side History panel, after a while, an "all\_output.zip" file should pop up.
+
+### Unzip the zip folder
+1. Near the top left corner, click "Tools".
+1. Near the left-side top corner, in the "Tools" search bar, type "unzip".
+1. Choose "Unzip Unzip a file".
+1. Mouse drag and drop the "all\_output.zip" file from the right-side History panel into the tool's parameters "Input file" field in the middle panel.
+1. On the center panel, click on one of the "Run Tool" buttons.
+1. On the right-side History panel, after a while, an unzipped file collection should pop up.
+
+
+## ✨ Upload local PhysiCell output to Galaxy
+
+1. Point your web browser to the European instance of Galaxy: https://usegalaxy.eu/
+1. Optionally: Log into your user account.
+1. Near the top left corner, click "Upload (New upload Beta)".
+1. Near the top left corner, choose "Upload from Computer".
+1. In the center panel click "Brows Files".
+1. Click your self through to the PhysiCell output folder.
+1. Click on one file in the output folder, then, on your keyboard, press Ctrl + A to choose all files.
+1. Click "Open". After a while the filenames will appear in the central panel.
+1. On the center panel bottom, flip the switch "Create a collection from these files" on.
+1. "Enter a collection name" (e.g. output) and choose "Collection Type" "List".
+1. Click "Start".
+1. After a while, the uploaded data collection should appear in the in the right-side History panel.
+
+
+## ✨ The pcdl tools on Galaxy
+
+1. Point your web browser to the European instance of Galaxy: https://usegalaxy.eu/
+1. Optionally: Log into your user account.
+1. Upload or generate PhysiCell output as described above.
+1. Near the top left corner, click "Tools".
+1. Near the left-side top corner, in the "Tools" search bar, type "pcdl".
+1. Choose one of the pcdl\_ tools (e.g. pcdl\_get\_version).
+1. Mouse drag and drop the uploaded or generated PhysiCell output data collection in the left-side History panel into the "essential:" "data collection" field in the middle panel.
+1. Optionally, tweak the "essential" and "advanced" parameters.
+1. Click "Run Tool".
+1. After a while, the result file(s) should appear in the left-side History panel.
+
+
+## ✨ Further readings
+
+You can learn more about Galaxy here:
++ https://galaxyproject.org/tutorials/g101/
+
+How to load, develop, or run a PhysiCell model in the studio can be learned here:
++ https://physicell-studio.readthedocs.io/en/latest/index.html
++ https://github.com/PhysiCell-Tools/PhysiCell-Studio
+
+That's it. The rest is analysis within Galaxy!
diff --git a/man/TUTORIAL_introduction.md b/man/TUTORIAL_introduction.md
index 8aea2fb..64c58ee 100644
--- a/man/TUTORIAL_introduction.md
+++ b/man/TUTORIAL_introduction.md
@@ -3,9 +3,8 @@
If you have not already done so, please install the latest version of physicell data loader (pcdl),
as described in the [HowTo](https://github.com/elmbeech/physicelldataloader/blob/master/man/HOWTO.md) section.\
The current development happens in branch v4.
-Branch v3 and v4 are maintained and [pip](https://pypi.org/project/pcdl/) installable.
-Branch v3 is also installable through [bioconada](https://bioconda.github.io/).
-Branch v1, v2 exists, if ever needed, for reproducibility of old results.
+Branch v4 is maintained and [pip](https://pypi.org/project/pcdl/) and [bioconada](https://bioconda.github.io/) installable.
+Branch v1, v2, v3 exists, if ever needed, for reproducibility of old results.
## Tutorial - branch v1 and v2
@@ -13,26 +12,27 @@ The original python-loader tutorial can be found here.
+ http://www.mathcancer.org/blog/python-loader/
-## Tutorial - branch v3 and v4
+## Tutorial - branch v4
### History
In the very early days, [PhysiCell](https://github.com/MathCancer/PhysiCell) output was with the help of a MATLAB script loaded into MATLAB for analysis.\
In 2019, a similar loader script was written for python3.
-The name of this script filed was pyMCDS.py and basically defined one class named pyMCDS.
+The name of this script file was pyMCDS.py and basically defined one class named pyMCDS.
In autumn 2022, an endeavor was undertaken to pack the original pyMCDS.py script into a pip installable python3 library and develop it further, but always in such a way that, if necessary, the code could still be run like in the early days.\
The result is the pcdl physicell data loader library branch v2, v3.
In spring 2025, the code was stripped of some relics (mainly in the back end) from the early days to make the code more python3 than C++ like, which resulted in branch v4.
+In summer 2026, branch v4 became throug a core and optional dependency installation feature bioconda compatible and, as such, made branch v3 superfluous.
-The result from all of this is the pcdl physicell data loader library here.\
+The result from all of this development is the pcdl physicell data loader library here.\
In the big picture, the pyMCDS class evolved into the TimeStep class, which is slightly heavier but much more powerful for downstream data analysis than the original pyMCDS class.
Additionally, a TimeSeries class was added.
If you inspect branch v3 pcdl source code, you will see that the [pyMCDS.py](https://github.com/elmbeech/physicelldataloader/blob/v3/pcdl/pyMCDS.py) file still exists.
And if you feel so, it is still possible to [load and process PhysiCell output the ancient way](https://github.com/elmbeech/physicelldataloader/blob/master/man/HOWTO.md#how-to-run-physicelldataloader-like-in-the-early-days-before-autumn-2022)!\
-Naturally, the full-fledged pcdl library with the TimeSteps and TimeSeries class is much more powerful than pyMCDS.py only.
+Naturally, the full-fledged branch v4 pcdl library with the TimeSteps and TimeSeries class is much more powerful than pyMCDS.py only.
### Concept
diff --git a/man/TUTORIAL_python3_muspan.md b/man/TUTORIAL_python3_muspan.md
index 5ab0054..ad76fc7 100644
--- a/man/TUTORIAL_python3_muspan.md
+++ b/man/TUTORIAL_python3_muspan.md
@@ -21,9 +21,9 @@ import muspan as ms
mcdsts = pcdl.TimeSeries('output/')
do_domain = mcdsts.get_muspan() # translate the mcds time seris into a dictionary of muspan domain objects.
-ls_domain = sorted(do_domain.keys()) # generate an orderes list of domain names
+ls_domain = sorted(do_domain.keys()) # generate an orderes list of domain names
-print(ls_domain) # print a list of domain names
+print(ls_domain) # print a list of domain names
print(do_domain[ls_domain[0]]) # take a look at the first domain in the ls_domain list.
```
diff --git a/man/TUTORIAL_python3_pandas.md b/man/TUTORIAL_python3_pandas.md
index 3d9d354..06bde9d 100644
--- a/man/TUTORIAL_python3_pandas.md
+++ b/man/TUTORIAL_python3_pandas.md
@@ -19,8 +19,8 @@ I recommend working through the pandas cookbook from Julia Evens:
The pandas library as such is very well documented.
Please spend some time to familiarize yourself with the homepage, the users guides, and the API reference.
+ https://pandas.pydata.org/
-+ http://pandas.pydata.org/pandas-docs/stable/user_guide/index.html
-+ http://pandas.pydata.org/pandas-docs/stable/reference/index.html
++ https://pandas.pydata.org/pandas-docs/stable/user_guide/index.html
++ https://pandas.pydata.org/pandas-docs/stable/reference/index.html
## Dump pcdl data construct from the command line into a csv file
diff --git a/man/TUTORIAL_python3_timeseries.md b/man/TUTORIAL_python3_timeseries.md
index 7184acf..6dab2ed 100644
--- a/man/TUTORIAL_python3_timeseries.md
+++ b/man/TUTORIAL_python3_timeseries.md
@@ -6,7 +6,7 @@ And perhaps, work thorough the [TUTORIAL_python3_timestep.md](https://github.com
An exciting thing about modeling is to have time series data.
-Pcdl's TimeSeries class is here to make the handling of a time series of MCD snapshots easy.
+Pcdl's TimeSeries class is here to make the handling of a time series of MCDS snapshots easy.
All analysis functions available for TimeStep are available for TimeSeries too,
and we will not further discuss them here.
@@ -38,17 +38,23 @@ mcdsts.get_cell_df()
mcdsts.get_anndata()
```
```python
-mcdsts.make_graph_gml()
-```
-```python
mcdsts.plot_scatter()
```
```python
mcdsts.make_cell_vtk()
```
+```python
+mcdsts.make_graph_gml()
+```
For microenvironment and cell data, these are the functions:
```python
+mcdsts.get_muspan()
+```
+```python
+mcdsts.get_spatialdata()
+```
+```python
mcdsts.make_ome_tiff()
```
```python
@@ -69,13 +75,15 @@ For microenvironment data, this is the function:
For cell data, this is the function:
+ `mcdsts.get_cell_attribute()`
++ `mcdsts.make_simularium()`
For microenvironment and cell data, this is the function:
++ `mcdsts.get_sdmcds_list()`
+ `mcdsts.plot_timeseries()`
Besides, there are functions to render a set of jpeg, png, or tiff images into a movie.
-+ `mcdsts.make_movie()` and `pcdl.make_movie()`
+ `mcdsts.make_gif()` and `pcdl.make_gif()`
++ `mcdsts.make_movie()` and `pcdl.make_movie()`
@@ -102,8 +110,8 @@ python3 -c"import pathlib, pcdl, shutil; pcdl.install_data(); s_ipath=str(pathli
Like in the TimeStep class, for memory consumption and processing speed control,
-we can specify if we want to load microenvironment data and graph data from the snapshots we later on analyze.
-Additionally, we can specify, if for first even want to load data at all,
+we can specify if we want to load microenvironment data, graph data, and possible physiboss data from the snapshots we later on analyze.
+Additionally, we can specify, if we for first even want to load data at all,
or if we only would like to load the output xml file list, which we will see, can be manipulated before actual data is loaded.
By default, all data from all snapshots is loaded.
@@ -117,13 +125,13 @@ mcdsts = pcdl.TimeSeries('output/')
```
Fine tuned what data from a time step will be loaded
-Here we only load cell data, not even information about cell type ID:label mapping.
+Here we only load cell data.
```python
import pcdl # the physicell data loader library,
print('pcdl version:', pcdl.__version__) # it is easy to figure out which pcdl version you run
-mcdsts = pcdl.TimeSeries(s_path, custom_data_type={}, load=True, microenv=False, graph=False, settingxml=None)
+mcdsts = pcdl.TimeSeries(s_path, custom_data_type={}, load=True, microenv=False, graph=False, physiboss=False)
```
Fine tuned which time steps are loaded.
@@ -167,7 +175,7 @@ mcdsts.read_mcds(ls_xml_even)
len(mcdsts.get_mcds_list()) # 13
```
-Single snapshots can now be accessed by indexing.
+Single snapshots can be accessed by indexing.
With a single snapshot, you may work exactly in the same way as with an object loaded by TimeStep.
```python
@@ -181,14 +189,18 @@ for mcds in mcdsts.get_mcds_list():
print(mcds.get_mcds_list().get_time())
```
-If you translate your time series into [anndata]((https://anndata.readthedocs.io/en/latest/) Objects,
-using the collapse=False argument, you will endup with a similar list for anndata objects.
+If you translate your time series into [anndata]((https://anndata.readthedocs.io/en/latest/) objects,
+using the collapse=False argument,
+or into [spatialdata](https://spatialdata.scverse.org/en/stable/) objects,
+you will endup with a similar list for anndata or spatialdata objects, respective.
```python
mcdsts.get_anndata(values=2, scale='maxabs', collapse=False)
mcdsts.get_annmcds_list() # [AnnData object with n_obs × n_vars ..., ..., ...]
```
-
+```python
+mcdsts.get_spatialdata(values=2, scale='maxabs', collapse=False)
+mcdsts.get_sdmcds_list() # [SpatialData object ..., ..., ...]
## Microenvironment Data Related Functions (Continuum Variables)
@@ -269,6 +281,19 @@ help(mcdsts.get_cell_attribute)
```
+### ✨ Cell Data Analysis with [Simularium](https://simularium.allencell.org/)
+
+For cell agent trajectory visualization in 3D a **simularium file** can be retrieved.\
+This file can be analyzed with the online simularium viewer.
++ https://simularium.allencell.org/
+
+```python
+mcdsts.make_simularium()
+```
+
+Please have a look at [TUTORIAL_simularium.md](https://github.com/elmbeech/physicelldataloader/blob/master/man/TUTORIAL_simularium.md) to learn more.
+
+
## Microenvironment and Cell Data Related Functions
diff --git a/man/TUTORIAL_python3_timestep.md b/man/TUTORIAL_python3_timestep.md
index 184233c..6e6a9ec 100644
--- a/man/TUTORIAL_python3_timestep.md
+++ b/man/TUTORIAL_python3_timestep.md
@@ -32,7 +32,7 @@ python3 -c"import pathlib, pcdl, shutil; pcdl.install_data(); s_ipath=str(pathli
By default, all data related to the snapshot is loaded.
For speed and less memory usage, it is however possible to only load the essential (output xml and cell mat data),
-and exclude microenvironment, graph data, PhysiBoss data, and the PhysiCell\_settings.xml cell type ID label mapping. \
+and exclude microenvironment data, graph data, and possible PhysiBoss data. \
For custom\_data variables it is possible to specify data types, apart from the generic float type, namely: int, bool, and str.
This can be done too, after the data is loaded, using the mcds.custom\_data\_astype function. \
For paths, in general, unix (slash) and windows (backslash) notation will work.
@@ -134,7 +134,7 @@ mcds.get_runtime() # will return a float value like 15.596373
mcds.get_timestamp() # will return a sting like 2022-10-19T01:12:01Z
```
-Finally, it is possible to retrieve a dictionary that lists all units from all tracked variables, from metadata, mesh, continuum\_variables, and discrete\_cells.
+Finally, it is possible to retrieve a dictionary that lists all units from all tracked variables, from metadata, mesh, substrate, and cells.
```python
mcds.get_unit_dict() # will return a dictionary, which maps the variables to the units specified in the setting.xml.
@@ -232,7 +232,7 @@ This file can be analyzed, for example with the [Paraview](https://en.wikipedia.
mcds.make_conc_vtk()
```
-Please have a look at [TUTORIAL_paraview.md](https://github.com/elmbeech/physicelldataloader/blob/master/man/TUTORIAL_paraview.md) to learn more.
+Please have a look at [pcdl and python3 and vtk](https://github.com/elmbeech/physicelldataloader/tree/master/man/TUTORIAL_python3_vtk.md) and [TUTORIAL_paraview.md](https://github.com/elmbeech/physicelldataloader/blob/master/man/TUTORIAL_paraview.md) to learn more.
@@ -352,6 +352,44 @@ And we have cell neighbor graph infromation (obsp, uns).
Please have a look at [TUTORIAL_python3_scverse.md](https://github.com/elmbeech/physicelldataloader/blob/master/man/TUTORIAL_python3_scverse.md) to learn more.
+### ✨ Cell Data Analysis with [Matplotlib](https://matplotlib.org/)
+
+For cell agent visualization **matplotlib scatter plots**,
+for any cell attribute, through any z\_slice can be retrieved. \
+The mcds.plot\_scatter function has many parameters to fine tune the plot.
+Please have a look at its docstring to learn more.
+
+```python
+fig = mcds.plot_scatter()
+fig.show()
+```
+```python
+fig = mcds.plot_scatter('pressure')
+fig.show()
+```
+```python
+help(mcds.plot_scatter)
+```
+
+The mcds.plot\_contour function output can combine with the mcds.plot\_contour output. \
+Please have a look at [TUTORIAL_python3_matplotlib.md](https://github.com/elmbeech/physicelldataloader/blob/master/man/TUTORIAL_python3_matplotlib.md) to learn more.
+
+
+### ✨ Cell Data Analysis with [Vtk](https://vtk.org/)
+
+For cell agent visualization in 3D **glyph vtk files** can be retrieved.\
+This files can be analyzed, for example with the [Paraview](https://en.wikipedia.org/wiki/ParaView) software.
+
+```python
+mcds.make_cell_vtk()
+```
+```python
+help(mcds.make_cell_vtk)
+```
+
+Please have a look at [pcdl and python3 and vtk](https://github.com/elmbeech/physicelldataloader/tree/master/man/TUTORIAL_python3_vtk.md) and [TUTORIAL_paraview.md](https://github.com/elmbeech/physicelldataloader/blob/master/man/TUTORIAL_paraview.md) to learn more.
+
+
### ✨ Cell Data Analysis within the [Networkx](https://networkx.org/) and [Igraph](https://igraph.org/)
Fore each cell, PhysiCell tracks the cell neighborhood (if cells touch each other, if cells are attached to each other).
@@ -375,7 +413,6 @@ Cell neighbor spring attached graph
```python
mcds.make_graph_gml('spring')
```
-
-Please have a look at [TUTORIAL_python3_graph.md](https://github.com/elmbeech/physicelldataloader/blob/master/man/TUTORIAL_python3_graph.md) to learn more.
-
-
-### ✨ Cell Data Analysis with [Matplotlib](https://matplotlib.org/)
-
-For cell agent visualization **matplotlib scatter plots**,
-for any cell attribute, through any z\_slice can be retrieved. \
-The mcds.plot\_scatter function has many parameters to fine tune the plot.
-Please have a look at its docstring to learn more.
-
+Furthermore, there are functions to recall the graph dictionary for each of the tracked graphs.
```python
-fig = mcds.plot_scatter()
-fig.show()
+mcds.get_neighbor_graph_dict()
```
```python
-fig = mcds.plot_scatter('pressure')
-fig.show()
+mcds.get_attached_graph_dict()
```
```python
-help(mcds.plot_scatter)
+mcds.get_spring_graph_dict()
```
-The mcds.plot\_contour function output can combine with the mcds.plot\_contour output. \
-Please have a look at [TUTORIAL_python3_matplotlib.md](https://github.com/elmbeech/physicelldataloader/blob/master/man/TUTORIAL_python3_matplotlib.md) to learn more.
+Please have a look at
+[TUTORIAL_python3_graph.md](https://github.com/elmbeech/physicelldataloader/blob/master/man/TUTORIAL_python3_graph.md) to learn more.
-### ✨ Cell Data Analysis with [Vtk](https://vtk.org/)
-For cell agent visualization in 3D **glyph vtk files** can be retrieved.\
-This files can be analyzed, for example with the [Paraview](https://en.wikipedia.org/wiki/ParaView) software.
+## Microenvironment and Cell Data Related Functions
+
+### ✨ Substrate and Cell Data Analysis within the [MuSpAn](https://www.muspan.co.uk/) and [Scverse](https://scverse.org/)
+For bioinformatics, substrate and cell agent data can be saved in the University of Oxford's multi spatial analysis [MuSpAn](https://www.muspan.co.uk/) or scverse's [SpatiaData](https://spatialdata.scverse.org/en/stable/) format.
```python
-mcds.make_cell_vtk()
+do_domain = mcds.get_muspan()
```
```python
-help(mcds.make_cell_vtk)
+sdata = mcds.get_spatialdata()
```
-Please have a look at [TUTORIAL_paraview.md](https://github.com/elmbeech/physicelldataloader/blob/master/man/TUTORIAL_paraview.md) to learn more.
-
-
+Please have a look at
+[TUTORIAL_python3_muspan.md](TUTORIAL_python3_muspan.md)
+[TUTORIAL_python3_scverse.md](TUTORIAL_python3_scverse.md)
+to learn more.
-## Microenvironment and Cell Data Related Functions
### ✨ PhysiCell Data Analysis with [Napari](https://napari.org/stable/), [Fiji Imagej](https://fiji.sc/), [Neuroglancer](https://research.google/blog/an-interactive-automated-3d-reconstruction-of-a-fly-brain/), and similar software.
@@ -461,7 +488,6 @@ and [TUTORIAL_neuroglancer.md]((https://github.com/elmbeech/physicelldataloader/
to learn more.
-
## Mesh Data Related Functions
For data analysis, the functions related to the mesh are most probably the least one you have to deal with.
diff --git a/man/TUTORIAL_simularium.md b/man/TUTORIAL_simularium.md
new file mode 100644
index 0000000..918a216
--- /dev/null
+++ b/man/TUTORIAL_simularium.md
@@ -0,0 +1,66 @@
+# PhysiCell Data Loader Tutorial: pcdl and Simularium
+
+The [simularium](https://simularium.allencell.org/) viewer was developed to share and interrogate interactive 3D visualizations of biological simulation trajectories and related plots directly in a web browser.
+
+Simularium files can easily be generated from mcds time series.
+
+
+## ✨ command line
+
+### command line time series
+
+Generate a simularium trajectory file.
+
+```bash
+pcdl_make_simularium output_2d/
+```
+
+### command line man page
+
+```bash
+pcdl_make_simularium -h
+```
+
+
+## ✨ python
+
+### python time series
+
+Load a time series and generate a simularium trajectory file.
+
+```python
+import pcdl
+
+mcdsts = pcdl.TimeSeries('output_2d/')
+mcdsts.make_simularium()
+```
+
+### python docstrings
+
+```python
+import pcdl
+
+mcdsts = pcdl.TimeSeries('output_2d/')
+help(mcdsts.make_simularium())
+```
+
+## ✨ simularium viewer
+
+1. Open the simularium viewer web page: https://simularium.allencell.org/
+1. Near the top right corner, click the "Load models" dropdown menu and choose "Simularium file".
+1. In the popup window choose "From your device" "Select File".
+1. Select the simularium file and click "Open".
+1. Click "Load".
+1. Explore the loaded file.
+
+
+## ✨ Further readings'
+
+Please work through the official documentation to learn more about how simularium software.
+
++ https://simularium.allencell.org/
++ https://github.com/simularium
++ https://simularium.github.io/simulariumio/#
++ https://doi.org/10.1038/s41592-022-01442-1
+
+That's it. The rest is analysis within simularium!
diff --git a/man/docstring/mcds.render_neuroglancer.md b/man/docstring/mcds.render_neuroglancer.md
new file mode 100644
index 0000000..d393610
--- /dev/null
+++ b/man/docstring/mcds.render_neuroglancer.md
@@ -0,0 +1,7 @@
+# mcds.render_neuroglancer()
+
+
+help(pcdl.render_neuroglancer)
+try: mcds.render_neuroglancer(mcds.make_ome_tiff())
+
+```
\ No newline at end of file
diff --git a/man/docstring/mcdsts.get_sdmcds_list.md b/man/docstring/mcdsts.get_sdmcds_list.md
new file mode 100644
index 0000000..9b6dc9f
--- /dev/null
+++ b/man/docstring/mcdsts.get_sdmcds_list.md
@@ -0,0 +1,22 @@
+# mcdsts.get_sdmcds_list()
+
+
+## input:
+```
+ self: TimeSeries class instance.
+
+```
+
+## output:
+```
+ self.l_sdmcds: list of chronologically ordered spatialdata mcds objects.
+ watch out, this is a pointer to the
+ self.l_sdmcds list of spdata mcds objects, not a copy of self.l_sdmcds!
+
+```
+
+## description:
+```
+ function returns a binding to the self.l_sdmcds list of spdata mcds objects.
+
+```
\ No newline at end of file
diff --git a/man/docstring/mcdsts.make_gif.md b/man/docstring/mcdsts.make_gif.md
new file mode 100644
index 0000000..74eb90d
--- /dev/null
+++ b/man/docstring/mcdsts.make_gif.md
@@ -0,0 +1,8 @@
+# mcdsts.make_gif()
+
+
+help(pcdl.make_gif)
+try: mcdsts.make_gif(mcdsts.plot_scatter())
+try: mcdsts.make_gif(mcdsts.plot_contour('substrate'))
+
+```
\ No newline at end of file
diff --git a/man/docstring/mcdsts.make_movie.md b/man/docstring/mcdsts.make_movie.md
new file mode 100644
index 0000000..b416acd
--- /dev/null
+++ b/man/docstring/mcdsts.make_movie.md
@@ -0,0 +1,8 @@
+# mcdsts.make_movie()
+
+
+help(pcdl.make_movie)
+try: mcdsts.make_movie(mcdsts.plot_scatter())
+try: mcdsts.make_movie(mcdsts.plot_contour('substrate'))
+
+```
\ No newline at end of file
diff --git a/man/docstring/mcdsts.make_simularium.md b/man/docstring/mcdsts.make_simularium.md
new file mode 100644
index 0000000..7e1ca7c
--- /dev/null
+++ b/man/docstring/mcdsts.make_simularium.md
@@ -0,0 +1,43 @@
+# mcdsts.make_simularium()
+
+
+## input:
+```
+ focus_cat: list of 1 or 2 string; default is ['cell_type','current_phase']
+ specify 1 or 2 categorical column labels, to be found
+ in mcdsts.get_cell_df().
+
+ trajectory_title: string; default 'timeseries'
+ the trajectory_title will be used as
+ .simularium file name and displayed
+ in the simulation.
+
+ scale_factor: float number; default is None
+ A multiplier for the scene, use if visualization is
+ too large or small. If None is provided, one will
+ be calculated based on the position data.
+ bue 20260822: does not seem to work in current simularium 1.13.0.
+
+ camera_defaults: simulariumio.CameraData object; default is None
+ camera's initial settings which it also returns to
+ when reset.
+
+ model_meta_data: simulariumio.ModelMetaData; default is None
+ Metadata for the model that produced this
+ trajectory.
+
+```
+
+## output:
+```
+ .simularium file
+
+```
+
+## description:
+```
+ function returns a simularium trajectory file that can be run with the
+ online Simularium Viewer.
+ + https://simularium.allencell.org/
+
+```
\ No newline at end of file
diff --git a/man/docstring/mcdsts.render_neuroglancer.md b/man/docstring/mcdsts.render_neuroglancer.md
new file mode 100644
index 0000000..f4d8730
--- /dev/null
+++ b/man/docstring/mcdsts.render_neuroglancer.md
@@ -0,0 +1,7 @@
+# mcdsts.render_neuroglancer()
+
+
+help(pcdl.render_neuroglancer)
+try: mcdsts.render_neuroglancer(mcdsts.make_ome_tiff(), 0)
+
+```
\ No newline at end of file
diff --git a/man/docstring/pcdl_get_muspan.md b/man/docstring/pcdl_get_muspan.md
new file mode 100644
index 0000000..215d4fe
--- /dev/null
+++ b/man/docstring/pcdl_get_muspan.md
@@ -0,0 +1,64 @@
+```
+usage: pcdl_get_muspan [-h] [--custom_data_type [CUSTOM_DATA_TYPE ...]]
+ [--microenv MICROENV] [--graph GRAPH]
+ [--physiboss PHYSIBOSS] [--settingxml SETTINGXML]
+ [-v VERBOSE] [--values VALUES] [--drop [DROP ...]]
+ [--keep [KEEP ...]]
+ [path] [z_slice]
+
+function to transform mcds time steps into muspan domain objects for
+downstream analysis.
+
+positional arguments:
+ path path to the PhysiCell output directory or a
+ outputnnnnnnnn.xml file. default is . .
+ z_slice z-axis position to slice a 2D xy-plain out of the 3D
+ mesh. if z_slice position numeric but not an exact
+ mesh center coordinate, then z_slice will be adjusted
+ to the nearest mesh center value, the smaller one, if
+ the coordinate lies on a saddle point. default is 0.0.
+
+options:
+ -h, --help show this help message and exit
+ --custom_data_type [CUSTOM_DATA_TYPE ...]
+ parameter to specify custom_data variable types other
+ than float (namely: int, bool, str) like this
+ var:dtype myint:int mybool:bool mystr:str . downstream
+ float and int will be handled as numeric, bool as
+ Boolean, and str as categorical data. default is an
+ empty string.
+ --microenv MICROENV should the microenvironment be extracted and loaded
+ into the muspan domain object? setting microenv to
+ False will use less memory and speed up processing.
+ default is True.
+ --graph GRAPH should neighbor graph, attach graph, and attached
+ spring graph be extracted and loaded into the muspan
+ domain object? default is True.
+ --physiboss PHYSIBOSS
+ if found, should physiboss state data be extracted and
+ loaded into the muspan domain object? default is True.
+ --settingxml SETTINGXML
+ the settings.xml that is loaded, from which the cell
+ type ID label mapping, is extracted, if this
+ information is not found in the output xml file. set
+ to None or False if the xml file is missing! default
+ is False.
+ -v, --verbose VERBOSE
+ setting verbose to False for less text output, while
+ processing. default is True.
+ --values VALUES minimal number of values a variable has to have in any
+ of the mcds time steps to be outputted. variables that
+ have only 1 state carry no information. None is a
+ state too. default is 1.
+ --drop [DROP ...] set of column labels to be dropped for the dataframe.
+ don't worry: essential columns like ID, coordinates
+ and time will never be dropped. Attention: when the
+ keep parameter is given, then the drop parameter has
+ to be an empty string! default is an empty string.
+ --keep [KEEP ...] set of column labels to be kept in the dataframe. set
+ values=1 to be sure that all variables are kept. don't
+ worry: essential columns like ID, coordinates and time
+ will always be kept. default is an empty string.
+
+homepage: https://github.com/elmbeech/physicelldataloader
+```
diff --git a/man/docstring/pcdl_make_simularium.md b/man/docstring/pcdl_make_simularium.md
new file mode 100644
index 0000000..dccd2c1
--- /dev/null
+++ b/man/docstring/pcdl_make_simularium.md
@@ -0,0 +1,50 @@
+```
+usage: pcdl_make_simularium [-h] [--custom_data_type [CUSTOM_DATA_TYPE ...]]
+ [--physiboss PHYSIBOSS] [--settingxml SETTINGXML]
+ [-v VERBOSE] [--trajectory_title TRAJECTORY_TITLE]
+ [--scale_factor [SCALE_FACTOR]]
+ [path] [focus_cat ...]
+
+function returns a simularium trajectory file which can be viewed with the
+simularium viewer (https://simularium.allencell.org/).
+
+positional arguments:
+ path path to the PhysiCell output directory or a
+ outputnnnnnnnn.xml file. default is . .
+ focus_cat one or two categorical mcds.get_cell_df dataframe
+ column names, used for cell attributes. default is
+ cell_type current_phase.
+
+options:
+ -h, --help show this help message and exit
+ --custom_data_type [CUSTOM_DATA_TYPE ...]
+ parameter to specify custom_data variable types other
+ than float (namely: int, bool, str) like this
+ var:dtype myint:int mybool:bool mystr:str . downstream
+ float and int will be handled as numeric, bool as
+ Boolean, and str as categorical data. default is an
+ empty string.
+ --physiboss PHYSIBOSS
+ if found, should physiboss state data be extracted and
+ loaded into the df_cell dataframe? default is True.
+ --settingxml SETTINGXML
+ the settings.xml that is loaded, from which the cell
+ type ID label mapping, is extracted, if this
+ information is not found in the output xml file. set
+ to None or False if the xml file is missing! default
+ is False.
+ -v, --verbose VERBOSE
+ setting verbose to False for less text output, while
+ processing. default is True.
+ --trajectory_title, --tt TRAJECTORY_TITLE
+ the trajectory_title will be used for
+ .simularium file name and displayed
+ in the simulation.
+ --scale_factor, --sf [SCALE_FACTOR]
+ a multiplier for the scene, use if visualization is
+ too large or small. if none is provided, one will be
+ calculated based on the position data. bue 20260822:
+ does not seem to work in current simularium 1.13.0.
+
+homepage: https://github.com/elmbeech/physicelldataloader
+```
diff --git a/man/img/physicelldataloader_concept_v4.0.0.jpg b/man/img/physicelldataloader_concept_v4.0.0.jpg
index 888ec28..1a24bf3 100644
Binary files a/man/img/physicelldataloader_concept_v4.0.0.jpg and b/man/img/physicelldataloader_concept_v4.0.0.jpg differ
diff --git a/man/img/physicelldataloader_concept_v4.0.0.png b/man/img/physicelldataloader_concept_v4.0.0.png
index b0052f1..bbccccc 100644
Binary files a/man/img/physicelldataloader_concept_v4.0.0.png and b/man/img/physicelldataloader_concept_v4.0.0.png differ
diff --git a/man/img/physicelldataloafder_github_qr.png b/man/img/physicelldataloafder_github_qr.png
deleted file mode 100644
index 86d3d92..0000000
Binary files a/man/img/physicelldataloafder_github_qr.png and /dev/null differ
diff --git a/man/scarab.py b/man/scarab.py
index 8252c60..e985249 100644
--- a/man/scarab.py
+++ b/man/scarab.py
@@ -139,6 +139,10 @@ def docstring_md(s_function, ls_doc, s_header=None, s_opath='man/docstring/'):
s_function = 'mcds.set_verbose_true',
ls_doc = pcdl.TimeStep.set_verbose_true.__doc__.split('\n'),
)
+docstring_md(
+ s_function = 'mcds.render_neuroglancer',
+ ls_doc = pcdl.TimeStep.render_neuroglancer.__doc__.split('\n'),
+)
# write TimeStep metadata function makdown files
docstring_md(
@@ -232,7 +236,7 @@ def docstring_md(s_function, ls_doc, s_header=None, s_opath='man/docstring/'):
ls_doc = pcdl.TimeStep.get_voxel_ijk.__doc__.split('\n'),
)
-# write TimeStep microenv function markdown files
+# write TimeStep substrate function markdown files
docstring_md(
s_function = 'mcds.get_substrate_list',
ls_doc = pcdl.TimeStep.get_substrate_list.__doc__.split('\n'),
@@ -275,20 +279,10 @@ def docstring_md(s_function, ls_doc, s_header=None, s_opath='man/docstring/'):
s_function = 'mcds.get_cell_attribute_list',
ls_doc = pcdl.TimeStep.get_cell_attribute_list.__doc__.split('\n'),
)
-docstring_md(
- s_function = 'mcds.plot_scatter',
- ls_doc = pcdl.TimeStep.plot_scatter.__doc__.split('\n'),
-)
-docstring_md(
- s_function = 'mcds.make_cell_vtk',
- ls_doc = pcdl.TimeStep.make_cell_vtk.__doc__.split('\n'),
-)
docstring_md(
s_function = 'mcds.get_anndata',
ls_doc = pcdl.TimeStep.get_anndata.__doc__.split('\n'),
)
-
-# write TimeStep graph function markdown files
docstring_md(
s_function = 'mcds.get_attached_graph_dict',
ls_doc = pcdl.TimeStep.get_attached_graph_dict.__doc__.split('\n'),
@@ -301,12 +295,20 @@ def docstring_md(s_function, ls_doc, s_header=None, s_opath='man/docstring/'):
s_function = 'mcds.get_spring_graph_dict',
ls_doc = pcdl.TimeStep.get_spring_graph_dict.__doc__.split('\n'),
)
+docstring_md(
+ s_function = 'mcds.plot_scatter',
+ ls_doc = pcdl.TimeStep.plot_scatter.__doc__.split('\n'),
+)
+docstring_md(
+ s_function = 'mcds.make_cell_vtk',
+ ls_doc = pcdl.TimeStep.make_cell_vtk.__doc__.split('\n'),
+)
docstring_md(
s_function = 'mcds.make_graph_gml',
ls_doc = pcdl.TimeStep.make_graph_gml.__doc__.split('\n'),
)
-# write TimeStep microenvironment and cells function markdown files
+# write TimeStep substarte and cells function markdown files
docstring_md(
s_function = 'mcds.get_muspan',
ls_doc = pcdl.TimeStep.get_muspan.__doc__.split('\n'),
@@ -321,21 +323,15 @@ def docstring_md(s_function, ls_doc, s_header=None, s_opath='man/docstring/'):
ls_doc = pcdl.TimeStep.make_ome_tiff.__doc__.split('\n'),
)
+# write TimeStep internal function makdown files
docstring_md(
- s_function = 'pcdl.render_neuroglancer',
- ls_doc = pcdl.render_neuroglancer.__doc__.split('\n'),
- s_header = "mcds.render_neuroglancer('path/to/ome.tiff')"
+ s_function = 'pcdl.graphfile_parser',
+ ls_doc = pcdl.graphfile_parser.__doc__.split('\n'),
)
-
-# write TimeStep internal function makdown files
docstring_md(
s_function = 'pcdl.scaler',
ls_doc = pcdl.scaler.__doc__.split('\n'),
)
-docstring_md(
- s_function = 'pcdl.graphfile_parser',
- ls_doc = pcdl.graphfile_parser.__doc__.split('\n'),
-)
# write TimeSeries initialize function makdown files
@@ -349,32 +345,41 @@ def docstring_md(s_function, ls_doc, s_header=None, s_opath='man/docstring/'):
ls_doc = pcdl.TimeSeries.custom_data_astype.__doc__.split('\n'),
)
docstring_md(
- s_function = 'mcdsts.get_xmlfile_list',
- ls_doc = pcdl.TimeSeries.get_xmlfile_list.__doc__.split('\n'),
+ s_function = 'mcdsts.set_verbose_false',
+ ls_doc = pcdl.TimeSeries.set_verbose_false.__doc__.split('\n'),
)
docstring_md(
- s_function = 'mcdsts.read_mcds',
- ls_doc = pcdl.TimeSeries.read_mcds.__doc__.split('\n'),
+ s_function = 'mcdsts.set_verbose_true',
+ ls_doc = pcdl.TimeSeries.set_verbose_true.__doc__.split('\n'),
)
docstring_md(
- s_function = 'mcdsts.get_mcds_list',
- ls_doc = pcdl.TimeSeries.get_mcds_list.__doc__.split('\n'),
+ s_function = 'mcdsts.make_gif',
+ ls_doc = pcdl.TimeSeries.make_gif.__doc__.split('\n'),
)
docstring_md(
- s_function = 'mcdsts.get_annmcds_list',
- ls_doc = pcdl.TimeSeries.get_annmcds_list.__doc__.split('\n'),
+ s_function = 'mcdsts.make_movie',
+ ls_doc = pcdl.TimeSeries.make_movie.__doc__.split('\n'),
+)
+docstring_md(
+ s_function = 'mcdsts.render_neuroglancer',
+ ls_doc = pcdl.TimeSeries.render_neuroglancer.__doc__.split('\n'),
)
+# write TimeSeries load function makdown files
docstring_md(
- s_function = 'mcdsts.set_verbose_false',
- ls_doc = pcdl.TimeSeries.set_verbose_false.__doc__.split('\n'),
+ s_function = 'mcdsts.get_xmlfile_list',
+ ls_doc = pcdl.TimeSeries.get_xmlfile_list.__doc__.split('\n'),
)
docstring_md(
- s_function = 'mcdsts.set_verbose_true',
- ls_doc = pcdl.TimeSeries.set_verbose_true.__doc__.split('\n'),
+ s_function = 'mcdsts.read_mcds',
+ ls_doc = pcdl.TimeSeries.read_mcds.__doc__.split('\n'),
+)
+docstring_md(
+ s_function = 'mcdsts.get_mcds_list',
+ ls_doc = pcdl.TimeSeries.get_mcds_list.__doc__.split('\n'),
)
-# write TimeSeries microenv function makdown files
+# write TimeSeries substrate function makdown files
docstring_md(
s_function = 'mcdsts.get_conc_df',
ls_doc = pcdl.TimeSeries.get_conc_df.__doc__.split('\n'),
@@ -401,6 +406,14 @@ def docstring_md(s_function, ls_doc, s_header=None, s_opath='man/docstring/'):
s_function = 'mcdsts.get_cell_attribute',
ls_doc = pcdl.TimeSeries.get_cell_attribute.__doc__.split('\n'),
)
+docstring_md(
+ s_function = 'mcdsts.get_anndata',
+ ls_doc = pcdl.TimeSeries.get_anndata.__doc__.split('\n'),
+)
+docstring_md(
+ s_function = 'mcdsts.get_annmcds_list',
+ ls_doc = pcdl.TimeSeries.get_annmcds_list.__doc__.split('\n'),
+)
docstring_md(
s_function = 'mcdsts.plot_scatter',
ls_doc = pcdl.TimeSeries.plot_scatter.__doc__.split('\n'),
@@ -409,16 +422,14 @@ def docstring_md(s_function, ls_doc, s_header=None, s_opath='man/docstring/'):
s_function = 'mcdsts.make_cell_vtk',
ls_doc = pcdl.TimeSeries.make_cell_vtk.__doc__.split('\n'),
)
-docstring_md(
- s_function = 'mcdsts.get_anndata',
- ls_doc = pcdl.TimeSeries.get_anndata.__doc__.split('\n'),
-)
-
-# write TimeSeries graph function makdown files
docstring_md(
s_function = 'mcdsts.make_graph_gml',
ls_doc = pcdl.TimeSeries.make_graph_gml.__doc__.split('\n'),
)
+docstring_md(
+ s_function = 'mcdsts.make_simularium',
+ ls_doc = pcdl.TimeSeries.make_simularium.__doc__.split('\n'),
+)
# write TimeSeries microenvironment and cells function makdown files
docstring_md(
@@ -429,21 +440,26 @@ def docstring_md(s_function, ls_doc, s_header=None, s_opath='man/docstring/'):
s_function = 'mcdsts.get_spatialdata',
ls_doc = pcdl.TimeSeries.get_spatialdata.__doc__.split('\n'),
)
+docstring_md(
+ s_function = 'mcdsts.get_sdmcds_list',
+ ls_doc = pcdl.TimeSeries.get_sdmcds_list.__doc__.split('\n'),
+)
+docstring_md(
+ s_function = 'mcdsts.plot_timeseries',
+ ls_doc = pcdl.TimeSeries.plot_timeseries.__doc__.split('\n'),
+)
docstring_md(
s_function = 'mcdsts.make_ome_tiff',
ls_doc = pcdl.TimeSeries.make_ome_tiff.__doc__.split('\n'),
)
+
+
+# write pcdl making movies function markdown files
docstring_md(
s_function = 'pcdl.render_neuroglancer',
ls_doc = pcdl.render_neuroglancer.__doc__.split('\n'),
s_header = "mcdsts.render_neuroglancer('path/to/ome.tiff')"
)
-docstring_md(
- s_function = 'mcdsts.plot_timeseries',
- ls_doc = pcdl.TimeSeries.plot_timeseries.__doc__.split('\n'),
-)
-
-# write TimeSeries making movies function markdown files
docstring_md(
s_function = 'pcdl.make_gif',
ls_doc = pcdl.make_gif.__doc__.split('\n'),
@@ -462,25 +478,27 @@ def docstring_md(s_function, ls_doc, s_header=None, s_opath='man/docstring/'):
help_md(s_command='pcdl_get_unit_dict')
# substrate
help_md(s_command='pcdl_get_substrate_list')
-help_md(s_command='pcdl_get_conc_attribute')
help_md(s_command='pcdl_get_conc_df')
+help_md(s_command='pcdl_get_conc_attribute')
help_md(s_command='pcdl_plot_contour')
help_md(s_command='pcdl_make_conc_vtk')
# cell agent
help_md(s_command='pcdl_get_celltype_list')
-help_md(s_command='pcdl_get_cell_attribute_list')
-help_md(s_command='pcdl_get_cell_attribute')
help_md(s_command='pcdl_get_cell_df')
+help_md(s_command='pcdl_get_cell_attribute')
+help_md(s_command='pcdl_get_cell_attribute_list')
help_md(s_command='pcdl_get_anndata')
-help_md(s_command='pcdl_make_graph_gml')
help_md(s_command='pcdl_plot_scatter')
help_md(s_command='pcdl_make_cell_vtk')
+help_md(s_command='pcdl_make_graph_gml')
+help_md(s_command='pcdl_make_simularium')
# substrate and cell agent
+help_md(s_command='pcdl_get_muspan')
help_md(s_command='pcdl_get_spatialdata')
help_md(s_command='pcdl_plot_timeseries')
help_md(s_command='pcdl_make_ome_tiff')
-help_md(s_command='pcdl_render_neuroglancer')
# making movies
+help_md(s_command='pcdl_render_neuroglancer')
help_md(s_command='pcdl_make_gif')
help_md(s_command='pcdl_make_movie')
diff --git a/pcdl/VERSION.py b/pcdl/VERSION.py
index f589b73..a9e714a 100644
--- a/pcdl/VERSION.py
+++ b/pcdl/VERSION.py
@@ -1 +1 @@
-__version__ = '4.1.8'
+__version__ = '4.1.9'
diff --git a/pcdl/commandline.py b/pcdl/commandline.py
index 7123a46..a9dae84 100644
--- a/pcdl/commandline.py
+++ b/pcdl/commandline.py
@@ -250,11 +250,11 @@ def get_substrate_list():
return 0
-def get_conc_attribute():
+def get_conc_df():
# argv
parser = argparse.ArgumentParser(
- prog = 'pcdl_get_conc_attribute',
- description = 'function to detect informative substrate concentration variables in a time series. this function detects even variables which have less than the minimal state count in each time step, but different values from time step to time step. the output is a json file with an entry of all non-coordinate column names that, at least in one of the time steps or in between time steps, reach the given minimal value count. key is the column name, mapped is a list of all values (bool, str, and, if allvalues is True, int and float) or a list with minimum and maximum values (int, float).',
+ prog = 'pcdl_get_conc_df',
+ description = 'this function extracts dataframes with concentration values for all chemical species in all voxels and saves them as csv files. additionally, this dataframe lists voxel and mesh center coordinates.',
epilog = 'homepage: https://github.com/elmbeech/physicelldataloader',
)
@@ -263,7 +263,7 @@ def get_conc_attribute():
'path',
nargs = '?',
default = '.',
- help = 'path to the PhysiCell output directory. default is . .',
+ help = 'path to the PhysiCell output directory or a outputnnnnnnnn.xml file. default is . .',
)
# TimeSeries output_path '.'
# TimeSeries custom_data_type nop
@@ -277,7 +277,7 @@ def get_conc_attribute():
default = 'true',
help = 'setting verbose to False for less text output, while processing. default is True.',
)
- # get_conc_attribute values
+ # get_conc_df values
parser.add_argument(
'values',
nargs = '?',
@@ -285,25 +285,25 @@ def get_conc_attribute():
type = int,
help = 'minimal number of values a variable has to have in any of the mcds time steps to be outputted. variables that have only 1 state carry no information. None is a state too. default is 1.',
)
- # get_conc_attribute drop
+ # get_conc_df drop
parser.add_argument(
'--drop',
nargs = '*',
default = [],
help = "set of column labels to be dropped for the dataframe. don't worry: essential columns like ID, coordinates and time will never be dropped. Attention: when the keep parameter is given, then the drop parameter has to be an empty string! default is an empty string.",
)
- # get_conc_attribute keep
+ # get_conc_df keep
parser.add_argument(
'--keep',
nargs = '*',
default = [],
help = "set of column labels to be kept in the dataframe. set values=1 to be sure that all variables are kept. don't worry: essential columns like ID, coordinates and time will always be kept. default is an empty string.",
)
- # get_conc_attribute allvalues
+ # get_conc_df collapse
parser.add_argument(
- '--allvalues',
- default = 'false',
- help = 'for numeric data, should only the min and max values or all values be returned? default is false.',
+ '--collapse',
+ default = 'true',
+ help = 'should all mcds time steps from the time series be collapsed into one big csv, or a many csv, one for each time step? default is True.'
)
# parse arguments
@@ -322,42 +322,69 @@ def get_conc_attribute():
else:
s_path = '/'.join(s_path.split('/')[:-1])
if not os.path.exists(s_pathfile):
- sys.exit(f'Error @ pcdl_get_conc_attribute : {s_pathfile} path does not look like a outputnnnnnnnn.xml file or physicell output directory ({s_path}/initial.xml is missing).')
+ sys.exit(f'Error @ pcdl_get_conc_df : {s_pathfile} path does not look like a outputnnnnnnnn.xml file or physicell output directory ({s_path}/initial.xml is missing).')
# run
- mcdsts = pcdl.TimeSeries(
- output_path = s_path,
- #custom_data_type,
- load = True,
- microenv = True,
- graph = False,
- physiboss = False,
- settingxml = None,
- verbose = False if args.verbose.lower().startswith('f') else True,
- )
- s_values = 'minmax'
- b_allvalues = True if args.allvalues.lower().startswith('t') else False
- if b_allvalues:
- s_values = 'all'
- dl_variable = mcdsts.get_conc_attribute(
- values = args.values,
- drop = set(args.drop),
- keep = set(args.keep),
- allvalues = b_allvalues,
- )
- s_ofile = f"timeseries_conc_attribute_{s_values.replace(' ','_')}.json"
- s_opathfile = s_path + '/' + s_ofile
- json.dump(dl_variable, open(s_opathfile, 'w'), sort_keys=True)
+ if os.path.isfile(args.path):
+ mcds = pcdl.TimeStep(
+ xmlfile = s_pathfile,
+ output_path = '.',
+ #custom_data_type,
+ microenv = True,
+ graph = False,
+ physiboss = False,
+ settingxml = None,
+ verbose = False if args.verbose.lower().startswith('f') else True
+ )
+ df_conc = mcds.get_conc_df(
+ values = args.values,
+ drop = set(args.drop),
+ keep = set(args.keep),
+ )
+ # going home
+ s_opathfile = s_pathfile.replace('.xml','_conc.csv')
+ df_conc.to_csv(s_opathfile)
+ print(s_opathfile)
+
+ else:
+ mcdsts = pcdl.TimeSeries(
+ output_path = s_path,
+ #custom_data_type,
+ load = True,
+ microenv = True,
+ graph = False,
+ physiboss = False,
+ settingxml = None,
+ verbose = False if args.verbose.lower().startswith('f') else True,
+ )
+ # handle collaps
+ b_collapse = False if args.collapse.lower().startswith('f') else True
+ ldf_conc = mcdsts.get_conc_df(
+ values = args.values,
+ drop = set(args.drop),
+ keep = set(args.keep),
+ collapse = b_collapse,
+ )
+ # going home
+ if b_collapse:
+ s_opathfile = f'{s_path}/timeseries_conc.csv'
+ ldf_conc.to_csv(s_opathfile)
+ print(s_opathfile)
+ else:
+ ls_opathfile = [f"{s_path}/{s_xmlfile.replace('.xml','_conc.csv')}" for s_xmlfile in mcdsts.get_xmlfile_list()]
+ for i, df_conc in enumerate(ldf_conc):
+ df_conc.to_csv(ls_opathfile[i])
+ print(ls_opathfile)
+
# going home
- print(s_opathfile)
return 0
-def get_conc_df():
+def get_conc_attribute():
# argv
parser = argparse.ArgumentParser(
- prog = 'pcdl_get_conc_df',
- description = 'this function extracts dataframes with concentration values for all chemical species in all voxels and saves them as csv files. additionally, this dataframe lists voxel and mesh center coordinates.',
+ prog = 'pcdl_get_conc_attribute',
+ description = 'function to detect informative substrate concentration variables in a time series. this function detects even variables which have less than the minimal state count in each time step, but different values from time step to time step. the output is a json file with an entry of all non-coordinate column names that, at least in one of the time steps or in between time steps, reach the given minimal value count. key is the column name, mapped is a list of all values (bool, str, and, if allvalues is True, int and float) or a list with minimum and maximum values (int, float).',
epilog = 'homepage: https://github.com/elmbeech/physicelldataloader',
)
@@ -366,7 +393,7 @@ def get_conc_df():
'path',
nargs = '?',
default = '.',
- help = 'path to the PhysiCell output directory or a outputnnnnnnnn.xml file. default is . .',
+ help = 'path to the PhysiCell output directory. default is . .',
)
# TimeSeries output_path '.'
# TimeSeries custom_data_type nop
@@ -380,7 +407,7 @@ def get_conc_df():
default = 'true',
help = 'setting verbose to False for less text output, while processing. default is True.',
)
- # get_conc_df values
+ # get_conc_attribute values
parser.add_argument(
'values',
nargs = '?',
@@ -388,25 +415,25 @@ def get_conc_df():
type = int,
help = 'minimal number of values a variable has to have in any of the mcds time steps to be outputted. variables that have only 1 state carry no information. None is a state too. default is 1.',
)
- # get_conc_df drop
+ # get_conc_attribute drop
parser.add_argument(
'--drop',
nargs = '*',
default = [],
help = "set of column labels to be dropped for the dataframe. don't worry: essential columns like ID, coordinates and time will never be dropped. Attention: when the keep parameter is given, then the drop parameter has to be an empty string! default is an empty string.",
)
- # get_conc_df keep
+ # get_conc_attribute keep
parser.add_argument(
'--keep',
nargs = '*',
default = [],
help = "set of column labels to be kept in the dataframe. set values=1 to be sure that all variables are kept. don't worry: essential columns like ID, coordinates and time will always be kept. default is an empty string.",
)
- # get_conc_df collapse
+ # get_conc_attribute allvalues
parser.add_argument(
- '--collapse',
- default = 'true',
- help = 'should all mcds time steps from the time series be collapsed into one big csv, or a many csv, one for each time step? default is True.'
+ '--allvalues',
+ default = 'false',
+ help = 'for numeric data, should only the min and max values or all values be returned? default is false.',
)
# parse arguments
@@ -425,61 +452,34 @@ def get_conc_df():
else:
s_path = '/'.join(s_path.split('/')[:-1])
if not os.path.exists(s_pathfile):
- sys.exit(f'Error @ pcdl_get_conc_df : {s_pathfile} path does not look like a outputnnnnnnnn.xml file or physicell output directory ({s_path}/initial.xml is missing).')
+ sys.exit(f'Error @ pcdl_get_conc_attribute : {s_pathfile} path does not look like a outputnnnnnnnn.xml file or physicell output directory ({s_path}/initial.xml is missing).')
# run
- if os.path.isfile(args.path):
- mcds = pcdl.TimeStep(
- xmlfile = s_pathfile,
- output_path = '.',
- #custom_data_type,
- microenv = True,
- graph = False,
- physiboss = False,
- settingxml = None,
- verbose = False if args.verbose.lower().startswith('f') else True
- )
- df_conc = mcds.get_conc_df(
- values = args.values,
- drop = set(args.drop),
- keep = set(args.keep),
- )
- # going home
- s_opathfile = s_pathfile.replace('.xml','_conc.csv')
- df_conc.to_csv(s_opathfile)
- print(s_opathfile)
-
- else:
- mcdsts = pcdl.TimeSeries(
- output_path = s_path,
- #custom_data_type,
- load = True,
- microenv = True,
- graph = False,
- physiboss = False,
- settingxml = None,
- verbose = False if args.verbose.lower().startswith('f') else True,
- )
- # handle collaps
- b_collapse = False if args.collapse.lower().startswith('f') else True
- ldf_conc = mcdsts.get_conc_df(
- values = args.values,
- drop = set(args.drop),
- keep = set(args.keep),
- collapse = b_collapse,
- )
- # going home
- if b_collapse:
- s_opathfile = f'{s_path}/timeseries_conc.csv'
- ldf_conc.to_csv(s_opathfile)
- print(s_opathfile)
- else:
- ls_opathfile = [f"{s_path}/{s_xmlfile.replace('.xml','_conc.csv')}" for s_xmlfile in mcdsts.get_xmlfile_list()]
- for i, df_conc in enumerate(ldf_conc):
- df_conc.to_csv(ls_opathfile[i])
- print(ls_opathfile)
-
+ mcdsts = pcdl.TimeSeries(
+ output_path = s_path,
+ #custom_data_type,
+ load = True,
+ microenv = True,
+ graph = False,
+ physiboss = False,
+ settingxml = None,
+ verbose = False if args.verbose.lower().startswith('f') else True,
+ )
+ s_values = 'minmax'
+ b_allvalues = True if args.allvalues.lower().startswith('t') else False
+ if b_allvalues:
+ s_values = 'all'
+ dl_variable = mcdsts.get_conc_attribute(
+ values = args.values,
+ drop = set(args.drop),
+ keep = set(args.keep),
+ allvalues = b_allvalues,
+ )
+ s_ofile = f"timeseries_conc_attribute_{s_values.replace(' ','_')}.json"
+ s_opathfile = s_path + '/' + s_ofile
+ json.dump(dl_variable, open(s_opathfile, 'w'), sort_keys=True)
# going home
+ print(s_opathfile)
return 0
@@ -832,6 +832,7 @@ def make_conc_vtk():
# going home
return 0
+
############################################
# cell agent relatd command line functions #
############################################
@@ -903,11 +904,11 @@ def get_celltype_list():
return 0
-def get_cell_attribute_list():
+def get_cell_df():
# argv
parser = argparse.ArgumentParser(
- prog = 'pcdl_get_cell_attribute_list',
- description = 'this function is returns a list with all cell attribute labels, alphabetically ordered.',
+ prog = 'pcdl_get_cell_df',
+ description = 'this function extracts dataframes with a cell centric view of the simulation and saves them as csv files.',
epilog = 'homepage: https://github.com/elmbeech/physicelldataloader',
)
@@ -916,22 +917,22 @@ def get_cell_attribute_list():
'path',
nargs = '?',
default = '.',
- help = 'path to the PhysiCell output directory or a outputnnnnnnnn.xml file. default is . .',
+ help = 'path to the PhysiCell output directory or a outputnnnnnnnn.xml file. default is . .'
)
# TimeSeries output_path '.'
- # TimeSeries custom_data_type nop
+ # TimeSeries custom_data_type nop (because datafarme is straightaway saved as csv)
# TimeSeries microenv
parser.add_argument(
'--microenv',
default = 'true',
- help = 'should the microenvironment data be loaded? setting microenv to False will use less memory and speed up processing. default is True.',
+ help = 'should the microenvironment data be loaded? setting microenv to False will use less memory and speed up processing. default is True.'
)
# TimeSeries graph False
# TimeSeries physiboss
parser.add_argument(
'--physiboss',
default = 'true',
- help = 'if found, should physiboss state data be extracted and loaded into df_cell dataframe? default is True.'
+ help = 'if found, should physiboss state data be extracted and loaded into the df_cell dataframe? default is True.'
)
# TimeSeries settingxml
parser.add_argument(
@@ -942,8 +943,36 @@ def get_cell_attribute_list():
# TimeSeries verbose
parser.add_argument(
'-v', '--verbose',
- default = 'false',
- help = 'setting verbose to True for more text output, while processing. default is False.',
+ default = 'true',
+ help = 'setting verbose to False for less text output, while processing. default is True.'
+ )
+ # get_cell_df values
+ parser.add_argument(
+ 'values',
+ nargs = '?',
+ default = 1,
+ type = int,
+ help = 'minimal number of values a variable has to have in any of the mcds time steps to be outputted. variables that have only 1 state carry no information. None is a state too. default is 1.'
+ )
+ # get_cell_df drop
+ parser.add_argument(
+ '--drop',
+ nargs = '*',
+ default = [],
+ help = "set of column labels to be dropped for the dataframe. don't worry: essential columns like ID, coordinates and time will never be dropped. Attention: when the keep parameter is given, then the drop parameter has to be an empty string! default is an empty string."
+ )
+ # get_cell_df keep
+ parser.add_argument(
+ '--keep',
+ nargs = '*',
+ default = [],
+ help = "set of column labels to be kept in the dataframe. set values=1 to be sure that all variables are kept. don't worry: essential columns like ID, coordinates and time will always be kept. default is an empty string."
+ )
+ # get_cell_df collapse
+ parser.add_argument(
+ '--collapse',
+ default = 'true',
+ help = 'should all mcds time steps from the time series be collapsed into one big csv, or a many csv, one csv for each time step?, default is True.'
)
# parse arguments
@@ -962,22 +991,62 @@ def get_cell_attribute_list():
else:
s_path = '/'.join(s_path.split('/')[:-1])
if not os.path.exists(s_pathfile):
- sys.exit(f'Error @ pcdl_get_cell_attribute_list : {s_pathfile} path does not look like a outputnnnnnnnn.xml file or physicell output directory ({s_path}/initial.xml is missing).')
+ sys.exit(f'Error @ pcdl_get_cell_df : {s_pathfile} path does not look like a outputnnnnnnnn.xml file or physicell output directory ({s_path}/initial.xml is missing).')
# run
- mcds = pcdl.TimeStep(
- xmlfile = s_pathfile,
- output_path = '.',
- #custom_data_type,
- microenv = False if args.microenv.lower().startswith('f') else True,
- graph = False,
- physiboss = False if args.physiboss.lower().startswith('f') else True,
- settingxml = None if ((args.settingxml.lower() == 'none') or (args.settingxml.lower() == 'false')) else args.settingxml,
- verbose = True if args.verbose.lower().startswith('t') else False
- )
+ if os.path.isfile(args.path):
+ mcds = pcdl.TimeStep(
+ xmlfile = s_pathfile,
+ output_path = '.',
+ #custom_data_type,
+ microenv = False if args.microenv.lower().startswith('f') else True,
+ graph = False,
+ physiboss = False if args.physiboss.lower().startswith('f') else True,
+ settingxml = None if ((args.settingxml.lower() == 'none') or (args.settingxml.lower() == 'false')) else args.settingxml,
+ verbose = False if args.verbose.lower().startswith('f') else True
+ )
+ df_cell = mcds.get_cell_df(
+ values = args.values,
+ drop = set(args.drop),
+ keep = set(args.keep),
+ )
+ # going home
+ s_opathfile = s_pathfile.replace('.xml','_cell.csv')
+ df_cell.to_csv(s_opathfile)
+ print(s_opathfile)
+
+ else:
+ mcdsts = pcdl.TimeSeries(
+ output_path = s_path,
+ #custom_data_type,
+ load = True,
+ microenv = False if args.microenv.lower().startswith('f') else True,
+ graph = False,
+ physiboss = False if args.physiboss.lower().startswith('f') else True,
+ settingxml = None if ((args.settingxml.lower() == 'none') or (args.settingxml.lower() == 'false')) else args.settingxml,
+ verbose = False if args.verbose.lower().startswith('f') else True,
+ )
+ # handle collaps
+ b_collapse = False if args.collapse.lower().startswith('f') else True
+ ldf_cell = mcdsts.get_cell_df(
+ values = args.values,
+ drop = set(args.drop),
+ keep = set(args.keep),
+ collapse = b_collapse,
+ )
+ # going home
+ if b_collapse:
+ s_opathfile = f'{s_path}/timeseries_cell.csv'
+ ldf_cell.to_csv(s_opathfile)
+ print(s_opathfile)
+ else:
+ ls_opathfile = [f"{s_path}/{s_xmlfile.replace('.xml','_cell.csv')}" for s_xmlfile in mcdsts.get_xmlfile_list()]
+ for i, df_cell in enumerate(ldf_cell):
+ df_cell.to_csv(ls_opathfile[i])
+ print(ls_opathfile)
# going home
- print(mcds.get_cell_attribute_list())
+ return 0
def get_cell_attribute():
@@ -1137,11 +1206,11 @@ def get_cell_attribute():
return 0
-def get_cell_df():
+def get_cell_attribute_list():
# argv
parser = argparse.ArgumentParser(
- prog = 'pcdl_get_cell_df',
- description = 'this function extracts dataframes with a cell centric view of the simulation and saves them as csv files.',
+ prog = 'pcdl_get_cell_attribute_list',
+ description = 'this function is returns a list with all cell attribute labels, alphabetically ordered.',
epilog = 'homepage: https://github.com/elmbeech/physicelldataloader',
)
@@ -1150,22 +1219,22 @@ def get_cell_df():
'path',
nargs = '?',
default = '.',
- help = 'path to the PhysiCell output directory or a outputnnnnnnnn.xml file. default is . .'
+ help = 'path to the PhysiCell output directory or a outputnnnnnnnn.xml file. default is . .',
)
# TimeSeries output_path '.'
- # TimeSeries custom_data_type nop (because datafarme is straightaway saved as csv)
+ # TimeSeries custom_data_type nop
# TimeSeries microenv
parser.add_argument(
'--microenv',
default = 'true',
- help = 'should the microenvironment data be loaded? setting microenv to False will use less memory and speed up processing. default is True.'
+ help = 'should the microenvironment data be loaded? setting microenv to False will use less memory and speed up processing. default is True.',
)
# TimeSeries graph False
# TimeSeries physiboss
parser.add_argument(
'--physiboss',
default = 'true',
- help = 'if found, should physiboss state data be extracted and loaded into the df_cell dataframe? default is True.'
+ help = 'if found, should physiboss state data be extracted and loaded into df_cell dataframe? default is True.'
)
# TimeSeries settingxml
parser.add_argument(
@@ -1176,36 +1245,8 @@ def get_cell_df():
# TimeSeries verbose
parser.add_argument(
'-v', '--verbose',
- default = 'true',
- help = 'setting verbose to False for less text output, while processing. default is True.'
- )
- # get_cell_df values
- parser.add_argument(
- 'values',
- nargs = '?',
- default = 1,
- type = int,
- help = 'minimal number of values a variable has to have in any of the mcds time steps to be outputted. variables that have only 1 state carry no information. None is a state too. default is 1.'
- )
- # get_cell_df drop
- parser.add_argument(
- '--drop',
- nargs = '*',
- default = [],
- help = "set of column labels to be dropped for the dataframe. don't worry: essential columns like ID, coordinates and time will never be dropped. Attention: when the keep parameter is given, then the drop parameter has to be an empty string! default is an empty string."
- )
- # get_cell_df keep
- parser.add_argument(
- '--keep',
- nargs = '*',
- default = [],
- help = "set of column labels to be kept in the dataframe. set values=1 to be sure that all variables are kept. don't worry: essential columns like ID, coordinates and time will always be kept. default is an empty string."
- )
- # get_cell_df collapse
- parser.add_argument(
- '--collapse',
- default = 'true',
- help = 'should all mcds time steps from the time series be collapsed into one big csv, or a many csv, one csv for each time step?, default is True.'
+ default = 'false',
+ help = 'setting verbose to True for more text output, while processing. default is False.',
)
# parse arguments
@@ -1224,62 +1265,22 @@ def get_cell_df():
else:
s_path = '/'.join(s_path.split('/')[:-1])
if not os.path.exists(s_pathfile):
- sys.exit(f'Error @ pcdl_get_cell_df : {s_pathfile} path does not look like a outputnnnnnnnn.xml file or physicell output directory ({s_path}/initial.xml is missing).')
+ sys.exit(f'Error @ pcdl_get_cell_attribute_list : {s_pathfile} path does not look like a outputnnnnnnnn.xml file or physicell output directory ({s_path}/initial.xml is missing).')
# run
- if os.path.isfile(args.path):
- mcds = pcdl.TimeStep(
- xmlfile = s_pathfile,
- output_path = '.',
- #custom_data_type,
- microenv = False if args.microenv.lower().startswith('f') else True,
- graph = False,
- physiboss = False if args.physiboss.lower().startswith('f') else True,
- settingxml = None if ((args.settingxml.lower() == 'none') or (args.settingxml.lower() == 'false')) else args.settingxml,
- verbose = False if args.verbose.lower().startswith('f') else True
- )
- df_cell = mcds.get_cell_df(
- values = args.values,
- drop = set(args.drop),
- keep = set(args.keep),
- )
- # going home
- s_opathfile = s_pathfile.replace('.xml','_cell.csv')
- df_cell.to_csv(s_opathfile)
- print(s_opathfile)
-
- else:
- mcdsts = pcdl.TimeSeries(
- output_path = s_path,
- #custom_data_type,
- load = True,
- microenv = False if args.microenv.lower().startswith('f') else True,
- graph = False,
- physiboss = False if args.physiboss.lower().startswith('f') else True,
- settingxml = None if ((args.settingxml.lower() == 'none') or (args.settingxml.lower() == 'false')) else args.settingxml,
- verbose = False if args.verbose.lower().startswith('f') else True,
- )
- # handle collaps
- b_collapse = False if args.collapse.lower().startswith('f') else True
- ldf_cell = mcdsts.get_cell_df(
- values = args.values,
- drop = set(args.drop),
- keep = set(args.keep),
- collapse = b_collapse,
- )
- # going home
- if b_collapse:
- s_opathfile = f'{s_path}/timeseries_cell.csv'
- ldf_cell.to_csv(s_opathfile)
- print(s_opathfile)
- else:
- ls_opathfile = [f"{s_path}/{s_xmlfile.replace('.xml','_cell.csv')}" for s_xmlfile in mcdsts.get_xmlfile_list()]
- for i, df_cell in enumerate(ldf_cell):
- df_cell.to_csv(ls_opathfile[i])
- print(ls_opathfile)
+ mcds = pcdl.TimeStep(
+ xmlfile = s_pathfile,
+ output_path = '.',
+ #custom_data_type,
+ microenv = False if args.microenv.lower().startswith('f') else True,
+ graph = False,
+ physiboss = False if args.physiboss.lower().startswith('f') else True,
+ settingxml = None if ((args.settingxml.lower() == 'none') or (args.settingxml.lower() == 'false')) else args.settingxml,
+ verbose = True if args.verbose.lower().startswith('t') else False
+ )
# going home
- return 0
+ print(mcds.get_cell_attribute_list())
def get_anndata():
@@ -1458,11 +1459,11 @@ def get_anndata():
return 0
-def make_graph_gml():
+def plot_scatter():
# argv
parser = argparse.ArgumentParser(
- prog = 'pcdl_make_graph_gml',
- description = 'function to generate graph files in the gml graph modelling language standard format. gml was the outcome of an initiative that started at the international symposium on graph drawing 1995 in Passau and ended at Graph Drawing 1996 in Berkeley. the networkx python library (https://networkx.org/) and igraph C and python libraries (https://igraph.org/) for graph analysis are gml compatible and can as such read and write this file format.',
+ prog = 'pcdl_plot_scatter',
+ description = 'function generates pandas scatter plots, under the returned path.',
epilog = 'homepage: https://github.com/elmbeech/physicelldataloader',
)
@@ -1485,9 +1486,9 @@ def make_graph_gml():
parser.add_argument(
'--microenv',
default = 'true',
- help = 'should the microenvironment data be loaded? setting microenv to False will use less memory and speed up processing. default is True.'
+ help = 'should the microenvironment data be loaded? setting microenv to False will use less memory and speed up processing. default is True.',
)
- # TimeSeries graph True
+ # TimeSeries graph False
# TimeSeries physiboss
parser.add_argument(
'--physiboss',
@@ -1506,167 +1507,26 @@ def make_graph_gml():
default = 'true',
help = 'setting verbose to False for less text output, while processing. default is True.',
)
- # make_graph_gml graph_type
+ # plot_scatter focus
parser.add_argument(
- 'graph_type',
+ 'focus',
nargs = '?',
- help = 'to specify which physicell output data should be processed. attached: processes mcds.get_attached_graph_dict dictionary. neighbor: processes mcds.get_neighbor_graph_dict dictionary spring: processes mcds.get_spring_graph_dict dictionary.',
+ default = 'cell_type',
+ help = 'column name within conc dataframe. default is cell_type.',
)
- # make_graph_gml edge_attribute
+ # plot_scatter cat_drop
parser.add_argument(
- '--edge_attribute',
- default = 'true',
- help = 'specifies if the spatial Euclidean distance is used for edge attribute, to generate a weighted graph. default is True.',
+ '--cat_drop',
+ nargs = '*',
+ default = [],
+ help = "if focus is a categorical attribute, set of category labels, strings separated by space, to be dropped for the dataframe. Attention: when the cat_keep parameter is given, then the cat_drop parameter has to be an empty string! default is an empty string.",
)
- # make_graph_gml node_attrributes
+ # plot_scatter cat_keep
parser.add_argument(
- '--node_attribute',
+ '--cat_keep',
nargs = '*',
default = [],
- help = 'listing of mcds.get_cell_df dataframe columns, used for node attributes. default is and empty list.',
- )
-
- # parse arguments
- args = parser.parse_args()
- print(args)
-
- # process arguments
- s_path = args.path.replace('\\','/')
- while (s_path.find('//') > -1):
- s_path = s_path.replace('//','/')
- if (s_path.endswith('/')) and (len(s_path) > 1):
- s_path = s_path[:-1]
- s_pathfile = s_path
- if not s_pathfile.endswith('.xml'):
- s_pathfile = s_pathfile + '/initial.xml'
- else:
- s_path = '/'.join(s_path.split('/')[:-1])
- if not os.path.exists(s_pathfile):
- sys.exit(f'Error @ pcdl_make_graph_gml : {s_pathfile} path does not look like a outputnnnnnnnn.xml file or physicell output directory ({s_path}/initial.xml is missing).')
-
- # custom_data_type
- d_vartype = {}
- for vartype in args.custom_data_type:
- s_var, s_type = vartype.split(':')
- if s_type in {'bool'}: o_type = bool
- elif s_type in {'int'}: o_type = int
- elif s_type in {'float'}: o_type = float
- elif s_type in {'str'}: o_type = str
- else:
- sys.exit(f'Error @ pcdl_make_graph_gml : {s_var} {s_type} has an unknowen data type. knowen are bool, int, float, str.')
- d_vartype.update({s_var : o_type})
-
- # run
- if os.path.isfile(args.path):
- mcds = pcdl.TimeStep(
- xmlfile = s_pathfile,
- output_path = '.',
- custom_data_type = d_vartype,
- microenv = False if args.microenv.lower().startswith('f') else True,
- graph = True,
- physiboss = False if args.physiboss.lower().startswith('f') else True,
- settingxml = None if ((args.settingxml.lower() == 'none') or (args.settingxml.lower() == 'false')) else args.settingxml,
- verbose = False if args.verbose.lower().startswith('f') else True
- )
- s_opathfile = mcds.make_graph_gml(
- graph_type = args.graph_type,
- edge_attribute = False if args.edge_attribute.lower().startswith('f') else True,
- node_attribute = args.node_attribute,
- )
- # going home
- print(s_opathfile)
-
- else:
- mcdsts = pcdl.TimeSeries(
- output_path = s_path,
- custom_data_type = d_vartype,
- load = True,
- microenv = False if args.microenv.lower().startswith('f') else True,
- graph = True,
- physiboss = False if args.physiboss.lower().startswith('f') else True,
- settingxml = None if ((args.settingxml.lower() == 'none') or (args.settingxml.lower() == 'false')) else args.settingxml,
- verbose = False if args.verbose.lower().startswith('f') else True,
- )
- ls_opathfile = mcdsts.make_graph_gml(
- graph_type = args.graph_type,
- edge_attribute = False if args.edge_attribute.lower().startswith('f') else True,
- node_attribute = args.node_attribute,
- )
- # going home
- print(ls_opathfile)
-
- # going home
- return 0
-
-
-def plot_scatter():
- # argv
- parser = argparse.ArgumentParser(
- prog = 'pcdl_plot_scatter',
- description = 'function generates pandas scatter plots, under the returned path.',
- epilog = 'homepage: https://github.com/elmbeech/physicelldataloader',
- )
-
- # TimeSeries path
- parser.add_argument(
- 'path',
- nargs = '?',
- default = '.',
- help = 'path to the PhysiCell output directory or a outputnnnnnnnn.xml file. default is . .',
- )
- # TimeSeries output_path '.'
- # TimeSeries custom_data_type
- parser.add_argument(
- '--custom_data_type',
- nargs = '*',
- default = [],
- help = 'parameter to specify custom_data variable types other than float (namely: int, bool, str) like this var:dtype myint:int mybool:bool mystr:str . downstream float and int will be handled as numeric, bool as Boolean, and str as categorical data. default is an empty string.',
- )
- # TimeSeries microenv
- parser.add_argument(
- '--microenv',
- default = 'true',
- help = 'should the microenvironment data be loaded? setting microenv to False will use less memory and speed up processing. default is True.',
- )
- # TimeSeries graph False
- # TimeSeries physiboss
- parser.add_argument(
- '--physiboss',
- default = 'true',
- help = 'if found, should physiboss state data be extracted and loaded into the df_cell dataframe? default is True.'
- )
- # TimeSeries settingxml
- parser.add_argument(
- '--settingxml',
- default = 'false',
- help = 'the settings.xml that is loaded, from which the cell type ID label mapping, is extracted, if this information is not found in the output xml file. set to None or False if the xml file is missing! default is False.',
- )
- # TimeSeries verbose
- parser.add_argument(
- '-v', '--verbose',
- default = 'true',
- help = 'setting verbose to False for less text output, while processing. default is True.',
- )
- # plot_scatter focus
- parser.add_argument(
- 'focus',
- nargs = '?',
- default = 'cell_type',
- help = 'column name within conc dataframe. default is cell_type.',
- )
- # plot_scatter cat_drop
- parser.add_argument(
- '--cat_drop',
- nargs = '*',
- default = [],
- help = "if focus is a categorical attribute, set of category labels, strings separated by space, to be dropped for the dataframe. Attention: when the cat_keep parameter is given, then the cat_drop parameter has to be an empty string! default is an empty string.",
- )
- # plot_scatter cat_keep
- parser.add_argument(
- '--cat_keep',
- nargs = '*',
- default = [],
- help = "if focus is a categorical attribute, set of category labels, strings separated by space, to be kept in the dataframe. default is an empty string.",
+ help = "if focus is a categorical attribute, set of category labels, strings separated by space, to be kept in the dataframe. default is an empty string.",
)
# plot_scatter z_slice
parser.add_argument(
@@ -1741,30 +1601,338 @@ def plot_scatter():
type = float,
help = 'scatter plot dot size scale factor. with figsizepx extracted from initial.svg, scale factor 1.0 should be ok. adjust if necessary. default 1.0.',
)
- # plot_scatter figsizepx
+ # plot_scatter figsizepx
+ parser.add_argument(
+ '--figsizepx',
+ nargs = '+',
+ default = ['none'],
+ help = 'size of the figure in pixels (integer), x y. the given x and y will be rounded to the nearest even number, to be able to generate movies from the images. None tries to take the values from the initial.svg file. fall back setting is 640 480. default is None.',
+ )
+ # plot_scatter directory
+ parser.add_argument(
+ '--directory',
+ default = 'none',
+ help = 'if none, a meaningful output directory name will be generated, based on focus and z_slice parameters, else the resulting plots will be moved to the explicit name directory.',
+ )
+ # plot_scatter ext
+ parser.add_argument(
+ '--ext',
+ default = 'jpeg',
+ help = 'output image format. possible formats are jpeg, png, and tiff. default is jpeg.',
+ )
+ # plot_scatter figbgcolor
+ parser.add_argument(
+ '--figbgcolor',
+ default = 'none',
+ help = 'figure background color. None is transparent (png) or white (jpeg, tiff). default is None.',
+ )
+
+ # parse arguments
+ args = parser.parse_args()
+ print(args)
+
+ # process arguments
+ s_path = args.path.replace('\\','/')
+ while (s_path.find('//') > -1):
+ s_path = s_path.replace('//','/')
+ if (s_path.endswith('/')) and (len(s_path) > 1):
+ s_path = s_path[:-1]
+ s_pathfile = s_path
+ if not s_pathfile.endswith('.xml'):
+ s_pathfile = s_pathfile + '/initial.xml'
+ else:
+ s_path = '/'.join(s_pathfile.split('/')[:-1])
+ if not os.path.exists(s_pathfile):
+ sys.exit(f'Error @ pcdl_plot_scatter : {s_pathfile} path does not look like a outputnnnnnnnn.xml file or physicell output directory ({s_path}/initial.xml is missing).')
+
+ # custom_data_type
+ d_vartype = {}
+ for vartype in args.custom_data_type:
+ s_var, s_type = vartype.split(':')
+ if s_type in {'bool'}: o_type = bool
+ elif s_type in {'int'}: o_type = int
+ elif s_type in {'float'}: o_type = float
+ elif s_type in {'str'}: o_type = str
+ else:
+ sys.exit(f'Error @ pcdl_plot_scatter : {s_var} {s_type} has an unknowen data type. knowen are bool, int, float, str.')
+ d_vartype.update({s_var : o_type})
+
+ # run
+ if os.path.isfile(args.path):
+ mcds = pcdl.TimeStep(
+ xmlfile = s_pathfile,
+ output_path = '.',
+ custom_data_type = d_vartype,
+ microenv = False if args.microenv.lower().startswith('f') else True,
+ graph = False,
+ physiboss = False if args.physiboss.lower().startswith('f') else True,
+ settingxml = None if ((args.settingxml.lower() == 'none') or (args.settingxml.lower() == 'false')) else args.settingxml,
+ verbose = False if args.verbose.lower().startswith('f') else True
+ )
+ # plot
+ s_opathfile = mcds.plot_scatter(
+ focus = args.focus,
+ cat_drop = set(args.cat_drop),
+ cat_keep = set(args.cat_keep),
+ z_slice = args.z_slice,
+ z_axis = None if (args.z_axis[0].lower() == 'none') else args.z_axis,
+ alpha = args.alpha,
+ cmap = args.cmap,
+ title = args.title,
+ grid = False if args.grid.lower().startswith('f') else True,
+ legend_loc = args.legend_loc,
+ xlim = None if (args.xlim[0].lower() == 'none') else args.xlim,
+ ylim = None if (args.ylim[0].lower() == 'none') else args.ylim,
+ xyequal = False if args.xyequal.lower().startswith('f') else True,
+ s = args.s,
+ ax = None,
+ figsizepx = None if (args.figsizepx[0].lower() == 'none') else [int(i) for i in args.figsizepx],
+ directory = None if (args.directory.lower() == 'none') else args.directory,
+ ext = args.ext,
+ figbgcolor = None if (args.figbgcolor.lower() == 'none') else args.figbgcolor,
+ )
+ # going home
+ print(s_opathfile)
+
+ else:
+ mcdsts = pcdl.TimeSeries(
+ output_path = s_path,
+ custom_data_type = d_vartype,
+ load = True,
+ microenv = False if args.microenv.lower().startswith('f') else True,
+ graph = False,
+ physiboss = False if args.physiboss.lower().startswith('f') else True,
+ settingxml = None if ((args.settingxml.lower() == 'none') or (args.settingxml.lower() == 'false')) else args.settingxml,
+ verbose = False if args.verbose.lower().startswith('f') else True,
+ )
+ # plot
+ ls_opathfile = mcdsts.plot_scatter(
+ focus = args.focus,
+ cat_drop = set(args.cat_drop),
+ cat_keep = set(args.cat_keep),
+ z_slice = args.z_slice,
+ z_axis = None if (args.z_axis[0].lower() == 'none') else args.z_axis,
+ alpha = args.alpha,
+ cmap = args.cmap,
+ title = args.title,
+ grid = False if args.grid.lower().startswith('f') else True,
+ legend_loc = args.legend_loc,
+ xlim = None if (args.xlim[0].lower() == 'none') else args.xlim,
+ ylim = None if (args.ylim[0].lower() == 'none') else args.ylim,
+ xyequal = False if args.xyequal.lower().startswith('f') else True,
+ s = args.s,
+ figsizepx = None if (args.figsizepx[0].lower() == 'none') else [int(i) for i in args.figsizepx],
+ directory = None if (args.directory.lower() == 'none') else args.directory,
+ ext = args.ext,
+ figbgcolor = None if (args.figbgcolor.lower() == 'none') else args.figbgcolor,
+ )
+ # going home
+ s_opath = '/'.join(ls_opathfile[0].split('/')[:-1])
+ print(s_opath)
+
+ # going home
+ return 0
+
+
+def make_cell_vtk():
+ # argv
+ parser = argparse.ArgumentParser(
+ prog = 'pcdl_make_cell_vtk',
+ description = 'function that generates 3D glyph vtk file for cells. cells can have specified attributes like cell_type, pressure, dead, etc. you can post-process this file in other software like paraview (https://www.paraview.org/).',
+ epilog = 'homepage: https://github.com/elmbeech/physicelldataloader',
+ )
+
+ # TimeSeries path
+ parser.add_argument(
+ 'path',
+ nargs = '?',
+ default = '.',
+ help = 'path to the PhysiCell output directory or a outputnnnnnnnn.xml file. default is . .',
+ )
+ # TimeSeries output_path '.'
+ # TimeSeries custom_data_type
+ parser.add_argument(
+ '--custom_data_type',
+ nargs = '*',
+ default = [],
+ help = 'parameter to specify custom_data variable types other than float (namely: int, bool, str) like this var:dtype myint:int mybool:bool mystr:str . downstream float and int will be handled as numeric, bool as Boolean, and str as categorical data. default is an empty string.',
+ )
+ # TimeSeries microenv
+ parser.add_argument(
+ '--microenv',
+ default = 'true',
+ help = 'should the microenvironment data be loaded? setting microenv to False will use less memory and speed up processing. default is True.',
+ )
+ # TimeSeries graph False
+ # TimeSeries physiboss
+ parser.add_argument(
+ '--physiboss',
+ default = 'true',
+ help = 'if found, should physiboss state data be extracted and loaded into the df_cell dataframe? default is True.',
+ )
+ # TimeSeries settingxml
+ parser.add_argument(
+ '--settingxml',
+ default = 'false',
+ help = 'the settings.xml that is loaded, from which the cell type ID label mapping, is extracted, if this information is not found in the output xml file. set to None or False if the xml file is missing! default is False.',
+ )
+ # TimeSeries verbose
+ parser.add_argument(
+ '-v', '--verbose',
+ default = 'true',
+ help = 'setting verbose to False for less text output, while processing. default is True.',
+ )
+ # make_cell_vtk attrribute
+ parser.add_argument(
+ 'attribute',
+ nargs = '*',
+ default = ['cell_type'],
+ help = 'listing of mcds.get_cell_df dataframe column names, used for cell attributes. default is a single term: cell_type.',
+ )
+ # make_cell_vtk file extension
+ parser.add_argument(
+ '--ext',
+ default = '_cell.vtp',
+ help = 'set file extension for the vtk polydata file. for example, the blender BVTKNodes plugin needs a simplified .vtp file extension to be able to load timeseries directly.',
+ )
+
+ # parse arguments
+ args = parser.parse_args()
+ print(args)
+
+ # process arguments
+ s_path = args.path.replace('\\','/')
+ while (s_path.find('//') > -1):
+ s_path = s_path.replace('//','/')
+ if (s_path.endswith('/')) and (len(s_path) > 1):
+ s_path = s_path[:-1]
+ s_pathfile = s_path
+ if not s_pathfile.endswith('.xml'):
+ s_pathfile = s_pathfile + '/initial.xml'
+ else:
+ s_path = '/'.join(s_pathfile.split('/')[:-1])
+ if not os.path.exists(s_pathfile):
+ sys.exit(f'Error @ pcdl_make_cell_vtk : {s_pathfile} path does not look like a outputnnnnnnnn.xml file or physicell output directory ({s_path}/initial.xml is missing).')
+
+ # custom_data_type
+ d_vartype = {}
+ for vartype in args.custom_data_type:
+ s_var, s_type = vartype.split(':')
+ if s_type in {'bool'}: o_type = bool
+ elif s_type in {'int'}: o_type = int
+ elif s_type in {'float'}: o_type = float
+ elif s_type in {'str'}: o_type = str
+ else:
+ sys.exit(f'Error @ pcdl_make_cell_vtk : {s_var} {s_type} has an unknowen data type. knowen are bool, int, float, str.')
+ d_vartype.update({s_var : o_type})
+
+ # run
+ if os.path.isfile(args.path):
+ mcds = pcdl.TimeStep(
+ xmlfile = s_pathfile,
+ output_path = '.',
+ custom_data_type = d_vartype,
+ microenv = False if args.microenv.lower().startswith('f') else True,
+ graph = False,
+ physiboss = False if args.physiboss.lower().startswith('f') else True,
+ settingxml = None if ((args.settingxml.lower() == 'none') or (args.settingxml.lower() == 'false')) else args.settingxml,
+ verbose = False if args.verbose.lower().startswith('f') else True
+ )
+ s_opathfile = mcds.make_cell_vtk(
+ attribute = args.attribute,
+ ext = args.ext,
+ )
+ # going home
+ print(s_opathfile)
+
+ else:
+ mcdsts = pcdl.TimeSeries(
+ output_path = s_path,
+ custom_data_type = d_vartype,
+ load = True,
+ microenv = False if args.microenv.lower().startswith('f') else True,
+ graph = False,
+ physiboss = False if args.physiboss.lower().startswith('f') else True,
+ settingxml = None if ((args.settingxml.lower() == 'none') or (args.settingxml.lower() == 'false')) else args.settingxml,
+ verbose = False if args.verbose.lower().startswith('f') else True,
+ )
+ ls_opathfile = mcdsts.make_cell_vtk(
+ attribute = args.attribute,
+ ext = args.ext,
+ )
+ # going home
+ print(ls_opathfile)
+
+ # going home
+ return 0
+
+
+def make_graph_gml():
+ # argv
+ parser = argparse.ArgumentParser(
+ prog = 'pcdl_make_graph_gml',
+ description = 'function to generate graph files in the gml graph modelling language standard format. gml was the outcome of an initiative that started at the international symposium on graph drawing 1995 in Passau and ended at Graph Drawing 1996 in Berkeley. the networkx python library (https://networkx.org/) and igraph C and python libraries (https://igraph.org/) for graph analysis are gml compatible and can as such read and write this file format.',
+ epilog = 'homepage: https://github.com/elmbeech/physicelldataloader',
+ )
+
+ # TimeSeries path
+ parser.add_argument(
+ 'path',
+ nargs = '?',
+ default = '.',
+ help = 'path to the PhysiCell output directory or a outputnnnnnnnn.xml file. default is . .',
+ )
+ # TimeSeries output_path '.'
+ # TimeSeries custom_data_type
+ parser.add_argument(
+ '--custom_data_type',
+ nargs = '*',
+ default = [],
+ help = 'parameter to specify custom_data variable types other than float (namely: int, bool, str) like this var:dtype myint:int mybool:bool mystr:str . downstream float and int will be handled as numeric, bool as Boolean, and str as categorical data. default is an empty string.',
+ )
+ # TimeSeries microenv
+ parser.add_argument(
+ '--microenv',
+ default = 'true',
+ help = 'should the microenvironment data be loaded? setting microenv to False will use less memory and speed up processing. default is True.'
+ )
+ # TimeSeries graph True
+ # TimeSeries physiboss
+ parser.add_argument(
+ '--physiboss',
+ default = 'true',
+ help = 'if found, should physiboss state data be extracted and loaded into the df_cell dataframe? default is True.'
+ )
+ # TimeSeries settingxml
+ parser.add_argument(
+ '--settingxml',
+ default = 'false',
+ help = 'the settings.xml that is loaded, from which the cell type ID label mapping, is extracted, if this information is not found in the output xml file. set to None or False if the xml file is missing! default is False.',
+ )
+ # TimeSeries verbose
parser.add_argument(
- '--figsizepx',
- nargs = '+',
- default = ['none'],
- help = 'size of the figure in pixels (integer), x y. the given x and y will be rounded to the nearest even number, to be able to generate movies from the images. None tries to take the values from the initial.svg file. fall back setting is 640 480. default is None.',
+ '-v', '--verbose',
+ default = 'true',
+ help = 'setting verbose to False for less text output, while processing. default is True.',
)
- # plot_scatter directory
+ # make_graph_gml graph_type
parser.add_argument(
- '--directory',
- default = 'none',
- help = 'if none, a meaningful output directory name will be generated, based on focus and z_slice parameters, else the resulting plots will be moved to the explicit name directory.',
+ 'graph_type',
+ nargs = '?',
+ help = 'to specify which physicell output data should be processed. attached: processes mcds.get_attached_graph_dict dictionary. neighbor: processes mcds.get_neighbor_graph_dict dictionary spring: processes mcds.get_spring_graph_dict dictionary.',
)
- # plot_scatter ext
+ # make_graph_gml edge_attribute
parser.add_argument(
- '--ext',
- default = 'jpeg',
- help = 'output image format. possible formats are jpeg, png, and tiff. default is jpeg.',
+ '--edge_attribute',
+ default = 'true',
+ help = 'specifies if the spatial Euclidean distance is used for edge attribute, to generate a weighted graph. default is True.',
)
- # plot_scatter figbgcolor
+ # make_graph_gml node_attrributes
parser.add_argument(
- '--figbgcolor',
- default = 'none',
- help = 'figure background color. None is transparent (png) or white (jpeg, tiff). default is None.',
+ '--node_attribute',
+ nargs = '*',
+ default = [],
+ help = 'listing of mcds.get_cell_df dataframe columns, used for node attributes. default is and empty list.',
)
# parse arguments
@@ -1781,9 +1949,9 @@ def plot_scatter():
if not s_pathfile.endswith('.xml'):
s_pathfile = s_pathfile + '/initial.xml'
else:
- s_path = '/'.join(s_pathfile.split('/')[:-1])
+ s_path = '/'.join(s_path.split('/')[:-1])
if not os.path.exists(s_pathfile):
- sys.exit(f'Error @ pcdl_plot_scatter : {s_pathfile} path does not look like a outputnnnnnnnn.xml file or physicell output directory ({s_path}/initial.xml is missing).')
+ sys.exit(f'Error @ pcdl_make_graph_gml : {s_pathfile} path does not look like a outputnnnnnnnn.xml file or physicell output directory ({s_path}/initial.xml is missing).')
# custom_data_type
d_vartype = {}
@@ -1794,7 +1962,7 @@ def plot_scatter():
elif s_type in {'float'}: o_type = float
elif s_type in {'str'}: o_type = str
else:
- sys.exit(f'Error @ pcdl_plot_scatter : {s_var} {s_type} has an unknowen data type. knowen are bool, int, float, str.')
+ sys.exit(f'Error @ pcdl_make_graph_gml : {s_var} {s_type} has an unknowen data type. knowen are bool, int, float, str.')
d_vartype.update({s_var : o_type})
# run
@@ -1804,32 +1972,15 @@ def plot_scatter():
output_path = '.',
custom_data_type = d_vartype,
microenv = False if args.microenv.lower().startswith('f') else True,
- graph = False,
+ graph = True,
physiboss = False if args.physiboss.lower().startswith('f') else True,
settingxml = None if ((args.settingxml.lower() == 'none') or (args.settingxml.lower() == 'false')) else args.settingxml,
verbose = False if args.verbose.lower().startswith('f') else True
)
- # plot
- s_opathfile = mcds.plot_scatter(
- focus = args.focus,
- cat_drop = set(args.cat_drop),
- cat_keep = set(args.cat_keep),
- z_slice = args.z_slice,
- z_axis = None if (args.z_axis[0].lower() == 'none') else args.z_axis,
- alpha = args.alpha,
- cmap = args.cmap,
- title = args.title,
- grid = False if args.grid.lower().startswith('f') else True,
- legend_loc = args.legend_loc,
- xlim = None if (args.xlim[0].lower() == 'none') else args.xlim,
- ylim = None if (args.ylim[0].lower() == 'none') else args.ylim,
- xyequal = False if args.xyequal.lower().startswith('f') else True,
- s = args.s,
- ax = None,
- figsizepx = None if (args.figsizepx[0].lower() == 'none') else [int(i) for i in args.figsizepx],
- directory = None if (args.directory.lower() == 'none') else args.directory,
- ext = args.ext,
- figbgcolor = None if (args.figbgcolor.lower() == 'none') else args.figbgcolor,
+ s_opathfile = mcds.make_graph_gml(
+ graph_type = args.graph_type,
+ edge_attribute = False if args.edge_attribute.lower().startswith('f') else True,
+ node_attribute = args.node_attribute,
)
# going home
print(s_opathfile)
@@ -1840,45 +1991,28 @@ def plot_scatter():
custom_data_type = d_vartype,
load = True,
microenv = False if args.microenv.lower().startswith('f') else True,
- graph = False,
+ graph = True,
physiboss = False if args.physiboss.lower().startswith('f') else True,
settingxml = None if ((args.settingxml.lower() == 'none') or (args.settingxml.lower() == 'false')) else args.settingxml,
verbose = False if args.verbose.lower().startswith('f') else True,
)
- # plot
- ls_opathfile = mcdsts.plot_scatter(
- focus = args.focus,
- cat_drop = set(args.cat_drop),
- cat_keep = set(args.cat_keep),
- z_slice = args.z_slice,
- z_axis = None if (args.z_axis[0].lower() == 'none') else args.z_axis,
- alpha = args.alpha,
- cmap = args.cmap,
- title = args.title,
- grid = False if args.grid.lower().startswith('f') else True,
- legend_loc = args.legend_loc,
- xlim = None if (args.xlim[0].lower() == 'none') else args.xlim,
- ylim = None if (args.ylim[0].lower() == 'none') else args.ylim,
- xyequal = False if args.xyequal.lower().startswith('f') else True,
- s = args.s,
- figsizepx = None if (args.figsizepx[0].lower() == 'none') else [int(i) for i in args.figsizepx],
- directory = None if (args.directory.lower() == 'none') else args.directory,
- ext = args.ext,
- figbgcolor = None if (args.figbgcolor.lower() == 'none') else args.figbgcolor,
+ ls_opathfile = mcdsts.make_graph_gml(
+ graph_type = args.graph_type,
+ edge_attribute = False if args.edge_attribute.lower().startswith('f') else True,
+ node_attribute = args.node_attribute,
)
# going home
- s_opath = '/'.join(ls_opathfile[0].split('/')[:-1])
- print(s_opath)
+ print(ls_opathfile)
# going home
return 0
-def make_cell_vtk():
+def make_simularium():
# argv
parser = argparse.ArgumentParser(
- prog = 'pcdl_make_cell_vtk',
- description = 'function that generates 3D glyph vtk file for cells. cells can have specified attributes like cell_type, pressure, dead, etc. you can post-process this file in other software like paraview (https://www.paraview.org/).',
+ prog = 'pcdl_make_simularium',
+ description = 'function returns a simularium trajectory file which can be viewed with the simularium viewer (https://simularium.allencell.org/).',
epilog = 'homepage: https://github.com/elmbeech/physicelldataloader',
)
@@ -1898,11 +2032,6 @@ def make_cell_vtk():
help = 'parameter to specify custom_data variable types other than float (namely: int, bool, str) like this var:dtype myint:int mybool:bool mystr:str . downstream float and int will be handled as numeric, bool as Boolean, and str as categorical data. default is an empty string.',
)
# TimeSeries microenv
- parser.add_argument(
- '--microenv',
- default = 'true',
- help = 'should the microenvironment data be loaded? setting microenv to False will use less memory and speed up processing. default is True.',
- )
# TimeSeries graph False
# TimeSeries physiboss
parser.add_argument(
@@ -1922,18 +2051,25 @@ def make_cell_vtk():
default = 'true',
help = 'setting verbose to False for less text output, while processing. default is True.',
)
- # make_cell_vtk attrribute
+ # make_simularium focus_cat
parser.add_argument(
- 'attribute',
+ 'focus_cat',
nargs = '*',
- default = ['cell_type'],
- help = 'listing of mcds.get_cell_df dataframe column names, used for cell attributes. default is a single term: cell_type.',
+ default = ['cell_type','current_phase'],
+ help = 'one or two categorical mcds.get_cell_df dataframe column names, used for cell attributes. default is cell_type current_phase.',
)
- # make_cell_vtk file extension
+ # make_simularium trajectory_title
parser.add_argument(
- '--ext',
- default = '_cell.vtp',
- help = 'set file extension for the vtk polydata file. for example, the blender BVTKNodes plugin needs a simplified .vtp file extension to be able to load timeseries directly.',
+ '--trajectory_title', '--tt',
+ default = 'timeseries',
+ help = 'the trajectory_title will be used for .simularium file name and displayed in the simulation.',
+ )
+ # make_simularium scale_factor
+ parser.add_argument(
+ '--scale_factor', '--sf',
+ nargs = '?',
+ default = 'none',
+ help = 'a multiplier for the scene, use if visualization is too large or small. if none is provided, one will be calculated based on the position data. bue 20260822: does not seem to work in current simularium 1.13.0.',
)
# parse arguments
@@ -1952,7 +2088,7 @@ def make_cell_vtk():
else:
s_path = '/'.join(s_pathfile.split('/')[:-1])
if not os.path.exists(s_pathfile):
- sys.exit(f'Error @ pcdl_make_cell_vtk : {s_pathfile} path does not look like a outputnnnnnnnn.xml file or physicell output directory ({s_path}/initial.xml is missing).')
+ sys.exit(f'Error @ pcdl_simularium : {s_pathfile} path does not look like a physicell output directory ({s_path}/initial.xml is missing).')
# custom_data_type
d_vartype = {}
@@ -1963,45 +2099,27 @@ def make_cell_vtk():
elif s_type in {'float'}: o_type = float
elif s_type in {'str'}: o_type = str
else:
- sys.exit(f'Error @ pcdl_make_cell_vtk : {s_var} {s_type} has an unknowen data type. knowen are bool, int, float, str.')
+ sys.exit(f'Error @ pcdl_simularium : {s_var} {s_type} has an unknowen data type. knowen are bool, int, float, str.')
d_vartype.update({s_var : o_type})
# run
- if os.path.isfile(args.path):
- mcds = pcdl.TimeStep(
- xmlfile = s_pathfile,
- output_path = '.',
- custom_data_type = d_vartype,
- microenv = False if args.microenv.lower().startswith('f') else True,
- graph = False,
- physiboss = False if args.physiboss.lower().startswith('f') else True,
- settingxml = None if ((args.settingxml.lower() == 'none') or (args.settingxml.lower() == 'false')) else args.settingxml,
- verbose = False if args.verbose.lower().startswith('f') else True
- )
- s_opathfile = mcds.make_cell_vtk(
- attribute = args.attribute,
- ext = args.ext,
- )
- # going home
- print(s_opathfile)
-
- else:
- mcdsts = pcdl.TimeSeries(
- output_path = s_path,
- custom_data_type = d_vartype,
- load = True,
- microenv = False if args.microenv.lower().startswith('f') else True,
- graph = False,
- physiboss = False if args.physiboss.lower().startswith('f') else True,
- settingxml = None if ((args.settingxml.lower() == 'none') or (args.settingxml.lower() == 'false')) else args.settingxml,
- verbose = False if args.verbose.lower().startswith('f') else True,
- )
- ls_opathfile = mcdsts.make_cell_vtk(
- attribute = args.attribute,
- ext = args.ext,
- )
- # going home
- print(ls_opathfile)
+ mcdsts = pcdl.TimeSeries(
+ output_path = s_path,
+ custom_data_type = d_vartype,
+ load = True,
+ microenv = False,
+ graph = False,
+ physiboss = False if args.physiboss.lower().startswith('f') else True,
+ settingxml = None if ((args.settingxml.lower() == 'none') or (args.settingxml.lower() == 'false')) else args.settingxml,
+ verbose = False if args.verbose.lower().startswith('f') else True,
+ )
+ mcdsts.make_simularium(
+ focus_cat = args.focus_cat,
+ trajectory_title = args.trajectory_title,
+ scale_factor = None if (args.scale_factor.lower() == 'none') else float(args.scale_factor),
+ camera_defaults=None,
+ model_meta_data=None,
+ )
# going home
return 0
@@ -2174,6 +2292,7 @@ def get_muspan():
# going home
return 0
+
def get_spatialdata():
# argv
parser = argparse.ArgumentParser(
@@ -2447,7 +2566,6 @@ def plot_timeseries():
default = 'cell',
help = 'to specifies the data dataframe. cell: dataframe will be retrieved through the mcds.get_cell_df function. conc: dataframe will be retrieved through the mcds.get_conc_df function. default is cell.',
)
-
# plot_timeseries cat_drop
parser.add_argument(
'--cat_drop',
@@ -2822,52 +2940,6 @@ def make_ome_tiff():
return 0
-#######################
-# render neuroglancer #
-#######################
-
-def render_neuroglancer():
- # argv
- parser = argparse.ArgumentParser(
- prog = 'pcdl_render_neuroglancer',
- description = 'function to load a time step from an ome tiff files, generated with make_ome_tiff, into neuroglancer.',
- epilog = 'homepage: https://github.com/elmbeech/physicelldataloader',
- )
- # ome tiff path file
- parser.add_argument(
- 'tiffpathfile',
- nargs = '?',
- default = '.',
- help = 'path to ome tiff file.',
- )
- # time step
- parser.add_argument(
- 'timestep',
- nargs = '?',
- default = 0,
- type = int,
- help = 'time step, within a possibly collapsed ome tiff file, to render. the default will work with single time step ome tiff files.',
- )
- # intensity colormap
- parser.add_argument(
- '--intensity_cmap',
- default = 'gray',
- help = 'matlab color map label, used to display expression intensity values. if None, no intensity layers will be generated. https://matplotlib.org/stable/users/explain/colors/colormaps.html',
- )
-
- # parse arguments
- args = parser.parse_args()
- print(args)
-
- # process arguments
- s_neuromancerpath = str(pathlib.Path(pcdl.__file__).parent).replace('\\','/') + '/'
- s_tiffpathfile = args.tiffpathfile.replace('\\','/')
-
- # run
- # bue 20250623: use subprocess to run python3 in interactive mode to run the neuromancer script, which is needed to keep the neuroglancer web gl server running.
- subprocess.run(['python3', '-i', f'{s_neuromancerpath}neuromancer.py', s_tiffpathfile, '--timestep', str(args.timestep), '--intensity_cmap', args.intensity_cmap])
-
-
#################
# making movies #
#################
@@ -2968,3 +3040,45 @@ def make_movie():
# going home
print(s_opathfile)
return 0
+
+
+def render_neuroglancer():
+ # argv
+ parser = argparse.ArgumentParser(
+ prog = 'pcdl_render_neuroglancer',
+ description = 'function to load a time step from an ome tiff files, generated with make_ome_tiff, into neuroglancer.',
+ epilog = 'homepage: https://github.com/elmbeech/physicelldataloader',
+ )
+ # ome tiff path file
+ parser.add_argument(
+ 'tiffpathfile',
+ nargs = '?',
+ default = '.',
+ help = 'path to ome tiff file.',
+ )
+ # time step
+ parser.add_argument(
+ 'timestep',
+ nargs = '?',
+ default = 0,
+ type = int,
+ help = 'time step, within a possibly collapsed ome tiff file, to render. the default will work with single time step ome tiff files.',
+ )
+ # intensity colormap
+ parser.add_argument(
+ '--intensity_cmap',
+ default = 'gray',
+ help = 'matlab color map label, used to display expression intensity values. if None, no intensity layers will be generated. https://matplotlib.org/stable/users/explain/colors/colormaps.html',
+ )
+
+ # parse arguments
+ args = parser.parse_args()
+ print(args)
+
+ # process arguments
+ s_neuromancerpath = str(pathlib.Path(pcdl.__file__).parent).replace('\\','/') + '/'
+ s_tiffpathfile = args.tiffpathfile.replace('\\','/')
+
+ # run
+ # bue 20250623: use subprocess to run python3 in interactive mode to run the neuromancer script, which is needed to keep the neuroglancer web gl server running.
+ subprocess.run(['python3', '-i', f'{s_neuromancerpath}neuromancer.py', s_tiffpathfile, '--timestep', str(args.timestep), '--intensity_cmap', args.intensity_cmap])
diff --git a/pcdl/timeseries.py b/pcdl/timeseries.py
index a6a3f01..01e09fb 100644
--- a/pcdl/timeseries.py
+++ b/pcdl/timeseries.py
@@ -421,7 +421,7 @@ def get_mcds_list(self):
return self.l_mcds
- ## MICROENVIRONMENT RELATED FUNCTIONS ##
+ ## SUBSTRATE RELATED FUNCTIONS ##
def get_conc_df(self, values=1, drop=set(), keep=set(), collapse=True):
"""
@@ -918,6 +918,160 @@ def get_cell_attribute(self, values=1, drop=set(), keep=set(), allvalues=False):
return dl_variable_range
+ def get_anndata(self, values=1, drop=set(), keep=set(), scale='maxabs', collapse=True, keep_mcds=True):
+ """
+ input:
+ values: integer; default is 1
+ minimal number of values a variable has to have to be outputted.
+ variables that have only 1 state carry no information.
+ None is a state too.
+
+ drop: set of strings; default is an empty set
+ set of column labels to be dropped for the dataframe.
+ don't worry: essential columns like ID, coordinates
+ and time will never be dropped.
+ Attention: when the keep parameter is given, then
+ the drop parameter has to be an empty set!
+
+ keep: set of strings; default is an empty set
+ set of column labels to be kept in the dataframe.
+ don't worry: essential columns like ID, coordinates
+ and time will always be kept.
+
+ scale: string; default 'maxabs'
+ specify how the data should be scaled.
+ possible values are None, maxabs, minmax, std.
+ for more input, check out: help(pcdl.scaler)
+
+ collapse: boole; default True
+ should all mcds time steps from the time series be collapsed
+ into one single anndata object, or a list of anndata objects
+ for each time step?
+
+ keep_mcds: boole; default True
+ should the loaded original mcds be kept in memory
+ after transformation?
+
+ output:
+ annmcds or self.l_annmcds: anndata object or list of anndata objects.
+ what is returned depends on the collapse setting.
+
+ description:
+ function to transform mcds time steps into one or many
+ anndata objects for downstream analysis.
+ """
+ # load optional dependency
+ ad = optional_import('anndata', s_caller='TimeSeries.get_anndata')
+
+ # initialize vaiable
+ l_annmcds = []
+ df_anncount = None
+ df_annobs = None
+ ar_annobsm = None
+
+ # variable triage
+ if (values < 2):
+ ls_column = list(self.l_mcds[0].get_cell_df(drop=drop, keep=keep).columns)
+ else:
+ ls_column = sorted(es_coor_cell.difference({'ID'}))
+ ls_column.extend(sorted(self.get_cell_attribute(values=values, drop=drop, keep=keep, allvalues=False).keys()))
+
+ # package collapse
+ if collapse:
+
+ # warning
+ if self.verbose:
+ print('Warning @ mcdsts.get_anndata : only df_cell data, but not graph data, can be collapsed.')
+
+ # extract
+ df_cell = self.get_cell_df(values=values, drop=drop, keep=keep, collapse=True)
+ df_count, df_obs, d_obsm, d_obsp, d_uns = _anndextract(
+ df_cell=df_cell,
+ scale = scale,
+ #graph_attached = {},
+ #graph_neighbor = {},
+ #graph_spring = {},
+ #graph_method = s_physicellv,
+ )
+
+ # fuse to anndata object
+ ann_mcdsts = ad.AnnData(
+ X = df_count,
+ obs = df_obs,
+ obsm = d_obsm,
+ #obsp = d_obsp, # nop (graph)
+ #uns = d_uns, # nop (graph)
+ )
+
+ # mcds
+ if not keep_mcds:
+ self.l_mcds = []
+
+ # output
+ return ann_mcdsts
+
+ # pack not collapsed
+ else:
+ # processing
+ lann_mcds = []
+ i_mcds = len(self.l_mcds)
+ for i in range(i_mcds):
+ # fetch mcds
+ if keep_mcds:
+ mcds = self.l_mcds[i]
+ else:
+ mcds = self.l_mcds.pop(0)
+
+ # extract physicell version
+ s_physicellv = mcds.get_physicell_version(),
+
+ # extract time and dataframes
+ if self.verbose:
+ print(f'processing: {i+1}/{i_mcds} {mcds.get_time()}[min] mcds into anndata obj.')
+ df_cell = mcds.get_cell_df()
+ df_cell = df_cell.loc[:,ls_column]
+
+ # extract
+ df_count, df_obs, d_obsm, d_obsp, d_uns = _anndextract(
+ df_cell=df_cell,
+ scale = scale,
+ graph_attached = mcds.get_attached_graph_dict(),
+ graph_neighbor = mcds.get_neighbor_graph_dict(),
+ graph_spring = mcds.get_spring_graph_dict(),
+ graph_method = s_physicellv,
+ )
+
+ # annmcds
+ ann_mcds = ad.AnnData(
+ X = df_count,
+ obs = df_obs,
+ obsm = d_obsm,
+ obsp = d_obsp,
+ uns = d_uns,
+ )
+ lann_mcds.append(ann_mcds)
+
+ # output
+ self.l_annmcds = lann_mcds
+ return self.l_annmcds
+
+
+ def get_annmcds_list(self):
+ """
+ input:
+ self: TimeSeries class instance.
+
+ output:
+ self.l_annmcds: list of chronologically ordered anndata mcds objects.
+ watch out, this is a pointer to the
+ self.l_annmcds list of anndata mcds objects, not a copy of self.l_annmcds!
+
+ description:
+ function returns a binding to the self.l_annmcds list of anndata mcds objects.
+ """
+ return self.l_annmcds
+
+
def plot_scatter(self, focus='cell_type', cat_drop=set(), cat_keep=set(), z_slice=0.0, z_axis=None, alpha=1, cmap='viridis', title='', grid=True, legend_loc='lower left', xlim=None, ylim=None, xyequal=True, s=1.0, figsizepx=None, directory=None, ext='jpeg', figbgcolor=None, **kwargs):
"""
input:
@@ -1093,147 +1247,330 @@ def make_cell_vtk(self, attribute=['cell_type'], ext='_cell.vtp'):
return ls_vtkpathfile
- ## OME TIFF RELATED FUNCTIONS ##
-
- def make_ome_tiff(self, cell_attribute='ID', conc_cutoff={}, focus=None, file=True, collapse=True):
+ def make_graph_gml(self, graph_type, edge_attribute=True, node_attribute=[]):
"""
input:
- cell_attribute: strings; default is 'ID', which will result in a
- cell segmentation mask.
- column name within the cell dataframe.
- the column data type has to be numeric (bool, int, float)
- and cannot be string.
- the result will be stored as 32 bit float.
-
- conc_cutoff: dictionary string to real; default is an empty dictionary.
- if a contour from a substrate not should be cut by greater
- than zero (shifted to integer 1), another cutoff value can be specified here.
+ self: TimeSeries class instance.
- focus: set of strings; default is a None
- set of substrate and cell_type names to specify what will be
- translated into ome tiff format.
- if None, all substrates and cell types will be processed.
+ graph_type: string
+ to specify which physicell output data should be processed.
+ attached, touch: processes mcds.get_attached_graph_dict dictionary.
+ neighbor: processes mcds.get_neighbor_graph_dict dictionary.
+ spring: processes mcds.get_spring_graph_dict dictionary.
- file: boolean; default True
- if True, an ome tiff file is the output.
- if False, a numpy array with shape tczyx is the output.
+ edge_attribute: boolean; default True
+ specifies if the spatial Euclidean distance is used for
+ edge attribute, to generate a weighted graph.
- collapse: boole; default True
- should all mcds time steps from the time series be collapsed
- into one ome tiff file (numpy array),
- or an ome tiff file (numpy array) for each time step?
+ node_attribute: list of strings; default is empty list
+ list of mcds.get_cell_df dataframe columns, used for
+ node attributes.
output:
- a_tczyx_img: numpy array or ome tiff file.
-
+ gml file for each time step.
+ path and filenames are printed to the standard output.
description:
- function to transform chosen mcdsts output into an 1[um] spaced
- tczyx (time, channel, z-axis, y-axis, x-axis) ome tiff file or numpy array,
- one substrate or cell_type per channel.
- a ome tiff file is more or less:
- a numpy array, containing the image information
- and a xml, containing the microscopy metadata information,
- like the channel labels.
- the ome tiff file format can for example be read by the napari
- or fiji (imagej) software.
+ function to generate graph files in the gml graph modelling language
+ standard format.
- https://napari.org/stable/
- https://fiji.sc/
+ gml was the outcome of an initiative that started at
+ the international symposium on graph drawing 1995 in Passau
+ and ended at Graph Drawing 1996 in Berkeley. the networkx python
+ and igraph C and python libraries for graph analysis are
+ gml compatible and can as such read and write this file format.
+
+ https://en.wikipedia.org/wiki/Graph_Modelling_Language
+ https://github.com/elmbeech/physicelldataloader/blob/master/man/publication/himsolt1996gml_a_portable_graph_file_format.pdf
+ https://networkx.org/
+ https://igraph.org/
"""
- # for each time step
- l_tczyx_img = []
+ # processing
+ ls_pathfile = []
for mcds in self.get_mcds_list():
- # processing
- b_file = True # 10
- if (not file and not collapse) or (not file and collapse) or (file and collapse): # 00, 01, 11
- b_file = False
- o_tczyx_img = mcds.make_ome_tiff(
- cell_attribute = cell_attribute,
- conc_cutoff = conc_cutoff,
- focus = focus,
- file = b_file
+ s_pathfile = mcds.make_graph_gml(
+ graph_type = graph_type,
+ edge_attribute = edge_attribute,
+ node_attribute = node_attribute,
)
- l_tczyx_img.append(o_tczyx_img)
+ ls_pathfile.append(s_pathfile)
- # handle channels
- ls_substrate = mcds.get_substrate_list()
- ls_celltype = mcds.get_celltype_list()
+ # outout
+ return ls_pathfile
- if not (focus is None):
- ls_substrate = [s_substrate for s_substrate in ls_substrate if s_substrate in set(focus)]
- ls_celltype = [s_celltype for s_celltype in ls_celltype if s_celltype in set(focus)]
- if (set(focus) != set(ls_substrate).union(set(ls_celltype))):
- sys.exit(f'Error : {focus} not found in {ls_substrate} {ls_celltype}')
- # output 00 list of numpy arrays
- if (not file and not collapse): # 00
- if self.verbose:
- print(f'la_tczyx_img shape: {len(l_tczyx_img)} * {l_tczyx_img[0].shape}')
- return l_tczyx_img
+ def make_simularium(self, focus_cat=['cell_type','current_phase'], trajectory_title='timeseries', scale_factor=None, camera_defaults=None, model_meta_data=None):
+ """
+ input:
+ focus_cat: list of 1 or 2 string; default is ['cell_type','current_phase']
+ specify 1 or 2 categorical column labels, to be found
+ in mcdsts.get_cell_df().
- # output 01 numpy array
- elif (not file and collapse): # 01
- # numpy array
- a_tczyx_img = np.array(l_tczyx_img)
- if self.verbose:
- print('a_tczyx_img shape:', a_tczyx_img.shape)
- return a_tczyx_img
+ trajectory_title: string; default 'timeseries'
+ the trajectory_title will be used as
+ .simularium file name and displayed
+ in the simulation.
- # output 10 list of pathfile strings
- elif (file and not collapse): # 10
- return l_tczyx_img
+ scale_factor: float number; default is None
+ A multiplier for the scene, use if visualization is
+ too large or small. If None is provided, one will
+ be calculated based on the position data.
+ bue 20260822: does not seem to work in current simularium 1.13.0.
- # output 11 ometiff file
- elif (file and collapse): # 11
- # load optional dependency
- OmeTiffWriter = optional_import('bioio.writers', s_attr='OmeTiffWriter', s_pip='bioio', s_caller='TimeSeries.make_ome_tiff')
- bioio_base = optional_import('bioio_base', s_pip='bioio', s_caller='TimeSeries.make_ome_tiff')
+ camera_defaults: simulariumio.CameraData object; default is None
+ camera's initial settings which it also returns to
+ when reset.
- # numpy array
- a_tczyx_img = np.array(l_tczyx_img)
- if self.verbose:
- print('a_tczyx_img shape:', a_tczyx_img.shape)
+ model_meta_data: simulariumio.ModelMetaData; default is None
+ Metadata for the model that produced this
+ trajectory.
- # generate filename
- s_channel = ''
- for s_substrate in ls_substrate:
- try:
- r_value = conc_cutoff[s_substrate]
- s_channel += f'_{s_substrate}{r_value}'
- except KeyError:
- s_channel += f'_{s_substrate}'
- for s_celltype in ls_celltype:
- s_channel += f'_{s_celltype}'
- if len(ls_celltype) > 0:
- s_channel += f'_{cell_attribute}'
- s_tifffile = f"timeseries{s_channel.replace(' ','_')}.ome.tiff"
- if (len(s_tifffile) > 255):
- print(f"Warning: filename {len(s_tifffile)} > 255 character.")
- s_tifffile = 'timeseries_channels.ome.tiff'
- print(f"file name adjusted to {s_tifffile}.")
- s_tiffpathfile = self.path + '/' + s_tifffile
+ output:
+ .simularium file
- # save to file
- OmeTiffWriter.save(
- a_tczyx_img,
- s_tiffpathfile,
- dim_order = 'TCZYX',
- #ome_xml=x_img,
- channel_names = ls_substrate + ls_celltype,
- image_names = [f'timeseries_{cell_attribute}'],
- physical_pixel_sizes = bioio_base.types.PhysicalPixelSizes(mcds.get_voxel_spacing()[2], 1.0, 1.0), # z,y,x [um]
- #channel_colors=,
- #fs_kwargs={},
+ description:
+ function returns a simularium trajectory file that can be run with the
+ online Simularium Viewer.
+ + https://simularium.allencell.org/
+ """
+ # library
+ sim = optional_import(s_module='simulariumio', s_caller='TimeSeries.make_simularium')
+
+ # handle input
+ model_meta_data=sim.ModelMetaData() if model_meta_data is None else model_meta_data
+ camera_defaults=sim.CameraData() if camera_defaults is None else camera_defaults
+
+ # here we go
+ if self.verbose:
+ print(f'generating {trajectory_title}.simularium file ...')
+
+ # extract box from mcdsts
+ ltr_domain = self.get_mcds_list()[0].get_mesh_mnp_range()
+ lr_space = self.get_mcds_list()[0].get_mesh_spacing()
+ lr_box = np.array([
+ ltr_domain[0][1] - ltr_domain[0][0],
+ ltr_domain[1][1] - ltr_domain[1][0],
+ ltr_domain[2][1] - ltr_domain[2][0],
+ ])
+ lr_box[0] = lr_box[0] if lr_box[0] != 0.0 else lr_space[0]
+ lr_box[1] = lr_box[1] if lr_box[1] != 0.0 else lr_space[1]
+ lr_box[2] = lr_box[2] if lr_box[2] != 0.0 else lr_space[2]
+ ar_box = np.array(lr_box)
+
+ # extract cell dataframe from mcdsts
+ df_cell = self.get_cell_df()
+
+ # handle agent annotation
+ se_type = df_cell.loc[:, focus_cat].astype(str).agg('#'.join, axis=1)
+
+ # extract units from mcdsts
+ ds_unit = self.get_mcds_list()[0].get_unit_dict()
+
+ # generate simularium dataframe
+ with pd.option_context('future.infer_string', False):
+ df_sim = pd.DataFrame({
+ 'time': df_cell.loc[:, 'time'].to_numpy(dtype=float),
+ 'unique_id': df_cell.loc[:, 'ID'].to_numpy(dtype=int),
+ 'type': se_type.to_numpy(dtype=object),
+ 'positionX': df_cell.loc[:, 'position_x'].to_numpy(dtype=float),
+ 'positionY': df_cell.loc[:, 'position_y'].to_numpy(dtype=float),
+ 'positionZ': df_cell.loc[:, 'position_z'].to_numpy(dtype=float),
+ 'radius': df_cell.loc[:, 'radius'].to_numpy(dtype=float),
+ 'rotationX': np.zeros(df_cell.shape[0], dtype=float),
+ 'rotationY': np.zeros(df_cell.shape[0], dtype=float),
+ 'rotationZ': np.zeros(df_cell.shape[0], dtype=float),
+ })
+ df_sim.sort_values(['time', 'unique_id'], inplace=True)
+ # SimulariumIO 1.13.0 AgentData.from_dataframe expects traj.loc[0, ...]
+ # to select the whole trajectory, so all rows need the same index label.
+ df_sim.index = np.zeros(df_sim.shape[0], dtype=int)
+
+ # generate simmularium trajectorydata object
+ o_sim = sim.TrajectoryData(
+ meta_data = sim.MetaData(
+ box_size=ar_box,
+ camera_defaults=camera_defaults,
+ scale_factor=scale_factor,
+ trajectory_title=trajectory_title,
+ model_meta_data=model_meta_data,
+ ),
+ agent_data = sim.AgentData.from_dataframe(df_sim),
+ time_units = sim.UnitData(ds_unit['time']),
+ spatial_units = sim.UnitData(ds_unit['spatial_unit']),
+ #plots=,
+ )
+
+ # transform data and save trajectorydata object to simularium file
+ s_save = self.path + '/' + trajectory_title
+ s_pathfile = s_save + '.simularium'
+ sim.TrajectoryConverter(o_sim).save(s_save)
+ if self.verbose:
+ print(f'simularium viewer at: https://simularium.allencell.org/')
+
+ # return error code
+ return s_pathfile
+
+
+ ## SUBSTRATE AND CELL RELATED FUNCTIONS ##
+
+ def get_muspan(self, z_slice=None, values=1, drop=set(), keep=set()):
+ """
+ input:
+ z_slice: floating point number; default is None
+ z-axis position to slice a 2D xy-plain out of the
+ 3D mesh. if None the whole 3D mesh will be returned.
+
+ values: integer; default is 1
+ minimal number of values a variable has to have to be outputted.
+ variables that have only 1 state carry no information.
+ None is a state too.
+
+ drop: set of strings; default is an empty set
+ set of column labels to be dropped for the dataframe.
+ don't worry: essential columns like ID, coordinates
+ and time will never be dropped.
+ Attention: when the keep parameter is given, then
+ the drop parameter has to be an empty set!
+
+ keep: set of strings; default is an empty set
+ set of column labels to be kept in the dataframe.
+ set values=1 to be sure that all variables are kept.
+ don't worry: essential columns like ID, coordinates
+ and time will always be kept.
+
+ output:
+ do_domain: dictionary of muspa domains, one for each time step z-layer.
+
+ description:
+ function returns a dictionary of muspa domains, containg a
+ cell and subs collection with disrcete and continuous labels
+ and all the graph as networks.
+ + https://www.muspan.co.uk
+ + https://docs.muspan.co.uk/latest/Documentation.html
+ """
+ # variable triage
+ es_keep = set(self.get_cell_attribute(values=values, drop=drop, keep=keep, allvalues=False).keys())
+
+ # processing
+ do_domain = {}
+ for mcds in self.get_mcds_list():
+ do_domain.update(
+ mcds.get_muspan(
+ z_slice = z_slice,
+ #values = 1,
+ #drop = set(),
+ keep = es_keep,
+ )
)
- return s_tiffpathfile
- # error case
- else:
- sys.exit(f'Error @ make_ome_tiff : {file} {collapse} strange file collapse combination.')
+ # output
+ return do_domain
+
+
+ def get_spatialdata(self, images={'subs'}, labels=set(), points={'subs'}, shapes={'cell'}, values=1, drop=set(), keep=set(), scale='maxabs', keep_mcds=True):
+ """
+ input:
+ images: set of string; default {'subs'}
+ specify if from the subs or cell dataset
+ a multichannel image should be generate.
+ so far, only the subs image element is implemented.
+
+ labels: set of strings; default is an empty set
+ specify if from the subs or cell dataset
+ a label element should be generated.
+ so far, neither subs nor cell label elements are implemented.
+
+ points: set of string; default {'subs'}
+ specify if from the subs or cell dataset
+ a points element should be generated.
+ both, subs and cell point elements, are implemented.
+
+ shapes: set of string; default {'cell'}
+ specify if from the subs or cell dataset
+ a shape element should be generated.
+ so far, only the cell shape element is implemented.
+
+ values: integer; default is 1
+ minimal number of values a variable has to have to be outputted.
+ variables that have only 1 state carry no information.
+ None is a state too.
+
+ drop: set of strings; default is an empty set
+ set of column labels to be dropped for the dataframe.
+ don't worry: essential columns like ID, coordinates
+ and time will never be dropped.
+ Attention: when the keep parameter is given, then
+ the drop parameter has to be an empty set!
+
+ keep: set of strings; default is an empty set
+ set of column labels to be kept in the dataframe.
+ don't worry: essential columns like ID, coordinates
+ and time will always be kept.
+
+ scale: string; default 'maxabs'
+ specify how the data should be scaled.
+ possible values are None, maxabs, minmax, std.
+ for more input, check out: help(pcdl.scaler)
+
+ keep_mcds: boole; default True
+ should the loaded original mcds be kept in memory
+ after transformation?
+
+ output:
+ self.l_sdmcds: list of spatialdata objects.
+
+ description:
+ function to transform mcds time steps into
+ spatialdata objects for downstream analysis.
+ """
+ # variable triage
+ es_keep = set(self.get_cell_attribute(values=values, drop=drop, keep=keep, allvalues=False).keys())
+
+ # processing
+ lsd_mcds = []
+ i_mcds = len(self.l_mcds)
+ for i in range(i_mcds):
+ # fetch mcds
+ if keep_mcds:
+ mcds = self.l_mcds[i]
+ else:
+ mcds = self.l_mcds.pop(0)
+
+ # extract time and dataframes
+ if self.verbose:
+ print(f'\nprocessing: {i+1}/{i_mcds} {mcds.get_time()}[min] mcds into spatialdata obj.')
+
+ # get spatialdata object
+ sd_mcds = mcds.get_spatialdata(
+ points = points,
+ shapes = shapes,
+ #values = 1,
+ #drop = set(),
+ keep = es_keep,
+ scale = scale,
+ )
+ lsd_mcds.append(sd_mcds)
+
+ # output
+ self.l_sdmcds = lsd_mcds
+ return self.l_sdmcds
+
+
+ def get_sdmcds_list(self):
+ """
+ input:
+ self: TimeSeries class instance.
+
+ output:
+ self.l_sdmcds: list of chronologically ordered spatialdata mcds objects.
+ watch out, this is a pointer to the
+ self.l_sdmcds list of spdata mcds objects, not a copy of self.l_sdmcds!
+ description:
+ function returns a binding to the self.l_sdmcds list of spdata mcds objects.
+ """
+ return self.l_sdmcds
- ## TIME SERIES RELATED FUNCTIONS ##
def plot_timeseries(self, focus_cat=None, focus_num=None, aggregate_num=np.nanmean, frame='cell', cat_drop=set(), cat_keep=set(), z_slice=None, logy=False, ylim=None, secondary_y=None, subplots=False, sharex=False, sharey=False, linestyle='-', linewidth=None, cmap=None, color=None, grid=True, legend=True, yunit=None, title=None, ax=None, figsizepx=[640, 480], ext=None, figbgcolor=None, **kwargs):
"""
@@ -1578,372 +1915,139 @@ def plot_timeseries(self, focus_cat=None, focus_num=None, aggregate_num=np.nanme
return fig
- ## GRAPH RELATED FUNCTIONS ##
-
- def make_graph_gml(self, graph_type, edge_attribute=True, node_attribute=[]):
+ def make_ome_tiff(self, cell_attribute='ID', conc_cutoff={}, focus=None, file=True, collapse=True):
"""
input:
- self: TimeSeries class instance.
+ cell_attribute: strings; default is 'ID', which will result in a
+ cell segmentation mask.
+ column name within the cell dataframe.
+ the column data type has to be numeric (bool, int, float)
+ and cannot be string.
+ the result will be stored as 32 bit float.
- graph_type: string
- to specify which physicell output data should be processed.
- attached, touch: processes mcds.get_attached_graph_dict dictionary.
- neighbor: processes mcds.get_neighbor_graph_dict dictionary.
- spring: processes mcds.get_spring_graph_dict dictionary.
+ conc_cutoff: dictionary string to real; default is an empty dictionary.
+ if a contour from a substrate not should be cut by greater
+ than zero (shifted to integer 1), another cutoff value can be specified here.
- edge_attribute: boolean; default True
- specifies if the spatial Euclidean distance is used for
- edge attribute, to generate a weighted graph.
+ focus: set of strings; default is a None
+ set of substrate and cell_type names to specify what will be
+ translated into ome tiff format.
+ if None, all substrates and cell types will be processed.
- node_attribute: list of strings; default is empty list
- list of mcds.get_cell_df dataframe columns, used for
- node attributes.
+ file: boolean; default True
+ if True, an ome tiff file is the output.
+ if False, a numpy array with shape tczyx is the output.
+
+ collapse: boole; default True
+ should all mcds time steps from the time series be collapsed
+ into one ome tiff file (numpy array),
+ or an ome tiff file (numpy array) for each time step?
output:
- gml file for each time step.
- path and filenames are printed to the standard output.
+ a_tczyx_img: numpy array or ome tiff file.
- description:
- function to generate graph files in the gml graph modelling language
- standard format.
- gml was the outcome of an initiative that started at
- the international symposium on graph drawing 1995 in Passau
- and ended at Graph Drawing 1996 in Berkeley. the networkx python
- and igraph C and python libraries for graph analysis are
- gml compatible and can as such read and write this file format.
+ description:
+ function to transform chosen mcdsts output into an 1[um] spaced
+ tczyx (time, channel, z-axis, y-axis, x-axis) ome tiff file or numpy array,
+ one substrate or cell_type per channel.
+ a ome tiff file is more or less:
+ a numpy array, containing the image information
+ and a xml, containing the microscopy metadata information,
+ like the channel labels.
+ the ome tiff file format can for example be read by the napari
+ or fiji (imagej) software.
- https://en.wikipedia.org/wiki/Graph_Modelling_Language
- https://github.com/elmbeech/physicelldataloader/blob/master/man/publication/himsolt1996gml_a_portable_graph_file_format.pdf
- https://networkx.org/
- https://igraph.org/
+ https://napari.org/stable/
+ https://fiji.sc/
"""
- # processing
- ls_pathfile = []
+ # for each time step
+ l_tczyx_img = []
for mcds in self.get_mcds_list():
- s_pathfile = mcds.make_graph_gml(
- graph_type = graph_type,
- edge_attribute = edge_attribute,
- node_attribute = node_attribute,
+ # processing
+ b_file = True # 10
+ if (not file and not collapse) or (not file and collapse) or (file and collapse): # 00, 01, 11
+ b_file = False
+ o_tczyx_img = mcds.make_ome_tiff(
+ cell_attribute = cell_attribute,
+ conc_cutoff = conc_cutoff,
+ focus = focus,
+ file = b_file
)
- ls_pathfile.append(s_pathfile)
-
- # outout
- return ls_pathfile
-
-
- ## ANNDATA RELATED FUNCTIONS ##
-
- def get_anndata(self, values=1, drop=set(), keep=set(), scale='maxabs', collapse=True, keep_mcds=True):
- """
- input:
- values: integer; default is 1
- minimal number of values a variable has to have to be outputted.
- variables that have only 1 state carry no information.
- None is a state too.
-
- drop: set of strings; default is an empty set
- set of column labels to be dropped for the dataframe.
- don't worry: essential columns like ID, coordinates
- and time will never be dropped.
- Attention: when the keep parameter is given, then
- the drop parameter has to be an empty set!
-
- keep: set of strings; default is an empty set
- set of column labels to be kept in the dataframe.
- don't worry: essential columns like ID, coordinates
- and time will always be kept.
-
- scale: string; default 'maxabs'
- specify how the data should be scaled.
- possible values are None, maxabs, minmax, std.
- for more input, check out: help(pcdl.scaler)
-
- collapse: boole; default True
- should all mcds time steps from the time series be collapsed
- into one single anndata object, or a list of anndata objects
- for each time step?
-
- keep_mcds: boole; default True
- should the loaded original mcds be kept in memory
- after transformation?
-
- output:
- annmcds or self.l_annmcds: anndata object or list of anndata objects.
- what is returned depends on the collapse setting.
-
- description:
- function to transform mcds time steps into one or many
- anndata objects for downstream analysis.
- """
- # load optional dependency
- ad = optional_import('anndata', s_caller='TimeSeries.get_anndata')
-
- # initialize vaiable
- l_annmcds = []
- df_anncount = None
- df_annobs = None
- ar_annobsm = None
+ l_tczyx_img.append(o_tczyx_img)
- # variable triage
- if (values < 2):
- ls_column = list(self.l_mcds[0].get_cell_df(drop=drop, keep=keep).columns)
- else:
- ls_column = sorted(es_coor_cell.difference({'ID'}))
- ls_column.extend(sorted(self.get_cell_attribute(values=values, drop=drop, keep=keep, allvalues=False).keys()))
+ # handle channels
+ ls_substrate = mcds.get_substrate_list()
+ ls_celltype = mcds.get_celltype_list()
- # package collapse
- if collapse:
+ if not (focus is None):
+ ls_substrate = [s_substrate for s_substrate in ls_substrate if s_substrate in set(focus)]
+ ls_celltype = [s_celltype for s_celltype in ls_celltype if s_celltype in set(focus)]
+ if (set(focus) != set(ls_substrate).union(set(ls_celltype))):
+ sys.exit(f'Error : {focus} not found in {ls_substrate} {ls_celltype}')
- # warning
+ # output 00 list of numpy arrays
+ if (not file and not collapse): # 00
if self.verbose:
- print('Warning @ mcdsts.get_anndata : only df_cell data, but not graph data, can be collapsed.')
-
- # extract
- df_cell = self.get_cell_df(values=values, drop=drop, keep=keep, collapse=True)
- df_count, df_obs, d_obsm, d_obsp, d_uns = _anndextract(
- df_cell=df_cell,
- scale = scale,
- #graph_attached = {},
- #graph_neighbor = {},
- #graph_spring = {},
- #graph_method = s_physicellv,
- )
-
- # fuse to anndata object
- ann_mcdsts = ad.AnnData(
- X = df_count,
- obs = df_obs,
- obsm = d_obsm,
- #obsp = d_obsp, # nop (graph)
- #uns = d_uns, # nop (graph)
- )
-
- # mcds
- if not keep_mcds:
- self.l_mcds = []
-
- # output
- return ann_mcdsts
-
- # pack not collapsed
- else:
- # processing
- lann_mcds = []
- i_mcds = len(self.l_mcds)
- for i in range(i_mcds):
- # fetch mcds
- if keep_mcds:
- mcds = self.l_mcds[i]
- else:
- mcds = self.l_mcds.pop(0)
-
- # extract physicell version
- s_physicellv = mcds.get_physicell_version(),
-
- # extract time and dataframes
- if self.verbose:
- print(f'processing: {i+1}/{i_mcds} {mcds.get_time()}[min] mcds into anndata obj.')
- df_cell = mcds.get_cell_df()
- df_cell = df_cell.loc[:,ls_column]
-
- # extract
- df_count, df_obs, d_obsm, d_obsp, d_uns = _anndextract(
- df_cell=df_cell,
- scale = scale,
- graph_attached = mcds.get_attached_graph_dict(),
- graph_neighbor = mcds.get_neighbor_graph_dict(),
- graph_spring = mcds.get_spring_graph_dict(),
- graph_method = s_physicellv,
- )
-
- # annmcds
- ann_mcds = ad.AnnData(
- X = df_count,
- obs = df_obs,
- obsm = d_obsm,
- obsp = d_obsp,
- uns = d_uns,
- )
- lann_mcds.append(ann_mcds)
-
- # output
- self.l_annmcds = lann_mcds
- return self.l_annmcds
-
- def get_annmcds_list(self):
- """
- input:
- self: TimeSeries class instance.
-
- output:
- self.l_annmcds: list of chronologically ordered anndata mcds objects.
- watch out, this is a pointer to the
- self.l_annmcds list of anndata mcds objects, not a copy of self.l_annmcds!
-
- description:
- function returns a binding to the self.l_annmcds list of anndata mcds objects.
- """
- return self.l_annmcds
-
-
- def get_spatialdata(self, images={'subs'}, labels=set(), points={'subs'}, shapes={'cell'}, values=1, drop=set(), keep=set(), scale='maxabs', keep_mcds=True):
- """
- input:
- images: set of string; default {'subs'}
- specify if from the subs or cell dataset
- a multichannel image should be generate.
- so far, only the subs image element is implemented.
-
- labels: set of strings; default is an empty set
- specify if from the subs or cell dataset
- a label element should be generated.
- so far, neither subs nor cell label elements are implemented.
-
- points: set of string; default {'subs'}
- specify if from the subs or cell dataset
- a points element should be generated.
- both, subs and cell point elements, are implemented.
-
- shapes: set of string; default {'cell'}
- specify if from the subs or cell dataset
- a shape element should be generated.
- so far, only the cell shape element is implemented.
-
- values: integer; default is 1
- minimal number of values a variable has to have to be outputted.
- variables that have only 1 state carry no information.
- None is a state too.
-
- drop: set of strings; default is an empty set
- set of column labels to be dropped for the dataframe.
- don't worry: essential columns like ID, coordinates
- and time will never be dropped.
- Attention: when the keep parameter is given, then
- the drop parameter has to be an empty set!
-
- keep: set of strings; default is an empty set
- set of column labels to be kept in the dataframe.
- don't worry: essential columns like ID, coordinates
- and time will always be kept.
-
- scale: string; default 'maxabs'
- specify how the data should be scaled.
- possible values are None, maxabs, minmax, std.
- for more input, check out: help(pcdl.scaler)
-
- keep_mcds: boole; default True
- should the loaded original mcds be kept in memory
- after transformation?
-
- output:
- self.l_sdmcds: list of spatialdata objects.
-
- description:
- function to transform mcds time steps into
- spatialdata objects for downstream analysis.
- """
- # variable triage
- es_keep = set(self.get_cell_attribute(values=values, drop=drop, keep=keep, allvalues=False).keys())
-
- # processing
- lsd_mcds = []
- i_mcds = len(self.l_mcds)
- for i in range(i_mcds):
- # fetch mcds
- if keep_mcds:
- mcds = self.l_mcds[i]
- else:
- mcds = self.l_mcds.pop(0)
+ print(f'la_tczyx_img shape: {len(l_tczyx_img)} * {l_tczyx_img[0].shape}')
+ return l_tczyx_img
- # extract time and dataframes
+ # output 01 numpy array
+ elif (not file and collapse): # 01
+ # numpy array
+ a_tczyx_img = np.array(l_tczyx_img)
if self.verbose:
- print(f'\nprocessing: {i+1}/{i_mcds} {mcds.get_time()}[min] mcds into spatialdata obj.')
-
- # get spatialdata object
- sd_mcds = mcds.get_spatialdata(
- points = points,
- shapes = shapes,
- #values = 1,
- #drop = set(),
- keep = es_keep,
- scale = scale,
- )
- lsd_mcds.append(sd_mcds)
-
- # output
- self.l_sdmcds = lsd_mcds
- return self.l_sdmcds
-
-
- def get_sdmcds_list(self):
- """
- input:
- self: TimeSeries class instance.
-
- output:
- self.l_sdmcds: list of chronologically ordered spatialdata mcds objects.
- watch out, this is a pointer to the
- self.l_sdmcds list of spdata mcds objects, not a copy of self.l_sdmcds!
-
- description:
- function returns a binding to the self.l_sdmcds list of spdata mcds objects.
- """
- return self.l_sdmcds
-
-
-
- ## MUSPAN RELATED FUNCTIONS ##
-
- def get_muspan(self, z_slice=None, values=1, drop=set(), keep=set()):
- """
- input:
- z_slice: floating point number; default is None
- z-axis position to slice a 2D xy-plain out of the
- 3D mesh. if None the whole 3D mesh will be returned.
-
- values: integer; default is 1
- minimal number of values a variable has to have to be outputted.
- variables that have only 1 state carry no information.
- None is a state too.
+ print('a_tczyx_img shape:', a_tczyx_img.shape)
+ return a_tczyx_img
- drop: set of strings; default is an empty set
- set of column labels to be dropped for the dataframe.
- don't worry: essential columns like ID, coordinates
- and time will never be dropped.
- Attention: when the keep parameter is given, then
- the drop parameter has to be an empty set!
+ # output 10 list of pathfile strings
+ elif (file and not collapse): # 10
+ return l_tczyx_img
- keep: set of strings; default is an empty set
- set of column labels to be kept in the dataframe.
- set values=1 to be sure that all variables are kept.
- don't worry: essential columns like ID, coordinates
- and time will always be kept.
+ # output 11 ometiff file
+ elif (file and collapse): # 11
+ # load optional dependency
+ OmeTiffWriter = optional_import('bioio.writers', s_attr='OmeTiffWriter', s_pip='bioio', s_caller='TimeSeries.make_ome_tiff')
+ bioio_base = optional_import('bioio_base', s_pip='bioio', s_caller='TimeSeries.make_ome_tiff')
- output:
- do_domain: dictionary of muspa domains, one for each time step z-layer.
+ # numpy array
+ a_tczyx_img = np.array(l_tczyx_img)
+ if self.verbose:
+ print('a_tczyx_img shape:', a_tczyx_img.shape)
- description:
- function returns a dictionary of muspa domains, containg a
- cell and subs collection with disrcete and continuous labels
- and all the graph as networks.
- + https://www.muspan.co.uk
- + https://docs.muspan.co.uk/latest/Documentation.html
- """
- # variable triage
- es_keep = set(self.get_cell_attribute(values=values, drop=drop, keep=keep, allvalues=False).keys())
+ # generate filename
+ s_channel = ''
+ for s_substrate in ls_substrate:
+ try:
+ r_value = conc_cutoff[s_substrate]
+ s_channel += f'_{s_substrate}{r_value}'
+ except KeyError:
+ s_channel += f'_{s_substrate}'
+ for s_celltype in ls_celltype:
+ s_channel += f'_{s_celltype}'
+ if len(ls_celltype) > 0:
+ s_channel += f'_{cell_attribute}'
+ s_tifffile = f"timeseries{s_channel.replace(' ','_')}.ome.tiff"
+ if (len(s_tifffile) > 255):
+ print(f"Warning: filename {len(s_tifffile)} > 255 character.")
+ s_tifffile = 'timeseries_channels.ome.tiff'
+ print(f"file name adjusted to {s_tifffile}.")
+ s_tiffpathfile = self.path + '/' + s_tifffile
- # processing
- do_domain = {}
- for mcds in self.get_mcds_list():
- do_domain.update(
- mcds.get_muspan(
- z_slice = z_slice,
- #values = 1,
- #drop = set(),
- keep = es_keep,
- )
+ # save to file
+ OmeTiffWriter.save(
+ a_tczyx_img,
+ s_tiffpathfile,
+ dim_order = 'TCZYX',
+ #ome_xml=x_img,
+ channel_names = ls_substrate + ls_celltype,
+ image_names = [f'timeseries_{cell_attribute}'],
+ physical_pixel_sizes = bioio_base.types.PhysicalPixelSizes(mcds.get_voxel_spacing()[2], 1.0, 1.0), # z,y,x [um]
+ #channel_colors=,
+ #fs_kwargs={},
)
+ return s_tiffpathfile
- # output
- return do_domain
+ # error case
+ else:
+ sys.exit(f'Error @ make_ome_tiff : {file} {collapse} strange file collapse combination.')
diff --git a/pcdl/timestep.py b/pcdl/timestep.py
index b318c18..49599ec 100644
--- a/pcdl/timestep.py
+++ b/pcdl/timestep.py
@@ -625,6 +625,19 @@ def set_verbose_true(self):
#print(f'pcdl: set mcds.verbose = True.')
+ def render_neuroglancer(self, tiffpathfile, timestep=0, intensity_cmap='gray'):
+ """
+ help(pcdl.render_neuroglancer)
+ try: mcds.render_neuroglancer(mcds.make_ome_tiff())
+ """
+ o_viewer = render_neuroglancer(
+ tiffpathfile = tiffpathfile,
+ timestep = timestep,
+ intensity_cmap = intensity_cmap,
+ )
+ return o_viewer
+
+
## METADATA RELATED FUNCTIONS ##
def get_multicellds_version(self):
@@ -1053,7 +1066,7 @@ def get_voxel_ijk(self, x, y, z, is_in_mesh=True):
return li_ijk
- ## MICROENVIRONMENT RELATED FUNCTIONS ##
+ ## SUBSTRATE RELATED FUNCTIONS ##
def get_substrate_list(self):
"""
@@ -1602,6 +1615,108 @@ def get_cell_attribute_list(self):
return self.data['cell']['ls_cellattr'].copy()
+ def get_anndata(self, values=1, drop=set(), keep=set(), scale='maxabs'):
+ """
+ input:
+ values: integer; default is 1
+ minimal number of values a variable has to have to be outputted.
+ variables that have only 1 state carry no information.
+ None is a state too.
+
+ drop: set of strings; default is an empty set
+ set of column labels to be dropped for the dataframe.
+ don't worry: essential columns like ID, coordinates
+ and time will never be dropped.
+ Attention: when the keep parameter is given, then
+ the drop parameter has to be an empty set!
+
+ keep: set of strings; default is an empty set
+ set of column labels to be kept in the dataframe.
+ set values=1 to be sure that all variables are kept.
+ don't worry: essential columns like ID, coordinates
+ and time will always be kept.
+
+ scale: string; default 'maxabs'
+ specify how the data should be scaled.
+ possible values are None, maxabs, minmax, std.
+ for more input, check out: help(pcdl.scaler)
+
+ output:
+ annmcds: anndata object
+ for this one time step.
+
+ description:
+ function to transform a mcds time step into an anndata object
+ for downstream analysis.
+ """
+ # load optional dependency
+ ad = optional_import('anndata', s_caller='TimeStep.get_anndata')
+
+ # processing
+ if self.verbose:
+ print(f'processing: 1/1 {round(self.get_time(),9)}[min] mcds into anndata obj.')
+ df_cell = self.get_cell_df(values=values, drop=drop, keep=keep)
+ df_count, df_obs, d_obsm, d_obsp, d_uns = _anndextract(
+ df_cell = df_cell,
+ scale = scale,
+ graph_attached = self.get_attached_graph_dict(),
+ graph_neighbor = self.get_neighbor_graph_dict(),
+ graph_spring = self.get_spring_graph_dict(),
+ graph_method = self.get_physicell_version(),
+ )
+ annmcds = ad.AnnData(
+ X = df_count,
+ obs = df_obs,
+ obsm = d_obsm,
+ obsp = d_obsp,
+ uns = d_uns
+ )
+ # output
+ return annmcds
+
+
+ def get_attached_graph_dict(self):
+ """
+ input:
+
+ output:
+ dei_graph: dictionary of sets of integers
+ maps each cell ID to the attached connected cell IDs.
+
+ description:
+ function returns the attached cell graph as a dictionary object.
+ """
+ return self.data['cell']['dei_graph']['attached_cells'].copy()
+
+
+ def get_neighbor_graph_dict(self):
+ """
+ input:
+
+ output:
+ dei_graph: dictionary of sets of integers
+ maps each cell ID to the connected neighbor cell IDs.
+
+ description:
+ function returns the cell neighbor graph as a dictionary object.
+ """
+ return self.data['cell']['dei_graph']['neighbor_cells'].copy()
+
+
+ def get_spring_graph_dict(self):
+ """
+ input:
+
+ output:
+ dei_graph: dictionary of sets of integers
+ maps each cell ID to the attached connected cell IDs.
+
+ description:
+ function returns the attached spring cell graph as a dictionary object.
+ """
+ return self.data['cell']['dei_graph']['spring_attached_cells'].copy()
+
+
def plot_scatter(self, focus='cell_type', cat_drop=set(), cat_keep=set(), z_slice=0.0, z_axis=None, alpha=1, cmap='viridis', title=None, grid=True, legend_loc='lower left', xlim=None, ylim=None, xyequal=True, s=1.0, ax=None, figsizepx=None, directory=None, ext=None, figbgcolor=None, **kwargs):
"""
input:
@@ -2014,451 +2129,281 @@ def make_cell_vtk(self, attribute=['cell_type'], ext='_cell.vtp'):
return s_vtkpathfile
- ## MICROENVIRONMENT AND CELL AGENT RELATED FUNCTIONS ##
-
- def make_ome_tiff(self, cell_attribute='ID', conc_cutoff={}, focus=None, file=True):
+ def make_graph_gml(self, graph_type, edge_attribute=True, node_attribute=[]):
"""
input:
- cell_attribute: strings; default is 'ID', which will result in a
- cell segmentation mask.
- column name within the cell dataframe.
- the column data type has to be numeric (bool, int, float)
- and cannot be string.
- the result will be stored as 32 bit float.
-
- conc_cutoff: dictionary string to real; default is an empty dictionary.
- if a contour from a substrate not should be cut by greater
- than zero (shifted to integer 1), another cutoff value can be
- specified here.
+ graph_type: string
+ to specify which physicell output data should be processed.
+ neighbor, touch: processes mcds.get_neighbor_graph_dict dictionary.
+ attached: processes mcds.get_attached_graph_dict dictionary.
+ spring: processes mcds.get_spring_graph_dict dictionary.
- focus: set of strings; default is a None
- set of substrate and cell_type names to specify what will be
- translated into ome tiff format.
- if None, all substrates and cell types will be processed.
+ edge_attribute: boolean; default True
+ specifies if the spatial Euclidean distance is used for
+ edge attribute, to generate a weighted graph.
- file: boolean; default True
- if True, an ome tiff file is the output.
- if False, a numpy array with shape czyx is the output.
+ node_attribute: list of strings; default is empty list
+ list of mcds.get_cell_df dataframe columns, used for
+ node attributes.
output:
- a_tczyx_img: numpy array or ome tiff file.
+ gml file, generated under the returned path.
description:
- function to transform chosen mcds output into an 1[um] spaced
- czyx (channel, z-axis, y-axis, x-axis) ome tiff file or numpy array,
- one substrate or cell_type per channel.
- an ome tiff file is more or less:
- a numpy array, containing the image information
- and a xml, containing the microscopy metadata information,
- like the channel labels.
- the ome tiff file format can for example be read by the napari
- or fiji (imagej) software.
+ function to generate graph files in the gml graph modelling language
+ standard format.
- https://napari.org/stable/
- https://fiji.sc/
+ gml was the outcome of an initiative that started at
+ the international symposium on graph drawing 1995 in Passau
+ and ended at Graph Drawing 1996 in Berkeley. the networkx python
+ and igraph C and python libraries for graph analysis are
+ gml compatible and can as such read and write this file format.
+
+ https://en.wikipedia.org/wiki/Graph_Modelling_Language
+ https://github.com/elmbeech/physicelldataloader/blob/master/man/publication/himsolt1996gml_a_portable_graph_file_format.pdf
+ https://networkx.org/
+ https://igraph.org/
"""
- # load optional dependencies
- if file:
- OmeTiffWriter = optional_import('bioio.writers', s_attr='OmeTiffWriter', s_pip='bioio', s_caller='TimeStep.make_ome_tiff')
- bioio_base = optional_import('bioio_base', s_pip='bioio', s_caller='TimeStep.make_ome_tiff')
+ # load dataframe for celltype information
+ df_cell = self.get_cell_df()
+ ds_unit = self.get_unit_dict()
+ s_unit_simtime = ds_unit["time"]
+ r_simtime = self.get_time()
+ if (graph_type in {'attached'}):
+ dei_graph = self.get_attached_graph_dict()
+ elif (graph_type in {'neighbor', 'touch'}):
+ dei_graph = self.get_neighbor_graph_dict()
+ elif (graph_type in {'spring'}):
+ dei_graph = self.get_spring_graph_dict()
+ #elif (graph_type in {'evo','devo','lineage'}):
+ # dei_graph = self.get_lineage_graph_dict()
+ else:
+ sys.exit(f'Erro @ make_graph_gml : unknown graph_type {graph_type}. known are attached, neighbor, spring, and touch.')
- # handle channels
- ls_substrate = self.get_substrate_list()
- ls_celltype = self.get_celltype_list()
+ # generate filename
+ s_gmlpathfile = self.path + '/' + self.xmlfile.replace('.xml',f'_{graph_type}.gml')
- if not (focus is None):
- ls_substrate = [s_substrate for s_substrate in ls_substrate if s_substrate in set(focus)]
- ls_celltype = [s_celltype for s_celltype in ls_celltype if s_celltype in set(focus)]
- if (set(focus) != set(ls_substrate).union(set(ls_celltype))):
- sys.exit(f'Error : {focus} not found in {ls_substrate} {ls_celltype}')
+ # open result gml file
+ f = open(s_gmlpathfile, 'w')
+ f.write(f'Creator "pcdl_v{__version__}"\ngraph [\n')
+ f.write(f' id {int(r_simtime)}\n comment "time_{s_unit_simtime}"\n label "{graph_type}_graph"\n directed 0\n')
+ for i_src, ei_dst in dei_graph.items():
+ #print(f'{i_src} {sorted(ei_dst)}')
+ # node
+ f.write(f' node [\n id {i_src}\n label "node_{i_src}"\n')
+ # node attributes
+ for s_attribute in node_attribute:
+ o_attribute = df_cell.loc[i_src, s_attribute]
+ if (type(o_attribute) == str) or (o_attribute.dtype == np.object_): #in {str, np.str_, np.object_}):
+ f.write(f' {s_attribute} "{o_attribute}"\n')
+ elif (o_attribute.dtype == bool) or (o_attribute.dtype == int): #in {bool, np.bool_, np.bool, int, np.int_, np.int8, np.int16, np.int32, np.int64}):
+ f.write(f' {s_attribute} {int(o_attribute)}\n')
+ elif (o_attribute.dtype == float): #in {float, np.float16, np.float32, np.float64, np.float128}):
+ f.write(f' {s_attribute} {o_attribute}\n')
+ else:
+ sys.exit(f'Error @ TimeStep.make_graph_gml : attribute {o_attribute}; type {o_attribute.dtype}; type seems not to be bool, int, float, or string.')
+ f.write(f' ]\n')
+ # edge
+ for i_dst in ei_dst:
+ if (i_src < i_dst):
+ f.write(f' edge [\n source {i_src}\n target {i_dst}\n label "edge_{i_src}_{i_dst}"\n')
+ if (edge_attribute):
+ # edge distance attribute
+ x = df_cell.loc[i_src, 'position_x'] - df_cell.loc[i_dst, 'position_x']
+ y = df_cell.loc[i_src, 'position_y'] - df_cell.loc[i_dst, 'position_y']
+ z = df_cell.loc[i_src, 'position_z'] - df_cell.loc[i_dst, 'position_z']
+ r_distance = (x**2 + y**2 + z**2)**(1/2)
+ f.write(f' distance_{ds_unit["position_y"]} {round(r_distance)}\n')
+ f.write(f' ]\n')
+ # development
+ #if (i_src > 16):
+ # break
+ # close result gml file
+ f.write(']\n')
+ f.close()
- # const
- ls_coor_mnp = ['mesh_center_m', 'mesh_center_n', 'mesh_center_p'] # xyz
- ls_coor_xyz = ['position_x', 'position_y', 'position_z'] # xyz
- ls_coor = ['voxel_x', 'voxel_y', 'voxel_z']
+ # output
+ return s_gmlpathfile
- # time step tensor
- i_time = int(self.get_time())
- # get xy coordinate dataframe
- lr_axis_z = list(self.get_mesh_mnp_axis()[2] - self.get_voxel_spacing()[2] / 2)
- lr_axis_z.append(self.get_mesh_mnp_axis()[2][-1] + self.get_voxel_spacing()[2] / 2)
- lll_coor = []
- for i_x in range(int(round(self.get_voxel_ijk_range()[0][1] * self.get_voxel_spacing()[0]))):
- for i_y in range(int(round(self.get_voxel_ijk_range()[1][1] * self.get_voxel_spacing()[1]))):
- lll_coor.append([i_x, i_y])
- df_coor = pd.DataFrame(lll_coor, columns=ls_coor[:2])
- lr_axis_z[-1] += 1
+ ## SUBSTRATE AND CELL AGENT RELATED FUNCTIONS ##
- # extract voxel radius
- di_grow = {}
- for s_substarte in ls_substrate:
- di_grow.update({
- s_substarte : int(np.round(np.mean(self.get_voxel_spacing()[:2])) - 1)
- })
-
- # get and shift substrate xy data
- df_conc = self.get_conc_df()
- df_conc = df_conc.loc[:, ls_coor_mnp + ls_substrate]
- df_conc.loc[:, 'mesh_center_m'] = (df_conc.loc[:, 'mesh_center_m'] - self.get_xyz_range()[0][0]).round()
- df_conc.loc[:, 'mesh_center_n'] = (df_conc.loc[:, 'mesh_center_n'] - self.get_xyz_range()[1][0]).round()
- df_conc.rename({'mesh_center_m':'voxel_x', 'mesh_center_n':'voxel_y', 'mesh_center_p':'voxel_z'}, axis=1, inplace=True)
- df_conc = df_conc.astype({'voxel_x': int, 'voxel_y': int, 'voxel_z': float})
- # level the cake
- for s_channel in conc_cutoff.keys():
- try:
- df_conc.loc[:, s_channel] = df_conc.loc[:, s_channel] - conc_cutoff[s_channel] + 1 # positive values starting at > 0
- df_conc.loc[(df_conc.loc[:, s_channel] <= conc_cutoff[s_channel]), s_channel] = 0
- except KeyError:
- pass
-
- # get cell data
- df_cell = self.get_cell_df().reset_index()
-
- # extract cell radius
- for s_celltype in ls_celltype:
- try:
- i_cell_grow = int(round(df_cell.loc[(df_cell.cell_type == s_celltype), 'radius'].mean()) - 1)
- except:
- i_cell_grow = 0
- di_grow.update({s_celltype : i_cell_grow})
-
- # filter and shift
- df_cell = df_cell.loc[:, ls_coor_xyz + ['cell_type', cell_attribute]]
- if (cell_attribute == 'cell_type'):
- sys.exit(f'Error @ TimeStep.make_ome_tiff : cell_attribute cannot be cell_type.')
- elif (df_cell.loc[:, cell_attribute].dtype == str) or (df_cell.loc[:, cell_attribute].dtype == np.object_): # in {str, np.str_, np.object_}):
- sys.exit(f'Error @ TimeStep.make_ome_tiff : {cell_attribute} {df_cell.loc[:, cell_attribute].dtype} cell_attribute cannot be string or object. cell_attribute has to be boolean, integer, or float.')
- elif (df_cell.loc[:, cell_attribute].dtype == bool): # in {bool, np.bool_, np.bool}):
- df_cell = df_cell.astype({cell_attribute: int})
- df_cell.loc[:, 'position_x'] = (df_cell.loc[:, 'position_x'] - self.get_xyz_range()[0][0]).round()
- df_cell.loc[:, 'position_y'] = (df_cell.loc[:, 'position_y'] - self.get_xyz_range()[1][0]).round()
- df_cell.rename({'position_x':'voxel_x', 'position_y':'voxel_y', 'position_z':'voxel_z'}, axis=1, inplace=True)
- df_cell = df_cell.astype({'voxel_x': int, 'voxel_y': int, 'voxel_z': float})
- # level the cake
- df_cell.loc[:, cell_attribute] = df_cell.loc[:, cell_attribute] - df_cell.loc[:, cell_attribute].min() + 1 # positive values starting at > 0
-
- # check for duplicates: two cell at exactelly the same xyz position.
- #if self.verbose and df_cell.loc[:,['voxel_x', 'voxel_y', 'voxel_z']].duplicated().any():
- # df_duplicate = df_cell.loc[(df_cell.loc[:, ['voxel_x', 'voxel_y', 'voxel_z']].duplicated()), :]
- # sys.exit(f"Error @ TimeStep.make_ome_tiff : {df_duplicate} cells at exactely the same xyz voxel position detected. cannot pivot!")
-
- # pivot cell_type
- df_cell = df_cell.pivot_table(index=ls_coor, columns='cell_type', values=cell_attribute, aggfunc='sum').reset_index() # fill_value is na
- for s_celltype in ls_celltype:
- if not s_celltype in set(df_cell.columns):
- df_cell[s_celltype] = 0
-
- # each C channel - time step tensors
- la_czyx_img = []
- ls_channel = ls_substrate + ls_celltype
- for s_channel in ls_channel:
-
- # get channel dataframe
- if s_channel in set(ls_substrate):
- df_channel = df_conc.loc[:, ls_coor + [s_channel]]
- elif s_channel in set(ls_celltype):
- df_channel = df_cell.loc[:, ls_coor + [s_channel]]
- else:
- sys.exit(f'Error @ TimeStep.make_ome_tiff : {s_channel} unknown channel detected. not in substrate and cell type list {ls_substrate} {ls_celltype}!')
-
- # each z axis
- la_zyx_img = []
- for i_zaxis in range(len(lr_axis_z)):
- if (i_zaxis < (len(lr_axis_z) - 1)):
- print(f'processing: {i_time} [min] {s_channel} [channel] {i_zaxis} [z_axis] ...')
- # extract z layer
- df_yxchannel = df_channel.loc[
- ((df_channel.loc[:, ls_coor[2]] >= lr_axis_z[i_zaxis]) & (df_channel.loc[:, ls_coor[2]] < lr_axis_z[i_zaxis + 1])),
- ls_coor[:2] + [s_channel]
- ]
-
- # drop row with na and duplicate entries
- df_yxchannel = df_yxchannel.dropna(axis=0)
- df_yxchannel = df_yxchannel.drop_duplicates()
-
- # merge with coooridnates and get image
- # bue 20240811: df_coor left side merge will cut off reset cell that are out of the xyz domain range, which is what we want.
- df_yxchannel = pd.merge(df_coor, df_yxchannel, on=ls_coor[:2], how='left').replace({np.nan: 0})
- try:
- df_yxchannel = df_yxchannel.pivot(columns=ls_coor[0], index=ls_coor[1], values=s_channel)
- except ValueError: # two cells from the same cell type very close to each other detetced.
- if self.verbose:
- df_duplicate = df_cell.loc[(df_yxchannel.loc[:, ['voxel_x', 'voxel_y']].duplicated()), :]
- print(f'Warning: {s_channel} {df_duplicate} cells within 1[um] distance form each detected. cannot pivot. erase cell type from this timestep.')
- df_yxchannel.loc[:,s_channel] = 0 # erase cells
- df_yxchannel = df_yxchannel.drop_duplicates()
- df_yxchannel = df_yxchannel.pivot(columns=ls_coor[0], index=ls_coor[1], values=s_channel)
- a_yx_img = df_yxchannel.values
-
- # grow
- a_yx_img = imagine.grow_seed(a_yx_img, i_step=di_grow[s_channel], b_verbose=False)
-
- # update output
- la_zyx_img.append(a_yx_img)
- a_zyx_img = np.array(la_zyx_img, np.float32)
- la_czyx_img.append(np.array(a_zyx_img, np.float32))
-
- # output
- a_czyx_img = np.array(la_czyx_img, dtype=np.float32)
-
- # numpy array
- if not file:
- return a_czyx_img
-
- # write to file
- else:
- if self.verbose:
- print('a_czyx_img shape:', a_czyx_img.shape)
- # generate filename
- s_channel = ''
- for s_substrate in ls_substrate:
- try:
- r_value = conc_cutoff[s_substrate]
- s_channel += f'_{s_substrate}{r_value}'
- except KeyError:
- s_channel += f'_{s_substrate}'
- for s_celltype in ls_celltype:
- s_channel += f'_{s_celltype}'
- if len(ls_celltype) > 0:
- s_channel += f'_{cell_attribute}'
- s_tifffile = self.xmlfile.replace('.xml', f'{s_channel}.ome.tiff')
- s_tifffile = s_tifffile.replace(' ','_')
- if (len(s_tifffile) > 255):
- print(f"Warning: filename {len(s_tifffile)} > 255 character.")
- s_tifffile = self.xmlfile.replace('.xml', f'_channels.ome.tiff')
- print(f"file name adjusted to {s_tifffile}.")
- s_tiffpathfile = self.path + '/' + s_tifffile
-
- # save to file
- OmeTiffWriter.save(
- a_czyx_img,
- s_tiffpathfile,
- dim_order = 'CZYX',
- #ome_xml=x_img,
- channel_names = ls_channel,
- image_names = [s_tifffile.replace('.ome.tiff','')],
- physical_pixel_sizes = bioio_base.types.PhysicalPixelSizes(self.get_voxel_spacing()[2], 1.0, 1.0), # z,y,x [um]
- #channel_colors=,
- #fs_kwargs={},
- )
- return s_tiffpathfile
-
-
- def render_neuroglancer(self, tiffpathfile, timestep=0, intensity_cmap='gray'):
- """
- help(pcdl.render_neuroglancer)
- try: mcds.render_neuroglancer(mcds.make_ome_tiff())
- """
- o_viewer = render_neuroglancer(
- tiffpathfile = tiffpathfile,
- timestep = timestep,
- intensity_cmap = intensity_cmap,
- )
- return o_viewer
-
-
- ## GRAPH RELATED FUNCTIONS ##
-
- def get_attached_graph_dict(self):
+ def get_muspan(self, z_slice=None, values=1, drop=set(), keep=set()):
"""
input:
+ z_slice: floating point number; default is None
+ z-axis position to slice a 2D xy-plain out of the
+ 3D mesh. if None the whole 3D mesh will be returned.
- output:
- dei_graph: dictionary of sets of integers
- maps each cell ID to the attached connected cell IDs.
-
- description:
- function returns the attached cell graph as a dictionary object.
- """
- return self.data['cell']['dei_graph']['attached_cells'].copy()
+ values: integer; default is 1
+ minimal number of values a variable has to have to be outputted.
+ variables that have only 1 state carry no information.
+ None is a state too.
+ drop: set of strings; default is an empty set
+ set of column labels to be dropped for the dataframe.
+ don't worry: essential columns like ID, coordinates
+ and time will never be dropped.
+ Attention: when the keep parameter is given, then
+ the drop parameter has to be an empty set!
- def get_neighbor_graph_dict(self):
- """
- input:
+ keep: set of strings; default is an empty set
+ set of column labels to be kept in the dataframe.
+ set values=1 to be sure that all variables are kept.
+ don't worry: essential columns like ID, coordinates
+ and time will always be kept.
output:
- dei_graph: dictionary of sets of integers
- maps each cell ID to the connected neighbor cell IDs.
+ do_domain: dictionary of muspa domains, one for each z-layer.
description:
- function returns the cell neighbor graph as a dictionary object.
+ function returns a dictionary of muspa domains, containg a
+ cell and subs collection with disrcete and continuous labels
+ and all the graph as networks.
+ + https://www.muspan.co.uk
+ + https://docs.muspan.co.uk/latest/Documentation.html
"""
- return self.data['cell']['dei_graph']['neighbor_cells'].copy()
-
+ # check if muspan library is installed
+ if (ms is None) or (ms.__file__ is None):
+ sys.exit(f'Error @ TimeStep.get_muspa : the muspan Multi Spatial Analysis python3 library is not installed!\nfor instructions check out : https://www.muspan.co.uk/')
- def get_spring_graph_dict(self):
- """
- input:
+ # load optional dependency
+ nx = optional_import('networkx', s_caller='TimeStep.get_muspan')
- output:
- dei_graph: dictionary of sets of integers
- maps each cell ID to the attached connected cell IDs.
+ # get conc and cell dataframe
+ df_conc = self.get_conc_df(values=values, drop=drop, keep=keep)
+ df_cell = self.get_cell_df(values=values, drop=drop, keep=keep)
+ i_kmax = df_conc.voxel_k.max()
+ i_kdigit = len(str(i_kmax))
+ if (z_slice is None):
+ li_klayer = sorted(df_conc.voxel_k.unique())
+ else:
+ li_klayer = [self.get_voxel_ijk(x=0,y=0, z=z_slice)[2]]
- description:
- function returns the attached spring cell graph as a dictionary object.
- """
- return self.data['cell']['dei_graph']['spring_attached_cells'].copy()
+ # for each z layer generate a muspa domain
+ do_domain = {}
+ for i_klayer in li_klayer:
+ # processing
+ if self.verbose:
+ print(f'processing: {self.xmlfile} mcds {i_klayer + 1}/{i_kmax + 1} z-stack layer to muspan obj.')
- def make_graph_gml(self, graph_type, edge_attribute=True, node_attribute=[]):
- """
- input:
- graph_type: string
- to specify which physicell output data should be processed.
- neighbor, touch: processes mcds.get_neighbor_graph_dict dictionary.
- attached: processes mcds.get_attached_graph_dict dictionary.
- spring: processes mcds.get_spring_graph_dict dictionary.
+ ## generate muspan domain
+ s_domain = f"{self.xmlfile.replace('.xml','')}_z{str(i_klayer).zfill(i_kdigit)}"
+ o_domain = ms.domain(
+ name = s_domain,
+ unit_of_length = 'um',
+ )
- edge_attribute: boolean; default True
- specifies if the spatial Euclidean distance is used for
- edge attribute, to generate a weighted graph.
-
- node_attribute: list of strings; default is empty list
- list of mcds.get_cell_df dataframe columns, used for
- node attributes.
-
- output:
- gml file, generated under the returned path.
-
- description:
- function to generate graph files in the gml graph modelling language
- standard format.
-
- gml was the outcome of an initiative that started at
- the international symposium on graph drawing 1995 in Passau
- and ended at Graph Drawing 1996 in Berkeley. the networkx python
- and igraph C and python libraries for graph analysis are
- gml compatible and can as such read and write this file format.
-
- https://en.wikipedia.org/wiki/Graph_Modelling_Language
- https://github.com/elmbeech/physicelldataloader/blob/master/man/publication/himsolt1996gml_a_portable_graph_file_format.pdf
- https://networkx.org/
- https://igraph.org/
- """
- # load dataframe for celltype information
- df_cell = self.get_cell_df()
- ds_unit = self.get_unit_dict()
- s_unit_simtime = ds_unit["time"]
- r_simtime = self.get_time()
- if (graph_type in {'attached'}):
- dei_graph = self.get_attached_graph_dict()
- elif (graph_type in {'neighbor', 'touch'}):
- dei_graph = self.get_neighbor_graph_dict()
- elif (graph_type in {'spring'}):
- dei_graph = self.get_spring_graph_dict()
- #elif (graph_type in {'evo','devo','lineage'}):
- # dei_graph = self.get_lineage_graph_dict()
- else:
- sys.exit(f'Erro @ make_graph_gml : unknown graph_type {graph_type}. known are attached, neighbor, spring, and touch.')
-
- # generate filename
- s_gmlpathfile = self.path + '/' + self.xmlfile.replace('.xml',f'_{graph_type}.gml')
+ ## handle subs collection
+ df_zconc = df_conc.loc[df_conc.voxel_k == i_klayer,:]
+ o_domain.add_points(
+ points = df_zconc.loc[:,['mesh_center_m','mesh_center_n']].values,
+ collection_name = 'subs'
+ )
+ # drop this data
+ es_drop = set(df_zconc.columns).intersection({
+ 'voxel_i', 'voxel_j', 'voxel_k',
+ 'mesh_center_m', 'mesh_center_n', 'mesh_center_p',
+ 'time', 'runtime', 'xmlfile',
+ })
+ df_zconc = df_zconc.drop(es_drop, axis=1)
+ # add numerical data (no scaling)
+ for s_num in sorted(df_zconc.columns):
+ o_domain.add_labels(
+ label_name = s_num,
+ labels = df_zconc.loc[:,s_num],
+ add_labels_to = 'subs',
+ label_type = 'continuous',
+ )
- # open result gml file
- f = open(s_gmlpathfile, 'w')
- f.write(f'Creator "pcdl_v{__version__}"\ngraph [\n')
- f.write(f' id {int(r_simtime)}\n comment "time_{s_unit_simtime}"\n label "{graph_type}_graph"\n directed 0\n')
- for i_src, ei_dst in dei_graph.items():
- #print(f'{i_src} {sorted(ei_dst)}')
- # node
- f.write(f' node [\n id {i_src}\n label "node_{i_src}"\n')
- # node attributes
- for s_attribute in node_attribute:
- o_attribute = df_cell.loc[i_src, s_attribute]
- if (type(o_attribute) == str) or (o_attribute.dtype == np.object_): #in {str, np.str_, np.object_}):
- f.write(f' {s_attribute} "{o_attribute}"\n')
- elif (o_attribute.dtype == bool) or (o_attribute.dtype == int): #in {bool, np.bool_, np.bool, int, np.int_, np.int8, np.int16, np.int32, np.int64}):
- f.write(f' {s_attribute} {int(o_attribute)}\n')
- elif (o_attribute.dtype == float): #in {float, np.float16, np.float32, np.float64, np.float128}):
- f.write(f' {s_attribute} {o_attribute}\n')
+ ## handle cell collection
+ df_zcell = df_cell.loc[df_cell.voxel_k == i_klayer,:]
+ o_domain.add_points(
+ points = df_zcell.loc[:,['position_x','position_y']].values,
+ collection_name = 'cell'
+ )
+ # get a physicell cell_id to muspan object id mapping
+ df_coor = df_zcell.loc[:,['position_x', 'position_y','position_z']]
+ df_coor['muspan_id'] = o_domain.collections['cell']['objects']
+ di_cellid = df_coor['muspan_id'].to_dict()
+ # drop this data
+ es_drop = set(df_zcell.columns).intersection({
+ 'voxel_i', 'voxel_j', 'voxel_k',
+ 'mesh_center_m', 'mesh_center_n', 'mesh_center_p',
+ 'position_x', 'position_y','position_z',
+ 'time', 'runtime', 'xmlfile',
+ })
+ df_zcell = df_zcell.drop(es_drop, axis=1)
+ # dectect variable types
+ des_type = {'float': set(), 'int': set(), 'bool': set(), 'str': set()}
+ for _, se_zcell in df_zcell.items():
+ if str(se_zcell.dtype).startswith('float'):
+ des_type['float'].add(se_zcell.name)
+ elif str(se_zcell.dtype).startswith('int'):
+ des_type['int'].add(se_zcell.name)
+ elif str(se_zcell.dtype).startswith('bool'):
+ des_type['bool'].add(se_zcell.name)
+ elif str(se_zcell.dtype).startswith('object') in str(se_zcell.dtype).startswith('str'):
+ des_type['str'].add(se_zcell.name)
else:
- sys.exit(f'Error @ TimeStep.make_graph_gml : attribute {o_attribute}; type {o_attribute.dtype}; type seems not to be bool, int, float, or string.')
- f.write(f' ]\n')
- # edge
- for i_dst in ei_dst:
- if (i_src < i_dst):
- f.write(f' edge [\n source {i_src}\n target {i_dst}\n label "edge_{i_src}_{i_dst}"\n')
- if (edge_attribute):
- # edge distance attribute
- x = df_cell.loc[i_src, 'position_x'] - df_cell.loc[i_dst, 'position_x']
- y = df_cell.loc[i_src, 'position_y'] - df_cell.loc[i_dst, 'position_y']
- z = df_cell.loc[i_src, 'position_z'] - df_cell.loc[i_dst, 'position_z']
- r_distance = (x**2 + y**2 + z**2)**(1/2)
- f.write(f' distance_{ds_unit["position_y"]} {round(r_distance)}\n')
- f.write(f' ]\n')
- # development
- #if (i_src > 16):
- # break
- # close result gml file
- f.write(']\n')
- f.close()
-
- # output
- return s_gmlpathfile
-
-
- ## ANNDATA RELATED FUNCTIONS ##
-
- def get_anndata(self, values=1, drop=set(), keep=set(), scale='maxabs'):
- """
- input:
- values: integer; default is 1
- minimal number of values a variable has to have to be outputted.
- variables that have only 1 state carry no information.
- None is a state too.
-
- drop: set of strings; default is an empty set
- set of column labels to be dropped for the dataframe.
- don't worry: essential columns like ID, coordinates
- and time will never be dropped.
- Attention: when the keep parameter is given, then
- the drop parameter has to be an empty set!
-
- keep: set of strings; default is an empty set
- set of column labels to be kept in the dataframe.
- set values=1 to be sure that all variables are kept.
- don't worry: essential columns like ID, coordinates
- and time will always be kept.
-
- scale: string; default 'maxabs'
- specify how the data should be scaled.
- possible values are None, maxabs, minmax, std.
- for more input, check out: help(pcdl.scaler)
+ sys.exit(f'Error @ TimeStep.get_muspa : column {se_zcell.name} detected with unknown dtype {str(se_zcell.dtype)}.')
+ # add categorical data
+ for s_cat in sorted(des_type['str'].union(des_type['bool'])):
+ o_domain.add_labels(
+ label_name = s_cat,
+ labels = df_zcell.loc[:,s_cat],
+ add_labels_to = 'cell',
+ label_type = 'categorical',
+ )
+ # add numerical data (no scaling)
+ for s_num in sorted(des_type['float'].union(des_type['int'])):
+ o_domain.add_labels(
+ label_name = s_num,
+ labels = df_zcell.loc[:,s_num],
+ add_labels_to = 'cell',
+ label_type = 'continuous',
+ )
+ ## add graphs
+ ei_pccellid = set(df_zcell.index)
+ for s_graph, dei_graph in [
+ ('neighbor', self.get_neighbor_graph_dict()),
+ ('attached', self.get_attached_graph_dict()),
+ ('spring', self.get_spring_graph_dict()),
+ ]:
+ # transform graph dict into weighted edge list
+ lt_wedge = []
+ for i_src, ei_dst in sorted(dei_graph.items()):
+ for i_dst in ei_dst:
+ if (i_src in ei_pccellid) and (i_dst in ei_pccellid):
+ r_distance = ((df_coor.loc[i_src, ['position_x','position_y','position_z']].values - df_coor.loc[i_dst, ['position_x','position_y','position_z']].values)**2).sum()**(1/2)
+ lt_wedge.append((di_cellid[i_src], di_cellid[i_dst], r_distance))
+ # generate graph
+ G = nx.Graph()
+ # dump the edges into the network
+ G.add_weighted_edges_from(lt_wedge, weight='Distance')
+ G.add_weighted_edges_from(lt_wedge, weight='Inverse Distance')
+ # add the network to the dictionary of networks
+ o_domain.networks[s_graph] = G
+ # clean up the domain
+ ms.helpers.clean_up(o_domain)
- output:
- annmcds: anndata object
- for this one time step.
+ ## set domain boundary (have to be done last!)
+ o_domain.estimate_boundary(
+ method='specify',
+ specify_boundary_coords=(
+ (self.get_xyz_range()[0][0], self.get_xyz_range()[1][0]),
+ (self.get_xyz_range()[0][0], self.get_xyz_range()[1][1]),
+ (self.get_xyz_range()[0][1], self.get_xyz_range()[1][1]),
+ (self.get_xyz_range()[0][1], self.get_xyz_range()[1][0])
+ )
+ )
- description:
- function to transform a mcds time step into an anndata object
- for downstream analysis.
- """
- # load optional dependency
- ad = optional_import('anndata', s_caller='TimeStep.get_anndata')
+ # update output
+ do_domain.update({s_domain : o_domain})
- # processing
- if self.verbose:
- print(f'processing: 1/1 {round(self.get_time(),9)}[min] mcds into anndata obj.')
- df_cell = self.get_cell_df(values=values, drop=drop, keep=keep)
- df_count, df_obs, d_obsm, d_obsp, d_uns = _anndextract(
- df_cell = df_cell,
- scale = scale,
- graph_attached = self.get_attached_graph_dict(),
- graph_neighbor = self.get_neighbor_graph_dict(),
- graph_spring = self.get_spring_graph_dict(),
- graph_method = self.get_physicell_version(),
- )
- annmcds = ad.AnnData(
- X = df_count,
- obs = df_obs,
- obsm = d_obsm,
- obsp = d_obsp,
- uns = d_uns
- )
# output
- return annmcds
+ return do_domain
def get_spatialdata(self, images={'subs'}, labels={}, points={'subs'}, shapes={'cell'}, values=1, drop=set(), keep=set(), scale='maxabs'):
@@ -2722,184 +2667,233 @@ def get_spatialdata(self, images={'subs'}, labels={}, points={'subs'}, shapes={'
return sdata
- ## MUSPAN RELATED FUNCTIONS ##
-
- def get_muspan(self, z_slice=None, values=1, drop=set(), keep=set()):
+ def make_ome_tiff(self, cell_attribute='ID', conc_cutoff={}, focus=None, file=True):
"""
input:
- z_slice: floating point number; default is None
- z-axis position to slice a 2D xy-plain out of the
- 3D mesh. if None the whole 3D mesh will be returned.
+ cell_attribute: strings; default is 'ID', which will result in a
+ cell segmentation mask.
+ column name within the cell dataframe.
+ the column data type has to be numeric (bool, int, float)
+ and cannot be string.
+ the result will be stored as 32 bit float.
- values: integer; default is 1
- minimal number of values a variable has to have to be outputted.
- variables that have only 1 state carry no information.
- None is a state too.
+ conc_cutoff: dictionary string to real; default is an empty dictionary.
+ if a contour from a substrate not should be cut by greater
+ than zero (shifted to integer 1), another cutoff value can be
+ specified here.
- drop: set of strings; default is an empty set
- set of column labels to be dropped for the dataframe.
- don't worry: essential columns like ID, coordinates
- and time will never be dropped.
- Attention: when the keep parameter is given, then
- the drop parameter has to be an empty set!
+ focus: set of strings; default is a None
+ set of substrate and cell_type names to specify what will be
+ translated into ome tiff format.
+ if None, all substrates and cell types will be processed.
- keep: set of strings; default is an empty set
- set of column labels to be kept in the dataframe.
- set values=1 to be sure that all variables are kept.
- don't worry: essential columns like ID, coordinates
- and time will always be kept.
+ file: boolean; default True
+ if True, an ome tiff file is the output.
+ if False, a numpy array with shape czyx is the output.
output:
- do_domain: dictionary of muspa domains, one for each z-layer.
+ a_tczyx_img: numpy array or ome tiff file.
description:
- function returns a dictionary of muspa domains, containg a
- cell and subs collection with disrcete and continuous labels
- and all the graph as networks.
- + https://www.muspan.co.uk
- + https://docs.muspan.co.uk/latest/Documentation.html
+ function to transform chosen mcds output into an 1[um] spaced
+ czyx (channel, z-axis, y-axis, x-axis) ome tiff file or numpy array,
+ one substrate or cell_type per channel.
+ an ome tiff file is more or less:
+ a numpy array, containing the image information
+ and a xml, containing the microscopy metadata information,
+ like the channel labels.
+ the ome tiff file format can for example be read by the napari
+ or fiji (imagej) software.
+
+ https://napari.org/stable/
+ https://fiji.sc/
"""
- # check if muspan library is installed
- if (ms is None) or (ms.__file__ is None):
- sys.exit(f'Error @ TimeStep.get_muspa : the muspan Multi Spatial Analysis python3 library is not installed!\nfor instructions check out : https://www.muspan.co.uk/')
+ # load optional dependencies
+ if file:
+ OmeTiffWriter = optional_import('bioio.writers', s_attr='OmeTiffWriter', s_pip='bioio', s_caller='TimeStep.make_ome_tiff')
+ bioio_base = optional_import('bioio_base', s_pip='bioio', s_caller='TimeStep.make_ome_tiff')
- # load optional dependency
- nx = optional_import('networkx', s_caller='TimeStep.get_muspan')
+ # handle channels
+ ls_substrate = self.get_substrate_list()
+ ls_celltype = self.get_celltype_list()
- # get conc and cell dataframe
- df_conc = self.get_conc_df(values=values, drop=drop, keep=keep)
- df_cell = self.get_cell_df(values=values, drop=drop, keep=keep)
- i_kmax = df_conc.voxel_k.max()
- i_kdigit = len(str(i_kmax))
- if (z_slice is None):
- li_klayer = sorted(df_conc.voxel_k.unique())
- else:
- li_klayer = [self.get_voxel_ijk(x=0,y=0, z=z_slice)[2]]
+ if not (focus is None):
+ ls_substrate = [s_substrate for s_substrate in ls_substrate if s_substrate in set(focus)]
+ ls_celltype = [s_celltype for s_celltype in ls_celltype if s_celltype in set(focus)]
+ if (set(focus) != set(ls_substrate).union(set(ls_celltype))):
+ sys.exit(f'Error : {focus} not found in {ls_substrate} {ls_celltype}')
- # for each z layer generate a muspa domain
- do_domain = {}
- for i_klayer in li_klayer:
+ # const
+ ls_coor_mnp = ['mesh_center_m', 'mesh_center_n', 'mesh_center_p'] # xyz
+ ls_coor_xyz = ['position_x', 'position_y', 'position_z'] # xyz
+ ls_coor = ['voxel_x', 'voxel_y', 'voxel_z']
- # processing
- if self.verbose:
- print(f'processing: {self.xmlfile} mcds {i_klayer + 1}/{i_kmax + 1} z-stack layer to muspan obj.')
+ # time step tensor
+ i_time = int(self.get_time())
- ## generate muspan domain
- s_domain = f"{self.xmlfile.replace('.xml','')}_z{str(i_klayer).zfill(i_kdigit)}"
- o_domain = ms.domain(
- name = s_domain,
- unit_of_length = 'um',
- )
+ # get xy coordinate dataframe
+ lr_axis_z = list(self.get_mesh_mnp_axis()[2] - self.get_voxel_spacing()[2] / 2)
+ lr_axis_z.append(self.get_mesh_mnp_axis()[2][-1] + self.get_voxel_spacing()[2] / 2)
+ lll_coor = []
+ for i_x in range(int(round(self.get_voxel_ijk_range()[0][1] * self.get_voxel_spacing()[0]))):
+ for i_y in range(int(round(self.get_voxel_ijk_range()[1][1] * self.get_voxel_spacing()[1]))):
+ lll_coor.append([i_x, i_y])
+ df_coor = pd.DataFrame(lll_coor, columns=ls_coor[:2])
+ lr_axis_z[-1] += 1
- ## handle subs collection
- df_zconc = df_conc.loc[df_conc.voxel_k == i_klayer,:]
- o_domain.add_points(
- points = df_zconc.loc[:,['mesh_center_m','mesh_center_n']].values,
- collection_name = 'subs'
- )
- # drop this data
- es_drop = set(df_zconc.columns).intersection({
- 'voxel_i', 'voxel_j', 'voxel_k',
- 'mesh_center_m', 'mesh_center_n', 'mesh_center_p',
- 'time', 'runtime', 'xmlfile',
+ # extract voxel radius
+ di_grow = {}
+ for s_substarte in ls_substrate:
+ di_grow.update({
+ s_substarte : int(np.round(np.mean(self.get_voxel_spacing()[:2])) - 1)
})
- df_zconc = df_zconc.drop(es_drop, axis=1)
- # add numerical data (no scaling)
- for s_num in sorted(df_zconc.columns):
- o_domain.add_labels(
- label_name = s_num,
- labels = df_zconc.loc[:,s_num],
- add_labels_to = 'subs',
- label_type = 'continuous',
- )
- ## handle cell collection
- df_zcell = df_cell.loc[df_cell.voxel_k == i_klayer,:]
- o_domain.add_points(
- points = df_zcell.loc[:,['position_x','position_y']].values,
- collection_name = 'cell'
- )
- # get a physicell cell_id to muspan object id mapping
- df_coor = df_zcell.loc[:,['position_x', 'position_y','position_z']]
- df_coor['muspan_id'] = o_domain.collections['cell']['objects']
- di_cellid = df_coor['muspan_id'].to_dict()
- # drop this data
- es_drop = set(df_zcell.columns).intersection({
- 'voxel_i', 'voxel_j', 'voxel_k',
- 'mesh_center_m', 'mesh_center_n', 'mesh_center_p',
- 'position_x', 'position_y','position_z',
- 'time', 'runtime', 'xmlfile',
- })
- df_zcell = df_zcell.drop(es_drop, axis=1)
- # dectect variable types
- des_type = {'float': set(), 'int': set(), 'bool': set(), 'str': set()}
- for _, se_zcell in df_zcell.items():
- if str(se_zcell.dtype).startswith('float'):
- des_type['float'].add(se_zcell.name)
- elif str(se_zcell.dtype).startswith('int'):
- des_type['int'].add(se_zcell.name)
- elif str(se_zcell.dtype).startswith('bool'):
- des_type['bool'].add(se_zcell.name)
- elif str(se_zcell.dtype).startswith('object') in str(se_zcell.dtype).startswith('str'):
- des_type['str'].add(se_zcell.name)
- else:
- sys.exit(f'Error @ TimeStep.get_muspa : column {se_zcell.name} detected with unknown dtype {str(se_zcell.dtype)}.')
- # add categorical data
- for s_cat in sorted(des_type['str'].union(des_type['bool'])):
- o_domain.add_labels(
- label_name = s_cat,
- labels = df_zcell.loc[:,s_cat],
- add_labels_to = 'cell',
- label_type = 'categorical',
- )
- # add numerical data (no scaling)
- for s_num in sorted(des_type['float'].union(des_type['int'])):
- o_domain.add_labels(
- label_name = s_num,
- labels = df_zcell.loc[:,s_num],
- add_labels_to = 'cell',
- label_type = 'continuous',
- )
- ## add graphs
- ei_pccellid = set(df_zcell.index)
- for s_graph, dei_graph in [
- ('neighbor', self.get_neighbor_graph_dict()),
- ('attached', self.get_attached_graph_dict()),
- ('spring', self.get_spring_graph_dict()),
- ]:
- # transform graph dict into weighted edge list
- lt_wedge = []
- for i_src, ei_dst in sorted(dei_graph.items()):
- for i_dst in ei_dst:
- if (i_src in ei_pccellid) and (i_dst in ei_pccellid):
- r_distance = ((df_coor.loc[i_src, ['position_x','position_y','position_z']].values - df_coor.loc[i_dst, ['position_x','position_y','position_z']].values)**2).sum()**(1/2)
- lt_wedge.append((di_cellid[i_src], di_cellid[i_dst], r_distance))
- # generate graph
- G = nx.Graph()
- # dump the edges into the network
- G.add_weighted_edges_from(lt_wedge, weight='Distance')
- G.add_weighted_edges_from(lt_wedge, weight='Inverse Distance')
- # add the network to the dictionary of networks
- o_domain.networks[s_graph] = G
- # clean up the domain
- ms.helpers.clean_up(o_domain)
+ # get and shift substrate xy data
+ df_conc = self.get_conc_df()
+ df_conc = df_conc.loc[:, ls_coor_mnp + ls_substrate]
+ df_conc.loc[:, 'mesh_center_m'] = (df_conc.loc[:, 'mesh_center_m'] - self.get_xyz_range()[0][0]).round()
+ df_conc.loc[:, 'mesh_center_n'] = (df_conc.loc[:, 'mesh_center_n'] - self.get_xyz_range()[1][0]).round()
+ df_conc.rename({'mesh_center_m':'voxel_x', 'mesh_center_n':'voxel_y', 'mesh_center_p':'voxel_z'}, axis=1, inplace=True)
+ df_conc = df_conc.astype({'voxel_x': int, 'voxel_y': int, 'voxel_z': float})
+ # level the cake
+ for s_channel in conc_cutoff.keys():
+ try:
+ df_conc.loc[:, s_channel] = df_conc.loc[:, s_channel] - conc_cutoff[s_channel] + 1 # positive values starting at > 0
+ df_conc.loc[(df_conc.loc[:, s_channel] <= conc_cutoff[s_channel]), s_channel] = 0
+ except KeyError:
+ pass
- ## set domain boundary (have to be done last!)
- o_domain.estimate_boundary(
- method='specify',
- specify_boundary_coords=(
- (self.get_xyz_range()[0][0], self.get_xyz_range()[1][0]),
- (self.get_xyz_range()[0][0], self.get_xyz_range()[1][1]),
- (self.get_xyz_range()[0][1], self.get_xyz_range()[1][1]),
- (self.get_xyz_range()[0][1], self.get_xyz_range()[1][0])
- )
- )
+ # get cell data
+ df_cell = self.get_cell_df().reset_index()
- # update output
- do_domain.update({s_domain : o_domain})
+ # extract cell radius
+ for s_celltype in ls_celltype:
+ try:
+ i_cell_grow = int(round(df_cell.loc[(df_cell.cell_type == s_celltype), 'radius'].mean()) - 1)
+ except:
+ i_cell_grow = 0
+ di_grow.update({s_celltype : i_cell_grow})
+
+ # filter and shift
+ df_cell = df_cell.loc[:, ls_coor_xyz + ['cell_type', cell_attribute]]
+ if (cell_attribute == 'cell_type'):
+ sys.exit(f'Error @ TimeStep.make_ome_tiff : cell_attribute cannot be cell_type.')
+ elif (df_cell.loc[:, cell_attribute].dtype == str) or (df_cell.loc[:, cell_attribute].dtype == np.object_): # in {str, np.str_, np.object_}):
+ sys.exit(f'Error @ TimeStep.make_ome_tiff : {cell_attribute} {df_cell.loc[:, cell_attribute].dtype} cell_attribute cannot be string or object. cell_attribute has to be boolean, integer, or float.')
+ elif (df_cell.loc[:, cell_attribute].dtype == bool): # in {bool, np.bool_, np.bool}):
+ df_cell = df_cell.astype({cell_attribute: int})
+ df_cell.loc[:, 'position_x'] = (df_cell.loc[:, 'position_x'] - self.get_xyz_range()[0][0]).round()
+ df_cell.loc[:, 'position_y'] = (df_cell.loc[:, 'position_y'] - self.get_xyz_range()[1][0]).round()
+ df_cell.rename({'position_x':'voxel_x', 'position_y':'voxel_y', 'position_z':'voxel_z'}, axis=1, inplace=True)
+ df_cell = df_cell.astype({'voxel_x': int, 'voxel_y': int, 'voxel_z': float})
+ # level the cake
+ df_cell.loc[:, cell_attribute] = df_cell.loc[:, cell_attribute] - df_cell.loc[:, cell_attribute].min() + 1 # positive values starting at > 0
+
+ # check for duplicates: two cell at exactelly the same xyz position.
+ #if self.verbose and df_cell.loc[:,['voxel_x', 'voxel_y', 'voxel_z']].duplicated().any():
+ # df_duplicate = df_cell.loc[(df_cell.loc[:, ['voxel_x', 'voxel_y', 'voxel_z']].duplicated()), :]
+ # sys.exit(f"Error @ TimeStep.make_ome_tiff : {df_duplicate} cells at exactely the same xyz voxel position detected. cannot pivot!")
+
+ # pivot cell_type
+ df_cell = df_cell.pivot_table(index=ls_coor, columns='cell_type', values=cell_attribute, aggfunc='sum').reset_index() # fill_value is na
+ for s_celltype in ls_celltype:
+ if not s_celltype in set(df_cell.columns):
+ df_cell[s_celltype] = 0
+
+ # each C channel - time step tensors
+ la_czyx_img = []
+ ls_channel = ls_substrate + ls_celltype
+ for s_channel in ls_channel:
+
+ # get channel dataframe
+ if s_channel in set(ls_substrate):
+ df_channel = df_conc.loc[:, ls_coor + [s_channel]]
+ elif s_channel in set(ls_celltype):
+ df_channel = df_cell.loc[:, ls_coor + [s_channel]]
+ else:
+ sys.exit(f'Error @ TimeStep.make_ome_tiff : {s_channel} unknown channel detected. not in substrate and cell type list {ls_substrate} {ls_celltype}!')
+
+ # each z axis
+ la_zyx_img = []
+ for i_zaxis in range(len(lr_axis_z)):
+ if (i_zaxis < (len(lr_axis_z) - 1)):
+ print(f'processing: {i_time} [min] {s_channel} [channel] {i_zaxis} [z_axis] ...')
+ # extract z layer
+ df_yxchannel = df_channel.loc[
+ ((df_channel.loc[:, ls_coor[2]] >= lr_axis_z[i_zaxis]) & (df_channel.loc[:, ls_coor[2]] < lr_axis_z[i_zaxis + 1])),
+ ls_coor[:2] + [s_channel]
+ ]
+
+ # drop row with na and duplicate entries
+ df_yxchannel = df_yxchannel.dropna(axis=0)
+ df_yxchannel = df_yxchannel.drop_duplicates()
+
+ # merge with coooridnates and get image
+ # bue 20240811: df_coor left side merge will cut off reset cell that are out of the xyz domain range, which is what we want.
+ df_yxchannel = pd.merge(df_coor, df_yxchannel, on=ls_coor[:2], how='left').replace({np.nan: 0})
+ try:
+ df_yxchannel = df_yxchannel.pivot(columns=ls_coor[0], index=ls_coor[1], values=s_channel)
+ except ValueError: # two cells from the same cell type very close to each other detetced.
+ if self.verbose:
+ df_duplicate = df_cell.loc[(df_yxchannel.loc[:, ['voxel_x', 'voxel_y']].duplicated()), :]
+ print(f'Warning: {s_channel} {df_duplicate} cells within 1[um] distance form each detected. cannot pivot. erase cell type from this timestep.')
+ df_yxchannel.loc[:,s_channel] = 0 # erase cells
+ df_yxchannel = df_yxchannel.drop_duplicates()
+ df_yxchannel = df_yxchannel.pivot(columns=ls_coor[0], index=ls_coor[1], values=s_channel)
+ a_yx_img = df_yxchannel.values
+
+ # grow
+ a_yx_img = imagine.grow_seed(a_yx_img, i_step=di_grow[s_channel], b_verbose=False)
+
+ # update output
+ la_zyx_img.append(a_yx_img)
+ a_zyx_img = np.array(la_zyx_img, np.float32)
+ la_czyx_img.append(np.array(a_zyx_img, np.float32))
# output
- return do_domain
+ a_czyx_img = np.array(la_czyx_img, dtype=np.float32)
+
+ # numpy array
+ if not file:
+ return a_czyx_img
+
+ # write to file
+ else:
+ if self.verbose:
+ print('a_czyx_img shape:', a_czyx_img.shape)
+ # generate filename
+ s_channel = ''
+ for s_substrate in ls_substrate:
+ try:
+ r_value = conc_cutoff[s_substrate]
+ s_channel += f'_{s_substrate}{r_value}'
+ except KeyError:
+ s_channel += f'_{s_substrate}'
+ for s_celltype in ls_celltype:
+ s_channel += f'_{s_celltype}'
+ if len(ls_celltype) > 0:
+ s_channel += f'_{cell_attribute}'
+ s_tifffile = self.xmlfile.replace('.xml', f'{s_channel}.ome.tiff')
+ s_tifffile = s_tifffile.replace(' ','_')
+ if (len(s_tifffile) > 255):
+ print(f"Warning: filename {len(s_tifffile)} > 255 character.")
+ s_tifffile = self.xmlfile.replace('.xml', f'_channels.ome.tiff')
+ print(f"file name adjusted to {s_tifffile}.")
+ s_tiffpathfile = self.path + '/' + s_tifffile
+
+ # save to file
+ OmeTiffWriter.save(
+ a_czyx_img,
+ s_tiffpathfile,
+ dim_order = 'CZYX',
+ #ome_xml=x_img,
+ channel_names = ls_channel,
+ image_names = [s_tifffile.replace('.ome.tiff','')],
+ physical_pixel_sizes = bioio_base.types.PhysicalPixelSizes(self.get_voxel_spacing()[2], 1.0, 1.0), # z,y,x [um]
+ #channel_colors=,
+ #fs_kwargs={},
+ )
+ return s_tiffpathfile
## LOAD DATA ##
diff --git a/pyproject.toml b/pyproject.toml
index dd74a72..54773a9 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -117,39 +117,42 @@ full = [
"neuroglancer",
"scikit-image>=0.24.0",
"shapely>=2.0.1", # spatialdata 0.7.3 compatible
+ "simulariumio",
"spatialdata>=0.7.3",
]
[project.scripts]
# special thanks to Miguel Ponce-de-Leon who introduced me to entry point scripts!
+# initialize
# metadata
pcdl_get_version = "pcdl.commandline:get_version"
pcdl_get_unit_dict = "pcdl.commandline:get_unit_dict"
# substrate
pcdl_get_substrate_list = "pcdl.commandline:get_substrate_list"
-pcdl_get_conc_attribute = "pcdl.commandline:get_conc_attribute"
pcdl_get_conc_df = "pcdl.commandline:get_conc_df"
+pcdl_get_conc_attribute = "pcdl.commandline:get_conc_attribute"
pcdl_plot_contour = "pcdl.commandline:plot_contour"
pcdl_make_conc_vtk = "pcdl.commandline:make_conc_vtk"
# cell agent
pcdl_get_celltype_list = "pcdl.commandline:get_celltype_list"
-pcdl_get_cell_attribute_list = "pcdl.commandline:get_cell_attribute_list"
-pcdl_get_cell_attribute = "pcdl.commandline:get_cell_attribute"
pcdl_get_cell_df = "pcdl.commandline:get_cell_df"
+pcdl_get_cell_attribute = "pcdl.commandline:get_cell_attribute"
+pcdl_get_cell_attribute_list = "pcdl.commandline:get_cell_attribute_list"
pcdl_get_anndata = "pcdl.commandline:get_anndata"
-pcdl_make_graph_gml = "pcdl.commandline:make_graph_gml"
pcdl_plot_scatter = "pcdl.commandline:plot_scatter"
pcdl_make_cell_vtk = "pcdl.commandline:make_cell_vtk"
+pcdl_make_graph_gml = "pcdl.commandline:make_graph_gml"
+pcdl_make_simularium = "pcdl.commandline:make_simularium"
# substrate and cell agent
pcdl_get_muspan = "pcdl.commandline:get_muspan"
pcdl_get_spatialdata = "pcdl.commandline:get_spatialdata"
pcdl_plot_timeseries = "pcdl.commandline:plot_timeseries"
pcdl_make_ome_tiff = "pcdl.commandline:make_ome_tiff"
-pcdl_render_neuroglancer = "pcdl.commandline:render_neuroglancer"
# making movies
pcdl_make_gif = "pcdl.commandline:make_gif"
pcdl_make_movie = "pcdl.commandline:make_movie"
+pcdl_render_neuroglancer = "pcdl.commandline:render_neuroglancer"
[project.urls]
diff --git a/test/test_commandline_2d.py b/test/test_commandline_2d.py
index 784d69e..8c95a48 100644
--- a/test/test_commandline_2d.py
+++ b/test/test_commandline_2d.py
@@ -153,63 +153,6 @@ def test_pcdl_get_substrate_list_timestep(self):
assert o_result.returncode == 0
-class TestCommandLineInterfaceConcDfAttribute(object):
- ''' tests for one pcdl command line interface function. '''
-
- # timeseries collapsed:
- # + path (str) nop
- # + verbose (true, _false_) nop
- # + values (int) ok
- # + drop (oxygen) ok
- # + keep (oxygen) ok
- # + allvalues (false _true_) ok
-
- def test_pcdl_get_conc_attribute_timeseries(self):
- o_result = subprocess.run(['pcdl_get_conc_attribute', s_path_2d], check=False, capture_output=True)
- print(f'o_result: {o_result}\n')
- print(f'o_result.returncode: {o_result.returncode}\n')
- print(f'o_result.stdout: {o_result.stdout}\n')
- print(f'o_result.stderr: {o_result.stderr}\n')
- os.remove(f'{s_path_2d}/timeseries_conc_attribute_minmax.json')
- assert o_result.returncode == 0
-
- def test_pcdl_get_conc_attribute_timeseries_value(self):
- o_result = subprocess.run(['pcdl_get_conc_attribute', s_path_2d, '2'], check=False, capture_output=True)
- print(f'o_result: {o_result}\n')
- print(f'o_result.returncode: {o_result.returncode}\n')
- print(f'o_result.stdout: {o_result.stdout}\n')
- print(f'o_result.stderr: {o_result.stderr}\n')
- os.remove(f'{s_path_2d}/timeseries_conc_attribute_minmax.json')
- assert o_result.returncode == 0
-
- def test_pcdl_get_conc_attribute_timeseries_drop(self):
- o_result = subprocess.run(['pcdl_get_conc_attribute', s_path_2d, '--drop', 'conc_type', 'oxygen'], check=False, capture_output=True)
- print(f'o_result: {o_result}\n')
- print(f'o_result.returncode: {o_result.returncode}\n')
- print(f'o_result.stdout: {o_result.stdout}\n')
- print(f'o_result.stderr: {o_result.stderr}\n')
- os.remove(f'{s_path_2d}/timeseries_conc_attribute_minmax.json')
- assert o_result.returncode == 0
-
- def test_pcdl_get_conc_attribute_timeseries_keep(self):
- o_result = subprocess.run(['pcdl_get_conc_attribute', s_path_2d, '--keep', 'conc_type', 'oxygen'], check=False, capture_output=True)
- print(f'o_result: {o_result}\n')
- print(f'o_result.returncode: {o_result.returncode}\n')
- print(f'o_result.stdout: {o_result.stdout}\n')
- print(f'o_result.stderr: {o_result.stderr}\n')
- os.remove(f'{s_path_2d}/timeseries_conc_attribute_minmax.json')
- assert o_result.returncode == 0
-
- def test_pcdl_get_conc_attribute_timeseries_allvalues(self):
- o_result = subprocess.run(['pcdl_get_conc_attribute', s_path_2d, '--allvalues', 'true'], check=False, capture_output=True)
- print(f'o_result: {o_result}\n')
- print(f'o_result.returncode: {o_result.returncode}\n')
- print(f'o_result.stdout: {o_result.stdout}\n')
- print(f'o_result.stderr: {o_result.stderr}\n')
- os.remove(f'{s_path_2d}/timeseries_conc_attribute_all.json')
- assert o_result.returncode == 0
-
-
class TestCommandLineInterfaceConcDf(object):
''' tests for one pcdl command line interface function. '''
@@ -305,6 +248,63 @@ def test_pcdl_get_conc_df_timestep_keep(self):
assert o_result.returncode == 0
+class TestCommandLineInterfaceConcDfAttribute(object):
+ ''' tests for one pcdl command line interface function. '''
+
+ # timeseries collapsed:
+ # + path (str) nop
+ # + verbose (true, _false_) nop
+ # + values (int) ok
+ # + drop (oxygen) ok
+ # + keep (oxygen) ok
+ # + allvalues (false _true_) ok
+
+ def test_pcdl_get_conc_attribute_timeseries(self):
+ o_result = subprocess.run(['pcdl_get_conc_attribute', s_path_2d], check=False, capture_output=True)
+ print(f'o_result: {o_result}\n')
+ print(f'o_result.returncode: {o_result.returncode}\n')
+ print(f'o_result.stdout: {o_result.stdout}\n')
+ print(f'o_result.stderr: {o_result.stderr}\n')
+ os.remove(f'{s_path_2d}/timeseries_conc_attribute_minmax.json')
+ assert o_result.returncode == 0
+
+ def test_pcdl_get_conc_attribute_timeseries_value(self):
+ o_result = subprocess.run(['pcdl_get_conc_attribute', s_path_2d, '2'], check=False, capture_output=True)
+ print(f'o_result: {o_result}\n')
+ print(f'o_result.returncode: {o_result.returncode}\n')
+ print(f'o_result.stdout: {o_result.stdout}\n')
+ print(f'o_result.stderr: {o_result.stderr}\n')
+ os.remove(f'{s_path_2d}/timeseries_conc_attribute_minmax.json')
+ assert o_result.returncode == 0
+
+ def test_pcdl_get_conc_attribute_timeseries_drop(self):
+ o_result = subprocess.run(['pcdl_get_conc_attribute', s_path_2d, '--drop', 'conc_type', 'oxygen'], check=False, capture_output=True)
+ print(f'o_result: {o_result}\n')
+ print(f'o_result.returncode: {o_result.returncode}\n')
+ print(f'o_result.stdout: {o_result.stdout}\n')
+ print(f'o_result.stderr: {o_result.stderr}\n')
+ os.remove(f'{s_path_2d}/timeseries_conc_attribute_minmax.json')
+ assert o_result.returncode == 0
+
+ def test_pcdl_get_conc_attribute_timeseries_keep(self):
+ o_result = subprocess.run(['pcdl_get_conc_attribute', s_path_2d, '--keep', 'conc_type', 'oxygen'], check=False, capture_output=True)
+ print(f'o_result: {o_result}\n')
+ print(f'o_result.returncode: {o_result.returncode}\n')
+ print(f'o_result.stdout: {o_result.stdout}\n')
+ print(f'o_result.stderr: {o_result.stderr}\n')
+ os.remove(f'{s_path_2d}/timeseries_conc_attribute_minmax.json')
+ assert o_result.returncode == 0
+
+ def test_pcdl_get_conc_attribute_timeseries_allvalues(self):
+ o_result = subprocess.run(['pcdl_get_conc_attribute', s_path_2d, '--allvalues', 'true'], check=False, capture_output=True)
+ print(f'o_result: {o_result}\n')
+ print(f'o_result.returncode: {o_result.returncode}\n')
+ print(f'o_result.stdout: {o_result.stdout}\n')
+ print(f'o_result.stderr: {o_result.stderr}\n')
+ os.remove(f'{s_path_2d}/timeseries_conc_attribute_all.json')
+ assert o_result.returncode == 0
+
+
class TestCommandLineInterfacePlotContour(object):
''' tests for one pcdl command line interface function. '''
@@ -473,332 +473,332 @@ def test_pcdl_get_celltype_list_timestep_settingxmlfalse(self):
assert o_result.returncode == 0
-class TestCommandLineInterfaceCellAttributeList(object):
+class TestCommandLineInterfaceCellDf(object):
''' tests for one pcdl command line interface function. '''
- # timeseries collapsed:
- # + path (str) nop
+ # timeseries
+ # + collapse (true false) ok
+
+ # timestep and timeseries:
+ # + path nop
+ # + customtype nop (because the dataframe is straightaway saved as csv)
# + microenv (true, _false_) ok
# + physiboss (true, _false_) ok
# + settingxml (string, _none_, _false_) ok
# + verbose (true, _false_) nop
+ # + values (int) ok
+ # + drop (cell_type oxygen) ok
+ # + keep (cell_type oxygen) ok
- def test_pcdl_get_cell_attribute_list_timeseries(self):
- o_result = subprocess.run(['pcdl_get_cell_attribute_list', s_path_2d], check=False, capture_output=True)
+ def test_pcdl_get_cell_df_timeseries(self):
+ o_result = subprocess.run(['pcdl_get_cell_df', s_path_2d], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
+ os.remove(f'{s_path_2d}/timeseries_cell.csv')
assert o_result.returncode == 0
- def test_pcdl_get_cell_attribute_list_timeseries_microenv(self):
- o_result = subprocess.run(['pcdl_get_cell_attribute_list', s_path_2d, '--microenv', 'false'], check=False, capture_output=True)
+ def test_pcdl_get_cell_df_timeseries_collapsed(self):
+ o_result = subprocess.run(['pcdl_get_cell_df', s_path_2d, '--collapse', 'false'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
+ for i_step in range(25):
+ os.remove(f'{s_path_2d}/output000000{str(i_step).zfill(2)}_cell.csv')
assert o_result.returncode == 0
- def test_pcdl_get_cell_attribute_list_timeseries_physiboss(self):
- o_result = subprocess.run(['pcdl_get_cell_attribute_list', s_path_2d, '--physiboss', 'false'], check=False, capture_output=True)
+ def test_pcdl_get_cell_df_timeseries_microenv(self):
+ o_result = subprocess.run(['pcdl_get_cell_df', s_path_2d, '--microenv', 'false'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
+ os.remove(f'{s_path_2d}/timeseries_cell.csv')
assert o_result.returncode == 0
- def test_pcdl_get_cell_attribute_list_timeseries_settingxmlfalse(self):
- o_result = subprocess.run(['pcdl_get_cell_attribute_list', s_path_2d, '--settingxml', 'false'], check=False, capture_output=True)
+ def test_pcdl_get_cell_df_timeseries_physiboss(self):
+ o_result = subprocess.run(['pcdl_get_cell_df', s_path_2d, '--physiboss', 'false'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
+ os.remove(f'{s_path_2d}/timeseries_cell.csv')
assert o_result.returncode == 0
- def test_pcdl_get_cell_attribute_list_timeseries_settingxmlnone(self):
- o_result = subprocess.run(['pcdl_get_cell_attribute_list', s_path_2d, '--settingxml', 'none'], check=False, capture_output=True)
+ def test_pcdl_get_cell_df_timeseries_settingxmlfalse(self):
+ o_result = subprocess.run(['pcdl_get_cell_df', s_path_2d, '--settingxml', 'false'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
+ os.remove(f'{s_path_2d}/timeseries_cell.csv')
assert o_result.returncode == 0
+ def test_pcdl_get_cell_df_timeseries_settingxmlnone(self):
+ o_result = subprocess.run(['pcdl_get_cell_df', s_path_2d, '--settingxml', 'none'], check=False, capture_output=True)
+ print(f'o_result: {o_result}\n')
+ print(f'o_result.returncode: {o_result.returncode}\n')
+ print(f'o_result.stdout: {o_result.stdout}\n')
+ print(f'o_result.stderr: {o_result.stderr}\n')
+ os.remove(f'{s_path_2d}/timeseries_cell.csv')
+ assert o_result.returncode == 0
-class TestCommandLineInterfaceCellDfAttribute(object):
- ''' tests for one pcdl command line interface function. '''
-
- # timeseries collapsed:
- # + path (str) nop
- # + customtype ([], _sample:bool_) ok
- # + microenv (true, _false_) ok
- # + physiboss (true, _false_)
- # + settingxml (string, _none_, _false_) ok
- # + verbose (true, _false_) nop
- # + values (int) ok
- # + drop (cell_type oxygen) ok
- # + keep (cell_type oxygen) ok
- # + allvalues (false _true_) ok
+ def test_pcdl_get_cell_df_timeseries_value(self):
+ o_result = subprocess.run(['pcdl_get_cell_df', s_path_2d, '2'], check=False, capture_output=True)
+ print(f'o_result: {o_result}\n')
+ print(f'o_result.returncode: {o_result.returncode}\n')
+ print(f'o_result.stdout: {o_result.stdout}\n')
+ print(f'o_result.stderr: {o_result.stderr}\n')
+ os.remove(f'{s_path_2d}/timeseries_cell.csv')
+ assert o_result.returncode == 0
- def test_pcdl_get_cell_attribute_timeseries(self):
- o_result = subprocess.run(['pcdl_get_cell_attribute', s_path_2d], check=False, capture_output=True)
+ def test_pcdl_get_cell_df_timeseries_drop(self):
+ o_result = subprocess.run(['pcdl_get_cell_df', s_path_2d, '--drop', 'cell_type', 'oxygen'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
- os.remove(f'{s_path_2d}/timeseries_cell_attribute_minmax.json')
+ os.remove(f'{s_path_2d}/timeseries_cell.csv')
assert o_result.returncode == 0
- def test_pcdl_get_cell_attribute_timeseries_customtype(self):
- o_result = subprocess.run(['pcdl_get_cell_attribute', s_path_2d, '--custom_data_type', 'sample:bool'], check=False, capture_output=True)
+ def test_pcdl_get_cell_df_timeseries_keep(self):
+ o_result = subprocess.run(['pcdl_get_cell_df', s_path_2d, '--keep', 'cell_type', 'oxygen'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
- os.remove(f'{s_path_2d}/timeseries_cell_attribute_minmax.json')
+ os.remove(f'{s_path_2d}/timeseries_cell.csv')
assert o_result.returncode == 0
- def test_pcdl_get_cell_attribute_timeseries_microenv(self):
- o_result = subprocess.run(['pcdl_get_cell_attribute', s_path_2d, '--microenv', 'false'], check=False, capture_output=True)
+ def test_pcdl_get_cell_df_timestep(self):
+ o_result = subprocess.run(['pcdl_get_cell_df', s_pathfile_2d], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
- os.remove(f'{s_path_2d}/timeseries_cell_attribute_minmax.json')
+ os.remove(f'{s_path_2d}/output00000024_cell.csv')
assert o_result.returncode == 0
- def test_pcdl_get_cell_attribute_timeseries_physiboss(self):
- o_result = subprocess.run(['pcdl_get_cell_attribute', s_path_2d, '--physiboss', 'false'], check=False, capture_output=True)
+ def test_pcdl_get_cell_df_timestep_microenv(self):
+ o_result = subprocess.run(['pcdl_get_cell_df', s_pathfile_2d, '--microenv', 'false'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
- os.remove(f'{s_path_2d}/timeseries_cell_attribute_minmax.json')
+ os.remove(f'{s_path_2d}/output00000024_cell.csv')
assert o_result.returncode == 0
- def test_pcdl_get_cell_attribute_timeseries_settingxmlfalse(self):
- o_result = subprocess.run(['pcdl_get_cell_attribute', s_path_2d, '--settingxml', 'false'], check=False, capture_output=True)
+ def test_pcdl_get_cell_df_timestep_physiboss(self):
+ o_result = subprocess.run(['pcdl_get_cell_df', s_pathfile_2d, '--physiboss', 'false'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
- os.remove(f'{s_path_2d}/timeseries_cell_attribute_minmax.json')
+ os.remove(f'{s_path_2d}/output00000024_cell.csv')
assert o_result.returncode == 0
- def test_pcdl_get_cell_attribute_timeseries_settingxmlnone(self):
- o_result = subprocess.run(['pcdl_get_cell_attribute', s_path_2d, '--settingxml', 'none'], check=False, capture_output=True)
+ def test_pcdl_get_cell_df_timestep_settingxmlfalse(self):
+ o_result = subprocess.run(['pcdl_get_cell_df', s_pathfile_2d, '--settingxml', 'false'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
- os.remove(f'{s_path_2d}/timeseries_cell_attribute_minmax.json')
+ os.remove(f'{s_path_2d}/output00000024_cell.csv')
assert o_result.returncode == 0
- def test_pcdl_get_cell_attribute_timeseries_value(self):
- o_result = subprocess.run(['pcdl_get_cell_attribute', s_path_2d, '2'], check=False, capture_output=True)
+ def test_pcdl_get_cell_df_timestep_settingxmlnone(self):
+ o_result = subprocess.run(['pcdl_get_cell_df', s_pathfile_2d, '--settingxml', 'none'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
- os.remove(f'{s_path_2d}/timeseries_cell_attribute_minmax.json')
+ os.remove(f'{s_path_2d}/output00000024_cell.csv')
assert o_result.returncode == 0
- def test_pcdl_get_cell_attribute_timeseries_drop(self):
- o_result = subprocess.run(['pcdl_get_cell_attribute', s_path_2d, '--drop', 'cell_type', 'oxygen'], check=False, capture_output=True)
+ def test_pcdl_get_cell_df_timestep_value(self):
+ o_result = subprocess.run(['pcdl_get_cell_df', s_pathfile_2d, '2'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
- os.remove(f'{s_path_2d}/timeseries_cell_attribute_minmax.json')
+ os.remove(f'{s_path_2d}/output00000024_cell.csv')
assert o_result.returncode == 0
- def test_pcdl_get_cell_attribute_timeseries_keep(self):
- o_result = subprocess.run(['pcdl_get_cell_attribute', s_path_2d, '--keep', 'cell_type', 'oxygen'], check=False, capture_output=True)
+ def test_pcdl_get_cell_df_timestep_drop(self):
+ o_result = subprocess.run(['pcdl_get_cell_df', s_pathfile_2d, '--drop', 'cell_type', 'oxygen'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
- os.remove(f'{s_path_2d}/timeseries_cell_attribute_minmax.json')
+ os.remove(f'{s_path_2d}/output00000024_cell.csv')
assert o_result.returncode == 0
- def test_pcdl_get_cell_attribute_timeseries_allvalues(self):
- o_result = subprocess.run(['pcdl_get_cell_attribute', s_path_2d, '--allvalues', 'true'], check=False, capture_output=True)
+ def test_pcdl_get_cell_df_timestep_keep(self):
+ o_result = subprocess.run(['pcdl_get_cell_df', s_pathfile_2d, '--keep', 'cell_type', 'oxygen'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
- os.remove(f'{s_path_2d}/timeseries_cell_attribute_all.json')
+ os.remove(f'{s_path_2d}/output00000024_cell.csv')
assert o_result.returncode == 0
-class TestCommandLineInterfaceCellDf(object):
+class TestCommandLineInterfaceCellDfAttribute(object):
''' tests for one pcdl command line interface function. '''
- # timeseries
- # + collapse (true false) ok
-
- # timestep and timeseries:
- # + path nop
- # + customtype nop (because the dataframe is straightaway saved as csv)
+ # timeseries collapsed:
+ # + path (str) nop
+ # + customtype ([], _sample:bool_) ok
# + microenv (true, _false_) ok
- # + physiboss (true, _false_) ok
+ # + physiboss (true, _false_)
# + settingxml (string, _none_, _false_) ok
# + verbose (true, _false_) nop
# + values (int) ok
# + drop (cell_type oxygen) ok
# + keep (cell_type oxygen) ok
+ # + allvalues (false _true_) ok
- def test_pcdl_get_cell_df_timeseries(self):
- o_result = subprocess.run(['pcdl_get_cell_df', s_path_2d], check=False, capture_output=True)
+ def test_pcdl_get_cell_attribute_timeseries(self):
+ o_result = subprocess.run(['pcdl_get_cell_attribute', s_path_2d], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
- os.remove(f'{s_path_2d}/timeseries_cell.csv')
+ os.remove(f'{s_path_2d}/timeseries_cell_attribute_minmax.json')
assert o_result.returncode == 0
- def test_pcdl_get_cell_df_timeseries_collapsed(self):
- o_result = subprocess.run(['pcdl_get_cell_df', s_path_2d, '--collapse', 'false'], check=False, capture_output=True)
+ def test_pcdl_get_cell_attribute_timeseries_customtype(self):
+ o_result = subprocess.run(['pcdl_get_cell_attribute', s_path_2d, '--custom_data_type', 'sample:bool'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
- for i_step in range(25):
- os.remove(f'{s_path_2d}/output000000{str(i_step).zfill(2)}_cell.csv')
+ os.remove(f'{s_path_2d}/timeseries_cell_attribute_minmax.json')
assert o_result.returncode == 0
- def test_pcdl_get_cell_df_timeseries_microenv(self):
- o_result = subprocess.run(['pcdl_get_cell_df', s_path_2d, '--microenv', 'false'], check=False, capture_output=True)
+ def test_pcdl_get_cell_attribute_timeseries_microenv(self):
+ o_result = subprocess.run(['pcdl_get_cell_attribute', s_path_2d, '--microenv', 'false'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
- os.remove(f'{s_path_2d}/timeseries_cell.csv')
+ os.remove(f'{s_path_2d}/timeseries_cell_attribute_minmax.json')
assert o_result.returncode == 0
- def test_pcdl_get_cell_df_timeseries_physiboss(self):
- o_result = subprocess.run(['pcdl_get_cell_df', s_path_2d, '--physiboss', 'false'], check=False, capture_output=True)
+ def test_pcdl_get_cell_attribute_timeseries_physiboss(self):
+ o_result = subprocess.run(['pcdl_get_cell_attribute', s_path_2d, '--physiboss', 'false'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
- os.remove(f'{s_path_2d}/timeseries_cell.csv')
+ os.remove(f'{s_path_2d}/timeseries_cell_attribute_minmax.json')
assert o_result.returncode == 0
- def test_pcdl_get_cell_df_timeseries_settingxmlfalse(self):
- o_result = subprocess.run(['pcdl_get_cell_df', s_path_2d, '--settingxml', 'false'], check=False, capture_output=True)
+ def test_pcdl_get_cell_attribute_timeseries_settingxmlfalse(self):
+ o_result = subprocess.run(['pcdl_get_cell_attribute', s_path_2d, '--settingxml', 'false'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
- os.remove(f'{s_path_2d}/timeseries_cell.csv')
+ os.remove(f'{s_path_2d}/timeseries_cell_attribute_minmax.json')
assert o_result.returncode == 0
- def test_pcdl_get_cell_df_timeseries_settingxmlnone(self):
- o_result = subprocess.run(['pcdl_get_cell_df', s_path_2d, '--settingxml', 'none'], check=False, capture_output=True)
+ def test_pcdl_get_cell_attribute_timeseries_settingxmlnone(self):
+ o_result = subprocess.run(['pcdl_get_cell_attribute', s_path_2d, '--settingxml', 'none'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
- os.remove(f'{s_path_2d}/timeseries_cell.csv')
+ os.remove(f'{s_path_2d}/timeseries_cell_attribute_minmax.json')
assert o_result.returncode == 0
- def test_pcdl_get_cell_df_timeseries_value(self):
- o_result = subprocess.run(['pcdl_get_cell_df', s_path_2d, '2'], check=False, capture_output=True)
+ def test_pcdl_get_cell_attribute_timeseries_value(self):
+ o_result = subprocess.run(['pcdl_get_cell_attribute', s_path_2d, '2'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
- os.remove(f'{s_path_2d}/timeseries_cell.csv')
+ os.remove(f'{s_path_2d}/timeseries_cell_attribute_minmax.json')
assert o_result.returncode == 0
- def test_pcdl_get_cell_df_timeseries_drop(self):
- o_result = subprocess.run(['pcdl_get_cell_df', s_path_2d, '--drop', 'cell_type', 'oxygen'], check=False, capture_output=True)
+ def test_pcdl_get_cell_attribute_timeseries_drop(self):
+ o_result = subprocess.run(['pcdl_get_cell_attribute', s_path_2d, '--drop', 'cell_type', 'oxygen'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
- os.remove(f'{s_path_2d}/timeseries_cell.csv')
+ os.remove(f'{s_path_2d}/timeseries_cell_attribute_minmax.json')
assert o_result.returncode == 0
- def test_pcdl_get_cell_df_timeseries_keep(self):
- o_result = subprocess.run(['pcdl_get_cell_df', s_path_2d, '--keep', 'cell_type', 'oxygen'], check=False, capture_output=True)
+ def test_pcdl_get_cell_attribute_timeseries_keep(self):
+ o_result = subprocess.run(['pcdl_get_cell_attribute', s_path_2d, '--keep', 'cell_type', 'oxygen'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
- os.remove(f'{s_path_2d}/timeseries_cell.csv')
+ os.remove(f'{s_path_2d}/timeseries_cell_attribute_minmax.json')
assert o_result.returncode == 0
- def test_pcdl_get_cell_df_timestep(self):
- o_result = subprocess.run(['pcdl_get_cell_df', s_pathfile_2d], check=False, capture_output=True)
+ def test_pcdl_get_cell_attribute_timeseries_allvalues(self):
+ o_result = subprocess.run(['pcdl_get_cell_attribute', s_path_2d, '--allvalues', 'true'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
- os.remove(f'{s_path_2d}/output00000024_cell.csv')
+ os.remove(f'{s_path_2d}/timeseries_cell_attribute_all.json')
assert o_result.returncode == 0
- def test_pcdl_get_cell_df_timestep_microenv(self):
- o_result = subprocess.run(['pcdl_get_cell_df', s_pathfile_2d, '--microenv', 'false'], check=False, capture_output=True)
- print(f'o_result: {o_result}\n')
- print(f'o_result.returncode: {o_result.returncode}\n')
- print(f'o_result.stdout: {o_result.stdout}\n')
- print(f'o_result.stderr: {o_result.stderr}\n')
- os.remove(f'{s_path_2d}/output00000024_cell.csv')
- assert o_result.returncode == 0
- def test_pcdl_get_cell_df_timestep_physiboss(self):
- o_result = subprocess.run(['pcdl_get_cell_df', s_pathfile_2d, '--physiboss', 'false'], check=False, capture_output=True)
- print(f'o_result: {o_result}\n')
- print(f'o_result.returncode: {o_result.returncode}\n')
- print(f'o_result.stdout: {o_result.stdout}\n')
- print(f'o_result.stderr: {o_result.stderr}\n')
- os.remove(f'{s_path_2d}/output00000024_cell.csv')
- assert o_result.returncode == 0
+class TestCommandLineInterfaceCellAttributeList(object):
+ ''' tests for one pcdl command line interface function. '''
- def test_pcdl_get_cell_df_timestep_settingxmlfalse(self):
- o_result = subprocess.run(['pcdl_get_cell_df', s_pathfile_2d, '--settingxml', 'false'], check=False, capture_output=True)
+ # timeseries collapsed:
+ # + path (str) nop
+ # + microenv (true, _false_) ok
+ # + physiboss (true, _false_) ok
+ # + settingxml (string, _none_, _false_) ok
+ # + verbose (true, _false_) nop
+
+ def test_pcdl_get_cell_attribute_list_timeseries(self):
+ o_result = subprocess.run(['pcdl_get_cell_attribute_list', s_path_2d], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
- os.remove(f'{s_path_2d}/output00000024_cell.csv')
assert o_result.returncode == 0
- def test_pcdl_get_cell_df_timestep_settingxmlnone(self):
- o_result = subprocess.run(['pcdl_get_cell_df', s_pathfile_2d, '--settingxml', 'none'], check=False, capture_output=True)
+ def test_pcdl_get_cell_attribute_list_timeseries_microenv(self):
+ o_result = subprocess.run(['pcdl_get_cell_attribute_list', s_path_2d, '--microenv', 'false'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
- os.remove(f'{s_path_2d}/output00000024_cell.csv')
assert o_result.returncode == 0
- def test_pcdl_get_cell_df_timestep_value(self):
- o_result = subprocess.run(['pcdl_get_cell_df', s_pathfile_2d, '2'], check=False, capture_output=True)
+ def test_pcdl_get_cell_attribute_list_timeseries_physiboss(self):
+ o_result = subprocess.run(['pcdl_get_cell_attribute_list', s_path_2d, '--physiboss', 'false'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
- os.remove(f'{s_path_2d}/output00000024_cell.csv')
assert o_result.returncode == 0
- def test_pcdl_get_cell_df_timestep_drop(self):
- o_result = subprocess.run(['pcdl_get_cell_df', s_pathfile_2d, '--drop', 'cell_type', 'oxygen'], check=False, capture_output=True)
+ def test_pcdl_get_cell_attribute_list_timeseries_settingxmlfalse(self):
+ o_result = subprocess.run(['pcdl_get_cell_attribute_list', s_path_2d, '--settingxml', 'false'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
- os.remove(f'{s_path_2d}/output00000024_cell.csv')
assert o_result.returncode == 0
- def test_pcdl_get_cell_df_timestep_keep(self):
- o_result = subprocess.run(['pcdl_get_cell_df', s_pathfile_2d, '--keep', 'cell_type', 'oxygen'], check=False, capture_output=True)
+ def test_pcdl_get_cell_attribute_list_timeseries_settingxmlnone(self):
+ o_result = subprocess.run(['pcdl_get_cell_attribute_list', s_path_2d, '--settingxml', 'none'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
- os.remove(f'{s_path_2d}/output00000024_cell.csv')
assert o_result.returncode == 0
@@ -1033,444 +1033,513 @@ def test_pcdl_get_anndata_timestep_scale(self):
assert o_result.returncode == 0
-class TestCommandLineInterfaceGraphGml(object):
+class TestCommandLineInterfacePlotScatter(object):
''' tests for one pcdl command line interface function. '''
- # timestep and timeseries:
+ # time series and time steps.
# + path nop
# + customtype ([], _sample:bool_) ok
- # + microenv (true, false) ok
+ # + microenv (true, _false_) ok
# + physiboss (true, _false_) ok
- # + settingxml (string, _none_, _false_) ok
+ # + settingxml (PhysiCell_settings.xml, _false_) ok
# + verbose (true, _false_) nop
- # + graph_type (neighbor, _attached_) ok
- # + edge_attribute (true, _false_) ok
- # + node_attribute (cell_type oxygen) ok
+ # + focus (_oxygen_) ok
+ # + z_slize (0.0, _1.1_) ok
+ # + z_axis (none, _0.0_40.0_) ok
+ # + alpha (1.0, _0.5_) ok
+ # + cmap (viridis, _magma_) ok
+ # + title (, _abc_) ok
+ # + grid (true, _false_) ok
+ # + legend_loc ('lower left', _'upper right'_) ok
+ # + xlim (none, _-40_400_) ok
+ # + ylim (none, _-30_300_) ok
+ # + xyequal (true, _false_) ok
+ # + s ('none', '74') ok
+ # + figsizepx (none, _[641, 481]_) ok
+ # + ext (jpeg, _tiff_) ok
+ # + figbgcolor (none, _yellow_) ok
- def test_pcdl_make_graph_gml_timeseries_default(self):
- o_result = subprocess.run(['pcdl_make_graph_gml', s_path_2d, 'neighbor'], check=False, capture_output=True)
+ def test_pcdl_plot_scatter_default(self):
+ o_result = subprocess.run([
+ 'pcdl_plot_scatter', s_pathfile_2d,
+ ], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
- for i_step in range(25):
- os.remove(f'{s_path_2d}/output000000{str(i_step).zfill(2)}_neighbor.gml')
+ shutil.rmtree(f'{s_path_2d}/cell_cell_type_z0.0/')
assert o_result.returncode == 0
- def test_pcdl_make_graph_gml_timeseries_customtype_nodeattribute_one(self):
- o_result = subprocess.run(['pcdl_make_graph_gml', s_path_2d, 'neighbor', '--custom_data_type', 'sample:bool', '--node_attribute', 'sample'], check=False, capture_output=True)
+ def test_pcdl_plot_scatter_set(self):
+ o_result = subprocess.run([
+ 'pcdl_plot_scatter', s_pathfile_2d, 'oxygen',
+ '--custom_data_type', 'sample:bool',
+ '--microenv', 'True',
+ '--physiboss', 'false',
+ '--settingxml', 'false',
+ '--cat_drop', '',
+ '--cat_keep', '',
+ '--z_slice', '1.1',
+ '--z_axis', '0.0', '40.0',
+ '--alpha', '0.5',
+ '--cmap', 'magma',
+ '--title', 'abc',
+ '--grid', 'false',
+ '--legend_loc', 'upper right',
+ '--xlim', '-40', '400',
+ '--ylim', '-30', '300',
+ '--xyequal', 'false',
+ '--s', '74',
+ '--figsizepx', '842', '531',
+ '--directory', f'{s_path_2d}/jakku',
+ '--ext', 'tiff',
+ '--figbgcolor', 'yellow',
+ ], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
- for i_step in range(25):
- os.remove(f'{s_path_2d}/output000000{str(i_step).zfill(2)}_neighbor.gml')
+ shutil.rmtree(f'{s_path_2d}/jakku/')
assert o_result.returncode == 0
- def test_pcdl_make_graph_gml_timeseries_microenv(self):
- o_result = subprocess.run(['pcdl_make_graph_gml', s_path_2d, 'neighbor', '--microenv', 'false'], check=False, capture_output=True)
+
+class TestCommandLineInterfaceCellVtk(object):
+ ''' tests for one pcdl command line interface function. '''
+
+ # timestep and timeseries:
+ # + path nop
+ # + customtype ([], _sample:bool_) ok
+ # + microenv (true, _false) ok
+ # + physiboss (true, _false_) ok
+ # + settingxml (string, _none_, _false_) ok
+ # + verbose (true, _false_) nop
+ # + attribute (cell_type oxygen, _empty_) ok
+ # + ext (_cell.vtp, _.vtp_) ok
+
+ def test_pcdl_make_cell_vtk_timeseries_default(self):
+ o_result = subprocess.run(['pcdl_make_cell_vtk', s_path_2d], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
for i_step in range(25):
- os.remove(f'{s_path_2d}/output000000{str(i_step).zfill(2)}_neighbor.gml')
+ os.remove(f'{s_path_2d}/output000000{str(i_step).zfill(2)}_cell.vtp')
assert o_result.returncode == 0
- def test_pcdl_make_graph_gml_timeseries_physiboss(self):
- o_result = subprocess.run(['pcdl_make_graph_gml', s_path_2d, 'neighbor', '--physiboss', 'false'], check=False, capture_output=True)
+ def test_pcdl_make_cell_vtk_timeseries_customtype_attribute_one(self):
+ o_result = subprocess.run(['pcdl_make_cell_vtk', s_path_2d, 'sample', '--custom_data_type', 'sample:bool'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
for i_step in range(25):
- os.remove(f'{s_path_2d}/output000000{str(i_step).zfill(2)}_neighbor.gml')
+ os.remove(f'{s_path_2d}/output000000{str(i_step).zfill(2)}_cell.vtp')
assert o_result.returncode == 0
- def test_pcdl_make_graph_gml_timeseries_settingxmlfalse_nodeattribute_one(self):
- o_result = subprocess.run(['pcdl_make_graph_gml', s_path_2d, 'neighbor', '--settingxml', 'false', '--node_attribute', 'default_fusion_rates'], check=False, capture_output=True)
+ def test_pcdl_make_cell_vtk_timeseries_microenv(self):
+ o_result = subprocess.run(['pcdl_make_cell_vtk', s_path_2d, '--microenv', 'false'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
for i_step in range(25):
- os.remove(f'{s_path_2d}/output000000{str(i_step).zfill(2)}_neighbor.gml')
+ os.remove(f'{s_path_2d}/output000000{str(i_step).zfill(2)}_cell.vtp')
assert o_result.returncode == 0
- def test_pcdl_make_graph_gml_timeseries_settingxmlnone_nodeattribute_one(self):
- o_result = subprocess.run(['pcdl_make_graph_gml', s_path_2d, 'neighbor', '--settingxml', 'none', '--node_attribute', 'default_fusion_rates'], check=False, capture_output=True)
+ def test_pcdl_make_cell_vtk_timeseries_physiboss(self):
+ o_result = subprocess.run(['pcdl_make_cell_vtk', s_path_2d, '--physiboss', 'false'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
for i_step in range(25):
- os.remove(f'{s_path_2d}/output000000{str(i_step).zfill(2)}_neighbor.gml')
+ os.remove(f'{s_path_2d}/output000000{str(i_step).zfill(2)}_cell.vtp')
assert o_result.returncode == 0
- def test_pcdl_make_graph_gml_timeseries_graph_type(self):
- o_result = subprocess.run(['pcdl_make_graph_gml', s_path_2d, 'attached'], check=False, capture_output=True)
+ def test_pcdl_make_cell_vtk_timeseries_settingxmlfalse_attribute_one(self):
+ o_result = subprocess.run(['pcdl_make_cell_vtk', s_path_2d, 'default_fusion_rates', '--settingxml', 'false'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
for i_step in range(25):
- os.remove(f'{s_path_2d}/output000000{str(i_step).zfill(2)}_attached.gml')
+ os.remove(f'{s_path_2d}/output000000{str(i_step).zfill(2)}_cell.vtp')
assert o_result.returncode == 0
- def test_pcdl_make_graph_gml_timeseries_edge_attribute(self):
- o_result = subprocess.run(['pcdl_make_graph_gml', s_path_2d, 'neighbor', '--edge_attribute', 'false'], check=False, capture_output=True)
+ def test_pcdl_make_cell_vtk_timeseries_settingxmlnone_attribute_one(self):
+ o_result = subprocess.run(['pcdl_make_cell_vtk', s_path_2d, 'default_fusion_rates', '--settingxml', 'none'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
for i_step in range(25):
- os.remove(f'{s_path_2d}/output000000{str(i_step).zfill(2)}_neighbor.gml')
+ os.remove(f'{s_path_2d}/output000000{str(i_step).zfill(2)}_cell.vtp')
assert o_result.returncode == 0
- def test_pcdl_make_graph_gml_timeseries_nodeattribute_one(self):
- o_result = subprocess.run(['pcdl_make_graph_gml', s_path_2d, 'neighbor', '--node_attribute', 'cell_type'], check=False, capture_output=True)
+ def test_pcdl_make_cell_vtk_timeseries_attribute_many(self):
+ o_result = subprocess.run(['pcdl_make_cell_vtk', s_path_2d, 'cell_type', 'oxygen'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
for i_step in range(25):
- os.remove(f'{s_path_2d}/output000000{str(i_step).zfill(2)}_neighbor.gml')
+ os.remove(f'{s_path_2d}/output000000{str(i_step).zfill(2)}_cell.vtp')
assert o_result.returncode == 0
- def test_pcdl_make_graph_gml_timeseries_nodeattribute_many(self):
- o_result = subprocess.run(['pcdl_make_graph_gml', s_path_2d, 'neighbor', '--node_attribute', 'cell_type', 'oxygen'], check=False, capture_output=True)
+ def test_pcdl_make_cell_vtk_timeseries_ext(self):
+ o_result = subprocess.run(['pcdl_make_cell_vtk', s_path_2d, '--ext', '.vtp'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
for i_step in range(25):
- os.remove(f'{s_path_2d}/output000000{str(i_step).zfill(2)}_neighbor.gml')
+ os.remove(f'{s_path_2d}/output000000{str(i_step).zfill(2)}.vtp')
assert o_result.returncode == 0
- def test_pcdl_make_graph_gml_timestep_default(self):
- o_result = subprocess.run(['pcdl_make_graph_gml', s_pathfile_2d, 'neighbor'], check=False, capture_output=True)
+ def test_pcdl_make_cell_vtk_timestep_default(self):
+ o_result = subprocess.run(['pcdl_make_cell_vtk', s_pathfile_2d], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
- os.remove(f'{s_path_2d}/output00000024_neighbor.gml')
+ os.remove(f'{s_path_2d}/output00000024_cell.vtp')
assert o_result.returncode == 0
- def test_pcdl_make_graph_gml_timestep_customtype_nodeattribute_one(self):
- o_result = subprocess.run(['pcdl_make_graph_gml', s_pathfile_2d, 'neighbor', '--custom_data_type', 'sample:bool', '--node_attribute', 'sample'], check=False, capture_output=True)
+ def test_pcdl_make_cell_vtk_timestep_customtype_attribute_one(self):
+ o_result = subprocess.run(['pcdl_make_cell_vtk', s_pathfile_2d, 'sample', '--custom_data_type', 'sample:bool'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
- os.remove(f'{s_path_2d}/output00000024_neighbor.gml')
+ os.remove(f'{s_path_2d}/output00000024_cell.vtp')
assert o_result.returncode == 0
- def test_pcdl_make_graph_gml_timestep_microenv(self):
- o_result = subprocess.run(['pcdl_make_graph_gml', s_pathfile_2d, 'neighbor', '--microenv', 'false'], check=False, capture_output=True)
+ def test_pcdl_make_cell_vtk_timestep_microenv(self):
+ o_result = subprocess.run(['pcdl_make_cell_vtk', s_pathfile_2d, '--microenv', 'false'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
- os.remove(f'{s_path_2d}/output00000024_neighbor.gml')
+ os.remove(f'{s_path_2d}/output00000024_cell.vtp')
assert o_result.returncode == 0
- def test_pcdl_make_graph_gml_timestep_physiboss(self):
- o_result = subprocess.run(['pcdl_make_graph_gml', s_pathfile_2d, 'neighbor', '--physiboss', 'false'], check=False, capture_output=True)
+ def test_pcdl_make_cell_vtk_timestep_physiboss(self):
+ o_result = subprocess.run(['pcdl_make_cell_vtk', s_pathfile_2d, '--physiboss', 'false'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
- os.remove(f'{s_path_2d}/output00000024_neighbor.gml')
+ os.remove(f'{s_path_2d}/output00000024_cell.vtp')
assert o_result.returncode == 0
- def test_pcdl_make_graph_gml_timestep_settingxmlfalse_nodeattribute_one(self):
- o_result = subprocess.run(['pcdl_make_graph_gml', s_pathfile_2d, 'neighbor', '--settingxml', 'false', '--node_attribute', 'default_fusion_rates'], check=False, capture_output=True)
+ def test_pcdl_make_cell_vtk_timestep_settingxmlfalse_attribute_one(self):
+ o_result = subprocess.run(['pcdl_make_cell_vtk', s_pathfile_2d, 'default_fusion_rates', '--settingxml', 'false'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
- os.remove(f'{s_path_2d}/output00000024_neighbor.gml')
+ os.remove(f'{s_path_2d}/output00000024_cell.vtp')
assert o_result.returncode == 0
- def test_pcdl_make_graph_gml_timestep_settingxmlnone_nodeattribute_one(self):
- o_result = subprocess.run(['pcdl_make_graph_gml', s_pathfile_2d, 'neighbor', '--settingxml', 'none', '--node_attribute', 'default_fusion_rates'], check=False, capture_output=True)
+ def test_pcdl_make_cell_vtk_timestep_settingxmlnone_attribute_one(self):
+ o_result = subprocess.run(['pcdl_make_cell_vtk', s_pathfile_2d, 'default_fusion_rates', '--settingxml', 'none'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
- os.remove(f'{s_path_2d}/output00000024_neighbor.gml')
+ os.remove(f'{s_path_2d}/output00000024_cell.vtp')
assert o_result.returncode == 0
- def test_pcdl_make_graph_gml_timestep_graph_type(self):
- o_result = subprocess.run(['pcdl_make_graph_gml', s_pathfile_2d, 'attached'], check=False, capture_output=True)
+ def test_pcdl_make_cell_vtk_timestep_attribute_many(self):
+ o_result = subprocess.run(['pcdl_make_cell_vtk', s_pathfile_2d, 'cell_type', 'oxygen'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
- os.remove(f'{s_path_2d}/output00000024_attached.gml')
+ os.remove(f'{s_path_2d}/output00000024_cell.vtp')
assert o_result.returncode == 0
- def test_pcdl_make_graph_gml_timestep_edge_attribute(self):
- o_result = subprocess.run(['pcdl_make_graph_gml', s_pathfile_2d, 'neighbor', '--edge_attribute', 'false'], check=False, capture_output=True)
+ def test_pcdl_make_cell_vtk_timestep_ext(self):
+ o_result = subprocess.run(['pcdl_make_cell_vtk', s_pathfile_2d, '--ext', '.vtp'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
- os.remove(f'{s_path_2d}/output00000024_neighbor.gml')
+ os.remove(f'{s_path_2d}/output00000024.vtp')
assert o_result.returncode == 0
- def test_pcdl_make_graph_gml_timestep_node_attribute_one(self):
- o_result = subprocess.run(['pcdl_make_graph_gml', s_pathfile_2d, 'neighbor', '--node_attribute', 'cell_type'], check=False, capture_output=True)
+
+class TestCommandLineInterfaceGraphGml(object):
+ ''' tests for one pcdl command line interface function. '''
+
+ # timestep and timeseries:
+ # + path nop
+ # + customtype ([], _sample:bool_) ok
+ # + microenv (true, false) ok
+ # + physiboss (true, _false_) ok
+ # + settingxml (string, _none_, _false_) ok
+ # + verbose (true, _false_) nop
+ # + graph_type (neighbor, _attached_) ok
+ # + edge_attribute (true, _false_) ok
+ # + node_attribute (cell_type oxygen) ok
+
+ def test_pcdl_make_graph_gml_timeseries_default(self):
+ o_result = subprocess.run(['pcdl_make_graph_gml', s_path_2d, 'neighbor'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
- os.remove(f'{s_path_2d}/output00000024_neighbor.gml')
+ for i_step in range(25):
+ os.remove(f'{s_path_2d}/output000000{str(i_step).zfill(2)}_neighbor.gml')
assert o_result.returncode == 0
- def test_pcdl_make_graph_gml_timestep_node_attribute_many(self):
- o_result = subprocess.run(['pcdl_make_graph_gml', s_pathfile_2d, 'neighbor', '--node_attribute', 'cell_type', 'oxygen'], check=False, capture_output=True)
+ def test_pcdl_make_graph_gml_timeseries_customtype_nodeattribute_one(self):
+ o_result = subprocess.run(['pcdl_make_graph_gml', s_path_2d, 'neighbor', '--custom_data_type', 'sample:bool', '--node_attribute', 'sample'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
- os.remove(f'{s_path_2d}/output00000024_neighbor.gml')
+ for i_step in range(25):
+ os.remove(f'{s_path_2d}/output000000{str(i_step).zfill(2)}_neighbor.gml')
assert o_result.returncode == 0
-
-class TestCommandLineInterfacePlotScatter(object):
- ''' tests for one pcdl command line interface function. '''
-
- # time series and time steps.
- # + path nop
- # + customtype ([], _sample:bool_) ok
- # + microenv (true, _false_) ok
- # + physiboss (true, _false_) ok
- # + settingxml (PhysiCell_settings.xml, _false_) ok
- # + verbose (true, _false_) nop
- # + focus (_oxygen_) ok
- # + z_slize (0.0, _1.1_) ok
- # + z_axis (none, _0.0_40.0_) ok
- # + alpha (1.0, _0.5_) ok
- # + cmap (viridis, _magma_) ok
- # + title (, _abc_) ok
- # + grid (true, _false_) ok
- # + legend_loc ('lower left', _'upper right'_) ok
- # + xlim (none, _-40_400_) ok
- # + ylim (none, _-30_300_) ok
- # + xyequal (true, _false_) ok
- # + s ('none', '74') ok
- # + figsizepx (none, _[641, 481]_) ok
- # + ext (jpeg, _tiff_) ok
- # + figbgcolor (none, _yellow_) ok
-
- def test_pcdl_plot_scatter_default(self):
- o_result = subprocess.run([
- 'pcdl_plot_scatter', s_pathfile_2d,
- ], check=False, capture_output=True)
+ def test_pcdl_make_graph_gml_timeseries_microenv(self):
+ o_result = subprocess.run(['pcdl_make_graph_gml', s_path_2d, 'neighbor', '--microenv', 'false'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
- shutil.rmtree(f'{s_path_2d}/cell_cell_type_z0.0/')
+ for i_step in range(25):
+ os.remove(f'{s_path_2d}/output000000{str(i_step).zfill(2)}_neighbor.gml')
assert o_result.returncode == 0
- def test_pcdl_plot_scatter_set(self):
- o_result = subprocess.run([
- 'pcdl_plot_scatter', s_pathfile_2d, 'oxygen',
- '--custom_data_type', 'sample:bool',
- '--microenv', 'True',
- '--physiboss', 'false',
- '--settingxml', 'false',
- '--cat_drop', '',
- '--cat_keep', '',
- '--z_slice', '1.1',
- '--z_axis', '0.0', '40.0',
- '--alpha', '0.5',
- '--cmap', 'magma',
- '--title', 'abc',
- '--grid', 'false',
- '--legend_loc', 'upper right',
- '--xlim', '-40', '400',
- '--ylim', '-30', '300',
- '--xyequal', 'false',
- '--s', '74',
- '--figsizepx', '842', '531',
- '--directory', f'{s_path_2d}/jakku',
- '--ext', 'tiff',
- '--figbgcolor', 'yellow',
- ], check=False, capture_output=True)
+ def test_pcdl_make_graph_gml_timeseries_physiboss(self):
+ o_result = subprocess.run(['pcdl_make_graph_gml', s_path_2d, 'neighbor', '--physiboss', 'false'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
- shutil.rmtree(f'{s_path_2d}/jakku/')
+ for i_step in range(25):
+ os.remove(f'{s_path_2d}/output000000{str(i_step).zfill(2)}_neighbor.gml')
assert o_result.returncode == 0
-
-class TestCommandLineInterfaceCellVtk(object):
- ''' tests for one pcdl command line interface function. '''
-
- # timestep and timeseries:
- # + path nop
- # + customtype ([], _sample:bool_) ok
- # + microenv (true, _false) ok
- # + physiboss (true, _false_) ok
- # + settingxml (string, _none_, _false_) ok
- # + verbose (true, _false_) nop
- # + attribute (cell_type oxygen, _empty_) ok
- # + ext (_cell.vtp, _.vtp_) ok
-
- def test_pcdl_make_cell_vtk_timeseries_default(self):
- o_result = subprocess.run(['pcdl_make_cell_vtk', s_path_2d], check=False, capture_output=True)
+ def test_pcdl_make_graph_gml_timeseries_settingxmlfalse_nodeattribute_one(self):
+ o_result = subprocess.run(['pcdl_make_graph_gml', s_path_2d, 'neighbor', '--settingxml', 'false', '--node_attribute', 'default_fusion_rates'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
for i_step in range(25):
- os.remove(f'{s_path_2d}/output000000{str(i_step).zfill(2)}_cell.vtp')
+ os.remove(f'{s_path_2d}/output000000{str(i_step).zfill(2)}_neighbor.gml')
assert o_result.returncode == 0
- def test_pcdl_make_cell_vtk_timeseries_customtype_attribute_one(self):
- o_result = subprocess.run(['pcdl_make_cell_vtk', s_path_2d, 'sample', '--custom_data_type', 'sample:bool'], check=False, capture_output=True)
+ def test_pcdl_make_graph_gml_timeseries_settingxmlnone_nodeattribute_one(self):
+ o_result = subprocess.run(['pcdl_make_graph_gml', s_path_2d, 'neighbor', '--settingxml', 'none', '--node_attribute', 'default_fusion_rates'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
for i_step in range(25):
- os.remove(f'{s_path_2d}/output000000{str(i_step).zfill(2)}_cell.vtp')
+ os.remove(f'{s_path_2d}/output000000{str(i_step).zfill(2)}_neighbor.gml')
assert o_result.returncode == 0
- def test_pcdl_make_cell_vtk_timeseries_microenv(self):
- o_result = subprocess.run(['pcdl_make_cell_vtk', s_path_2d, '--microenv', 'false'], check=False, capture_output=True)
+ def test_pcdl_make_graph_gml_timeseries_graph_type(self):
+ o_result = subprocess.run(['pcdl_make_graph_gml', s_path_2d, 'attached'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
for i_step in range(25):
- os.remove(f'{s_path_2d}/output000000{str(i_step).zfill(2)}_cell.vtp')
+ os.remove(f'{s_path_2d}/output000000{str(i_step).zfill(2)}_attached.gml')
assert o_result.returncode == 0
- def test_pcdl_make_cell_vtk_timeseries_physiboss(self):
- o_result = subprocess.run(['pcdl_make_cell_vtk', s_path_2d, '--physiboss', 'false'], check=False, capture_output=True)
+ def test_pcdl_make_graph_gml_timeseries_edge_attribute(self):
+ o_result = subprocess.run(['pcdl_make_graph_gml', s_path_2d, 'neighbor', '--edge_attribute', 'false'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
for i_step in range(25):
- os.remove(f'{s_path_2d}/output000000{str(i_step).zfill(2)}_cell.vtp')
+ os.remove(f'{s_path_2d}/output000000{str(i_step).zfill(2)}_neighbor.gml')
assert o_result.returncode == 0
- def test_pcdl_make_cell_vtk_timeseries_settingxmlfalse_attribute_one(self):
- o_result = subprocess.run(['pcdl_make_cell_vtk', s_path_2d, 'default_fusion_rates', '--settingxml', 'false'], check=False, capture_output=True)
+ def test_pcdl_make_graph_gml_timeseries_nodeattribute_one(self):
+ o_result = subprocess.run(['pcdl_make_graph_gml', s_path_2d, 'neighbor', '--node_attribute', 'cell_type'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
for i_step in range(25):
- os.remove(f'{s_path_2d}/output000000{str(i_step).zfill(2)}_cell.vtp')
+ os.remove(f'{s_path_2d}/output000000{str(i_step).zfill(2)}_neighbor.gml')
assert o_result.returncode == 0
- def test_pcdl_make_cell_vtk_timeseries_settingxmlnone_attribute_one(self):
- o_result = subprocess.run(['pcdl_make_cell_vtk', s_path_2d, 'default_fusion_rates', '--settingxml', 'none'], check=False, capture_output=True)
+ def test_pcdl_make_graph_gml_timeseries_nodeattribute_many(self):
+ o_result = subprocess.run(['pcdl_make_graph_gml', s_path_2d, 'neighbor', '--node_attribute', 'cell_type', 'oxygen'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
for i_step in range(25):
- os.remove(f'{s_path_2d}/output000000{str(i_step).zfill(2)}_cell.vtp')
+ os.remove(f'{s_path_2d}/output000000{str(i_step).zfill(2)}_neighbor.gml')
assert o_result.returncode == 0
- def test_pcdl_make_cell_vtk_timeseries_attribute_many(self):
- o_result = subprocess.run(['pcdl_make_cell_vtk', s_path_2d, 'cell_type', 'oxygen'], check=False, capture_output=True)
+ def test_pcdl_make_graph_gml_timestep_default(self):
+ o_result = subprocess.run(['pcdl_make_graph_gml', s_pathfile_2d, 'neighbor'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
- for i_step in range(25):
- os.remove(f'{s_path_2d}/output000000{str(i_step).zfill(2)}_cell.vtp')
+ os.remove(f'{s_path_2d}/output00000024_neighbor.gml')
assert o_result.returncode == 0
- def test_pcdl_make_cell_vtk_timeseries_ext(self):
- o_result = subprocess.run(['pcdl_make_cell_vtk', s_path_2d, '--ext', '.vtp'], check=False, capture_output=True)
+ def test_pcdl_make_graph_gml_timestep_customtype_nodeattribute_one(self):
+ o_result = subprocess.run(['pcdl_make_graph_gml', s_pathfile_2d, 'neighbor', '--custom_data_type', 'sample:bool', '--node_attribute', 'sample'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
- for i_step in range(25):
- os.remove(f'{s_path_2d}/output000000{str(i_step).zfill(2)}.vtp')
+ os.remove(f'{s_path_2d}/output00000024_neighbor.gml')
assert o_result.returncode == 0
- def test_pcdl_make_cell_vtk_timestep_default(self):
- o_result = subprocess.run(['pcdl_make_cell_vtk', s_pathfile_2d], check=False, capture_output=True)
+ def test_pcdl_make_graph_gml_timestep_microenv(self):
+ o_result = subprocess.run(['pcdl_make_graph_gml', s_pathfile_2d, 'neighbor', '--microenv', 'false'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
- os.remove(f'{s_path_2d}/output00000024_cell.vtp')
+ os.remove(f'{s_path_2d}/output00000024_neighbor.gml')
assert o_result.returncode == 0
- def test_pcdl_make_cell_vtk_timestep_customtype_attribute_one(self):
- o_result = subprocess.run(['pcdl_make_cell_vtk', s_pathfile_2d, 'sample', '--custom_data_type', 'sample:bool'], check=False, capture_output=True)
+ def test_pcdl_make_graph_gml_timestep_physiboss(self):
+ o_result = subprocess.run(['pcdl_make_graph_gml', s_pathfile_2d, 'neighbor', '--physiboss', 'false'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
- os.remove(f'{s_path_2d}/output00000024_cell.vtp')
+ os.remove(f'{s_path_2d}/output00000024_neighbor.gml')
assert o_result.returncode == 0
- def test_pcdl_make_cell_vtk_timestep_microenv(self):
- o_result = subprocess.run(['pcdl_make_cell_vtk', s_pathfile_2d, '--microenv', 'false'], check=False, capture_output=True)
+ def test_pcdl_make_graph_gml_timestep_settingxmlfalse_nodeattribute_one(self):
+ o_result = subprocess.run(['pcdl_make_graph_gml', s_pathfile_2d, 'neighbor', '--settingxml', 'false', '--node_attribute', 'default_fusion_rates'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
- os.remove(f'{s_path_2d}/output00000024_cell.vtp')
+ os.remove(f'{s_path_2d}/output00000024_neighbor.gml')
assert o_result.returncode == 0
- def test_pcdl_make_cell_vtk_timestep_physiboss(self):
- o_result = subprocess.run(['pcdl_make_cell_vtk', s_pathfile_2d, '--physiboss', 'false'], check=False, capture_output=True)
+ def test_pcdl_make_graph_gml_timestep_settingxmlnone_nodeattribute_one(self):
+ o_result = subprocess.run(['pcdl_make_graph_gml', s_pathfile_2d, 'neighbor', '--settingxml', 'none', '--node_attribute', 'default_fusion_rates'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
- os.remove(f'{s_path_2d}/output00000024_cell.vtp')
+ os.remove(f'{s_path_2d}/output00000024_neighbor.gml')
assert o_result.returncode == 0
- def test_pcdl_make_cell_vtk_timestep_settingxmlfalse_attribute_one(self):
- o_result = subprocess.run(['pcdl_make_cell_vtk', s_pathfile_2d, 'default_fusion_rates', '--settingxml', 'false'], check=False, capture_output=True)
+ def test_pcdl_make_graph_gml_timestep_graph_type(self):
+ o_result = subprocess.run(['pcdl_make_graph_gml', s_pathfile_2d, 'attached'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
- os.remove(f'{s_path_2d}/output00000024_cell.vtp')
+ os.remove(f'{s_path_2d}/output00000024_attached.gml')
assert o_result.returncode == 0
- def test_pcdl_make_cell_vtk_timestep_settingxmlnone_attribute_one(self):
- o_result = subprocess.run(['pcdl_make_cell_vtk', s_pathfile_2d, 'default_fusion_rates', '--settingxml', 'none'], check=False, capture_output=True)
+ def test_pcdl_make_graph_gml_timestep_edge_attribute(self):
+ o_result = subprocess.run(['pcdl_make_graph_gml', s_pathfile_2d, 'neighbor', '--edge_attribute', 'false'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
- os.remove(f'{s_path_2d}/output00000024_cell.vtp')
+ os.remove(f'{s_path_2d}/output00000024_neighbor.gml')
assert o_result.returncode == 0
- def test_pcdl_make_cell_vtk_timestep_attribute_many(self):
- o_result = subprocess.run(['pcdl_make_cell_vtk', s_pathfile_2d, 'cell_type', 'oxygen'], check=False, capture_output=True)
+ def test_pcdl_make_graph_gml_timestep_node_attribute_one(self):
+ o_result = subprocess.run(['pcdl_make_graph_gml', s_pathfile_2d, 'neighbor', '--node_attribute', 'cell_type'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
- os.remove(f'{s_path_2d}/output00000024_cell.vtp')
+ os.remove(f'{s_path_2d}/output00000024_neighbor.gml')
assert o_result.returncode == 0
- def test_pcdl_make_cell_vtk_timestep_ext(self):
- o_result = subprocess.run(['pcdl_make_cell_vtk', s_pathfile_2d, '--ext', '.vtp'], check=False, capture_output=True)
+ def test_pcdl_make_graph_gml_timestep_node_attribute_many(self):
+ o_result = subprocess.run(['pcdl_make_graph_gml', s_pathfile_2d, 'neighbor', '--node_attribute', 'cell_type', 'oxygen'], check=False, capture_output=True)
print(f'o_result: {o_result}\n')
print(f'o_result.returncode: {o_result.returncode}\n')
print(f'o_result.stdout: {o_result.stdout}\n')
print(f'o_result.stderr: {o_result.stderr}\n')
- os.remove(f'{s_path_2d}/output00000024.vtp')
+ os.remove(f'{s_path_2d}/output00000024_neighbor.gml')
+ assert o_result.returncode == 0
+
+
+class TestCommandLineInterfaceSimularium(object):
+ ''' tests for one pcdl command line interface function. '''
+
+ # timeseries (there is no timestep function):
+ # + path nop
+ # + customtype ([], _sample:bool_) ok
+ # + microenv nop
+ # + physiboss (true, _false_) ok
+ # + settingxml (string, _none_, _false_) ok
+ # + verbose (true, _false_) nop
+ # + focus_cat (['cell_type','current_phase'], _['current_phase','cell_type']_) ok
+ # + trajectory_title (timeseries, _zeitreihe_) ok
+ # + scale_factor (None, 1.0) ok
+
+ def test_pcdl_make_simularium_timeseries_default(self):
+ o_result = subprocess.run(['pcdl_make_simularium', s_path_2d], check=False, capture_output=True)
+ print(f'o_result: {o_result}\n')
+ print(f'o_result.returncode: {o_result.returncode}\n')
+ print(f'o_result.stdout: {o_result.stdout}\n')
+ print(f'o_result.stderr: {o_result.stderr}\n')
+ os.remove(f'{s_path_2d}/timeseries.simularium')
+ assert o_result.returncode == 0
+
+ def test_pcdl_make_simularium_timeseries_customtype_attribute_one(self):
+ o_result = subprocess.run(['pcdl_make_simularium', s_path_2d, 'sample', '--custom_data_type', 'sample:bool'], check=False, capture_output=True)
+ print(f'o_result: {o_result}\n')
+ print(f'o_result.returncode: {o_result.returncode}\n')
+ print(f'o_result.stdout: {o_result.stdout}\n')
+ print(f'o_result.stderr: {o_result.stderr}\n')
+ os.remove(f'{s_path_2d}/timeseries.simularium')
+ assert o_result.returncode == 0
+
+ def test_pcdl_make_simularium_timeseries_physiboss(self):
+ o_result = subprocess.run(['pcdl_make_simularium', s_path_2d, '--physiboss', 'false'], check=False, capture_output=True)
+ print(f'o_result: {o_result}\n')
+ print(f'o_result.returncode: {o_result.returncode}\n')
+ print(f'o_result.stdout: {o_result.stdout}\n')
+ print(f'o_result.stderr: {o_result.stderr}\n')
+ os.remove(f'{s_path_2d}/timeseries.simularium')
+ assert o_result.returncode == 0
+
+ def test_pcdl_make_simularium_timeseries_settingxmlfalse_attribute_one(self):
+ o_result = subprocess.run(['pcdl_make_simularium', s_path_2d, 'default_fusion_rates', '--settingxml', 'false'], check=False, capture_output=True)
+ print(f'o_result: {o_result}\n')
+ print(f'o_result.returncode: {o_result.returncode}\n')
+ print(f'o_result.stdout: {o_result.stdout}\n')
+ print(f'o_result.stderr: {o_result.stderr}\n')
+ os.remove(f'{s_path_2d}/timeseries.simularium')
+ assert o_result.returncode == 0
+
+ def test_pcdl_make_simularium_timeseries_settingxmlnone_attribute_one(self):
+ o_result = subprocess.run(['pcdl_make_simularium', s_path_2d, 'default_fusion_rates', '--settingxml', 'none'], check=False, capture_output=True)
+ print(f'o_result: {o_result}\n')
+ print(f'o_result.returncode: {o_result.returncode}\n')
+ print(f'o_result.stdout: {o_result.stdout}\n')
+ print(f'o_result.stderr: {o_result.stderr}\n')
+ os.remove(f'{s_path_2d}/timeseries.simularium')
+ assert o_result.returncode == 0
+
+ def test_pcdl_make_simularium_timeseries_attribute_many(self):
+ o_result = subprocess.run(['pcdl_make_simularium', s_path_2d, 'current_phase', 'cell_type', '--trajectory_title', 'zeitreihe', '--scale_factor', '1.0'], check=False, capture_output=True)
+ print(f'o_result: {o_result}\n')
+ print(f'o_result.returncode: {o_result.returncode}\n')
+ print(f'o_result.stdout: {o_result.stdout}\n')
+ print(f'o_result.stderr: {o_result.stderr}\n')
+ os.remove(f'{s_path_2d}/zeitreihe.simularium')
assert o_result.returncode == 0
diff --git a/test/test_timeseries_2d.py b/test/test_timeseries_2d.py
index 9340a28..6218214 100644
--- a/test/test_timeseries_2d.py
+++ b/test/test_timeseries_2d.py
@@ -39,7 +39,7 @@
## making movies related functions ##
-class TestTimeSeriesMovies(object):
+class TestTimeSeries2dMovies(object):
''' tests for loading a pcdl.TimeSeries data set. '''
mcdsts = pcdl.TimeSeries(s_path_2d, verbose=True)
@@ -114,9 +114,48 @@ def test_mcdsts_make_movie_jpeg6(self, mcdsts=mcdsts):
shutil.rmtree(s_opath)
+class TestTimeSeries2dNeuroglancer(object):
+ ''' tests for loading a pcdl.TimeSeries data set. '''
+ mcdsts = pcdl.TimeSeries(s_path_2d, verbose=True)
+
+ ## make_gif and magick ommand ##
+ def test_mcdsts_render_neuroglancer_default(self, mcdsts=mcdsts):
+ s_tiffpathfile = mcdsts.make_ome_tiff()
+ o_viewer = mcdsts.render_neuroglancer(
+ tiffpathfile = s_tiffpathfile,
+ #timestep = 0,
+ #intensity_cmap='gray',
+ )
+ assert(str(type(o_viewer)) == "") and \
+ (str(o_viewer).startswith('http://127.0.0.1:'))
+ os.remove(s_tiffpathfile)
+
+ def test_mcdsts_render_neuroglancer_timestep(self, mcdsts=mcdsts):
+ s_tiffpathfile = mcdsts.make_ome_tiff()
+ o_viewer = mcdsts.render_neuroglancer(
+ tiffpathfile = s_tiffpathfile,
+ timestep = 12,
+ intensity_cmap='gray',
+ )
+ assert(str(type(o_viewer)) == "") and \
+ (str(o_viewer).startswith('http://127.0.0.1:'))
+ os.remove(s_tiffpathfile)
+
+ def test_mcdsts_render_neuroglancer_cmap(self, mcdsts=mcdsts):
+ s_tiffpathfile = mcdsts.make_ome_tiff()
+ o_viewer = mcdsts.render_neuroglancer(
+ tiffpathfile = s_tiffpathfile,
+ timestep = 0,
+ intensity_cmap='magma',
+ )
+ assert(str(type(o_viewer)) == "") and \
+ (str(o_viewer).startswith('http://127.0.0.1:'))
+ os.remove(s_tiffpathfile)
+
+
## data loading related functions ##
-class TestTimeSeriesInit(object):
+class TestTimeSeries2dInit(object):
''' tests for loading a pcdl.TimeSeries data set. '''
def test_mcdsts_custom_data_astype(self):
@@ -137,6 +176,10 @@ def test_mcdsts_set_verbose_false(self):
assert(str(type(mcdsts)) == "") and \
(not mcdsts.verbose)
+ # test_make_gif double command
+ # test_make_movie double command
+ # test_render_neuroglancer double command
+
## get_xmlfile and read_mcds command and get_mcds_list ##
def test_mcdsts_get_xmlfile_list(self):
mcdsts = pcdl.TimeSeries(s_path_2d, load=False, verbose=True)
@@ -146,28 +189,29 @@ def test_mcdsts_get_xmlfile_list(self):
(ls_xmlfile[-1] == 'output00000024.xml') and \
(len(ls_xmlfile) == 25)
- def test_mcdsts_get_mcds_list(self):
- mcdsts = pcdl.TimeSeries(s_path_2d, load=True, verbose=True)
- l_mcds = mcdsts.get_mcds_list()
+ def test_mcdsts_read_mcds(self):
+ mcdsts = pcdl.TimeSeries(s_path_2d, load=False, verbose=True)
+ l_mcds_loadfalse = mcdsts.get_mcds_list()
+ mcdsts.read_mcds()
assert(str(type(mcdsts)) == "") and \
(str(type(mcdsts.l_mcds[0])) == "") and \
(str(type(mcdsts.l_mcds[-1])) == "") and \
(mcdsts.l_mcds[0].get_time() == 0) and \
(mcdsts.l_mcds[-1].get_time() == 1440) and \
(len(mcdsts.l_mcds) == 25) and \
- (mcdsts.l_mcds == l_mcds)
+ (l_mcds_loadfalse is None)
- def test_mcdsts_read_mcds(self):
- mcdsts = pcdl.TimeSeries(s_path_2d, load=False, verbose=True)
- l_mcds_loadfalse = mcdsts.get_mcds_list()
- mcdsts.read_mcds()
+ def test_mcdsts_get_mcds_list(self):
+ mcdsts = pcdl.TimeSeries(s_path_2d, load=True, verbose=True)
+ l_mcds = mcdsts.get_mcds_list()
assert(str(type(mcdsts)) == "") and \
(str(type(mcdsts.l_mcds[0])) == "") and \
(str(type(mcdsts.l_mcds[-1])) == "") and \
(mcdsts.l_mcds[0].get_time() == 0) and \
(mcdsts.l_mcds[-1].get_time() == 1440) and \
(len(mcdsts.l_mcds) == 25) and \
- (l_mcds_loadfalse is None)
+ (mcdsts.l_mcds == l_mcds)
+
def test_mcdsts_read_mcds_xmlfilelist(self):
mcdsts = pcdl.TimeSeries(s_path_2d, load=False, verbose=True)
@@ -192,7 +236,7 @@ def test_mcdsts_form_list_of_mcds(self):
## micro environment related functions ##
-class TestTimeSeriesMicroenv(object):
+class TestTimeSeries2dMicroenv(object):
''' tests for pcdl.TimeSeriesmicro environment related functions. '''
mcdsts = pcdl.TimeSeries(s_path_2d, verbose=True)
@@ -313,7 +357,7 @@ def test_mcdsts_make_conc_vtk(self, mcdsts=mcdsts):
## cell related functions ##
-class TestTimeSeriesCell(object):
+class TestTimeSeries2dCell(object):
''' tests for pcdl.TimeSeries cell related functions. '''
mcdsts = pcdl.TimeSeries(s_path_2d, verbose=False)
@@ -454,9 +498,99 @@ def test_mcdsts_make_cell_vtk(self, mcdsts=mcdsts):
os.remove(s_pathfile)
+## anndata time series related functions ##
+
+class TestTimeSeries2dAnnData(object):
+ ''' test for pcdl.TestSeries class. '''
+
+ # get_anndata
+ # get_annmcds_list {integrated}
+ # value {1, _2_}
+ # collaps {True, _False_}
+ # keep_mcds {True, _False_}
+
+ ## get_anndata command ##
+ def test_mcdsts_get_anndata(self):
+ mcdsts = pcdl.TimeSeries(s_path_2d, verbose=True)
+ ann = mcdsts.get_anndata(values=1, drop=set(), keep=set(), scale='maxabs', collapse=True, keep_mcds=True)
+ l_annmcds = mcdsts.get_annmcds_list()
+ assert(str(type(mcdsts)) == "") and \
+ (len(mcdsts.l_mcds) == 25) and \
+ (l_annmcds == mcdsts.l_annmcds) and \
+ (mcdsts.l_annmcds is None) and \
+ (str(type(ann)) == "") and \
+ (ann.X.shape[0] > 9) and \
+ (ann.X.shape[1] == 105) and \
+ (ann.obs.shape[0] > 9) and \
+ (ann.obs.shape[1] == 8) and \
+ (ann.obsm['spatial'].shape[0] > 9) and \
+ (ann.obsm['spatial'].shape[1] == 2) and \
+ (len(ann.obsp) == 0) and \
+ (ann.var.shape == (105, 0)) and \
+ (len(ann.uns) == 0)
+
+ def test_mcdsts_get_anndata_value(self):
+ mcdsts = pcdl.TimeSeries(s_path_2d, verbose=True)
+ ann = mcdsts.get_anndata(values=2, drop=set(), keep=set(), scale='maxabs', collapse=True, keep_mcds=True)
+ l_annmcds = mcdsts.get_annmcds_list()
+ assert(str(type(mcdsts)) == "") and \
+ (len(mcdsts.l_mcds) == 25) and \
+ (l_annmcds == mcdsts.l_annmcds) and \
+ (mcdsts.l_annmcds is None) and \
+ (str(type(ann)) == "") and \
+ (ann.X.shape[0] > 9) and \
+ (ann.X.shape[1] == 50) and \
+ (ann.obs.shape[0] > 9) and \
+ (ann.obs.shape[1] == 7) and \
+ (ann.obsm['spatial'].shape[0] > 9) and \
+ (ann.obsm['spatial'].shape[1] == 2) and \
+ (len(ann.obsp) == 0) and \
+ (ann.var.shape == (50, 0)) and \
+ (len(ann.uns) == 0)
+
+ def test_mcdsts_get_anndata_collapsefalse(self):
+ mcdsts = pcdl.TimeSeries(s_path_2d, verbose=True)
+ ann = mcdsts.get_anndata(values=1, drop=set(), keep=set(), scale='maxabs', collapse=False, keep_mcds=True)
+ l_annmcds = mcdsts.get_annmcds_list()
+ assert(str(type(mcdsts)) == "") and \
+ (len(mcdsts.l_mcds) == 25) and \
+ (l_annmcds == mcdsts.l_annmcds) and \
+ (str(type(mcdsts.l_annmcds)) == "") and \
+ (len(mcdsts.l_annmcds) == 25) and \
+ (all([str(type(ann)) == "" for ann in mcdsts.l_annmcds])) and \
+ (mcdsts.l_annmcds[24].X.shape[0] > 9) and \
+ (mcdsts.l_annmcds[24].X.shape[1] == 105) and \
+ (mcdsts.l_annmcds[24].obs.shape[0] > 9) and \
+ (mcdsts.l_annmcds[24].obs.shape[1] == 8) and \
+ (mcdsts.l_annmcds[24].obsm['spatial'].shape[0] > 9) and \
+ (mcdsts.l_annmcds[24].obsm['spatial'].shape[1] == 2) and \
+ (len(mcdsts.l_annmcds[24].obsp) == 4) and \
+ (mcdsts.l_annmcds[24].var.shape == (105, 0)) and \
+ (len(mcdsts.l_annmcds[24].uns) == 2)
+
+ def test_mcdsts_get_anndata_keepmcdsfalse(self):
+ mcdsts = pcdl.TimeSeries(s_path_2d, verbose=True)
+ ann = mcdsts.get_anndata(values=1, drop=set(), keep=set(), scale='maxabs', collapse=True, keep_mcds=False)
+ l_annmcds = mcdsts.get_annmcds_list()
+ assert(str(type(mcdsts)) == "") and \
+ (len(mcdsts.l_mcds) == 0) and \
+ (l_annmcds == mcdsts.l_annmcds) and \
+ (mcdsts.l_annmcds is None) and \
+ (str(type(ann)) == "") and \
+ (ann.X.shape[0] > 9) and \
+ (ann.X.shape[1] == 105) and \
+ (ann.obs.shape[0] > 9) and \
+ (ann.obs.shape[1] == 8) and \
+ (ann.obsm['spatial'].shape[0] > 9) and \
+ (ann.obsm['spatial'].shape[1] == 2) and \
+ (len(ann.obsp) == 0) and \
+ (ann.var.shape == (105, 0)) and \
+ (len(ann.uns) == 0)
+
+
## graph related functions ##
-class TestTimeSeriesGraph(object):
+class TestTimeSeries2dGraph(object):
''' tests for pcdl.TimeSeries graph related functions. '''
mcdsts = pcdl.TimeSeries(s_path_2d, verbose=False)
@@ -495,96 +629,113 @@ def test_mcdsts_get_graph_gml_neighbor_allattr(self, mcdsts=mcdsts):
os.remove(s_pathfile)
-## ome tiff related functions ##
+## simularium time series related functions ##
-class TestTimeSeriesOmeTiff(object):
- ''' tests for pcdl.TimeSeries ome tiff related functions. '''
- mcdsts = pcdl.TimeSeries(s_path_2d, verbose=False)
+class TestTimeSeries2dSimularium(object):
+ ''' test for pcdl.TimeSeries class. '''
- ## ome tiff related functions ##
- def test_mcdsts_make_ome_tiff_defaultattr_00(self, mcdsts=mcdsts):
- la_ometiff = mcdsts.make_ome_tiff(cell_attribute='ID', conc_cutoff={}, focus=None, file=False, collapse=False)
+ ## get_simularium command ##
+ def test_mcdsts_get_simularium_default(self):
+ import simulariumio as sim
+ mcdsts = pcdl.TimeSeries(s_path_2d, verbose=False)
+ s_pathfile = mcdsts.make_simularium(focus_cat=['cell_type','current_phase'], trajectory_title='timeseries', scale_factor=None, camera_defaults=None, model_meta_data=None)
assert(str(type(mcdsts)) == "") and \
- (type(la_ometiff) is list) and \
- (type(la_ometiff[0]) is np.ndarray) and \
- (type(la_ometiff[-1]) is np.ndarray) and \
- (la_ometiff[0].dtype == np.float32) and \
- (la_ometiff[-1].dtype == np.float32) and \
- (la_ometiff[0].shape == (4, 1, 200, 300)) and \
- (la_ometiff[-1].shape == (4, 1, 200, 300)) and \
- (len(la_ometiff) == 25)
+ (s_pathfile.endswith('/pcdl/output_2d/timeseries.simularium')) and \
+ (os.path.exists(s_pathfile))
+ os.remove(s_pathfile)
- def test_mcdsts_make_ome_tiff_defaultattr_01(self, mcdsts=mcdsts):
- a_ometiff = mcdsts.make_ome_tiff(cell_attribute='ID', conc_cutoff={}, focus=None, file=False, collapse=True)
+ def test_mcdsts_get_simularium_nondefault(self):
+ import simulariumio as sim
+ mcdsts = pcdl.TimeSeries(s_path_2d, verbose=False)
+ s_pathfile = mcdsts.make_simularium(focus_cat=['current_phase', 'dead'], trajectory_title='zeitreihe', scale_factor=0.1, camera_defaults=sim.CameraData(), model_meta_data=sim.ModelMetaData())
assert(str(type(mcdsts)) == "") and \
- (type(a_ometiff) is np.ndarray) and \
- (a_ometiff.dtype == np.float32) and \
- (a_ometiff.shape == (25, 4, 1, 200, 300))
+ (s_pathfile.endswith('/pcdl/output_2d/zeitreihe.simularium')) and \
+ (os.path.exists(s_pathfile))
+ os.remove(s_pathfile)
- def test_mcdsts_make_ome_tiff_defaultattr_10(self, mcdsts=mcdsts):
- ls_pathfile = mcdsts.make_ome_tiff(cell_attribute='ID', conc_cutoff={}, focus=None, file=True, collapse=False)
- assert(str(type(mcdsts)) == "") and \
- (ls_pathfile[0].endswith('pcdl/output_2d/output00000000_oxygen_water_default_blood_cells_ID.ome.tiff')) and \
- (ls_pathfile[-1].endswith('pcdl/output_2d/output00000024_oxygen_water_default_blood_cells_ID.ome.tiff')) and \
- (os.path.exists(ls_pathfile[0])) and \
- (os.path.exists(ls_pathfile[-1])) and \
- (os.path.getsize(ls_pathfile[0]) > 2**10) and\
- (os.path.getsize(ls_pathfile[-1]) > 2**10) and\
- (len(ls_pathfile) == 25)
- for s_pathfile in ls_pathfile:
- os.remove(s_pathfile)
- def test_mcdsts_make_ome_tiff_defaultattr_11(self, mcdsts=mcdsts):
- s_pathfile = mcdsts.make_ome_tiff(cell_attribute='ID', conc_cutoff={}, focus=None, file=True, collapse=True)
- assert(str(type(mcdsts)) == "") and \
- (s_pathfile.endswith('pcdl/output_2d/timeseries_oxygen_water_default_blood_cells_ID.ome.tiff')) and \
- (os.path.exists(s_pathfile)) and \
- (os.path.getsize(s_pathfile) > 2**10 )
- os.remove(s_pathfile)
+## muspan time series related functions ##
+class TestTimeSeries2dMuspan(object):
+ ''' test for pcdl.TimeSeries class. '''
+ ## get_muspan command ##
+ def test_mcdsts_get_muspan_default(self):
+ try:
+ import muspan as ms
+ mcdsts = pcdl.TimeSeries(s_path_2d, verbose=False)
+ do_domain = mcdsts.get_muspan(z_slice=None, values=1, drop=set(), keep=set())
+ s_key = sorted(do_domain.keys())[-1]
+ assert(str(type(mcdsts)) == "") and \
+ (type(do_domain) == dict) and \
+ (len(do_domain) == 25) and \
+ (str(type(do_domain[s_key])) == "") and \
+ (len(do_domain[s_key].collections) == 2) and \
+ (len(do_domain[s_key].networks) == 3) and \
+ (len(do_domain[s_key].objects) > 9)
+ except ModuleNotFoundError:
+ print('Warning @ pytest TestTimeSeries2dMuspan : muspan module not installed.')
+ assert True
+ except SystemExit:
+ print('Warning @ pytest TestTimeSeries2dMuspan : muspan module not installed.')
+ assert True
-class TestTimeSeriesNeuroglancer(object):
- ''' tests for loading a pcdl.TimeSeries data set. '''
- mcdsts = pcdl.TimeSeries(s_path_2d, verbose=True)
+ def test_mcdsts_get_muspan_zslice(self):
+ try:
+ import muspan as ms
+ mcdsts = pcdl.TimeSeries(s_path_2d, verbose=False)
+ do_domain = mcdsts.get_muspan(z_slice=0.0, values=1, drop=set(), keep=set())
+ s_key = sorted(do_domain.keys())[-1]
+ assert(str(type(mcdsts)) == "") and \
+ (type(do_domain) == dict) and \
+ (len(do_domain) == 25) and \
+ (str(type(do_domain[s_key])) == "") and \
+ (len(do_domain[s_key].collections) == 2) and \
+ (len(do_domain[s_key].networks) == 3) and \
+ (len(do_domain[s_key].objects) > 9)
+ except ModuleNotFoundError:
+ print('Warning @ pytest TestTimeSeries2dMuspan : muspan module not installed.')
+ assert True
+ except SystemExit:
+ print('Warning @ pytest TestTimeSeries2dMuspan : muspan module not installed.')
+ assert True
- ## make_gif and magick ommand ##
- def test_mcdsts_render_neuroglancer_default(self, mcdsts=mcdsts):
- s_tiffpathfile = mcdsts.make_ome_tiff()
- o_viewer = mcdsts.render_neuroglancer(
- tiffpathfile = s_tiffpathfile,
- #timestep = 0,
- #intensity_cmap='gray',
- )
- assert(str(type(o_viewer)) == "") and \
- (str(o_viewer).startswith('http://127.0.0.1:'))
- os.remove(s_tiffpathfile)
- def test_mcdsts_render_neuroglancer_timestep(self, mcdsts=mcdsts):
- s_tiffpathfile = mcdsts.make_ome_tiff()
- o_viewer = mcdsts.render_neuroglancer(
- tiffpathfile = s_tiffpathfile,
- timestep = 12,
- intensity_cmap='gray',
- )
- assert(str(type(o_viewer)) == "") and \
- (str(o_viewer).startswith('http://127.0.0.1:'))
- os.remove(s_tiffpathfile)
+## spatialdata time seris related functions ##
- def test_mcdsts_render_neuroglancer_cmap(self, mcdsts=mcdsts):
- s_tiffpathfile = mcdsts.make_ome_tiff()
- o_viewer = mcdsts.render_neuroglancer(
- tiffpathfile = s_tiffpathfile,
- timestep = 0,
- intensity_cmap='magma',
- )
- assert(str(type(o_viewer)) == "") and \
- (str(o_viewer).startswith('http://127.0.0.1:'))
- os.remove(s_tiffpathfile)
+class TestTimeSeries2dSpatialData(object):
+ ''' test for pcdl.TestSeries class. '''
+
+ # get_sdmcds_list {integrated}
+ # get_cell_attributes ok
+ # get_get_spatialdata ok
+ # keep_mcds {True, _False_}
+
+ def test_mcdsts_get_spatialdata_default(self):
+ mcdsts = pcdl.TimeSeries(s_path_2d, verbose=True)
+ lo_sdmcds_output = mcdsts.get_spatialdata(images={'subs'}, labels=set(), points={'subs'}, shapes={'cell'}, values=1, drop=set(), keep=set(), scale='maxabs', keep_mcds=True)
+ lo_sdmcds_memory = mcdsts.get_sdmcds_list()
+ assert(str(type(mcdsts)) == "") and \
+ (len(mcdsts.l_mcds) == 25) and \
+ (len(mcdsts.l_sdmcds) == 25) and \
+ (lo_sdmcds_output == mcdsts.l_sdmcds) and \
+ (lo_sdmcds_output == lo_sdmcds_memory) and \
+ (str(type(lo_sdmcds_output[8])) == "")
+
+ def test_mcdsts_get_spatialdata_keepmcdsfalse(self):
+ mcdsts = pcdl.TimeSeries(s_path_2d, verbose=True)
+ lo_sdmcds_output = mcdsts.get_spatialdata(images={'subs'}, labels=set(), points={'subs'}, shapes={'cell'}, values=1, drop=set(), keep=set(), scale='maxabs', keep_mcds=False)
+ lo_sdmcds_memory = mcdsts.get_sdmcds_list()
+ assert(str(type(mcdsts)) == "") and \
+ (len(mcdsts.l_mcds) == 0) and \
+ (len(mcdsts.l_sdmcds) == 25) and \
+ (lo_sdmcds_output == mcdsts.l_sdmcds) and \
+ (lo_sdmcds_output == lo_sdmcds_memory) and \
+ (str(type(lo_sdmcds_output[8])) == "")
## time series related functions ##
-class TestTimeSeriesTimeseries(object):
+class TestTimeSeries2dTimeseries(object):
''' tests for pcdl.TimeSeries graph related functions. '''
mcdsts = pcdl.TimeSeries(s_path_2d, verbose=False)
@@ -917,170 +1068,49 @@ def test_mcdsts_plot_timeseries_none_none_yunit_conc_fig(self, mcdsts=mcdsts):
plt.close()
-## anndata time series related functions ##
-
-class TestTimeSeriesAnnData(object):
- ''' test for pcdl.TestSeries class. '''
-
- # get_anndata
- # get_annmcds_list {integrated}
- # value {1, _2_}
- # collaps {True, _False_}
- # keep_mcds {True, _False_}
-
- ## get_anndata command ##
- def test_mcdsts_get_anndata(self):
- mcdsts = pcdl.TimeSeries(s_path_2d, verbose=True)
- ann = mcdsts.get_anndata(values=1, drop=set(), keep=set(), scale='maxabs', collapse=True, keep_mcds=True)
- l_annmcds = mcdsts.get_annmcds_list()
- assert(str(type(mcdsts)) == "") and \
- (len(mcdsts.l_mcds) == 25) and \
- (l_annmcds == mcdsts.l_annmcds) and \
- (mcdsts.l_annmcds is None) and \
- (str(type(ann)) == "") and \
- (ann.X.shape[0] > 9) and \
- (ann.X.shape[1] == 105) and \
- (ann.obs.shape[0] > 9) and \
- (ann.obs.shape[1] == 8) and \
- (ann.obsm['spatial'].shape[0] > 9) and \
- (ann.obsm['spatial'].shape[1] == 2) and \
- (len(ann.obsp) == 0) and \
- (ann.var.shape == (105, 0)) and \
- (len(ann.uns) == 0)
+## ome tiff related functions ##
- def test_mcdsts_get_anndata_value(self):
- mcdsts = pcdl.TimeSeries(s_path_2d, verbose=True)
- ann = mcdsts.get_anndata(values=2, drop=set(), keep=set(), scale='maxabs', collapse=True, keep_mcds=True)
- l_annmcds = mcdsts.get_annmcds_list()
- assert(str(type(mcdsts)) == "") and \
- (len(mcdsts.l_mcds) == 25) and \
- (l_annmcds == mcdsts.l_annmcds) and \
- (mcdsts.l_annmcds is None) and \
- (str(type(ann)) == "") and \
- (ann.X.shape[0] > 9) and \
- (ann.X.shape[1] == 50) and \
- (ann.obs.shape[0] > 9) and \
- (ann.obs.shape[1] == 7) and \
- (ann.obsm['spatial'].shape[0] > 9) and \
- (ann.obsm['spatial'].shape[1] == 2) and \
- (len(ann.obsp) == 0) and \
- (ann.var.shape == (50, 0)) and \
- (len(ann.uns) == 0)
+class TestTimeSeries2dOmeTiff(object):
+ ''' tests for pcdl.TimeSeries ome tiff related functions. '''
+ mcdsts = pcdl.TimeSeries(s_path_2d, verbose=False)
- def test_mcdsts_get_anndata_collapsefalse(self):
- mcdsts = pcdl.TimeSeries(s_path_2d, verbose=True)
- ann = mcdsts.get_anndata(values=1, drop=set(), keep=set(), scale='maxabs', collapse=False, keep_mcds=True)
- l_annmcds = mcdsts.get_annmcds_list()
+ ## ome tiff related functions ##
+ def test_mcdsts_make_ome_tiff_defaultattr_00(self, mcdsts=mcdsts):
+ la_ometiff = mcdsts.make_ome_tiff(cell_attribute='ID', conc_cutoff={}, focus=None, file=False, collapse=False)
assert(str(type(mcdsts)) == "") and \
- (len(mcdsts.l_mcds) == 25) and \
- (l_annmcds == mcdsts.l_annmcds) and \
- (str(type(mcdsts.l_annmcds)) == "") and \
- (len(mcdsts.l_annmcds) == 25) and \
- (all([str(type(ann)) == "" for ann in mcdsts.l_annmcds])) and \
- (mcdsts.l_annmcds[24].X.shape[0] > 9) and \
- (mcdsts.l_annmcds[24].X.shape[1] == 105) and \
- (mcdsts.l_annmcds[24].obs.shape[0] > 9) and \
- (mcdsts.l_annmcds[24].obs.shape[1] == 8) and \
- (mcdsts.l_annmcds[24].obsm['spatial'].shape[0] > 9) and \
- (mcdsts.l_annmcds[24].obsm['spatial'].shape[1] == 2) and \
- (len(mcdsts.l_annmcds[24].obsp) == 4) and \
- (mcdsts.l_annmcds[24].var.shape == (105, 0)) and \
- (len(mcdsts.l_annmcds[24].uns) == 2)
+ (type(la_ometiff) is list) and \
+ (type(la_ometiff[0]) is np.ndarray) and \
+ (type(la_ometiff[-1]) is np.ndarray) and \
+ (la_ometiff[0].dtype == np.float32) and \
+ (la_ometiff[-1].dtype == np.float32) and \
+ (la_ometiff[0].shape == (4, 1, 200, 300)) and \
+ (la_ometiff[-1].shape == (4, 1, 200, 300)) and \
+ (len(la_ometiff) == 25)
- def test_mcdsts_get_anndata_keepmcdsfalse(self):
- mcdsts = pcdl.TimeSeries(s_path_2d, verbose=True)
- ann = mcdsts.get_anndata(values=1, drop=set(), keep=set(), scale='maxabs', collapse=True, keep_mcds=False)
- l_annmcds = mcdsts.get_annmcds_list()
+ def test_mcdsts_make_ome_tiff_defaultattr_01(self, mcdsts=mcdsts):
+ a_ometiff = mcdsts.make_ome_tiff(cell_attribute='ID', conc_cutoff={}, focus=None, file=False, collapse=True)
assert(str(type(mcdsts)) == "") and \
- (len(mcdsts.l_mcds) == 0) and \
- (l_annmcds == mcdsts.l_annmcds) and \
- (mcdsts.l_annmcds is None) and \
- (str(type(ann)) == "") and \
- (ann.X.shape[0] > 9) and \
- (ann.X.shape[1] == 105) and \
- (ann.obs.shape[0] > 9) and \
- (ann.obs.shape[1] == 8) and \
- (ann.obsm['spatial'].shape[0] > 9) and \
- (ann.obsm['spatial'].shape[1] == 2) and \
- (len(ann.obsp) == 0) and \
- (ann.var.shape == (105, 0)) and \
- (len(ann.uns) == 0)
-
-
-## muspan time series related functions ##
-class TestTimeSeriesMuspan(object):
- ''' test for pcdl.TimeSeries class. '''
-
- ## get_muspan command ##
- def test_mcdsts_get_muspan_default(self):
- try:
- import muspan as ms
- mcdsts = pcdl.TimeSeries(s_path_2d, verbose=False)
- do_domain = mcdsts.get_muspan(z_slice=None, values=1, drop=set(), keep=set())
- s_key = sorted(do_domain.keys())[-1]
- assert(str(type(mcdsts)) == "") and \
- (type(do_domain) == dict) and \
- (len(do_domain) == 25) and \
- (str(type(do_domain[s_key])) == "") and \
- (len(do_domain[s_key].collections) == 2) and \
- (len(do_domain[s_key].networks) == 3) and \
- (len(do_domain[s_key].objects) > 9)
- except ModuleNotFoundError:
- print('Warning @ pytest TestTimeSeriesMuspan : muspan module not installed.')
- assert True
- except SystemExit:
- print('Warning @ pytest TestTimeSeriesMuspan : muspan module not installed.')
- assert True
-
- def test_mcdsts_get_muspan_zslice(self):
- try:
- import muspan as ms
- mcdsts = pcdl.TimeSeries(s_path_2d, verbose=False)
- do_domain = mcdsts.get_muspan(z_slice=0.0, values=1, drop=set(), keep=set())
- s_key = sorted(do_domain.keys())[-1]
- assert(str(type(mcdsts)) == "") and \
- (type(do_domain) == dict) and \
- (len(do_domain) == 25) and \
- (str(type(do_domain[s_key])) == "") and \
- (len(do_domain[s_key].collections) == 2) and \
- (len(do_domain[s_key].networks) == 3) and \
- (len(do_domain[s_key].objects) > 9)
- except ModuleNotFoundError:
- print('Warning @ pytest TestTimeSeriesMuspan : muspan module not installed.')
- assert True
- except SystemExit:
- print('Warning @ pytest TestTimeSeriesMuspan : muspan module not installed.')
- assert True
-
-
-## spatialdata time seris related functions ##
-class TestTimeSeriesSpatialData(object):
- ''' test for pcdl.TestSeries class. '''
-
- # get_sdmcds_list {integrated}
- # get_cell_attributes ok
- # get_get_spatialdata ok
- # keep_mcds {True, _False_}
+ (type(a_ometiff) is np.ndarray) and \
+ (a_ometiff.dtype == np.float32) and \
+ (a_ometiff.shape == (25, 4, 1, 200, 300))
- def test_mcdsts_get_spatialdata_default(self):
- mcdsts = pcdl.TimeSeries(s_path_2d, verbose=True)
- lo_sdmcds_output = mcdsts.get_spatialdata(images={'subs'}, labels=set(), points={'subs'}, shapes={'cell'}, values=1, drop=set(), keep=set(), scale='maxabs', keep_mcds=True)
- lo_sdmcds_memory = mcdsts.get_sdmcds_list()
+ def test_mcdsts_make_ome_tiff_defaultattr_10(self, mcdsts=mcdsts):
+ ls_pathfile = mcdsts.make_ome_tiff(cell_attribute='ID', conc_cutoff={}, focus=None, file=True, collapse=False)
assert(str(type(mcdsts)) == "") and \
- (len(mcdsts.l_mcds) == 25) and \
- (len(mcdsts.l_sdmcds) == 25) and \
- (lo_sdmcds_output == mcdsts.l_sdmcds) and \
- (lo_sdmcds_output == lo_sdmcds_memory) and \
- (str(type(lo_sdmcds_output[8])) == "")
+ (ls_pathfile[0].endswith('pcdl/output_2d/output00000000_oxygen_water_default_blood_cells_ID.ome.tiff')) and \
+ (ls_pathfile[-1].endswith('pcdl/output_2d/output00000024_oxygen_water_default_blood_cells_ID.ome.tiff')) and \
+ (os.path.exists(ls_pathfile[0])) and \
+ (os.path.exists(ls_pathfile[-1])) and \
+ (os.path.getsize(ls_pathfile[0]) > 2**10) and\
+ (os.path.getsize(ls_pathfile[-1]) > 2**10) and\
+ (len(ls_pathfile) == 25)
+ for s_pathfile in ls_pathfile:
+ os.remove(s_pathfile)
- def test_mcdsts_get_spatialdata_keepmcdsfalse(self):
- mcdsts = pcdl.TimeSeries(s_path_2d, verbose=True)
- lo_sdmcds_output = mcdsts.get_spatialdata(images={'subs'}, labels=set(), points={'subs'}, shapes={'cell'}, values=1, drop=set(), keep=set(), scale='maxabs', keep_mcds=False)
- lo_sdmcds_memory = mcdsts.get_sdmcds_list()
+ def test_mcdsts_make_ome_tiff_defaultattr_11(self, mcdsts=mcdsts):
+ s_pathfile = mcdsts.make_ome_tiff(cell_attribute='ID', conc_cutoff={}, focus=None, file=True, collapse=True)
assert(str(type(mcdsts)) == "") and \
- (len(mcdsts.l_mcds) == 0) and \
- (len(mcdsts.l_sdmcds) == 25) and \
- (lo_sdmcds_output == mcdsts.l_sdmcds) and \
- (lo_sdmcds_output == lo_sdmcds_memory) and \
- (str(type(lo_sdmcds_output[8])) == "")
-
+ (s_pathfile.endswith('pcdl/output_2d/timeseries_oxygen_water_default_blood_cells_ID.ome.tiff')) and \
+ (os.path.exists(s_pathfile)) and \
+ (os.path.getsize(s_pathfile) > 2**10 )
+ os.remove(s_pathfile)
diff --git a/test/test_timeseries_3d.py b/test/test_timeseries_3d.py
index 7e0fe0c..73bdb8d 100644
--- a/test/test_timeseries_3d.py
+++ b/test/test_timeseries_3d.py
@@ -380,7 +380,97 @@ def test_mcdsts_make_cell_vtk(self, mcdsts=mcdsts):
os.remove(s_pathfile)
+## anndata time series related functions ##
+class TestTimeSeries3dAnnData(object):
+ ''' test for pcdl.TestSeries class. '''
+
+ # get_anndata
+ # get_annmcds_list {integrated}
+ # value {1, _2_}
+ # collaps {True, _False_}
+ # keep_mcds {True, _False_}
+
+ ## get_anndata command ##
+ def test_mcdsts_get_anndata(self):
+ mcdsts = pcdl.TimeSeries(s_path_3d, verbose=True)
+ ann = mcdsts.get_anndata(values=1, drop=set(), keep=set(), scale='maxabs', collapse=True, keep_mcds=True)
+ l_annmcds = mcdsts.get_annmcds_list()
+ assert(str(type(mcdsts)) == "") and \
+ (len(mcdsts.l_mcds) == 25) and \
+ (l_annmcds == mcdsts.l_annmcds) and \
+ (mcdsts.l_annmcds is None) and \
+ (str(type(ann)) == "") and \
+ (ann.X.shape[0] > 9) and \
+ (ann.X.shape[1] == 105) and \
+ (ann.obs.shape[0] > 9) and \
+ (ann.obs.shape[1] == 8) and \
+ (ann.obsm['spatial'].shape[0] > 9) and \
+ (ann.obsm['spatial'].shape[1] == 3) and \
+ (len(ann.obsp) == 0) and \
+ (ann.var.shape == (105, 0)) and \
+ (len(ann.uns) == 0)
+
+ def test_mcdsts_get_anndata_value(self):
+ mcdsts = pcdl.TimeSeries(s_path_3d, verbose=True)
+ ann = mcdsts.get_anndata(values=2, drop=set(), keep=set(), scale='maxabs', collapse=True, keep_mcds=True)
+ l_annmcds = mcdsts.get_annmcds_list()
+ assert(str(type(mcdsts)) == "") and \
+ (len(mcdsts.l_mcds) == 25) and \
+ (l_annmcds == mcdsts.l_annmcds) and \
+ (mcdsts.l_annmcds is None) and \
+ (str(type(ann)) == "") and \
+ (ann.X.shape[0] > 9) and \
+ (ann.X.shape[1] == 56) and \
+ (ann.obs.shape[0] > 9) and \
+ (ann.obs.shape[1] == 7) and \
+ (ann.obsm['spatial'].shape[0] > 9) and \
+ (ann.obsm['spatial'].shape[1] == 3) and \
+ (len(ann.obsp) == 0) and \
+ (ann.var.shape == (56, 0)) and \
+ (len(ann.uns) == 0)
+
+ def test_mcdsts_get_anndata_collapsefalse(self):
+ mcdsts = pcdl.TimeSeries(s_path_3d, verbose=True)
+ ann = mcdsts.get_anndata(values=1, drop=set(), keep=set(), scale='maxabs', collapse=False, keep_mcds=True)
+ l_annmcds = mcdsts.get_annmcds_list()
+ assert(str(type(mcdsts)) == "") and \
+ (len(mcdsts.l_mcds) == 25) and \
+ (l_annmcds == mcdsts.l_annmcds) and \
+ (str(type(mcdsts.l_annmcds)) == "") and \
+ (len(mcdsts.l_annmcds) == 25) and \
+ (all([str(type(ann)) == "" for ann in mcdsts.l_annmcds])) and \
+ (mcdsts.l_annmcds[24].X.shape[0] > 9) and \
+ (mcdsts.l_annmcds[24].X.shape[1] == 105) and \
+ (mcdsts.l_annmcds[24].obs.shape[0] > 9) and \
+ (mcdsts.l_annmcds[24].obs.shape[1] == 8) and \
+ (mcdsts.l_annmcds[24].obsm['spatial'].shape[0] > 9) and \
+ (mcdsts.l_annmcds[24].obsm['spatial'].shape[1] == 3) and \
+ (len(mcdsts.l_annmcds[24].obsp) == 4) and \
+ (mcdsts.l_annmcds[24].var.shape == (105, 0)) and \
+ (len(mcdsts.l_annmcds[24].uns) == 2)
+
+ def test_mcdsts_get_anndata_keepmcdsfalse(self):
+ mcdsts = pcdl.TimeSeries(s_path_3d, verbose=True)
+ ann = mcdsts.get_anndata(values=1, drop=set(), keep=set(), scale='maxabs', collapse=True, keep_mcds=False)
+ l_annmcds = mcdsts.get_annmcds_list()
+ assert(str(type(mcdsts)) == "") and \
+ (len(mcdsts.l_mcds) == 0) and \
+ (l_annmcds == mcdsts.l_annmcds) and \
+ (mcdsts.l_annmcds is None) and \
+ (str(type(ann)) == "") and \
+ (ann.X.shape[0] > 9) and \
+ (ann.X.shape[1] == 105) and \
+ (ann.obs.shape[0] > 9) and \
+ (ann.obs.shape[1] == 8) and \
+ (ann.obsm['spatial'].shape[0] > 9) and \
+ (ann.obsm['spatial'].shape[1] == 3) and \
+ (len(ann.obsp) == 0) and \
+ (ann.var.shape == (105, 0)) and \
+ (len(ann.uns) == 0)
+
+
## graph related functions ##
+
class TestTimeSeries3dGraph(object):
''' tests for pcdl.TimeStep graph related functions. '''
mcdsts = pcdl.TimeSeries(s_path_3d, verbose=False)
@@ -419,30 +509,109 @@ def test_mcdsts_get_graph_gml_neighbor_allattr(self, mcdsts=mcdsts):
for s_pathfile in ls_pathfile:
os.remove(s_pathfile)
-## ome.tiff related functions ##
-class TestTimeSeries3dOmeTiff(object):
- ''' tests for pcdl.TimeStep graph related functions. '''
- mcdsts = pcdl.TimeSeries(s_path_3d, verbose=False)
- ## graph related functions ##
- def test_mcdsts_make_ome_tiff_defaultattr_00(self, mcdsts=mcdsts):
- la_ometiff = mcdsts.make_ome_tiff(cell_attribute='ID', conc_cutoff={}, focus=None, file=False, collapse=False)
+## simularium time series related functions ##
+
+class TestTimeSeries3dSimularium(object):
+ ''' test for pcdl.TimeSeries class. '''
+
+ ## get_simularium command ##
+ def test_mcdsts_get_simularium_default(self):
+ import simulariumio as sim
+ mcdsts = pcdl.TimeSeries(s_path_3d, verbose=False)
+ s_pathfile = mcdsts.make_simularium(focus_cat=['cell_type','current_phase'], trajectory_title='timeseries', scale_factor=None, camera_defaults=None, model_meta_data=None)
assert(str(type(mcdsts)) == "") and \
- (type(la_ometiff) is list) and \
- (type(la_ometiff[0]) is np.ndarray) and \
- (type(la_ometiff[-1]) is np.ndarray) and \
- (la_ometiff[0].dtype == np.float32) and \
- (la_ometiff[-1].dtype == np.float32) and \
- (la_ometiff[0].shape == (4, 11, 200, 300)) and \
- (la_ometiff[-1].shape == (4, 11, 200, 300)) and \
- (len(la_ometiff) == 25)
+ (s_pathfile.endswith('/pcdl/output_3d/timeseries.simularium')) and \
+ (os.path.exists(s_pathfile))
+ os.remove(s_pathfile)
- def test_mcdsts_make_ome_tiff_defaultattr_01(self, mcdsts=mcdsts):
- a_ometiff = mcdsts.make_ome_tiff(cell_attribute='ID', conc_cutoff={}, focus=None, file=False, collapse=True)
+ def test_mcdsts_get_simularium_nondefault(self):
+ import simulariumio as sim
+ mcdsts = pcdl.TimeSeries(s_path_3d, verbose=False)
+ s_pathfile = mcdsts.make_simularium(focus_cat=['current_phase', 'dead'], trajectory_title='zeitreihe', scale_factor=0.1, camera_defaults=sim.CameraData(), model_meta_data=sim.ModelMetaData())
assert(str(type(mcdsts)) == "") and \
- (type(a_ometiff) is np.ndarray) and \
- (a_ometiff.dtype == np.float32) and \
- (a_ometiff.shape == (25, 4, 11, 200, 300))
+ (s_pathfile.endswith('/pcdl/output_3d/zeitreihe.simularium')) and \
+ (os.path.exists(s_pathfile))
+ os.remove(s_pathfile)
+
+
+## muspan time series related functions ##
+
+class TestTimeSeries3dMuspan(object):
+ ''' test for pcdl.TimeSeries class. '''
+
+ ## get_muspan command ##
+ def test_mcdsts_get_muspan_default(self):
+ try:
+ import muspan as ms
+ mcdsts = pcdl.TimeSeries(s_path_3d, verbose=False)
+ do_domain = mcdsts.get_muspan(z_slice=None, values=1, drop=set(), keep=set())
+ s_key = sorted(do_domain.keys())[-1]
+ assert(str(type(mcdsts)) == "") and \
+ (type(do_domain) == dict) and \
+ (len(do_domain) == 275) and \
+ (str(type(do_domain[s_key])) == "") and \
+ (len(do_domain[s_key].collections) == 2) and \
+ (len(do_domain[s_key].networks) == 3) and \
+ (len(do_domain[s_key].objects) > 9)
+ except ModuleNotFoundError:
+ print('Warning @ pytest TestTimeSeries3dMuspan : muspan module not installed.')
+ assert True
+ except SystemExit:
+ print('Warning @ pytest TestTimeSeries3dMuspan : muspan module not installed.')
+ assert True
+
+ def test_mcdsts_get_muspan_zslice(self):
+ try:
+ import muspan as ms
+ mcdsts = pcdl.TimeSeries(s_path_3d, verbose=False)
+ do_domain = mcdsts.get_muspan(z_slice=0.0, values=1, drop=set(), keep=set())
+ s_key = sorted(do_domain.keys())[-1]
+ assert(str(type(mcdsts)) == "") and \
+ (type(do_domain) == dict) and \
+ (len(do_domain) == 25) and \
+ (str(type(do_domain[s_key])) == "") and \
+ (len(do_domain[s_key].collections) == 2) and \
+ (len(do_domain[s_key].networks) == 3) and \
+ (len(do_domain[s_key].objects) > 9)
+ except ModuleNotFoundError:
+ print('Warning @ pytest TestTimeSeries3dMuspan : muspan module not installed.')
+ assert True
+ except SystemExit:
+ print('Warning @ pytest TestTimeSeries3dMuspan : muspan module not installed.')
+ assert True
+
+
+## spatialdata time seris related functions ##
+class TestTimeSeries3dSpatialData(object):
+ ''' test for pcdl.TestSeries class. '''
+
+ # get_sdmcds_list {integrated}
+ # get_cell_attributes ok
+ # get_get_spatialdata ok
+ # keep_mcds {True, _False_}
+
+ def test_mcdsts_get_spatialdata_default(self):
+ mcdsts = pcdl.TimeSeries(s_path_3d, verbose=True)
+ lo_sdmcds_output = mcdsts.get_spatialdata(images={'subs'}, labels=set(), points={'subs'}, shapes={'cell'}, values=1, drop=set(), keep=set(), scale='maxabs', keep_mcds=True)
+ lo_sdmcds_memory = mcdsts.get_sdmcds_list()
+ assert(str(type(mcdsts)) == "") and \
+ (len(mcdsts.l_mcds) == 25) and \
+ (len(mcdsts.l_sdmcds) == 25) and \
+ (lo_sdmcds_output == mcdsts.l_sdmcds) and \
+ (lo_sdmcds_output == lo_sdmcds_memory) and \
+ (str(type(lo_sdmcds_output[8])) == "")
+
+ def test_mcdsts_get_spatialdata_keepmcdsfalse(self):
+ mcdsts = pcdl.TimeSeries(s_path_3d, verbose=True)
+ lo_sdmcds_output = mcdsts.get_spatialdata(images={'subs'}, labels=set(), points={'subs'}, shapes={'cell'}, values=1, drop=set(), keep=set(), scale='maxabs', keep_mcds=False)
+ lo_sdmcds_memory = mcdsts.get_sdmcds_list()
+ assert(str(type(mcdsts)) == "") and \
+ (len(mcdsts.l_mcds) == 0) and \
+ (len(mcdsts.l_sdmcds) == 25) and \
+ (lo_sdmcds_output == mcdsts.l_sdmcds) and \
+ (lo_sdmcds_output == lo_sdmcds_memory) and \
+ (str(type(lo_sdmcds_output[8])) == "")
## time series related functions ##
@@ -780,169 +949,27 @@ def test_mcdsts_plot_timeseries_none_none_yunit_conc_fig(self, mcdsts=mcdsts):
plt.close()
-## anndata time series related functions ##
-class TestTimeSeries3dAnnData(object):
- ''' test for pcdl.TestSeries class. '''
-
- # get_anndata
- # get_annmcds_list {integrated}
- # value {1, _2_}
- # collaps {True, _False_}
- # keep_mcds {True, _False_}
-
- ## get_anndata command ##
- def test_mcdsts_get_anndata(self):
- mcdsts = pcdl.TimeSeries(s_path_3d, verbose=True)
- ann = mcdsts.get_anndata(values=1, drop=set(), keep=set(), scale='maxabs', collapse=True, keep_mcds=True)
- l_annmcds = mcdsts.get_annmcds_list()
- assert(str(type(mcdsts)) == "") and \
- (len(mcdsts.l_mcds) == 25) and \
- (l_annmcds == mcdsts.l_annmcds) and \
- (mcdsts.l_annmcds is None) and \
- (str(type(ann)) == "") and \
- (ann.X.shape[0] > 9) and \
- (ann.X.shape[1] == 105) and \
- (ann.obs.shape[0] > 9) and \
- (ann.obs.shape[1] == 8) and \
- (ann.obsm['spatial'].shape[0] > 9) and \
- (ann.obsm['spatial'].shape[1] == 3) and \
- (len(ann.obsp) == 0) and \
- (ann.var.shape == (105, 0)) and \
- (len(ann.uns) == 0)
-
- def test_mcdsts_get_anndata_value(self):
- mcdsts = pcdl.TimeSeries(s_path_3d, verbose=True)
- ann = mcdsts.get_anndata(values=2, drop=set(), keep=set(), scale='maxabs', collapse=True, keep_mcds=True)
- l_annmcds = mcdsts.get_annmcds_list()
- assert(str(type(mcdsts)) == "") and \
- (len(mcdsts.l_mcds) == 25) and \
- (l_annmcds == mcdsts.l_annmcds) and \
- (mcdsts.l_annmcds is None) and \
- (str(type(ann)) == "") and \
- (ann.X.shape[0] > 9) and \
- (ann.X.shape[1] == 56) and \
- (ann.obs.shape[0] > 9) and \
- (ann.obs.shape[1] == 7) and \
- (ann.obsm['spatial'].shape[0] > 9) and \
- (ann.obsm['spatial'].shape[1] == 3) and \
- (len(ann.obsp) == 0) and \
- (ann.var.shape == (56, 0)) and \
- (len(ann.uns) == 0)
-
- def test_mcdsts_get_anndata_collapsefalse(self):
- mcdsts = pcdl.TimeSeries(s_path_3d, verbose=True)
- ann = mcdsts.get_anndata(values=1, drop=set(), keep=set(), scale='maxabs', collapse=False, keep_mcds=True)
- l_annmcds = mcdsts.get_annmcds_list()
- assert(str(type(mcdsts)) == "") and \
- (len(mcdsts.l_mcds) == 25) and \
- (l_annmcds == mcdsts.l_annmcds) and \
- (str(type(mcdsts.l_annmcds)) == "") and \
- (len(mcdsts.l_annmcds) == 25) and \
- (all([str(type(ann)) == "" for ann in mcdsts.l_annmcds])) and \
- (mcdsts.l_annmcds[24].X.shape[0] > 9) and \
- (mcdsts.l_annmcds[24].X.shape[1] == 105) and \
- (mcdsts.l_annmcds[24].obs.shape[0] > 9) and \
- (mcdsts.l_annmcds[24].obs.shape[1] == 8) and \
- (mcdsts.l_annmcds[24].obsm['spatial'].shape[0] > 9) and \
- (mcdsts.l_annmcds[24].obsm['spatial'].shape[1] == 3) and \
- (len(mcdsts.l_annmcds[24].obsp) == 4) and \
- (mcdsts.l_annmcds[24].var.shape == (105, 0)) and \
- (len(mcdsts.l_annmcds[24].uns) == 2)
-
- def test_mcdsts_get_anndata_keepmcdsfalse(self):
- mcdsts = pcdl.TimeSeries(s_path_3d, verbose=True)
- ann = mcdsts.get_anndata(values=1, drop=set(), keep=set(), scale='maxabs', collapse=True, keep_mcds=False)
- l_annmcds = mcdsts.get_annmcds_list()
- assert(str(type(mcdsts)) == "") and \
- (len(mcdsts.l_mcds) == 0) and \
- (l_annmcds == mcdsts.l_annmcds) and \
- (mcdsts.l_annmcds is None) and \
- (str(type(ann)) == "") and \
- (ann.X.shape[0] > 9) and \
- (ann.X.shape[1] == 105) and \
- (ann.obs.shape[0] > 9) and \
- (ann.obs.shape[1] == 8) and \
- (ann.obsm['spatial'].shape[0] > 9) and \
- (ann.obsm['spatial'].shape[1] == 3) and \
- (len(ann.obsp) == 0) and \
- (ann.var.shape == (105, 0)) and \
- (len(ann.uns) == 0)
-
-
-## muspan time series related functions ##
-class TestTimeSeriesMuspan(object):
- ''' test for pcdl.TimeSeries class. '''
-
- ## get_muspan command ##
- def test_mcdsts_get_muspan_default(self):
- try:
- import muspan as ms
- mcdsts = pcdl.TimeSeries(s_path_3d, verbose=False)
- do_domain = mcdsts.get_muspan(z_slice=None, values=1, drop=set(), keep=set())
- s_key = sorted(do_domain.keys())[-1]
- assert(str(type(mcdsts)) == "") and \
- (type(do_domain) == dict) and \
- (len(do_domain) == 275) and \
- (str(type(do_domain[s_key])) == "") and \
- (len(do_domain[s_key].collections) == 2) and \
- (len(do_domain[s_key].networks) == 3) and \
- (len(do_domain[s_key].objects) > 9)
- except ModuleNotFoundError:
- print('Warning @ pytest TestTimeSeriesMuspan : muspan module not installed.')
- assert True
- except SystemExit:
- print('Warning @ pytest TestTimeSeriesMuspan : muspan module not installed.')
- assert True
-
- def test_mcdsts_get_muspan_zslice(self):
- try:
- import muspan as ms
- mcdsts = pcdl.TimeSeries(s_path_3d, verbose=False)
- do_domain = mcdsts.get_muspan(z_slice=0.0, values=1, drop=set(), keep=set())
- s_key = sorted(do_domain.keys())[-1]
- assert(str(type(mcdsts)) == "") and \
- (type(do_domain) == dict) and \
- (len(do_domain) == 25) and \
- (str(type(do_domain[s_key])) == "") and \
- (len(do_domain[s_key].collections) == 2) and \
- (len(do_domain[s_key].networks) == 3) and \
- (len(do_domain[s_key].objects) > 9)
- except ModuleNotFoundError:
- print('Warning @ pytest TestTimeSeriesMuspan : muspan module not installed.')
- assert True
- except SystemExit:
- print('Warning @ pytest TestTimeSeriesMuspan : muspan module not installed.')
- assert True
-
-
-## spatialdata time seris related functions ##
-class TestTimeSeriesSpatialData(object):
- ''' test for pcdl.TestSeries class. '''
-
- # get_sdmcds_list {integrated}
- # get_cell_attributes ok
- # get_get_spatialdata ok
- # keep_mcds {True, _False_}
+## ome.tiff related functions ##
+class TestTimeSeries3dOmeTiff(object):
+ ''' tests for pcdl.TimeStep graph related functions. '''
+ mcdsts = pcdl.TimeSeries(s_path_3d, verbose=False)
- def test_mcdsts_get_spatialdata_default(self):
- mcdsts = pcdl.TimeSeries(s_path_3d, verbose=True)
- lo_sdmcds_output = mcdsts.get_spatialdata(images={'subs'}, labels=set(), points={'subs'}, shapes={'cell'}, values=1, drop=set(), keep=set(), scale='maxabs', keep_mcds=True)
- lo_sdmcds_memory = mcdsts.get_sdmcds_list()
+ ## graph related functions ##
+ def test_mcdsts_make_ome_tiff_defaultattr_00(self, mcdsts=mcdsts):
+ la_ometiff = mcdsts.make_ome_tiff(cell_attribute='ID', conc_cutoff={}, focus=None, file=False, collapse=False)
assert(str(type(mcdsts)) == "") and \
- (len(mcdsts.l_mcds) == 25) and \
- (len(mcdsts.l_sdmcds) == 25) and \
- (lo_sdmcds_output == mcdsts.l_sdmcds) and \
- (lo_sdmcds_output == lo_sdmcds_memory) and \
- (str(type(lo_sdmcds_output[8])) == "")
+ (type(la_ometiff) is list) and \
+ (type(la_ometiff[0]) is np.ndarray) and \
+ (type(la_ometiff[-1]) is np.ndarray) and \
+ (la_ometiff[0].dtype == np.float32) and \
+ (la_ometiff[-1].dtype == np.float32) and \
+ (la_ometiff[0].shape == (4, 11, 200, 300)) and \
+ (la_ometiff[-1].shape == (4, 11, 200, 300)) and \
+ (len(la_ometiff) == 25)
- def test_mcdsts_get_spatialdata_keepmcdsfalse(self):
- mcdsts = pcdl.TimeSeries(s_path_3d, verbose=True)
- lo_sdmcds_output = mcdsts.get_spatialdata(images={'subs'}, labels=set(), points={'subs'}, shapes={'cell'}, values=1, drop=set(), keep=set(), scale='maxabs', keep_mcds=False)
- lo_sdmcds_memory = mcdsts.get_sdmcds_list()
+ def test_mcdsts_make_ome_tiff_defaultattr_01(self, mcdsts=mcdsts):
+ a_ometiff = mcdsts.make_ome_tiff(cell_attribute='ID', conc_cutoff={}, focus=None, file=False, collapse=True)
assert(str(type(mcdsts)) == "") and \
- (len(mcdsts.l_mcds) == 0) and \
- (len(mcdsts.l_sdmcds) == 25) and \
- (lo_sdmcds_output == mcdsts.l_sdmcds) and \
- (lo_sdmcds_output == lo_sdmcds_memory) and \
- (str(type(lo_sdmcds_output[8])) == "")
-
+ (type(a_ometiff) is np.ndarray) and \
+ (a_ometiff.dtype == np.float32) and \
+ (a_ometiff.shape == (25, 4, 11, 200, 300))
diff --git a/test/test_timestep_2d.py b/test/test_timestep_2d.py
index 6fa64e5..0183c90 100644
--- a/test/test_timestep_2d.py
+++ b/test/test_timestep_2d.py
@@ -38,9 +38,50 @@
pcdl.install_data()
+## neuroglancer rendering realted function
+
+class TestTimeStep2dNeuroglancer(object):
+ ''' tests for loading a pcdl.TimeStep data set. '''
+ mcds = pcdl.TimeStep(xmlfile=s_file_2d, output_path=s_path_2d, custom_data_type={}, microenv=True, graph=True, physiboss=True, settingxml='PhysiCell_settings.xml', verbose=True)
+
+ ## make_gif and magick ommand ##
+ def test_mcds_render_neuroglancer_default(self, mcds=mcds):
+ s_tiffpathfile = mcds.make_ome_tiff()
+ o_viewer = mcds.render_neuroglancer(
+ tiffpathfile = s_tiffpathfile,
+ #timestep = 0,
+ #intensity_cmap='gray',
+ )
+ assert(str(type(o_viewer)) == "") and \
+ (str(o_viewer).startswith('http://127.0.0.1:'))
+ os.remove(s_tiffpathfile)
+
+ def test_mcds_render_neuroglancer_timestep(self, mcds=mcds):
+ s_tiffpathfile = mcds.make_ome_tiff()
+ o_viewer = mcds.render_neuroglancer(
+ tiffpathfile = s_tiffpathfile,
+ timestep = -1,
+ intensity_cmap='gray',
+ )
+ assert(str(type(o_viewer)) == "") and \
+ (str(o_viewer).startswith('http://127.0.0.1:'))
+ os.remove(s_tiffpathfile)
+
+ def test_mcds_render_neuroglancer_cmap(self, mcds=mcds):
+ s_tiffpathfile = mcds.make_ome_tiff()
+ o_viewer = mcds.render_neuroglancer(
+ tiffpathfile = s_tiffpathfile,
+ timestep = 0,
+ intensity_cmap='magma',
+ )
+ assert(str(type(o_viewer)) == "") and \
+ (str(o_viewer).startswith('http://127.0.0.1:'))
+ os.remove(s_tiffpathfile)
+
+
## data loading related functions ##
-class TestTimeStepInit(object):
+class TestTimeStep2dInit(object):
''' tests for loading a pcdl.TimeStep data set. '''
mcds = pcdl.TimeStep(xmlfile=s_file_2d, output_path=s_path_2d, custom_data_type={}, microenv=True, graph=True, physiboss=True, settingxml='PhysiCell_settings.xml', verbose=True)
df_cell = mcds.get_cell_df()
@@ -69,7 +110,17 @@ def test_mcds_init_settingxml(self, mcds=mcds, df_cell=df_cell):
(df_cell.shape[1] == 122)
-class TestTimeStepInitMicroenvFalse(object):
+class TestTimeStep2dInitCustomdataastype(object):
+ ''' tests for loading a pcdl.TimeStep data and run custom_data_astype function. '''
+ mcds = pcdl.TimeStep(xmlfile=s_file_2d, output_path=s_path_2d, custom_data_type={}, microenv=True, graph=True, physiboss=True, settingxml='PhysiCell_settings.xml', verbose=True)
+
+ def test_mcds_custom_data_astype(self, mcds=mcds):
+ mcds.custom_data_astype({'sample': bool})
+ assert(str(type(mcds)) == "") and \
+ (mcds.data['cell']['df_cell']['sample'].dtype == bool)
+
+
+class TestTimeStep2dInitMicroenvFalse(object):
''' tests for loading a pcdl.TimeStep data set with microenv false. '''
mcds = pcdl.TimeStep(xmlfile=s_file_2d, output_path=s_path_2d, custom_data_type={}, microenv=False, graph=True, physiboss=True, settingxml='PhysiCell_settings.xml', verbose=True)
df_cell = mcds.get_cell_df()
@@ -98,7 +149,7 @@ def test_mcds_init_settingxml(self, mcds=mcds, df_cell=df_cell):
(df_cell.shape[1] == 116)
-class TestTimeStepInitGraphFalse(object):
+class TestTimeStep2dInitGraphFalse(object):
''' tests for loading a pcdl.TimeStep data set with graph false. '''
mcds = pcdl.TimeStep(xmlfile=s_file_2d, output_path=s_path_2d, custom_data_type={}, microenv=True, graph=False, physiboss=True, settingxml='PhysiCell_settings.xml', verbose=True)
df_cell = mcds.get_cell_df()
@@ -127,7 +178,7 @@ def test_mcds_init_settingxml(self, mcds=mcds, df_cell=df_cell):
(df_cell.shape[1] == 122)
-class TestTimeStepInitPhysibossFalse(object):
+class TestTimeStep2dInitPhysibossFalse(object):
''' tests for loading a pcdl.TimeStep data set with physiboss false. '''
mcds = pcdl.TimeStep(xmlfile=s_file_2d, output_path=s_path_2d, custom_data_type={}, microenv=True, graph=True, physiboss=False, settingxml='PhysiCell_settings.xml', verbose=True)
df_cell = mcds.get_cell_df()
@@ -156,7 +207,7 @@ def test_mcds_init_settingxml(self, mcds=mcds, df_cell=df_cell):
(df_cell.shape[1] == 122)
-class TestTimeStepInitSettingxmlFalse(object):
+class TestTimeStep2dInitSettingxmlFalse(object):
''' tests for loading a pcdl.TimeStep data set with settingxml false. '''
mcds = pcdl.TimeStep(xmlfile=s_file_2d, output_path=s_path_2d, custom_data_type={}, microenv=True, graph=True, physiboss=True, settingxml=False, verbose=True)
df_cell = mcds.get_cell_df()
@@ -185,7 +236,7 @@ def test_mcds_init_settingxml(self, mcds=mcds, df_cell=df_cell):
(df_cell.shape[1] == 122)
-class TestTimeStepInitSettingxmlNone(object):
+class TestTimeStep2dInitSettingxmlNone(object):
''' tests for loading a pcdl.TimeStep data set with settingxml none. '''
mcds = pcdl.TimeStep(xmlfile=s_file_2d, output_path=s_path_2d, custom_data_type={}, microenv=True, graph=True, physiboss=True, settingxml=None, verbose=True)
df_cell = mcds.get_cell_df()
@@ -214,17 +265,7 @@ def test_mcds_init_settingxml(self, mcds=mcds, df_cell=df_cell):
(df_cell.shape[1] == 122)
-class TestTimeStepInitCustomdataastype(object):
- ''' tests for loading a pcdl.TimeStep data and run custom_data_astype function. '''
- mcds = pcdl.TimeStep(xmlfile=s_file_2d, output_path=s_path_2d, custom_data_type={}, microenv=True, graph=True, physiboss=True, settingxml='PhysiCell_settings.xml', verbose=True)
-
- def test_mcds_custom_data_astype(self, mcds=mcds):
- mcds.custom_data_astype({'sample': bool})
- assert(str(type(mcds)) == "") and \
- (mcds.data['cell']['df_cell']['sample'].dtype == bool)
-
-
-class TestTimeStepInitVerboseTrue(object):
+class TestTimeStep2dInitVerboseTrue(object):
''' tests for loading a pcdl.TimeStep data set and set_verbose_false function. '''
mcds = pcdl.TimeStep(xmlfile=s_file_2d, output_path=s_path_2d, custom_data_type={}, microenv=True, graph=True, physiboss=True, settingxml='PhysiCell_settings.xml', verbose=True)
@@ -238,7 +279,7 @@ def test_mcds_set_verbose_false(self, mcds=mcds):
(not mcds.verbose)
-class TestTimeStepInitVerboseFalse(object):
+class TestTimeStep2dInitVerboseFalse(object):
''' tests for loading a pcdl.TimeStep data set and set_verbose_true function. '''
mcds = pcdl.TimeStep(xmlfile=s_file_2d, output_path=s_path_2d, custom_data_type={}, microenv=True, graph=True, physiboss=True, settingxml='PhysiCell_settings.xml', verbose=False)
@@ -254,7 +295,7 @@ def test_mcds_set_verbose_true(self, mcds=mcds):
## metadata related functions ##
-class TestTimeStepMetadata(object):
+class TestTimeStep2dMetadata(object):
''' tests for pcdl.TimeStep metadata related functions. '''
mcds = pcdl.TimeStep(xmlfile=s_file_2d, output_path=s_path_2d, custom_data_type={}, microenv=True, graph=True, physiboss=True, settingxml='PhysiCell_settings.xml', verbose=True)
@@ -295,9 +336,9 @@ def test_mcds_get_runtime(self, mcds=mcds):
(r_runtime == 1.952156)
-## setting related functions ##
+## parameter setting related functions ##
-class TestTimeStepSetting(object):
+class TestTimeStep2dUnitdict(object):
''' tests for pcdl.TimeStep setting related functions. '''
mcds = pcdl.TimeStep(xmlfile=s_file_2d, output_path=s_path_2d, custom_data_type={}, microenv=True, graph=True, physiboss=True, settingxml='PhysiCell_settings.xml', verbose=True)
@@ -311,7 +352,7 @@ def test_mcds_get_unit_dict(self, mcds=mcds):
## mesh related functions ##
-class TestTimeStepMesh(object):
+class TestTimeStep2dMesh(object):
''' tests for pcdl.TimeStep mesh related functions. '''
mcds = pcdl.TimeStep(xmlfile=s_file_2d, output_path=s_path_2d, custom_data_type={}, microenv=True, graph=True, physiboss=True, settingxml='PhysiCell_settings.xml', verbose=True)
@@ -399,12 +440,6 @@ def test_mcds_get_mesh_coordinate(self, mcds=mcds):
(set(aar_voxel[1]) == er_n_cube) and \
(set(aar_voxel[2]) == er_p_cube)
- def test_mcds_get_voxel_volume(self, mcds=mcds):
- r_volume = mcds.get_voxel_volume()
- assert(str(type(mcds)) == "") and \
- (str(type(r_volume)) == "") and \
- (r_volume == 6000.0)
-
# bue: check else in 3D
def test_mcds_get_mesh_spacing(self, mcds=mcds):
lr_spacing = mcds.get_mesh_spacing()
@@ -415,14 +450,6 @@ def test_mcds_get_mesh_spacing(self, mcds=mcds):
(str(type(lr_spacing[-1])) == "") and \
(lr_spacing == [30.0, 20.0, 10.0])
- def test_mcds_get_voxel_spacing(self, mcds=mcds):
- lr_spacing = mcds.get_voxel_spacing()
- assert(str(type(mcds)) == "") and \
- (str(type(lr_spacing)) == "") and \
- (str(type(lr_spacing[0])) == "") and \
- (str(type(lr_spacing[-1])) == "") and \
- (lr_spacing == [30.0, 20.0, 10.0])
-
def test_mcds_is_in_mesh(self, mcds=mcds):
assert(str(type(mcds)) == "") and \
(mcds.is_in_mesh(x=0, y=0, z=0, halt=False)) and \
@@ -443,6 +470,20 @@ def test_mcds_get_mesh_mnp(self, mcds=mcds):
(li_mesh_2 == [15.0, 10.0, 0.0]) and \
(li_mesh_none is None)
+ def test_mcds_get_voxel_spacing(self, mcds=mcds):
+ lr_spacing = mcds.get_voxel_spacing()
+ assert(str(type(mcds)) == "") and \
+ (str(type(lr_spacing)) == "") and \
+ (str(type(lr_spacing[0])) == "") and \
+ (str(type(lr_spacing[-1])) == "") and \
+ (lr_spacing == [30.0, 20.0, 10.0])
+
+ def test_mcds_get_voxel_volume(self, mcds=mcds):
+ r_volume = mcds.get_voxel_volume()
+ assert(str(type(mcds)) == "") and \
+ (str(type(r_volume)) == "") and \
+ (r_volume == 6000.0)
+
def test_mcds_get_voxel_ijk(self, mcds=mcds):
li_voxel_0 = mcds.get_voxel_ijk(x=0, y=0, z=0, is_in_mesh=True) # if b_calc
li_voxel_1 = mcds.get_voxel_ijk(x=15, y=10, z=0, is_in_mesh=True) # if b_calc
@@ -459,11 +500,11 @@ def test_mcds_get_voxel_ijk(self, mcds=mcds):
## micro environment related functions ##
-class TestTimeStepMicroenv(object):
+class TestTimeStep2dMicroenv(object):
''' tests for pcdl.TimeStep micro environment related functions. '''
mcds = pcdl.TimeStep(xmlfile=s_file_2d, output_path=s_path_2d, custom_data_type={}, microenv=True, graph=True, physiboss=True, settingxml='PhysiCell_settings.xml', verbose=True)
- def test_mcds_get_substrate_name(self, mcds=mcds):
+ def test_mcds_get_substrate_list(self, mcds=mcds):
ls_substrate = mcds.get_substrate_list()
assert(str(type(mcds)) == "") and \
(str(type(ls_substrate)) == "") and \
@@ -580,19 +621,13 @@ def test_mcds_make_conc_vtk(self, mcds=mcds):
(os.path.getsize(s_pathfile) > 2**10)
os.remove(s_pathfile)
+
## cell related functions ##
-class TestTimeStepCell(object):
+class TestTimeStep2dCell(object):
''' tests for pcdl.TimeStep cell related functions. '''
mcds = pcdl.TimeStep(xmlfile=s_file_2d, output_path=s_path_2d, custom_data_type={}, microenv=True, graph=True, physiboss=True, settingxml='PhysiCell_settings.xml', verbose=True)
- def test_mcds_get_cell_attribute_list(self, mcds=mcds):
- ls_cellattr = mcds.get_cell_attribute_list()
- assert(str(type(mcds)) == "") and \
- (str(type(ls_cellattr)) == "") and \
- (str(type(ls_cellattr[0])) == "") and \
- (len(ls_cellattr) == 110)
-
def test_mcds_get_celltype_list(self, mcds=mcds):
ls_celltype = mcds.get_celltype_list()
assert(str(type(mcds)) == "") and \
@@ -635,6 +670,13 @@ def test_mcds_get_cell_df_keep(self, mcds=mcds):
(df_cell.shape[0] > 9) and \
(df_cell.shape[1] == 13)
+ def test_mcds_get_cell_attribute_list(self, mcds=mcds):
+ ls_cellattr = mcds.get_cell_attribute_list()
+ assert(str(type(mcds)) == "") and \
+ (str(type(ls_cellattr)) == "") and \
+ (str(type(ls_cellattr[0])) == "") and \
+ (len(ls_cellattr) == 110)
+
# scatter categorical
def test_mcds_plot_scatter_cat_if(self, mcds=mcds):
fig = mcds.plot_scatter(
@@ -806,9 +848,63 @@ def test_mcds_make_cell_vtk_attribute_many(self, mcds=mcds):
os.remove(s_pathfile)
+## anndata time step related functions ##
+
+class TestTimeStep2dAnnData(object):
+ ''' test for pcdl.TimeStep class. '''
+
+ ## get_anndata command ##
+ def test_mcds_get_anndata(self):
+ mcds = pcdl.TimeStep(s_pathfile_2d, verbose=False)
+ ann = mcds.get_anndata(values=1, drop=set(), keep=set(), scale='maxabs')
+ assert(str(type(mcds)) == "") and \
+ (str(type(ann)) == "") and \
+ (ann.X.shape[0] > 9) and \
+ (ann.X.shape[1] == 105) and \
+ (ann.obs.shape[0] > 9) and \
+ (ann.obs.shape[1] == 8) and \
+ (ann.obsm['spatial'].shape[0] > 9) and \
+ (ann.obsm['spatial'].shape[1] == 2) and \
+ (len(ann.obsp) == 4) and \
+ (ann.var.shape == (105, 0)) and \
+ (len(ann.uns) == 2)
+
+
+class TestTimeStep2dScaler(object):
+ ''' test for pcdl.scaler function '''
+ a_x = np.array([[ 1.,-1., 2., 0.],[ 2., 0., 0.,0.],[ 0., 1.,-1.,0.]])
+ df_x = pd.DataFrame(a_x, columns=['a','b','c','d'])
+
+ def test_scaler_none(self, df_x=df_x):
+ df_scaled = pcdl.timestep.scaler(df_x=df_x, scale=None)
+ assert(str(type(df_scaled)) == "") and \
+ (all(df_scaled == df_x))
+
+ def test_scaler_minabs(self, df_x=df_x):
+ df_scaled = pcdl.timestep.scaler(df_x=df_x, scale='maxabs')
+ assert(str(type(df_scaled)) == "") and \
+ (df_scaled.values.sum().round(3) == 2.0) and \
+ (df_scaled.values.min().round(3) == -1.0) and \
+ (df_scaled.values.max().round(3) == 1.0)
+
+ def test_scaler_minmax(self, df_x=df_x):
+ df_scaled = pcdl.timestep.scaler(df_x=df_x, scale='minmax')
+ assert(str(type(df_scaled)) == "") and \
+ (df_scaled.values.sum().round(3) == 4.333) and \
+ (df_scaled.values.min().round(3) == 0.0) and \
+ (df_scaled.values.max().round(3) == 1.0)
+
+ def test_scaler_std(self, df_x=df_x):
+ df_scaled = pcdl.timestep.scaler(df_x=df_x, scale='std')
+ assert(str(type(df_scaled)) == "") and \
+ (df_scaled.values.sum().round(3) == 0.0) and \
+ (df_scaled.values.min().round(3) == -1.0) and \
+ (df_scaled.values.max().round(3) == 1.091)
+
+
## graph related functions ##
-class TestTimeStepGraph(object):
+class TestTimeStep2dGraph(object):
''' tests for pcdl.TimeStep graph related functions. '''
mcds = pcdl.TimeStep(xmlfile=s_file_2d, output_path=s_path_2d, custom_data_type={}, microenv=True, graph=True, physiboss=True, settingxml='PhysiCell_settings.xml', verbose=True)
@@ -933,178 +1029,9 @@ def test_mcds_make_graph_gml_neighbor_nodeattrtrue(self, mcds=mcds):
os.remove(s_pathfile)
-## ome tiff related functions ##
-
-class TestTimeStepOmeTiff(object):
- ''' tests for pcdl.TimeStep graph related functions. '''
- mcds = pcdl.TimeStep(xmlfile=s_file_2d, output_path=s_path_2d, custom_data_type={}, microenv=True, graph=True, physiboss=True, settingxml='PhysiCell_settings.xml', verbose=True)
-
- ## ome tiff related functions ##
- def test_mcds_make_ome_tiff_default(self, mcds=mcds):
- s_pathfile = mcds.make_ome_tiff(cell_attribute='ID', conc_cutoff={}, focus=None, file=True)
- assert(str(type(mcds)) == "") and \
- (s_pathfile.replace('\\','/').endswith('pcdl/output_2d/output00000024_oxygen_water_default_blood_cells_ID.ome.tiff')) and \
- (os.path.exists(s_pathfile)) and \
- (os.path.getsize(s_pathfile) > 2**10)
- os.remove(s_pathfile)
-
- def test_mcds_make_ome_tiff_bool(self, mcds=mcds):
- a_ometiff = mcds.make_ome_tiff(cell_attribute='dead', conc_cutoff={}, focus=None, file=False)
- assert(str(type(mcds)) == "") and \
- (str(type(a_ometiff)) == "") and \
- (a_ometiff.dtype == np.float32) and \
- (a_ometiff.shape == (4, 1, 200, 300)) and \
- (a_ometiff[2].min() == 0.0) and \
- (a_ometiff[3].min() == 0.0) and \
- (a_ometiff[0].max() >= 1.0) and \
- (a_ometiff[1].max() >= 1.0) and \
- (a_ometiff[2].max() >= 1.0) and \
- (a_ometiff[3].max() >= 1.0)
-
- def test_mcds_make_ome_tiff_int(self, mcds=mcds):
- a_ometiff = mcds.make_ome_tiff(cell_attribute='cell_count_voxel', conc_cutoff={}, focus=None, file=False)
- assert(str(type(mcds)) == "") and \
- (str(type(a_ometiff)) == "") and \
- (a_ometiff.dtype == np.float32) and \
- (a_ometiff.shape == (4, 1, 200, 300)) and \
- (a_ometiff[2].min() == 0.0) and \
- (a_ometiff[3].min() == 0.0) and \
- (a_ometiff[0].max() >= 1.0) and \
- (a_ometiff[1].max() >= 1.0) and \
- (a_ometiff[2].max() >= 1.0) and \
- (a_ometiff[3].max() >= 1.0)
-
- def test_mcds_make_ome_tiff_float(self, mcds=mcds):
- a_ometiff = mcds.make_ome_tiff(cell_attribute='pressure', conc_cutoff={}, focus=None, file=False)
- assert(str(type(mcds)) == "") and \
- (str(type(a_ometiff)) == "") and \
- (a_ometiff.dtype == np.float32) and \
- (a_ometiff.shape == (4, 1, 200, 300)) and\
- (a_ometiff[2].min() == 0.0) and \
- (a_ometiff[3].min() == 0.0) and \
- (a_ometiff[0].max() >= 1.0) and \
- (a_ometiff[1].max() >= 1.0) and \
- (a_ometiff[2].max() >= 1.0) and \
- (a_ometiff[3].max() >= 1.0)
-
- def test_mcds_make_ome_tiff_conccutoff(self, mcds=mcds):
- a_ometiff = mcds.make_ome_tiff(cell_attribute='ID', conc_cutoff={'oxygen': -1}, focus=None, file=False)
- assert(str(type(mcds)) == "") and \
- (str(type(a_ometiff)) == "") and \
- (a_ometiff.dtype == np.float32) and \
- (a_ometiff.shape == (4, 1, 200, 300)) and \
- (a_ometiff[2].min() == 0.0) and \
- (a_ometiff[3].min() == 0.0) and \
- (a_ometiff[0].max() >= 1.0) and \
- (a_ometiff[1].max() >= 1.0) and \
- (a_ometiff[2].max() >= 1.0) and \
- (a_ometiff[3].max() >= 1.0)
-
- def test_mcds_make_ome_tiff_focus(self, mcds=mcds):
- a_ometiff = mcds.make_ome_tiff(cell_attribute='ID', conc_cutoff={}, focus={'default'}, file=False)
- assert(str(type(mcds)) == "") and \
- (str(type(a_ometiff)) == "") and \
- (a_ometiff.dtype == np.float32) and \
- (a_ometiff.shape == (1, 1, 200, 300)) and \
- (a_ometiff[0].min() == 0.0) and \
- (a_ometiff[0].max() >= 1.0)
-
-
-class TestTimeStepNeuroglancer(object):
- ''' tests for loading a pcdl.TimeStep data set. '''
- mcds = pcdl.TimeStep(xmlfile=s_file_2d, output_path=s_path_2d, custom_data_type={}, microenv=True, graph=True, physiboss=True, settingxml='PhysiCell_settings.xml', verbose=True)
-
- ## make_gif and magick ommand ##
- def test_mcds_render_neuroglancer_default(self, mcds=mcds):
- s_tiffpathfile = mcds.make_ome_tiff()
- o_viewer = mcds.render_neuroglancer(
- tiffpathfile = s_tiffpathfile,
- #timestep = 0,
- #intensity_cmap='gray',
- )
- assert(str(type(o_viewer)) == "") and \
- (str(o_viewer).startswith('http://127.0.0.1:'))
- os.remove(s_tiffpathfile)
-
- def test_mcds_render_neuroglancer_timestep(self, mcds=mcds):
- s_tiffpathfile = mcds.make_ome_tiff()
- o_viewer = mcds.render_neuroglancer(
- tiffpathfile = s_tiffpathfile,
- timestep = -1,
- intensity_cmap='gray',
- )
- assert(str(type(o_viewer)) == "") and \
- (str(o_viewer).startswith('http://127.0.0.1:'))
- os.remove(s_tiffpathfile)
-
- def test_mcds_render_neuroglancer_cmap(self, mcds=mcds):
- s_tiffpathfile = mcds.make_ome_tiff()
- o_viewer = mcds.render_neuroglancer(
- tiffpathfile = s_tiffpathfile,
- timestep = 0,
- intensity_cmap='magma',
- )
- assert(str(type(o_viewer)) == "") and \
- (str(o_viewer).startswith('http://127.0.0.1:'))
- os.remove(s_tiffpathfile)
-
-
-## anndata helper function ##
-class TestTimeStepScaler(object):
- ''' test for pcdl.scaler function '''
- a_x = np.array([[ 1.,-1., 2., 0.],[ 2., 0., 0.,0.],[ 0., 1.,-1.,0.]])
- df_x = pd.DataFrame(a_x, columns=['a','b','c','d'])
-
- def test_scaler_none(self, df_x=df_x):
- df_scaled = pcdl.timestep.scaler(df_x=df_x, scale=None)
- assert(str(type(df_scaled)) == "") and \
- (all(df_scaled == df_x))
-
- def test_scaler_minabs(self, df_x=df_x):
- df_scaled = pcdl.timestep.scaler(df_x=df_x, scale='maxabs')
- assert(str(type(df_scaled)) == "") and \
- (df_scaled.values.sum().round(3) == 2.0) and \
- (df_scaled.values.min().round(3) == -1.0) and \
- (df_scaled.values.max().round(3) == 1.0)
-
- def test_scaler_minmax(self, df_x=df_x):
- df_scaled = pcdl.timestep.scaler(df_x=df_x, scale='minmax')
- assert(str(type(df_scaled)) == "") and \
- (df_scaled.values.sum().round(3) == 4.333) and \
- (df_scaled.values.min().round(3) == 0.0) and \
- (df_scaled.values.max().round(3) == 1.0)
-
- def test_scaler_std(self, df_x=df_x):
- df_scaled = pcdl.timestep.scaler(df_x=df_x, scale='std')
- assert(str(type(df_scaled)) == "") and \
- (df_scaled.values.sum().round(3) == 0.0) and \
- (df_scaled.values.min().round(3) == -1.0) and \
- (df_scaled.values.max().round(3) == 1.091)
-
-
-## anndata time step related functions ##
-class TestTimeStepAnnData(object):
- ''' test for pcdl.TimeStep class. '''
-
- ## get_anndata command ##
- def test_mcds_get_anndata(self):
- mcds = pcdl.TimeStep(s_pathfile_2d, verbose=False)
- ann = mcds.get_anndata(values=1, drop=set(), keep=set(), scale='maxabs')
- assert(str(type(mcds)) == "") and \
- (str(type(ann)) == "") and \
- (ann.X.shape[0] > 9) and \
- (ann.X.shape[1] == 105) and \
- (ann.obs.shape[0] > 9) and \
- (ann.obs.shape[1] == 8) and \
- (ann.obsm['spatial'].shape[0] > 9) and \
- (ann.obsm['spatial'].shape[1] == 2) and \
- (len(ann.obsp) == 4) and \
- (ann.var.shape == (105, 0)) and \
- (len(ann.uns) == 2)
-
-
## muspan time step related functions ##
-class TestTimeStepMuspan(object):
+
+class TestTimeStep2dMuspan(object):
''' test for pcdl.TimeStep class. '''
## get_muspan command ##
@@ -1122,10 +1049,10 @@ def test_mcds_get_muspan_default(self):
(len(do_domain[s_key].networks) == 3) and \
(len(do_domain[s_key].objects) > 9)
except ModuleNotFoundError:
- print('Warning @ pytest TestTimeStepMuspan : muspan module not installed.')
+ print('Warning @ pytest TestTimeStep2dMuspan : muspan module not installed.')
assert True
except SystemExit:
- print('Warning @ pytest TestTimeStepMuspan : muspan module not installed.')
+ print('Warning @ pytest TestTimeStep2dMuspan : muspan module not installed.')
assert True
def test_mcds_get_muspan_zslice(self):
@@ -1142,15 +1069,16 @@ def test_mcds_get_muspan_zslice(self):
(len(do_domain[s_key].networks) == 3) and \
(len(do_domain[s_key].objects) > 9)
except ModuleNotFoundError:
- print('Warning @ pytest TestTimeStepMuspan : muspan module not installed.')
+ print('Warning @ pytest TestTimeStep2dMuspan : muspan module not installed.')
assert True
except SystemExit:
- print('Warning @ pytest TestTimeStepMuspan : muspan module not installed.')
+ print('Warning @ pytest TestTimeStep2dMuspan : muspan module not installed.')
assert True
## spatialdata time step related functions ##
-class TestTimeStepSpatialData(object):
+
+class TestTimeStep2dSpatialData(object):
''' test for pcdl.TimeStep class. '''
## get_spatialdata command ##
@@ -1213,3 +1141,80 @@ def test_mcds_get_spatialdata_none(self):
(sdata['subs_table'].shape[1] ==2) and \
(sdata['subs_table'].obs.shape[0] > 9) and \
(sdata['subs_table'].obs.shape[1] == 11)
+
+
+## ome tiff related functions ##
+
+class TestTimeStep2dOmeTiff(object):
+ ''' tests for pcdl.TimeStep graph related functions. '''
+ mcds = pcdl.TimeStep(xmlfile=s_file_2d, output_path=s_path_2d, custom_data_type={}, microenv=True, graph=True, physiboss=True, settingxml='PhysiCell_settings.xml', verbose=True)
+
+ ## ome tiff related functions ##
+ def test_mcds_make_ome_tiff_default(self, mcds=mcds):
+ s_pathfile = mcds.make_ome_tiff(cell_attribute='ID', conc_cutoff={}, focus=None, file=True)
+ assert(str(type(mcds)) == "") and \
+ (s_pathfile.replace('\\','/').endswith('pcdl/output_2d/output00000024_oxygen_water_default_blood_cells_ID.ome.tiff')) and \
+ (os.path.exists(s_pathfile)) and \
+ (os.path.getsize(s_pathfile) > 2**10)
+ os.remove(s_pathfile)
+
+ def test_mcds_make_ome_tiff_bool(self, mcds=mcds):
+ a_ometiff = mcds.make_ome_tiff(cell_attribute='dead', conc_cutoff={}, focus=None, file=False)
+ assert(str(type(mcds)) == "") and \
+ (str(type(a_ometiff)) == "") and \
+ (a_ometiff.dtype == np.float32) and \
+ (a_ometiff.shape == (4, 1, 200, 300)) and \
+ (a_ometiff[2].min() == 0.0) and \
+ (a_ometiff[3].min() == 0.0) and \
+ (a_ometiff[0].max() >= 1.0) and \
+ (a_ometiff[1].max() >= 1.0) and \
+ (a_ometiff[2].max() >= 1.0) and \
+ (a_ometiff[3].max() >= 1.0)
+
+ def test_mcds_make_ome_tiff_int(self, mcds=mcds):
+ a_ometiff = mcds.make_ome_tiff(cell_attribute='cell_count_voxel', conc_cutoff={}, focus=None, file=False)
+ assert(str(type(mcds)) == "") and \
+ (str(type(a_ometiff)) == "") and \
+ (a_ometiff.dtype == np.float32) and \
+ (a_ometiff.shape == (4, 1, 200, 300)) and \
+ (a_ometiff[2].min() == 0.0) and \
+ (a_ometiff[3].min() == 0.0) and \
+ (a_ometiff[0].max() >= 1.0) and \
+ (a_ometiff[1].max() >= 1.0) and \
+ (a_ometiff[2].max() >= 1.0) and \
+ (a_ometiff[3].max() >= 1.0)
+
+ def test_mcds_make_ome_tiff_float(self, mcds=mcds):
+ a_ometiff = mcds.make_ome_tiff(cell_attribute='pressure', conc_cutoff={}, focus=None, file=False)
+ assert(str(type(mcds)) == "") and \
+ (str(type(a_ometiff)) == "") and \
+ (a_ometiff.dtype == np.float32) and \
+ (a_ometiff.shape == (4, 1, 200, 300)) and\
+ (a_ometiff[2].min() == 0.0) and \
+ (a_ometiff[3].min() == 0.0) and \
+ (a_ometiff[0].max() >= 1.0) and \
+ (a_ometiff[1].max() >= 1.0) and \
+ (a_ometiff[2].max() >= 1.0) and \
+ (a_ometiff[3].max() >= 1.0)
+
+ def test_mcds_make_ome_tiff_conccutoff(self, mcds=mcds):
+ a_ometiff = mcds.make_ome_tiff(cell_attribute='ID', conc_cutoff={'oxygen': -1}, focus=None, file=False)
+ assert(str(type(mcds)) == "") and \
+ (str(type(a_ometiff)) == "") and \
+ (a_ometiff.dtype == np.float32) and \
+ (a_ometiff.shape == (4, 1, 200, 300)) and \
+ (a_ometiff[2].min() == 0.0) and \
+ (a_ometiff[3].min() == 0.0) and \
+ (a_ometiff[0].max() >= 1.0) and \
+ (a_ometiff[1].max() >= 1.0) and \
+ (a_ometiff[2].max() >= 1.0) and \
+ (a_ometiff[3].max() >= 1.0)
+
+ def test_mcds_make_ome_tiff_focus(self, mcds=mcds):
+ a_ometiff = mcds.make_ome_tiff(cell_attribute='ID', conc_cutoff={}, focus={'default'}, file=False)
+ assert(str(type(mcds)) == "") and \
+ (str(type(a_ometiff)) == "") and \
+ (a_ometiff.dtype == np.float32) and \
+ (a_ometiff.shape == (1, 1, 200, 300)) and \
+ (a_ometiff[0].min() == 0.0) and \
+ (a_ometiff[0].max() >= 1.0)
diff --git a/test/test_timestep_3d.py b/test/test_timestep_3d.py
index c9288fe..1c4f146 100644
--- a/test/test_timestep_3d.py
+++ b/test/test_timestep_3d.py
@@ -63,7 +63,9 @@ def test_mcds_get_mesh_spacing(self, mcds=mcds):
# test workhorse for speed #
############################
-class TestTimeStepInit(object):
+## data loading related functions ##
+
+class TestTimeStep3dInit(object):
''' tests for loading a pcdl.TimeStep data set. '''
mcds = pcdl.TimeStep(xmlfile=s_file_3d, output_path=s_path_3d, custom_data_type={}, microenv=True, graph=True, physiboss=True, settingxml='PhysiCell_settings.xml', verbose=True)
df_cell = mcds.get_cell_df()
@@ -92,7 +94,7 @@ def test_mcds_init_settingxml(self, mcds=mcds, df_cell=df_cell):
(df_cell.shape[1] == 122)
-class TestTimeStepInitMicroenvFalse(object):
+class TestTimeStep3dInitMicroenvFalse(object):
''' tests for loading a pcdl.TimeStep data set with microenv false. '''
mcds = pcdl.TimeStep(xmlfile=s_file_3d, output_path=s_path_3d, custom_data_type={}, microenv=False, graph=True, physiboss=True, settingxml='PhysiCell_settings.xml', verbose=True)
df_cell = mcds.get_cell_df()
@@ -121,7 +123,7 @@ def test_mcds_init_settingxml(self, mcds=mcds, df_cell=df_cell):
(df_cell.shape[1] == 116)
-class TestTimeStepInitGraphFalse(object):
+class TestTimeStep3dInitGraphFalse(object):
''' tests for loading a pcdl.TimeStep data set with graph false. '''
mcds = pcdl.TimeStep(xmlfile=s_file_3d, output_path=s_path_3d, custom_data_type={}, microenv=True, graph=False, physiboss=True, settingxml='PhysiCell_settings.xml', verbose=True)
df_cell = mcds.get_cell_df()
@@ -150,7 +152,7 @@ def test_mcds_init_settingxml(self, mcds=mcds, df_cell=df_cell):
(df_cell.shape[1] == 122)
-class TestTimeStepInitPhysibossFalse(object):
+class TestTimeStep3dInitPhysibossFalse(object):
''' tests for loading a pcdl.TimeStep data set with physiboss false. '''
mcds = pcdl.TimeStep(xmlfile=s_file_3d, output_path=s_path_3d, custom_data_type={}, microenv=True, graph=True, physiboss=False, settingxml='PhysiCell_settings.xml', verbose=True)
df_cell = mcds.get_cell_df()
@@ -179,17 +181,17 @@ def test_mcds_init_settingxml(self, mcds=mcds, df_cell=df_cell):
(df_cell.shape[1] == 122)
-#class TestTimeStepInitSettingxmlFalse(object):
+#class TestTimeStep3dInitSettingxmlFalse(object):
# ''' tests for loading a pcdl.TimeStep data set with settingxml false. '''
# NOP PhysiCell >= v1.14.0
-#class TestTimeStepInitSettingxmlNone(object):
+#class TestTimeStep3dInitSettingxmlNone(object):
# ''' tests for loading a pcdl.TimeStep data set with settingxml none. '''
# NOP PhysiCell >= v1.14.0
-class TestTimeStepInitVerboseTrue(object):
+class TestTimeStep3dInitVerboseTrue(object):
''' tests for loading a pcdl.TimeStep data set and set_verbose_false function. '''
mcds = pcdl.TimeStep(xmlfile=s_file_3d, output_path=s_path_3d, custom_data_type={}, microenv=True, graph=True, physiboss=True, settingxml='PhysiCell_settings.xml', verbose=True)
@@ -203,7 +205,7 @@ def test_mcds_set_verbose_false(self, mcds=mcds):
(not mcds.verbose)
-class TestTimeStepInitVerboseFalse(object):
+class TestTimeStep3dInitVerboseFalse(object):
''' tests for loading a pcdl.TimeStep data set and set_verbose_true function. '''
mcds = pcdl.TimeStep(xmlfile=s_file_3d, output_path=s_path_3d, custom_data_type={}, microenv=True, graph=True, physiboss=True, settingxml='PhysiCell_settings.xml', verbose=False)
@@ -217,7 +219,9 @@ def test_mcds_set_verbose_true(self, mcds=mcds):
(mcds.verbose)
-class TestTimeStep3dSettingWorkhorse(object):
+## parameter setting related functions ##
+
+class TestTimeStep3dUnitdictWorkhorse(object):
''' tests on 3D data set, for speed, for pcdl.TimeStep unit related workhorse functions. '''
mcds = pcdl.TimeStep(xmlfile=s_pathfile_3d) # custom_data_type={}, microenv=True, graph=True, physiboss=True, settingxml='PhysiCell_settings.xml', verbose=True
@@ -229,6 +233,8 @@ def test_mcds_get_unit_dict(self, mcds=mcds):
(ds_unit['oxygen'] == 'dimensionless')
+## metadata related functions ##
+
class TestTimeStep3dMicroenvWorkhorse(object):
''' tests on 3D data set, for speed, for pcdl.TimeStep microenvironment related workhorse functions. '''
mcds = pcdl.TimeStep(xmlfile=s_pathfile_3d) # custom_data_type={}, microenv=True, graph=True, physiboss=True, settingxml='PhysiCell_settings.xml', verbose=True
@@ -334,6 +340,8 @@ def test_mcds_make_conc_vtk(self, mcds=mcds):
os.remove(s_pathfile)
+## cell agent related functions ##
+
class TestTimeStep3dCellWorkhorse(object):
''' tests on 3D data set, for speed, for pcdl.TimeStep cell related workhorse functions. '''
mcds = pcdl.TimeStep(xmlfile=s_pathfile_3d) # custom_data_type={}, microenv=True, graph=True, physiboss=True, settingxml='PhysiCell_settings.xml', verbose=True
@@ -539,6 +547,30 @@ def test_mcds_make_cell_vtk_attribute_many(self, mcds=mcds):
os.remove(s_pathfile)
+## anndata time step related functions ##
+
+class TestTimeStep3dAnnData(object):
+ ''' test for pcdl.TimeStep class. '''
+
+ ## get_anndata command ##
+ def test_mcds_get_anndata(self):
+ mcds = pcdl.TimeStep(s_pathfile_3d, verbose=False)
+ ann = mcds.get_anndata(values=1, drop=set(), keep=set(), scale='maxabs')
+ assert(str(type(mcds)) == "") and \
+ (str(type(ann)) == "") and \
+ (ann.X.shape[0] > 9) and \
+ (ann.X.shape[1] == 105) and \
+ (ann.obs.shape[0] > 9) and \
+ (ann.obs.shape[1] == 8) and \
+ (ann.obsm['spatial'].shape[0] > 9) and \
+ (ann.obsm['spatial'].shape[1] == 3) and \
+ (len(ann.obsp) == 4) and \
+ (ann.var.shape == (105, 0)) and \
+ (len(ann.uns) == 2)
+
+
+## graph related functions ##
+
class TestTimeStep3dGraphWorkhorse(object):
''' tests on 3D data set, for speed, for pcdl.TimeStep graph related workhorse functions. '''
mcds = pcdl.TimeStep(xmlfile=s_pathfile_3d) # custom_data_type={}, microenv=True, graph=True, physiboss=True, settingxml='PhysiCell_settings.xml', verbose=True
@@ -645,50 +677,9 @@ def test_mcds_make_graph_gml_neighbor_nodeattrtrue(self, mcds=mcds):
os.remove(s_pathfile)
-class TestTimeStep3dOmeTiffWorkhorse(object):
- ''' tests on 3D data set, for speed, for pcdl.TimeStep ome tiff related workhorse functions. '''
- mcds = pcdl.TimeStep(xmlfile=s_pathfile_3d) # custom_data_type={}, microenv=True, graph=True, physiboss=True, settingxml='PhysiCell_settings.xml', verbose=True
-
- ## ome tiff related functions ##
- def test_mcds_make_ome_tiff_default(self, mcds=mcds):
- s_pathfile = mcds.make_ome_tiff(cell_attribute='ID', conc_cutoff={}, focus=None, file=True)
- assert(str(type(mcds)) == "") and \
- (s_pathfile.replace('\\','/').endswith('pcdl/output_3d/output00000024_oxygen_water_default_blood_cells_ID.ome.tiff')) and \
- (os.path.exists(s_pathfile)) and \
- (os.path.getsize(s_pathfile) > 2**10)
- os.remove(s_pathfile)
-
- def test_mcds_make_ome_tiff_nofile(self, mcds=mcds):
- a_ometiff = mcds.make_ome_tiff(cell_attribute='ID', conc_cutoff={}, focus=None, file=False)
- assert(str(type(mcds)) == "") and \
- (str(type(a_ometiff)) == "") and \
- (a_ometiff.dtype == np.float32) and \
- (a_ometiff.shape == (4, 11, 200, 300))
-
-
-## anndata time step related functions ##
-class TestTimeStep3dAnnData(object):
- ''' test for pcdl.TimeStep class. '''
-
- ## get_anndata command ##
- def test_mcds_get_anndata(self):
- mcds = pcdl.TimeStep(s_pathfile_3d, verbose=False)
- ann = mcds.get_anndata(values=1, drop=set(), keep=set(), scale='maxabs')
- assert(str(type(mcds)) == "") and \
- (str(type(ann)) == "") and \
- (ann.X.shape[0] > 9) and \
- (ann.X.shape[1] == 105) and \
- (ann.obs.shape[0] > 9) and \
- (ann.obs.shape[1] == 8) and \
- (ann.obsm['spatial'].shape[0] > 9) and \
- (ann.obsm['spatial'].shape[1] == 3) and \
- (len(ann.obsp) == 4) and \
- (ann.var.shape == (105, 0)) and \
- (len(ann.uns) == 2)
-
-
## muspan time step related functions ##
-class TestTimeStepMuspan(object):
+
+class TestTimeStep3dMuspan(object):
''' test for pcdl.TimeStep class. '''
## get_muspan command ##
@@ -734,7 +725,8 @@ def test_mcds_get_muspan_zslice(self):
## spatialdata time step related functions ##
-class TestTimeStepSpatialData(object):
+
+class TestTimeStep3dSpatialData(object):
''' test for pcdl.TimeStep class. '''
## get_spatialdata command ##
@@ -798,3 +790,25 @@ def test_mcds_get_spatialdata_none(self):
(sdata['subs_table'].obs.shape[0] > 9) and \
(sdata['subs_table'].obs.shape[1] == 11)
+
+## ome tiff related functions ##
+
+class TestTimeStep3dOmeTiffWorkhorse(object):
+ ''' tests on 3D data set, for speed, for pcdl.TimeStep ome tiff related workhorse functions. '''
+ mcds = pcdl.TimeStep(xmlfile=s_pathfile_3d) # custom_data_type={}, microenv=True, graph=True, physiboss=True, settingxml='PhysiCell_settings.xml', verbose=True
+
+ ## ome tiff related functions ##
+ def test_mcds_make_ome_tiff_default(self, mcds=mcds):
+ s_pathfile = mcds.make_ome_tiff(cell_attribute='ID', conc_cutoff={}, focus=None, file=True)
+ assert(str(type(mcds)) == "") and \
+ (s_pathfile.replace('\\','/').endswith('pcdl/output_3d/output00000024_oxygen_water_default_blood_cells_ID.ome.tiff')) and \
+ (os.path.exists(s_pathfile)) and \
+ (os.path.getsize(s_pathfile) > 2**10)
+ os.remove(s_pathfile)
+
+ def test_mcds_make_ome_tiff_nofile(self, mcds=mcds):
+ a_ometiff = mcds.make_ome_tiff(cell_attribute='ID', conc_cutoff={}, focus=None, file=False)
+ assert(str(type(mcds)) == "") and \
+ (str(type(a_ometiff)) == "") and \
+ (a_ometiff.dtype == np.float32) and \
+ (a_ometiff.shape == (4, 11, 200, 300))