Show grid ticks on geographic plots
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())

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

Proplot version
0.6.4
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]
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).
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))

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)
