Skip to content

Commit 0097711

Browse files
authored
Merge pull request #16 from CSSFrancis/refactor/project-reorganization
Add axes setters and adjustments
2 parents 0c03764 + 020fb92 commit 0097711

31 files changed

Lines changed: 2568 additions & 262 deletions

anyplotlib/__init__.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
from anyplotlib.figure import Figure, GridSpec, SubplotSpec, subplots
22
from anyplotlib.axes import Axes, InsetAxes
33
from anyplotlib.plot1d import Plot1D, PlotBar
4+
from anyplotlib.plot1d._plot1d import Line1D
45
from anyplotlib.plot2d import Plot2D, PlotMesh
56
from anyplotlib.plot3d import Plot3D
67
from anyplotlib.callbacks import CallbackRegistry, Event
8+
from anyplotlib.markers import MarkerRegistry, MarkerGroup
79
from anyplotlib.widgets import (
810
Widget, RectangleWidget, CircleWidget, AnnularWidget,
911
CrosshairWidget, PolygonWidget, LabelWidget,
@@ -15,12 +17,26 @@
1517
# Default True: badges appear whenever a figure has help text set.
1618
show_help: bool = True
1719

20+
_COLOR_CYCLE: list[str] = [
21+
"#4fc3f7", "#ff7043", "#aed581", "#ffd54f",
22+
"#ba68c8", "#4db6ac", "#f06292", "#90a4ae",
23+
"#ffb74d", "#a5d6a7",
24+
]
25+
26+
27+
def get_color_cycle() -> list[str]:
28+
"""Return the default color cycle as a list of CSS hex strings."""
29+
return list(_COLOR_CYCLE)
30+
31+
1832
__all__ = [
1933
"Figure", "GridSpec", "SubplotSpec", "subplots",
2034
"Axes", "InsetAxes", "Plot1D", "Plot2D", "PlotMesh", "Plot3D", "PlotBar",
35+
"Line1D",
2136
"CallbackRegistry", "Event",
37+
"MarkerRegistry", "MarkerGroup",
2238
"Widget", "RectangleWidget", "CircleWidget", "AnnularWidget",
2339
"CrosshairWidget", "PolygonWidget", "LabelWidget",
2440
"VLineWidget", "HLineWidget", "RangeWidget",
25-
"show_help",
41+
"show_help", "get_color_cycle",
2642
]

anyplotlib/_utils.py

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,16 @@
99
import numpy as np
1010

1111
_LINESTYLE_ALIASES: dict[str, str] = {
12-
"-": "solid",
13-
"--": "dashed",
14-
":": "dotted",
15-
"-.": "dashdot",
16-
"solid": "solid",
17-
"dashed": "dashed",
18-
"dotted": "dotted",
19-
"dashdot": "dashdot",
12+
"-": "solid",
13+
"--": "dashed",
14+
":": "dotted",
15+
"-.": "dashdot",
16+
"solid": "solid",
17+
"dashed": "dashed",
18+
"dotted": "dotted",
19+
"dashdot": "dashdot",
20+
"step-mid": "step-mid",
21+
"steps-mid": "step-mid",
2022
}
2123

2224

@@ -49,7 +51,7 @@ def _norm_linestyle(ls: str) -> str:
4951
if canonical is None:
5052
raise ValueError(
5153
f"Unknown linestyle {ls!r}. Expected one of: "
52-
"'solid', 'dashed', 'dotted', 'dashdot', "
54+
"'solid', 'dashed', 'dotted', 'dashdot', 'step-mid' (alias: 'steps-mid') "
5355
"or shorthands '-', '--', ':', '-.'."
5456
)
5557
return canonical

anyplotlib/axes/_axes.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,8 @@ def plot(self, data: np.ndarray,
192192
alpha: float = 1.0,
193193
marker: str = "none",
194194
markersize: float = 4.0,
195-
label: str = "") -> "Plot1D":
195+
label: str = "",
196+
yscale: str = "linear") -> "Plot1D":
196197
"""Attach a 1-D line to this axes cell.
197198
198199
Parameters
@@ -265,10 +266,16 @@ def plot(self, data: np.ndarray,
265266
color=color, linewidth=linewidth,
266267
linestyle=ls if ls is not None else linestyle,
267268
alpha=alpha, marker=marker, markersize=markersize,
268-
label=label)
269+
label=label, yscale=yscale)
269270
self._attach(plot)
270271
return plot
271272

273+
def semilogy(self, data: np.ndarray,
274+
axes: list | None = None, **kwargs) -> "Plot1D":
275+
"""Attach a 1-D line with a logarithmic y-axis."""
276+
kwargs.setdefault("yscale", "log")
277+
return self.plot(data, axes=axes, **kwargs)
278+
272279
def bar(self, x, height=None, width: float = 0.8, bottom: float = 0.0, *,
273280
align: str = "center",
274281
color: str = "#4fc3f7",

anyplotlib/callbacks.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
VALID_EVENT_TYPES = frozenset({
2525
"pointer_down", "pointer_up", "pointer_move", "pointer_settled",
2626
"pointer_enter", "pointer_leave", "double_click", "wheel",
27-
"key_down", "key_up", "*",
27+
"key_down", "key_up", "close", "*",
2828
})
2929

3030

anyplotlib/figure/_figure.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@ def __init__(self, nrows=1, ncols=1, figsize=(640, 480),
114114
self._axes_map: dict = {}
115115
self._plots_map: dict = {}
116116
self._insets_map: dict = {}
117+
self._hspace: float | None = None
118+
self._wspace: float | None = None
117119
with self.hold_trait_notifications():
118120
self.fig_width = figsize[0]
119121
self.fig_height = figsize[1]
@@ -149,6 +151,29 @@ def set_help(self, text: str) -> None:
149151
"""
150152
self.help_text = self._resolve_help(text)
151153

154+
def subplots_adjust(self, hspace: float | None = None,
155+
wspace: float | None = None) -> None:
156+
"""Set the spacing between subplot panels.
157+
158+
Only the arguments that are explicitly provided are updated; omitting
159+
an argument leaves the current value unchanged.
160+
161+
Parameters
162+
----------
163+
hspace : float, optional
164+
Fraction of the average row height to use as vertical gap between
165+
panels. ``0.1`` adds a gap of 10 % of the mean row height.
166+
``None`` (default) leaves the current hspace unchanged.
167+
wspace : float, optional
168+
Fraction of the average column width to use as horizontal gap.
169+
``None`` (default) leaves the current wspace unchanged.
170+
"""
171+
if hspace is not None:
172+
self._hspace = float(hspace)
173+
if wspace is not None:
174+
self._wspace = float(wspace)
175+
self._push_layout()
176+
152177
# ── subplot creation ──────────────────────────────────────────────────────
153178
def add_subplot(self, spec) -> Axes:
154179
"""Add a subplot cell and return its :class:`Axes`.
@@ -303,6 +328,8 @@ def _mg(flag, key):
303328
"panel_specs": panel_specs,
304329
"share_groups": share_groups,
305330
"inset_specs": inset_specs,
331+
"hspace": self._hspace,
332+
"wspace": self._wspace,
306333
})
307334

308335
# ── inset creation ────────────────────────────────────────────────────────
@@ -464,6 +491,25 @@ def _repr_html_(self) -> str:
464491
"""
465492
return repr_html_iframe(self)
466493

494+
def close(self) -> None:
495+
"""Close the figure.
496+
497+
Fires a ``"close"`` event on every panel's :attr:`callbacks`, then
498+
hides the widget by setting its CSS ``display`` to ``"none"``.
499+
Subsequent calls are no-ops.
500+
"""
501+
if getattr(self, "_closed", False):
502+
return
503+
self._closed = True
504+
close_event = Event(event_type="close")
505+
for plot in self._plots_map.values():
506+
if hasattr(plot, "callbacks"):
507+
plot.callbacks.fire(close_event)
508+
try:
509+
self.layout.display = "none"
510+
except Exception:
511+
pass
512+
467513
def __repr__(self) -> str:
468514
return (f"Figure({self._nrows}x{self._ncols}, "
469515
f"panels={len(self._plots_map)}, "

0 commit comments

Comments
 (0)