Managing projections when plotting in Geopandas - python

I am using geopandas to draw a map of Italy.
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize = (20,30))
region_map.plot(ax=ax, color='white', edgecolor='black')
plt.xlim([6,19])
plt.ylim([36,47.7])
plt.tight_layout()
plt.show()
And this is the results, after properly defining region_map as a piece of 'geometry' GeoSeries .
However, I am unable to modify the figure aspect ratio, even varying figsize in plt.subplots. Am I missing something trivial, or is it likely to be a geopandas issue?
Thanks

Your source dataset (region_map) is obviously "encoded" in geographic coordinate system (units: lats and lons). It is safe to assume in your case this is WGS84 (EPSG: 4326). If you want your plot to look more like it does in e.g Google Maps, you will have to reproject its coordinates into one of many projected coordinate systems (units: meters) . You can use globally acceptable WEB MERCATOR (EPSG: 3857).
Geopandas makes this as easy as possible. You only need to know the basics of how we deal with coordinate projections in computer science and learning most popular CRSes by their EPSG code.
import matplotlib.pyplot as plt
#If your source does not have a crs assigned to it, do it like this:
region_map.crs = {"init": "epsg:4326"}
#Now that Geopandas what is the "encoding" of your coordinates, you can perform any coordinate reprojection
region_map = region_map.to_crs(epsg=3857)
fig, ax = plt.subplots(figsize = (20,30))
region_map.plot(ax=ax, color='white', edgecolor='black')
#Keep in mind that these limits are not longer referring to the source data!
# plt.xlim([6,19])
# plt.ylim([36,47.7])
plt.tight_layout()
plt.show()
I highly recommend reading official GeoPandas docs regarding managing projections.

Related

Cartopy Image from Grib2 file does not align with Coastlines and Borders in same CRS

This seems like it's going to be something simple that will fix my code but I think I've just looked at the code too much at the moment and need to get some fresh eyes on it. I'm simply trying to bring in a Grib2 file that I've downloaded from NCEP for the HRRR model. According to their information the grid type is Lambert Conformal with the extents of (21.13812, 21.14055, 47.84219, 47.83862) for the latitudes of the corners and (-122.7195, -72.28972, -60.91719, -134.0955) for the longitudes of the corners for the models domain.
Before even trying to zoom into my area of interest I just wanted to simply display an image in the appropriate CRS however when I try to do this for the domain of the model I get the borders and coastlines to fall within that extent but the actual image produced from the Grib2 file is just zoomed into. I've tried to use extent=[my domain extent] but it always seems to crash the notebook I'm testing it in. Here is my code and the associated image that I get from it.
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy
from mpl_toolkits.basemap import Basemap
from osgeo import gdal
gdal.SetConfigOption('GRIB_NORMALIZE_UNITS', 'NO')
plt.figure()
filename='C:\\Users\\Public\\Documents\\GRIB\\hrrr.t18z.wrfsfcf00.grib2'
grib = gdal.Open(filename, gdal.GA_ReadOnly)
z00 = grib.GetRasterBand(47)
meta00 = z00.GetMetadata()
band_description = z00.GetDescription()
bz00 = z00.ReadAsArray()
latitude_south = 21.13812 #38.5
latitude_north = 47.84219 #50
longitude_west = -134.0955 #-91
longitude_east = -60.91719 #-69
fig = plt.figure(figsize=(20, 20))
title= meta00['GRIB_COMMENT']+' at '+meta00['GRIB_SHORT_NAME']
fig.set_facecolor('white')
ax = plt.axes(projection=ccrs.LambertConformal())
ax.add_feature(cartopy.feature.BORDERS, linestyle=':')
ax.coastlines(resolution='110m')
ax.imshow(bz00,origin='upper',transform=ccrs.LambertConformal())
plt.title(title)
plt.show()
Returns Just Grib File
If I change:
ax = plt.axes(projection=ccrs.LambertConformal()
to
ax = plt.axes(projection=ccrs.LambertConformal(central_longitude=-95.5,
central_latitude=38.5,cutoff=21.13)
I get my borders but my actual data is not aligned and it creates what I'm dubbing a Batman plot.
Batman Plot
A similar issue occurs even when I do zoom into the domain and still have my borders present. The underlying data from the Grib file doesn't change to correspond to what I'm trying to get.
So as I've already said this is probably something that is an easy fix that I'm just missing but if not, it would be nice to know what step or what process I'm screwing up that I can learn from so that I don't do it in the future!
Updated 1:
I've added and changed some code and am back to getting only the image to show without the borders and coastlines showing up.
test_extent = [longitude_west,longitude_east,latitude_south,latitude_north]
ax.imshow(bz00,origin='upper',extent=test_extent)
This gives me the following image.
Looks exactly like image 1.
The other thing that I'm noticing which maybe the root cause of all of this is that when I'm printing out the value for plt.gca().get_ylim() and plt.gca().get_xlim() I'm getting hugely different values depending on what is being displayed.
It seems that my problem arises from the fact that the Grib file regardless of whether or not it can be displayed properly in other programs just doesn't play nicely with Matplotlib and Cartopy out of the box. Or at the very least does not with the Grib files that I was using. Which for sake of this perhaps helping others in the future are from the NCEP HRRR model that you can get here or here.
Everything seems to work nicely if you convert the file from Grib2 format to NetCDF format and I was able to get what I wanted with the borders, coastlines, etc. on the map. I've attached the code and the output below to show how it worked. Also I hand picked a single dataset that I wanted to display to test versus my previous code so incase you want to look at the rest of datasets available in the file you'll need to utilize ncdump or something similar to view the information on the datasets.
import numpy as np
from netCDF4 import Dataset
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy
import cartopy.feature as cfeature
from osgeo import gdal
gdal.SetConfigOption('GRIB_NORMALIZE_UNITS', 'NO')
nc_f = 'C:\\Users\\Public\\Documents\\GRIB\\test.nc' # Your filename
nc_fid = Dataset(nc_f, 'r') # Dataset is the class behavior to open the
# file and create an instance of the ncCDF4
# class
# Extract data from NetCDF file
lats = nc_fid.variables['gridlat_0'][:]
lons = nc_fid.variables['gridlon_0'][:]
temp = nc_fid.variables['TMP_P0_L1_GLC0'][:]
fig = plt.figure(figsize=(20, 20))
states_provinces = cfeature.NaturalEarthFeature(category='cultural', \
name='admin_1_states_provinces_lines',scale='50m', facecolor='none')
proj = ccrs.LambertConformal()
ax = plt.axes(projection=proj)
plt.pcolormesh(lons, lats, temp, transform=ccrs.PlateCarree(),
cmap='RdYlBu_r', zorder=1)
ax.add_feature(cartopy.feature.BORDERS, linestyle=':', zorder=2)
ax.add_feature(states_provinces, edgecolor='black')
ax.coastlines()
plt.show()
Final Preview of Map

How to embed a zoomed portion of a FITS image in the same plot with APLpy

I want to embed a zoomed portion of a FITS image in the same plot with APLpy.
But when loading a FITS file with APLpy, there is only a 'FITSFigure' object returned.
fig = aplpy.FITSFigure('tmp.fits', slices=[0,0])
Is it possible to make it work with zoomed_inset_axes like here , or there are some other solution?
You may specify the figure to which to plot with aplpy. You can then get the axes inside the figure.
fig = plt.figure()
aplpyfig = aplpy.FITSFigure('tmp.fits', figure=fig)
axes = fig.get_axes()
From that point onwards you can work with that axes and use any of the methods that matplotlib offers to obtain insets.
Also see this question: Aplpy multiplot dynamic axis sharing

Basemap drawcountries() not working

I'm simply trying to plot a map and add the borders of the countries.
Here is the code snipped:
map=Basemap(projection="lcc",resolution="l",width=1E6,height=1E6,lon_0=9.9167,lat_0=51.5167,fix_aspect=False)
map.drawcounties(zorder=1,color="black")
map.shadedrelief()
map.drawcoastlines(color="black",linewidth=2)
map.drawrivers(linewidth=0.5,color="blue")
map.drawmapboundary()
Everything is working besides the borders....There is also no
Error...it simply does nothing.
What am I doing wrong?
Additionaly the resolution of the map is a bit blurred. Is there any way to boost the resolution?
Thanks for your answers!!!
To draw to borders of the countries you need drawcountries. (Mind the r)
To draw to borders of the counties you need drawcounties.
Note however that the german Bundesländer are no "counties" in the sense of the basemap, so it will not draw them.
To get a higher resolution try resolution="i" in the Basemap initialization.
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
map=Basemap(projection="lcc",resolution="i",width=1E6,height=1E6,
lon_0=9.9167,lat_0=51.5167,fix_aspect=False)
map.drawcountries(zorder=1,color="black", linewidth=1)
map.shadedrelief()
map.drawcoastlines(color="black",linewidth=1.2)
map.drawrivers(linewidth=0.5,color="blue")
map.drawmapboundary()
plt.show()

putting some text to a python plot

I'm trying to do a correlation plot using python, so I'm starting with this basic example
import numpy as np
import matplotlib.pyplot as plt
image=np.random.rand(10,10)
plt.imshow(image)
plt.colorbar()
plt.show()
ok, this script give to me an image like this
so the next step is to put my dataset and not a random matrix, i know it, but I want to put some axis or text in this plot, and to get something like this image
It is a very pretty image using paint (lol), but someone can say me what way I need to follow to do something like thik please (how to search it in google).
Before to post it I think in labels, but also I think that I can assign only one label to each axis
cheers
As #tcaswell said in the comments, the function you want to use is annotate, and the documentation can be found here.
I've given an example below using your code above:
import numpy as np
import matplotlib.pyplot as plt
def annotate_axes(x1,y1,x2,y2,x3,y3,text):
ax.annotate('', xy=(x1, y1),xytext=(x2,y2), #draws an arrow from one set of coordinates to the other
arrowprops=dict(arrowstyle='<->'), #sets style of arrow
annotation_clip=False) #This enables the arrow to be outside of the plot
ax.annotate(text,xy=(0,0),xytext=(x3,y3), #Adds another annotation for the text
annotation_clip=False)
fig, ax = plt.subplots()
image=np.random.rand(10,10)
plt.imshow(image)
plt.colorbar()
#annotate x-axis
annotate_axes(-0.5,10,4.5,10,2.5,10.5,'A') # changing these changes the position of the arrow and the text
annotate_axes(5,10,9.5,10,7.5,10.5,'B')
#annotate y-axis
annotate_axes(-1,0,-1,4,-1.5,2,'A')
annotate_axes(-1,4.5,-1,9.5,-1.5,7.5,'B')
plt.show()
This give the image shown below:

x/y axis graph tool [text file input]

Is there a free tool I can download that will display a graph given a set of x,y coordinates in a text file? Or is there a python module I could use that would give me a quick and dirty view of a graph? Excel is not an option because I do not have it. I would prefer something light weight.
You can try gnuplot.
If you want a python solution, use matplotlib. It is a bit heavy weight, but once setup, it is very simple to use.
If you want something very quick and dirty, you could try ascii-plotter:
http://www.algorithm.co.il/blogs/ascii-plotter/
Otherwise I would go with matplotlib
http://matplotlib.sourceforge.net/
matplotlib in combination with numpy is very powerful:
import numpy as np
import matplotlib.pyplot as plt
x,y = np.loadtxt('xycoords.txt')
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(x,y)
plt.show()
if 'xycoords.txt' is a simple flat file with two columns of numbers representing your x and y data. And of course there are more options for varying levels of data and plotting complexity.

Categories

Resources