marsilea 0.4.2__py3-none-any.whl → 0.4.4__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.
oncoprinter/preset.py ADDED
@@ -0,0 +1,258 @@
1
+ from dataclasses import dataclass, field
2
+ from enum import Enum, auto
3
+ from typing import List
4
+
5
+ import marsilea.layers as mlayers
6
+ import numpy as np
7
+ from matplotlib.collections import PatchCollection
8
+ from matplotlib.patches import Rectangle
9
+
10
+ # The preset follows the style of cBioPortal as much as possible
11
+ # https://github.com/cBioPortal/cbioportal-frontend/blob/master/src/shared/components/oncoprint/geneticrules.ts
12
+ MUT_COLOR_MISSENSE = "#008000"
13
+ MUT_COLOR_MISSENSE_PASSENGER = "#53D400"
14
+ MUT_COLOR_INFRAME = "#993404"
15
+ MUT_COLOR_INFRAME_PASSENGER = "#a68028"
16
+ MUT_COLOR_TRUNC = "#000000"
17
+ MUT_COLOR_TRUNC_PASSENGER = "#708090"
18
+ MUT_COLOR_SPLICE = "#e5802b"
19
+ MUT_COLOR_SPLICE_PASSENGER = "#f0b87b"
20
+ MUT_COLOR_PROMOTER = "#00B7CE"
21
+ MUT_COLOR_OTHER = "#cf58bc"
22
+
23
+ MUT_DRIVER = "#000000"
24
+ MUT_VUS = "#696969"
25
+ MUT_COLOR_GERMLINE = "#FFFFFF"
26
+
27
+ MRNA_COLOR_HIGH = "#ff9999"
28
+ MRNA_COLOR_LOW = "#6699cc"
29
+
30
+ PROT_COLOR_HIGH = "#ff3df8"
31
+ PROT_COLOR_LOW = "#00E1FF"
32
+
33
+ CNA_COLOR_AMP = "#ff0000"
34
+ CNA_COLOR_GAIN = "#ffb6c1"
35
+ CNA_COLOR_HETLOSS = "#8fd8d8"
36
+ CNA_COLOR_HOMDEL = "#0000ff"
37
+
38
+ MUT_COLOR_FUSION = "#C900A1"
39
+ STRUCTURAL_VARIANT_COLOR = "#8B00C9"
40
+ STRUCTURAL_VARIANT_PASSENGER_COLOR = "#ce92e8"
41
+
42
+ DEFAULT_GREY = "#BEBEBE"
43
+
44
+
45
+ class Alteration(Enum):
46
+ BACKGROUND = auto()
47
+ AMP = auto()
48
+ GAIN = auto()
49
+ HOMDEL = auto()
50
+ HETLOSS = auto()
51
+ MRNA_HIGH = auto()
52
+ MRNA_LOW = auto()
53
+ PROTEIN_HIGH = auto()
54
+ PROTEIN_LOW = auto()
55
+ FUSION = auto()
56
+ GERMLINE = auto()
57
+ SPLICE = auto()
58
+ SPLICE_PASSENGER = auto()
59
+ MISSENSE = auto()
60
+ MISSENSE_PASSENGER = auto()
61
+ PROMOTER = auto()
62
+ TRUNC = auto()
63
+ TRUNC_PASSENGER = auto()
64
+ INFRAME = auto()
65
+ INFRAME_PASSENGER = auto()
66
+ STRUCTURAL_VARIANT = auto()
67
+ STRUCTURAL_VARIANT_PASSENGER = auto()
68
+ # STRUCTURE_VARIANT
69
+
70
+ OTHER = 10000
71
+
72
+
73
+ # Overwrite the default legend
74
+ # So that the legend entry will add a background
75
+ class _AltPiece:
76
+ background_color = None
77
+
78
+ def legend(self, x, y, w, h):
79
+ arts = []
80
+ if self.background_color is not None:
81
+ arts.append(Rectangle((x, y), w, h, facecolor=self.background_color))
82
+ arts.append(self.draw(x, y, w, h, None))
83
+ return PatchCollection(arts, match_original=True)
84
+
85
+
86
+ class Rect(_AltPiece, mlayers.Rect):
87
+ pass
88
+
89
+
90
+ class FrameRect(_AltPiece, mlayers.FrameRect):
91
+ pass
92
+
93
+
94
+ class FracRect(_AltPiece, mlayers.FracRect):
95
+ pass
96
+
97
+
98
+ @dataclass(repr=False)
99
+ class MatchRule:
100
+ startswith: str = None
101
+ endswith: str = None
102
+ contains: List[str] = field(default_factory=list)
103
+ flexible: bool = False
104
+
105
+ def is_match(self, text: str):
106
+ text = text.lower()
107
+
108
+ match_start = not self.flexible
109
+ if self.startswith is not None:
110
+ match_start = text.startswith(self.startswith)
111
+
112
+ match_end = not self.flexible
113
+ if self.endswith is not None:
114
+ match_end = text.endswith(self.endswith)
115
+
116
+ match_contains = True
117
+ if len(self.contains) > 0:
118
+ match_contains = np.sum([i in text for i in self.contains])
119
+
120
+ if self.flexible:
121
+ return match_start | match_end | match_contains
122
+ else:
123
+ return match_start & match_end & match_contains
124
+
125
+
126
+ MATCH_POOL = {
127
+ Alteration.AMP: MatchRule(startswith="amp"),
128
+ Alteration.GAIN: MatchRule(startswith="gain"),
129
+ Alteration.HOMDEL: MatchRule(
130
+ startswith="homdel", contains=["deep", "deletion"], flexible=True
131
+ ),
132
+ Alteration.HETLOSS: MatchRule(
133
+ startswith="hetloss", contains=["shallow", "deletion"], flexible=True
134
+ ),
135
+ Alteration.MRNA_HIGH: MatchRule(contains=["mrna", "high"]),
136
+ Alteration.MRNA_LOW: MatchRule(contains=["mrna", "low"]),
137
+ Alteration.PROTEIN_HIGH: MatchRule(contains=["protein", "high"]),
138
+ Alteration.PROTEIN_LOW: MatchRule(contains=["protein", "low"]),
139
+ Alteration.FUSION: MatchRule(startswith="fusion"),
140
+ Alteration.GERMLINE: MatchRule(startswith="germline"),
141
+ Alteration.MISSENSE_PASSENGER: MatchRule(
142
+ startswith="missense", contains=["passenger"]
143
+ ),
144
+ Alteration.MISSENSE: MatchRule(
145
+ startswith="missense", contains=["driver"], flexible=True
146
+ ),
147
+ Alteration.PROMOTER: MatchRule(startswith="promoter"),
148
+ Alteration.TRUNC_PASSENGER: MatchRule(startswith="trunc", contains=["passenger"]),
149
+ Alteration.TRUNC: MatchRule(startswith="trunc"),
150
+ Alteration.INFRAME_PASSENGER: MatchRule(
151
+ startswith="inframe", contains=["passenger"]
152
+ ),
153
+ Alteration.INFRAME: MatchRule(startswith="inframe"),
154
+ Alteration.STRUCTURAL_VARIANT_PASSENGER: MatchRule(
155
+ startswith="sv", contains=["structural", "variant", "passenger"], flexible=True
156
+ ),
157
+ Alteration.STRUCTURAL_VARIANT: MatchRule(
158
+ startswith="sv", contains=["structural", "variant"], flexible=True
159
+ ),
160
+ Alteration.SPLICE_PASSENGER: MatchRule(startswith="splice", contains=["passenger"]),
161
+ Alteration.SPLICE: MatchRule(startswith="splice"),
162
+ }
163
+
164
+ SHAPE_BANK = {
165
+ Alteration.BACKGROUND: Rect(
166
+ color=DEFAULT_GREY, label="No alterations", zorder=-10000
167
+ ),
168
+ # CNA
169
+ Alteration.AMP: Rect(color=CNA_COLOR_AMP, label="Amplification"),
170
+ # ShapeId.ampRectangle
171
+ Alteration.GAIN: Rect(color=CNA_COLOR_GAIN, label="Gain"),
172
+ # ShapeId.gainRectangle
173
+ Alteration.HOMDEL: Rect(color=CNA_COLOR_HOMDEL, label="Deep Deletion"),
174
+ Alteration.HETLOSS: Rect(color=CNA_COLOR_HETLOSS, label="Shallow Deletion"),
175
+ # mRNA Regulation
176
+ Alteration.MRNA_HIGH: FrameRect(
177
+ color=MRNA_COLOR_HIGH, width=1.5, label="mRNA High", zorder=1000
178
+ ),
179
+ Alteration.MRNA_LOW: FrameRect(
180
+ color=MRNA_COLOR_LOW, width=1.5, label="mRNA Low", zorder=1000
181
+ ),
182
+ # Protein Expression Regulation
183
+ Alteration.PROTEIN_HIGH: FracRect(
184
+ color=PROT_COLOR_HIGH, frac=(1.0, 0.2), label="Protein High", zorder=100
185
+ ),
186
+ Alteration.PROTEIN_LOW: FracRect(
187
+ color=PROT_COLOR_LOW, frac=(1.0, 0.2), label="Protein Low", zorder=100
188
+ ),
189
+ # Structural variant
190
+ Alteration.STRUCTURAL_VARIANT: FracRect(
191
+ color=STRUCTURAL_VARIANT_COLOR,
192
+ frac=(1.0, 0.6),
193
+ label="Structural variant",
194
+ zorder=200,
195
+ ),
196
+ Alteration.STRUCTURAL_VARIANT_PASSENGER: FracRect(
197
+ color=STRUCTURAL_VARIANT_PASSENGER_COLOR,
198
+ frac=(1.0, 0.6),
199
+ label="Structural variant (putative passenger)",
200
+ zorder=200,
201
+ ),
202
+ Alteration.FUSION: FracRect(
203
+ color=MUT_COLOR_FUSION, frac=(1.0, 0.6), label="Fusion", zorder=200
204
+ ),
205
+ # Splice
206
+ Alteration.SPLICE: FracRect(
207
+ color=MUT_COLOR_SPLICE, frac=(1.0, 0.3), label="Splice Mutation", zorder=400
208
+ ),
209
+ Alteration.SPLICE_PASSENGER: FracRect(
210
+ color=MUT_COLOR_SPLICE_PASSENGER,
211
+ frac=(1.0, 0.3),
212
+ label="Splice Mutation (putative passenger)",
213
+ zorder=400,
214
+ ),
215
+ Alteration.MISSENSE: FracRect(
216
+ color=MUT_COLOR_MISSENSE,
217
+ frac=(1.0, 0.3),
218
+ label="Mutation (putative driver)",
219
+ zorder=400,
220
+ ),
221
+ Alteration.MISSENSE_PASSENGER: FracRect(
222
+ color=MUT_COLOR_MISSENSE_PASSENGER,
223
+ frac=(1.0, 0.3),
224
+ label="Missense Mutation (putative passenger)",
225
+ zorder=400,
226
+ ),
227
+ Alteration.OTHER: FracRect(
228
+ color=MUT_COLOR_OTHER, frac=(1.0, 0.3), label="Other Mutation", zorder=400
229
+ ),
230
+ Alteration.PROMOTER: FracRect(
231
+ color=MUT_COLOR_PROMOTER, frac=(1.0, 0.3), label="Promoter Mutation", zorder=400
232
+ ),
233
+ Alteration.TRUNC: FracRect(
234
+ color=MUT_COLOR_TRUNC, frac=(1.0, 0.3), label="Truncating Mutation", zorder=400
235
+ ),
236
+ Alteration.TRUNC_PASSENGER: FracRect(
237
+ color=MUT_COLOR_TRUNC_PASSENGER,
238
+ frac=(1.0, 0.3),
239
+ label="Truncating Mutation (putative passenger)",
240
+ zorder=400,
241
+ ),
242
+ Alteration.INFRAME: FracRect(
243
+ color=MUT_COLOR_INFRAME,
244
+ frac=(1.0, 0.3),
245
+ label="Inframe Mutation (putative driver)",
246
+ zorder=400,
247
+ ),
248
+ Alteration.INFRAME_PASSENGER: FracRect(
249
+ color=MUT_COLOR_INFRAME_PASSENGER,
250
+ frac=(1.0, 0.3),
251
+ label="Inframe Mutation (putative passenger)",
252
+ zorder=400,
253
+ ),
254
+ # Germline
255
+ Alteration.GERMLINE: FracRect(
256
+ color=MUT_COLOR_GERMLINE, frac=(1.0, 0.1), label="Germline Mutation", zorder=600
257
+ ),
258
+ }
@@ -1,99 +0,0 @@
1
- # The implementation of Image in matplotlib may suffer from compatibility
2
- # issues across different rendering backend at different DPI. Currently
3
- # not a public API.
4
- from functools import partial
5
-
6
- import numpy as np
7
- from matplotlib.image import imread, BboxImage
8
- from matplotlib.transforms import Bbox
9
- from pathlib import Path
10
- from platformdirs import user_cache_dir
11
- from urllib.request import urlretrieve
12
-
13
- from .base import RenderPlan
14
-
15
- TWEMOJI_CDN = "https://cdn.jsdelivr.net/gh/twitter/twemoji/assets/72x72/"
16
-
17
-
18
- def _cache_remote(url, cache=True):
19
- data_dir = Path(user_cache_dir(appname="Marsilea"))
20
- data_dir.mkdir(exist_ok=True, parents=True)
21
-
22
- fname = url.split("/")[-1]
23
- dest = data_dir / fname
24
- if not (cache and dest.exists()):
25
- urlretrieve(url, dest)
26
-
27
- return dest
28
-
29
-
30
- class Emoji(RenderPlan):
31
- def __init__(self, images, lang="en", scale=1, mode="filled"):
32
- try:
33
- import emoji
34
- except ImportError:
35
- raise ImportError("Required emoji, try `pip install emoji`.")
36
-
37
- codes = []
38
- for i in images:
39
- i = emoji.emojize(i, language=lang)
40
- if not emoji.is_emoji(i):
41
- raise ValueError(f"{i} is not a valid emoji")
42
- codes.append(f"{ord(i):X}".lower())
43
-
44
- self.set_data(np.asarray(codes))
45
- self.emoji_caches = {}
46
- for c in codes:
47
- cache_image = _cache_remote(f"{TWEMOJI_CDN}{c}.png")
48
- self.emoji_caches[c] = imread(cache_image)
49
-
50
- self.scale = scale
51
- self.mode = mode
52
-
53
- def _get_images_bbox(self, figure, imgs):
54
- for img in imgs:
55
- width, height = img.shape[:2]
56
-
57
- return Bbox.from_bounds(0, 0, width, height)
58
-
59
- def render_ax(self, spec):
60
- ax = spec.ax
61
- data = spec.data
62
-
63
- # TODO: Does not work for orient = "v"
64
- locs = np.linspace(0, 1, len(data) + 1)
65
- for loc, d in zip(locs, data):
66
- img = self.emoji_caches[d]
67
- width, height = img.shape[:2]
68
-
69
- xmin, ymin = ax.transAxes.transform((0, 0))
70
- xmax, ymax = ax.transAxes.transform((1, 1))
71
-
72
- ax_width = xmax - xmin
73
- ax_height = ymax - ymin
74
-
75
- fit_width = ax_width / len(data)
76
- fit_height = height / width * fit_width
77
-
78
- fit_scale_width = fit_width * self.scale
79
- fit_scale_height = fit_height * self.scale
80
-
81
- offset = (fit_width - fit_scale_width) / 2 / ax_width
82
- loc += offset
83
-
84
- loc_y = 0.5 - fit_scale_height / 2 / ax_height
85
-
86
- def get_emoji_bbox(renderer, loc, loc_y, width, height):
87
- x0, y0 = ax.transData.transform((loc, loc_y))
88
- return Bbox.from_bounds(x0, y0, width, height)
89
-
90
- partial_get_emoji_bbox = partial(
91
- get_emoji_bbox,
92
- loc=loc,
93
- loc_y=loc_y,
94
- width=fit_scale_width,
95
- height=fit_scale_height,
96
- )
97
-
98
- i1 = BboxImage(partial_get_emoji_bbox, data=img)
99
- ax.add_artist(i1)
@@ -1,76 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: marsilea
3
- Version: 0.4.2
4
- Summary: Declarative creation of composable visualization
5
- Author: Zhihang Zheng
6
- Author-email: Mr-Milk <yzheng@cemm.at>
7
- Requires-Python: >=3.8
8
- Description-Content-Type: text/markdown
9
- Classifier: License :: OSI Approved :: MIT License
10
- Classifier: Programming Language :: Python :: 3
11
- Classifier: Framework :: Matplotlib
12
- Requires-Dist: numpy
13
- Requires-Dist: pandas
14
- Requires-Dist: matplotlib>=3.6
15
- Requires-Dist: seaborn
16
- Requires-Dist: scipy
17
- Requires-Dist: legendkit
18
- Requires-Dist: platformdirs
19
- Requires-Dist: ruff ; extra == "dev"
20
- Requires-Dist: icecream ; extra == "dev"
21
- Requires-Dist: python-hmr ; extra == "dev"
22
- Requires-Dist: pytest ; extra == "dev"
23
- Requires-Dist: scikit-learn ; extra == "dev"
24
- Requires-Dist: sphinx ; extra == "dev"
25
- Requires-Dist: numpydoc ; extra == "dev"
26
- Requires-Dist: sphinx_design ; extra == "dev"
27
- Requires-Dist: pydata-sphinx-theme ; extra == "dev"
28
- Requires-Dist: sphinx-copybutton ; extra == "dev"
29
- Requires-Dist: sphinx_gallery ; extra == "dev"
30
- Requires-Dist: mpl_fontkit ; extra == "dev"
31
- Project-URL: Home, https://github.com/Marsilea-viz/marsilea
32
- Provides-Extra: dev
33
-
34
- <p align="center">
35
- <picture align="center">
36
- <source media="(prefers-color-scheme: dark)" srcset="https://github.com/Marsilea-viz/marsilea/raw/main/img/banner-dark.jpg">
37
- <source media="(prefers-color-scheme: light)" srcset="https://github.com/Marsilea-viz/marsilea/raw/main/img/banner-blue.jpg">
38
- <img alt="Shows a bar chart with benchmark results." src="https://github.com/Marsilea-viz/marsilea/raw/main/img/banner-dark.jpg" width="400">
39
- </picture>
40
- </p>
41
-
42
- [![Documentation Status](https://img.shields.io/readthedocs/marsilea?color=57B77E&logo=readthedocs&logoColor=white&style=flat-square)](https://marsilea.readthedocs.io/en/stable)
43
- ![pypi version](https://img.shields.io/pypi/v/marsilea?color=0098FF&logo=python&logoColor=white&style=flat-square)
44
-
45
- ❗We are in beta, API may change and bugs expected
46
-
47
- ### Declarative creation of composable visualization!
48
-
49
- [Read Documentation](https://marsilea.readthedocs.io/)
50
-
51
-
52
- ### Installation
53
-
54
- ```shell
55
- pip install marsilea
56
- ```
57
-
58
- [//]: # (### Examples)
59
-
60
- [//]: # ()
61
- [//]: # (| | |)
62
-
63
- [//]: # (|-----------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------|)
64
-
65
- [//]: # (| Heatmap | Oncoprint |)
66
-
67
- [//]: # (| <img src="https://marsilea.readthedocs.io/en/latest/_images/sphx_glr_plot_pbmc3k_001_2_00x.png" width=400> | <img src="https://marsilea.readthedocs.io/en/latest/_images/sphx_glr_plot_oncoprint_005_2_00x.png" width=400> |)
68
-
69
- [//]: # (| Upsetplot | Composition Stacked Bar |)
70
-
71
- [//]: # (| <img src="https://marsilea.readthedocs.io/en/latest/_images/sphx_glr_plot_upset_001_2_00x.png" width=400> | <img src="https://marsilea.readthedocs.io/en/latest/_images/sphx_glr_plot_oil_well_001_2_00x.png" width=400> |)
72
-
73
- [//]: # (| Arc Diagram | Protein sequence alignment |)
74
-
75
- [//]: # (| <img src="https://marsilea.readthedocs.io/en/latest/_images/sphx_glr_plot_arc_diagram_001_2_00x.png" width=400> | <img src="https://marsilea.readthedocs.io/en/latest/_images/sphx_glr_plot_seqalign_001_2_00x.png" width=400> |)
76
-
@@ -1,27 +0,0 @@
1
- marsilea/__init__.py,sha256=d0Ly-YfvxU50ILe2FqnmpvcnSg6XwCHVIh1LRIqQfNE,541
2
- marsilea/_api.py,sha256=tymWZHfjhx8-0NNd9762znfdIu36NrARRweEIr5L1mA,283
3
- marsilea/_deform.py,sha256=SKXLvhyUrwTRAw7Fl--OpupDLk6T3S5DRfwCAdewHQs,14138
4
- marsilea/base.py,sha256=HSY25Ax39Vj80FxSZkg4es0YklNtFJ_DgfQzbFIJseI,46637
5
- marsilea/dataset.py,sha256=a0mXjPu9_tRGHofnnQaTryFpxftkfqldq_ZLXMSBf7A,4410
6
- marsilea/dendrogram.py,sha256=WUnV2JMSY9mPt1sfkFAEikkl2ta7xHFD13teas_iZgE,14767
7
- marsilea/exceptions.py,sha256=kIXDRF8Fy-BkNqeMbLqde06PaWESuKiGCMGyDpVpWIE,1006
8
- marsilea/heatmap.py,sha256=lKGt0lTtziNFDsb_SBfFt3zoYzVYRzezc9aae5RxHyk,4168
9
- marsilea/layers.py,sha256=puXLlGGpEqAzaTqadpgpsYmIDPH33WyyHIuysRSqFZQ,12163
10
- marsilea/layout.py,sha256=X8MGPlAbbr7dcZiqW4pI7sEb8U3jVaiS7t1DKOqMYLI,27758
11
- marsilea/upset.py,sha256=U1Rsmo1WpCAV9z3LBlE2L4T0nAW9ols8Z36fXzmXycw,30388
12
- marsilea/utils.py,sha256=LJ7U0aVw_Ru45DXo4x5zi1FEjjIKt4j0mpdDY34wiNA,2903
13
- marsilea/plotter/__init__.py,sha256=n1E53C5oqnsHZcXAtN6HgZsZdcAvANONNx-fupTxzN0,738
14
- marsilea/plotter/_images.py,sha256=RWCI4FhcxJZimLrhdy9CHw3ri1kweGRICUyByE4wzmg,3065
15
- marsilea/plotter/_seaborn.py,sha256=aK0EnboshfNCNvNjsIc7dxDE_4KBKi4HMUt7CKWt_6U,8188
16
- marsilea/plotter/_utils.py,sha256=Efhdk-TrrAanhbXRiEVWThMYvZ4vVHZMVYMs5X3JvIM,710
17
- marsilea/plotter/arc.py,sha256=PFXlJ0TBIJ1mEB-lIl-Zs2UdEXkLSwDlRJbsSa5Ss5U,8165
18
- marsilea/plotter/area.py,sha256=zjjAhvgKHYe9rqzcseqZqhwfpgvzm0w2FRJ_vr9Fxm4,2650
19
- marsilea/plotter/bar.py,sha256=TeX6li--kE9NtqCRflDTX0jkG1-uIq0Dn8ILKSv-AuA,12080
20
- marsilea/plotter/base.py,sha256=NgaoFnbMS6Mj4BghVcGaSYYN8A9e3DD_rRomDIm4C5c,20456
21
- marsilea/plotter/bio.py,sha256=_pZkGoAei7eirFCpu7AcZJhebBneNjUKcZlI36bpqUE,5044
22
- marsilea/plotter/mesh.py,sha256=YY6aq62QS1HyTeIWF79rpIJUUQTOxWXx3LZ7oZXYlzU,23797
23
- marsilea/plotter/text.py,sha256=oYJ5py3_nGHKi60DSVzFgPg4drnTSTw__IcYs0cut4M,36222
24
- marsilea-0.4.2.dist-info/LICENSE,sha256=2TLD8FnLJqXzg8YBRs7W3VZBwfWfp4ArDfBl-rn96Qc,1074
25
- marsilea-0.4.2.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
26
- marsilea-0.4.2.dist-info/METADATA,sha256=3H95A_-TertDPICUSKoJECa8Hf29atnkEYs28p00lLE,4074
27
- marsilea-0.4.2.dist-info/RECORD,,