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

issues with plotting multipolygons #72

Closed
lopollar opened this issue May 17, 2023 · 2 comments · Fixed by #93
Closed

issues with plotting multipolygons #72

lopollar opened this issue May 17, 2023 · 2 comments · Fixed by #93
Assignees
Labels
enhancement New feature or request priority: medium

Comments

@lopollar
Copy link

Although spatialData supports multipolygons, plt.shapes doesn't support it.

When running following code (where sdate.shapes contains multipolygons):

'''
import spatialdata_plot
sdata.pl.render_images('raw_image').pl.render_shapes().pl.show()
'''
Following error is produced:

AttributeError Traceback (most recent call last)
Input In [58], in <cell line: 2>()
1 import spatialdata_plot
----> 2 sdata.pl.render_images('raw_image').pl.render_shapes().pl.show()

File /srv/scratch/lottep/anaconda3/envs/napari-spongepy/lib/python3.10/site-packages/spatialdata_plot/pl/basic.py:625, in PlotAccessor.show(self, coordinate_systems, legend_fontsize, legend_fontweight, legend_loc, legend_fontoutline, na_in_legend, colorbar, wspace, hspace, ncols, frameon, figsize, dpi, fig, ax, return_ax, save)
618 if is_categorical_dtype(colors):
619 _maybe_set_colors(
620 source=sdata.table,
621 target=sdata.table,
622 key=params.color,
623 palette=params.palette,
624 )
--> 625 _render_shapes(
626 sdata=sdata,
627 render_params=params,
628 coordinate_system=cs,
629 ax=ax,
630 fig_params=fig_params,
631 scalebar_params=scalebar_params,
632 legend_params=legend_params,
633 )
635 elif cmd == "render_points" and cs_contents.query(f"cs == '{cs}'")["has_points"][0]:
636 _render_points(
637 sdata=sdata,
638 render_params=params,
(...)
643 legend_params=legend_params,
644 )

File /srv/scratch/lottep/anaconda3/envs/napari-spongepy/lib/python3.10/site-packages/spatialdata_plot/pl/render.py:154, in _render_shapes(sdata, render_params, coordinate_system, ax, fig_params, scalebar_params, legend_params)
151 if len(color_vector) == 0:
152 color_vector = [(0.83, 0.83, 0.83, 1.0)]
--> 154 _cax = _get_collection_shape(
155 shapes=shapes,
156 s=render_params.size,
157 c=color_vector,
158 rasterized=sc_settings._vector_friendly,
159 cmap=render_params.cmap_params.cmap,
160 norm=norm,
161 alpha=render_params.alpha,
162 # **kwargs,
163 )
164 cax = ax.add_collection(_cax)
166 _ = _decorate_axs(
167 ax=ax,
168 cax=cax,
(...)
184 # scalebar_kwargs=scalebar_params.scalebar_kwargs,
185 )

File /srv/scratch/lottep/anaconda3/envs/napari-spongepy/lib/python3.10/site-packages/spatialdata_plot/pl/render.py:109, in _render_shapes.._get_collection_shape(shapes, c, s, norm, **kwargs)
107 """Get collection of shapes."""
108 if shapes["geometry"].iloc[0].geom_type == "Polygon":
--> 109 patches = [Polygon(p.exterior.coords, closed=False) for p in shapes["geometry"]]
110 elif shapes["geometry"].iloc[0].geom_type == "Point":
111 patches = [Circle((circ.x, circ.y), radius=r * s) for circ, r in zip(shapes["geometry"], shapes["radius"])]

File /srv/scratch/lottep/anaconda3/envs/napari-spongepy/lib/python3.10/site-packages/spatialdata_plot/pl/render.py:109, in (.0)
107 """Get collection of shapes."""
108 if shapes["geometry"].iloc[0].geom_type == "Polygon":
--> 109 patches = [Polygon(p.exterior.coords, closed=False) for p in shapes["geometry"]]
110 elif shapes["geometry"].iloc[0].geom_type == "Point":
111 patches = [Circle((circ.x, circ.y), radius=r * s) for circ, r in zip(shapes["geometry"], shapes["radius"])]

AttributeError: 'MultiPolygon' object has no attribute 'exterior'

Will multipolygons will be supported for plotting in the future or should I try to make them into polygons? (and thus losing information)?

@timtreis timtreis self-assigned this Jun 8, 2023
@timtreis timtreis added the bug Something isn't working label Jun 8, 2023
@timtreis
Copy link
Member

timtreis commented Jun 8, 2023

Hey there! Sorry, only now seeing the issue. Yeah, will be supported in the future. I'm currently trying to reproduce your error and will then fix it.

"A sequence of Polygons, or a sequence of (shell, holes) tuples where shell is the sequence representation of a linear ring (see LinearRing) and holes is a sequence of such linear rings.". https://shapely.readthedocs.io/en/stable/reference/shapely.MultiPolygon.html

Since you said that information would be lost, I'm assuming you have the "(shell, holes)" case, f.e., to label only the cytoplasm. Very happy to support that case as it seems super useful. From now on I'll just assume you meant that scenario.


MRE

import spatialdata as sd
import spatialdata_plot
from spatialdata.models import ShapesModel
from shapely.geometry import Polygon, MultiPolygon
import pandas as pd
import geopandas as gpd
import numpy as np


def _make_multi():
    poly = Polygon([(2.0, 0.0), (2.0, 1.0), (3.0, 1.0), (3.0, 0.0)])
    multi = MultiPolygon([(
        ((0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0)),
         [((0.2,0.2), (0.2,0.8), (0.8,0.8), (0.8,0.2))]
    )])
    polygon_series = gpd.GeoSeries([poly, multi])
    cell_polygon_table = gpd.GeoDataFrame(geometry=polygon_series)
    sd_polygons = ShapesModel.parse(cell_polygon_table)
    return sd_polygons

multi = _make_multi()
sdata = sd.SpatialData(shapes={"p": _make_multi()})
sdata.shapes["p"].iloc[1,0]
# sdata.pl.render_shapes().pl.show() fails

image

@timtreis timtreis added enhancement New feature or request and removed bug Something isn't working labels Jun 8, 2023
@timtreis timtreis linked a pull request Jun 8, 2023 that will close this issue
1 task
@timtreis
Copy link
Member

timtreis commented Jun 13, 2023

@berombau provided example CellPose output which produces MultiPolygons -> https://dl01.irc.ugent.be/spatial/geojsons/adataA1-1.geojson

Can we used with

import spatialdata as sd
import spatialdata_plot
from spatialdata.models import ShapesModel
import pandas as pd
import geopandas as gpd


def _make_multi():

    multipolygon = gpd.read_file('/Users/tim.treis/Downloads/adataA1-1.geojson')
    multipolygon = multipolygon[[e.geom_type != "Polygon" for e in multipolygon.geometry]]
    sd_polygons = ShapesModel.parse(multipolygon)
    return sd_polygons

multi = _make_multi()
sdata = sd.SpatialData(shapes={"p": _make_multi()})

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request priority: medium
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants