vitessce 3.6.9__tar.gz → 3.7.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. {vitessce-3.6.9 → vitessce-3.7.1}/PKG-INFO +1 -1
  2. {vitessce-3.6.9 → vitessce-3.7.1}/pyproject.toml +1 -1
  3. {vitessce-3.6.9 → vitessce-3.7.1}/src/vitessce/config.py +24 -0
  4. {vitessce-3.6.9 → vitessce-3.7.1}/src/vitessce/constants.py +1 -0
  5. {vitessce-3.6.9 → vitessce-3.7.1}/src/vitessce/widget.py +43 -27
  6. {vitessce-3.6.9 → vitessce-3.7.1}/src/vitessce/wrappers.py +4 -3
  7. {vitessce-3.6.9 → vitessce-3.7.1}/uv.lock +2 -2
  8. {vitessce-3.6.9 → vitessce-3.7.1}/.coveragerc_omit +0 -0
  9. {vitessce-3.6.9 → vitessce-3.7.1}/.coveragerc_real +0 -0
  10. {vitessce-3.6.9 → vitessce-3.7.1}/.gitignore +0 -0
  11. {vitessce-3.6.9 → vitessce-3.7.1}/.python-version +0 -0
  12. {vitessce-3.6.9 → vitessce-3.7.1}/CHANGELOG.md +0 -0
  13. {vitessce-3.6.9 → vitessce-3.7.1}/LICENSE +0 -0
  14. {vitessce-3.6.9 → vitessce-3.7.1}/MANIFEST.in +0 -0
  15. {vitessce-3.6.9 → vitessce-3.7.1}/Makefile +0 -0
  16. {vitessce-3.6.9 → vitessce-3.7.1}/README.md +0 -0
  17. {vitessce-3.6.9 → vitessce-3.7.1}/setup.cfg +0 -0
  18. {vitessce-3.6.9 → vitessce-3.7.1}/setup.py +0 -0
  19. {vitessce-3.6.9 → vitessce-3.7.1}/src/vitessce/__init__.py +0 -0
  20. {vitessce-3.6.9 → vitessce-3.7.1}/src/vitessce/config_converter.py +0 -0
  21. {vitessce-3.6.9 → vitessce-3.7.1}/src/vitessce/data_utils/__init__.py +0 -0
  22. {vitessce-3.6.9 → vitessce-3.7.1}/src/vitessce/data_utils/anndata.py +0 -0
  23. {vitessce-3.6.9 → vitessce-3.7.1}/src/vitessce/data_utils/entities.py +0 -0
  24. {vitessce-3.6.9 → vitessce-3.7.1}/src/vitessce/data_utils/multivec.py +0 -0
  25. {vitessce-3.6.9 → vitessce-3.7.1}/src/vitessce/data_utils/ome.py +0 -0
  26. {vitessce-3.6.9 → vitessce-3.7.1}/src/vitessce/export.py +0 -0
  27. {vitessce-3.6.9 → vitessce-3.7.1}/src/vitessce/file_def_utils.py +0 -0
  28. {vitessce-3.6.9 → vitessce-3.7.1}/src/vitessce/repr.py +0 -0
  29. {vitessce-3.6.9 → vitessce-3.7.1}/src/vitessce/responses.py +0 -0
  30. {vitessce-3.6.9 → vitessce-3.7.1}/src/vitessce/routes.py +0 -0
  31. {vitessce-3.6.9 → vitessce-3.7.1}/src/vitessce/utils.py +0 -0
  32. {vitessce-3.6.9 → vitessce-3.7.1}/src/vitessce/widget_plugins/__init__.py +0 -0
  33. {vitessce-3.6.9 → vitessce-3.7.1}/src/vitessce/widget_plugins/demo_plugin.py +0 -0
  34. {vitessce-3.6.9 → vitessce-3.7.1}/src/vitessce/widget_plugins/spatial_query.py +0 -0
  35. {vitessce-3.6.9 → vitessce-3.7.1}/tests/__init__.py +0 -0
  36. {vitessce-3.6.9 → vitessce-3.7.1}/tests/create_test_data.py +0 -0
  37. {vitessce-3.6.9 → vitessce-3.7.1}/tests/data/test.ome.tif +0 -0
  38. {vitessce-3.6.9 → vitessce-3.7.1}/tests/test_anndata_utils.py +0 -0
  39. {vitessce-3.6.9 → vitessce-3.7.1}/tests/test_config.py +0 -0
  40. {vitessce-3.6.9 → vitessce-3.7.1}/tests/test_config_converter.py +0 -0
  41. {vitessce-3.6.9 → vitessce-3.7.1}/tests/test_config_updates.py +0 -0
  42. {vitessce-3.6.9 → vitessce-3.7.1}/tests/test_entities.py +0 -0
  43. {vitessce-3.6.9 → vitessce-3.7.1}/tests/test_ome_utils.py +0 -0
  44. {vitessce-3.6.9 → vitessce-3.7.1}/tests/test_wrappers.py +0 -0
  45. {vitessce-3.6.9 → vitessce-3.7.1}/tests-widget/example.spec.js +0 -0
  46. {vitessce-3.6.9 → vitessce-3.7.1}/tests-widget/package.json +0 -0
  47. {vitessce-3.6.9 → vitessce-3.7.1}/tests-widget/playwright.config.js +0 -0
  48. {vitessce-3.6.9 → vitessce-3.7.1}/tests-widget/pnpm-lock.yaml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vitessce
3
- Version: 3.6.9
3
+ Version: 3.7.1
4
4
  Summary: Jupyter widget facilitating interactive visualization of spatial single-cell data with Vitessce
5
5
  Project-URL: repository, https://github.com/vitessce/vitessce-python
6
6
  Author-email: Mark Keller <mark_keller@hms.harvard.edu>
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "vitessce"
7
- version = "3.6.9"
7
+ version = "3.7.1"
8
8
  authors = [
9
9
  { name="Mark Keller", email="mark_keller@hms.harvard.edu" },
10
10
  ]
@@ -925,6 +925,19 @@ class VitessceConfig:
925
925
  del self.background_servers[port]
926
926
 
927
927
  def stop_all_servers(self):
928
+ """
929
+ Stop all background servers associated with this config instance.
930
+
931
+ .. code-block:: python
932
+ :emphasize-lines: 5
933
+
934
+ from vitessce import VitessceConfig
935
+
936
+ vc = VitessceConfig(schema_version="1.0.18", name='My Config')
937
+ vw = vc.widget()
938
+ # ... do something with the widget ...
939
+ vc.stop_all_servers()
940
+ """
928
941
  for server in self.background_servers.values():
929
942
  server.stop()
930
943
  self.background_servers = {}
@@ -1791,6 +1804,17 @@ class VitessceConfig:
1791
1804
  :param int height: The height of the widget, in pixels. By default, 600.
1792
1805
  :param int port: The port to use when serving data objects on localhost. By default, 8000.
1793
1806
  :param bool proxy: Is this widget being served through a proxy, for example with a cloud notebook (e.g. Binder)?
1807
+ :param str js_package_version: The version of the NPM package ('vitessce' if not js_dev_mode else '@vitessce/dev').
1808
+ :param bool js_dev_mode: Should @vitessce/dev be used (typically for debugging purposes)? By default, False.
1809
+ :param str custom_js_url: A URL to a JavaScript file to use (instead of 'vitessce' or '@vitessce/dev' NPM package).
1810
+ :param list[VitesscePlugin] plugins: A list of subclasses of VitesscePlugin. Optional.
1811
+ :param bool remount_on_uid_change: Passed to the remountOnUidChange prop of the <Vitessce/> React component. By default, True.
1812
+ :param bool prefer_local: Should local data be preferred (only applies to `*_artifact` data objects)? By default, True.
1813
+ :param int invoke_timeout: The timeout in milliseconds for invoking Python functions from JavaScript. By default, 300000.
1814
+ :param bool invoke_batched: Should invocations (Zarr gets) be submitted in batch, or individually? By default, True.
1815
+ :param bool page_mode: Whether to render the <Vitessce/> component in grid-mode or page-mode. By default, False.
1816
+ :param str page_esm: The ES module string for the page component creation function. Optional.
1817
+ :param bool prevent_scroll: Should mouseover in the Vitessce widget prevent disable the scrolling of the notebook? By default, True.
1794
1818
 
