plotnine 0.15.0.dev1__py3-none-any.whl → 0.15.0.dev2__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.
- plotnine/_mpl/layout_manager/_layout_items.py +219 -78
- plotnine/_mpl/layout_manager/_spaces.py +8 -8
- plotnine/_mpl/patches.py +1 -1
- plotnine/_mpl/text.py +59 -24
- plotnine/_utils/__init__.py +1 -1
- plotnine/facets/strips.py +5 -2
- plotnine/guides/guide.py +2 -2
- plotnine/guides/guide_legend.py +7 -8
- plotnine/iapi.py +4 -2
- plotnine/mapping/aes.py +4 -3
- plotnine/plot_composition/_compose.py +13 -4
- plotnine/themes/elements/element_text.py +1 -0
- plotnine/themes/targets.py +1 -1
- plotnine/themes/theme_gray.py +1 -0
- plotnine/themes/themeable.py +4 -4
- {plotnine-0.15.0.dev1.dist-info → plotnine-0.15.0.dev2.dist-info}/METADATA +1 -1
- {plotnine-0.15.0.dev1.dist-info → plotnine-0.15.0.dev2.dist-info}/RECORD +20 -20
- {plotnine-0.15.0.dev1.dist-info → plotnine-0.15.0.dev2.dist-info}/WHEEL +1 -1
- {plotnine-0.15.0.dev1.dist-info → plotnine-0.15.0.dev2.dist-info}/licenses/LICENSE +0 -0
- {plotnine-0.15.0.dev1.dist-info → plotnine-0.15.0.dev2.dist-info}/top_level.txt +0 -0
|
@@ -361,9 +361,9 @@ class LayoutItems:
|
|
|
361
361
|
]
|
|
362
362
|
return self.calc.max_width(artists)
|
|
363
363
|
|
|
364
|
-
def
|
|
364
|
+
def axis_ticks_x_max_height_at(self, location: AxesLocation) -> float:
|
|
365
365
|
"""
|
|
366
|
-
Return maximum height[
|
|
366
|
+
Return maximum height[figure space] of x ticks
|
|
367
367
|
"""
|
|
368
368
|
heights = [
|
|
369
369
|
self.calc.tight_height(tick.tick1line)
|
|
@@ -372,22 +372,31 @@ class LayoutItems:
|
|
|
372
372
|
]
|
|
373
373
|
return max(heights) if len(heights) else 0
|
|
374
374
|
|
|
375
|
-
def axis_text_x_max_height(self,
|
|
375
|
+
def axis_text_x_max_height(self, ax: Axes) -> float:
|
|
376
376
|
"""
|
|
377
|
-
Return maximum height[
|
|
377
|
+
Return maximum height[figure space] of x tick labels
|
|
378
378
|
"""
|
|
379
379
|
heights = [
|
|
380
380
|
self.calc.tight_height(label) + pad
|
|
381
|
-
for ax in self._filter_axes(location)
|
|
382
381
|
for label, pad in zip(
|
|
383
382
|
self.axis_text_x(ax), self.axis_text_x_margin(ax)
|
|
384
383
|
)
|
|
385
384
|
]
|
|
386
385
|
return max(heights) if len(heights) else 0
|
|
387
386
|
|
|
388
|
-
def
|
|
387
|
+
def axis_text_x_max_height_at(self, location: AxesLocation) -> float:
|
|
388
|
+
"""
|
|
389
|
+
Return maximum height[figure space] of x tick labels
|
|
390
|
+
"""
|
|
391
|
+
heights = [
|
|
392
|
+
self.axis_text_x_max_height(ax)
|
|
393
|
+
for ax in self._filter_axes(location)
|
|
394
|
+
]
|
|
395
|
+
return max(heights) if len(heights) else 0
|
|
396
|
+
|
|
397
|
+
def axis_ticks_y_max_width_at(self, location: AxesLocation) -> float:
|
|
389
398
|
"""
|
|
390
|
-
Return maximum width[
|
|
399
|
+
Return maximum width[figure space] of y ticks
|
|
391
400
|
"""
|
|
392
401
|
widths = [
|
|
393
402
|
self.calc.tight_width(tick.tick1line)
|
|
@@ -396,22 +405,31 @@ class LayoutItems:
|
|
|
396
405
|
]
|
|
397
406
|
return max(widths) if len(widths) else 0
|
|
398
407
|
|
|
399
|
-
def axis_text_y_max_width(self,
|
|
408
|
+
def axis_text_y_max_width(self, ax: Axes) -> float:
|
|
400
409
|
"""
|
|
401
|
-
Return maximum width[
|
|
410
|
+
Return maximum width[figure space] of y tick labels
|
|
402
411
|
"""
|
|
403
412
|
widths = [
|
|
404
413
|
self.calc.tight_width(label) + pad
|
|
405
|
-
for ax in self._filter_axes(location)
|
|
406
414
|
for label, pad in zip(
|
|
407
415
|
self.axis_text_y(ax), self.axis_text_y_margin(ax)
|
|
408
416
|
)
|
|
409
417
|
]
|
|
410
418
|
return max(widths) if len(widths) else 0
|
|
411
419
|
|
|
420
|
+
def axis_text_y_max_width_at(self, location: AxesLocation) -> float:
|
|
421
|
+
"""
|
|
422
|
+
Return maximum width[figure space] of y tick labels
|
|
423
|
+
"""
|
|
424
|
+
widths = [
|
|
425
|
+
self.axis_text_y_max_width(ax)
|
|
426
|
+
for ax in self._filter_axes(location)
|
|
427
|
+
]
|
|
428
|
+
return max(widths) if len(widths) else 0
|
|
429
|
+
|
|
412
430
|
def axis_text_y_top_protrusion(self, location: AxesLocation) -> float:
|
|
413
431
|
"""
|
|
414
|
-
Return maximum height[
|
|
432
|
+
Return maximum height[figure space] above the axes of y tick labels
|
|
415
433
|
"""
|
|
416
434
|
extras = []
|
|
417
435
|
for ax in self._filter_axes(location):
|
|
@@ -424,7 +442,7 @@ class LayoutItems:
|
|
|
424
442
|
|
|
425
443
|
def axis_text_y_bottom_protrusion(self, location: AxesLocation) -> float:
|
|
426
444
|
"""
|
|
427
|
-
Return maximum height[
|
|
445
|
+
Return maximum height[figure space] below the axes of y tick labels
|
|
428
446
|
"""
|
|
429
447
|
extras = []
|
|
430
448
|
for ax in self._filter_axes(location):
|
|
@@ -438,7 +456,7 @@ class LayoutItems:
|
|
|
438
456
|
|
|
439
457
|
def axis_text_x_left_protrusion(self, location: AxesLocation) -> float:
|
|
440
458
|
"""
|
|
441
|
-
Return maximum width[
|
|
459
|
+
Return maximum width[figure space] left of the axes of x tick labels
|
|
442
460
|
"""
|
|
443
461
|
extras = []
|
|
444
462
|
for ax in self._filter_axes(location):
|
|
@@ -452,7 +470,7 @@ class LayoutItems:
|
|
|
452
470
|
|
|
453
471
|
def axis_text_x_right_protrusion(self, location: AxesLocation) -> float:
|
|
454
472
|
"""
|
|
455
|
-
Return maximum width[
|
|
473
|
+
Return maximum width[figure space] right of the axes of y tick labels
|
|
456
474
|
"""
|
|
457
475
|
extras = []
|
|
458
476
|
for ax in self._filter_axes(location):
|
|
@@ -470,6 +488,7 @@ class LayoutItems:
|
|
|
470
488
|
theme = self.plot.theme
|
|
471
489
|
plot_title_position = theme.getp("plot_title_position", "panel")
|
|
472
490
|
plot_caption_position = theme.getp("plot_caption_position", "panel")
|
|
491
|
+
justify = TextJustifier(spaces)
|
|
473
492
|
|
|
474
493
|
if self.plot_tag:
|
|
475
494
|
set_plot_tag_position(self.plot_tag, spaces)
|
|
@@ -477,37 +496,124 @@ class LayoutItems:
|
|
|
477
496
|
if self.plot_title:
|
|
478
497
|
ha = theme.getp(("plot_title", "ha"))
|
|
479
498
|
self.plot_title.set_y(spaces.t.y2("plot_title"))
|
|
480
|
-
|
|
481
|
-
self.plot_title, ha,
|
|
499
|
+
justify.horizontally_about(
|
|
500
|
+
self.plot_title, ha, plot_title_position
|
|
482
501
|
)
|
|
483
502
|
|
|
484
503
|
if self.plot_subtitle:
|
|
485
504
|
ha = theme.getp(("plot_subtitle", "ha"))
|
|
486
505
|
self.plot_subtitle.set_y(spaces.t.y2("plot_subtitle"))
|
|
487
|
-
|
|
488
|
-
self.plot_subtitle, ha,
|
|
506
|
+
justify.horizontally_about(
|
|
507
|
+
self.plot_subtitle, ha, plot_title_position
|
|
489
508
|
)
|
|
490
509
|
|
|
491
510
|
if self.plot_caption:
|
|
492
511
|
ha = theme.getp(("plot_caption", "ha"), "right")
|
|
493
512
|
self.plot_caption.set_y(spaces.b.y1("plot_caption"))
|
|
494
|
-
|
|
495
|
-
self.plot_caption, ha,
|
|
513
|
+
justify.horizontally_about(
|
|
514
|
+
self.plot_caption, ha, plot_caption_position
|
|
496
515
|
)
|
|
497
516
|
|
|
498
517
|
if self.axis_title_x:
|
|
499
518
|
ha = theme.getp(("axis_title_x", "ha"), "center")
|
|
500
519
|
self.axis_title_x.set_y(spaces.b.y1("axis_title_x"))
|
|
501
|
-
|
|
520
|
+
justify.horizontally_about(self.axis_title_x, ha, "panel")
|
|
502
521
|
|
|
503
522
|
if self.axis_title_y:
|
|
504
523
|
va = theme.getp(("axis_title_y", "va"), "center")
|
|
505
524
|
self.axis_title_y.set_x(spaces.l.x1("axis_title_y"))
|
|
506
|
-
|
|
525
|
+
justify.vertically_about(self.axis_title_y, va, "panel")
|
|
507
526
|
|
|
508
527
|
if self.legends:
|
|
509
528
|
set_legends_position(self.legends, spaces)
|
|
510
529
|
|
|
530
|
+
self._adjust_axis_text_x(justify)
|
|
531
|
+
self._adjust_axis_text_y(justify)
|
|
532
|
+
|
|
533
|
+
def _adjust_axis_text_x(self, justify: TextJustifier):
|
|
534
|
+
"""
|
|
535
|
+
Adjust x-axis text, justifying vertically as necessary
|
|
536
|
+
"""
|
|
537
|
+
|
|
538
|
+
def to_vertical_axis_dimensions(value: float, ax: Axes) -> float:
|
|
539
|
+
"""
|
|
540
|
+
Convert value in figure dimensions to axis dimensions
|
|
541
|
+
"""
|
|
542
|
+
_, H = self.plot.figure.bbox.size
|
|
543
|
+
h = ax.get_window_extent().height
|
|
544
|
+
return value * H / h
|
|
545
|
+
|
|
546
|
+
if self._is_blank("axis_text_x"):
|
|
547
|
+
return
|
|
548
|
+
|
|
549
|
+
va = self.plot.theme.getp(("axis_text_x", "va"), "top")
|
|
550
|
+
|
|
551
|
+
for ax in self.plot.axs:
|
|
552
|
+
texts = list(self.axis_text_x(ax))
|
|
553
|
+
axis_text_row_height = to_vertical_axis_dimensions(
|
|
554
|
+
self.axis_text_x_max_height(ax), ax
|
|
555
|
+
)
|
|
556
|
+
for text in texts:
|
|
557
|
+
height = to_vertical_axis_dimensions(
|
|
558
|
+
self.calc.tight_height(text), ax
|
|
559
|
+
)
|
|
560
|
+
justify.vertically(
|
|
561
|
+
text, va, -axis_text_row_height, 0, height=height
|
|
562
|
+
)
|
|
563
|
+
|
|
564
|
+
def _adjust_axis_text_y(self, justify: TextJustifier):
|
|
565
|
+
"""
|
|
566
|
+
Adjust x-axis text, justifying horizontally as necessary
|
|
567
|
+
"""
|
|
568
|
+
|
|
569
|
+
def to_horizontal_axis_dimensions(value: float, ax: Axes) -> float:
|
|
570
|
+
"""
|
|
571
|
+
Convert value in figure dimensions to axis dimensions
|
|
572
|
+
|
|
573
|
+
Matplotlib expects x position of y-axis text is in transAxes,
|
|
574
|
+
but all our layout measurements are in transFigure.
|
|
575
|
+
|
|
576
|
+
---------------------
|
|
577
|
+
| |
|
|
578
|
+
| ----------- |
|
|
579
|
+
| X | | |
|
|
580
|
+
| X | | |
|
|
581
|
+
| X | | |
|
|
582
|
+
| X | | |
|
|
583
|
+
| X | | |
|
|
584
|
+
| X | | |
|
|
585
|
+
| 0-----------1 |
|
|
586
|
+
| axes |
|
|
587
|
+
| |
|
|
588
|
+
0---------------------1
|
|
589
|
+
figure
|
|
590
|
+
|
|
591
|
+
We do not set the transform to transFigure because, then we need
|
|
592
|
+
to calculate the position in transFigure; accounting for all the
|
|
593
|
+
space wherever the panel may be.
|
|
594
|
+
"""
|
|
595
|
+
W, _ = self.plot.figure.bbox.size
|
|
596
|
+
w = ax.get_window_extent().width
|
|
597
|
+
return value * W / w
|
|
598
|
+
|
|
599
|
+
if self._is_blank("axis_text_y"):
|
|
600
|
+
return
|
|
601
|
+
|
|
602
|
+
ha = self.plot.theme.getp(("axis_text_y", "ha"), "right")
|
|
603
|
+
|
|
604
|
+
for ax in self.plot.axs:
|
|
605
|
+
texts = list(self.axis_text_y(ax))
|
|
606
|
+
axis_text_col_width = to_horizontal_axis_dimensions(
|
|
607
|
+
self.axis_text_y_max_width(ax), ax
|
|
608
|
+
)
|
|
609
|
+
for text in texts:
|
|
610
|
+
width = to_horizontal_axis_dimensions(
|
|
611
|
+
self.calc.tight_width(text), ax
|
|
612
|
+
)
|
|
613
|
+
justify.horizontally(
|
|
614
|
+
text, ha, -axis_text_col_width, 0, width=width
|
|
615
|
+
)
|
|
616
|
+
|
|
511
617
|
|
|
512
618
|
def _text_is_visible(text: Text) -> bool:
|
|
513
619
|
"""
|
|
@@ -516,54 +622,47 @@ def _text_is_visible(text: Text) -> bool:
|
|
|
516
622
|
return text.get_visible() and text._text # type: ignore
|
|
517
623
|
|
|
518
624
|
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
ha: str | float,
|
|
522
|
-
spaces: LayoutSpaces,
|
|
523
|
-
how: Literal["panel", "plot"] = "panel",
|
|
524
|
-
):
|
|
625
|
+
@dataclass
|
|
626
|
+
class TextJustifier:
|
|
525
627
|
"""
|
|
526
|
-
|
|
628
|
+
Justify Text
|
|
527
629
|
|
|
528
|
-
|
|
529
|
-
|
|
630
|
+
The justification methods reinterpret alignment values to be justification
|
|
631
|
+
about a span.
|
|
530
632
|
"""
|
|
531
|
-
if isinstance(ha, str):
|
|
532
|
-
lookup = {
|
|
533
|
-
"left": 0.0,
|
|
534
|
-
"center": 0.5,
|
|
535
|
-
"right": 1.0,
|
|
536
|
-
}
|
|
537
|
-
rel = lookup[ha]
|
|
538
|
-
else:
|
|
539
|
-
rel = ha
|
|
540
|
-
|
|
541
|
-
if how == "panel":
|
|
542
|
-
left = spaces.l.left
|
|
543
|
-
right = spaces.r.right
|
|
544
|
-
else:
|
|
545
|
-
left = spaces.l.plot_left
|
|
546
|
-
right = spaces.r.plot_right
|
|
547
633
|
|
|
548
|
-
|
|
549
|
-
x = rel_position(rel, width, left, right)
|
|
550
|
-
text.set_x(x)
|
|
551
|
-
text.set_horizontalalignment("left")
|
|
634
|
+
spaces: LayoutSpaces
|
|
552
635
|
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
636
|
+
def horizontally(
|
|
637
|
+
self,
|
|
638
|
+
text: Text,
|
|
639
|
+
ha: str | float,
|
|
640
|
+
left: float,
|
|
641
|
+
right: float,
|
|
642
|
+
width: float | None = None,
|
|
643
|
+
):
|
|
644
|
+
"""
|
|
645
|
+
Horizontally Justify text between left and right
|
|
646
|
+
"""
|
|
647
|
+
lookup = {"left": 0.0, "center": 0.5, "right": 1.0}
|
|
648
|
+
rel = lookup.get(ha, ha) # pyright: ignore[reportCallIssue, reportArgumentType]
|
|
649
|
+
if width is None:
|
|
650
|
+
width = self.spaces.items.calc.width(text)
|
|
651
|
+
x = rel_position(rel, width, left, right)
|
|
652
|
+
text.set_x(x)
|
|
653
|
+
text.set_horizontalalignment("left")
|
|
654
|
+
|
|
655
|
+
def vertically(
|
|
656
|
+
self,
|
|
657
|
+
text: Text,
|
|
658
|
+
va: str | float,
|
|
659
|
+
bottom: float,
|
|
660
|
+
top: float,
|
|
661
|
+
height: float | None = None,
|
|
662
|
+
):
|
|
663
|
+
"""
|
|
664
|
+
Vertically Justify text between bottom and top
|
|
665
|
+
"""
|
|
567
666
|
lookup = {
|
|
568
667
|
"top": 1.0,
|
|
569
668
|
"center": 0.5,
|
|
@@ -571,21 +670,63 @@ def vertically_align_text(
|
|
|
571
670
|
"center_baseline": 0.5,
|
|
572
671
|
"bottom": 0.0,
|
|
573
672
|
}
|
|
574
|
-
rel = lookup[
|
|
575
|
-
else:
|
|
576
|
-
rel = va
|
|
673
|
+
rel = lookup.get(va, va) # pyright: ignore[reportCallIssue, reportArgumentType]
|
|
577
674
|
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
bottom = spaces.b.plot_bottom
|
|
675
|
+
if height is None:
|
|
676
|
+
height = self.spaces.items.calc.height(text)
|
|
677
|
+
y = rel_position(rel, height, bottom, top)
|
|
678
|
+
text.set_y(y)
|
|
679
|
+
text.set_verticalalignment("bottom")
|
|
584
680
|
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
681
|
+
def horizontally_across_panel(self, text: Text, ha: str | float):
|
|
682
|
+
"""
|
|
683
|
+
Horizontally Justify text accross the panel(s) width
|
|
684
|
+
"""
|
|
685
|
+
self.horizontally(text, ha, self.spaces.l.left, self.spaces.r.right)
|
|
686
|
+
|
|
687
|
+
def horizontally_across_plot(self, text: Text, ha: str | float):
|
|
688
|
+
"""
|
|
689
|
+
Horizontally Justify text across the plot's width
|
|
690
|
+
"""
|
|
691
|
+
self.horizontally(
|
|
692
|
+
text, ha, self.spaces.l.plot_left, self.spaces.r.plot_right
|
|
693
|
+
)
|
|
694
|
+
|
|
695
|
+
def vertically_along_panel(self, text: Text, va: str | float):
|
|
696
|
+
"""
|
|
697
|
+
Horizontally Justify text along the panel(s) height
|
|
698
|
+
"""
|
|
699
|
+
self.vertically(text, va, self.spaces.b.bottom, self.spaces.t.top)
|
|
700
|
+
|
|
701
|
+
def vertically_along_plot(self, text: Text, va: str | float):
|
|
702
|
+
"""
|
|
703
|
+
Vertically Justify text along the plot's height
|
|
704
|
+
"""
|
|
705
|
+
self.vertically(
|
|
706
|
+
text, va, self.spaces.b.plot_bottom, self.spaces.t.plot_top
|
|
707
|
+
)
|
|
708
|
+
|
|
709
|
+
def horizontally_about(
|
|
710
|
+
self, text: Text, ratio: float, how: Literal["panel", "plot"]
|
|
711
|
+
):
|
|
712
|
+
"""
|
|
713
|
+
Horizontally Justify text across the panel or plot
|
|
714
|
+
"""
|
|
715
|
+
if how == "panel":
|
|
716
|
+
self.horizontally_across_panel(text, ratio)
|
|
717
|
+
else:
|
|
718
|
+
self.horizontally_across_plot(text, ratio)
|
|
719
|
+
|
|
720
|
+
def vertically_about(
|
|
721
|
+
self, text: Text, ratio: float, how: Literal["panel", "plot"]
|
|
722
|
+
):
|
|
723
|
+
"""
|
|
724
|
+
Vertically Justify text along the panel or plot
|
|
725
|
+
"""
|
|
726
|
+
if how == "panel":
|
|
727
|
+
self.vertically_along_panel(text, ratio)
|
|
728
|
+
else:
|
|
729
|
+
self.vertically_along_plot(text, ratio)
|
|
589
730
|
|
|
590
731
|
|
|
591
732
|
def set_legends_position(legends: legend_artists, spaces: LayoutSpaces):
|
|
@@ -255,8 +255,8 @@ class left_spaces(_side_spaces):
|
|
|
255
255
|
self.axis_title_y_margin_right = m.r
|
|
256
256
|
|
|
257
257
|
# Account for the space consumed by the axis
|
|
258
|
-
self.axis_text_y = items.
|
|
259
|
-
self.axis_ticks_y = items.
|
|
258
|
+
self.axis_text_y = items.axis_text_y_max_width_at("first_col")
|
|
259
|
+
self.axis_ticks_y = items.axis_ticks_y_max_width_at("first_col")
|
|
260
260
|
|
|
261
261
|
# Adjust plot_margin to make room for ylabels that protude well
|
|
262
262
|
# beyond the axes
|
|
@@ -616,8 +616,8 @@ class bottom_spaces(_side_spaces):
|
|
|
616
616
|
self.axis_title_x_margin_top = m.t * F
|
|
617
617
|
|
|
618
618
|
# Account for the space consumed by the axis
|
|
619
|
-
self.axis_ticks_x = items.
|
|
620
|
-
self.axis_text_x = items.
|
|
619
|
+
self.axis_ticks_x = items.axis_ticks_x_max_height_at("last_row")
|
|
620
|
+
self.axis_text_x = items.axis_text_x_max_height_at("last_row")
|
|
621
621
|
|
|
622
622
|
# Adjust plot_margin to make room for ylabels that protude well
|
|
623
623
|
# beyond the axes
|
|
@@ -917,13 +917,13 @@ class LayoutSpaces:
|
|
|
917
917
|
self.sh += self.t.strip_text_x_height_top * (1 + strip_align_x)
|
|
918
918
|
|
|
919
919
|
if facet.free["x"]:
|
|
920
|
-
self.sh += self.items.
|
|
920
|
+
self.sh += self.items.axis_text_x_max_height_at(
|
|
921
921
|
"all"
|
|
922
|
-
) + self.items.
|
|
922
|
+
) + self.items.axis_ticks_x_max_height_at("all")
|
|
923
923
|
if facet.free["y"]:
|
|
924
|
-
self.sw += self.items.
|
|
924
|
+
self.sw += self.items.axis_text_y_max_width_at(
|
|
925
925
|
"all"
|
|
926
|
-
) + self.items.
|
|
926
|
+
) + self.items.axis_ticks_y_max_width_at("all")
|
|
927
927
|
|
|
928
928
|
# width and height of axes as fraction of figure width & height
|
|
929
929
|
self.w = ((self.r.right - self.l.left) - self.sw * (ncol - 1)) / ncol
|
plotnine/_mpl/patches.py
CHANGED
|
@@ -49,7 +49,7 @@ class StripTextPatch(FancyBboxPatch):
|
|
|
49
49
|
return
|
|
50
50
|
|
|
51
51
|
text = self.text
|
|
52
|
-
posx, posy = text.get_transform().transform(
|
|
52
|
+
posx, posy = text.get_transform().transform(text.get_position())
|
|
53
53
|
x, y, w, h = _get_textbox(text, renderer)
|
|
54
54
|
|
|
55
55
|
self.set_bounds(0.0, 0.0, w, h)
|
plotnine/_mpl/text.py
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
4
|
|
|
5
5
|
from matplotlib.text import Text
|
|
6
6
|
|
|
7
7
|
from .patches import StripTextPatch
|
|
8
|
-
from .utils import bbox_in_axes_space
|
|
8
|
+
from .utils import bbox_in_axes_space, rel_position
|
|
9
9
|
|
|
10
|
-
if
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
11
|
from matplotlib.backend_bases import RendererBase
|
|
12
12
|
|
|
13
13
|
from plotnine.iapi import strip_draw_info
|
|
14
|
+
from plotnine.typing import HorizontalJustification, VerticalJustification
|
|
14
15
|
|
|
15
16
|
|
|
16
17
|
class StripText(Text):
|
|
@@ -23,8 +24,6 @@ class StripText(Text):
|
|
|
23
24
|
|
|
24
25
|
def __init__(self, info: strip_draw_info):
|
|
25
26
|
kwargs = {
|
|
26
|
-
"ha": info.ha,
|
|
27
|
-
"va": info.va,
|
|
28
27
|
"rotation": info.rotation,
|
|
29
28
|
"transform": info.ax.transAxes,
|
|
30
29
|
"clip_on": False,
|
|
@@ -40,38 +39,74 @@ class StripText(Text):
|
|
|
40
39
|
self.draw_info = info
|
|
41
40
|
self.patch = StripTextPatch(self)
|
|
42
41
|
|
|
42
|
+
# TODO: Move these _justify methods to the layout manager
|
|
43
|
+
# We need to first make sure that the patch has the final size during
|
|
44
|
+
# layout computation. Right now, the final size is calculated during
|
|
45
|
+
# draw (in these justify methods)
|
|
46
|
+
def _justify_horizontally(self, renderer):
|
|
47
|
+
"""
|
|
48
|
+
Justify the text along the strip_background
|
|
49
|
+
"""
|
|
50
|
+
info = self.draw_info
|
|
51
|
+
lookup: dict[HorizontalJustification, float] = {
|
|
52
|
+
"left": 0.0,
|
|
53
|
+
"center": 0.5,
|
|
54
|
+
"right": 1.0,
|
|
55
|
+
}
|
|
56
|
+
rel = lookup.get(info.ha, 0.5) if isinstance(info.ha, str) else info.ha
|
|
57
|
+
patch_bbox = bbox_in_axes_space(self.patch, info.ax, renderer)
|
|
58
|
+
text_bbox = bbox_in_axes_space(self, info.ax, renderer)
|
|
59
|
+
l, b, w, h = info.x, info.y, info.box_width, patch_bbox.height
|
|
60
|
+
b = b + patch_bbox.height * info.strip_align
|
|
61
|
+
x = rel_position(rel, text_bbox.width, patch_bbox.x0, patch_bbox.x1)
|
|
62
|
+
y = b + h / 2
|
|
63
|
+
self.set_horizontalalignment("left")
|
|
64
|
+
self.patch.set_bounds(l, b, w, h)
|
|
65
|
+
self.set_position((x, y))
|
|
66
|
+
|
|
67
|
+
def _justify_vertically(self, renderer):
|
|
68
|
+
"""
|
|
69
|
+
Justify the text along the strip_background
|
|
70
|
+
"""
|
|
71
|
+
# Note that the strip text & background and horizontal but
|
|
72
|
+
# rotated to appear vertical. So we really are still justifying
|
|
73
|
+
# horizontally.
|
|
74
|
+
info = self.draw_info
|
|
75
|
+
lookup: dict[VerticalJustification, float] = {
|
|
76
|
+
"bottom": 0.0,
|
|
77
|
+
"center": 0.5,
|
|
78
|
+
"top": 1.0,
|
|
79
|
+
}
|
|
80
|
+
rel = lookup.get(info.va, 0.5) if isinstance(info.va, str) else info.va
|
|
81
|
+
patch_bbox = bbox_in_axes_space(self.patch, info.ax, renderer)
|
|
82
|
+
text_bbox = bbox_in_axes_space(self, info.ax, renderer)
|
|
83
|
+
l, b, w, h = info.x, info.y, patch_bbox.width, info.box_height
|
|
84
|
+
l = l + patch_bbox.width * info.strip_align
|
|
85
|
+
x = l + w / 2
|
|
86
|
+
y = rel_position(rel, text_bbox.height, patch_bbox.y0, patch_bbox.y1)
|
|
87
|
+
self.set_horizontalalignment("right") # 90CW right means bottom
|
|
88
|
+
self.patch.set_bounds(l, b, w, h)
|
|
89
|
+
self.set_position((x, y))
|
|
90
|
+
|
|
43
91
|
def draw(self, renderer: RendererBase):
|
|
44
92
|
if not self.get_visible():
|
|
45
93
|
return
|
|
46
94
|
|
|
47
|
-
|
|
48
|
-
# "fill up" spatch to contain the text
|
|
95
|
+
# expand strip_text patch to contain the text
|
|
49
96
|
self.patch.update_position_size(renderer)
|
|
50
97
|
|
|
51
|
-
# Get bbox of spatch in transAxes space
|
|
52
|
-
patch_bbox = bbox_in_axes_space(self.patch, info.ax, renderer)
|
|
53
|
-
|
|
54
98
|
# Align patch across the edge of the panel
|
|
55
|
-
if
|
|
56
|
-
|
|
57
|
-
b = b + patch_bbox.height * info.strip_align
|
|
99
|
+
if self.draw_info.position == "top":
|
|
100
|
+
self._justify_horizontally(renderer)
|
|
58
101
|
else: # "right"
|
|
59
|
-
|
|
60
|
-
l = l + patch_bbox.width * info.strip_align
|
|
102
|
+
self._justify_vertically(renderer)
|
|
61
103
|
|
|
62
|
-
self.patch.
|
|
63
|
-
self.patch.set_transform(info.ax.transAxes)
|
|
104
|
+
self.patch.set_transform(self.draw_info.ax.transAxes)
|
|
64
105
|
self.patch.set_mutation_scale(0)
|
|
65
106
|
|
|
66
107
|
# Put text in center of patch
|
|
67
|
-
self._x = l + w / 2
|
|
68
|
-
self._y = b + h / 2
|
|
69
|
-
|
|
70
|
-
# "anchor" aligns before rotation so the right-strip get properly
|
|
71
|
-
# centered text
|
|
72
108
|
self.set_rotation_mode("anchor")
|
|
73
|
-
self.
|
|
74
|
-
self.set_verticalalignment("center_baseline") # top-strip
|
|
109
|
+
self.set_verticalalignment("center_baseline")
|
|
75
110
|
|
|
76
111
|
# Draw spatch
|
|
77
112
|
self.patch.draw(renderer)
|
plotnine/_utils/__init__.py
CHANGED
|
@@ -299,7 +299,7 @@ def ninteraction(df: pd.DataFrame, drop: bool = False) -> list[int]:
|
|
|
299
299
|
return _id_var(df[df.columns[0]], drop)
|
|
300
300
|
|
|
301
301
|
# Calculate individual ids
|
|
302
|
-
ids = df.apply(_id_var, axis=0)
|
|
302
|
+
ids = df.apply(_id_var, axis=0, drop=drop)
|
|
303
303
|
ids = ids.reindex(columns=list(reversed(ids.columns)))
|
|
304
304
|
|
|
305
305
|
# Calculate dimensions
|
plotnine/facets/strips.py
CHANGED
|
@@ -63,11 +63,13 @@ class strip:
|
|
|
63
63
|
"""
|
|
64
64
|
theme = self.theme
|
|
65
65
|
position = self.position
|
|
66
|
+
|
|
66
67
|
if position == "top":
|
|
67
68
|
# The x & y values are just starting locations
|
|
68
69
|
# The final location is determined by the layout manager.
|
|
69
70
|
y = 1
|
|
70
|
-
ha
|
|
71
|
+
ha = theme.getp(("strip_text_x", "ha"), "center")
|
|
72
|
+
va = theme.getp(("strip_text_x", "va"), "bottom")
|
|
71
73
|
rotation = theme.getp(("strip_text_x", "rotation"))
|
|
72
74
|
box_width = 1
|
|
73
75
|
box_height = 0 # Determined by the text size
|
|
@@ -88,7 +90,8 @@ class strip:
|
|
|
88
90
|
# The x & y values are just starting locations
|
|
89
91
|
# The final location is determined by the layout manager.
|
|
90
92
|
x = 1
|
|
91
|
-
ha
|
|
93
|
+
ha = theme.getp(("strip_text_y", "ha"), "left")
|
|
94
|
+
va = theme.getp(("strip_text_y", "va"), "center")
|
|
92
95
|
rotation = theme.getp(("strip_text_y", "rotation"))
|
|
93
96
|
box_width = 0 # Determine by the text height
|
|
94
97
|
# TODO: Allow two unique paddings for either side.
|
plotnine/guides/guide.py
CHANGED
|
@@ -18,7 +18,7 @@ if TYPE_CHECKING:
|
|
|
18
18
|
from typing_extensions import Self
|
|
19
19
|
|
|
20
20
|
from plotnine import aes, guides
|
|
21
|
-
from plotnine.layer import Layers
|
|
21
|
+
from plotnine.layer import Layers, layer
|
|
22
22
|
from plotnine.scales.scale import scale
|
|
23
23
|
from plotnine.typing import (
|
|
24
24
|
LegendPosition,
|
|
@@ -79,7 +79,7 @@ class guide(ABC, metaclass=Register):
|
|
|
79
79
|
self.elements = cast("GuideElements", None)
|
|
80
80
|
self.guides_elements: GuidesElements
|
|
81
81
|
|
|
82
|
-
def legend_aesthetics(self, layer):
|
|
82
|
+
def legend_aesthetics(self, layer: layer):
|
|
83
83
|
"""
|
|
84
84
|
Return the aesthetics that contribute to the legend
|
|
85
85
|
|
plotnine/guides/guide_legend.py
CHANGED
|
@@ -171,21 +171,20 @@ class guide_legend(guide):
|
|
|
171
171
|
# Modify aesthetics
|
|
172
172
|
|
|
173
173
|
# When doing after_scale evaluations, we only consider those
|
|
174
|
-
# for the aesthetics
|
|
175
|
-
# warnings where an evaluation of another aesthetic failed yet
|
|
176
|
-
# it is not needed.
|
|
174
|
+
# for the aesthetics that are valid for this layer/geom.
|
|
177
175
|
aes_modifiers = {
|
|
178
|
-
ae:
|
|
179
|
-
for ae
|
|
180
|
-
if ae in matched_set
|
|
176
|
+
ae: l.mapping._scaled[ae]
|
|
177
|
+
for ae in l.geom.aesthetics() & l.mapping._scaled.keys()
|
|
181
178
|
}
|
|
182
179
|
|
|
183
180
|
try:
|
|
184
181
|
data = l.use_defaults(data, aes_modifiers)
|
|
185
182
|
except PlotnineError:
|
|
186
183
|
warn(
|
|
187
|
-
"Failed to apply `after_scale` modifications "
|
|
188
|
-
"
|
|
184
|
+
"Failed to apply `after_scale` modifications to the "
|
|
185
|
+
"legend. This probably should not happen. Help us "
|
|
186
|
+
"discover why, please open and issue at "
|
|
187
|
+
"https://github.com/has2k1/plotnine/issues",
|
|
189
188
|
PlotnineWarning,
|
|
190
189
|
)
|
|
191
190
|
data = l.use_defaults(data, {})
|
plotnine/iapi.py
CHANGED
|
@@ -22,8 +22,10 @@ if TYPE_CHECKING:
|
|
|
22
22
|
from plotnine.typing import (
|
|
23
23
|
CoordRange,
|
|
24
24
|
FloatArrayLike,
|
|
25
|
+
HorizontalJustification,
|
|
25
26
|
ScaledAestheticsName,
|
|
26
27
|
StripPosition,
|
|
28
|
+
VerticalJustification,
|
|
27
29
|
)
|
|
28
30
|
|
|
29
31
|
from ._mpl.offsetbox import FlexibleAnchoredOffsetbox
|
|
@@ -231,8 +233,8 @@ class strip_draw_info:
|
|
|
231
233
|
|
|
232
234
|
x: float
|
|
233
235
|
y: float
|
|
234
|
-
ha:
|
|
235
|
-
va:
|
|
236
|
+
ha: HorizontalJustification | float
|
|
237
|
+
va: VerticalJustification | float
|
|
236
238
|
box_width: float
|
|
237
239
|
box_height: float
|
|
238
240
|
strip_text_margin: float
|
plotnine/mapping/aes.py
CHANGED
|
@@ -6,6 +6,7 @@ from collections.abc import Iterable, Sequence
|
|
|
6
6
|
from contextlib import suppress
|
|
7
7
|
from copy import deepcopy
|
|
8
8
|
from dataclasses import fields
|
|
9
|
+
from functools import cached_property
|
|
9
10
|
from typing import Any, Dict
|
|
10
11
|
|
|
11
12
|
import pandas as pd
|
|
@@ -237,7 +238,7 @@ class aes(Dict[str, Any]):
|
|
|
237
238
|
kwargs[name] = after_stat(_after_stat)
|
|
238
239
|
return kwargs
|
|
239
240
|
|
|
240
|
-
@
|
|
241
|
+
@cached_property
|
|
241
242
|
def _starting(self) -> dict[str, Any]:
|
|
242
243
|
"""
|
|
243
244
|
Return the subset of aesthetics mapped from the layer data
|
|
@@ -254,7 +255,7 @@ class aes(Dict[str, Any]):
|
|
|
254
255
|
|
|
255
256
|
return d
|
|
256
257
|
|
|
257
|
-
@
|
|
258
|
+
@cached_property
|
|
258
259
|
def _calculated(self) -> dict[str, Any]:
|
|
259
260
|
"""
|
|
260
261
|
Return only the aesthetics mapped to calculated statistics
|
|
@@ -269,7 +270,7 @@ class aes(Dict[str, Any]):
|
|
|
269
270
|
|
|
270
271
|
return d
|
|
271
272
|
|
|
272
|
-
@
|
|
273
|
+
@cached_property
|
|
273
274
|
def _scaled(self) -> dict[str, Any]:
|
|
274
275
|
"""
|
|
275
276
|
Return only the aesthetics mapped to after scaling
|
|
@@ -283,11 +283,20 @@ class Compose:
|
|
|
283
283
|
)
|
|
284
284
|
return figure
|
|
285
285
|
|
|
286
|
-
def save(
|
|
287
|
-
|
|
288
|
-
|
|
286
|
+
def save(self, filename: str | Path | BytesIO, format: str | None = None):
|
|
287
|
+
"""
|
|
288
|
+
Save a Compose object as an image file
|
|
289
|
+
|
|
290
|
+
Parameters
|
|
291
|
+
----------
|
|
292
|
+
filename :
|
|
293
|
+
File name to write the plot to. If not specified, a name
|
|
294
|
+
format :
|
|
295
|
+
Image format to use, automatically extract from
|
|
296
|
+
file name extension.
|
|
297
|
+
"""
|
|
289
298
|
figure = self.draw()
|
|
290
|
-
figure.savefig(filename, format=
|
|
299
|
+
figure.savefig(filename, format=format)
|
|
291
300
|
|
|
292
301
|
|
|
293
302
|
@dataclass
|
plotnine/themes/targets.py
CHANGED
plotnine/themes/theme_gray.py
CHANGED
plotnine/themes/themeable.py
CHANGED
|
@@ -811,7 +811,7 @@ class strip_text_x(MixinSequenceOfValues):
|
|
|
811
811
|
theme_element : element_text
|
|
812
812
|
"""
|
|
813
813
|
|
|
814
|
-
_omit = ["margin"]
|
|
814
|
+
_omit = ["margin", "ha"]
|
|
815
815
|
|
|
816
816
|
def apply_figure(self, figure: Figure, targets: ThemeTargets):
|
|
817
817
|
super().apply_figure(figure, targets)
|
|
@@ -834,7 +834,7 @@ class strip_text_y(MixinSequenceOfValues):
|
|
|
834
834
|
theme_element : element_text
|
|
835
835
|
"""
|
|
836
836
|
|
|
837
|
-
_omit = ["margin"]
|
|
837
|
+
_omit = ["margin", "va"]
|
|
838
838
|
|
|
839
839
|
def apply_figure(self, figure: Figure, targets: ThemeTargets):
|
|
840
840
|
super().apply_figure(figure, targets)
|
|
@@ -890,7 +890,7 @@ class axis_text_x(MixinSequenceOfValues):
|
|
|
890
890
|
creates a margin of 5 points.
|
|
891
891
|
"""
|
|
892
892
|
|
|
893
|
-
_omit = ["margin"]
|
|
893
|
+
_omit = ["margin", "va"]
|
|
894
894
|
|
|
895
895
|
def apply_ax(self, ax: Axes):
|
|
896
896
|
super().apply_ax(ax)
|
|
@@ -923,7 +923,7 @@ class axis_text_y(MixinSequenceOfValues):
|
|
|
923
923
|
creates a margin of 5 points.
|
|
924
924
|
"""
|
|
925
925
|
|
|
926
|
-
_omit = ["margin"]
|
|
926
|
+
_omit = ["margin", "ha"]
|
|
927
927
|
|
|
928
928
|
def apply_ax(self, ax: Axes):
|
|
929
929
|
super().apply_ax(ax)
|
|
@@ -3,7 +3,7 @@ plotnine/animation.py,sha256=izJZ4Gy0cBHEBc8ehofsWSWOzZW8UEroy1Uvw86Igb0,7521
|
|
|
3
3
|
plotnine/doctools.py,sha256=OoPKtbFNkhQ6vKk8NfivC_xKPSvwBWvNo5-ZHS8tRAk,14540
|
|
4
4
|
plotnine/exceptions.py,sha256=SgTxBHkV65HjGI3aFy2q1_lHP9HAdiuxVLN3U-PJWSQ,1616
|
|
5
5
|
plotnine/ggplot.py,sha256=oMeAwsYDVhpsFV1VhxYes-0bgAPmlAE8py_eI92Xlbo,24822
|
|
6
|
-
plotnine/iapi.py,sha256=
|
|
6
|
+
plotnine/iapi.py,sha256=GZfXYS6JKyc8J2DB-QuSdtG_WGjBeR2vZP6ERYPUlrg,8420
|
|
7
7
|
plotnine/labels.py,sha256=Ja1F0ZN5YxNjaWiAckc-jniMqXdnZxHCsqK5uudpx1s,2827
|
|
8
8
|
plotnine/layer.py,sha256=r46mX4Sh_M2sHSpLcnf9UL-zc4ANuXvK8HRCQeWcya4,16749
|
|
9
9
|
plotnine/options.py,sha256=j3zXv4wc3J4nOI_TqJ5s_abuifodt_UN8MR8M4i8UVA,3108
|
|
@@ -14,17 +14,17 @@ plotnine/watermark.py,sha256=_SLjhiQquB0Vd_b5t_7-mUCvrbiN86tUYbBqU76JcSM,1506
|
|
|
14
14
|
plotnine/_mpl/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
15
15
|
plotnine/_mpl/gridspec.py,sha256=OvlXchYXam1c1n8iNPKu4fJr6rqmH7OWebhJX5qqOmY,7903
|
|
16
16
|
plotnine/_mpl/offsetbox.py,sha256=E7810lS9W7Gexwz5mkSMz7PQXXHkYX-WHKlPHqapmTg,3216
|
|
17
|
-
plotnine/_mpl/patches.py,sha256=
|
|
18
|
-
plotnine/_mpl/text.py,sha256=
|
|
17
|
+
plotnine/_mpl/patches.py,sha256=DLIFn4BFqrv0FXtbtloNWE5kaJRq85Q_8vz21sMJxuU,2568
|
|
18
|
+
plotnine/_mpl/text.py,sha256=0rkIi69Yd3qX9yg4f3wfaDY8tky1HZXkZFA0575Di_c,3822
|
|
19
19
|
plotnine/_mpl/ticker.py,sha256=RY_7AdTggc7QBq9_t0KBJXg36oxKfB-Vtc9FzLnaGnQ,393
|
|
20
20
|
plotnine/_mpl/transforms.py,sha256=DNaOlNq76xlT696sN8ot1bmYyp4mmrjXQHk3kTi4HIg,76
|
|
21
21
|
plotnine/_mpl/utils.py,sha256=c9wkxxUEweDg6O0hdgZonNOFncwxkqFye8_bL7td7I4,4131
|
|
22
22
|
plotnine/_mpl/layout_manager/__init__.py,sha256=IXpPF5Oycc45uFpK4MJ6kcQCe1u5VUfnHLNZGcnrJCg,157
|
|
23
23
|
plotnine/_mpl/layout_manager/_engine.py,sha256=ESUvbLAlZApFbBi6w7gZA7S4guS0Rmrj-us-gzYP2ZM,2809
|
|
24
|
-
plotnine/_mpl/layout_manager/_layout_items.py,sha256=
|
|
24
|
+
plotnine/_mpl/layout_manager/_layout_items.py,sha256=9wkXgCa66yCCYtpF_e0n0ORGuGGwDmEmPnNrkv-QbEg,28360
|
|
25
25
|
plotnine/_mpl/layout_manager/_layout_tree.py,sha256=Cm2-udh5DQ8cxIZwefRkRp1ddgtJp8kvMYKeWBasHVU,18061
|
|
26
|
-
plotnine/_mpl/layout_manager/_spaces.py,sha256=
|
|
27
|
-
plotnine/_utils/__init__.py,sha256=
|
|
26
|
+
plotnine/_mpl/layout_manager/_spaces.py,sha256=8ydStHv0O1b6JBdtBXbHkSrGzklMgutMUfgwB0lH_Dk,31866
|
|
27
|
+
plotnine/_utils/__init__.py,sha256=9RVYfwi9NmDGGzprUlE40yv9tJhW_VDAZkUKTTuvN7g,32473
|
|
28
28
|
plotnine/_utils/context.py,sha256=HPQy_uyNXdS0s9URD7ZePyuc5hFU2XrRBLDTqRDLJzY,1708
|
|
29
29
|
plotnine/_utils/dev.py,sha256=0qgRbMhcd4dfuLuYxx0skocKAtfwHF02ntyILRBogbg,1629
|
|
30
30
|
plotnine/_utils/ipython.py,sha256=5Obr73xJ-4dzJEdBrFA8z9TXuxY7pIjKmzdTzWwnxNk,1884
|
|
@@ -61,7 +61,7 @@ plotnine/facets/facet_null.py,sha256=J--RdOvFP7AE0jK79-LNRksvCJExQTpS-tU5i0pGqs8
|
|
|
61
61
|
plotnine/facets/facet_wrap.py,sha256=NOoNdkaSb1y_ho6UygGkDih7zlQYXcEgJYK0Lqu6e98,8805
|
|
62
62
|
plotnine/facets/labelling.py,sha256=JEuwERTK0IfmxTWHbl2nsGgxZ6xi0n2TTWT4_OSfQcQ,8833
|
|
63
63
|
plotnine/facets/layout.py,sha256=TIkMChA0wJWLKN31PH0czS6CN4pw3o--PF49LakJ2h4,8967
|
|
64
|
-
plotnine/facets/strips.py,sha256=
|
|
64
|
+
plotnine/facets/strips.py,sha256=7K_SLVLhlb2-E-JNCZWOamFbC-yKLJ0yuqbwNoElLXk,6154
|
|
65
65
|
plotnine/geoms/__init__.py,sha256=HEfhNmmNH4xm4rpXnFRXY4eLkJha3XPM72IIwVjv5Lc,2697
|
|
66
66
|
plotnine/geoms/annotate.py,sha256=5sCHIMR_GjM2ujNY73i4iBczOkGi-vq1Nr1Yc3cBgZo,4022
|
|
67
67
|
plotnine/geoms/annotation_logticks.py,sha256=2_ILqE2cgX2acFoGZPDnbTJ0V7b3-ALVjno71FQuuxE,8953
|
|
@@ -111,17 +111,17 @@ plotnine/geoms/geom_tile.py,sha256=3x9BSxaSr-ys6N5R2wY8B9fNiyV9vMdoXbjIDqHy_ng,1
|
|
|
111
111
|
plotnine/geoms/geom_violin.py,sha256=-lXdHQjrPAQXvFEviGi9iJqU_8L6_YrYYXwg62-8N58,6545
|
|
112
112
|
plotnine/geoms/geom_vline.py,sha256=qKUd4IosH1VrwHbqNbs29kZyIW5lQRa_LZLRcLbPg38,3377
|
|
113
113
|
plotnine/guides/__init__.py,sha256=ulI-mDhtq3jAQEAqPv8clrn3UHGFOu3xRuO7jXlq-LY,201
|
|
114
|
-
plotnine/guides/guide.py,sha256=
|
|
114
|
+
plotnine/guides/guide.py,sha256=L1O26atzSjiQR-YW9w3XEcH0BDFiqthdY6wA6DAOapo,8229
|
|
115
115
|
plotnine/guides/guide_axis.py,sha256=zG_5Ot1kTuHOeuQspL5V1A1-7c7X8cNeMDoF01Ghh2w,296
|
|
116
116
|
plotnine/guides/guide_colorbar.py,sha256=zHM6QRrzACC2l1Vq6p04Cu0QAGuTBfp3AhPyyMbYbgc,16290
|
|
117
|
-
plotnine/guides/guide_legend.py,sha256=
|
|
117
|
+
plotnine/guides/guide_legend.py,sha256=0CSyRxlHu0RSJjnMWvnStnq-EtjgdmHv54QgPWC3ufE,14236
|
|
118
118
|
plotnine/guides/guides.py,sha256=UI3AhTOQCsXur_L-Jr3VwAQcX4dBeZMohSbA2wg1YeA,15478
|
|
119
119
|
plotnine/mapping/__init__.py,sha256=DLu9E0kwwuHxzTUenoVjCNTTdkWMwIDtkExLleBq1MI,205
|
|
120
120
|
plotnine/mapping/_env.py,sha256=ZzcSv54PLOD8b8Ny2h6xteGoO8bJdbj9dM6Mlg5h0V8,6094
|
|
121
|
-
plotnine/mapping/aes.py,sha256=
|
|
121
|
+
plotnine/mapping/aes.py,sha256=feWP04esVXjrpHlIsSRgoGvFtJjQ4noy-2gIp5MdUww,16192
|
|
122
122
|
plotnine/mapping/evaluation.py,sha256=91xVP2KxCM-ur_KOFyki7Jm1t8GWPA1TecJbjZ9yOaQ,7699
|
|
123
123
|
plotnine/plot_composition/__init__.py,sha256=ZJYpfVF158cQZ1zREXy6wHNJ4FbSmqWxIkHWZwX3QT8,148
|
|
124
|
-
plotnine/plot_composition/_compose.py,sha256=
|
|
124
|
+
plotnine/plot_composition/_compose.py,sha256=uQfXxDbEayqyjX6yMOCJiePqAK7I2OU5YnBhphkYFY4,11477
|
|
125
125
|
plotnine/plot_composition/_plotspec.py,sha256=0F7q7PjDMDqcallpnBdX3N2iSRjdBTyjSvMFf83uvPU,1015
|
|
126
126
|
plotnine/plot_composition/_spacer.py,sha256=vaC4F5tHhvL7T7Ns9zxUbytqwB6MLNhm5jtiKG0vAiU,798
|
|
127
127
|
plotnine/positions/__init__.py,sha256=DQZE6duMUNRQifpa6SBrOKxZpGDk4NqQSGZLr9Yc9GI,595
|
|
@@ -184,13 +184,13 @@ plotnine/stats/stat_unique.py,sha256=7SXu_gb6h6YgLa1L-LM8hHe0jMZfcus4c_mEAN9zcWo
|
|
|
184
184
|
plotnine/stats/stat_ydensity.py,sha256=cuGZwpBdotGhOLYaK_W_JvJSjCht9W1eJpbzW69ZhOY,5686
|
|
185
185
|
plotnine/themes/__init__.py,sha256=tEKIF4gYmOF2Z1-_UDdK8zh41dLl-61HUGIhOQvki6I,916
|
|
186
186
|
plotnine/themes/seaborn_rcmod.py,sha256=Pi-UX5LyH9teSuteYpqPOEnfLgKUz01LnKDyDA7Aois,15502
|
|
187
|
-
plotnine/themes/targets.py,sha256=
|
|
187
|
+
plotnine/themes/targets.py,sha256=MjBRWWRgsLXXM_PJffPsV4DttQJB_m11jdD837BteuU,1686
|
|
188
188
|
plotnine/themes/theme.py,sha256=sMEDXgbqMNRCnkS3AXIqE_KXdXrXVjwf3r1Kr0WnE5E,16244
|
|
189
189
|
plotnine/themes/theme_538.py,sha256=6ZeIzzJ1VTgCMBYw4uprSjkS8GtcFvJmOIGjbm7h3Ok,1141
|
|
190
190
|
plotnine/themes/theme_bw.py,sha256=KDOqt5C6SYaxr05ngZoTmvGvgZVeCDFLWOpChcO-Hek,1077
|
|
191
191
|
plotnine/themes/theme_classic.py,sha256=B6QkU6blGnEY5iaiPtu4VsvFzC0peWSAhlKiC2SJSkM,923
|
|
192
192
|
plotnine/themes/theme_dark.py,sha256=RbdMfK9GW3q5XFIVgSe_OH-ozohSgjMoxMYqw40QZJ4,1335
|
|
193
|
-
plotnine/themes/theme_gray.py,sha256=
|
|
193
|
+
plotnine/themes/theme_gray.py,sha256=9NVn5jOh_ypMbtnkICQk_v6GsL2gUzjal1xQKMHmwFk,5300
|
|
194
194
|
plotnine/themes/theme_light.py,sha256=-vFWjP_vBMnuThNxkhVJvT9rKtr0tXWcrHDKdI_G3Ic,1429
|
|
195
195
|
plotnine/themes/theme_linedraw.py,sha256=woMr18xoEJmsD8ZCiUpdyn-CE-P1AGFHRNapwCGWUjg,1350
|
|
196
196
|
plotnine/themes/theme_matplotlib.py,sha256=Dqjr4J68lPxaCxp6Xq9VthOOS5CZLit-pL3zMV24ZaA,4260
|
|
@@ -199,16 +199,16 @@ plotnine/themes/theme_seaborn.py,sha256=l4lz5qD5CqhqBDgfQ61Mye3TX3f5aCHoHHx1Q04j
|
|
|
199
199
|
plotnine/themes/theme_tufte.py,sha256=qUOrZhQyfJgc0fmy8Es7tT7aYqUSzCjvkP7-dBilwHE,1926
|
|
200
200
|
plotnine/themes/theme_void.py,sha256=bU2REV9dI4x2kDIlPO6Oaq3E5di2cE8VDH-hRrnWEMc,3367
|
|
201
201
|
plotnine/themes/theme_xkcd.py,sha256=q3i1W97kBwpCRbR_Y609JxcfJA2cEX5e5iAS7flbF6I,2257
|
|
202
|
-
plotnine/themes/themeable.py,sha256=
|
|
202
|
+
plotnine/themes/themeable.py,sha256=nWgJ-0u4TnXH2rJa-qScUT-Hrefc2O7lPfYnmTTnttg,69179
|
|
203
203
|
plotnine/themes/elements/__init__.py,sha256=Z9xHdhyWPNR2uF_P80aBEXYWp1DU-T2KGOuM7VimpbM,295
|
|
204
204
|
plotnine/themes/elements/element_base.py,sha256=D7cfEglzsSuhW91KpZVAZ2MAHWZp64r9Aajoh8uMGZ4,832
|
|
205
205
|
plotnine/themes/elements/element_blank.py,sha256=4r7-6HeR1494oWNIGQh0ASrFQ4SLvYa6aQHA85eH-Ds,187
|
|
206
206
|
plotnine/themes/elements/element_line.py,sha256=xF6xW-iA66YEP_fN7ooqaYry8_8qZT-eT5wvKwXg3to,1838
|
|
207
207
|
plotnine/themes/elements/element_rect.py,sha256=w5cLH-Sr4cTRXVdkRiu8kBqFt3TXHhIb1MUITfi89gE,1767
|
|
208
|
-
plotnine/themes/elements/element_text.py,sha256=
|
|
208
|
+
plotnine/themes/elements/element_text.py,sha256=8yhwBa9s9JKCtBcqcBNybbCGK6ieDnZv4SHiC4Sy2qc,6255
|
|
209
209
|
plotnine/themes/elements/margin.py,sha256=EsT46lqky7APHxMUDiNiTieNo_SIbHF-Sjhmf9zo4WY,2880
|
|
210
|
-
plotnine-0.15.0.
|
|
211
|
-
plotnine-0.15.0.
|
|
212
|
-
plotnine-0.15.0.
|
|
213
|
-
plotnine-0.15.0.
|
|
214
|
-
plotnine-0.15.0.
|
|
210
|
+
plotnine-0.15.0.dev2.dist-info/licenses/LICENSE,sha256=GY4tQiUd17Tq3wWR42Zs9MRTFOTf6ahIXhZTcwAdOeU,1082
|
|
211
|
+
plotnine-0.15.0.dev2.dist-info/METADATA,sha256=FYs_q0rKbRXD28ywez0hpKxIKULY21v9RCMw2dEgClI,9289
|
|
212
|
+
plotnine-0.15.0.dev2.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
|
213
|
+
plotnine-0.15.0.dev2.dist-info/top_level.txt,sha256=t340Mbko1ZbmvYPkQ81dIiPHcaQdTUszYz-bWUpr8ys,9
|
|
214
|
+
plotnine-0.15.0.dev2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|