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

Commitbc91f3e

Browse files
committed
ENH: add arbitrary-scale functionality
API: add ability to set formatter and locators from scale initFIX: rename to FuncScaleDOC: add whats newFIX: simplify Mercator transformTST: simplify test
1 parent6b3c015 commitbc91f3e

File tree

7 files changed

+196
-3
lines changed

7 files changed

+196
-3
lines changed

‎.flake8

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ per-file-ignores =
198198
examples/pyplots/whats_new_99_spines.py: E231, E402
199199
examples/recipes/placing_text_boxes.py: E501
200200
examples/scales/power_norm.py: E402
201+
examples/scales/scales.py: E402
201202
examples/shapes_and_collections/artist_reference.py: E402
202203
examples/shapes_and_collections/collections.py: E402
203204
examples/shapes_and_collections/compound_path.py: E402
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
:orphan:
2+
3+
New `~.scale.FuncScale` added for arbitrary axes scales
4+
````````````````````````````````````````````````````````
5+
6+
A new `~.scale.FuncScale` class was added (and `~.scale.FuncTransform`)
7+
to allow the user to have arbitrary scale transformations without having to
8+
write a new subclass of `~.scale.ScaleBase`. This can be accessed by
9+
``ax.set_yscale('function', functions=(forward, inverse))``, where
10+
``forward`` and ``inverse`` are callables that return the scale transform and
11+
its inverse. See the last example in:doc:`/gallery/scales/scales`.

‎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.FuncScale` and the ``'function'`` 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: 68 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 ``'function'`` 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,66 @@
5457
ax.yaxis.set_minor_formatter(NullFormatter())
5558

5659

60+
# Function 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('function',functions=(forward,inverse))
72+
ax.set_title('function: $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+
# Function Mercator transform
79+
defforward(a):
80+
a=np.deg2rad(a)
81+
returnnp.rad2deg(np.log(np.abs(np.tan(a)+1.0/np.cos(a))))
82+
83+
84+
definverse(a):
85+
a=np.deg2rad(a)
86+
returnnp.rad2deg(np.arctan(np.sinh(a)))
87+
88+
ax=axs[2,1]
89+
90+
t=np.arange(-170.0,170.0,0.1)
91+
s=t/2.
92+
93+
ax.plot(t,s,'-',lw=2)
94+
95+
ax.set_yscale('function',functions=(forward,inverse))
96+
ax.set_title('function: Mercator')
97+
ax.grid(True)
98+
ax.set_xlim([-180,180])
99+
ax.yaxis.set_minor_formatter(NullFormatter())
100+
ax.yaxis.set_major_locator(FixedLocator(np.arange(-90,90,30)))
101+
57102
plt.show()
103+
104+
#############################################################################
105+
#
106+
# ------------
107+
#
108+
# References
109+
# """"""""""
110+
#
111+
# The use of the following functions, methods, classes and modules is shown
112+
# in this example:
113+
114+
importmatplotlib
115+
matplotlib.axes.Axes.set_yscale
116+
matplotlib.axes.Axes.set_xscale
117+
matplotlib.axis.Axis.set_major_locator
118+
matplotlib.scale.LogitScale
119+
matplotlib.scale.LogScale
120+
matplotlib.scale.LinearScale
121+
matplotlib.scale.SymmetricalLogScale
122+
matplotlib.scale.FuncScale

‎lib/matplotlib/scale.py

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,96 @@ def get_transform(self):
9494
returnIdentityTransform()
9595

9696

97+
classFuncTransform(Transform):
98+
"""
99+
A simple transform that takes and arbitrary function for the
100+
forward and inverse transform.
101+
"""
102+
103+
input_dims=1
104+
output_dims=1
105+
is_separable=True
106+
has_inverse=True
107+
108+
def__init__(self,forward,inverse):
109+
"""
110+
Parameters
111+
----------
112+
113+
forward: callable
114+
The forward function for the transform. This function must have
115+
an inverse and, for best behavior, be monotonic.
116+
It must have the signature::
117+
118+
def forward(values: array-like) -> array-like
119+
120+
inverse: callable
121+
The inverse of the forward function. Signature as ``forward``.
122+
"""
123+
super().__init__()
124+
ifcallable(forward)andcallable(inverse):
125+
self._forward=forward
126+
self._inverse=inverse
127+
else:
128+
raiseValueError('arguments to FuncTransform must '
129+
'be functions')
130+
131+
deftransform_non_affine(self,values):
132+
returnself._forward(values)
133+
134+
definverted(self):
135+
returnFuncTransform(self._inverse,self._forward)
136+
137+
138+
classFuncScale(ScaleBase):
139+
"""
140+
Provide an arbitrary scale with user-supplied function for the axis.
141+
"""
142+
143+
name='function'
144+
145+
def__init__(self,axis,functions):
146+
"""
147+
Parameters
148+
----------
149+
150+
axis: the axis for the scale
151+
152+
functions: (callable, callable)
153+
two-tuple of the forward and inverse functions for the scale.
154+
The forward function must have an inverse and, for best behavior,
155+
be monotonic.
156+
157+
Both functions must have the signature::
158+
159+
def forward(values: array-like) -> array-like
160+
"""
161+
forward,inverse=functions
162+
transform=FuncTransform(forward,inverse)
163+
self._transform=transform
164+
165+
defget_transform(self):
166+
"""
167+
The transform for arbitrary scaling
168+
"""
169+
returnself._transform
170+
171+
defset_default_locators_and_formatters(self,axis):
172+
"""
173+
Set the locators and formatters to the same defaults as the
174+
linear scale.
175+
"""
176+
axis.set_major_locator(AutoLocator())
177+
axis.set_major_formatter(ScalarFormatter())
178+
axis.set_minor_formatter(NullFormatter())
179+
# update the minor locator for x and y axis based on rcParams
180+
if (axis.axis_name=='x'andrcParams['xtick.minor.visible']
181+
oraxis.axis_name=='y'andrcParams['ytick.minor.visible']):
182+
axis.set_minor_locator(AutoMinorLocator())
183+
else:
184+
axis.set_minor_locator(NullLocator())
185+
186+
97187
classLogTransformBase(Transform):
98188
input_dims=1
99189
output_dims=1
@@ -557,6 +647,7 @@ def limit_range_for_scale(self, vmin, vmax, minpos):
557647
'log':LogScale,
558648
'symlog':SymmetricalLogScale,
559649
'logit':LogitScale,
650+
'function':FuncScale,
560651
}
561652

562653

‎lib/matplotlib/tests/test_scale.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
frommatplotlib.testing.decoratorsimportimage_comparison
22
importmatplotlib.pyplotasplt
33
frommatplotlib.scaleimportLog10Transform,InvertedLog10Transform
4+
45
importnumpyasnp
56
importio
67
importplatform
@@ -148,3 +149,21 @@ def test_invalid_log_lims():
148149
withpytest.warns(UserWarning):
149150
ax.set_ylim(top=-1)
150151
assertax.get_ylim()==original_ylim
152+
153+
154+
@image_comparison(baseline_images=['function_scales'],remove_text=True,
155+
extensions=['png'],style='mpl20')
156+
deftest_function_scale():
157+
definverse(x):
158+
returnx**2
159+
160+
defforward(x):
161+
returnx**(1/2)
162+
163+
fig,ax=plt.subplots()
164+
165+
x=np.arange(1,1000)
166+
167+
ax.plot(x,x)
168+
ax.set_xscale('function',functions=(forward,inverse))
169+
ax.set_xlim(1,1000)

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp