Skip to content
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

Feature request: generalized meridian/parallel labelling, like in Basemap #881

Closed
lukelbd opened this issue May 10, 2017 · 14 comments
Closed

Comments

@lukelbd
Copy link
Contributor

lukelbd commented May 10, 2017

The basemap package from mpl_toolkits allows labelling parallels/meridians wherever they cross any of four edges of the projected region, "left/right/top/bottom".

For example, from the examples gallery

from mpl_toolkits.basemap import Basemap
import numpy as np
import matplotlib.pyplot as plt
m = Basemap(width=12000000,height=9000000,projection='lcc',
            resolution='c',lat_1=45.,lat_2=55,lat_0=50,lon_0=-107.)
m.drawcoastlines()
m.drawmapboundary(fill_color='aqua')
m.fillcontinents(color='coral',lake_color='aqua')
parallels = np.arange(0.,81,10.)
m.drawparallels(parallels,labels=[False,True,True,False])
meridians = np.arange(10.,351.,20.)
m.drawmeridians(meridians,labels=[True,False,False,True])
plt.show()

labels wherever parallels intersect the right/top of the plotting area, and wherever meridians intersect the left/bottom of the plot (this is specified by the labels kwarg). See this link.

I think I understand one of the issues with this: for situations like the north polar azimuthal equidistant projection, we have a circle and there is no "left/right/top/bottom". basemap solves this by just making these projections into squares (kind of a workaround); for cartopy this would need careful considerations. But the pseudocylindrical projections (like Robinson) and other square/rectangle-shaped projections could use basemaps's implementation pretty much as-is.

I find labelling the parallels/meridians absolutely necessary for professionally visualizing geophysical data (and I think others in my field would agree); for the time being this has been a dealbreaker, even though basemap is clearly outdated and I suspect cartopy is the future.

@gutmann
Copy link

gutmann commented May 18, 2017

I agree, I see that this issue has come up a number of times in past discussions (for at least ~3-4 years now?), but I don't see any other open related feature requests, so I think this needs highlighting again. I want to use cartopy, but for any professional publications this is sort of a deal breaker for me too.

I think even implementing an API that (initially) requires the user to specify which ticks to draw and which axis to draw them on (for some projections) would be acceptable. I don't think that would interfere with the longer term development/stability of the API, as that customizability would still be useful even after cartopy can come up with a good guess by itself.

Has there been any discussion of what such an API should/could look like to fit in cartopy's style? I get that this is hard, and for some projections very hard, but it seems pretty important for a mapping library.

@jhamman
Copy link

jhamman commented Oct 16, 2017

I'm a big 👍 on this.

Questions for the Cartopy developers:

  1. Are there thoughts/plans for developing an API for this?
  2. Does anyone have a "workaround" for adding grid labels to unsupported projections? Or is everyone falling back to basemap?

@ajdawson
Copy link
Member

In my opinion doing this completely generically would be very difficult (although probably achievable). However, I think implementing something that is not completely generic but suits 90% of use cases could be done. It would be useful to know what the typical requirements are so an API can be designed.

Some years ago I produced an example of how to label a plot using a Lambert Conformal projection: https://gist.github.com/ajdawson/dd536f786741e987ae4e. I hope that this can help demonstrate both the possibilities of what could be achieved, but also highlight why this is difficult (i.e. how to pick locations depends on the shape and orientation of the map, which depends on the subdomain within the projection being plotted, and on user tastes as to what they'd like to see labelled).

@chiaral
Copy link

chiaral commented May 18, 2018

Landing here to add a big thumb up to this issue.... doesn't seem to be any pull request open on this, so I was wondering if there is a plan to work it into next versions. I want to move from basemap to cartopy, given the imminent EOL of basemap, but, as for many other folks, the lack of labeling makes it problematic.

@raybellwaves
Copy link

Similar to basemap. Andy Heaps's cf-plot looks like it can handle this:
cm
http://ajheaps.github.io/cf-plot/_images/cm.png
Maybe something can be adapted from his code
https://github.com/ajheaps/cf-plot

@Jeitan
Copy link
Contributor

Jeitan commented Jun 4, 2018

I'd like to ping this again - this is a killer for switching for me. If it can be done without too much trouble for the majority of use-cases, I think that would be worth it rather than waiting for something completely generalized. I actually just tested the gist that @ajdawson posted using all of Cartopy's supported projections with no other modifications other than changing the projection (the functions in the gist are labeled "lambert_ticks" but I don't think there's anything in there that is specific to that projection alone) and it actually worked just fine for most. Here's what happened:

The tick labelling on all projections worked perfectly except:

  • Robinson - the x ticks didn't show up
  • RotatedPole - yielded an error
  • OSGB, EuroPP, OSNI worked fine but I obviously omitted the set_extent call
  • Geostationary - the x ticks didn't show up
  • North/SouthPolarStereo, UTM - I didn't try

@wckoeppen
Copy link

Seems like there is clear need for this feature but maybe not enough time available to dedicate to the issue? Working in Alaska, we rarely use Plate Caree or Mercator, though I appreciate that they're very common.

@leouieda
Copy link

leouieda commented Jul 15, 2018

We want to take a shot at implementing this through the gridline method for square maps. That will be first step only. The curved map axis will be separate cases.

cc @hetland @pelson @kthyng

@ahuang11
Copy link
Contributor

ahuang11 commented Aug 21, 2018

A temporary hacky method if anyone's interested.

def add_grid_labels(ax, x0, x1, y0, y1, dx, dy,
                    lft=True, rgt=True, top=True, bot=True, spherical=False):
    """Add grid line labels manually for projections that aren't supported

    Args:
        ax (geoaxes.GeoAxesSubplot)
        x0 (scalar)
        x1 (scalar)
        y0 (scalar)
        y1 (scalar)
        dx (scalar)
        dy (scalar)
        lft (bool): whether to label the left side
        rgt (bool): whether to label the right side
        top (bool): whether to label the top side
        bot (bool): whether to label the bottom side
        spherical (bool): pad the labels better if a side of ax is spherical
    """
    if dx <= 10:
        dtype = float
    else:
        dtype = int

    if dy <= 10:
        dtype = float
    else:
        dtype = int

    for lon in np.arange(x0, x1 + dx / 2., dx, dtype=dtype):
        if top:
            text = ax.text(lon, y1, '{0}\n\n'.format(lon),
                           va='center', ha='center',
                           transform=ccrs.PlateCarree())
        if bot:
            text = ax.text(lon, y0, '\n\n{0}'.format(lon),
                           va='center', ha='center',
                           transform=ccrs.PlateCarree())

    for lat in np.arange(y0, y1 + dy / 2., dy, dtype=dtype):
        if spherical:
            if lat == 0:
                va = 'center'
            elif lat > 0:
                va = 'bottom'
            elif lat < 0:
                va = 'top'
        else:
            va = 'center'
        if lft:
            text = ax.text(x0, lat, '{0}  '.format(lat), va=va, ha='right',
                           transform=ccrs.PlateCarree())
        if rgt:
            text = ax.text(x1, lat, '  {0}'.format(lat), va=va, ha='left',
                           transform=ccrs.PlateCarree())

image
image

@dopplershift
Copy link
Contributor

Just wanted to capture that this matplotlib example may point to some code in matplotlib that may help implementation.

@jypeter
Copy link

jypeter commented Jun 13, 2019

Any progress here? I have just triggered the following error when trying to use gridlines(draw_labels=True, ...) with a Mollweide projection

TypeError: Cannot label gridlines on a Mollweide plot. Only PlateCarree and Mercator plots are currently supported.

I have also found the 2 following examples (that don't seem to be mentioned above) for labelling and projections on the matplotlib web site. One even mentions cartopy

@dopplershift
Copy link
Contributor

I think this was merged in #1117 which will be in the next release.

@lukelbd
Copy link
Contributor Author

lukelbd commented Jun 23, 2022

Sorry should have closed this a while ago. Cartopy's current meridian/parallel labeling features are really awesome :)

@lukelbd lukelbd closed this as completed Jun 23, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests