Skip to content

Show grid ticks on geographic plots #227

Open

Description

@zxdawn

Description

Currently, only grid_lines is supported for geographic plots.
It would be useful to add the grid_ticks for cleaner plot.

Steps to reproduce

import proplot as plot

fig, axs = plot.subplots(proj='cyl')
axs.format(land=True,
           labels=True,
           lonlines=20,
           latlines=20,
           gridminor=True,
           lonlim=(-140, 60),
           latlim=(-10, 50))

Expected behavior: [What you expected to happen]

Ticks without gridlines.

I found one example showing ticks with Gridlines:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
import cartopy.crs as ccrs
from cartopy.mpl.ticker import LongitudeFormatter, LatitudeFormatter

dlon, dlat = 60, 30
xticks = np.arange(0, 360.1, dlon)
yticks = np.arange(-90, 90.1, dlat)

fig = plt.figure(figsize=(6,5))
ax = fig.add_subplot(1,1,1, projection=ccrs.PlateCarree(central_longitude=180))
ax.coastlines() #海岸线

gl = ax.gridlines(crs=ccrs.PlateCarree(), draw_labels=False,linewidth=1, linestyle=':', color='k', alpha=0.8)
gl.xlocator = mticker.FixedLocator(xticks)
gl.ylocator = mticker.FixedLocator(yticks)

ax.set_xticks(xticks, crs=ccrs.PlateCarree())
ax.set_yticks(yticks, crs=ccrs.PlateCarree())

ax.xaxis.set_major_formatter(LongitudeFormatter(zero_direction_label=True))
ax.yaxis.set_major_formatter(LatitudeFormatter())

image

Actual behavior: [What actually happened]
Can't let ticks show.
test_tick

Proplot version

0.6.4

Activity

  1. zxdawn commented on Sep 26, 2020

    @zxdawn
    Author

    This method of retrieving gridline ticks may be useful for adding the function:

    # create grid
    gridliner = ax.gridlines(draw_labels=True)
    
    # we need to draw the figure, such that the gridlines are populated
    fig.canvas.draw()   
    
    ysegs = gridliner.yline_artists[0].get_segments()
    yticks = [yseg[0,1] for yseg in ysegs]
    
    xsegs = gridliner.xline_artists[0].get_segments()
    xticks = [xseg[0,0] for xseg in xsegs]
    
    print(xticks)
    print(yticks)
    
    [-180.0, -120.0, -60.0, 0.0, 60.0, 120.0]
    [-80.0, -60.0, -40.0, -20.0, 0.0, 20.0, 40.0, 60.0, 80.0, 100.0]
    
  2. lukelbd commented on Jul 12, 2021

    @lukelbd
    Collaborator

    You can monitor #253 for updates

    Please also note the padding you see in that example is a cartopy bug confusing "pixels" with "points". It was fixed in SciTools/cartopy#1556. You can upgrade to cartopy v0.19 to get nicely-padded labels or play with ax.format(labelpad=N).

  3. added this to the Version 0.10 milestone on Jul 21, 2021
  4. kM-Stone commented on Nov 29, 2021

    @kM-Stone

    Hi, maybe try ax.format(labels = False)first, then use ax.set_xticks([0, 60, 120, 180, 240, 300, 360], crs=ccrs.PlateCarree()) to specify tick lines explicitly. It worked for me with Version 0.6.4.

    import cartopy.crs as ccrs
    from cartopy.mpl.ticker import LongitudeFormatter, LatitudeFormatter
    import matplotlib.pyplot as plt
    import proplot as pplt
    
    # plt.figure(figsize=(8, 10))
    fig, ax1 = pplt.subplots(proj=ccrs.PlateCarree(central_longitude=180),width=5)
    
    ax1.coastlines()
    
    lon_formatter = LongitudeFormatter(zero_direction_label=True)
    lat_formatter = LatitudeFormatter()
    ax1.xaxis.set_major_formatter(lon_formatter)
    ax1.yaxis.set_major_formatter(lat_formatter)
    
    ax1.set_xticks([30, 60, 120, 180, 240, 300, 350], crs=ccrs.PlateCarree())
    ax1.set_yticks([0, 20, 40], crs=ccrs.PlateCarree())
    
    ax1.tick_params(which='minor',direction='out',length=3,width=1,)
    ax1.tick_params(which='major',direction='out', length=5, width=1, colors='k',)
    
    ax1.format(land=True,
            #    labels=True,
               gridminor=True,
               lonlim=(-140, 60),
               latlim=(-10, 50))
    

    output

  5. syrte commented on Jan 14, 2022

    @syrte

    kM-Stone's solution does not work properly for some other projections such as 'gnom'.

    ---> 16 ax1.set_xticks([30, 60, 120, 180, 240, 300, 350], crs=ccrs.PlateCarree())
         17 ax1.set_yticks([0, 20, 40], crs=ccrs.PlateCarree())
         18 
    
    ~/local/conda/envs/myenv/lib/python3.8/site-packages/cartopy/mpl/geoaxes.py in set_xticks(self, ticks, minor, crs)
        986                                    (ccrs._RectangularProjection,
        987                                     ccrs.Mercator)):
    --> 988                 raise RuntimeError('Cannot handle non-rectangular coordinate '
        989                                    'systems.')
        990             proj_xyz = self.projection.transform_points(crs,
    
    RuntimeError: Cannot handle non-rectangular coordinate systems.
    

    I found a temporary workaround for general projections. I put it here in case it is helpful for anyone.

    import numpy as np
    import proplot as pplt
    
    
    def add_ticks(ax, labelpad=None):
        """Only works for major ticks on the left and bottom."""
        ax.grid(False)
        ax.tick_params('both', which='major', size=pplt.rc['tick.len'])
        if labelpad is None:
            labelpad = pplt.rc['tick.len'] + 2
    
        for gl in ax._gridliners:
            gl.xpadding = gl.ypadding = labelpad
        ax.format(labelpad=labelpad)
        ax.figure.canvas.draw_idle()  # necessary for generating xlabel_artists...
    
        for gl in ax._gridliners:
            xy = np.array([t.get_position() for t in gl.bottom_label_artists if t.get_visible()])
            if xy.any():
                ax.set_xticks(xy[:, 0])
                ax.set_xticklabels([])
    
            xy = np.array([t.get_position() for t in gl.left_label_artists if t.get_visible()])
            if xy.any():
                ax.set_yticks(xy[:, 1])
                ax.set_yticklabels([])
    
    
    fig = pplt.figure(span=False, suptitle='Example')
    ax = fig.subplot(111, proj='gnom', proj_kw={'lon_0': 0, 'lat_0': 45})
    ax.format(lonlim=(-20, 20), latlim=(30, 60),
              labels=True, grid=True, gridminor=True,
              lonlocator=np.arange(-50, 50, 5), latlocator=5,
              )
    add_ticks(ax)

    image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions