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

Label lat lon gridlines parallel to intersection angle at plot boundary #1560

Closed
friedrichknuth opened this issue May 14, 2020 · 5 comments
Closed
Milestone

Comments

@friedrichknuth
Copy link

friedrichknuth commented May 14, 2020

Description

Enhancement to orient lat lon gridline labels parallel to the gridlines as they intersect the plot boundary. Something like the labels seen here:

plot

[source]

Code

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

rotated_crs = ccrs.RotatedPole(pole_longitude=120.0, pole_latitude=70.0)

ax = plt.axes(projection=rotated_crs)
ax.set_extent((-6, 3, 48, 58), crs=ccrs.PlateCarree())
ax.coastlines(resolution='50m')

gl = ax.gridlines(draw_labels=True,x_inline=False, y_inline=False)
plt.show()

Cartopy version
0.18.0

Result

here

Notice the inconsistent orientation of gridline labels, which can get somewhat messy. It is possible to disable the automated orientation feature with gl.rotate_labels = False, however, I can't seem to find a method to align the label angle so that the text is parallel to the gridline as it intersects the plot boundary, as seen in the plot under the description.

Additional Information

I think the logic for this might be here

def _segment_angle_to_text_specs(self, angle, lonlat):

This issue was briefly discussed here ##1089 (comment), but unsure if it has been addressed further.

@ocefpaf
Copy link
Member

ocefpaf commented May 14, 2020

@dopplershift I believe that the behavior @friedrichknuth proposes here should be the default. It is quite odd to have different angle on the same side of the labels. What do you think?

@lacstorm
Copy link

This kind of gridline labels look much better!!

@icetianli
Copy link

By changing the rotation and rotation_mode parameters in xlabel_style and ylabel_style as follows can make the orientation of gridline labels in the sample region to be consistently horizontal:

gl.xlabel_style = {'size': 12, 'color': 'black', 'rotation': 0, 'rotation_mode': 'anchor'}
gl.ylabel_style = {'size': 12, 'color': 'black', 'rotation': 0, 'rotation_mode': 'anchor'}

This produces the map:
image

This at least makes the orientation of labels in the sample region to be consistent, but not sure how to make the text parallel to the gridline mentioned by @friedrichknuth.

If change the map extent to a larger region, for example:

import matplotlib.pyplot as plt
import cartopy.crs as ccrs
rotated_crs = ccrs.RotatedPole(pole_longitude=120.0, pole_latitude=70.0)
ax = plt.axes(projection=rotated_crs)
ax.set_extent((-10, 10, 50, 60), crs=ccrs.PlateCarree())
ax.coastlines(resolution='50m')
gl = ax.gridlines(draw_labels=True,x_inline=False, y_inline=False)
ticker_locator = 4
gl.xlocator = ticker.MultipleLocator(ticker_locator)
gl.ylocator = ticker.MultipleLocator(ticker_locator)
gl.xformatter = LongitudeFormatter()
gl.yformatter = LatitudeFormatter()
gl.xlabel_style = {'size': 12, 'color': 'black', 'rotation': 0, 'rotation_mode': 'anchor'}
gl.ylabel_style = {'size': 12, 'color': 'black', 'rotation': 0, 'rotation_mode': 'anchor'}

The above code produces map:
image

It has an unwanted label 16E on the right axis and its orientation is not horizontal anymore, looks like the rotation in xlabel_style and ylabel_style just can't change the orientation of all gridline labels at one time.

Also, I would like to ask if there's a way to label only latitude or longitude on one side, instead of a mixture of both as the case of the right axis in the second figure.

@friedrichknuth
Copy link
Author

friedrichknuth commented Mar 30, 2021

Regarding @icetianli's question

Is there's a way to label only latitude or longitude on one side, instead of a mixture of both as the case of the right axis in the second figure.

A possible solution is to modify the axis with different sets of lon/lat gridlines to be labeled.

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

def add_gridline_labels(ax,
                        labels_set    = None,
                        side          = None): # 'top', 'bottom', 'left', 'right'
    
    gl = ax.gridlines(draw_labels=True,x_inline=False, y_inline=False)
    gl.xlabel_style = {'size': 12, 'color': 'black', 'rotation': 0, 'rotation_mode': 'anchor'}
    gl.ylabel_style = {'size': 12, 'color': 'black', 'rotation': 0, 'rotation_mode': 'anchor'}
    
    if side == 'top':
        gl.xlocator = ticker.FixedLocator(labels_set)
        gl.ylines = False
        gl.top_labels = True
        gl.bottom_labels = False
        gl.left_labels = False
        gl.right_labels = False
    elif side == 'bottom':
        gl.xlocator = ticker.FixedLocator(labels_set)
        gl.ylines = False
        gl.top_labels = False
        gl.bottom_labels = True
        gl.left_labels = False
        gl.right_labels = False
    elif side == 'left':
        gl.ylocator = ticker.FixedLocator(labels_set)
        gl.xlines = False
        gl.top_labels = False
        gl.bottom_labels = False
        gl.left_labels = True
        gl.right_labels = False
    elif side == 'right':
        gl.ylocator = ticker.FixedLocator(labels_set)
        gl.xlines = False
        gl.top_labels = False
        gl.bottom_labels = False
        gl.left_labels = False
        gl.right_labels = True
        
    gl.xformatter = LongitudeFormatter()
    gl.yformatter = LatitudeFormatter()

    return ax

fig = plt.figure()

rotated_crs = ccrs.RotatedPole(pole_longitude=120.0, pole_latitude=70.0)
ax = plt.axes(projection=rotated_crs)
ax.set_extent((-10, 10, 50, 60), crs=ccrs.PlateCarree())
ax.coastlines(resolution='50m')

add_gridline_labels(ax, 
                    labels_set = [-4, 0, 4, 8, 12,16],
                    side = 'top')

add_gridline_labels(ax, 
                    labels_set = [-12, -8, -4, 0, 4],
                    side = 'bottom')

add_gridline_labels(ax, 
                    labels_set = [52, 56, 60],
                    side = 'left')

add_gridline_labels(ax, 
                    labels_set = [48, 52, 56],
                    side = 'right')

which produces

fig

@QuLogic
Copy link
Member

QuLogic commented Sep 10, 2021

Closed by #1537

@QuLogic QuLogic closed this as completed Sep 10, 2021
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

5 participants