1795
1819
  :returns: The Jupyter widget.
1796
1820
  :rtype: VitessceWidget
@@ -163,6 +163,7 @@ class FileType(DocEnum):
163
163
  """
164
164
  ANNDATA_ZARR = "anndata.zarr", "Joint file type for AnnData objects"
165
165
  SPATIALDATA_ZARR = "spatialdata.zarr", "Joint file type for SpatialData objects"
166
+ SPATIALDATA_ZARR_ZIP = "spatialdata.zarr.zip", "Joint file type for SpatialData objects in a Zarr directory store that has been zipped"
166
167
  ANNDATA_H5AD = "anndata.h5ad", "Joint file type for AnnData objects"
167
168
  ANNDATA_ZARR_ZIP = "anndata.zarr.zip", "Joint file type for AnnData object in a Zarr directory store that has been zipped"
168
169
  OBS_EMBEDDING_CSV = 'obsEmbedding.csv', "File type for obsEmbedding values stored in a CSV file"
@@ -445,7 +445,7 @@ async function render(view) {
445
445
  function VitessceWidget(props) {
446
446
  const { model, styleContainer } = props;
447
447
 
448
- const [config, setConfig] = React.useState(prependBaseUrl(model.get('config'), model.get('proxy'), model.get('has_host_name')));
448
+ const [config, setConfig] = React.useState(prependBaseUrl(model.get('_config'), model.get('proxy'), model.get('has_host_name')));
449
449
  const [validateConfig, setValidateConfig] = React.useState(true);
450
450
  const height = model.get('height');
451
451
  const theme = model.get('theme') === 'auto' ? (prefersDark ? 'dark' : 'light') : model.get('theme');
@@ -484,7 +484,7 @@ async function render(view) {
484
484
  // Config changed on JS side (from within <Vitessce/>),
485
485
  // send updated config to Python side.
486
486
  const onConfigChange = React.useCallback((config) => {
487
- model.set('config', config);
487
+ model.set('_config', config);
488
488
  setValidateConfig(false);
489
489
  model.save_changes();
490
490
  }, [model]);
@@ -492,8 +492,8 @@ async function render(view) {
492
492
  // Config changed on Python side,
493
493
  // pass to <Vitessce/> component to it is updated on JS side.
494
494
  React.useEffect(() => {
495
- model.on('change:config', () => {
496
- const newConfig = prependBaseUrl(model.get('config'), model.get('proxy'), model.get('has_host_name'));
495
+ model.on('change:_config', () => {
496
+ const newConfig = prependBaseUrl(model.get('_config'), model.get('proxy'), model.get('has_host_name'));
497
497
 
498
498
  // Force a re-render and re-validation by setting a new config.uid value.
499
499
  // TODO: make this conditional on a parameter from Python.
@@ -597,8 +597,12 @@ class VitesscePlugin:
597
597
  """
598
598
  A class that represents a Vitessce widget plugin. Custom plugins can be created by subclassing this class.
599
599
  """
600
- plugin_esm = DEFAULT_PLUGIN_ESM
601
- commands = {}
600
+
601
+ #: The ES module string for the plugin.
602
+ plugin_esm = DEFAULT_PLUGIN_ESM # type: str
603
+
604
+ #: A dictionary mapping command name strings to functions. Functions should take two arguments (message, buffers) and return a tuple (response, buffers).
605
+ commands = {} # type: dict
602
606
 
603
607
  def on_config_change(self, new_config):
604
608
  """
