Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

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

Sign up
Appearance settings

Commit1e2d23e

Browse files
committed
ENH: add arbitrary-scale functionality
API: add ability to set formatter and locators from scale init
1 parentac0525e commit1e2d23e

File tree

6 files changed

+186
-3
lines changed

6 files changed

+186
-3
lines changed

‎.flake8

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ per-file-ignores =
197197
examples/pyplots/whats_new_99_spines.py: E231, E402
198198
examples/recipes/placing_text_boxes.py: E501
199199
examples/scales/power_norm.py: E402
200+
examples/scales/scales.py: E402
200201
examples/shapes_and_collections/artist_reference.py: E402
201202
examples/shapes_and_collections/collections.py: E402
202203
examples/shapes_and_collections/compound_path.py: E402

‎examples/scales/custom_scale.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@
55
66
Create a custom scale, by implementing the scaling use for latitude data in a
77
Mercator Projection.
8+
9+
Unless you are making special use of the `~.Transform` class, you probably
10+
don't need to use this verbose method, and instead can use
11+
`~.matplotlib.scale.ArbitraryScale` and the ``'arbitrary'`` option of
12+
`~.matplotlib.axes.Axes.set_xscale` and `~.matplotlib.axes.Axes.set_yscale`.
13+
See the last example in :doc:`/gallery/scales/scales`.
814
"""
915

1016
importnumpyasnp

‎examples/scales/scales.py

Lines changed: 75 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,13 @@
44
======
55
66
Illustrate the scale transformations applied to axes, e.g. log, symlog, logit.
7+
8+
The last two examples are examples of using the ``'arbitrary'`` scale by
9+
supplying forward and inverse functions for the scale transformation.
710
"""
811
importnumpyasnp
912
importmatplotlib.pyplotasplt
10-
frommatplotlib.tickerimportNullFormatter
13+
frommatplotlib.tickerimportNullFormatter,FixedLocator
1114

1215
# Fixing random state for reproducibility
1316
np.random.seed(19680801)
@@ -19,8 +22,8 @@
1922
x=np.arange(len(y))
2023

2124
# plot with various axes scales
22-
fig,axs=plt.subplots(2,2,sharex=True)
23-
fig.subplots_adjust(left=0.08,right=0.98,wspace=0.3)
25+
fig,axs=plt.subplots(3,2,figsize=(6,8),
26+
constrained_layout=True)
2427

2528
# linear
2629
ax=axs[0,0]
@@ -54,4 +57,73 @@
5457
ax.yaxis.set_minor_formatter(NullFormatter())
5558

5659

60+
# Arbitrary x**(1/2)
61+
defforward(x):
62+
returnx**(1/2)
63+
64+
65+
definverse(x):
66+
returnx**2
67+
68+
69+
ax=axs[2,0]
70+
ax.plot(x,y)
71+
ax.set_yscale('arbitrary',functions=(forward,inverse))
72+
ax.set_title('arbitrary: $x^{1/2}$')
73+
ax.grid(True)
74+
ax.yaxis.set_major_locator(FixedLocator(np.arange(0,1,0.2)**2))
75+
ax.yaxis.set_major_locator(FixedLocator(np.arange(0,1,0.2)))
76+
77+
78+
# Arbitrary Mercator transform
79+
defforward(a):
80+
a=np.deg2rad(a)
81+
# mask values too close to +/- 90, which are ill-defined.
82+
masked=np.ma.masked_where((a<=-np.pi/2+0.02)|
83+
(a>=np.pi/2-0.02),a)
84+
ifmasked.mask.any():
85+
returnnp.rad2deg(
86+
np.ma.log(np.abs(np.ma.tan(masked)+1.0/np.ma.cos(masked))))
87+
else:
88+
returnnp.rad2deg(np.log(np.abs(np.tan(a)+1.0/np.cos(a))))
89+
90+
91+
definverse(a):
92+
a=np.deg2rad(a)
93+
returnnp.rad2deg(np.arctan(np.sinh(a)))
94+
95+
ax=axs[2,1]
96+
97+
t=np.arange(-170.0,170.0,0.1)
98+
s=t/2.
99+
100+
ax.plot(t,s,'-',lw=2)
101+
102+
ax.set_yscale('arbitrary',functions=(forward,inverse))
103+
ax.set_title('arbitrary: Mercator')
104+
ax.grid(True)
105+
ax.set_xlim([-180,180])
106+
ax.yaxis.set_minor_formatter(NullFormatter())
107+
ax.yaxis.set_major_locator(FixedLocator(np.arange(-90,90,30)))
108+
57109
plt.show()
110+
111+
#############################################################################
112+
#
113+
# ------------
114+
#
115+
# References
116+
# """"""""""
117+
#
118+
# The use of the following functions, methods, classes and modules is shown
119+
# in this example:
120+
121+
importmatplotlib
122+
matplotlib.axes.Axes.set_yscale
123+
matplotlib.axes.Axes.set_xscale
124+
matplotlib.axis.Axis.set_major_locator
125+
matplotlib.scale.LogitScale
126+
matplotlib.scale.LogScale
127+
matplotlib.scale.LinearScale
128+
matplotlib.scale.SymmetricalLogScale
129+
matplotlib.scale.ArbitraryScale

‎lib/matplotlib/scale.py

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,84 @@ def get_transform(self):
8282
returnIdentityTransform()
8383

8484

85+
classArbitraryTransform(Transform):
86+
"""
87+
A simple transform that takes and arbitrary function for the
88+
forward and inverse transform.
89+
"""
90+
91+
input_dims=1
92+
output_dims=1
93+
is_separable=True
94+
has_inverse=True
95+
96+
def__init__(self,forward,inverse):
97+
"""
98+
Parameters
99+
----------
100+
101+
forward: The forward function for the transform
102+
103+
inverse: The inverse of the forward function.
104+
"""
105+
super().__init__()
106+
ifcallable(forward)andcallable(inverse):
107+
self._forward=forward
108+
self._inverse=inverse
109+
else:
110+
raiseValueError('arguments to ArbitraryTransform must '
111+
'be functions')
112+
113+
deftransform_non_affine(self,values):
114+
returnself._forward(values)
115+
116+
definverted(self):
117+
returnArbitraryTransform(self._inverse,self._forward)
118+
119+
120+
classArbitraryScale(ScaleBase):
121+
"""
122+
Provide an arbitrary scale for the axis.
123+
"""
124+
125+
name='arbitrary'
126+
127+
def__init__(self,axis,functions):
128+
"""
129+
Parameters
130+
----------
131+
132+
axis: the axis for the scale
133+
134+
functions: (forward, inverse)
135+
two-tuple of the forward and inverse functions for the scale.
136+
"""
137+
forward,inverse=functions
138+
transform=ArbitraryTransform(forward,inverse)
139+
self._transform=transform
140+
141+
defget_transform(self):
142+
"""
143+
The transform for linear scaling is just the
144+
:class:`~matplotlib.transforms.IdentityTransform`.
145+
"""
146+
returnself._transform
147+
148+
defset_default_locators_and_formatters(self,axis):
149+
"""
150+
Set the locators and formatters to reasonable defaults for
151+
linear scaling.
152+
"""
153+
axis.set_major_locator(AutoLocator())
154+
axis.set_major_formatter(ScalarFormatter())
155+
axis.set_minor_formatter(NullFormatter())
156+
# update the minor locator for x and y axis based on rcParams
157+
ifrcParams['xtick.minor.visible']:
158+
axis.set_minor_locator(AutoMinorLocator())
159+
else:
160+
axis.set_minor_locator(NullLocator())
161+
162+
85163
classLogTransformBase(Transform):
86164
input_dims=1
87165
output_dims=1
@@ -545,6 +623,7 @@ def limit_range_for_scale(self, vmin, vmax, minpos):
545623
'log':LogScale,
546624
'symlog':SymmetricalLogScale,
547625
'logit':LogitScale,
626+
'arbitrary':ArbitraryScale,
548627
}
549628

550629

‎lib/matplotlib/tests/test_scale.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
frommatplotlib.testing.decoratorsimportimage_comparison
22
importmatplotlib.pyplotasplt
33
frommatplotlib.scaleimportLog10Transform,InvertedLog10Transform
4+
importmatplotlib.tickerasmticker
5+
46
importnumpyasnp
57
importio
68
importplatform
@@ -148,3 +150,26 @@ def test_invalid_log_lims():
148150
withpytest.warns(UserWarning):
149151
ax.set_ylim(top=-1)
150152
assertax.get_ylim()==original_ylim
153+
154+
155+
definverse(x):
156+
returnx**2
157+
158+
159+
defforward(x):
160+
good=x>=0
161+
y=np.full_like(x,np.NaN)
162+
y[good]=x[good]**(1/2)
163+
returny
164+
165+
166+
@image_comparison(baseline_images=['arbitrary_scales'],remove_text=True,
167+
extensions=['png'],style='mpl20')
168+
deftest_arbitrary_scale():
169+
fig,ax=plt.subplots()
170+
171+
x=np.arange(1,1000)
172+
173+
ax.plot(x,x)
174+
ax.set_xscale('arbitrary',functions=(forward,inverse))
175+
ax.set_xlim(1,1000)

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp