marsilea 0.5.4__py3-none-any.whl → 0.5.5__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,8 @@
1
1
  """Declarative creation of composable visualization"""
2
2
 
3
- __version__ = "0.5.4"
3
+ from ._version import version
4
+
5
+ __version__ = version
4
6
 
5
7
  import marsilea.plotter as plotter
6
8
  from ._deform import Deformation
marsilea/_version.py ADDED
@@ -0,0 +1 @@
1
+ version = "0.5.5"
marsilea/layout.py CHANGED
@@ -461,8 +461,8 @@ class CrossLayout(_MarginMixin):
461
461
  y = self.get_side_size("bottom")
462
462
  if self.is_composite:
463
463
  return x, y
464
- x += self.margin.bottom
465
- y += self.margin.left
464
+ x += self.margin.left
465
+ y += self.margin.bottom
466
466
  return x, y
467
467
  else:
468
468
  return self.anchor
marsilea/plotter/mesh.py CHANGED
@@ -1,14 +1,21 @@
1
1
  __all__ = ["ColorMesh", "Colors", "SizedMesh", "MarkerMesh", "TextMesh", "PatchMesh"]
2
2
 
3
- import numpy as np
4
- import pandas as pd
5
3
  import warnings
6
4
  from itertools import cycle
7
- from legendkit import ColorArt, CatLegend, SizeLegend
8
- from matplotlib.cm import ScalarMappable
9
- from matplotlib.colors import ListedColormap, TwoSlopeNorm, Normalize, is_color_like
10
5
  from typing import Mapping
11
6
 
7
+ import numpy as np
8
+ import pandas as pd
9
+ from legendkit import ColorArt, CatLegend, SizeLegend, ListLegend
10
+ from matplotlib.cm import ScalarMappable
11
+ from matplotlib.colors import (
12
+ ListedColormap,
13
+ TwoSlopeNorm,
14
+ Normalize,
15
+ is_color_like,
16
+ to_hex,
17
+ )
18
+
12
19
  from ._utils import _format_label
13
20
  from .base import RenderPlan
14
21
  from ..layout import close_ticks
@@ -426,8 +433,9 @@ class SizedMesh(MeshBase):
426
433
  The range of the size of elements
427
434
  size_norm : :class:`matplotlib.colors.Normalize`
428
435
  A Normalize instance to map size
429
- edgecolor : color
430
- The border color of each elements
436
+ edgecolor : color or array of colors
437
+ The border color of each elements, if you want to control every element,
438
+ please supply a 2d array with the same shape as input.
431
439
  linewidth : float
432
440
  The width of the border of each elements
433
441
  frameon : bool
@@ -454,6 +462,10 @@ class SizedMesh(MeshBase):
454
462
  Control the size legend, See :class:`legendkit.size_legend`
455
463
  color_legend_kws : dict
456
464
  Control the color legend, See :class:`legendkit.colorart`
465
+ edgecolor_legend_text : list of str
466
+ The texts for the edgecolor legend
467
+ edgecolor_legend_kws : dict
468
+ Control the edgecolor legend, See :class:`legendkit.legend`
457
469
  kwargs : dict
458
470
  Pass to :meth:`matplotlib.axes.Axes.scatter`
459
471
 
@@ -511,6 +523,8 @@ class SizedMesh(MeshBase):
511
523
  legend=True,
512
524
  size_legend_kws=None,
513
525
  color_legend_kws=None,
526
+ edgecolor_legend_text=None,
527
+ edgecolor_legend_kws=None,
514
528
  **kwargs,
515
529
  ):
516
530
  # normalize size
@@ -528,6 +542,11 @@ class SizedMesh(MeshBase):
528
542
  self.legend = legend
529
543
  self.color_legend_kws = {} if color_legend_kws is None else color_legend_kws
530
544
  self.size_legend_kws = {} if size_legend_kws is None else size_legend_kws
545
+ self.edgecolor_legend_text = edgecolor_legend_text
546
+ self.edgecolor_legend_kws = (
547
+ {} if edgecolor_legend_kws is None else edgecolor_legend_kws
548
+ )
549
+
531
550
  self._has_colormesh = False
532
551
  # process color
533
552
  # By default, the circles colors are uniform
@@ -557,7 +576,23 @@ class SizedMesh(MeshBase):
557
576
  self._has_colormesh = True
558
577
  self.alpha = alpha
559
578
  self.frameon = frameon
560
- self.edgecolor = edgecolor
579
+
580
+ self.edgecolor = None
581
+ if edgecolor is not None:
582
+ if is_color_like(edgecolor):
583
+ self.edgecolor = np.repeat(edgecolor, size.size).reshape(size.shape)
584
+ self._single_edgecolor = True
585
+ else:
586
+ edgecolor = np.asarray(edgecolor)
587
+ if edgecolor.shape != self.size_matrix.shape:
588
+ raise ValueError(
589
+ "If use multiple edgecolors, "
590
+ "the shape must be the same as input size"
591
+ )
592
+ # Covert to hex
593
+ edgecolor = [[to_hex(c) for c in row] for row in edgecolor]
594
+ self.edgecolor = np.asarray(edgecolor)
595
+ self._single_edgecolor = False
561
596
  self.linewidth = linewidth