@@ -614,7 +618,16 @@ class VitesscePlugin:
614
618
 
615
619
  class VitessceWidget(anywidget.AnyWidget):
616
620
  """
617
- A class to represent a Jupyter widget for Vitessce.
621
+ A class to represent a Jupyter widget for Vitessce. Not intended to be instantiated directly; instead, use ``VitessceConfig.widget``.
622
+
623
+ .. code-block:: python
624
+ :emphasize-lines: 4
625
+
626
+ from vitessce import VitessceConfig
627
+
628
+ vc = VitessceConfig.from_object(my_scanpy_object)
629
+ vw = vc.widget()
630
+ vw
618
631
  """
619
632
  _esm = ESM
620
633
 
@@ -622,7 +635,13 @@ class VitessceWidget(anywidget.AnyWidget):
622
635
  # Widget properties are defined as traitlets. Any property tagged with `sync=True`
623
636
  # is automatically synced to the frontend *any* time it changes in Python.
624
637
  # It is synced back to Python from the frontend *any* time the model is touched.
625
- config = Dict({}).tag(sync=True)
638
+
639
+ #: Dictionary representation of the Vitessce JSON configuration. Synced via traitlets upon interactions.
640
+ _config = Dict({}).tag(sync=True) # type: dict
641
+
642
+ #: The VitessceConfig instance used to create this widget. Not synced upon interactions.
643
+ config = None # type: vitessce.config.VitessceConfig
644
+
626
645
  height = Int(600).tag(sync=True)
627
646
  theme = Unicode('auto').tag(sync=True)
628
647
  proxy = Bool(False).tag(sync=True)
@@ -631,7 +650,7 @@ class VitessceWidget(anywidget.AnyWidget):
631
650
 
632
651
  next_port = DEFAULT_PORT
633
652
 
634
- js_package_version = Unicode('3.6.11').tag(sync=True)
653
+ js_package_version = Unicode('3.6.13').tag(sync=True)
635
654
  js_dev_mode = Bool(False).tag(sync=True)
636
655
  custom_js_url = Unicode('').tag(sync=True)
637
656
  plugin_esm = List(trait=Unicode(''), default_value=[]).tag(sync=True)
@@ -644,9 +663,9 @@ class VitessceWidget(anywidget.AnyWidget):
644
663
 
645
664
  store_urls = List(trait=Unicode(''), default_value=[]).tag(sync=True)
646
665
 
647
- def __init__(self, config, height=600, theme='auto', uid=None, port=None, proxy=False, js_package_version='3.6.11', js_dev_mode=False, custom_js_url='', plugins=None, remount_on_uid_change=True, prefer_local=True, invoke_timeout=300000, invoke_batched=True, page_mode=False, page_esm=None, prevent_scroll=True):
666
+ def __init__(self, config, height=600, theme='auto', uid=None, port=None, proxy=False, js_package_version='3.6.13', js_dev_mode=False, custom_js_url='', plugins=None, remount_on_uid_change=True, prefer_local=True, invoke_timeout=300000, invoke_batched=True, page_mode=False, page_esm=None, prevent_scroll=True):
648
667
  """
649
- Construct a new Vitessce widget.
668
+ Construct a new Vitessce widget. Not intended to be instantiated directly; instead, use ``VitessceConfig.widget``.
650
669
 
651
670
  :param config: A view config instance.
652
671
  :type config: VitessceConfig
@@ -666,19 +685,16 @@ class VitessceWidget(anywidget.AnyWidget):
666
685
  :param str page_esm: The ES module string for the page component creation function. Optional.
667
686
  :param bool prevent_scroll: Should mouseover in the Vitessce widget prevent disable the scrolling of the notebook? By default, True.
668
687
 
669
- .. code-block:: python
670
- :emphasize-lines: 4
671
-
672
- from vitessce import VitessceConfig, VitessceWidget
673
-
674
- vc = VitessceConfig.from_object(my_scanpy_object)
675
- vw = vc.widget()
676
- vw
688
+ Note: these parameter docstrings need to be manually kept in sync with the VitessceConfig.widget docstring.
677
689
  """
