Skip to content

Commit

Permalink
artists.create_figure: margins for all sides (#1024)
Browse files Browse the repository at this point in the history
* Update _helpers.py

create_fiigure/subplots_adjust: support for unequal margins

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* cleanup

remove print statements

* documentation

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* artists.plot_margins

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Update _helpers.py

* Update _helpers.py

test CodeQL

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
  • Loading branch information
ddkohler and pre-commit-ci[bot] committed Oct 21, 2021
1 parent 5634ea6 commit 1fb6eb4
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 28 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/).

## [Unreleased]

### Added
- `artists.create_figure`: kwarg `margin` allows unique margins on all sides

### Fixed
- Fixed bug in `wt.artists.interact2D` where constants were not handled properly.

Expand Down
91 changes: 63 additions & 28 deletions WrightTools/artists/_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -253,8 +253,7 @@ def create_figure(
Figures are defined primarily by their width. Height is defined by the
aspect ratios of the subplots contained within. hspace, wspace, and
cbar_width are defined in inches, making it easier to make consistent
plots. Margins are enforced to be equal around the entire plot, starting
from the edges of the subplots.
plots.
Parameters
----------
Expand All @@ -268,10 +267,12 @@ def create_figure(
A list of numbers, defining the number and width-ratios of the
figure columns. May also contain the special string 'cbar', defining
a column as a colorbar-containing column. Default is [1].
margin : float (optional)
Margin in inches. Margin is applied evenly around the figure, starting
from the subplot boundaries (so that ticks and labels appear in the
margin). Default is 1.
margin : float or length 4 list (optional)
Spacing, in inches, between the figure edge and the subplot boundary
(i.e. ticks and labels appear in the margin space). If margin is a
float, uniform spacing is applied to all four sides of the figure. If
margin is a list, unique spacing is applied along each side [top,
right, bottom, left]. Default is 1.
hspace : float (optional)
The 'height space' (space seperating two subplots vertically), in
inches. Default is 0.25.
Expand Down Expand Up @@ -331,12 +332,16 @@ def create_figure(
figure_width = 13.0
else:
figure_width = float(width)
if isinstance(margin, float) or isinstance(margin, int):
mtop, mright, mbottom, mleft = [margin] * 4
else:
mtop, mright, mbottom, mleft = margin
# check if aspect constraints are valid
rows_in_aspects = [item[0][0] for item in aspects]
if not len(rows_in_aspects) == len(set(rows_in_aspects)):
raise Exception("can only specify aspect for one plot in each row")
# get width avalible to subplots (not including colorbars)
total_subplot_width = figure_width - 2 * margin
total_subplot_width = figure_width - mleft - mright
total_subplot_width -= (len(cols) - 1) * wspace # whitespace in width
total_subplot_width -= cols.count("cbar") * cbar_width # colorbar width
# converters
Expand Down Expand Up @@ -376,12 +381,12 @@ def mpl_to_in(mpl, total, n):
height_ratios = subplot_heights
figure_height = sum(subplot_heights)
figure_height += (nrows - 1) * hspace
figure_height += 2 * margin
figure_height += mtop + mbottom
# make figure
fig = plt.figure(figsize=[figure_width, figure_height], FigureClass=Figure)
# get hspace, wspace in relative units
hspace = in_to_mpl(hspace, figure_height - 2 * margin, nrows)
wspace = in_to_mpl(wspace, figure_width - 2 * margin, len(cols))
hspace = in_to_mpl(hspace, figure_height - mtop - mbottom, nrows)
wspace = in_to_mpl(wspace, figure_width - mleft - mright, len(cols))
# make gridpsec
gs = GridSpec(
nrows,
Expand Down Expand Up @@ -721,8 +726,12 @@ def plot_margins(*, fig=None, inches=1.0, centers=True, edges=True):
----------
fig : matplotlib.figure.Figure object (optional)
The figure to plot onto. If None, gets current figure. Default is None.
inches : float (optional)
The size of the figure margin, in inches. Default is 1.
inches : float or length 4 list (optional)
Spacing, in inches, between the figure edge and the subplot boundary
(i.e. ticks and labels appear in the margin space). If margin is a
float, uniform spacing is applied to all four sides of the figure. If
margin is a list, unique spacing is applied along each side [top,
right, bottom, left]. Default is 1 inch margins.
centers : bool (optional)
Toggle for plotting lines indicating the figure center. Default is
True.
Expand All @@ -732,21 +741,28 @@ def plot_margins(*, fig=None, inches=1.0, centers=True, edges=True):
if fig is None:
fig = plt.gcf()
size = fig.get_size_inches() # [H, V]
trans_vert = inches / size[0]
left = matplotlib.lines.Line2D(
[trans_vert, trans_vert], [0, 1], transform=fig.transFigure, figure=fig
)

if isinstance(inches, float):
m_bottom = inches / size[1]
m_top = 1 - m_bottom
m_left = inches / size[0]
m_right = 1 - m_left
else: # isinstance(inches, list):
m_top = 1 - inches[0] / size[1]
m_bottom = inches[2] / size[1]
m_right = 1 - inches[1] / size[0]
m_left = inches[3] / size[0]

left = matplotlib.lines.Line2D([m_left, m_left], [0, 1], transform=fig.transFigure, figure=fig)
right = matplotlib.lines.Line2D(
[1 - trans_vert, 1 - trans_vert], [0, 1], transform=fig.transFigure, figure=fig
[m_right, m_right], [0, 1], transform=fig.transFigure, figure=fig
)
trans_horz = inches / size[1]
bottom = matplotlib.lines.Line2D(
[0, 1], [trans_horz, trans_horz], transform=fig.transFigure, figure=fig
)
top = matplotlib.lines.Line2D(
[0, 1], [1 - trans_horz, 1 - trans_horz], transform=fig.transFigure, figure=fig
[0, 1], [m_bottom, m_bottom], transform=fig.transFigure, figure=fig
)
top = matplotlib.lines.Line2D([0, 1], [m_top, m_top], transform=fig.transFigure, figure=fig)
fig.lines.extend([left, right, bottom, top])

if centers:
vert = matplotlib.lines.Line2D(
[0.5, 0.5], [0, 1], transform=fig.transFigure, figure=fig, c="r"
Expand All @@ -755,6 +771,7 @@ def plot_margins(*, fig=None, inches=1.0, centers=True, edges=True):
[0, 1], [0.5, 0.5], transform=fig.transFigure, figure=fig, c="r"
)
fig.lines.extend([vert, horiz])

if edges:
left = matplotlib.lines.Line2D(
[0, 0], [0, 1], transform=fig.transFigure, figure=fig, c="k"
Expand Down Expand Up @@ -1025,11 +1042,22 @@ def set_fig_labels(


def subplots_adjust(fig=None, inches=1):
"""Enforce margin to be equal around figure, starting at subplots.
"""Enforce margins for generated figure, starting at subplots.
.. note::
You probably should be using wt.artists.create_figure instead.
Parameters
----------
fig : matplotlib.figure.Figure (optional)
figure to adjust. If not specified, current figure (plt.gcf) will be
adjusted.
inches : float or length 4 list (optional)
Spacing, in inches, between the figure edge and the subplot boundary
(i.e. ticks and labels appear in the margin space). If margin is a
float, uniform spacing is applied to all four sides of the figure. If
margin is a list, unique spacing is applied along each side [top,
right, bottom, left]. Default is 1.
See Also
--------
wt.artists.plot_margins
Expand All @@ -1039,10 +1067,17 @@ def subplots_adjust(fig=None, inches=1):
"""
if fig is None:
fig = plt.gcf()
size = fig.get_size_inches()
vert = inches / size[0]
horz = inches / size[1]
fig.subplots_adjust(vert, horz, 1 - vert, 1 - horz)
size = fig.get_size_inches() # [H, V]
if isinstance(inches, float) or isinstance(inches, int):
vert = inches / size[1]
horz = inches / size[0]
fig.subplots_adjust(bottom=vert, left=horz, top=1 - vert, right=1 - horz)
elif isinstance(inches, list):
top = 1 - inches[0] / size[1]
bottom = inches[2] / size[1]
right = 1 - inches[1] / size[0]
left = inches[3] / size[0]
fig.subplots_adjust(top=top, right=right, bottom=bottom, left=left)


def stitch_to_animation(images, outpath=None, *, duration=0.5, palettesize=256, verbose=True):
Expand Down

0 comments on commit 1fb6eb4

Please sign in to comment.