From 14bad633f08215156506a57fb5adbad45e8f0d67 Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Tue, 5 Oct 2021 17:03:23 +0200 Subject: [PATCH] Demonstrate inset_axes in scatter_hist example. Currently, the scatter_hist example needs to force the main axes to be square by carefully adjusting the figure size -- shared axes and fixed aspects don't work well together (and manually resizing the figure shows that the aspect is indeed not fixed). In fact, the scatter_hist_locatable_axes example explicitly states that the advantage of using axes_grid1 is to allow the aspect to be fixed. I realized that one can also use inset_axes to position the marginals axes relative to the main axes *and* support a fixed aspect ratio for the main axes. Perhaps this can be considered as a slight API abuse, but I think this is a solution for a real limitation; the question is whether we want to promote this use? --- .../axes_grid1/scatter_hist_locatable_axes.py | 12 +-- .../lines_bars_and_markers/scatter_hist.py | 99 +++++++++---------- 2 files changed, 54 insertions(+), 57 deletions(-) diff --git a/examples/axes_grid1/scatter_hist_locatable_axes.py b/examples/axes_grid1/scatter_hist_locatable_axes.py index 8d2ee72b9c6b..c605e9e81258 100644 --- a/examples/axes_grid1/scatter_hist_locatable_axes.py +++ b/examples/axes_grid1/scatter_hist_locatable_axes.py @@ -3,16 +3,16 @@ Scatter Histogram (Locatable Axes) ================================== -Show the marginal distributions of a scatter as histograms at the sides of +Show the marginal distributions of a scatter plot as histograms at the sides of the plot. For a nice alignment of the main axes with the marginals, the axes positions -are defined by a ``Divider``, produced via `.make_axes_locatable`. +are defined by a ``Divider``, produced via `.make_axes_locatable`. Note that +the ``Divider`` API allows setting axes sizes and pads in inches, which is its +main feature. -An alternative method to produce a similar figure is shown in the -:doc:`/gallery/lines_bars_and_markers/scatter_hist` example. The advantage of -the locatable axes method shown below is that the marginal axes follow the -fixed aspect ratio of the main axes. +If one wants to set axes sizes and pads relative to the main Figure, see the +:doc:`/gallery/lines_bars_and_markers/scatter_hist` example. """ import numpy as np diff --git a/examples/lines_bars_and_markers/scatter_hist.py b/examples/lines_bars_and_markers/scatter_hist.py index 1ad5d8ac1c8b..1e18932a76db 100644 --- a/examples/lines_bars_and_markers/scatter_hist.py +++ b/examples/lines_bars_and_markers/scatter_hist.py @@ -3,18 +3,22 @@ Scatter plot with histograms ============================ -Show the marginal distributions of a scatter as histograms at the sides of +Show the marginal distributions of a scatter plot as histograms at the sides of the plot. For a nice alignment of the main axes with the marginals, two options are shown -below. +below: -* the axes positions are defined in terms of rectangles in figure coordinates -* the axes positions are defined via a gridspec +.. contents:: + :local: + +While `.Axes.inset_axes` may be a bit more complex, it allows correct handling +of main axes with a fixed aspect ratio. An alternative method to produce a similar figure using the ``axes_grid1`` -toolkit is shown in the -:doc:`/gallery/axes_grid1/scatter_hist_locatable_axes` example. +toolkit is shown in the :doc:`/gallery/axes_grid1/scatter_hist_locatable_axes` +example. Finally, it is also possible to position all axes in absolute +coordinates using `.Figure.add_axes` (not shown here). Let us first define a function that takes x and y data as input, as well as three axes, the main axes for the scatter, and two marginal axes. It will @@ -52,60 +56,53 @@ def scatter_hist(x, y, ax, ax_histx, ax_histy): ############################################################################# # -# Axes in figure coordinates -# -------------------------- -# -# To define the axes positions, `.Figure.add_axes` is provided with a rectangle -# ``[left, bottom, width, height]`` in figure coordinates. The marginal axes -# share one dimension with the main axes. - -# definitions for the axes -left, width = 0.1, 0.65 -bottom, height = 0.1, 0.65 -spacing = 0.005 - - -rect_scatter = [left, bottom, width, height] -rect_histx = [left, bottom + height + spacing, width, 0.2] -rect_histy = [left + width + spacing, bottom, 0.2, height] - -# start with a square Figure -fig = plt.figure(figsize=(8, 8)) - -ax = fig.add_axes(rect_scatter) -ax_histx = fig.add_axes(rect_histx, sharex=ax) -ax_histy = fig.add_axes(rect_histy, sharey=ax) - -# use the previously defined function -scatter_hist(x, y, ax, ax_histx, ax_histy) - -plt.show() - - -############################################################################# -# -# Using a gridspec -# ---------------- +# Defining the axes positions using a gridspec +# -------------------------------------------- # -# We may equally define a gridspec with unequal width- and height-ratios to -# achieve desired layout. Also see the :doc:`/tutorials/intermediate/gridspec` -# tutorial. - -# start with a square Figure -fig = plt.figure(figsize=(8, 8)) +# We define a gridspec with unequal width- and height-ratios to achieve desired +# layout. Also see the :doc:`/tutorials/intermediate/gridspec` tutorial. -# Add a gridspec with two rows and two columns and a ratio of 2 to 7 between +# Start with a square Figure. +fig = plt.figure(figsize=(6, 6)) +# Add a gridspec with two rows and two columns and a ratio of 1 to 4 between # the size of the marginal axes and the main axes in both directions. # Also adjust the subplot parameters for a square plot. -gs = fig.add_gridspec(2, 2, width_ratios=(7, 2), height_ratios=(2, 7), +gs = fig.add_gridspec(2, 2, width_ratios=(4, 1), height_ratios=(1, 4), left=0.1, right=0.9, bottom=0.1, top=0.9, wspace=0.05, hspace=0.05) - +# Create the Axes. ax = fig.add_subplot(gs[1, 0]) ax_histx = fig.add_subplot(gs[0, 0], sharex=ax) ax_histy = fig.add_subplot(gs[1, 1], sharey=ax) +# Draw the scatter plot and marginals. +scatter_hist(x, y, ax, ax_histx, ax_histy) + -# use the previously defined function +############################################################################# +# +# Defining the axes positions using inset_axes +# -------------------------------------------- +# +# `~.Axes.inset_axes` can be used to position marginals *outside* the main +# axes. The advantage of doing so is that the aspect ratio of the main axes +# can be fixed, and the marginals will always be drawn relative to the position +# of the axes. + +# Create a Figure, which doesn't have to be square. +fig = plt.figure(constrained_layout=True) +# Create the main axes, leaving 25% of the figure space at the top and on the +# right to position marginals. +ax = fig.add_gridspec(top=0.75, right=0.75).subplots() +# The main axes' aspect can be fixed. +ax.set(aspect=1) +# Create marginal axes, which have 25% of the size of the main axes. Note that +# the inset axes are positioned *outside* (on the right and the top) of the +# main axes, by specifying axes coordinates greater than 1. Axes coordinates +# less than 0 would likewise specify positions on the left and the bottom of +# the main axes. +ax_histx = ax.inset_axes([0, 1.05, 1, 0.25], sharex=ax) +ax_histy = ax.inset_axes([1.05, 0, 0.25, 1], sharey=ax) +# Draw the scatter plot and marginals. scatter_hist(x, y, ax, ax_histx, ax_histy) plt.show() @@ -118,8 +115,8 @@ def scatter_hist(x, y, ax, ax_histx, ax_histy): # The use of the following functions, methods, classes and modules is shown # in this example: # -# - `matplotlib.figure.Figure.add_axes` # - `matplotlib.figure.Figure.add_subplot` # - `matplotlib.figure.Figure.add_gridspec` +# - `matplotlib.axes.Axes.inset_axes` # - `matplotlib.axes.Axes.scatter` # - `matplotlib.axes.Axes.hist`