scanpy icon indicating copy to clipboard operation
scanpy copied to clipboard

Scanpy.pl.embedding throws error when projection='3d' and all values are the same for coloring

Open dsm-72 opened this issue 3 years ago • 0 comments

  • [x] I have checked that this issue has not already been reported.
  • [x] I have confirmed this bug exists on the latest version of scanpy.
  • [ ] (optional) I have confirmed this bug exists on the master branch of scanpy.

Note: Please read this guide detailing how to provide the necessary information for us to reproduce your bug.

Minimal code sample (that we can copy&paste without having any data)

# NOTE: This throws error
sc.pl.embedding(
    adata, basis='X_emb', color=de_genes[:10], sort_order=True, vmin=0, color_map='magma',
    projection='3d'
)

# NOTE: This doesn't throw error
sc.pl.embedding(
    adata, basis='X_emb', color=de_genes[:10], sort_order=True, vmin=0, color_map='magma',
    projection='2d'
)

# NOTE: the error is that one of the genes in `de_genes` has almost the value for all cells
np.unique(adata.X[:, de_genes.index('KRT1')])
> array([-0.09614931, -0.09614931, -0.09614931, -0.09614931, -0.09614931,
       -0.09614931, -0.09614931, -0.09614931, -0.09614931, -0.09614931,
       -0.09614931, -0.09614931, -0.09614931, -0.09614931, -0.09614931,
       -0.09614931, -0.09614931, -0.09614931, -0.09614931, -0.09614931,
       -0.09614931, -0.09614931, -0.09614931, -0.09614931, -0.09614931,
       -0.09614931, -0.09614931, -0.09614931, -0.09614931, -0.09614931,
       -0.09614931, -0.09614931, -0.09614931, -0.09614931])

# Thus this is a combination of projection 3d and rounding. This should not throw an error and just plot all points same color
[Paste the error output produced by the above code here]
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Input In [403], in <cell line: 1>()
----> 1 sc.pl.embedding(
      2     adata, basis='X_phate_alone', color=de_genes[:10], sort_order=True, vmin=0, color_map='magma',
      3     projection='3d'
      4 )

File ~/anaconda3/envs/ml/lib/python3.9/site-packages/scanpy/plotting/_tools/scatterplots.py:325, in embedding(adata, basis, color, gene_symbols, use_raw, sort_order, edges, edges_width, edges_color, neighbors_key, arrows, arrows_kwds, groups, components, dimensions, layer, projection, scale_factor, color_map, cmap, palette, na_color, na_in_legend, size, frameon, legend_fontsize, legend_fontweight, legend_loc, legend_fontoutline, colorbar_loc, vmax, vmin, vcenter, norm, add_outline, outline_width, outline_color, ncols, hspace, wspace, title, show, save, ax, return_fig, **kwargs)
    323 # make the scatter plot
    324 if projection == '3d':
--> 325     cax = ax.scatter(
    326         coords[:, 0],
    327         coords[:, 1],
    328         coords[:, 2],
    329         marker=".",
    330         c=color_vector,
    331         rasterized=settings._vector_friendly,
    332         norm=normalize,
    333         **kwargs,
    334     )
    335 else:
    336     scatter = (
    337         partial(ax.scatter, s=size, plotnonfinite=True)
    338         if scale_factor is None
   (...)
    341         )  # size in circles is radius
    342     )

File ~/anaconda3/envs/ml/lib/python3.9/site-packages/mpl_toolkits/mplot3d/axes3d.py:2417, in Axes3D.scatter(self, xs, ys, zs, zdir, s, c, depthshade, *args, **kwargs)
   2414     zs = zs.copy()
   2416 patches = super().scatter(xs, ys, s=s, c=c, *args, **kwargs)
-> 2417 art3d.patch_collection_2d_to_3d(patches, zs=zs, zdir=zdir,
   2418                                 depthshade=depthshade)
   2420 if self._zmargin < 0.05 and xs.size > 0:
   2421     self.set_zmargin(0.05)

File ~/anaconda3/envs/ml/lib/python3.9/site-packages/mpl_toolkits/mplot3d/art3d.py:674, in patch_collection_2d_to_3d(col, zs, zdir, depthshade)
    672 col._depthshade = depthshade
    673 col._in_draw = False
--> 674 col.set_3d_properties(zs, zdir)

File ~/anaconda3/envs/ml/lib/python3.9/site-packages/mpl_toolkits/mplot3d/art3d.py:542, in Path3DCollection.set_3d_properties(self, zs, zdir)
    539 def set_3d_properties(self, zs, zdir):
    540     # Force the collection to initialize the face and edgecolors
    541     # just in case it is a scalarmappable with a colormap.
--> 542     self.update_scalarmappable()
    543     offsets = self.get_offsets()
    544     if len(offsets) > 0:

File ~/anaconda3/envs/ml/lib/python3.9/site-packages/matplotlib/collections.py:926, in Collection.update_scalarmappable(self)
    924         # pcolormesh, scatter, maybe others flatten their _A
    925         self._alpha = self._alpha.reshape(self._A.shape)
--> 926     self._mapped_colors = self.to_rgba(self._A, self._alpha)
    928 if self._face_is_mapped:
    929     self._facecolors = self._mapped_colors

File ~/anaconda3/envs/ml/lib/python3.9/site-packages/matplotlib/cm.py:359, in ScalarMappable.to_rgba(self, x, alpha, bytes, norm)
    357 x = ma.asarray(x)
    358 if norm:
--> 359     x = self.norm(x)
    360 rgba = self.cmap(x, alpha=alpha, bytes=bytes)
    361 return rgba

File ~/anaconda3/envs/ml/lib/python3.9/site-packages/matplotlib/colors.py:1193, in Normalize.__call__(self, value, clip)
   1191     result.fill(0)   # Or should it be all masked?  Or 0.5?
   1192 elif vmin > vmax:
-> 1193     raise ValueError("minvalue must be less than or equal to maxvalue")
   1194 else:
   1195     if clip:

ValueError: minvalue must be less than or equal to maxvalue

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
File ~/anaconda3/envs/ml/lib/python3.9/site-packages/IPython/core/formatters.py:339, in BaseFormatter.__call__(self, obj)
    337     pass
    338 else:
--> 339     return printer(obj)
    340 # Finally look for special method names
    341 method = get_real_method(obj, self.print_method)

File ~/anaconda3/envs/ml/lib/python3.9/site-packages/IPython/core/pylabtools.py:151, in print_figure(fig, fmt, bbox_inches, base64, **kwargs)
    148     from matplotlib.backend_bases import FigureCanvasBase
    149     FigureCanvasBase(fig)
--> 151 fig.canvas.print_figure(bytes_io, **kw)
    152 data = bytes_io.getvalue()
    153 if fmt == 'svg':

File ~/anaconda3/envs/ml/lib/python3.9/site-packages/matplotlib/backend_bases.py:2230, in FigureCanvasBase.print_figure(self, filename, dpi, facecolor, edgecolor, orientation, format, bbox_inches, pad_inches, bbox_extra_artists, backend, **kwargs)
   2226     ctx = (renderer._draw_disabled()
   2227            if hasattr(renderer, '_draw_disabled')
   2228            else suppress())
   2229     with ctx:
-> 2230         self.figure.draw(renderer)
   2232 if bbox_inches:
   2233     if bbox_inches == "tight":

File ~/anaconda3/envs/ml/lib/python3.9/site-packages/matplotlib/artist.py:74, in _finalize_rasterization.<locals>.draw_wrapper(artist, renderer, *args, **kwargs)
     72 @wraps(draw)
     73 def draw_wrapper(artist, renderer, *args, **kwargs):
---> 74     result = draw(artist, renderer, *args, **kwargs)
     75     if renderer._rasterizing:
     76         renderer.stop_rasterizing()

File ~/anaconda3/envs/ml/lib/python3.9/site-packages/matplotlib/artist.py:51, in allow_rasterization.<locals>.draw_wrapper(artist, renderer, *args, **kwargs)
     48     if artist.get_agg_filter() is not None:
     49         renderer.start_filter()
---> 51     return draw(artist, renderer, *args, **kwargs)
     52 finally:
     53     if artist.get_agg_filter() is not None:

File ~/anaconda3/envs/ml/lib/python3.9/site-packages/matplotlib/figure.py:2790, in Figure.draw(self, renderer)
   2787         # ValueError can occur when resizing a window.
   2789 self.patch.draw(renderer)
-> 2790 mimage._draw_list_compositing_images(
   2791     renderer, self, artists, self.suppressComposite)
   2793 for sfig in self.subfigs:
   2794     sfig.draw(renderer)

File ~/anaconda3/envs/ml/lib/python3.9/site-packages/matplotlib/image.py:132, in _draw_list_compositing_images(renderer, parent, artists, suppress_composite)
    130 if not_composite or not has_images:
    131     for a in artists:
--> 132         a.draw(renderer)
    133 else:
    134     # Composite any adjacent images together
    135     image_group = []

File ~/anaconda3/envs/ml/lib/python3.9/site-packages/matplotlib/artist.py:51, in allow_rasterization.<locals>.draw_wrapper(artist, renderer, *args, **kwargs)
     48     if artist.get_agg_filter() is not None:
     49         renderer.start_filter()
---> 51     return draw(artist, renderer, *args, **kwargs)
     52 finally:
     53     if artist.get_agg_filter() is not None:

File ~/anaconda3/envs/ml/lib/python3.9/site-packages/mpl_toolkits/mplot3d/axes3d.py:485, in Axes3D.draw(self, renderer)
    480 # Calculate projection of collections and patches and zorder them.
    481 # Make sure they are drawn above the grids.
    482 zorder_offset = max(axis.get_zorder()
    483                     for axis in self._get_axis_list()) + 1
    484 for i, col in enumerate(
--> 485         sorted(self.collections,
    486                key=do_3d_projection,
    487                reverse=True)):
    488     col.zorder = zorder_offset + i
    489 for i, patch in enumerate(
    490         sorted(self.patches,
    491                key=do_3d_projection,
    492                reverse=True)):

File ~/anaconda3/envs/ml/lib/python3.9/site-packages/mpl_toolkits/mplot3d/axes3d.py:471, in Axes3D.draw.<locals>.do_3d_projection(artist)
    458 """
    459 Call `do_3d_projection` on an *artist*, and warn if passing
    460 *renderer*.
   (...)
    464 *renderer* and raise a warning.
    465 """
    467 if artist.__module__ == 'mpl_toolkits.mplot3d.art3d':
    468     # Our 3D Artists have deprecated the renderer parameter, so
    469     # avoid passing it to them; call this directly once the
    470     # deprecation has expired.
--> 471     return artist.do_3d_projection()
    473 _api.warn_deprecated(
    474     "3.4",
    475     message="The 'renderer' parameter of "
    476     "do_3d_projection() was deprecated in Matplotlib "
    477     "%(since)s and will be removed %(removal)s.")
    478 return artist.do_3d_projection(renderer)

File ~/anaconda3/envs/ml/lib/python3.9/site-packages/matplotlib/_api/deprecation.py:431, in delete_parameter.<locals>.wrapper(*inner_args, **inner_kwargs)
    421     deprecation_addendum = (
    422         f"If any parameter follows {name!r}, they should be passed as "
    423         f"keyword, not positionally.")
    424     warn_deprecated(
    425         since,
    426         name=repr(name),
   (...)
    429                  else deprecation_addendum,
    430         **kwargs)
--> 431 return func(*inner_args, **inner_kwargs)

File ~/anaconda3/envs/ml/lib/python3.9/site-packages/mpl_toolkits/mplot3d/art3d.py:599, in Path3DCollection.do_3d_projection(self, renderer)
    597 @_api.delete_parameter('3.4', 'renderer')
    598 def do_3d_projection(self, renderer=None):
--> 599     xs, ys, zs = self._offsets3d
    600     vxs, vys, vzs, vis = proj3d.proj_transform_clip(xs, ys, zs,
    601                                                     self.axes.M)
    602     # Sort the points based on z coordinates
    603     # Performance optimization: Create a sorted index array and reorder
    604     # points and point properties according to the index array

AttributeError: 'Path3DCollection' object has no attribute '_offsets3d'


Versions

[Paste the output of scanpy.logging.print_versions() leaving a blank line after the details tag]

anndata 0.8.0 scanpy 1.9.1

PIL 9.1.1 aa8f2297d25b4dc6fd3d98411eb3ba53823c4f42 NA absl NA asttokens NA astunparse 1.6.3 backcall 0.2.0 batchglm v0.7.4 beta_ufunc NA binom_ufunc NA bottleneck 1.3.4 certifi 2022.05.18.1 cffi 1.15.0 charset_normalizer 2.0.12 cloudpickle 2.1.0 colorama 0.4.5 cycler 0.10.0 cython_runtime NA dask 2022.6.1 dateutil 2.8.2 debugpy 1.6.0 decorator 5.1.1 defusedxml 0.7.1 deprecated 1.2.13 diffxpy v0.7.4 entrypoints 0.4 executing 0.8.3 flatbuffers NA fsspec 2022.5.0 future 0.18.2 gast NA google NA graphtools 1.5.2 h5py 3.7.0 hypergeom_ufunc NA idna 3.3 ipykernel 6.15.0 ipython_genutils 0.2.0 ipywidgets 7.7.0 jedi 0.18.1 jinja2 3.1.2 joblib 1.1.0 keras 2.9.0 kiwisolver 1.4.3 llvmlite 0.38.1 magic 3.0.0 markupsafe 2.1.1 matplotlib 3.4.3 matplotlib_inline NA mkl 2.4.0 mpl_toolkits NA natsort 8.1.0 nbinom_ufunc NA numba 0.55.2 numexpr 2.8.1 numpy 1.22.3 opt_einsum v3.3.0 packaging 21.3 pandas 1.4.2 parso 0.8.3 patsy 0.5.2 pcurve NA pexpect 4.8.0 phate 1.0.7 pickleshare 0.7.5 pkg_resources NA prompt_toolkit 3.0.29 psutil 5.9.1 ptyprocess 0.7.0 pure_eval 0.2.2 pydev_ipython NA pydevconsole NA pydevd 2.8.0 pydevd_file_utils NA pydevd_plugins NA pydevd_tracing NA pygments 2.12.0 pygsp 0.5.1 pyparsing 3.0.9 pytz 2022.1 requests 2.28.0 s_gd2 1.8 scipy 1.8.1 scprep 1.2.0 seaborn 0.11.2 session_info 1.0.0 setuptools 62.6.0 six 1.16.0 sklearn 1.1.1 slingshot NA sparse 0.13.0 stack_data 0.3.0 statsmodels 0.13.2 swig_runtime_data4 NA tasklogger 1.1.2 tensorboard 2.9.1 tensorflow 2.9.1 termcolor 1.1.0 threadpoolctl 3.1.0 tlz 0.11.2 toolz 0.11.2 torch 1.11.0 tornado 6.1 tqdm 4.64.0 traitlets 5.3.0 typing_extensions NA unicodedata2 NA urllib3 1.26.9 wcwidth 0.2.5 wrapt 1.14.1 yaml 6.0 zipp NA zmq 23.1.0

IPython 8.4.0 jupyter_client 7.3.4 jupyter_core 4.10.0 notebook 6.4.12

Python 3.9.12 | packaged by conda-forge | (main, Mar 24 2022, 23:25:59) [GCC 10.3.0] Linux-5.10.16.3-microsoft-standard-WSL2-x86_64-with-glibc2.31

Session information updated at 2022-06-28 16:19

dsm-72 avatar Jun 28 '22 20:06 dsm-72