562
597
  self.set_label(label, label_loc, label_props)
563
598
  self.grid = grid
@@ -566,7 +601,11 @@ class SizedMesh(MeshBase):
566
601
  self.kwargs = kwargs
567
602
 
568
603
  self._collections = None
569
- self.set_data(self.size_matrix, self.color2d)
604
+ render_data = [self.size_matrix, self.color2d]
605
+ if self.edgecolor is not None:
606
+ render_data.append(self.edgecolor)
607
+
608
+ self.set_data(*render_data)
570
609
 
571
610
  def update_main_canvas_size(self):
572
611
  return get_canvas_size_by_data(self.orig_size.shape)
@@ -574,11 +613,18 @@ class SizedMesh(MeshBase):
574
613
  def get_legends(self):
575
614
  if not self.legend:
576
615
  return None
616
+
617
+ legends = []
618
+
577
619
  if self.color is not None:
578
620
  size_color = self.color
579
621
  else:
580
622
  size_color = "black"
581
- handler_kw = dict(edgecolor=self.edgecolor, linewidth=self.linewidth)
623
+ edgecolor = None
624
+ if self.edgecolor is not None:
625
+ if self._single_edgecolor:
626
+ edgecolor = self.edgecolor.flatten()[0]
627
+ handler_kw = dict(edgecolor=edgecolor, linewidth=self.linewidth)
582
628
  options = dict(
583
629
  colors=size_color,
584
630
  handle=self.marker,
@@ -588,6 +634,26 @@ class SizedMesh(MeshBase):
588
634
  )
589
635
  options.update(self.size_legend_kws)
590
636
  size_legend = SizeLegend(self.size_matrix, array=self.orig_size, **options)
637
+ legends.append(size_legend)
638
+
639
+ # Construct edgecolor legend
640
+ if self.edgecolor is not None:
641
+ if self.edgecolor_legend_text is not None:
642
+ unique_ecs = np.unique(self.edgecolor)
643
+ if len(self.edgecolor_legend_text) == len(unique_ecs):
644
+ legend_items = [
645
+ ("circle", text, dict(ec=ec, fc="none"))
646
+ for text, ec in zip(self.edgecolor_legend_text, unique_ecs)
647
+ ]
648
+ ec_legend = ListLegend(
649
+ legend_items=legend_items, **self.color_legend_kws
650
+ )
651
+ legends.append(ec_legend)
652
+ else:
653
+ raise ValueError(
654
+ "If edgecolor legend text is provided, the number of unique edgecolors "
655
+ "must match the number of texts"
656
+ )
591
657
 
592
658
  if self._has_colormesh & (self.color != "none"):
593
659
  if self.palette is not None:
@@ -606,16 +672,20 @@ class SizedMesh(MeshBase):
606
672
  else:
607
673
  ScalarMappable(norm=self.norm, cmap=self.cmap)
608
674
  color_legend = ColorArt(self._collections, **self.color_legend_kws)
609
- return [size_legend, color_legend]
675
+ legends.append(color_legend)
676
+
677
+ if len(legends) == 1:
678
+ return legends[0]
610
679
  else:
611
- return size_legend
680
+ return legends
612
681
 
613
682
  def render_ax(self, spec):
614
683
  ax = spec.ax
615
- size, color = spec.data
684
+ size, color, edgecolors = spec.data
616
685
  if self.is_flank:
617
686
  size = size.T
618
687
  color = color.T
688
+ edgecolors = edgecolors.T
619
689
  Y, X = size.shape
620
690
  xticks = np.arange(X) + 0.5
621
691
  yticks = np.arange(Y) + 0.5
@@ -633,7 +703,7 @@ class SizedMesh(MeshBase):
633
703
 
