Skip to content

Commit 0368b66

Browse files
committed
Add footer line
1 parent 9ccf81c commit 0368b66

File tree

15 files changed

+120
-6
lines changed

15 files changed

+120
-6
lines changed

doc/_quartodoc.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,7 @@ quartodoc:
479479
- plot_caption_position
480480
- plot_footer
481481
- plot_footer_background
482+
- plot_footer_line
482483
- plot_footer_position
483484
- plot_margin
484485
- plot_margin_bottom

doc/changelog.qmd

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,11 @@ title: Changelog
3232
theme(plot_footer_background=element_text(fill="pink"))
3333
```
3434

35-
- Added footer labels which are placed below the caption.
35+
Or separate it from the `caption` or the rest of the plot with a line.
3636

37-
which you can set with [](:class:`~plotnine.themeable.`), allowing you to add title,
38-
subtitle or caption to a composition.
37+
```python
38+
theme(plot_footer_line=element_line(color="black"))
39+
```
3940

4041
### Bug Fixes
4142

plotnine/_mpl/layout_manager/_composition_layout_items.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
if TYPE_CHECKING:
1515
from typing import Any
1616

17+
from matplotlib.lines import Line2D
1718
from matplotlib.patches import Rectangle
1819

1920
from plotnine.composition._compose import Compose
@@ -50,6 +51,7 @@ def get(name: str) -> Any:
5051
self.plot_footer_background: Rectangle | None = get(
5152
"plot_footer_background"
5253
)
54+
self.plot_footer_line: Line2D | None = get("plot_footer_line")
5355

5456
def _is_blank(self, name: str) -> bool:
5557
return self.cmp.theme.T.is_blank(name)
@@ -92,6 +94,7 @@ def _move_artists(self, spaces: CompositionSideSpaces):
9294
self.plot_footer, ha, plot_footer_position
9395
)
9496
self._resize_plot_footer_background(spaces)
97+
self._resize_plot_footer_line(spaces)
9598

9699
def _resize_plot_footer_background(self, spaces: CompositionSideSpaces):
97100
"""
@@ -105,6 +108,19 @@ def _resize_plot_footer_background(self, spaces: CompositionSideSpaces):
105108
self.plot_footer_background.set_height(spaces.b.footer_height)
106109
self.plot_footer_background.set_width(spaces.plot_width)
107110

111+
def _resize_plot_footer_line(self, spaces: CompositionSideSpaces):
112+
"""
113+
Resize the footer line to be a border above the footer
114+
"""
115+
if not self.plot_footer_line:
116+
return
117+
118+
x1 = spaces.l.offset
119+
x2 = x1 + spaces.plot_width
120+
y1 = y2 = spaces.b.offset + spaces.b.footer_height
121+
self.plot_footer_line.set_xdata([x1, x2])
122+
self.plot_footer_line.set_ydata([y1, y2])
123+
108124

109125
class CompositionTextJustifier(TextJustifier):
110126
"""

plotnine/_mpl/layout_manager/_plot_layout_items.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
from matplotlib.axes import Axes
2828
from matplotlib.axis import Tick
29+
from matplotlib.lines import Line2D
2930
from matplotlib.patches import Rectangle
3031
from matplotlib.transforms import Transform
3132

@@ -97,6 +98,7 @@ def get(name: str) -> Any:
9798
self.plot_footer_background: Rectangle | None = get(
9899
"plot_footer_background"
99100
)
101+
self.plot_footer_line: Line2D | None = get("plot_footer_line")
100102

101103
def _is_blank(self, name: str) -> bool:
102104
return self.plot.theme.T.is_blank(name)
@@ -385,6 +387,7 @@ def _move_artists(self, spaces: PlotSideSpaces):
385387
self.plot_footer, ha, plot_footer_position
386388
)
387389
self._resize_plot_footer_background(spaces)
390+
self._resize_plot_footer_line(spaces)
388391

389392
if self.axis_title_x:
390393
ha = theme.getp(("axis_title_x", "ha"), "center")
@@ -532,6 +535,19 @@ def _resize_plot_footer_background(self, spaces: PlotSideSpaces):
532535
self.plot_footer_background.set_height(spaces.b.footer_height)
533536
self.plot_footer_background.set_width(spaces.plot_width)
534537

538+
def _resize_plot_footer_line(self, spaces: PlotSideSpaces):
539+
"""
540+
Resize the footer line to be a border above the footer
541+
"""
542+
if not self.plot_footer_line:
543+
return
544+
545+
x1 = spaces.l.offset
546+
x2 = x1 + spaces.plot_width
547+
y1 = y2 = spaces.b.offset + spaces.b.footer_height
548+
self.plot_footer_line.set_xdata([x1, x2])
549+
self.plot_footer_line.set_ydata([y1, y2])
550+
535551

536552
def _text_is_visible(text: Text) -> bool:
537553
"""

plotnine/composition/_compose.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ class Compose:
123123
| ------------- |
124124
| |
125125
| caption |
126+
|-------------------|
126127
| footer |
127128
-------------------
128129
"""
@@ -574,6 +575,7 @@ def _draw_composition_background(self):
574575
"""
575576
Draw the background rectangle of the composition
576577
"""
578+
from matplotlib.lines import Line2D
577579
from matplotlib.patches import Rectangle
578580

579581
zorder = -1000
@@ -589,6 +591,12 @@ def _draw_composition_background(self):
589591
self.figure.add_artist(rect)
590592
self.theme.targets.plot_footer_background = rect
591593

594+
line = Line2D(
595+
[0, 0], [0, 0], color="none", linewidth=0, zorder=zorder + 2
596+
)
597+
self.figure.add_artist(line)
598+
self.theme.targets.plot_footer_line = line
599+
592600
def _draw_annotation(self):
593601
"""
594602
Draw the items in the annotation

plotnine/ggplot.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ class ggplot:
127127
| axis_text |
128128
| axis_title |
129129
| caption |
130+
|-------------------------|
130131
| footer |
131132
-------------------------
132133
"""
@@ -592,6 +593,7 @@ def _draw_watermarks(self):
592593
wm.draw(self.figure)
593594

594595
def _draw_plot_background(self):
596+
from matplotlib.lines import Line2D
595597
from matplotlib.patches import Rectangle
596598

597599
zorder = -1000
@@ -600,15 +602,21 @@ def _draw_plot_background(self):
600602
self._gridspec.patch = rect
601603
self.theme.targets.plot_background = rect
602604

603-
# Footer background only if there is a footer, and put it on top of
604-
# the plot background
605+
# Footer background and line only if there is a footer, and put
606+
# it on top of the plot background
605607
if self.labels.get("footer", ""):
606608
rect = Rectangle(
607609
(0, 0), 0, 0, facecolor="none", linewidth=0, zorder=zorder + 1
608610
)
609611
self.figure.add_artist(rect)
610612
self.theme.targets.plot_footer_background = rect
611613

614+
line = Line2D(
615+
[0, 0], [0, 0], color="none", linewidth=0, zorder=zorder + 2
616+
)
617+
self.figure.add_artist(line)
618+
self.theme.targets.plot_footer_line = line
619+
612620
def _save_filename(self, ext: str) -> Path:
613621
"""
614622
Make a filename for use by the save method

plotnine/themes/targets.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from typing import Optional
88

99
from matplotlib.collections import LineCollection
10+
from matplotlib.lines import Line2D
1011
from matplotlib.patches import Rectangle
1112
from matplotlib.text import Text
1213

@@ -42,6 +43,7 @@ class ThemeTargets:
4243
plot_title: Optional[Text] = None
4344
plot_background: Optional[Rectangle] = None
4445
plot_footer_background: Optional[Rectangle] = None
46+
plot_footer_line: Optional[Line2D] = None
4547
strip_background_x: list[StripTextPatch] = field(default_factory=list)
4648
strip_background_y: list[StripTextPatch] = field(default_factory=list)
4749
strip_text_x: list[StripText] = field(default_factory=list)

plotnine/themes/theme.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ def __init__(
159159
panel_grid_major=None,
160160
panel_grid_minor=None,
161161
panel_grid=None,
162+
plot_footer_line=None,
162163
line=None,
163164
legend_key=None,
164165
legend_frame=None,

plotnine/themes/theme_gray.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ def __init__(self, base_size=11, base_family=None):
117117
margin=margin(t=1 / 3, b=1 / 3, unit="lines"),
118118
),
119119
plot_footer_background=element_blank(),
120+
plot_footer_line=element_blank(),
120121
plot_margin=m,
121122
plot_subtitle=element_text(
122123
va="top",

plotnine/themes/theme_matplotlib.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ def __init__(self, rc=None, fname=None, use_defaults=True):
9999
margin=margin(b=m, unit="fig"),
100100
),
101101
plot_footer_background=element_blank(),
102+
plot_footer_line=element_blank(),
102103
plot_title=element_text(
103104
va="top",
104105
ma="left",

0 commit comments

Comments
 (0)