marsilea 0.4.7__py3-none-any.whl → 0.5.0__py3-none-any.whl

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.
marsilea/__init__.py CHANGED
@@ -1,6 +1,6 @@
1
1
  """Declarative creation of composable visualization"""
2
2
 
3
- __version__ = "0.4.7"
3
+ __version__ = "0.5.0"
4
4
 
5
5
  import marsilea.plotter as plotter
6
6
  from ._deform import Deformation
marsilea/base.py CHANGED
@@ -169,7 +169,14 @@ class LegendMaker:
169
169
  for _, legs in legends.items():
170
170
  for leg in legs:
171
171
  try:
172
+ # Try to detach legend from figure
172
173
  leg.remove()
174
+ # For matplotlib >= 3.10.0
175
+ if hasattr(leg, "_parent_figure"):
176
+ setattr(leg, "_parent_figure", None)
177
+ # For matplotlib < 3.10.0
178
+ if hasattr(leg, "figure"):
179
+ setattr(leg, "figure", None)
173
180
  except Exception:
174
181
  pass
175
182
 
@@ -1135,142 +1142,6 @@ class ClusterBoard(WhiteBoard):
1135
1142
  rasterized=rasterized,
1136
1143
  )
1137
1144
 
1138
- def hsplit(self, cut=None, labels=None, order=None, spacing=0.01):
1139
- """Split the main canvas horizontally
1140
-
1141
- .. deprecated:: 0.5.0
1142
- Use :meth:`~marsilea.base.ClusterBoard.cut_rows` \
1143
- or :meth:`~marsilea.base.ClusterBoard.group_rows` instead
1144
-
1145
- Parameters
1146
- ----------
1147
- cut : array-like, optional
1148
- The index of your data to specify where to split the canvas
1149
- labels : array-like, optional
1150
- The labels of your data, must be the same length as the data
1151
- order : array-like, optional
1152
- The order of the unique labels
1153
- spacing : float, optional
1154
- The spacing between each split chunks, default is 0.01
1155
-
1156
- Examples
1157
- --------
1158
- Split the canvas by the unique labels
1159
-
1160
- .. plot::
1161
- :context: close-figs
1162
-
1163
- >>> data = np.random.rand(10, 11)
1164
- >>> import marsilea as ma
1165
- >>> h = ma.Heatmap(data)
1166
- >>> labels = ["A", "B", "C", "A", "B", "C", "A", "B", "C", "A"]
1167
- >>> h.hsplit(labels=labels, order=["A", "B", "C"])
1168
- >>> h.add_left(ma.plotter.Labels(labels), pad=.1)
1169
- >>> h.render()
1170
-
1171
-
1172
- Split the canvas by the index
1173
-
1174
- .. plot::
1175
- :context: close-figs
1176
-
1177
- >>> h = ma.Heatmap(data)
1178
- >>> h.hsplit(cut=[4, 8])
1179
- >>> h.render()
1180
-
1181
-
1182
- """
1183
- warnings.warn(
1184
- DeprecationWarning(
1185
- "`hsplit` will be deprecated in v0.5.0, use `cut_rows` or `group_rows` instead"
1186
- ),
1187
- stacklevel=2,
1188
- )
1189
- if self._split_row:
1190
- raise SplitTwice(axis="horizontally")
1191
- self._split_row = True
1192
-
1193
- deform = self.get_deform()
1194
- deform.hspace = spacing
1195
- if cut is not None:
1196
- deform.set_split_row(breakpoints=cut)
1197
- else:
1198
- labels = np.asarray(labels)
1199
-
1200
- reindex, order = reorder_index(labels, order=order)
1201
- deform.set_data_row_reindex(reindex)
1202
-
1203
- breakpoints = get_breakpoints(labels[reindex])
1204
- deform.set_split_row(breakpoints=breakpoints, order=order)
1205
-
1206
- def vsplit(self, cut=None, labels=None, order=None, spacing=0.01):
1207
- """Split the main canvas vertically
1208
-
1209
- .. deprecated:: 0.5.0
1210
- Use :meth:`~marsilea.base.ClusterBoard.cut_cols` \
1211
- or :meth:`~marsilea.base.ClusterBoard.group_cols` instead
1212
-
1213
- Parameters
1214
- ----------
1215
- cut : array-like, optional
1216
- The index of your data to specify where to split the canvas
1217
- labels : array-like, optional
1218
- The labels of your data, must be the same length as the data
1219
- order : array-like, optional
1220
- The order of the unique labels
1221
- spacing : float, optional
1222
- The spacing between each split chunks, default is 0.01
1223
-
1224
- Examples
1225
- --------
1226
- Split the canvas by the unique labels
1227
-
1228
- .. plot::
1229
- :context: close-figs
1230
-
1231
- >>> data = np.random.rand(10, 11)
1232
- >>> import marsilea as ma
1233
- >>> h = ma.Heatmap(data)
1234
- >>> labels = ["A", "B", "C", "A", "B", "C", "A", "B", "C", "A", "B"]
1235
- >>> h.vsplit(labels=labels, order=["A", "B", "C"])
1236
- >>> h.add_top(ma.plotter.Labels(labels), pad=.1)
1237
- >>> h.render()
1238
-
1239
-
1240
- Split the canvas by the index
1241
-
1242
- .. plot::
1243
- :context: close-figs
1244
-
1245
- >>> h = ma.Heatmap(data)
1246
- >>> h.vsplit(cut=[4, 8])
1247
- >>> h.render()
1248
-
1249
-
1250
- """
1251
- warnings.warn(
1252
- DeprecationWarning(
1253
- "`vsplit` will be deprecated in v0.5.0, use `cut_cols` or `group_cols` instead"
1254
- ),
1255
- stacklevel=2,
1256
- )
1257
- if self._split_col:
1258
- raise SplitTwice(axis="vertically")
1259
- self._split_col = True
1260
-
1261
- deform = self.get_deform()
1262
- deform.wspace = spacing
1263
- if cut is not None:
1264
- deform.set_split_col(breakpoints=cut)
1265
- else:
1266
- labels = np.asarray(labels)
1267
-
1268
- reindex, order = reorder_index(labels, order=order)
1269
- deform.set_data_col_reindex(reindex)
1270
-
1271
- breakpoints = get_breakpoints(labels[reindex])
1272
- deform.set_split_col(breakpoints=breakpoints, order=order)
1273
-
1274
1145
  def group_rows(self, group, order=None, spacing=0.01):
1275
1146
  """Group rows into chunks
1276
1147
 
marsilea/heatmap.py CHANGED
@@ -50,6 +50,7 @@ class Heatmap(ClusterBoard):
50
50
  height=None,
51
51
  cluster_data=None,
52
52
  init_main=True,
53
+ legend=True,
53
54
  **kwargs,
54
55
  ):
55
56
  if cluster_data is None:
@@ -80,7 +81,7 @@ class Heatmap(ClusterBoard):
80
81
  )
81
82
  name = get_plot_name(name, "main", mesh.__class__.__name__)
82
83
  mesh.set(name=name)
83
- self.add_layer(mesh)
84
+ self.add_layer(mesh, legend=legend)
84
85
 
85
86
 
86
87
  class CatHeatmap(ClusterBoard):
@@ -109,6 +110,7 @@ class CatHeatmap(ClusterBoard):
109
110
  name=None,
110
111
  width=None,
111
112
  height=None,
113
+ legend=True,
112
114
  cluster_data=None,
113
115
  linewidth=0,
114
116
  linecolor="white",
@@ -128,7 +130,7 @@ class CatHeatmap(ClusterBoard):
128
130
  super().__init__(cluster_data, width=width, height=height, name=name)
129
131
  name = get_plot_name(name, "main", mesh.__class__.__name__)
130
132
  mesh.set(name=name)
131
- self.add_layer(mesh)
133
+ self.add_layer(mesh, legend=legend)
132
134
 
133
135
 
134
136
  class SizedHeatmap(ClusterBoard):
@@ -156,6 +158,7 @@ class SizedHeatmap(ClusterBoard):
156
158
  name=None,
157
159
  width=None,
158
160
  height=None,
161
+ legend=True,
159
162
  **kwargs,
160
163
  ):
161
164
  if cluster_data is None:
@@ -166,4 +169,4 @@ class SizedHeatmap(ClusterBoard):
166
169
  super().__init__(cluster_data, width=width, height=height, name=name)
167
170
 
168
171
  mesh = SizedMesh(size=size, color=color, **kwargs)
169
- self.add_layer(mesh)
172
+ self.add_layer(mesh, legend=legend)
marsilea/plotter/arc.py CHANGED
@@ -231,11 +231,9 @@ class Arc(StatsBase):
231
231
  ax.set_ylim(lim * 1.1, 0)
232
232
  ax.set_xlim(0, 1)
233
233
  if self.side == "top":
234
- if not ax.yaxis_inverted():
235
- ax.invert_yaxis()
234
+ ax.invert_yaxis()
236
235
  if self.side == "left":
237
- if not ax.xaxis_inverted():
238
- ax.invert_xaxis()
236
+ ax.invert_xaxis()
239
237
  ax.set_axis_off()
240
238
 
241
239
  def get_legends(self):
marsilea/plotter/area.py CHANGED
@@ -90,8 +90,7 @@ class Area(StatsBase):
90
90
  ax.plot(data, x, **line_options)
91
91
  ax.set_ylim(-0.5, len(data) - 0.5)
92
92
  if self.side == "left":
93
- if not ax.xaxis_inverted():
94
- ax.invert_xaxis()
93
+ ax.invert_xaxis()
95
94
  else:
96
95
  ax.fill_between(x, data, **fill_options)
97
96
  if self.add_outline:
marsilea/plotter/bar.py CHANGED
@@ -270,8 +270,7 @@ class CenterBar(_BarBase):
270
270
  ax.xaxis.set_major_formatter(FuncFormatter(lambda x, p: f"{np.abs(x):g}"))
271
271
 
272
272
  if self.is_flank:
273
- if not ax.yaxis_inverted():
274
- ax.invert_yaxis()
273
+ ax.invert_yaxis()
275
274
 
276
275
  if self.show_value:
277
276
  left_label = _format_labels(left_bar, self.fmt)
marsilea/plotter/bio.py CHANGED
@@ -171,12 +171,9 @@ class SeqLogo(StatsBase):
171
171
  ax.set_xlim(0, lim)
172
172
  ax.set_ylim(0, data.shape[1])
173
173
  if self.is_flank:
174
- if not ax.yaxis_inverted():
175
- ax.invert_yaxis()
174
+ ax.invert_yaxis()
176
175
  if self.side == "left":
177
- if not ax.xaxis_inverted():
178
- ax.invert_xaxis()
176
+ ax.invert_xaxis()
179
177
  if self.side == "bottom":
180
- if not ax.yaxis_inverted():
181
- ax.invert_yaxis()
178
+ ax.invert_yaxis()
182
179
  ax.set_axis_off()
marsilea/plotter/range.py CHANGED
@@ -125,8 +125,7 @@ class Range(StatsBase):
125
125
  else:
126
126
  ax.set_xlim(0, len(data))
127
127
  if self.side == "left":
128
- if not ax.xaxis_inverted():
129
- ax.invert_xaxis()
128
+ ax.invert_xaxis()
130
129
 
131
130
  def get_legends(self):
132
131
  return [
marsilea/upset.py CHANGED
@@ -947,7 +947,7 @@ class Upset(WhiteBoard):
947
947
  def _extra_legends(self):
948
948
  handles = [Patch(**entry) for entry in self._legend_entries]
949
949
  highlight_legend = ListLegend(handles=handles, handlelength=2)
950
- highlight_legend.figure = None
950
+ # highlight_legend.set_figure(None)
951
951
  return {"highlight_subsets": [highlight_legend]}
952
952
 
953
953
  def render(self, figure=None, scale=1):
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: marsilea
3
- Version: 0.4.7
4
- Dynamic: Summary
3
+ Version: 0.5.0
4
+ Summary: Declarative creation of composable visualizations
5
5
  Project-URL: Home, https://github.com/Marsilea-viz/marsilea
6
- Author: Zhihang Zheng
7
- Author-email: Mr-Milk <yzheng@cemm.at>
6
+ Project-URL: Documentation, https://marsilea.readthedocs.io
7
+ Author-email: Yimin Zheng <yzheng@cemm.at>, Zhihang Zheng <zhihang.zheng@connect.polyu.hk>
8
8
  License: The MIT License (MIT)
9
9
 
10
- Copyright (c) 2024 Mr-Milk
10
+ Copyright (c) 2025 Yimin Zheng
11
11
 
12
12
  Permission is hereby granted, free of charge, to any person obtaining a copy
13
13
  of this software and associated documentation files (the "Software"), to deal
@@ -30,6 +30,8 @@ License-File: LICENSE
30
30
  Classifier: Framework :: Matplotlib
31
31
  Classifier: License :: OSI Approved :: MIT License
32
32
  Classifier: Programming Language :: Python :: 3
33
+ Classifier: Topic :: Scientific/Engineering
34
+ Classifier: Topic :: Scientific/Engineering :: Visualization
33
35
  Requires-Python: >=3.8
34
36
  Requires-Dist: legendkit
35
37
  Requires-Dist: matplotlib>=3.6
@@ -38,20 +40,6 @@ Requires-Dist: pandas[parquet]
38
40
  Requires-Dist: platformdirs
39
41
  Requires-Dist: scipy
40
42
  Requires-Dist: seaborn
41
- Provides-Extra: dev
42
- Requires-Dist: icecream; extra == 'dev'
43
- Requires-Dist: mpl-fontkit; extra == 'dev'
44
- Requires-Dist: numpydoc; extra == 'dev'
45
- Requires-Dist: pre-commit; extra == 'dev'
46
- Requires-Dist: pydata-sphinx-theme; extra == 'dev'
47
- Requires-Dist: pytest; extra == 'dev'
48
- Requires-Dist: python-hmr; extra == 'dev'
49
- Requires-Dist: ruff; extra == 'dev'
50
- Requires-Dist: scikit-learn; extra == 'dev'
51
- Requires-Dist: sphinx; extra == 'dev'
52
- Requires-Dist: sphinx-copybutton; extra == 'dev'
53
- Requires-Dist: sphinx-design; extra == 'dev'
54
- Requires-Dist: sphinx-gallery; extra == 'dev'
55
43
  Description-Content-Type: text/markdown
56
44
 
57
45
  <p align="center">
@@ -66,6 +54,7 @@ Description-Content-Type: text/markdown
66
54
  ![pypi version](https://img.shields.io/pypi/v/marsilea?color=0098FF&logo=python&logoColor=white&style=flat-square)
67
55
  ![Conda Version](https://img.shields.io/conda/vn/conda-forge/marsilea?style=flat-square&logo=anaconda&logoColor=white&color=%2344A833)
68
56
  ![PyPI - License](https://img.shields.io/pypi/l/marsilea?color=FFD43B&style=flat-square)
57
+ [![DOI](https://img.shields.io/badge/DOI-10.1186%2Fs13059--024--03469--3-blue?color=0098FF&style=flat-square)](https://doi.org/10.1186/s13059-024-03469-3)
69
58
 
70
59
  # Marsilea: Declarative creation of composable visualization!
71
60
 
@@ -104,6 +93,16 @@ and then create a bar chart to show the expression of genes in different cell ty
104
93
  A visualization contains multiple plots is called a composable visualization.
105
94
  In Marsilea, we employ a declarative approach for user to create composable visualization incrementally.
106
95
 
96
+ ## Citation
97
+
98
+ If you use Marsilea in your research, please cite the following:
99
+
100
+ > Marsilea: an intuitive generalized paradigm for composable visualizations
101
+ >
102
+ > Yimin Zheng, Zhihang Zheng, André F. Rendeiro & Edwin Cheung
103
+ >
104
+ > _Genome Biology_ 2025 Jan 06. DOI: [10.1186/s13059-017-1382-0](https://doi.org/10.1186/s13059-024-03469-3)
105
+
107
106
  ## Examples
108
107
 
109
108
  <table>
@@ -1,31 +1,31 @@
1
- marsilea/__init__.py,sha256=b_Tj0KRFEksVgd6EPUVp5XtnbmdU-LRgaw0jW_NOPWg,595
1
+ marsilea/__init__.py,sha256=0ws5dRLTu-1jr567U5FStwBhguxacSpj6oijY_23Eio,595
2
2
  marsilea/_api.py,sha256=tymWZHfjhx8-0NNd9762znfdIu36NrARRweEIr5L1mA,283
3
3
  marsilea/_deform.py,sha256=QRz4OGXMsQzbiIkC3ASzZayMPhHhoFsEK38oBzSeQG8,14440
4
- marsilea/base.py,sha256=DOjsR3kzDTnE-YzCVHHL4J1O3kzXeFL1XW9CxPYa3S4,50842
4
+ marsilea/base.py,sha256=CmzuwFu0JzgkNpPdI1SqAnkUxINShjT73hrJpksKjhE,46872
5
5
  marsilea/dataset.py,sha256=Qh8k1DhTiwP_Me709CkpNwRaYLDzlenRTIk0U6D58_g,4631
6
6
  marsilea/dendrogram.py,sha256=Ung43zseybZKzTEvH5P_ge3WGfsr7i7qsX7YEVDlC74,15590
7
7
  marsilea/exceptions.py,sha256=wN5ElUZxuaJKSnnwWdkNx6P-Oc16dzSuaRPbRKWIBEM,1046
8
- marsilea/heatmap.py,sha256=UhRcBFhx1JKrtndZPvQCDaiMt8Pb314PT1BtL-JndCY,4208
8
+ marsilea/heatmap.py,sha256=8Wo1NxFTBp1a7NOISmer0yQYWWgf51Xsvjav1h1vTYk,4316
9
9
  marsilea/layers.py,sha256=puXLlGGpEqAzaTqadpgpsYmIDPH33WyyHIuysRSqFZQ,12163
10
10
  marsilea/layout.py,sha256=yNuGvIDfWjbCksQZO-4aUWSA78LJwBBKF5Z5cthC6fM,39741
11
- marsilea/upset.py,sha256=U1Rsmo1WpCAV9z3LBlE2L4T0nAW9ols8Z36fXzmXycw,30388
11
+ marsilea/upset.py,sha256=JnqV9HYYpoeLt-6yMy0HN_PUSgV-ENasf6vq6HsX3cI,30393
12
12
  marsilea/utils.py,sha256=y_KYs4ToiuKEsiBdmcIVtmxMXFpD4wKiJ0k7iBa11z8,2854
13
13
  marsilea/plotter/__init__.py,sha256=la30o20zYiHWN2RzElhS8MMCbGKbDDEe0WHXakq9OBQ,806
14
14
  marsilea/plotter/_seaborn.py,sha256=Ahy5id35KV-PZ50rI5lmEpA4Oov51u8w6VVQzVZH6hM,8330
15
15
  marsilea/plotter/_utils.py,sha256=Efhdk-TrrAanhbXRiEVWThMYvZ4vVHZMVYMs5X3JvIM,710
16
- marsilea/plotter/arc.py,sha256=5sSUcqVzzyA6ijlExlrzCNcVwyUzls12eHd4sm7sTSQ,8227
17
- marsilea/plotter/area.py,sha256=34Q8JABaYJLziFkt97LXgy-DH6YLpRg9ePX3YTOfKlg,2698
18
- marsilea/plotter/bar.py,sha256=ByX_1aSPHbb1o_qwuFPRisUppCc8sdrtTj0ZShPdCCo,12398
16
+ marsilea/plotter/arc.py,sha256=44BKVGvDc_OpghfgEvaiVCovZe7_OwZiM20iepaRMFw,8139
17
+ marsilea/plotter/area.py,sha256=zjjAhvgKHYe9rqzcseqZqhwfpgvzm0w2FRJ_vr9Fxm4,2650
18
+ marsilea/plotter/bar.py,sha256=RWDsNbyCUKbybpsBOgbl43lVZc_ynZmTOevE-CtJ5KE,12354
19
19
  marsilea/plotter/base.py,sha256=b_NmrW_oNPc-HwQsjx1NsC2lknYK6qSaDp_7SxeoUEM,18938
20
- marsilea/plotter/bio.py,sha256=9W69WNPNi9TN5ccxc5LXxYEVnon-ZgtY-RdpaaS22eU,5172
20
+ marsilea/plotter/bio.py,sha256=34tucmxs4LM3TFZoGsrjnXTolyrzYaHVEiRe4dzDH68,5040
21
21
  marsilea/plotter/images.py,sha256=gb0xIQhUch3rNAt3FfvuUoamSGEynoBBBky2eE754ec,9560
22
22
  marsilea/plotter/mesh.py,sha256=4jTa05GQsxStDur6FkrNGXAIHUsoipFEDydP8CMCExE,24376
23
- marsilea/plotter/range.py,sha256=iLFPCZkgh5RrP6nqdI2-J1PisWQRmYLR8sFMRarlkZQ,3814
23
+ marsilea/plotter/range.py,sha256=sXWKrvpq7nU7giiHPjayM7h9Q7gblhjXxHm8ioB3cm4,3770
24
24
  marsilea/plotter/text.py,sha256=6S4mnAxLJLMkduKiyor03lPd86oTOJ5TojVREA9oU6s,37466
25
25
  oncoprinter/__init__.py,sha256=efshcAD1h9s-NVJj4HLU9-hXc_LtTeIrNYqLHl-sm_g,106
26
26
  oncoprinter/core.py,sha256=5KPnKW5ivlxPp14uJd0OtfTv-pXV2UEym8EbII2VCcw,11846
27
27
  oncoprinter/preset.py,sha256=mBk2tFCqoTj_1ZZKRYuv4j2I3NTBa6Swc9wjzbmxRVw,8238
28
- marsilea-0.4.7.dist-info/METADATA,sha256=blEo9TyIG-VKJG4b7_N1hYeud35761rtfIguJFSKXyc,6866
29
- marsilea-0.4.7.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
30
- marsilea-0.4.7.dist-info/licenses/LICENSE,sha256=2TLD8FnLJqXzg8YBRs7W3VZBwfWfp4ArDfBl-rn96Qc,1074
31
- marsilea-0.4.7.dist-info/RECORD,,
28
+ marsilea-0.5.0.dist-info/METADATA,sha256=lC8_51jHvIq0C6-k536cXZzsNGvYrx3ZqnOnOR74s2M,7023
29
+ marsilea-0.5.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
30
+ marsilea-0.5.0.dist-info/licenses/LICENSE,sha256=RhHHDuP61qzKmfHtOQUVLZfCgMkKx9PXzxzkLtmAjHo,1078
31
+ marsilea-0.5.0.dist-info/RECORD,,
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2024 Mr-Milk
3
+ Copyright (c) 2025 Yimin Zheng
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal