Skip to content

Commit 9602112

Browse files
committed
Improve speed
1 parent a2ddfc0 commit 9602112

File tree

1 file changed

+47
-37
lines changed
  • lib/matplotlib/projections

1 file changed

+47
-37
lines changed

lib/matplotlib/projections/geo.py

Lines changed: 47 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import math
12
import numpy as np
23

34
from matplotlib import _api, rcParams
@@ -52,8 +53,8 @@ def cla(self):
5253

5354
self.grid(rcParams['axes.grid'])
5455

55-
Axes.set_xlim(self, -np.pi, np.pi)
56-
Axes.set_ylim(self, -np.pi / 2.0, np.pi / 2.0)
56+
Axes.set_xlim(self, -math.pi, math.pi)
57+
Axes.set_ylim(self, -math.pi / 2.0, math.pi / 2.0)
5758

5859
def _set_lim_and_transforms(self):
5960
# A (possibly non-linear) projection on the (already scaled) data
@@ -88,7 +89,7 @@ def _set_lim_and_transforms(self):
8889
Affine2D().translate(0, -4)
8990

9091
# This is the transform for latitude ticks.
91-
yaxis_stretch = Affine2D().scale(np.pi * 2, 1).translate(-np.pi, 0)
92+
yaxis_stretch = Affine2D().scale(math.pi * 2, 1).translate(-math.pi, 0)
9293
yaxis_space = Affine2D().scale(1, 1.1)
9394
self._yaxis_transform = \
9495
yaxis_stretch + \
@@ -108,8 +109,8 @@ def _set_lim_and_transforms(self):
108109

109110
def _get_affine_transform(self):
110111
transform = self._get_core_transform(1)
111-
xscale, _ = transform.transform((np.pi, 0))
112-
_, yscale = transform.transform((0, np.pi/2))
112+
xscale, _ = transform.transform((math.pi, 0))
113+
_, yscale = transform.transform((0, math.pi / 2))
113114
return Affine2D() \
114115
.scale(0.5 / xscale, 0.5 / yscale) \
115116
.translate(0.5, 0.5)
@@ -261,14 +262,17 @@ def transform_non_affine(self, ll):
261262
longitude, latitude = ll.T
262263

263264
# Pre-compute some values
264-
half_long = longitude / 2.0
265-
cos_latitude = np.cos(latitude)
265+
half_long = longitude / 2
266+
cos_half = np.cos(half_long)
267+
sin_half = np.cos(half_long)
268+
cos_latitude = cos_half*cos_half - sin_half*sin_half
266269

267-
alpha = np.arccos(cos_latitude * np.cos(half_long))
268-
sinc_alpha = np.sinc(alpha / np.pi) # np.sinc is sin(pi*x)/(pi*x).
270+
alpha = np.arccos(cos_latitude * cos_half)
271+
# np.sinc is sin(pi*x)/(pi*x).
272+
sinc_alpha = np.sinc(alpha / math.pi)
269273

270-
x = (cos_latitude * np.sin(half_long)) / sinc_alpha
271-
y = np.sin(latitude) / sinc_alpha
274+
x = (cos_latitude * sin_half) / sinc_alpha
275+
y = 2.0 * sin_half * cos_half / sinc_alpha # sin(lat) / sinc_alpha
272276
return np.column_stack([x, y])
273277

274278
def inverted(self):
@@ -287,7 +291,7 @@ def inverted(self):
287291
return AitoffAxes.AitoffTransform(self._resolution)
288292

289293
def __init__(self, *args, **kwargs):
290-
self._longitude_cap = np.pi / 2.0
294+
self._longitude_cap = math.pi / 2
291295
super().__init__(*args, **kwargs)
292296
self.set_aspect(0.5, adjustable='box', anchor='C')
293297
self.cla()
@@ -305,12 +309,14 @@ class HammerTransform(_GeoTransform):
305309
def transform_non_affine(self, ll):
306310
# docstring inherited
307311
longitude, latitude = ll.T
308-
half_long = longitude / 2.0
309-
cos_latitude = np.cos(latitude)
310-
sqrt2 = np.sqrt(2.0)
311-
alpha = np.sqrt(1.0 + cos_latitude * np.cos(half_long))
312-
x = (2.0 * sqrt2) * (cos_latitude * np.sin(half_long)) / alpha
313-
y = (sqrt2 * np.sin(latitude)) / alpha
312+
half_long = longitude / 2
313+
cos_half = np.cos(half_long)
314+
sin_half = np.cos(half_long)
315+
cos_latitude = cos_half*cos_half - sin_half*sin_half
316+
sqrt8 = 8 ** (1/2)
317+
alpha = np.sqrt(1.0 + cos_latitude * cos_half)
318+
x = (sqrt8 * cos_latitude * sin_half) / alpha
319+
y = (sqrt8 * cos_half * sin_half) / alpha # sin(lat)
314320
return np.column_stack([x, y])
315321

316322
def inverted(self):
@@ -324,15 +330,15 @@ def transform_non_affine(self, xy):
324330
x, y = xy.T
325331
z = np.sqrt(1 - (x / 4) ** 2 - (y / 2) ** 2)
326332
longitude = 2 * np.arctan((z * x) / (2 * (2 * z ** 2 - 1)))
327-
latitude = np.arcsin(y*z)
333+
latitude = np.arcsin(y * z)
328334
return np.column_stack([longitude, latitude])
329335

330336
def inverted(self):
331337
# docstring inherited
332338
return HammerAxes.HammerTransform(self._resolution)
333339

334340
def __init__(self, *args, **kwargs):
335-
self._longitude_cap = np.pi / 2.0
341+
self._longitude_cap = math.pi / 2
336342
super().__init__(*args, **kwargs)
337343
self.set_aspect(0.5, adjustable='box', anchor='C')
338344
self.cla()
@@ -351,18 +357,18 @@ def transform_non_affine(self, ll):
351357
# docstring inherited
352358
def d(theta):
353359
delta = (-(theta + np.sin(theta) - pi_sin_l)
354-
/ (1 + np.cos(theta)))
360+
/ (1.0 + np.cos(theta)))
355361
return delta, np.abs(delta) > 0.001
356362

357363
longitude, latitude = ll.T
358-
359-
clat = np.pi/2 - np.abs(latitude)
364+
pi_half = math.pi / 2
365+
clat = pi_half - np.abs(latitude)
360366
ihigh = clat < 0.087 # within 5 degrees of the poles
361367
ilow = ~ihigh
362368
aux = np.empty(latitude.shape, dtype=float)
363369

364370
if ilow.any(): # Newton-Raphson iteration
365-
pi_sin_l = np.pi * np.sin(latitude[ilow])
371+
pi_sin_l = math.pi * np.sin(latitude[ilow])
366372
theta = 2.0 * latitude[ilow]
367373
delta, large_delta = d(theta)
368374
while np.any(large_delta):
@@ -372,12 +378,13 @@ def d(theta):
372378

373379
if ihigh.any(): # Taylor series-based approx. solution
374380
e = clat[ihigh]
375-
d = 0.5 * (3 * np.pi * e**2) ** (1.0/3)
376-
aux[ihigh] = (np.pi/2 - d) * np.sign(latitude[ihigh])
381+
d = np.cbrt(3.0 * math.pi * e ** 2) / 2
382+
aux[ihigh] = (pi_half - d) * np.sign(latitude[ihigh])
377383

378384
xy = np.empty(ll.shape, dtype=float)
379-
xy[:, 0] = (2.0 * np.sqrt(2.0) / np.pi) * longitude * np.cos(aux)
380-
xy[:, 1] = np.sqrt(2.0) * np.sin(aux)
385+
sqrt2 = 2 ** (1 / 2)
386+
xy[:, 0] = (sqrt2 / pi_half) * longitude * np.cos(aux)
387+
xy[:, 1] = sqrt2 * np.sin(aux)
381388

382389
return xy
383390

@@ -392,17 +399,18 @@ def transform_non_affine(self, xy):
392399
x, y = xy.T
393400
# from Equations (7, 8) of
394401
# https://mathworld.wolfram.com/MollweideProjection.html
395-
theta = np.arcsin(y / np.sqrt(2))
396-
longitude = (np.pi / (2 * np.sqrt(2))) * x / np.cos(theta)
397-
latitude = np.arcsin((2 * theta + np.sin(2 * theta)) / np.pi)
402+
sqrt2 = 2 ** (1 / 2)
403+
theta = np.arcsin(y / sqrt2)
404+
longitude = (math.pi / (2.0 * sqrt2)) * x / np.cos(theta)
405+
latitude = np.arcsin((2.0 * theta + np.sin(2.0 * theta)) / math.pi)
398406
return np.column_stack([longitude, latitude])
399407

400408
def inverted(self):
401409
# docstring inherited
402410
return MollweideAxes.MollweideTransform(self._resolution)
403411

404412
def __init__(self, *args, **kwargs):
405-
self._longitude_cap = np.pi / 2.0
413+
self._longitude_cap = math.pi / 2.0
406414
super().__init__(*args, **kwargs)
407415
self.set_aspect(0.5, adjustable='box', anchor='C')
408416
self.cla()
@@ -434,15 +442,17 @@ def transform_non_affine(self, ll):
434442
clat = self._center_latitude
435443
cos_lat = np.cos(latitude)
436444
sin_lat = np.sin(latitude)
445+
cos_clat = np.cos(clat)
446+
sin_clat = np.sin(clat)
437447
diff_long = longitude - clong
438448
cos_diff_long = np.cos(diff_long)
439449

440450
inner_k = np.maximum( # Prevent divide-by-zero problems
441-
1 + np.sin(clat)*sin_lat + np.cos(clat)*cos_lat*cos_diff_long,
451+
1.0 + sin_clat*sin_lat + cos_clat*cos_lat*cos_diff_long,
442452
1e-15)
443-
k = np.sqrt(2 / inner_k)
453+
k = np.sqrt(2.0 / inner_k)
444454
x = k * cos_lat*np.sin(diff_long)
445-
y = k * (np.cos(clat)*sin_lat - np.sin(clat)*cos_lat*cos_diff_long)
455+
y = k * (cos_clat*sin_lat - sin_clat*cos_lat*cos_diff_long)
446456

447457
return np.column_stack([x, y])
448458

@@ -466,7 +476,7 @@ def transform_non_affine(self, xy):
466476
clong = self._center_longitude
467477
clat = self._center_latitude
468478
p = np.maximum(np.hypot(x, y), 1e-9)
469-
c = 2 * np.arcsin(0.5 * p)
479+
c = 2.0 * np.arcsin(0.5 * p)
470480
sin_c = np.sin(c)
471481
cos_c = np.cos(c)
472482

@@ -485,7 +495,7 @@ def inverted(self):
485495
self._resolution)
486496

487497
def __init__(self, *args, center_longitude=0, center_latitude=0, **kwargs):
488-
self._longitude_cap = np.pi / 2
498+
self._longitude_cap = math.pi / 2
489499
self._center_longitude = center_longitude
490500
self._center_latitude = center_latitude
491501
super().__init__(*args, **kwargs)

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy