Search code examples
matplotlibcartopy

Facing weird problem when trying to plot simple lat/ lon points


I have following dataframe (corresponding csv is hosted here: http://www.sharecsv.com/s/3795d862c1973efa311d8a770e978215/t.csv)

            lat     lon
count   6159.000000     6159.000000
mean    37.764859   -122.355491
std     0.028214    0.038874
min     37.742200   -122.482783
25%     37.746317   -122.360133
50%     37.746417   -122.333717
75%     37.785825   -122.331300
max     37.818133   -122.331167

Following code plots correctly:

    test_ax = plt.axes(projection=ccrs.Mercator())
    test_ax.plot(test_df['lon'], test_df['lat'], color="blue", linewidth=4, alpha=1.0,
            transform=ccrs.Geodetic())
    plt.show()

Plot1

But if I take one subset, it doesn't:

    test_ax = plt.axes(projection=ccrs.Mercator())
    test_ax.plot(test_df['lon'][:1001], test_df['lat'][:1001], color="blue", linewidth=4, alpha=1.0,
            transform=ccrs.Geodetic())
    plt.show()

Plot2

But does so with another subset.

    test_ax = plt.axes(projection=ccrs.Mercator())
    test_ax.plot(test_df['lon'][:3501], test_df['lat'][:3501], color="blue", linewidth=4, alpha=1.0,
            transform=ccrs.Geodetic())
    plt.show()

Plot3

I am pretty sure I am doing something stupid, but I am just unable to figure the reason for this behaviour.

Edit:

On further experimentation I found that if I set the extent of map manually to include 0 meridian, the plot for the subset :1001, which wasn't showing earlier starts showing (the blue dot near San Francisco).

    test_ax = plt.axes(projection=ccrs.Mercator())
    test_ax.plot(test_df['lon'][:1001], test_df['lat'][:1001], color="blue", linewidth=4, alpha=1.0, transform=ccrs.Geodetic())
    test_ax.coastlines()
    test_ax.set_extent([-130, 0, 30, 40], crs=ccrs.Geodetic())
    test_ax.gridlines(draw_labels=True)
    plt.show()

Plot4

Edit: with reproducible example

(For jupyter notebook)

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

df_csv_url = 'http://www.sharecsv.com/dl/76dd767525a37180ca54cd1d9314b9dc/t1.csv'
test_df = pd.read_csv(df_csv_url)
figure_params = { 'width': 9.6, 'height': 5.4 }

fig = plt.figure(
        figsize=(figure_params["width"], figure_params["height"])        
    )
test_ax = fig.add_axes((0, 0.5, 0.5, 0.5), projection=ccrs.Mercator(), label="map1")
test_ax.plot(test_df['lon'], test_df['lat'], color="blue", linewidth=4, alpha=1.0, transform=ccrs.Geodetic())
test_ax.coastlines()
test_ax.gridlines(draw_labels=True)
test_ax.set_title("Path doesn\'t show", y=1.5)

# Including 0 meridian in extent shows the path
test_ax1 = fig.add_axes((0, 0, 0.5, 0.5), projection=ccrs.Mercator(), label="map2")
test_ax1.plot(test_df['lon'], test_df['lat'], color="blue", linewidth=4, alpha=1.0, transform=ccrs.Geodetic())
test_ax1.set_extent([-130, 0, 30, 40], crs=ccrs.Geodetic())
test_ax1.coastlines()
test_ax1.gridlines(draw_labels=True)
test_ax1.set_title("Path shows (blue dot near San Francisco)", y=1.1)

plt.show()

Plot5

Edit

(with simplified reproducible example)

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import cartopy.crs as ccrs

test_df = pd.DataFrame()
test_df['lon'] = np.linspace(-120, -60, num=1000)
test_df['lat'] = 38

test_df1 = pd.DataFrame()
test_df1['lon'] = np.linspace(-120, -60, num=1001)
test_df1['lat'] = 38


fig = plt.figure()

meridian=0

test_ax = fig.add_axes((0, 0, 1, 0.6), projection=ccrs.Mercator())
test_ax.plot(test_df['lon'], test_df['lat'], color="blue", linewidth=4, alpha=1.0, transform=ccrs.Geodetic())
test_ax.coastlines()
test_ax.set_extent((-125, meridian, 36, 38))
gl = test_ax.gridlines(draw_labels=True)
gl.xlabels_top = False
gl.ylabels_left = False
test_ax.set_title('Path with {} points, eastern edge={}'.format(len(test_df),meridian))


test_ax1 = fig.add_axes((0, 0.7, 1, 0.6), projection=ccrs.Mercator())
test_ax1.plot(test_df1['lon'], test_df1['lat'], color="red", linewidth=4, alpha=1.0, transform=ccrs.Geodetic())
test_ax1.coastlines()
test_ax1.set_extent((-125, meridian, 36, 38))
gl1 = test_ax1.gridlines(draw_labels=True)
gl1.xlabels_top = False
gl1.ylabels_left = False
test_ax1.set_title('Path with {} points, eastern edge={}'.format(len(test_df1),meridian))


meridian=-10

test_ax2 = fig.add_axes((0, 1.4, 1, 0.6), projection=ccrs.Mercator())
test_ax2.plot(test_df['lon'], test_df['lat'], color="black", linewidth=4, alpha=1.0, transform=ccrs.Geodetic())
test_ax2.coastlines()
test_ax2.set_extent((-125, -10, 36, 38))
gl2 = test_ax2.gridlines(draw_labels=True)
gl2.xlabels_top = False
gl2.ylabels_left = False
test_ax2.set_title('Path with {} points, eastern edge={}'.format(len(test_df),meridian))


test_ax3 = fig.add_axes((0, 2.1, 1, 0.6), projection=ccrs.Mercator())
test_ax3.plot(test_df1['lon'], test_df1['lat'], color="green", linewidth=4, alpha=1.0, transform=ccrs.Geodetic())
test_ax3.coastlines()
test_ax3.set_extent((-125, -10, 36, 38))
gl3 = test_ax3.gridlines(draw_labels=True)
gl3.xlabels_top = False
gl3.ylabels_left = False
test_ax3.set_title('Path with {} points, eastern edge={}'.format(len(test_df1),meridian))

plt.show()

enter image description here


Solution

  • I have been able to find another workaround. If the points are transformed prior to using the plot function (instead of passing the transform parameter), it works.

    import numpy as np
    import pandas as pd
    import matplotlib.pyplot as plt
    import cartopy.crs as ccrs
    
    test_df = pd.DataFrame()
    test_df['lon'] = np.linspace(-120, -60, num=1000)
    test_df['lat'] = 38
    
    test_df1 = pd.DataFrame()
    test_df1['lon'] = np.linspace(-120, -60, num=1001)
    test_df1['lat'] = 38
    
    
    fig = plt.figure()
    
    meridian=0
    
    test_ax = fig.add_axes((0, 0, 1, 0.6), projection=ccrs.Mercator())
    test_ax.plot(test_df['lon'], test_df['lat'], color="blue", linewidth=4, alpha=1.0, transform=ccrs.Geodetic())
    test_ax.coastlines()
    test_ax.set_extent((-125, meridian, 36, 38))
    gl = test_ax.gridlines(draw_labels=True)
    gl.xlabels_top = False
    gl.ylabels_left = False
    test_ax.set_title('Path with {} points, eastern edge={}'.format(len(test_df),meridian))
    
    
    test_ax1 = fig.add_axes((0, 0.7, 1, 0.6), projection=ccrs.Mercator())
    test_ax1.plot(test_df1['lon'], test_df1['lat'], color="red", linewidth=4, alpha=1.0, transform=ccrs.Geodetic())
    test_ax1.coastlines()
    test_ax1.set_extent((-125, meridian, 36, 38))
    gl1 = test_ax1.gridlines(draw_labels=True)
    gl1.xlabels_top = False
    gl1.ylabels_left = False
    test_ax1.set_title('Path with {} points, eastern edge={}'.format(len(test_df1),meridian))
    
    
    meridian=-10
    
    test_ax2 = fig.add_axes((0, 1.4, 1, 0.6), projection=ccrs.Mercator())
    test_ax2.plot(test_df['lon'], test_df['lat'], color="black", linewidth=4, alpha=1.0, transform=ccrs.Geodetic())
    test_ax2.coastlines()
    test_ax2.set_extent((-125, -10, 36, 38))
    gl2 = test_ax2.gridlines(draw_labels=True)
    gl2.xlabels_top = False
    gl2.ylabels_left = False
    test_ax2.set_title('Path with {} points, eastern edge={}'.format(len(test_df),meridian))
    
    
    test_ax3 = fig.add_axes((0, 2.1, 1, 0.6), projection=ccrs.Mercator())
    test_ax3.plot(test_df1['lon'], test_df1['lat'], color="green", linewidth=4, alpha=1.0, transform=ccrs.Geodetic())
    test_ax3.coastlines()
    test_ax3.set_extent((-125, -10, 36, 38))
    gl3 = test_ax3.gridlines(draw_labels=True)
    gl3.xlabels_top = False
    gl3.ylabels_left = False
    test_ax3.set_title('Path with {} points, eastern edge={}'.format(len(test_df1),meridian))
    
    
    test_ax4 = fig.add_axes((0, 2.8, 1, 0.6), projection=ccrs.Mercator())
    # Instead of transforming within the plot function, transform and then plot
    transformed_points = ccrs.Mercator().transform_points(ccrs.Geodetic(), test_df1['lon'].values, test_df1['lat'].values)
    test_ax4.plot([p[0] for p in transformed_points], [p[1] for p in transformed_points], color="green", linewidth=4, alpha=1.0)
    test_ax4.coastlines()
    test_ax4.set_extent((-125, -10, 36, 38))
    gl3 = test_ax4.gridlines(draw_labels=True)
    gl3.xlabels_top = False
    gl3.ylabels_left = False
    test_ax4.set_title('Path with {} prior transformed points, eastern edge={}'.format(len(test_df1),meridian))
    
    
    plt.show()
    
    

    enter image description here