|
10 | 10 | if typing.TYPE_CHECKING: |
11 | 11 | from typing import Any |
12 | 12 |
|
| 13 | + from matplotlib.axes import Axes |
13 | 14 | import numpy.typing as npt |
14 | 15 | import pandas as pd |
15 | 16 |
|
16 | | - from plotnine import ggplot |
| 17 | + from plotnine import ggplot, theme |
17 | 18 | from plotnine.iapi import labels_view, panel_view |
18 | 19 | from plotnine.scales.scale import scale |
19 | 20 | from plotnine.typing import ( |
@@ -115,13 +116,50 @@ def draw(self, axs: list) -> None: |
115 | 116 | add elements such as polar grid lines. |
116 | 117 | """ |
117 | 118 |
|
118 | | - def post_setup_ax(self, ax: Any) -> None: |
| 119 | + def setup_ax( |
| 120 | + self, ax: Axes, panel_params: panel_view, theme: theme |
| 121 | + ) -> None: |
119 | 122 | """ |
120 | | - Hook called for each axes after set_limits_breaks_and_labels. |
| 123 | + Set limits, breaks and labels for one panel axes. |
121 | 124 |
|
122 | | - Override in subclasses to apply per-axes settings that must |
123 | | - run after the facet has set tick positions and label padding. |
| 125 | + Subclasses can override this to customize axes setup, or call |
| 126 | + `super().setup_ax(...)` and add coordinate-specific behavior. |
124 | 127 | """ |
| 128 | + from .._mpl.ticker import MyFixedFormatter |
| 129 | + |
| 130 | + def _inf_to_none( |
| 131 | + t: tuple[float, float], |
| 132 | + ) -> tuple[float | None, float | None]: |
| 133 | + """ |
| 134 | + Replace infinities with None |
| 135 | + """ |
| 136 | + a = t[0] if np.isfinite(t[0]) else None |
| 137 | + b = t[1] if np.isfinite(t[1]) else None |
| 138 | + return (a, b) |
| 139 | + |
| 140 | + # limits |
| 141 | + ax.set_xlim(*_inf_to_none(panel_params.x.range)) |
| 142 | + ax.set_ylim(*_inf_to_none(panel_params.y.range)) |
| 143 | + |
| 144 | + # breaks, labels |
| 145 | + ax.set_xticks(panel_params.x.breaks, panel_params.x.labels) |
| 146 | + ax.set_yticks(panel_params.y.breaks, panel_params.y.labels) |
| 147 | + |
| 148 | + # minor breaks |
| 149 | + ax.set_xticks(panel_params.x.minor_breaks, minor=True) |
| 150 | + ax.set_yticks(panel_params.y.minor_breaks, minor=True) |
| 151 | + |
| 152 | + # When you manually set the tick labels MPL changes the locator |
| 153 | + # so that it no longer reports the x & y positions |
| 154 | + # Fixes https://github.com/has2k1/plotnine/issues/187 |
| 155 | + ax.xaxis.set_major_formatter(MyFixedFormatter(panel_params.x.labels)) |
| 156 | + ax.yaxis.set_major_formatter(MyFixedFormatter(panel_params.y.labels)) |
| 157 | + |
| 158 | + pad_x = theme.get_margin("axis_text_x").pt.t |
| 159 | + pad_y = theme.get_margin("axis_text_y").pt.r |
| 160 | + |
| 161 | + ax.tick_params(axis="x", which="major", pad=pad_x) |
| 162 | + ax.tick_params(axis="y", which="major", pad=pad_y) |
125 | 163 |
|
126 | 164 | def labels(self, cur_labels: labels_view) -> labels_view: |
127 | 165 | """ |
|
0 commit comments