3
votes

Ignorer les limites de projection lors de la définition de l'étendue

Existe-t-il un moyen de définir l'étendue de la figure au-delà des limites de projection?

Par exemple, lors de l'utilisation de la projection "Rijksdriehoek" (EPSG 28992), les limites de Cartopy (proj4?) sont également erronées étroit.

Cette projection est conçue pour couvrir tous les Pays-Bas, mais les limites imposées entraînent même la coupure d'une partie du pays. Alors que je préfère définir l'étendue légèrement plus large que les limites officielles pour fournir un contexte supplémentaire.

 Rd exemple

Malheureusement, le set_extent renvoie une erreur:

print(projection.bounds)
print(ax.get_extent())

(646.3608848793374, 284347.25011780026, 308289.55751689477, 637111.0245778429)
(646.3608848793374, 284347.25011780026, 308289.55751689477, 637111.0245778429)

Les méthodes set_xlim / set_ylim ne semblent rien faire , qui fonctionnerait pour un axe matplotlib normal.

Exemple de code:

import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy.feature as cfeature

projection = ccrs.epsg(28992)

fig, ax = plt.subplots(figsize=(5,10), subplot_kw=dict(projection=projection))

ax.coastlines(resolution='10m')
ax.add_feature(cfeature.NaturalEarthFeature('cultural', 'admin_0_boundary_lines_land', '10m', facecolor='none', edgecolor='k'))

L'étendue de la figure est automatiquement définie aux limites de la projection:

ValueError: Failed to determine the required bounds in projection 
coordinates. Check that the values provided are within the valid range 
(x_limits=[646.3608848793374, 284347.25011780026], 
y_limits=[308289.55751689477, 637111.0245778429]).

Selon la documentation sur la projection, les limites réelles devraient être: (-700 300000 289000 629000) . Mais même ceux-ci semblent un peu stricts à des fins de visualisation.

Voir par exemple la section "Périmètre de validité" sur:

https://translate.google.com/translate?hl=fr&sl = nl & u = https: //nl.wikipedia.org/wiki/Rijksdriehoeksco%25C3%25B6rdinaten


3 commentaires

Question stupide: à l'échelle de cette limitation (c'est-à-dire une carte de tout le pays), observeriez-vous une différence avec toute autre projection qui n'a pas ces limites?


Oui, cela serait bien sûr possible, en utilisant par exemple UTM 31N . Mais il faudrait également reprojeter les données raster que j'ai, ce qui est moins optimal. C'est une solution de contournement.


Encore une fois, je me trompe peut-être ici, mais j'avais à l'esprit que la différence entre les systèmes de coordonnées serait de 100 mètres au maximum, donc une reprojection pourrait même ne pas être nécessaire? (Cela est basé sur Gauß-Krüger contre UMT en Allemagne, je ne sais pas pour "Rijksdriehoek")


3 Réponses :


3
votes

J'ai trouvé que les limites de projection dans Cartopy sont tirées de celles de Proj4, donc il n'y a pas de solution immédiate. Cependant, vous pouvez définir une projection équivalente en interrogeant les paramètres ... Premièrement,

import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy.feature as cfeat
proj_equivalent = ccrs.Stereographic(central_longitude=5.3876388888, central_latitude=52.15616055555,
    false_easting=155000, false_northing=463000, scale_factor=0.9999079)
ax = plt.axes(projection=proj_equivalent)
x0, x1 = -4.7e4, +3.7e5
y0, y1 = 2.6e5, 6.82e5
ax.set_extent((x0, x1, y0, y1), crs=proj_equivalent)
ax.coastlines('50m', color='blue'); ax.gridlines()
ax.add_feature(cfeat.BORDERS, edgecolor='red', linestyle='--')
plt.show()

Ensuite, par exemple ..

>>> import pyepsg
>>> proj4_epsg = pyepsg.get(28992)
>>> print(proj4_epsg.as_proj4())
'+proj=sterea +lat_0=52.15616055555555 +lon_0=5.38763888888889 +k=0.9999079 +x_0=155000 +y_0=463000 +ellps=bessel +towgs84=565.417,50.3319,465.552,-0.398957,0.343988,-1.8774,4.0725 +units=m +no_defs'
>>> 

Ce qui donne un tracé comme celui-ci: entrez la description de l'image ici

De toute évidence, les limites de comté intégrées sont très grossières ici. De plus, je n'ai pas configuré l'ellipse correcte, ce qui nécessite un peu plus de recherche. Mais cela montre comment briser la limitation des limites de projection fournies.

Je ne sais pas s'il y a une opportunité ici de repousser Proj4?


0 commentaires

2
votes

La réponse de @ pp-mo est excellente. Cependant, voici une solution alternative. Le code de travail est:

import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy.feature as cfeature

# subclassing for a modified projection
class nd_prj(ccrs.Stereographic):
    """
    Hacked projection for ccrs.epsg(28992) to get extended plotting limits
    """
    def __init__(self):
        globe = ccrs.Globe(ellipse=u'bessel')
        super(nd_prj, self).__init__(central_latitude=52.15616055555555, \
                     central_longitude=5.38763888888889, \
                     #true_scale_latitude=52.0, \
                     scale_factor=0.9999079, \
                     false_easting=155000, false_northing=463000, globe=globe)

    @property
    def x_limits(self):
        return (500, 300000)   # define the values you need

    @property
    def y_limits(self):
        return (300000, 650000) # define the values you need

projection = nd_prj()  # make use of the projection
fig, ax = plt.subplots(figsize=(5,10), subplot_kw=dict(projection=projection))

ax.coastlines(resolution='10m')
ax.add_feature(cfeature.NaturalEarthFeature('cultural', 'admin_0_boundary_lines_land', \
                                            '10m', facecolor='none', edgecolor='k'))
plt.show()

Le tracé résultant:

entrez la description de l'image ici

J'espère que cela vous sera utile .


1 commentaires

Merci! Après quelques recherches sur Github, je suis également arrivé à la conclusion qu'une projection personnalisée est probablement le meilleur moyen de gérer cela. Voir ma réponse ci-dessous pour une légère variation à ce sujet. Initialiser la projection avec ccrs.epsg (28992) est très bien dans ce cas, puisque la définition elle-même est correcte, mais les limites ne le sont pas.



1
votes
fig, ax = plt.subplots(figsize=(10,15), subplot_kw=dict(projection=projection), facecolor='w')

ax.coastlines(resolution='10m')
ax.add_feature(cfeature.NaturalEarthFeature('cultural', 'admin_0_boundary_lines_land', '10m', 
                                            facecolor='none', edgecolor='k'), label='Stereo', zorder=999, lw=1, linestyle='-')


ax.set_extent([-100000, 400000, 200000, 700000], crs=projection)

0 commentaires