634
704
  options = dict(
635
705
  s=size,
636
- edgecolor=self.edgecolor,
706
+ edgecolors=edgecolors.flatten(),
637
707
  linewidths=self.linewidth,
638
708
  marker=self.marker,
639
709
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: marsilea
3
- Version: 0.5.4
3
+ Version: 0.5.5
4
4
  Summary: Declarative creation of composable visualizations
5
5
  Project-URL: Home, https://github.com/Marsilea-viz/marsilea
6
6
  Project-URL: Documentation, https://marsilea.readthedocs.io
@@ -1,13 +1,14 @@
1
- marsilea/__init__.py,sha256=Ml3xgdyN-IinhsaejVadUjIURHJzg8fhi2Y_uERAuI8,595
1
+ marsilea/__init__.py,sha256=mMtII0QzSVGrr1vJXTglr6wBd2AHElrDnDp1iGQbOxo,626
2
2
  marsilea/_api.py,sha256=tymWZHfjhx8-0NNd9762znfdIu36NrARRweEIr5L1mA,283
3
3
  marsilea/_deform.py,sha256=QRz4OGXMsQzbiIkC3ASzZayMPhHhoFsEK38oBzSeQG8,14440
4
+ marsilea/_version.py,sha256=v9c8T1qB0Dxuq0vdkPvh2bpcAlRxlK4BxHPcACDymFw,18
4
5
  marsilea/base.py,sha256=CmzuwFu0JzgkNpPdI1SqAnkUxINShjT73hrJpksKjhE,46872
5
6
  marsilea/dataset.py,sha256=Qh8k1DhTiwP_Me709CkpNwRaYLDzlenRTIk0U6D58_g,4631
6
7
  marsilea/dendrogram.py,sha256=Ung43zseybZKzTEvH5P_ge3WGfsr7i7qsX7YEVDlC74,15590
7
8
  marsilea/exceptions.py,sha256=wN5ElUZxuaJKSnnwWdkNx6P-Oc16dzSuaRPbRKWIBEM,1046
8
9
  marsilea/heatmap.py,sha256=8Wo1NxFTBp1a7NOISmer0yQYWWgf51Xsvjav1h1vTYk,4316
9
10
  marsilea/layers.py,sha256=w_yvghwYAO112mVvp1krjUjEIQYq_1nz2uCsTUJdB-Y,12909
10
- marsilea/layout.py,sha256=yNuGvIDfWjbCksQZO-4aUWSA78LJwBBKF5Z5cthC6fM,39741
11
+ marsilea/layout.py,sha256=b6aynXl2senRYjaYnNikjIzK84RkXaBvAyt86VRWw-g,39741
11
12
  marsilea/upset.py,sha256=9m4Los-yVvVZOEHg6X-yfOdLA9eUBQdK1A_BkOaLIMA,30602
12
13
  marsilea/utils.py,sha256=y_KYs4ToiuKEsiBdmcIVtmxMXFpD4wKiJ0k7iBa11z8,2854
13
14
  marsilea/plotter/__init__.py,sha256=la30o20zYiHWN2RzElhS8MMCbGKbDDEe0WHXakq9OBQ,806
@@ -19,13 +20,13 @@ marsilea/plotter/bar.py,sha256=RWDsNbyCUKbybpsBOgbl43lVZc_ynZmTOevE-CtJ5KE,12354
19
20
  marsilea/plotter/base.py,sha256=b_NmrW_oNPc-HwQsjx1NsC2lknYK6qSaDp_7SxeoUEM,18938
20
21
  marsilea/plotter/bio.py,sha256=34tucmxs4LM3TFZoGsrjnXTolyrzYaHVEiRe4dzDH68,5040
21
22
  marsilea/plotter/images.py,sha256=gb0xIQhUch3rNAt3FfvuUoamSGEynoBBBky2eE754ec,9560
22
- marsilea/plotter/mesh.py,sha256=D6snenMjQ-rM9g3O4PGelSiaBNKmY2OPZU5onILlmO0,24530
23
+ marsilea/plotter/mesh.py,sha256=t9odi21DtrcSmoBQWtYyqmX5_gYDb4wNZQH_VrBjrtY,27190
23
24
  marsilea/plotter/range.py,sha256=sXWKrvpq7nU7giiHPjayM7h9Q7gblhjXxHm8ioB3cm4,3770
24
25
  marsilea/plotter/text.py,sha256=6S4mnAxLJLMkduKiyor03lPd86oTOJ5TojVREA9oU6s,37466
25
26
  oncoprinter/__init__.py,sha256=efshcAD1h9s-NVJj4HLU9-hXc_LtTeIrNYqLHl-sm_g,106
26
27
  oncoprinter/core.py,sha256=5KPnKW5ivlxPp14uJd0OtfTv-pXV2UEym8EbII2VCcw,11846
27
28
  oncoprinter/preset.py,sha256=mBk2tFCqoTj_1ZZKRYuv4j2I3NTBa6Swc9wjzbmxRVw,8238
28
- marsilea-0.5.4.dist-info/METADATA,sha256=9SS9_JT6N9FRdBenz-95mnzFY5LVal4lhMocoyvcUsA,7265
29
- marsilea-0.5.4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
30
- marsilea-0.5.4.dist-info/licenses/LICENSE,sha256=RhHHDuP61qzKmfHtOQUVLZfCgMkKx9PXzxzkLtmAjHo,1078
31
- marsilea-0.5.4.dist-info/RECORD,,
29
+ marsilea-0.5.5.dist-info/METADATA,sha256=k47nj_h3fBERMN2AXbhVg9yZkrNujRnDVIASpTk1qKE,7265
30
+ marsilea-0.5.5.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
31
+ marsilea-0.5.5.dist-info/licenses/LICENSE,sha256=RhHHDuP61qzKmfHtOQUVLZfCgMkKx9PXzxzkLtmAjHo,1078
32
+ marsilea-0.5.5.dist-info/RECORD,,