pythonmapszoomingcartopyorthographic

How to zoom into a specific latitude in cartopy.crs.Orthographic?


I'm unsure if this is possible, but I'm essentially trying to isolate the Arctic circle latitude (60N) in an orthographic map AND maintain the ellipsoid, not have the zoomed in image be a rectangle/square.

Here is what I have:

fig = plt.figure(figsize=[20, 10])

ax1 = plt.subplot(1, 1, 1, projection=ccrs.Orthographic(0, 90))

for ax in [ax1]:
    ax.coastlines(zorder=2)
    ax.stock_img()
    ax.gridlines()

This gives the north polar view I want, but I would like for it to stop at 60N.

Current yield


Solution

  • To get a zoom-in and square extent of an orthographic map, You need to plot some control points (with .scatter, for example) or specify correct extent in projection coordinates (more difficult). Here is the code to try.

    import cartopy
    import cartopy.crs as ccrs
    import matplotlib.pyplot as plt
    
    fig = plt.figure(figsize=[8, 8])
    
    lonlatproj = ccrs.PlateCarree()
    my_projn = ccrs.Orthographic(central_longitude=0,central_latitude=90)
    
    ax1 = plt.subplot(1, 1, 1, projection=my_projn)
    
    # set `lowlat` as lower limits of latitude to plot some points
    # these points will determine the plot extents of the map
    lowlat = 60 + 2.8   # and get 60
    lons, lats = [-180,-90,0,90], [lowlat,lowlat,lowlat,lowlat]
    # plot invisible points to get map extents
    ax1.scatter(lons, lats, s=0, color='r', transform=lonlatproj)
    #ax1.stock_img()  #uncomment to get it plotted
    ax1.coastlines(lw=0.5, zorder=2)
    ax1.gridlines(lw=2, ec='black', draw_labels=True)
    

    ortho60

    Method 2: By specifying correct extent in projection coordinates

    import cartopy
    import cartopy.crs as ccrs
    import matplotlib.pyplot as plt
    
    fig = plt.figure(figsize=[8, 8])
    
    lonlatproj = ccrs.PlateCarree()
    my_projn = ccrs.Orthographic(central_longitude=0,central_latitude=90)
    
    ax1 = plt.subplot(1, 1, 1, projection=my_projn)
    
    # These 2 lines of code grab extents in projection coordinates
    _, y_min = my_projn.transform_point(0, 60, lonlatproj)  #(0.0, -3189068.5)
    x_max, _ = my_projn.transform_point(90, 60, lonlatproj) #(3189068.5, 0)
    
    # prep extents of the axis to plot map
    pad = 25000
    xmin,xmax,ymin,ymax = y_min-pad, x_max+pad, y_min-pad, x_max+pad
    # set extents with prepped values
    ax1.set_extent([xmin,xmax,ymin,ymax], crs=my_projn) # data/projection coordinates
    
    ax1.stock_img()
    ax1.coastlines(lw=0.5, zorder=2)
    
    # plot other layers of data here using proper values of zorder
    
    # finally, plot gridlines
    ax1.gridlines(draw_labels=True, x_inline=False, y_inline=True,
                  color='k', linestyle='dashed', linewidth=0.5)
    plt.show()
    

    img2

    Method 3 Plot the map with circular boundary

    The runnable code:

    import cartopy.crs as ccrs
    import matplotlib.pyplot as plt
    import matplotlib.path as mpath
    import numpy as np
    
    r_limit = 3214068.5 #from: ax.get_ylim() of above plot
    
    # some settings  
    lonlatproj = ccrs.PlateCarree()
    my_projn = ccrs.Orthographic(central_longitude=0, central_latitude=90)
    fig = plt.figure(figsize=[8, 8])
    ax = plt.subplot(1, 1, 1, projection=my_projn)
    
    # add bluemarble image
    ax.stock_img()
    # add coastlines
    ax.coastlines(lw=0.5, color="black", zorder=20)
    
    
    # draw graticule (of meridian and parallel lines)
    gls = ax.gridlines(draw_labels=True, crs=ccrs.PlateCarree(), lw=3, color="gold",
            y_inline=True, xlocs=range(-180,180,30), ylocs=range(-80,91,10))
    
    
    # add extra padding to the plot extents
    r_extent = r_limit*1.0001
    ax.set_xlim(-r_extent, r_extent)
    ax.set_ylim(-r_extent, r_extent)
    
    
    # Prep circular boundary
    circle_path = mpath.Path.unit_circle()
    circle_path = mpath.Path(circle_path.vertices.copy() * r_limit,
                               circle_path.codes.copy())
    
    #set circle boundary
    ax.set_boundary(circle_path)
    #hide frame
    ax.set_frame_on(False)  #hide the rectangle frame
    
    plt.show()
    

    ortho_N_circle