Example #1
0
class MatPlot(Atom):
    """
    Overall class for matplotlib figure. can have several child axes instances.

    allow slider and next/prev buttons, interactive fitting?
    """

    fig = Typed(Figure)
    _axes = Instance(subplot_class_factory(), np.ndarray)
    axes = Instance(AtomAxes, np.ndarray)

    def __init__(self,
                 nrows=1,
                 ncols=1,
                 sharex=False,
                 sharey=False,
                 squeeze=True,
                 subplot_kw=None,
                 gridspec_kw=None,
                 **fig_kw):
        super(MatPlot, self).__init__()

        self.fig, self._axes = plt.subplots(nrows=1,
                                            ncols=1,
                                            sharex=sharex,
                                            sharey=sharey,
                                            squeeze=squeeze,
                                            subplot_kw=subplot_kw,
                                            gridspec_kw=gridspec_kw,
                                            **fig_kw)

        if isinstance(self._axes, np.ndarray):
            self.axes = np.array([AtomAxes(self, ax)
                                  for ax in self._axes]).reshape(nrows, ncols)
        else:
            self.axes = AtomAxes(self, self._axes)

    def __iadd__(self, other):
        if isinstance(self.axes, AtomAxes):
            self.axes.add_dataobject(other)
        else:
            raise ValueError(
                'Please add the DataObject to the appropriate axes')
        return self

    def __isub__(self, other):
        if isinstance(self.axes, AtomAxes):
            self.axes.remove_dataobject(other)
        else:
            raise ValueError(
                'Please add the DataObject to the appropriate axes')

    @staticmethod
    def show(*args, **kwargs):
        plt.show(*args, **kwargs)

    @staticmethod
    def savefig(*args, **kwargs):
        plt.savefig(*args, **kwargs)
Example #2
0
    def add_subplot(self, *args, **kwargs):

        cycler = kwargs.pop('cycler', None)

        if 'figure' in kwargs:
            # Axes itself allows for a 'figure' kwarg, but since we want to
            # bind the created Axes to self, it is not allowed here.
            raise TypeError(
                "add_subplot() got an unexpected keyword argument 'figure'")

        if len(args) == 1 and isinstance(args[0], SubplotBase):
            ax = args[0]
            key = ax._projection_init
            if ax.get_figure() is not self:
                raise ValueError("The Subplot must have been created in "
                                 "the present figure")
        else:
            if not args:
                args = (1, 1, 1)
            # Normalize correct ijk values to (i, j, k) here so that
            # add_subplot(211) == add_subplot(2, 1, 1).  Invalid values will
            # trigger errors later (via SubplotSpec._from_subplot_args).
            if (len(args) == 1 and isinstance(args[0], Integral)
                    and 100 <= args[0] <= 999):
                args = tuple(map(int, str(args[0])))
            projection_class, pkw = self._process_projection_requirements(
                *args, **kwargs)

            # ESS override class to use ours
            # ax = subplot_class_factory(projection_class)(self, *args, **pkw)
            ax = subplot_class_factory(HickoryAxes)(
                self,
                *args,
                cycler=cycler,
                **pkw,
            )

            key = (projection_class, pkw)
        return self._add_axes_internal(ax, key)
Example #3
0
def host_subplot_class_factory(axes_class):
    host_axes_class = host_axes_class_factory(axes_class=axes_class)
    subplot_host_class = subplot_class_factory(host_axes_class)
    return subplot_host_class
Example #4
0
    def get_tightbbox(self, renderer):

        if not self.get_visible():
            return

        bb = [b for b in self._bboxes if b and (b.width != 0 or b.height != 0)]

        if bb:
            _bbox = Bbox.union(bb)
            return _bbox
        else:
            return self.get_window_extent(renderer)

    def grid(self, draw_grid=True, **kwargs):
        """
        Plot gridlines for both coordinates.

        Standard matplotlib appearance options (color, alpha, etc.) can be
        passed as keyword arguments.

        Parameters
        ----------
        draw_grid : bool
            Whether to show the gridlines
        """
        if draw_grid:
            self.coords.grid(draw_grid=draw_grid, **kwargs)


WCSAxesSubplot = subplot_class_factory(WCSAxes)
        maxes.Axes.__init__(self, *kl, **kw)

    def draw(self, renderer):
        usetex = plt.rcParams["text.usetex"]
        preview = plt.rcParams["text.latex.preview"]
        plt.rcParams["text.usetex"] = self.usetex
        plt.rcParams["text.latex.preview"] = self.preview

        maxes.Axes.draw(self, renderer)

        plt.rcParams["text.usetex"] = usetex
        plt.rcParams["text.latex.preview"] = preview


subplot = maxes.subplot_class_factory(Axes)


def test_window_extent(ax, usetex, preview):

    va = "baseline"
    ax.xaxis.set_visible(False)
    ax.yaxis.set_visible(False)

    text_kw = dict(va=va,
                   size=50,
                   bbox=dict(pad=0., ec="k", fc="none"))

    test_strings = ["lg", r"$\frac{1}{2}\pi$",
                    r"$p^{3^A}$", r"$p_{3_2}$"]
Example #6
0
    def _get_base_axes(self):
        return axes_class

    return type("%sHostAxes" % axes_class.__name__,
                (HostAxesBase, axes_class),
                {'_get_base_axes': _get_base_axes})


def host_subplot_class_factory(axes_class):
    host_axes_class = host_axes_class_factory(axes_class=axes_class)
    subplot_host_class = subplot_class_factory(host_axes_class)
    return subplot_host_class


HostAxes = host_axes_class_factory(axes_class=Axes)
SubplotHost = subplot_class_factory(HostAxes)


def host_axes(*args, axes_class=None, figure=None, **kwargs):
    """
    Create axes that can act as a hosts to parasitic axes.

    Parameters
    ----------
    figure : `matplotlib.figure.Figure`
        Figure to which the axes will be added. Defaults to the current figure
        `pyplot.gcf()`.

    *args, **kwargs
        Will be passed on to the underlying ``Axes`` object creation.
    """
Example #7
0
           Geophysical Research, Vol. 64, No. 11, pp. 1891--1909.
        """
        lon, lat, totals, kwargs = self._contour_helper(args, kwargs)
        return self.contourf(lon, lat, totals, **kwargs)


class EqualAngleAxes(StereonetAxes):
    """An axes representing a lower-hemisphere "Wulff" (a.k.a. equal angle)
    projection."""
    _base_transform = stereonet_transforms.StereographicTransform
    _scale = 2.0
    name = 'equal_angle_stereonet'


class EqualAreaAxes(StereonetAxes):
    """An axes representing a lower-hemisphere "Schmitt" (a.k.a. equal area)
    projection."""
    name = 'equal_area_stereonet'


# We need to define explict subplot classes so that we don't mess up the
# method resolution order when using matplotlib subplots.
EqualAngleAxesSubplot = subplot_class_factory(EqualAngleAxes)
EqualAngleAxesSubplot.__module__ = EqualAngleAxes.__module__
EqualAreaAxesSubplot = subplot_class_factory(EqualAngleAxes)
EqualAreaAxesSubplot.__module__ = EqualAngleAxes.__module__

register_projection(StereonetAxes)
register_projection(EqualAreaAxes)
register_projection(EqualAngleAxes)
Example #8
0
            axis_direction=None,
            offset=offset,
            axes=self,
        )
        return axis

    def new_floating_axis(self, nth_coord, value, axis_direction="bottom"):
        gh = self.get_grid_helper()
        axis = gh.new_floating_axis(nth_coord,
                                    value,
                                    axis_direction=axis_direction,
                                    axes=self)
        return axis


Subplot = maxes.subplot_class_factory(Axes)


class AxesZero(Axes):
    def _init_axis_artists(self):
        super()._init_axis_artists()

        new_floating_axis = self._grid_helper.new_floating_axis
        xaxis_zero = new_floating_axis(nth_coord=0,
                                       value=0.,
                                       axis_direction="bottom",
                                       axes=self)

        xaxis_zero.line.set_clip_path(self.patch)
        xaxis_zero.set_visible(False)
        self._axislines["xzero"] = xaxis_zero
Example #9
0
        self.patch.set_clip_path(patch)
        self.gridlines.set_clip_path(patch)

        self._original_patch = patch

    def adjust_axes_lim(self):
        grid_helper = self.get_grid_helper()
        t = grid_helper.get_boundary()
        x, y = t[:, 0], t[:, 1]

        xmin, xmax = min(x), max(x)
        ymin, ymax = min(y), max(y)

        dx = (xmax - xmin) / 100
        dy = (ymax - ymin) / 100

        self.set_xlim(xmin - dx, xmax + dx)
        self.set_ylim(ymin - dy, ymax + dy)


@functools.lru_cache(None)
def floatingaxes_class_factory(axes_class):
    return type("Floating %s" % axes_class.__name__,
                (FloatingAxesBase, axes_class),
                {'_axes_class_floating': axes_class})


FloatingAxes = floatingaxes_class_factory(
    host_axes_class_factory(axislines.Axes))
FloatingSubplot = maxes.subplot_class_factory(FloatingAxes)
Example #10
0
    if id != None:
        param = []
        for j in range(len(params)):
            param.append([p[id] for p in params[j]])
        params = param[:]

    # at this point, we should have:
    #bounds = [(60,105),(0,30),(2.1,2.8)] or [(None,None),(None,None),(None,None)]
    #xyz = [(0,1),(4,5),(8,9)] for any length tuple
    #select = ['-1:'] or [':'] or [':1','1:2','2:3','3:'] or similar
    #id = 0 or None

    from mpl_toolkits.mplot3d import Axes3D
    import matplotlib.pyplot as plt
    from matplotlib.axes import subplot_class_factory
    Subplot3D = subplot_class_factory(Axes3D)

    plots = len(select)
    if not flatten:
        dim1, dim2 = best_dimensions(plots)
    else:
        dim1, dim2 = 1, 1

    # use the default bounds where not specified
    bounds = [list(i) for i in bounds]
    for i in range(len(bounds)):
        if bounds[i][0] is None: bounds[i][0] = 0
        if bounds[i][1] is None: bounds[i][1] = 1

    # correctly bound the first plot.  there must be at least one plot
    fig = plt.figure()
Example #11
0
class WCSAxesSubplot(subplot_class_factory(WCSAxes)):
    pass
Example #12
0
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.axes import Axes, SubplotBase
from matplotlib.axes import subplot_class_factory

fig, axes = plt.subplots()

fake_cls = subplot_class_factory()
print(type(fake_cls))
print(fake_cls)

#
# print(type(fig))
# print(type(axes))
#
# print('super")')
# print(super(axes))
# print(Axes.mro())
# #print(axes.__bases__())
# print(axes.mro())
# print(type(Axes) in Axes.mro())
Example #13
0
    def add_subplot(self, *args, **kwargs):
        """Add a subplot to the figure.

        Parameters
        ----------
        *args
        **kwargs

        Returns
        -------
        WrightTools.artists.Axes object
        """
        # this method is largely copied from upstream
        # --- Blaise 2018-02-24
        #
        # projection
        if 'projection' not in kwargs.keys():
            projection = 'wright'
        else:
            projection = kwargs['projection']
        # must be arguments
        if not len(args):
            return
        # int args must be correct
        if len(args) == 1 and isinstance(args[0], int):
            args = tuple([int(c) for c in str(args[0])])
            if len(args) != 3:
                raise ValueError("Integer subplot specification must " +
                                 "be a three digit number.  " +
                                 "Not {n:d}".format(n=len(args)))
        # subplotbase args
        if isinstance(args[0], SubplotBase):
            a = args[0]
            if a.get_figure() is not self:
                msg = ("The Subplot must have been created in the present"
                       " figure")
                raise ValueError(msg)
            # make a key for the subplot (which includes the axes object id
            # in the hash)
            key = self._make_key(*args, **kwargs)
        else:
            projection_class, kwargs, key = matplotlib.figure.process_projection_requirements(
                self, *args, **kwargs)
            # try to find the axes with this key in the stack
            ax = self._axstack.get(key)
            if ax is not None:
                if isinstance(ax, projection_class):
                    # the axes already existed, so set it as active & return
                    self.sca(ax)
                    return ax
                else:
                    # Undocumented convenience behavior:
                    # subplot(111); subplot(111, projection='polar')
                    # will replace the first with the second.
                    # Without this, add_subplot would be simpler and
                    # more similar to add_axes.
                    self._axstack.remove(ax)
            if projection == 'wright':
                a = subplot_class_factory(Axes)(self, *args, **kwargs)
            else:
                a = subplot_class_factory(projection_class)(self, *args,
                                                            **kwargs)
        self._axstack.add(key, a)
        self.sca(a)
        if int(matplotlib.__version__.split('.')[0]) > 1:
            a._remove_method = self.__remove_ax
            self.stale = True
            a.stale_callback = matplotlib.figure._stale_figure_callback
        # finish
        return a
Example #14
0
    headeradd("CRVAL1  =  %10.5f / Galactic longitude of reference pixel" \
              % (lon_center,))
    
    cards = pyfits.CardList()
    for l in header_list:
        card = pyfits.Card()
        card.fromstring(l.strip())
        cards.append(card)

    h = pyfits.Header(cards)
    return h


FloatingAxes = floatingaxes_class_factory(AxesWcs)
FloatingSubplot = maxes.subplot_class_factory(FloatingAxes)


_proj_pseudo_cyl_list = ["SFL", "PAR", "MOL"]
_proj_lat_limits = dict(MER= 75)

def make_allsky_axes_from_header(fig, rect, header, lon_center,
                                 lat_minmax=None, pseudo_cyl=None):
    

    proj = header["CTYPE1"].split("-")[-1]
    if pseudo_cyl is None:
        if proj in _proj_pseudo_cyl_list:
            pseudo_cyl = True
        
    if lat_minmax is None:
Example #15
0
        deltax = x0 - xlim[0]
        deltay = y0 - ylim[0]
        self.set_xlim(xlim[0] + deltax, xlim[1] - deltax)
        self.set_ylim(ylim[0] + deltay, ylim[1] - deltay)

    def center_y(self, y):
        ymin, ymax = self.get_ylim()
        yoff = (ymax - ymin) * 0.5
        self.set_ylim(y - yoff, y + yoff)

    def center_x(self, x, offset=0.3):
        xmin, xmax = self.get_xlim()
        xspan = xmax - xmin
        xoff = xspan * 0.5 + xspan * offset
        self.set_xlim(x - xoff, x + xoff)

    def scroll(self, x, y):
        x0, x1 = self.get_xlim()
        y0, y1 = self.get_ylim()
        xd = (x1 - x0) * x
        yd = (y1 - y0) * y
        self.set_xlim(x0 + xd, x1 + xd)
        self.set_ylim(y0 + yd, y1 + yd)

    def home(self):
        self.set_xlim(0, self.nchar)
        self.set_ylim(self.ntax, 0)


AlignmentPlot = subplot_class_factory(Alignment)
Example #16
0
        self.name2plot = {}
        self.highlighted = set()
        self.divs = []
        self.figure.clf()

    def picked(self, e):
        try:
            if e.mouseevent.button==1:
                print e.artist.get_text()
                sys.stdout.flush()
        except:
            pass

    def getplot(self, x):
        p = None
        try:
            i = self.root.index(x)
            return self.plot[i]
        except ValueError:
            return self.name2plot.get(x)

class UpdatingRect(Rectangle): # Used in overview plot
    def __call__(self, p):
        self.set_bounds(*p.viewLim.bounds)
        p.draw_labels()
        p.figure.canvas.draw_idle()

TreePlot = subplot_class_factory(Tree)
RadialTreePlot = subplot_class_factory(RadialTree)
OverviewTreePlot = subplot_class_factory(OverviewTree)
Example #17
0
    def add_overview_rect(self):
        rect = UpdatingRect([0, 0], 0, 0, facecolor='black', edgecolor='red')
        rect.set_alpha(0.2)
        rect.target = self.target
        rect.set_bounds(*self.target.viewLim.bounds)
        self.zoomrect = rect
        self.add_patch(rect)
        self.target.callbacks.connect('xlim_changed', rect)
        self.target.callbacks.connect('ylim_changed', rect)

    def redraw(self):
        Tree.redraw(self)
        self.add_overview_rect()
        self.figure.canvas.draw_idle()

TreePlot = subplot_class_factory(Tree)
OverviewTreePlot = subplot_class_factory(OverviewTree)

def axes_enter(e):
    ax = e.inaxes
    ax._active = True

def axes_leave(e):
    ax = e.inaxes
    ax._active = False

def onselect(estart, estop):
    b = estart.button
    ## print b, estart.key

def onkeypress(e):
Example #18
0
                                 nth_coord=None,
                                 axis_direction=None,
                                 offset=offset,
                                 axes=self,
                                 )
        return axis

    def new_floating_axis(self, nth_coord, value, axis_direction="bottom"):
        gh = self.get_grid_helper()
        axis = gh.new_floating_axis(nth_coord, value,
                                    axis_direction=axis_direction,
                                    axes=self)
        return axis


Subplot = maxes.subplot_class_factory(Axes)


class AxesZero(Axes):

    def _init_axis_artists(self):
        super()._init_axis_artists()

        new_floating_axis = self._grid_helper.new_floating_axis
        xaxis_zero = new_floating_axis(nth_coord=0,
                                       value=0.,
                                       axis_direction="bottom",
                                       axes=self)

        xaxis_zero.line.set_clip_path(self.patch)
        xaxis_zero.set_visible(False)
Example #19
0
        self.preview = kw.pop("preview", "False")

        maxes.Axes.__init__(self, *kl, **kw)

    def draw(self, renderer):
        usetex = plt.rcParams["text.usetex"]
        preview = plt.rcParams["text.latex.preview"]
        plt.rcParams["text.usetex"] = self.usetex
        plt.rcParams["text.latex.preview"] = self.preview

        maxes.Axes.draw(self, renderer)

        plt.rcParams["text.usetex"] = usetex
        plt.rcParams["text.latex.preview"] = preview

Subplot = maxes.subplot_class_factory(Axes)


def test_window_extent(ax, usetex, preview):

    va = "baseline"
    ax.xaxis.set_visible(False)
    ax.yaxis.set_visible(False)


    #t = ax.text(0., 0., r"mlp", va="baseline", size=150)
    text_kw = dict(va=va,
                   size=50,
                   bbox=dict(pad=0., ec="k", fc="none"))

Example #20
0
def test_subplot_factory_reapplication():
    assert maxes.subplot_class_factory(maxes.Axes) is maxes.Subplot
    assert maxes.subplot_class_factory(maxes.Subplot) is maxes.Subplot
Example #21
0
    param = []
    for j in range(len(params)):
      param.append([p[id] for p in params[j]])
    params = param[:]

  # at this point, we should have:
  #bounds = [(60,105),(0,30),(2.1,2.8)] or [(None,None),(None,None),(None,None)]
  #xyz = [(2,3),(6,7),(10,11)] for any length tuple
  #wxyz = [(0,1),(4,5),(8,9)] for any length tuple (should match up with xyz)
  #select = ['-1'] or ['1','2','3','-1'] or similar
  #id = 0 or None

  from mpl_toolkits.mplot3d import Axes3D
  import matplotlib.pyplot as plt
  from matplotlib.axes import subplot_class_factory
  Subplot3D = subplot_class_factory(Axes3D)

  plots = len(select)
  if not flatten:
    dim1,dim2 = best_dimensions(plots)
  else: dim1,dim2 = 1,1

  # use the default bounds where not specified
  bounds = [list(i) for i in bounds]
  for i in range(len(bounds)):
    if bounds[i][0] is None: bounds[i][0] = 0
    if bounds[i][1] is None: bounds[i][1] = 1

  # correctly bound the first plot.  there must be at least one plot
  fig = plt.figure()
  ax1 = Subplot3D(fig, dim1,dim2,1)
Example #22
0
    def get_tightbbox(self, renderer):

        if not self.get_visible():
            return

        bb = [b for b in self._bboxes if b and (b.width != 0 or b.height != 0)]

        if bb:
            _bbox = Bbox.union(bb)
            return _bbox
        else:
            return self.get_window_extent(renderer)

    def grid(self, draw_grid=True, **kwargs):
        """
        Plot gridlines for both coordinates.

        Standard matplotlib appearance options (color, alpha, etc.) can be
        passed as keyword arguments.

        Parameters
        ----------
        draw_grid : bool
            Whether to show the gridlines
        """
        if draw_grid:
            self.coords.grid(draw_grid=draw_grid, **kwargs)


WCSAxesSubplot = subplot_class_factory(WCSAxes)
Example #23
0
        x0, x1 = points[:,0]; y0, y1 = points[:,1]
        deltax = x0 - xlim[0]; deltay = y0 - ylim[0]
        self.set_xlim(xlim[0]+deltax, xlim[1]-deltax)
        self.set_ylim(ylim[0]+deltay, ylim[1]-deltay)

    def center_y(self, y):
        ymin, ymax = self.get_ylim()
        yoff = (ymax - ymin) * 0.5
        self.set_ylim(y-yoff, y+yoff)

    def center_x(self, x, offset=0.3):
        xmin, xmax = self.get_xlim()
        xspan = xmax - xmin
        xoff = xspan*0.5 + xspan*offset
        self.set_xlim(x-xoff, x+xoff)

    def scroll(self, x, y):
        x0, x1 = self.get_xlim()
        y0, y1 = self.get_ylim()
        xd = (x1-x0)*x
        yd = (y1-y0)*y
        self.set_xlim(x0+xd, x1+xd)
        self.set_ylim(y0+yd, y1+yd)

    def home(self):
        self.set_xlim(0, self.nchar)
        self.set_ylim(self.ntax, 0)

AlignmentPlot = subplot_class_factory(Alignment)

Example #24
0
def host_subplot_class_factory(axes_class):
    host_axes_class = host_axes_class_factory(axes_class=axes_class)
    subplot_host_class = subplot_class_factory(host_axes_class)
    return subplot_host_class
Example #25
0
                '_get_base_axes': _get_base_axes
            })

        _host_axes_classes[axes_class] = new_class

    return new_class


def host_subplot_class_factory(axes_class):
    host_axes_class = host_axes_class_factory(axes_class=axes_class)
    subplot_host_class = subplot_class_factory(host_axes_class)
    return subplot_host_class


HostAxes = host_axes_class_factory(axes_class=Axes)
SubplotHost = subplot_class_factory(HostAxes)


def host_axes(*args, **kwargs):
    import matplotlib.pyplot as plt
    axes_class = kwargs.pop("axes_class", None)
    host_axes_class = host_axes_class_factory(axes_class)
    fig = plt.gcf()
    ax = host_axes_class(fig, *args, **kwargs)
    fig.add_axes(ax)
    plt.draw_if_interactive()
    return ax


def host_subplot(*args, **kwargs):
    import matplotlib.pyplot as plt
Example #26
0
class WCSAxesSubplot(subplot_class_factory(WCSAxes)):
    """
    A subclass class for WCSAxes
    """
    pass
Example #27
0
    def add_subplot(self, *args, **kwargs):
        """
        Add a subplot.  Examples::

            fig.add_subplot(111)

            # equivalent but more general
            fig.add_subplot(1,1,1)

            # add subplot with red background
            fig.add_subplot(212, axisbg='r')

            # add a polar subplot
            fig.add_subplot(111, projection='polar')

            # add Subplot instance sub
            fig.add_subplot(sub)

        *kwargs* are legal :class:`~matplotlib.axes.Axes` kwargs plus
        *projection*, which chooses a projection type for the axes.
        (For backward compatibility, *polar=True* may also be
        provided, which is equivalent to *projection='polar'*). Valid
        values for *projection* are: %(projection_names)s.  Some of
        these projections
        support additional *kwargs*, which may be provided to
        :meth:`add_axes`.

        The :class:`~matplotlib.axes.Axes` instance will be returned.

        If the figure already has a subplot with key (*args*,
        *kwargs*) then it will simply make that subplot current and
        return it.

        The following kwargs are supported:

        %(Axes)s
        """
        if not len(args): return

        if len(args) == 1 and isinstance(args[0], int):
            args = tuple([int(c) for c in str(args[0])])

        if isinstance(args[0], SubplotBase):

            a = args[0]
            assert(a.get_figure() is self)
            # make a key for the subplot (which includes the axes object id
            # in the hash)
            key = self._make_key(*args, **kwargs)
        else:
            projection_class, kwargs, key = \
                        process_projection_requirements(self, *args, **kwargs)

            # try to find the axes with this key in the stack
            ax = self._axstack.get(key)

            if ax is not None:
                if isinstance(ax, projection_class):
                    # the axes already existed, so set it as active & return
                    self.sca(ax)
                    return ax
                else:
                    # Undocumented convenience behavior:
                    # subplot(111); subplot(111, projection='polar')
                    # will replace the first with the second.
                    # Without this, add_subplot would be simpler and
                    # more similar to add_axes.
                    self._axstack.remove(ax)

            a = subplot_class_factory(projection_class)(self, *args, **kwargs)

        self._axstack.add(key, a)
        self.sca(a)
        return a