FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Allow sharex/y after axes creation. by anntzer · Pull Request #15287 · matplotlib/matplotlib · GitHub

Repository navigation

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension .py  (2) .rst  (2) All 2 file types selected
Viewed files
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Unified
Split
Hide whitespace
Diff view
Unified
Split
Hide whitespace
7 changes: 5 additions & 2 deletions doc/api/axes_api.rst
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -447,8 +447,8 @@ Adding Artists
Axes.add_table


Twinning
========
Twinning and sharing
====================

.. autosummary::
:toctree: _as_gen
Expand All @@ -458,6 +458,9 @@ Twinning
Axes.twinx
Axes.twiny

Axes.sharex
Axes.sharey

Axes.get_shared_x_axes
Axes.get_shared_y_axes

Expand Down
8 changes: 8 additions & 0 deletions doc/users/next_whats_new/2020-01-24-lateshare.rst
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
`.Axes.sharex`, `.Axes.sharey`
------------------------------
These new methods allow sharing axes *immediately* after creating them. For
example, they can be used to selectively link some axes created all together
using `~.Figure.subplots`.

Note that they may *not* be used to share axes after any operation (e.g.,
drawing) has occurred on them.
17 changes: 17 additions & 0 deletions examples/subplots_axes_and_figures/subplots_demo.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,23 @@
for ax in axs.flat:
ax.label_outer()

###############################################################################
# If you want a more complex sharing structure, you can first create the
# grid of axes with no sharing, and then call `.axes.Axes.sharex` or
# `.axes.Axes.sharey` to add sharing info a posteriori.

fig, axs = plt.subplots(2, 2)
axs[0, 0].plot(x, y)
axs[0, 0].set_title("main")
axs[1, 0].plot(x, y**2)
axs[1, 0].set_title("shares x with main")
axs[1, 0].sharex(axs[0, 0])
axs[0, 1].plot(x + 1, y + 1)
axs[0, 1].set_title("unrelated")
axs[1, 1].plot(x + 2, y + 2)
axs[1, 1].set_title("also unrelated")
fig.tight_layout()

###############################################################################
# Polar axes
# """"""""""
Expand Down
79 changes: 50 additions & 29 deletions lib/matplotlib/axes/_base.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -487,16 +487,8 @@ def __init__(self, fig, rect,
self._anchor = 'C'
self._stale_viewlim_x = False
self._stale_viewlim_y = False
self._sharex = sharex
self._sharey = sharey
if sharex is not None:
if not isinstance(sharex, _AxesBase):
raise TypeError('sharex must be an axes, not a bool')
self._shared_x_axes.join(self, sharex)
if sharey is not None:
if not isinstance(sharey, _AxesBase):
raise TypeError('sharey must be an axes, not a bool')
self._shared_y_axes.join(self, sharey)
self._sharex = None
self._sharey = None
self.set_label(label)
self.set_figure(fig)
self.set_box_aspect(box_aspect)
Expand All @@ -515,6 +507,11 @@ def __init__(self, fig, rect,
self._rasterization_zorder = None
self.cla()

if sharex is not None:
self.sharex(sharex)
if sharey is not None:
self.sharey(sharey)

# funcs used to format x and y - fall back on major formatters
self.fmt_xdata = None
self.fmt_ydata = None
Expand Down Expand Up @@ -1008,6 +1005,44 @@ def _gen_axes_spines(self, locations=None, offset=0.0, units='inches'):
return OrderedDict((side, mspines.Spine.linear_spine(self, side))
for side in ['left', 'right', 'bottom', 'top'])

def sharex(self, other):
"""
Share the x-axis with *other*.

This is equivalent to passing ``sharex=other`` when constructing the

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

This docstring could be more explicit and non circular. For instance the verb to share would indicate that self shares with other, whereas the exact opposite happens. Further passing sharex=other calls this function so I don’t think it’s very helpful to say that this function is the same as that and expect the user to ferret out the behaviour

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

"self shares with other, whereas the exact opposite happens"
What do you mean by "opposite"? Isn't sharing symmetrical? (well perhaps not deep in the implementation details, but from the user PoV it is)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

I meant in everyday English the transitive verb “to share” means one person shares Something with another

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Can you propose an alternate wording here?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Sorry, the main point is that saying ax.sharex is "Equivalent to passing sharex=other when constructing..." is a circular doc, because when you construct, you call ax.sharex. This function ideally would define what ax.sharex does explicitly.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Right now the docs of sharex (as kwargs to the Axes constructor) are

        sharex, sharey : `~.axes.Axes`, optional
            The x or y `~.matplotlib.axis` is shared with the x or
            y axis in the input `~.axes.Axes`.

which is not much better :/ I agree this can be improved, but is arguably a separate issue?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

The docstring defines what the function does for the user, and one of our main problems with "share" is that people don't know what it means and even in the history of the code base different definitions have popped up. Right now I'm not 100% sure what this PR changed and I think it should be defined clearly, in plain English, what calling this function will do.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality
ax0 = (some axes)
ax1 = fig.add_subplot(...)
ax1.sharex(ax0)

is equivalent to

ax0 = (some axes)
ax1 = fig.add_subplot(..., sharex=ax0)

Now it is true that what the latter does is not really well documented either, but the doc available for ax1.sharex(ax0) is, well, exactly the same.

axes, and cannot be used if the x-axis is already being shared with
another axes.
"""
cbook._check_isinstance(_AxesBase, other=other)
if self._sharex is not None and other is not self._sharex:
raise ValueError("x-axis is already shared")
self._shared_x_axes.join(self, other)
self._sharex = other
self.xaxis.major = other.xaxis.major # Ticker instances holding
self.xaxis.minor = other.xaxis.minor # locator and formatter.
x0, x1 = other.get_xlim()
self.set_xlim(x0, x1, emit=False, auto=other.get_autoscalex_on())
self.xaxis._scale = other.xaxis._scale

def sharey(self, other):
"""
Share the y-axis with *other*.

This is equivalent to passing ``sharey=other`` when constructing the
axes, and cannot be used if the y-axis is already being shared with
another axes.
"""
cbook._check_isinstance(_AxesBase, other=other)
if self._sharey is not None and other is not self._sharey:
raise ValueError("y-axis is already shared")
self._shared_y_axes.join(self, other)
self._sharey = other
self.yaxis.major = other.yaxis.major # Ticker instances holding
self.yaxis.minor = other.yaxis.minor # locator and formatter.
y0, y1 = other.get_ylim()
self.set_ylim(y0, y1, emit=False, auto=other.get_autoscaley_on())
self.yaxis._scale = other.yaxis._scale

def cla(self):
"""Clear the current axes."""
# Note: this is called by Axes.__init__()
Expand All @@ -1031,38 +1066,25 @@ def cla(self):
self.callbacks = cbook.CallbackRegistry()

if self._sharex is not None:
# major and minor are axis.Ticker class instances with
# locator and formatter attributes
self.xaxis.major = self._sharex.xaxis.major
self.xaxis.minor = self._sharex.xaxis.minor
x0, x1 = self._sharex.get_xlim()
self.set_xlim(x0, x1, emit=False,
auto=self._sharex.get_autoscalex_on())
self.xaxis._scale = self._sharex.xaxis._scale
self.sharex(self._sharex)
else:
self.xaxis._set_scale('linear')
try:
self.set_xlim(0, 1)
except TypeError:
pass

if self._sharey is not None:
self.yaxis.major = self._sharey.yaxis.major
self.yaxis.minor = self._sharey.yaxis.minor
y0, y1 = self._sharey.get_ylim()
self.set_ylim(y0, y1, emit=False,
auto=self._sharey.get_autoscaley_on())
self.yaxis._scale = self._sharey.yaxis._scale
self.sharey(self._sharey)
else:
self.yaxis._set_scale('linear')
try:
self.set_ylim(0, 1)
except TypeError:
pass

# update the minor locator for x and y axis based on rcParams
if mpl.rcParams['xtick.minor.visible']:
self.xaxis.set_minor_locator(mticker.AutoMinorLocator())

if mpl.rcParams['ytick.minor.visible']:
self.yaxis.set_minor_locator(mticker.AutoMinorLocator())

Expand Down Expand Up @@ -1144,11 +1166,10 @@ def cla(self):

self._shared_x_axes.clean()
self._shared_y_axes.clean()
if self._sharex:
if self._sharex is not None:
self.xaxis.set_visible(xaxis_visible)
self.patch.set_visible(patch_visible)

if self._sharey:
if self._sharey is not None:
self.yaxis.set_visible(yaxis_visible)
self.patch.set_visible(patch_visible)

Expand Down

Back | FazBrowse Home | New Git URL