Plotting coordinate data on top of a map in Python matplotlib - python

So, what I am having trouble with is how I am supposed to plot the data I have on top of a global map. I have an array of data, and two arrays of coordinates in latitude and longitude, where each datapoint was taken, but I am not sure of how to plot it on top of a global map. Creating the map itself is not too difficult, I just use:
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
fig = plt.figure(figsize=(10, 8))
m = Basemap(projection='cyl', resolution='c',
llcrnrlat=-90, urcrnrlat=90,
llcrnrlon=-180, urcrnrlon=180, )
m.shadedrelief(scale=0.5)
m.drawcoastlines(color='black')
But the next step is where I am having problems. I have tried doing both a colormesh plot and scatter plot, but they haven't worked so far. How should I go about it so that the data is plotted in the correct coordinate locations for the global map?
Thanks a lot for any help!

Maybe a bit late, but I have this piece of code I used to plot multiple linear plot over a map in Basemap that worked for me.
map = Basemap(projection='cyl', resolution='c',
llcrnrlat=mins[1], urcrnrlat=maxs[1],
llcrnrlon=mins[0], urcrnrlon=50, )
plt.figure(figsize=(15, 15))
for i in range(1259):
filepath = filename[i]
data = pd.read_csv(filepath, index_col=0)
map.plot(data.x,data.y,'k-', alpha=0.1) ### Calling the plot in a loop!!
map.drawcoastlines(linewidth=1)
map.drawcountries(linewidth=0.5, linestyle='solid', color='k' )
plt.show()
The loop calls data from different folders, and I just use the map.plot command to plot. By doing it like that, you can plot all data in the same map.

Related

Geopandas plot shapefile on xarray with same legend

I'm trying to create some maps of precipitation data (xarray) with a shapefile of the region of interest on top. However, when Python plots the figures, I get two seperate figures:
When I open the data in QGIS they do appear on top of each other, so the coordinate systems do check out. Then I have an additional bonus question: I have to create multiple precipitation maps, on for a visual analysis it would be ideal if I could have the same legend (thus the same min/max for the colorbar) for each map. Anyone an idea how to proceed further?
My code so far:
def chirps_to_map(input1, input2, title):
projection = input1 + input2
plt.figure(figsize=(9, 9))
projection['pr'].plot()
watershed.plot()
plt.title(title)
plt.show()
plt.close()
projection.to_netcdf(str(path)+str(title)+".nc")
return projection
This is a case where it's simpler to use the Matplotlib object-oriented API.
A nice general workflow might be
fig, ax = plt.subplot()
gdf.plot(ax=ax) # Plot the vector data on the subplot
raster.plot(ax=ax) # Plot the raster data on the same subplot
Example
First, we get some sample raster+vector data
import xarray as xr
import geopandas as gpd
import matplotlib.pyplot as plt
da = xr.tutorial.load_dataset('ROMS_example').zeta.isel(ocean_time=0)
gdf = gpd.read_file(gpd.datasets.get_path('naturalearth_lowres'))
usa = gdf.loc[gdf['name'].eq('United States of America')]
Next, we plot both of the data on the same AxesSubplot
fig, ax = plt.subplots(figsize=(15, 10))
da.plot.pcolormesh(x='lon_rho', y='lat_rho', ax=ax)
usa.plot(ax=ax, edgecolor='red', color='none')
# Focus on the raster extent
ax.set_xlim(-95, -87)
ax.set_ylim(26, 32)
Bonus: hvPlot way
hvPlot provides a nice unified API for interactive plotting with pandas, xarray, and many other libraries, and might be of interest to people stumbling upon this answer.
Plotting both vector and raster data is rather easy, simply use the * operator.
import hvplot.pandas
import hvplot.xarray
usa.hvplot(geo=True) * da.hvplot.quadmesh(x='lon_rho', y='lat_rho', geo=True)

Plotting gridded data with cartopy using NorthPolarStereo

I'm moving from Basemap to Cartopy and want to plot data for the Arctic Ocean that covers the pole.
I've decided to use the NorthPolarStereo() projection and am happy to use either pcolormesh or contourf. Unfortunately my field of data doesn't show up when I execute the following code:
import cartopy.crs as ccrso
from netCDF4 import Dataset
def import_envisat_field(year,
month):
data_dir = f'/media/robbie/Seagate Portable Drive/Envisat_thickness/{year}/'
file = f'ESACCI-SEAICE-L3C-SITHICK-RA2_ENVISAT-NH25KMEASE2-{year}{month}-fv2.0.nc'
data = Dataset(data_dir+file)
return(data)
# Import data
data = import_envisat_field("2003","02")
# Make plot
fig = plt.figure(figsize=[10, 5])
ax = plt.axes(projection=ccrs.NorthPolarStereo())
ax.add_feature(cartopy.feature.OCEAN, zorder=0)
ax.add_feature(cartopy.feature.LAND, zorder=1, edgecolor='black')
extent = 2500000
ax.set_extent((-extent,
extent,
-extent,
extent),
crs=ccrs.NorthPolarStereo())
ax.gridlines()
lon = np.array(data['lon'])
lat = np.array(data['lat'])
field = np.array(data['sea_ice_thickness'])[0]
print(lon.shape,lat.shape,field.shape)
# This print command gives (432, 432) (432, 432) (432, 432)
plt.pcolormesh(lon, lat, field,zorder=2,
transform=ccrs.NorthPolarStereo())
plt.show()
The data plots in a straightforward way using Basemap, but executing the above code just gives me a nice picture of the Arctic ocean but without my data on it.
I've also tried replacing plt.pcolormesh with ax.pcolormesh but that didn't work either.
Cartopy output:
Basemap output with the same data:
If your data coordinates are latitude and longitude you need to use the PlateCarree transform:
plt.pcolormesh(lon, lat, field,zorder=2, transform=ccrs.PlateCarree())
The transform describes the data coordinates and is independent from the projection you'd like to plot on. See this guide in the Cartopy documentation for more details https://scitools.org.uk/cartopy/docs/latest/tutorials/understanding_transform.html

How do I overlay multiple plot types (bar + scatter) in one figure, sharing x-axis

