Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Show grid ticks on geographic plots #227

Open
zxdawn opened this issue Sep 26, 2020 · 4 comments · May be fixed by #253
Open

Show grid ticks on geographic plots #227

zxdawn opened this issue Sep 26, 2020 · 4 comments · May be fixed by #253
Labels
Milestone

Comments

@zxdawn
Copy link

zxdawn commented Sep 26, 2020

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

@zxdawn
Copy link
Author

zxdawn commented Sep 26, 2020

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]

@lukelbd lukelbd linked a pull request Jun 30, 2021 that will close this issue
@lukelbd
Copy link
Collaborator

lukelbd commented Jul 12, 2021

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).

@lukelbd lukelbd added this to the Version 0.10 milestone Jul 21, 2021
@kM-Stone
Copy link

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

@syrte
Copy link

syrte commented Jan 14, 2022

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

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants