I am trying to make contour maps with a Latitude, Longitude, and a value that is not elevation for my Master's project. I really like the contour plot of irregularly spaced data in matplotlib, but just can't make it work for my data! I get how it generally works. I have over 600 coordinates.
SEE:
https://matplotlib.org/stable/gallery/images_contours_and_fields/irregulardatagrid.html
I have a data frame and just need it to plot some points and those nice contour lines. Please save me! I am a noob. I bet this is super easy for one of you matplotlib pros. Here is what I have:
import matplotlib.pyplot as plt
import matplotlib.tri as tri
import numpy as np
df = pd.read_csv('BI_LT_475_South_Carolina.csv')
Lon = df.iloc[:,0]
Lat = df.iloc[:,1]
CSR = df.iloc[:,2] # What I want to plot instead of elevation.
The csv. looks like this:
Longitude, Latitude, and CSR
Related
Trying to plot a surface using matplotlib. However, the plotted surface has lower grid density than the meshgrid.
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
xgrid = np.arange(0,1,1/100)
ygrid = xgrid.copy()
xx, yy = np.meshgrid(xgrid,ygrid)
fig = plt.figure()
ax = fig.add_subplot(111,projection='3d')
ax.plot_surface(xx,yy,np.square(xx)+np.square(yy))
The meshgrid was defined to have 100 segments in each direction. However, the surface in the figure doesn't have 100 segments. Is there anyway to render the surface with the same density?
Don't worry, you don't have to count the number of segments, so I overlap the plot with a scatter plot with the same points
ax.scatter3D(xx,yy,np.square(xx)+np.square(yy))
Upon zooming in, you can see that each grid of the surface plot has a scatter point in the middle, which shows that the plot_surface changed the density of the points.
Usually it doesn't matter for smooth plots such as these, but I have singular points in my data which sometimes disappear in the surface plot because of this
I'm migrating from basemap to cartopy. One thing I would like to do is plot high/low pressure on a map, such as in basemap. There is a good example on this page of how to do this: https://matplotlib.org/basemap/users/examples.html ("Plot sea-level pressure weather map with labelled highs and lows"). I'm not going to copy and paste the code from this site, but would like to know how to do the same in cartopy. The main thing I can't get my head around is how to do m.xmax and x > m.xmin and y < m.ymax and y > m.ymin in cartopy (some kind of vector transform I'd imagine.
I've had a good look and can't see this particular example translated into something compatible with cartopy. Any help would be welcome!
In order to write an equivalent program using cartopy you need to be able to translate two concepts. The first is finding the extent of a projection, this can be done with the get_extent() method of a GeoAxes:
import cartopy.crs as ccrs
import matplotlib.pyplot as plt
my_proj = ccrs.Miller(central_longitude=180)
ax = plt.axes(projection=my_proj)
xmin, xmax, ymin, ymax = ax.get_extent()
You also need to transform coordinate points from geographic to projection coordinates, which is the function of the transform_points() method of a coordinate reference system instance:
import numpy as np
lons2d, lats2d = np.meshgrid(lons, lats) # lons lats are in degrees
transformed = my_proj.transform_points(ccrs.Geodetic(), lons2d, lats2d)
x = transformed[..., 0] # lons in projection coordinates
y = transformed[..., 1] # lats in projection coordinates
Now you can use the same technique as in the basemap example to filter and plot points, where instead of m.xmin you use xmin etc.
There are of course alternate ways of doing this which have pros and cons relative to the basemap example. If you come up with something nice you can contribute it to the Cartopy gallery.
I am trying to plot some data on an AzimuthalEquidistant projection using cartopy. However, it gives me a couple of problems. First the coastlines no longer show for this type of projection. Not sure if this is my code or a Cartopy problem. I also notice that if I use a ccrs.PlateCarree() transform in the pcolormesh command the coastlines do show but then, presumably, my data is on the wrong type of prejection?
Second I would prefer if the axis boarder was circular after plotting the data, is it possible to use set_extent or some similar function to do this?
The code below should reproduce the problems, the circle shows how I would like the boarder to look.
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import matplotlib.patches as mpatches
clat = 55.0
clon = -8.0
lons = np.arange(clon-15,clon+16,0.5)
lats = np.arange(clat-15,clat+16,0.5)
d = np.random.rand(lons.shape[0],lats.shape[0])
trans = ccrs.AzimuthalEquidistant(central_latitude=clat, central_longitude=clon)
ax = plt.axes(projection=trans)
ax.coastlines(resolution='10m')
CB=ax.pcolormesh(lons-0.25, lats-0.25, d.T,
cmap=plt.cm.viridis, alpha=0.5,
transform=trans)#ccrs.PlateCarree())
p1 = mpatches.Circle((clon,clat), radius=15, color='k', lw=5, fill=False,
transform=trans)
ax.add_patch(p1)
If the data you are plotting is in latitude/longitude coordinates then the correct value for the transform keyword is indeed ccrs.PlateCarree(). This is common gotcha for new users. The transform argument tells cartopy what coordinates your data are in, and is completely independent of the projection you want to plot onto.
To make the plot circular you'll need to set the boundary yourself. The Cartopy documentation have a couple of examples of this: http://scitools.org.uk/cartopy/docs/latest/examples/always_circular_stereo.html and http://scitools.org.uk/cartopy/docs/latest/examples/star_shaped_boundary.html.
I generated the attached image using matplotlib (png format). I would like to use eps or pdf, but I find that with all the data points, the figure is really slow to render on the screen. Other than just plotting less of the data, is there anyway to optimize it so that it loads faster?
I think you have three options:
As you mentioned yourself, you can plot fewer points. For the plot you showed in your question I think it would be fine to only plot every other point.
As #tcaswell stated in his comment, you can use a line instead of points which will be rendered more efficiently.
You could rasterize the blue dots. Matplotlib allows you to selectively rasterize single artists, so if you pass rasterized=True to the plotting command you will get a bitmapped version of the points in the output file. This will be way faster to load at the price of limited zooming due to the resolution of the bitmap. (Note that the axes and all the other elements of the plot will remain as vector graphics and font elements).
First, if you want to show a "trend" in your plot , and considering the x,y arrays you are plotting are "huge" you could apply a random sub-sampling to your x,y arrays, as a fraction of your data:
import numpy as np
import matplotlib.pyplot as plt
fraction = 0.50
x_resampled = []
y_resampled = []
for k in range(0,len(x)):
if np.random.rand() < fraction:
x_resampled.append(x[k])
y_resampled.append(y[k])
plt.scatter(x_resampled,y_resampled , s=6)
plt.show()
Second, have you considered using log-scale in the x-axis to increase visibility?
In this example, only the plotting area is rasterized, the axis are still in vector format:
import numpy as np
import matplotlib.pyplot as plt
x = np.random.uniform(size=400000)
y = np.random.uniform(size=400000)
plt.scatter(x, y, marker='x', rasterized=False)
plt.savefig("norm.pdf", format='pdf')
I have two shapefiles. One is a point feature shapefile, named "point.shp", the other is a polygon shapefile named "polygon.shp". Both I want to add to a map using cartopy.
I managed to add the "polygon.shp", but failed with the "point.shp".
Here's my code:
import matplotlib.pyplot as plt
from cartopy import crs
from cartopy.io.shapereader import Reader
from cartopy.feature import ShapelyFeature
ax = plt.axes(projection=crs.PlateCarree())
# add the polygon file, worked
ax.add_geometries(Reader("polygon.shp").geometries(), crs.PlateCarree(), facecolor='w')
# or(also worked):
ax.add_feature(ShapelyFeature(Reader("polygon.shp").geometries(), crs.PlateCarree(), facecolor='r'))
# but these two ways both failed with the "point.shp"
ax.add_geometries(Reader("point.shp").geometries(), crs.PlateCarree())
# or, this doesn't work neither:
ax.add_feature(ShapelyFeature(Reader("polygon.shp").geometries(), crs.PlateCarree(), facecolor='r'))
Does any one know how to do this, or why, without retrieving all the points' x, y coords and then plotting them?
And with coordinates(x, y values), ax.plot() works, but ax.scatter() fails, why?
Thanks
add_geometries currently turns a geometry into a polygon and then colours it appropriately, which of course means that when you pass points the add_geometries, the polygons are not visible. Potentially cartopy could do a better job of this in the future, but in the meantime, it sounds like you just want to use something like scatter to visualize your data.
You can achieve this by getting the x and y coordinate values out of the geometry and passing these straight on to scatter with the appropriate transform:
import cartopy.crs as ccrs
import cartopy.io
import matplotlib.pyplot as plt
fname = cartopy.io.shapereader.natural_earth(resolution='10m',
category='cultural',
name='populated_places_simple')
plt.figure(figsize=(12, 6))
ax = plt.axes(projection=ccrs.Robinson())
ax.set_title('Populated places of the world.')
ax.coastlines()
points = list(cartopy.io.shapereader.Reader(fname).geometries())
ax.scatter([point.x for point in points],
[point.y for point in points],
transform=ccrs.Geodetic())
plt.show()
HTH