marsilea 0.5.3__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.3"
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
 
@@ -483,8 +495,6 @@ class SizedMesh(MeshBase):
483
495
  >>> h.add_right(mesh, size=0.2, pad=0.05)
484
496
  >>> h.render()
485
497
 
486
-
487
-
488
498
  """
489
499
 
490
500
  def __init__(
@@ -513,6 +523,8 @@ class SizedMesh(MeshBase):
513
523
  legend=True,
514
524
  size_legend_kws=None,
515
525
  color_legend_kws=None,
526
+ edgecolor_legend_text=None,
527
+ edgecolor_legend_kws=None,
516
528
  **kwargs,
517
529
  ):
518
530
  # normalize size
@@ -530,6 +542,11 @@ class SizedMesh(MeshBase):
530
542
  self.legend = legend
531
543
  self.color_legend_kws = {} if color_legend_kws is None else color_legend_kws
532
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
+
533
550
  self._has_colormesh = False
534
551
  # process color
535
552
  # By default, the circles colors are uniform
@@ -550,13 +567,32 @@ class SizedMesh(MeshBase):
550
567
  render_colors.append(c)
551
568
  self.cmap = ListedColormap(render_colors)
552
569
  self.color2d = encode_numeric(color, encoder)
570
+ if self.norm is None:
571
+ vs = encoder.values()
572
+ self.norm = Normalize(vmin=min(vs), vmax=max(vs))
553
573
  else:
554
574
  self._process_cmap(color, vmin, vmax, cmap, norm, center)
555
575
  self.color2d = color
556
576
  self._has_colormesh = True
557
577
  self.alpha = alpha
558
578
  self.frameon = frameon
559
- 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
560
596
  self.linewidth = linewidth
561
597
  self.set_label(label, label_loc, label_props)
562
598
  self.grid = grid
@@ -565,7 +601,11 @@ class SizedMesh(MeshBase):
565
601
  self.kwargs = kwargs
566
602
 
567
603
  self._collections = None
568
- 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)
569
609
 
570
610
  def update_main_canvas_size(self):
571
611
  return get_canvas_size_by_data(self.orig_size.shape)
@@ -573,11 +613,18 @@ class SizedMesh(MeshBase):
573
613
  def get_legends(self):
574
614
  if not self.legend:
575
615
  return None
616
+
617
+ legends = []
618
+
576
619
  if self.color is not None:
577
620
  size_color = self.color
578
621
  else:
579
622
  size_color = "black"
580
- 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)
581
628
  options = dict(
582
629
  colors=size_color,
583
630
  handle=self.marker,
@@ -587,6 +634,26 @@ class SizedMesh(MeshBase):
587
634
  )
588
635
  options.update(self.size_legend_kws)
589
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
+ )
590
657
 
591
658
  if self._has_colormesh & (self.color != "none"):
592
659
  if self.palette is not None:
@@ -605,16 +672,20 @@ class SizedMesh(MeshBase):
605
672
  else:
606
673
  ScalarMappable(norm=self.norm, cmap=self.cmap)
607
674
  color_legend = ColorArt(self._collections, **self.color_legend_kws)
608
- return [size_legend, color_legend]
675
+ legends.append(color_legend)
676
+
677
+ if len(legends) == 1:
678
+ return legends[0]
609
679
  else:
610
- return size_legend
680
+ return legends
611
681
 
612
682
  def render_ax(self, spec):
613
683
  ax = spec.ax
614
- size, color = spec.data
684
+ size, color, edgecolors = spec.data
615
685
  if self.is_flank:
616
686
  size = size.T
617
687
  color = color.T
688
+ edgecolors = edgecolors.T
618
689
  Y, X = size.shape
619
690
  xticks = np.arange(X) + 0.5
620
691
  yticks = np.arange(Y) + 0.5
@@ -632,13 +703,12 @@ class SizedMesh(MeshBase):
632
703
 
633
704
  options = dict(
634
705
  s=size,
635
- edgecolor=self.edgecolor,
706
+ edgecolors=edgecolors.flatten(),
636
707
  linewidths=self.linewidth,
637
708
  marker=self.marker,
638
709
  )
639
-
640
710
  if self.color is not None:
641
- options["c"] = self.color
711
+ options["c"] = color
642
712
  else:
643
713
  options.update(dict(c=color, norm=self.norm, cmap=self.cmap))
644
714
  self._collections = ax.scatter(xv, yv, **options, **self.kwargs)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: marsilea
3
- Version: 0.5.3
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=sJ1qYZyJvKSKnbyOUwBjhnDU2pB4TMjOaPBE-msoo3E,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=4jTa05GQsxStDur6FkrNGXAIHUsoipFEDydP8CMCExE,24376
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.3.dist-info/METADATA,sha256=lsolvQQM7C1em-dpNvnkwU2Pr8fAtiIu-H-8DxOQtaU,7265
29
- marsilea-0.5.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
30
- marsilea-0.5.3.dist-info/licenses/LICENSE,sha256=RhHHDuP61qzKmfHtOQUVLZfCgMkKx9PXzxzkLtmAjHo,1078
31
- marsilea-0.5.3.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,,