Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

v2.1.1 #128

Merged
merged 39 commits into from
Jun 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
2db8783
mem optim and parallelize flux
ckmah May 1, 2024
8dac377
100x plot speedup replacing geopandas plot fns with mpl patches
ckmah May 1, 2024
3e8cc93
Add scalene files to .gitignore
ckmah May 1, 2024
30062ee
dont sort flux metadata before joining if not needed
ckmah May 1, 2024
6c709c3
wip fixing slow plotting with gpd
ckmah May 1, 2024
b68aa4d
cosmx v1
ckmah May 1, 2024
97e4ce2
outside cell mask now handles polygons with holes
ckmah May 2, 2024
4e48a71
pull out util fn for plt poly to patch conversion
ckmah May 2, 2024
6a22080
add min count threshold to hide points in radviz plots
ckmah May 2, 2024
3fd1b29
simplify hide extracellular and add legend to fluxmap plot
ckmah May 2, 2024
bcd65df
cleanup tutorials
ckmah May 2, 2024
d7c8694
Update python-package.yml
ckmah May 2, 2024
e21e874
Update python-package.yml
ckmah May 2, 2024
fa8b2a1
hide_outside respect current theme color
ckmah May 3, 2024
1171a4c
lp parallelized
ckmah May 3, 2024
68f5b75
disable plot tests for now
ckmah May 3, 2024
66bf18f
cosmx and xenium with vanilla flux analysis
ckmah May 3, 2024
a2ca7c8
remove 3.10 syntax
ckmah May 14, 2024
f9aa430
labels to shapes conversion
ckmah May 14, 2024
17c6714
fix some accessors
ckmah May 14, 2024
8affa08
pixel units
ckmah May 14, 2024
96700cc
fix sample data formatting
ckmah May 14, 2024
9c8d8dd
Merge pull request #126 from ckmah/codecov
ckmah May 14, 2024
0b590fc
point_features join points to shapes fix
dylanclam12 May 15, 2024
d80290a
Merge branch 'prep-fixes' of https://github.com/ckmah/bento-tools int…
dylanclam12 May 15, 2024
7524d9e
minimal test data covering partial mapping of shapes
ckmah Jun 4, 2024
5ea1217
clarify prep error
ckmah Jun 4, 2024
2eaa67e
pytest dep
ckmah Jun 4, 2024
d00fbda
nucleus mapping edge case
ckmah Jun 4, 2024
128bb71
off by one for min flux components; fluxmap handles negative coordina…
ckmah Jun 4, 2024
6ddc74e
prep adds point instance_key
ckmah Jun 4, 2024
ec7edc4
migrate to pytest, add second test set
ckmah Jun 4, 2024
d58af46
images for prep tutorial
ckmah Jun 4, 2024
4722974
guarantee shape indices unique
ckmah Jun 4, 2024
006a268
compat for mpl
ckmah Jun 4, 2024
81a5b51
mpl register fix
ckmah Jun 5, 2024
b3ba749
mpl register fix
ckmah Jun 5, 2024
8237e35
Merge branch 'prep-fixes' of github.com:ckmah/bento-tools into prep-f…
ckmah Jun 5, 2024
b664b70
add data prep guide, will need to update image urls
ckmah Jun 5, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/python-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os : [ubuntu-22.04, macos-11, macos-12, windows-2019]
python-version: ['3.9', '3.10']
os : [ubuntu-latest, windows-latest, macos-latest]
python-version: ['3.9', '3.10', '3.11']
steps:
- uses: actions/[email protected]
- name: Set up Python ${{ matrix.python-version }}
Expand All @@ -28,7 +28,7 @@ jobs:
python -m pip install --upgrade pip
python -m pip install .[docs]
- name: Lint & test coverage
if: ${{ matrix.os == 'ubuntu-22.04' && matrix.python-version == '3.8' }}
if: ${{ matrix.os == 'ubuntu-latest' && matrix.python-version == '3.10' }}
run: |
pip install flake8
# stop the build if there are Python syntax errors or undefined names
Expand All @@ -38,7 +38,7 @@ jobs:
pip install coverage
coverage run -m unittest
- name: Upload Coverage to Codecov
if: ${{ matrix.os == 'ubuntu-22.04' && matrix.python-version == '3.8' }}
if: ${{ matrix.os == 'ubuntu-latest' && matrix.python-version == '3.10' }}
uses: codecov/codecov-action@v1
with:
fail_ci_if_error: true
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -143,4 +143,6 @@ tests/data/processed/pre_transform.pt
.DS_Store

requirements.lock
requirements-dev.lock
requirements-dev.lock
profile.html
profile.json
1 change: 1 addition & 0 deletions bento/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@
from . import datasets as ds
from . import io
from .plotting import _colors as colors
from ._constants import CosMx, Merscope, Xenium
23 changes: 23 additions & 0 deletions bento/_constants.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,26 @@
from enum import Enum

PATTERN_COLORS = ["#17becf", "#1f77b4", "#7f7f7f", "#ff7f0e", "#d62728"]
PATTERN_NAMES = ["cell_edge", "cytoplasmic", "none", "nuclear", "nuclear_edge"]
PATTERN_PROBS = [f"{p}_p" for p in PATTERN_NAMES]


class CosMx(Enum):
"""CosMx microscope constants"""

# https://nanostring-public-share.s3.us-west-2.amazonaws.com/SMI-Compressed/SMI-ReadMe.html
PIXEL_MICRONS = 0.18


class Merscope(Enum):
"""Merscope microscope constants"""

# https://vizgen.com/wp-content/uploads/2023/06/91600001_MERSCOPE-Instrument-User-Guide_Rev-G.pdf
PIXEL_MICRONS = 1


class Xenium(Enum):
"""Xenium microscope constants"""

# https://www.10xgenomics.com/instruments/xenium-analyzer
PIXEL_MICRONS = 0.2125
93 changes: 44 additions & 49 deletions bento/_utils.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
# Geometric operations for SpatialData ShapeElements wrapping GeoPandas GeoDataFrames.
from typing import List, Optional
from typing import List, Optional, Union

import geopandas as gpd
import numpy as np
import pandas as pd
from dask import dataframe as dd
from spatialdata import SpatialData
from spatialdata.models import PointsModel, ShapesModel, TableModel
from spatialdata.transformations import get_transformation, set_transformation


def filter_by_gene(
Expand Down Expand Up @@ -66,7 +65,7 @@ def get_points(
points_key: str = "transcripts",
astype: str = "pandas",
sync: bool = True,
) -> pd.DataFrame | dd.DataFrame | gpd.GeoDataFrame:
) -> Union[pd.DataFrame, dd.DataFrame, gpd.GeoDataFrame]:
"""Get points DataFrame synced to AnnData object.

Parameters
Expand Down Expand Up @@ -144,10 +143,10 @@ def get_shape(sdata: SpatialData, shape_key: str, sync: bool = True) -> gpd.GeoS

def get_points_metadata(
sdata: SpatialData,
metadata_keys: List[str] | str,
metadata_keys: Union[List[str], str],
points_key: str,
astype="pandas",
):
astype: str = "pandas",
) -> Union[pd.DataFrame, dd.DataFrame]:
"""Get points metadata.

Parameters
Expand Down Expand Up @@ -188,9 +187,9 @@ def get_points_metadata(

def get_shape_metadata(
sdata: SpatialData,
metadata_keys: List[str] | str,
metadata_keys: Union[List[str], str],
shape_key: str,
):
) -> pd.DataFrame:
"""Get shape metadata.

Parameters
Expand All @@ -204,7 +203,7 @@ def get_shape_metadata(

Returns
-------
pd.Dataframe
pd.DataFrame
Returns `sdata.shapes[shape_key][metadata_keys]` as a `pd.DataFrame`
"""
if shape_key not in sdata.shapes.keys():
Expand All @@ -223,9 +222,9 @@ def get_shape_metadata(
def set_points_metadata(
sdata: SpatialData,
points_key: str,
metadata: List | pd.Series | pd.DataFrame | np.ndarray,
columns: List[str] | str,
):
metadata: Union[List, pd.Series, pd.DataFrame, np.ndarray],
columns: Union[List[str], str],
) -> None:
"""Write metadata in SpatialData points element as column(s). Aligns metadata index to shape index if present.

Parameters
Expand Down Expand Up @@ -268,9 +267,9 @@ def set_points_metadata(
def set_shape_metadata(
sdata: SpatialData,
shape_key: str,
metadata: List | pd.Series | pd.DataFrame | np.ndarray,
column_names: Optional[str | List[str]] = None,
):
metadata: Union[List, pd.Series, pd.DataFrame, np.ndarray],
column_names: Union[List[str], str] = None,
) -> None:
"""Write metadata in SpatialData shapes element as column(s). Aligns metadata index to shape index.

Parameters
Expand Down Expand Up @@ -310,7 +309,9 @@ def set_shape_metadata(
if "" not in metadata[col].cat.categories:
metadata[col] = metadata[col].cat.add_categories([""]).fillna("")

sdata.shapes[shape_key].loc[:, metadata.columns] = metadata.reindex(shape_index)
sdata.shapes[shape_key].loc[:, metadata.columns] = metadata.reindex(
shape_index
).fillna("")


def _sync_points(sdata, points_key):
Expand All @@ -331,24 +332,20 @@ def _sync_points(sdata, points_key):
"""
points = sdata.points[points_key].compute()
instance_key = get_instance_key(sdata)
if instance_key not in points.columns:
raise ValueError(
f"Points {points_key} not synced to instance_key shape element. Run bento.io.prep() to setup SpatialData object for bento-tools."
)
else:
# Only keep points within instance_key shape
cells = set(sdata.shapes[instance_key].index)
transform = sdata.points[points_key].attrs
points_valid = points[
points[instance_key].isin(cells)
] # TODO why doesnt this grab the right cells
# Set points back to SpatialData object
points_valid = PointsModel.parse(
dd.from_pandas(points_valid, npartitions=1),
coordinates={"x": "x", "y": "y"},
)
points_valid.attrs = transform
sdata.points[points_key] = points_valid

# Only keep points within instance_key shape
cells = set(sdata.shapes[instance_key].index)
transform = sdata.points[points_key].attrs
points_valid = points[
points[instance_key].isin(cells)
] # TODO why doesnt this grab the right cells
# Set points back to SpatialData object
points_valid = PointsModel.parse(
dd.from_pandas(points_valid, npartitions=1),
coordinates={"x": "x", "y": "y"},
)
points_valid.attrs = transform
sdata.points[points_key] = points_valid


def _sync_shapes(sdata, shape_key, instance_key):
Expand All @@ -371,22 +368,18 @@ def _sync_shapes(sdata, shape_key, instance_key):
"""
shapes = sdata.shapes[shape_key]
instance_shapes = sdata.shapes[instance_key]
if instance_key not in shapes.columns or shape_key not in instance_shapes.columns:
raise ValueError(
f"Shape {shape_key} not synced to instance_key shape element. Run bento.io.prep() to setup SpatialData object for bento-tools."
)
elif shape_key == instance_key:
if shape_key == instance_key:
return
else:
# Only keep shapes within instance_key shape
cells = set(instance_shapes.index)
shapes = shapes[shapes[instance_key].isin(cells)]

# Set shapes back to SpatialData object
transform = sdata.shapes[shape_key].attrs
shapes_valid = ShapesModel.parse(shapes)
shapes_valid.attrs = transform
sdata.shapes[shape_key] = shapes_valid
# Only keep shapes within instance_key shape
cells = set(instance_shapes.index)
shapes = shapes[shapes[instance_key].isin(cells)]

# Set shapes back to SpatialData object
transform = sdata.shapes[shape_key].attrs
shapes_valid = ShapesModel.parse(shapes)
shapes_valid.attrs = transform
sdata.shapes[shape_key] = shapes_valid


def get_instance_key(sdata: SpatialData):
Expand All @@ -406,7 +399,9 @@ def get_instance_key(sdata: SpatialData):
try:
return sdata.points["transcripts"].attrs["spatialdata_attrs"]["instance_key"]
except KeyError:
raise KeyError("Instance key attribute not found in spatialdata object.")
raise KeyError(
"Instance key attribute not found in spatialdata object. Run bento.io.prep() to setup SpatialData object for bento-tools."
)


def get_feature_key(sdata: SpatialData):
Expand Down
3 changes: 3 additions & 0 deletions bento/datasets/merfish_sample.zarr.bak/points/.zgroup
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"zarr_format": 2
}
44 changes: 44 additions & 0 deletions bento/datasets/merfish_sample.zarr.bak/points/transcripts/.zattrs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"axes": null,
"coordinateTransformations": [
{
"input": {
"axes": [
{
"name": "x",
"type": "space",
"unit": "unit"
},
{
"name": "y",
"type": "space",
"unit": "unit"
}
],
"name": "xy"
},
"output": {
"axes": [
{
"name": "x",
"type": "space",
"unit": "unit"
},
{
"name": "y",
"type": "space",
"unit": "unit"
}
],
"name": "global"
},
"type": "identity"
}
],
"encoding-type": "ngff:points",
"spatialdata_attrs": {
"feature_key": "feature_name",
"instance_key": "cell_boundaries",
"version": "0.1"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"zarr_format": 2
}
Binary file not shown.
3 changes: 3 additions & 0 deletions bento/datasets/merfish_sample.zarr.bak/shapes/.zgroup
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"zarr_format": 2
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,14 @@
],
"name": "global"
},
"scale": [
4.705882352941177,
4.705882352941177
],
"type": "scale"
"type": "identity"
}
],
"encoding-type": "ngff:shapes",
"spatialdata_attrs": {
"geos": {
"name": "POINT",
"type": 0
"name": "POLYGON",
"type": 3
},
"version": "0.1"
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"zarr_format": 2
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"chunks": [
14
],
"compressor": {
"blocksize": 0,
"clevel": 5,
"cname": "lz4",
"id": "blosc",
"shuffle": 1
},
"dimension_separator": "/",
"dtype": "|O",
"fill_value": 0,
"filters": [
{
"id": "vlen-utf8"
}
],
"order": "C",
"shape": [
14
],
"zarr_format": 2
}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"chunks": [
1224,
2
],
"compressor": {
"blocksize": 0,
"clevel": 5,
"cname": "lz4",
"id": "blosc",
"shuffle": 1
},
"dimension_separator": "/",
"dtype": "<f8",
"fill_value": 0.0,
"filters": null,
"order": "C",
"shape": [
1224,
2
],
"zarr_format": 2
}
Binary file not shown.
Loading
Loading