I am attempting to overlay two graphs, a bar graph and a scatter plot, that share an x-axis, but have separate y-axis on either side of the graph. I have tried using matplotlib, ggplot, and seaborn, but I am having the same problem with all of them. I can graph them both separately, and they graph correctly, but when I try to graph them together, the bar graph is correct, but, only a couple data points from the scatter plot show up. I have zoomed in and can confirm that almost none of the scatter-plot points are appearing.
Here is my code. I have loaded a pandas dataframe and am trying to graph 'dKO_Log2FC' as a bar graph, and 'TTCAAG' as a scatter plot. They both share 'bin_end' postion on the x-axis. If I comment out sns.barplot, the scatter plot graphs perfectly. If I comment out the sns.scatterplot, the bar plot graphs as well. When I graph them together without commenting out either, the bar graph graphs, but only two datapoints from 'TTCAAG' column show up. I have played with with size of the scatter dots, zoomed in, etc, but nothing working.
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
import pandas as pd
file = pd.read_csv('path/to/csv_file.csv')
df = pd.DataFrame(file, columns=['bin_end', 'TTCAAG', 'dKO_Log2FC'])
bin_end = df['bin_end']
TTCAAG = df['TTCAAG']
dKO_Log2FC = df['dKO_Log2FC']
fig, ax = plt.subplots()
ax2 = ax.twinx()
sns.barplot(x=bin_end, y=dKO_Log2FC, ax=ax, color="blue", data=df)
sns.scatterplot(x=bin_end, y=TTCAAG, ax=ax2, color="red", data=df)
plt.title('Histone Position in TS559 vs dKO')
plt.xlabel('Genomic Position (Bin = 1000nt)', fontsize=10)
plt.xticks([])
plt.ylabel('Log2 Fold Change', fontsize=10)
plt.show()
I have have no idea why this the scatter plot won't completely graph. The dataset is quite large, but even when I break it up into smaller bits, only a few scatter points show up.
Here are the graphs
I`m not sure what is the problem, I think is something related to the amount of data or some other data related problem, however as you can plot the data separately, you can generate an image for each plot and then blend the two images to get the required plot.
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
from PIL import Image
npoints=200
xRange=np.arange(0,npoints,1)
randomdata0=np.abs(np.random.normal(0,1,npoints))
randomdata1=np.random.normal(10,1,npoints)
axtick=[7,10,14]
ax2tick=[0,1.5,3]
fig0=plt.figure(0)
ax=fig0.gca()
ax2=ax.twinx()
sns.scatterplot(x=xRange,y=randomdata1,ax=ax)
ax.set_yticks(axtick)
ax.set_ylim([6,15])
ax2.set_yticks(ax2tick)
ax2.set_ylim([0,3.5])
plt.xticks([])
canvas0 = FigureCanvas(fig0)
s, (width, height) = canvas0.print_to_buffer()
X0 = Image.frombytes("RGBA", (width, height), s) #Contains the data of the first plot
fig1=plt.figure(1)
ax=fig1.gca()
ax2=ax.twinx()
sns.barplot(x=xRange,y=randomdata0,ax=ax2)
ax.set_yticks(axtick)
ax.set_ylim([6,15])
ax2.set_yticks(ax2tick)
ax2.set_ylim([0,3.5])
plt.xticks([])
canvas1 = FigureCanvas(fig1)
s, (width, height) = canvas1.print_to_buffer()
X1 = Image.frombytes("RGBA", (width, height), s) #Contains the data of the second plot
plt.figure(13,figsize=(10,10))
plt.imshow(Image.blend(X0,X1,0.5),interpolation='gaussian')
Axes=plt.gca()
Axes.spines['top'].set_visible(False)
Axes.spines['right'].set_visible(False)
Axes.spines['bottom'].set_visible(False)
Axes.spines['left'].set_visible(False)
Axes.set_xticks([])
Axes.set_yticks([])
Just remember to set the twin axes with the same range and ticks in both plots, otherwise, there will be some shift in the images and the numbers will not align.
Hope it helps

How to insert a triangle/contour plot generated with GetDist into a Matplotlib subplot?

I'm doing some analysis on MCMC samples and I'm using the GetDist python package to create my contour plots. However the contour plots are only a part of the whole analysis, and I would like to show some other plots along with the contour plot in the same figure.
I'm using matplotlib to generate all my other plots, so my question is: is there any way to have a GetDist plot in a matplotlib subplot, so that I have a matplotlib figure with multiple plots and a GetDist plot in it?
I'm using GridSpec to split the figure in subplots (and also to split subplots in subsubplots).
I tried to set a particular subplot as the current axis before creating the triangle plot, and I also tried to look at the GetDist source code to find a way to pass the wanted subplot as an argument to GetDist, but with no luck.
Right now, my code looks something like this
import matplotlib.pyplot as plt
import getdist.plots
from matplotlib import gridspec
import numpy as np
import numpy.random
N = 4
# Generate mock random data
chain = np.array([numpy.random.normal(loc=(i+0.5), scale=(i+0.5), size=100000) for i in xrange(N)])
Names = [str(unichr(i+97)) for i in xrange(N)]
Labels = [str(unichr(i+97)) for i in xrange(N)]
Sample = getdist.MCSamples(samples=chain.T, names=Names, labels=Labels)
#Set up plot layout
fig = plt.figure(figsize=(10.5,12.5))
gs = gridspec.GridSpec(3, 2, width_ratios=[2,3], height_ratios=[10,0.5,4], wspace=0.2, hspace=.05)
Lplot = gridspec.GridSpecFromSubplotSpec(N, 1, subplot_spec=gs[0,0], hspace=0.)
Rplot = gridspec.GridSpecFromSubplotSpec(2,1,subplot_spec=gs[0,1], height_ratios=[4,1.265])
Dplot = plt.subplot(gs[2,0:2])
axL = [plt.subplot(Lplot[i]) for i in xrange(N)]
axR = plt.subplot(Rplot[1])
GD = plt.subplot(Rplot[0])
for i in axL+[axR]+[GD]+[Dplot]: i.set_xticks([]); i.set_yticks([])
plt.sca(GD)
# Generate triangle plot
g = getdist.plots.getSubplotPlotter()
g.triangle_plot(Sample, filled=True)
plt.savefig("outfile.pdf", bbox_inches='tight')
I would like to have my contour plot in the "GD" subplot.
Any help?

polar chart : showing yearly trend

I'm trying to reproduce the following chart:
But I'm not sure if's actually possible to create such a plot using Python,R or Tableau.
Here is my first attempt using Plotly in R:
Do you have any suggestion for creating such a chart?
You can use R and de package highcharter to create a plot like this one:
spiderweb plot
the plot js code is in www/highcharts.com/demo/polar-spider
While I was working on creating this plot with matplotlib, someone mentioned that I can create this chart using Excel! in less than 2 minutes, so I didn't complete the code but anyway as I already figure out how should I create different elements of the plot in matplotlib, I put the code here in case anyone wants to create such a thing.
import matplotlib.pyplot as plt
import matplotlib.patches as patches
fig1 = plt.figure()
#Adding grids
for rad in reversed(range(1,10)): #10 is maximum of ranks we need to show
ax1 = fig1.add_subplot(111,aspect = 'equal')
ax1.add_patch(
patches.RegularPolygon(
(0,0), #center of the shape
11, #number of vertices
rad,
fill=False,
ls='--',
))
plt.xlim(xmin = -10,xmax=10)
plt.ylim(ymin = -10,ymax=10)
fig1.show()
#plotting the trend
plt.scatter(xs,ys) #xs = list of x coordinates, the same for ys
for k in range(len(xs)-1):
x, y = [xs[k], xs[k+1]], [ys[k], ys[k+1]]
plt.plot(x, y,color = 'b')
plt.grid(False)
plt.show()
Result plot
(As I said the code doesn't create the whole trends, labels,...but it's pretty much all you need to create the plot)

Categories

Resources