diff --git a/docs/source/conf.py b/docs/source/conf.py index 47d0322..d89ebd2 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -55,6 +55,7 @@ 'legend.borderaxespad': 0.5, 'legend.columnspacing': 1.0 } +plot_apply_rcparams = True plot_pre_code = """ import numpy as np from matplotlib import pyplot as plt diff --git a/docs/source/cover.py b/docs/source/cover.py index 770e926..5f832a2 100644 --- a/docs/source/cover.py +++ b/docs/source/cover.py @@ -1,8 +1,9 @@ import matplotlib as mpl import matplotlib.pyplot as plt +import numpy as np from matplotlib.colors import Normalize -from legendkit import legend, cat_legend, colorbar, colorart, hstack, vstack +from legendkit import legend, cat_legend, colorbar, colorart, hstack, vstack, size_legend mpl.rcParams['legend.handleheight'] = 1 mpl.rcParams['legend.handlelength'] = 1 @@ -83,9 +84,10 @@ colors=["#A7D2CB", "#F2D388", "#A7D2CB", "#F2D388"], labels=["Item 1", "Item 2", "Item 3", "Item 4"], ) -legend = cat_legend(**args, title="Legend", handle="circle") +legend1 = cat_legend(**args, title="Category", handle="circle") +legend2 = size_legend(sizes=np.arange(1, 401), title="Size", handle="circle") cart = colorart(norm=norm, cmap="cool", ax=ax, title="Colorart") -hstack([legend, cart], spacing=20, title="Stack colorbar and legend", +hstack([legend1, legend2, cart], spacing=20, title="Stack colorbar and legend", alignment="left", loc="upper left", bbox_to_anchor=(1, 1), bbox_transform=ax.transAxes, frameon=True, ax=ax, padding=2) diff --git a/legendkit/__init__.py b/legendkit/__init__.py index dabcb58..296db61 100644 --- a/legendkit/__init__.py +++ b/legendkit/__init__.py @@ -1,9 +1,9 @@ """Legend creation and manipulation with ease for matplotlib""" -__version__ = "0.3.3" +__version__ = "0.3.4" -from ._colorbar import Colorbar from ._colorart import ColorArt +from ._colorbar import Colorbar from ._legend import ListLegend, CatLegend, SizeLegend # To register default setting and legend handlers from ._register import register diff --git a/legendkit/_colorart.py b/legendkit/_colorart.py index c4ec6a1..c7eef6e 100644 --- a/legendkit/_colorart.py +++ b/legendkit/_colorart.py @@ -159,10 +159,10 @@ def __init__(self, self.is_axes = True if not isinstance(ax, Axes): self.is_axes = False - self.set_figure(ax) + self.figure = ax else: - self.set_figure(ax.figure) + self.figure = ax.figure self.axes = ax if rasterized: # Force rasterization @@ -271,7 +271,6 @@ def __init__(self, Locs().transform(ax, loc, bbox_to_anchor=bbox_to_anchor, bbox_transform=bbox_transform, deviation=deviation) - print(self._bbox_to_anchor) self.textpad = mpl.rcParams[ 'legend.handletextpad'] if textpad is None else textpad @@ -281,6 +280,7 @@ def __init__(self, 'legend.borderaxespad'] if borderaxespad is None else borderaxespad # the container for title, colorbar, ticks and tick labels + self._final_pack = None self._cbar_box = None self._process_values() self._get_locator_formatter() @@ -321,7 +321,8 @@ def _make_cbar_box(self): # Add cbar canvas = DrawingArea(da_width, da_height, clip=False) # self._add_color_patches(self._cbar_canvas) - canvas.set_figure(self.figure) + # canvas.set_figure(self.figure) + canvas.figure = self.figure cmap_caller = get_colormap(self.cmap) colors_list = cmap_caller(np.arange(cmap_caller.N)) @@ -334,10 +335,10 @@ def _make_cbar_box(self): if self.orientation == "vertical": for i, (y1, y2) in enumerate(zip(locs, locs[1::])): rects.append(Rectangle((0, y1), width=self.width, - height=y2-y1, fc=colors_list[i])) + height=y2 - y1, fc=colors_list[i])) else: for i, (x1, x2) in enumerate(zip(locs, locs[1::])): - rects.append(Rectangle((x1, 0), width=x2-x1, + rects.append(Rectangle((x1, 0), width=x2 - x1, height=self.height, fc=colors_list[i])) else: @@ -405,10 +406,12 @@ def _make_cbar_box(self): children=[title_canvas, canvas], align=self.alignment ) - title_pack.set_figure(self.figure) + # title_pack.set_figure(self.figure) + title_pack.figure = self.figure final_pack = title_pack else: final_pack = canvas + self._final_pack = final_pack self._cbar_box = AnchoredOffsetbox( self._loc, child=final_pack, pad=self.borderpad, @@ -416,12 +419,22 @@ def _make_cbar_box(self): bbox_transform=self._bbox_transform, bbox_to_anchor=self._bbox_to_anchor, frameon=False) - self._cbar_box.set_figure(self.figure) + # self._cbar_box.set_figure(self.figure) + self._cbar_box.figure = self.figure if self.is_axes: self.axes.add_artist(self._cbar_box) else: self.figure.add_artist(self._cbar_box) + def get_bbox(self, renderer=None): + return self._final_pack.get_bbox(renderer=renderer) + + def get_window_extent(self, renderer=None): + return self._final_pack.get_window_extent(renderer=renderer) + + def set_offset(self, offset): + self._final_pack.set_offset(offset) + def _get_text_size(self, ticklabels): """Used to get the proper size for drawing area""" renderer = self.figure.canvas.get_renderer() diff --git a/legendkit/_colorbar.py b/legendkit/_colorbar.py index ce11ce2..4366ca5 100644 --- a/legendkit/_colorbar.py +++ b/legendkit/_colorbar.py @@ -205,4 +205,4 @@ def get_corner(self): xlims = np.sort(self.ax.get_xlim()) ylims = np.sort(self.ax.get_ylim()) return (xlims[0], ylims[0]), (xlims[0], ylims[1]), \ - (xlims[1], ylims[1]), (xlims[1], ylims[0]) + (xlims[1], ylims[1]), (xlims[1], ylims[0]) diff --git a/legendkit/_legend.py b/legendkit/_legend.py index a2f7dcd..046e8fb 100644 --- a/legendkit/_legend.py +++ b/legendkit/_legend.py @@ -5,15 +5,15 @@ import numpy as np from matplotlib import _api from matplotlib.axes import Axes -from matplotlib.collections import Collection, PatchCollection -from matplotlib.colors import is_color_like, Normalize +from matplotlib.collections import Collection +from matplotlib.colors import is_color_like from matplotlib.figure import FigureBase from matplotlib.font_manager import FontProperties from matplotlib.legend import Legend from matplotlib.lines import Line2D from matplotlib.markers import MarkerStyle from matplotlib.offsetbox import VPacker, HPacker -from matplotlib.patches import Patch, Rectangle +from matplotlib.patches import Patch from ._handlers import CircleHandler, RectHandler, BoxplotHanlder from ._locs import Locs @@ -210,14 +210,20 @@ def __init__(self, title_loc=title_loc) self._has_parent = ax is not None self._is_axes = isinstance(ax, Axes) + parent = None if ax is None: - axes = plt.gca() + parent = plt.gca() + axes = [parent] + self._is_axes = True else: if not self._is_axes: fig = ax axes = fig.get_axes() + parent = fig else: axes = [ax] + parent = ax + self._title_loc = title_loc self.titlepad = titlepad self._is_patch = False @@ -281,7 +287,7 @@ def val_or_rc(val, rc_name): loc = "center right" else: loc, bbox_to_anchor, bbox_transform = \ - Locs().transform(ax, loc, bbox_to_anchor=bbox_to_anchor, + Locs().transform(parent, loc, bbox_to_anchor=bbox_to_anchor, bbox_transform=bbox_transform, deviation=deviation) if handler_map is None: @@ -304,7 +310,7 @@ def val_or_rc(val, rc_name): ) final_options = {**default_kwargs, **kwargs} - super().__init__(ax, + super().__init__(parent, handles=legend_handles, labels=legend_labels, **final_options) @@ -317,13 +323,14 @@ def val_or_rc(val, rc_name): # Attach as legend element # 1. ax.get_legend() will work # 2. legend won't be clipped - if isinstance(ax, Axes): + if self._is_axes: + ax = axes[0] if ax.legend_ is None: ax.legend_ = self else: ax.add_artist(self) else: - ax.legends.append(self) + fig.legends.append(self) def _parse_handler(self, handle, handle_size, config=None): if not isinstance(handle, str): @@ -386,7 +393,7 @@ def _title_layout(self): self._legend_box = packer(pad=pad, sep=sep, align=alignment, children=children) - self._legend_box.set_figure(self.figure) + self._legend_box.figure = self.figure self._legend_box.axes = self.axes # call this to maintain consistent behavior as legend diff --git a/legendkit/handles.py b/legendkit/handles.py index ce682ca..285de47 100644 --- a/legendkit/handles.py +++ b/legendkit/handles.py @@ -19,9 +19,9 @@ """ from abc import ABC +from matplotlib.collections import Collection from matplotlib.lines import Line2D from matplotlib.patches import Patch -from matplotlib.collections import Collection class SquareItem(Patch, ABC): @@ -48,6 +48,7 @@ def __init__(self, *args, **kwargs): class BoxplotItem(Collection, ABC): """Create boxplot for legend handles""" + def __init__(self, *args, **kwargs): user_ec = kwargs.get('ec') user_edgecolor = kwargs.get('edgecolor') diff --git a/legendkit/layout.py b/legendkit/layout.py index 13f68bc..83664f9 100644 --- a/legendkit/layout.py +++ b/legendkit/layout.py @@ -1,5 +1,5 @@ from functools import partial -from typing import List, Optional, Dict +from typing import List, Dict from matplotlib.artist import Artist from matplotlib.legend import Legend diff --git a/pyproject.toml b/pyproject.toml index ec4c49d..af25bde 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,4 +35,5 @@ dev = [ "numpydoc", "sphinx_gallery", "furo", + "mpl_fontkit" ] \ No newline at end of file