Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Add rcParams for Axes(3D) parameters #25642

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: main
Choose a base branch
Loading
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions 18 doc/users/next_whats_new/axes_rcparams.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
New rcParams for Axes creation
------------------------------

A number of rcParams are introduced to control parts of the Axes creation.
For a standard 2D Axes, the following are introduced:

* :rc:`axes.adjustable`, see `.Axes.set_adjustable`
* :rc:`axes.anchor`, see `.Axes.set_anchor`
* :rc:`axes.aspect`, see `.Axes.set_aspect`
* :rc:`axes.box_aspect`, see `.Axes.set_box_aspect`

There are separate parameters for 3D Axes, including an additional 3D-specific one:

* :rc:`axes3d.adjustable`, see `.Axes.set_adjustable`
* :rc:`axes3d.anchor`, see `.Axes.set_anchor`
* :rc:`axes3d.aspect`, see `.Axes3D.set_aspect`
* :rc:`axes3d.box_aspect`, see `.Axes3D.set_box_aspect`
* :rc:`axes3d.proj_type`, see `.Axes3D.set_proj_type`
6 changes: 3 additions & 3 deletions 6 lib/matplotlib/axes/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -646,9 +646,9 @@ def __init__(self, fig,
raise ValueError('Width and height specified must be non-negative')
self._originalPosition = self._position.frozen()
self.axes = self
self._aspect = 'auto'
self._adjustable = 'box'
self._anchor = 'C'
self._aspect = mpl.rcParams['axes.aspect']
self._adjustable = mpl.rcParams['axes.adjustable']
self._anchor = mpl.rcParams['axes.anchor']
self._stale_viewlims = {name: False for name in self._axis_names}
self._sharex = sharex
self._sharey = sharey
Expand Down
15 changes: 13 additions & 2 deletions 15 lib/matplotlib/mpl-data/matplotlibrc
Original file line number Diff line number Diff line change
Expand Up @@ -425,8 +425,19 @@
#axes.autolimit_mode: data # If "data", use axes.xmargin and axes.ymargin as is.
# If "round_numbers", after application of margins, axis
# limits are further expanded to the nearest "round" number.
#polaraxes.grid: True # display grid on polar axes
#axes3d.grid: True # display grid on 3D axes
#axes.adjustable: box # {box, adjustable}
#axes.anchor: C # {C, E, N, S, W, NE, NW, SE, SW} or two-tuple of floats
#axes.aspect: auto # {equal, auto} or a number
#axes.box_aspect: None # None or a number

#polaraxes.grid: True # display grid on polar axes

#axes3d.grid: True # display grid on 3D axes
#axes3d.adjustable: box # {box, adjustable}
#axes3d.anchor: C # {C, E, N, S, W, NE, NW, SE, SW} or two-tuple of floats
Comment on lines +436 to +437
Copy link
Contributor

Choose a reason for hiding this comment

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

Why not inherit these from axes.adjustable or axes.anchor? A lot of other 3D properties fall back on this without setting an explicit 3D param.

Copy link
Member Author

Choose a reason for hiding this comment

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

#25641 :-)

One can for sure discuss which can be the same and which are beneficial to have separately.

Copy link
Contributor

Choose a reason for hiding this comment

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

#25641 is definitely interesting.

For this one, as defaults, maybe defaulting to what is done is 2d is useful?

Copy link
Member Author

Choose a reason for hiding this comment

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

Sorry, I do not get it. Are you saying that if the 3D-version of the RCparam is not changed, but the 2D-version is, it should use the 2D-version? How do we know if the style-sheet has set the 3D-version to the default value or not? I may be missing something, but I didn't think it was possible to query if the param comes from the style sheet or if the default is used?

Also, wouldn't that be a bit confusing? Now we add double parameters that are also physically located quite nearby, so I guess if someone want to change the 2D-case, chances are that they will notice the 3D-case as well?

Then it may very well be that it is not worthwhile to have separate 2D and 3D versions for all parameters introduced here. aspect and ´adjustableseems to make sense to have separately, which leavesanchor`. That was basically just added because it ended up nearby in the code and I realized that it could be done.

Copy link
Contributor

Choose a reason for hiding this comment

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

So, I found a few places where we do this

self._axinfo.update({
'axisline': {
'linewidth': mpl.rcParams['axes.linewidth'],
'color': mpl.rcParams['axes.edgecolor'],
},

wherein a 3d parameter is set on based on the value of a "2d rcparam", which is why I thought we can use mpl.rcParams['axes.anchor'] directly.

Now, I personally would prefer more rcParams instead of less with inheritance as you mentioned, but I brought it up because there were some such examples. Am not opposed to adding the new rcParams though.

Copy link
Member Author

Choose a reason for hiding this comment

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

OK, then I understand. Yes, it is not a problem as such, more a question of which parameters we would like to separate.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes. But I guess that's a part of a bigger conversation about the role of rcparams itself. For now, I don't mind having all 3 separate parameters either.

#axes3d.aspect: auto
#axes3d.box_aspect: 4, 4, 3 # three floats: x, y, z
#axes3d.proj_type: persp # {persp, ortho}

#axes3d.xaxis.panecolor: (0.95, 0.95, 0.95, 0.5) # background pane on 3D axes
#axes3d.yaxis.panecolor: (0.90, 0.90, 0.90, 0.5) # background pane on 3D axes
Expand Down
20 changes: 20 additions & 0 deletions 20 lib/matplotlib/rcsetup.py
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,17 @@ def validate_aspect(s):
raise ValueError('not a valid aspect specification') from e


def validate_anchor(s):
if s in ('C', 'E', 'N', 'S', 'W', 'NE', 'NW', 'SE', 'SW'):
return s
if isinstance(s, tuple):
try:
return (float(s[0]), float(s[1]))
except ValueError as e:
raise ValueError('not a valid anchor specification') from e
raise ValueError(f'not a valid anchor specification: {s!r}')


def validate_fontsize_None(s):
if s is None or s == 'None':
return None
Expand Down Expand Up @@ -1015,9 +1026,18 @@ def _convert_validator_spec(key, conv):
"axes.xmargin": _range_validators["0 <= x <= 1"], # margin added to xaxis
"axes.ymargin": _range_validators["0 <= x <= 1"], # margin added to yaxis
'axes.zmargin': _range_validators["0 <= x <= 1"], # margin added to zaxis
"axes.adjustable": ["box", "datalim"],
"axes.anchor": validate_anchor,
"axes.aspect": validate_aspect, # equal, auto, a number
"axes.box_aspect": validate_float_or_None,

"polaraxes.grid": validate_bool, # display polar grid or not
"axes3d.grid": validate_bool, # display 3d grid
"axes3d.adjustable": ["box", "datalim"],
"axes3d.anchor": validate_anchor,
"axes3d.aspect": ["auto", "equal", "equalxy", "equalxz", "equalyz"],
"axes3d.proj_type": ["persp", "ortho"],
"axes3d.box_aspect": _listify_validator(validate_float, n=3),

"axes3d.xaxis.panecolor": validate_color, # 3d background pane
"axes3d.yaxis.panecolor": validate_color, # 3d background pane
Expand Down
30 changes: 20 additions & 10 deletions 30 lib/mpl_toolkits/mplot3d/axes3d.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ class Axes3D(Axes):

def __init__(
self, fig, rect=None, *args,
elev=30, azim=-60, roll=0, sharez=None, proj_type='persp',
elev=30, azim=-60, roll=0, sharez=None, proj_type=None,
box_aspect=None, computed_zorder=True, focal_length=None,
**kwargs):
"""
Expand All @@ -89,8 +89,12 @@ def __init__(
scene to rotate counter-clockwise.
sharez : Axes3D, optional
Other Axes to share z-limits with.
proj_type : {'persp', 'ortho'}
The projection type, default 'persp'.
proj_type : {'persp', 'ortho'}, optional
The projection type, default :rc:`axes3d.proj_type`.

.. versionadded:: 3.8
rcParam added, in earlier versions, the default is 'persp'.

box_aspect : 3-tuple of floats, default: None
Changes the physical dimensions of the Axes3D, such that the ratio
of the axis lengths in display units is x:y:z.
Expand Down Expand Up @@ -124,7 +128,7 @@ def __init__(
self.initial_azim = azim
self.initial_elev = elev
self.initial_roll = roll
self.set_proj_type(proj_type, focal_length)
self.set_proj_type(proj_type or mpl.rcParams["axes3d.proj_type"], focal_length)
self.computed_zorder = computed_zorder

self.xy_viewLim = Bbox.unit()
Expand All @@ -148,6 +152,12 @@ def __init__(
'Use fig.add_axes(ax) instead.'
)

if 'aspect' not in kwargs:
kwargs['aspect'] = mpl.rcParams["axes3d.aspect"]
if 'adjustable' not in kwargs:
kwargs['adjustable'] = mpl.rcParams["axes3d.adjustable"]
if 'anchor' not in kwargs:
kwargs['anchor'] = mpl.rcParams["axes3d.anchor"]
super().__init__(
fig, rect, frameon=True, box_aspect=box_aspect, *args, **kwargs
)
Expand Down Expand Up @@ -376,10 +386,10 @@ def set_box_aspect(self, aspect, *, zoom=1):
"""
Set the Axes box aspect.

The box aspect is the ratio of height to width in display
units for each face of the box when viewed perpendicular to
that face. This is not to be confused with the data aspect (see
`~.Axes3D.set_aspect`). The default ratios are 4:4:3 (x:y:z).
The box aspect is the ratio of height to width in display units for each face
of the box when viewed perpendicular to that face. This is not to be confused
with the data aspect (see `~.Axes3D.set_aspect`). The default ratios are
:rc:`axes3d.box_aspect` (x, y, z).

To simulate having equal aspect in data space, set the box
aspect to match your data range in each dimension.
Expand All @@ -391,7 +401,7 @@ def set_box_aspect(self, aspect, *, zoom=1):
aspect : 3-tuple of floats or None
Changes the physical dimensions of the Axes3D, such that the ratio
of the axis lengths in display units is x:y:z.
If None, defaults to (4, 4, 3).
If None, defaults to :rc:`axes3d.box_aspect`.

zoom : float, default: 1
Control overall size of the Axes3D in the figure. Must be > 0.
Expand All @@ -400,7 +410,7 @@ def set_box_aspect(self, aspect, *, zoom=1):
raise ValueError(f'Argument zoom = {zoom} must be > 0')

if aspect is None:
aspect = np.asarray((4, 4, 3), dtype=float)
aspect = np.asarray(mpl.rcParams['axes3d.box_aspect'], dtype=float)
else:
aspect = np.asarray(aspect, dtype=float)
_api.check_shape((3,), aspect=aspect)
Expand Down
Morty Proxy This is a proxified and sanitized view of the page, visit original site.