|
27 | 27 |
|
28 | 28 | from matplotlib.axes import Axes |
29 | 29 | from matplotlib.axis import Tick |
| 30 | + from matplotlib.figure import Figure |
30 | 31 | from matplotlib.lines import Line2D |
31 | 32 | from matplotlib.patches import Rectangle |
32 | 33 | from matplotlib.transforms import Transform |
|
36 | 37 | from plotnine._mpl.text import StripText |
37 | 38 | from plotnine.iapi import legend_artists |
38 | 39 | from plotnine.themes.elements import margin as Margin |
| 40 | + from plotnine.themes.theme import theme |
39 | 41 | from plotnine.typing import ( |
40 | 42 | StripPosition, |
41 | 43 | ) |
42 | 44 |
|
| 45 | + from ._composition_layout_items import CompositionLayoutItems |
| 46 | + from ._composition_side_space import CompositionSideSpaces |
43 | 47 | from ._plot_side_space import PlotSideSpaces |
44 | 48 |
|
45 | 49 | AxesLocation: TypeAlias = Literal[ |
@@ -352,67 +356,13 @@ def _move_artists(self, spaces: PlotSideSpaces): |
352 | 356 | Move the artists to their final positions |
353 | 357 | """ |
354 | 358 | theme = self.plot.theme |
355 | | - plot_title_position = theme.getp("plot_title_position", "panel") |
356 | | - plot_caption_position = theme.getp("plot_caption_position", "panel") |
357 | | - plot_footer_position = theme.getp("plot_footer_position", "plot") |
358 | | - justify = TextJustifier.from_boundaries( |
359 | | - spaces.plot.figure, |
360 | | - plot_left=spaces.l.plot_left, |
361 | | - plot_right=spaces.r.plot_right, |
362 | | - plot_bottom=spaces.b.plot_bottom, |
363 | | - plot_top=spaces.t.plot_top, |
364 | | - panel_left=spaces.l.panel_left, |
365 | | - panel_right=spaces.r.panel_right, |
366 | | - panel_bottom=spaces.b.panel_bottom, |
367 | | - panel_top=spaces.t.panel_top, |
| 359 | + justify = _position_plot_labels( |
| 360 | + spaces.plot.figure, theme, spaces, self |
368 | 361 | ) |
369 | 362 |
|
370 | 363 | if self.plot_tag: |
371 | 364 | set_plot_tag_position(self.plot_tag, spaces) |
372 | 365 |
|
373 | | - if self.plot_title: |
374 | | - ha = theme.getp(("plot_title", "ha")) |
375 | | - self.plot_title.set_y(spaces.t.y2("plot_title")) |
376 | | - justify.horizontally_about( |
377 | | - self.plot_title, ha, plot_title_position |
378 | | - ) |
379 | | - |
380 | | - if self.plot_subtitle: |
381 | | - ha = theme.getp(("plot_subtitle", "ha")) |
382 | | - self.plot_subtitle.set_y(spaces.t.y2("plot_subtitle")) |
383 | | - justify.horizontally_about( |
384 | | - self.plot_subtitle, ha, plot_title_position |
385 | | - ) |
386 | | - |
387 | | - if self.plot_caption: |
388 | | - ha = theme.getp(("plot_caption", "ha"), "right") |
389 | | - self.plot_caption.set_y(spaces.b.y1("plot_caption")) |
390 | | - justify.horizontally_about( |
391 | | - self.plot_caption, ha, plot_caption_position |
392 | | - ) |
393 | | - |
394 | | - if self.plot_footer: |
395 | | - ha = theme.getp(("plot_footer", "ha"), "left") |
396 | | - self.plot_footer.set_y(spaces.b.y1("plot_footer")) |
397 | | - justify.horizontally_about( |
398 | | - self.plot_footer, ha, plot_footer_position |
399 | | - ) |
400 | | - if self.plot_footer_background: |
401 | | - resize_footer_background( |
402 | | - self.plot_footer_background, |
403 | | - x=spaces.l.offset, |
404 | | - y=spaces.b.offset, |
405 | | - height=spaces.b.footer_height, |
406 | | - width=spaces.plot_width, |
407 | | - ) |
408 | | - if self.plot_footer_line: |
409 | | - resize_footer_line( |
410 | | - self.plot_footer_line, |
411 | | - x=spaces.l.offset, |
412 | | - width=spaces.plot_width, |
413 | | - y=spaces.b.offset + spaces.b.footer_height, |
414 | | - ) |
415 | | - |
416 | 366 | if self.axis_title_x: |
417 | 367 | ha = theme.getp(("axis_title_x", "ha"), "center") |
418 | 368 | self.axis_title_x.set_y(spaces.b.y1("axis_title_x")) |
@@ -555,6 +505,75 @@ def _text_is_visible(text: Text) -> bool: |
555 | 505 | return text.get_visible() and text._text # type: ignore |
556 | 506 |
|
557 | 507 |
|
| 508 | +def _position_plot_labels( |
| 509 | + figure: Figure, |
| 510 | + theme: theme, |
| 511 | + spaces: PlotSideSpaces | CompositionSideSpaces, |
| 512 | + items: PlotLayoutItems | CompositionLayoutItems, |
| 513 | +) -> TextJustifier: |
| 514 | + """ |
| 515 | + Position title, subtitle, caption, footer, and footer decorations |
| 516 | +
|
| 517 | + Returns the TextJustifier so the caller can reuse it for |
| 518 | + additional positioning (e.g. axis titles). |
| 519 | + """ |
| 520 | + plot_title_position = theme.getp("plot_title_position", "panel") |
| 521 | + plot_caption_position = theme.getp("plot_caption_position", "panel") |
| 522 | + plot_footer_position = theme.getp("plot_footer_position", "plot") |
| 523 | + justify = TextJustifier.from_boundaries( |
| 524 | + figure, |
| 525 | + plot_left=spaces.plot_left, |
| 526 | + plot_right=spaces.plot_right, |
| 527 | + plot_bottom=spaces.plot_bottom, |
| 528 | + plot_top=spaces.plot_top, |
| 529 | + panel_left=spaces.panel_left, |
| 530 | + panel_right=spaces.panel_right, |
| 531 | + panel_bottom=spaces.panel_bottom, |
| 532 | + panel_top=spaces.panel_top, |
| 533 | + ) |
| 534 | + |
| 535 | + if items.plot_title: |
| 536 | + ha = theme.getp(("plot_title", "ha")) |
| 537 | + items.plot_title.set_y(spaces.t.y2("plot_title")) |
| 538 | + justify.horizontally_about(items.plot_title, ha, plot_title_position) |
| 539 | + |
| 540 | + if items.plot_subtitle: |
| 541 | + ha = theme.getp(("plot_subtitle", "ha")) |
| 542 | + items.plot_subtitle.set_y(spaces.t.y2("plot_subtitle")) |
| 543 | + justify.horizontally_about( |
| 544 | + items.plot_subtitle, ha, plot_title_position |
| 545 | + ) |
| 546 | + |
| 547 | + if items.plot_caption: |
| 548 | + ha = theme.getp(("plot_caption", "ha"), "right") |
| 549 | + items.plot_caption.set_y(spaces.b.y1("plot_caption")) |
| 550 | + justify.horizontally_about( |
| 551 | + items.plot_caption, ha, plot_caption_position |
| 552 | + ) |
| 553 | + |
| 554 | + if items.plot_footer: |
| 555 | + ha = theme.getp(("plot_footer", "ha"), "left") |
| 556 | + items.plot_footer.set_y(spaces.b.y1("plot_footer")) |
| 557 | + justify.horizontally_about(items.plot_footer, ha, plot_footer_position) |
| 558 | + if items.plot_footer_background: |
| 559 | + resize_footer_background( |
| 560 | + items.plot_footer_background, |
| 561 | + x=spaces.l.offset, |
| 562 | + y=spaces.b.offset, |
| 563 | + height=spaces.b.footer_height, |
| 564 | + width=spaces.plot_width, |
| 565 | + ) |
| 566 | + if items.plot_footer_line: |
| 567 | + resize_footer_line( |
| 568 | + items.plot_footer_line, |
| 569 | + x=spaces.l.offset, |
| 570 | + width=spaces.plot_width, |
| 571 | + y=spaces.b.offset + spaces.b.footer_height, |
| 572 | + ) |
| 573 | + |
| 574 | + return justify |
| 575 | + |
| 576 | + |
558 | 577 | def set_legends_position(legends: legend_artists, spaces: PlotSideSpaces): |
559 | 578 | """ |
560 | 579 | Place legend on the figure and justify is a required |
|
0 commit comments