678
690
 
679
691
  base_url, use_port, VitessceWidget.next_port = get_base_url_and_port(
680
692
  port, VitessceWidget.next_port, proxy=proxy)
681
- self.config_obj = config
693
+ # Note:
694
+ # - self.config is the VitessceConfig instance.
695
+ # - self._config is the JSON configuration, synced via traitlets
696
+
697
+ self.config = config
682
698
  self.port = use_port
683
699
  config_dict = config.to_dict(base_url=base_url)
684
700
  routes = config.get_routes()
@@ -694,7 +710,7 @@ class VitessceWidget(anywidget.AnyWidget):
694
710
  uid_str = get_uid_str(uid)
695
711
 
696
712
  super(VitessceWidget, self).__init__(
697
- config=config_dict, height=height, theme=theme, proxy=proxy,
713
+ _config=config_dict, height=height, theme=theme, proxy=proxy,
698
714
  js_package_version=js_package_version, js_dev_mode=js_dev_mode, custom_js_url=custom_js_url,
699
715
  plugin_esm=plugin_esm, remount_on_uid_change=remount_on_uid_change,
700
716
  page_mode=page_mode, page_esm=('' if page_esm is None else page_esm),
@@ -712,14 +728,14 @@ class VitessceWidget(anywidget.AnyWidget):
712
728
  # It is optional for plugins to implement on_config_change.
713
729
  pass
714
730
  if new_config is not None:
715
- self.config = new_config
731
+ self._config = new_config
716
732
 
717
- self.observe(handle_config_change, names=['config'])
733
+ self.observe(handle_config_change, names=['_config'])
718
734
 
719
735
  serve_routes(config, routes, use_port)
720
736
 
721
737
  def _get_coordination_value(self, coordination_type, coordination_scope):
722
- obj = self.config['coordinationSpace'][coordination_type]
738
+ obj = self._config['coordinationSpace'][coordination_type]
723
739
  obj_scopes = list(obj.keys())
724
740
  if coordination_scope is not None:
725
741
  if coordination_scope in obj_scopes:
@@ -742,7 +758,7 @@ class VitessceWidget(anywidget.AnyWidget):
742
758
  return self._get_coordination_value('cellSelection', scope)
743
759
 
744
760
  def close(self):
745
- self.config_obj.stop_server(self.port)
761
+ self.config.stop_server(self.port)
746
762
  super().close()
747
763
 
748
764
  @anywidget.experimental.command
@@ -780,7 +796,7 @@ class VitessceWidget(anywidget.AnyWidget):
780
796
  # Launch Vitessce using plain HTML representation (no ipywidgets)
781
797
 
782
798
 
783
- def ipython_display(config, height=600, theme='auto', base_url=None, host_name=None, uid=None, port=None, proxy=False, js_package_version='3.6.11', js_dev_mode=False, custom_js_url='', plugins=None, remount_on_uid_change=True, page_mode=False, page_esm=None):
799
+ def ipython_display(config, height=600, theme='auto', base_url=None, host_name=None, uid=None, port=None, proxy=False, js_package_version='3.6.13', js_dev_mode=False, custom_js_url='', plugins=None, remount_on_uid_change=True, page_mode=False, page_esm=None):
784
800
  from IPython.display import display, HTML
785
801
  uid_str = "vitessce" + get_uid_str(uid)
786
802
 
@@ -808,7 +824,7 @@ def ipython_display(config, height=600, theme='auto', base_url=None, host_name=N
808
824
  "has_host_name": host_name is not None,
809
825
  "height": height,
810
826
  "theme": theme,
811
- "config": config_dict,
827
+ "_config": config_dict,
812
828
  "store_urls": [],
813
829
  }
814
830
 
@@ -1399,7 +1399,7 @@ SpatialDataWrapperType = TypeVar('SpatialDataWrapperType', bound='SpatialDataWra
1399
1399
 
1400
1400
  class SpatialDataWrapper(AnnDataWrapper):
1401
1401
 
1402
- def __init__(self, sdata_path: Optional[str] = None, sdata_url: Optional[str] = None, sdata_store: Optional[Union[str, zarr.storage.StoreLike]] = None, sdata_artifact: Optional[ln.Artifact] = None, image_path: Optional[str] = None, region: Optional[str] = None, coordinate_system: Optional[str] = None, obs_spots_path: Optional[str] = None, obs_segmentations_path: Optional[str] = None, table_path: str = "tables/table", coordination_values=None, **kwargs):
1402
+ def __init__(self, sdata_path: Optional[str] = None, sdata_url: Optional[str] = None, sdata_store: Optional[Union[str, zarr.storage.StoreLike]] = None, sdata_artifact: Optional[ln.Artifact] = None, image_path: Optional[str] = None, region: Optional[str] = None, coordinate_system: Optional[str] = None, obs_spots_path: Optional[str] = None, obs_segmentations_path: Optional[str] = None, table_path: str = "tables/table", is_zip=None, coordination_values=None, **kwargs):
1403
1403
  """
1404
1404
  Wrap a SpatialData object.
1405
1405
 
@@ -1415,6 +1415,7 @@ class SpatialDataWrapper(AnnDataWrapper):
1415
1415
  :type image_path: Optional[str]
1416
1416
  :param coordinate_system: Name of a target coordinate system.
1417
1417
  :type coordinate_system: Optional[str]
1418
+ :param is_zip: Boolean indicating whether the Zarr store is in a zipped format.
1418
1419
  :param affine_transformation: Transformation to be applied to the image. By default, None. Prefer coordinate_system.
1419
1420
  :type affine_transformation: Optional[np.ndarray]
1420
1421
  :param obs_spots_path: Location of shapes that should be interpreted as spot observations, by default None
@@ -1434,7 +1435,7 @@ class SpatialDataWrapper(AnnDataWrapper):
1434
1435
  kwargs.get('adata_store', None),
1435
1436
  kwargs.get('adata_artifact', None)
1436
1437
  ])
1437
- super().__init__(adata_path=sdata_path, adata_url=sdata_url, adata_store=sdata_store, adata_artifact=sdata_artifact, **kwargs)
1438
+ super().__init__(adata_path=sdata_path, adata_url=sdata_url, adata_store=sdata_store, adata_artifact=sdata_artifact, is_zip=is_zip, **kwargs)
1438
1439
  if "labels_path" in kwargs:
1439
1440
  warnings.warn("`labels_path` is deprecated. Use `obs_segmentations_path` instead.", DeprecationWarning)
1440
1441
  self._obs_segmentations_path = kwargs["labels_path"]
@@ -1540,7 +1541,7 @@ class SpatialDataWrapper(AnnDataWrapper):
1540
1541
  options = gen_feature_labels_schema(self._feature_labels, options)
1541
1542
  if len(options.keys()) > 0:
1542
1543
  obj_file_def = {
1543
- "fileType": ft.SPATIALDATA_ZARR.value,
1544
+ "fileType": ft.SPATIALDATA_ZARR_ZIP.value if self.is_zip else ft.SPATIALDATA_ZARR.value,
1544
1545
  "url": self.get_zarr_url(base_url, dataset_uid, obj_i),
1545
1546
  "options": options
1546
1547
  }
@@ -1,5 +1,5 @@
1
1
  version = 1
2
- revision = 2
2
+ revision = 3
3
3
  requires-python = ">=3.10"
4
4
  resolution-markers = [
5
5
  "python_full_version < '3.11'",
@@ -4496,7 +4496,7 @@ wheels = [
4496
4496
 
4497
4497
  [[package]]
4498
4498
  name = "vitessce"
4499
- version = "3.6.9"
4499
+ version = "3.7.1"
4500
4500
  source = { editable = "." }
4501
4501
  dependencies = [
4502
4502
  { name = "black" },
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes