Plotting contour Maps on Basemap for Python 2.7 - python

I had a question regarding Matplotlib and Basemap in python. I am trying to take a list of latitudes and longitudes and temperatures and plot them on a contour map. I had relative success when I put in data for Alaska. It plotted my data no problem. When I tried putting in data for Alabama, it outputted a completely random map filled with a bunch of garbage data points. I think this may be a problem with the map projection as I subbed out the Alaska data that gave me a working map for the Alabama data that gave me random data. It could be that the differences in coordinates are distorting the temperature values. I'm not exactly sure.
Thanks,
Scott
Here is an example of the Alabama data(first column:ICAO, second column: lat, third column: lon,4th column:temp):
K8A0,34.14,-86.15, 64
KALX,32.55,-85.58, 65
K79J,31.19,-86.24, 75
KANB,33.35,-85.51, 69
import urllib2
from urllib2 import urlopen
import cookielib
from cookielib import CookieJar
import time
from Tkinter import *
import numpy as np
import pandas as pd
from matplotlib.mlab import griddata
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
from scipy import interpolate
import scipy
from matplotlib.colors import Normalize
FN = '/Users/scottreinhardt/Desktop/airportcodetext1.txt'
data = np.genfromtxt(FN,dtype=None,names=["ICAO","Lat","Lon","Temp"],skip_header=1,delimiter=',')
m = Basemap(projection = 'cyl',llcrnrlon = -73.5, llcrnrlat = 41, urcrnrlon = -81, urcrnrlat = 30, resolution='h')
# data from http://water.weather.gov/precip/
# create polar stereographic Basemap instance.
plt.figure(num=None, figsize=(25, 25), dpi=25,edgecolor='k')
xs = np.array(data["Lon"])
ys = np.array(data["Lat"])
z = np.array(data["Temp"])
#x = x + np.random.normal(scale=1e-8, size=x.shape)
#y = y + np.random.normal(scale=1e-8, size=y.shape)
#numcols, numrows = 300, 300
xi = np.linspace(data["Lat"].min(), data["Lat"].max(), 150)
yi = np.linspace(data["Lon"].min(), data["Lon"].max(), 150)
xi, yi = np.meshgrid(xi, yi)
# Set up a regular grid of interpolation points
#xi, yi = np.linspace(xs.min(), xs.max(), 500), np.linspace(ys.min(), ys.max(), 500)
#xi, yi = np.meshgrid(xi, yi)
# Interpolate
rbf = scipy.interpolate.Rbf(data["Lat"], data["Lon"], data["Temp"], function='linear')
zi = rbf(xi, yi)
plt.imshow(zi, vmin=z.min(), vmax=z.max(), origin='lower',
extent=[xs.min(), xs.max(), ys.min(), ys.max()])
plt.colorbar()
plt.show()

Related

Interpolation for 3D surface

I have my data in an ndarray of size 21 by 30; it contains velocity values at each point. I have made a 3D surface plot to visualize it but the data is not so smooth. In order to interpolate the data, so that I have smooth peaks, I tried the function griddata but it does not seem to work.
Here is my code:
import numpy as np
import matplotlib.pyplot as plt
vel = np.genfromtxt(r'velocity.txt')
x = np.arange(0, 21, 1)
y = np.arange(0, 30, 1)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
X,Y = np.meshgrid(x, y)
surf = ax.plot_surface(x, y, vel, cmap="RdBu")
fig.set_size_inches(10, 10)
plt.show()
From what I can understand from the question, what you need to do is grid interpolation. It is possible to do that using RegularGridInterpolator from scipy here. Just make a finer mesh, interpolate on that grid, and plot.
import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import RegularGridInterpolator
vel=np.random.random((21,30))
#grid old
x=np.arange(0,21,1)
y=np.arange(0,30,1)
grid_old=(x,y)
#grid new
# the limits of the interpolated x and y val have to be less than the original grid
x_new=np.arange(0.1,19.9,0.1)
y_new=np.arange(0.1,28.9,0.1)
grid_new = np.meshgrid(x_new, y_new)
grid_flattened = np.transpose(np.array([k.flatten() for k in grid_new]))
#Interpolation onto a finer grid
grid_interpol = RegularGridInterpolator(grid_old,vel,method='linear')
vel_interpol = grid_interpol(grid_flattened)
#Unflatten the interpolated velocities and store into a new variable.
index=0
vel_new=np.zeros((len(x_new),len(y_new)))
for i in range(len(x_new)):
for j in range(len(y_new)):
vel_new[i,j] =vel_interpol[index]
index+=1
fig=plt.figure()
ax=fig.add_subplot(111,projection='3d')
surf=ax.plot_surface(grid_new[0],grid_new[1],vel_new.T, cmap="RdBu")
fig.set_size_inches(10,10)
plt.show()

Fit of intensity distribution does not work

So im sitting here and don't know how to fit the right function for my Intensity distribution of a doubleslit experiment. I tried so much but I don't know how it works. The x,y data are more than 1000 values.
Here is my Plot:
And here's how it should look like:
And that is my code to that:
import matplotlib.patches as mp
import matplotlib.pyplot as plt
import numpy as np
from scipy import optimize
from scipy.optimize import curve_fit
import pandas as pd
import math
data = pd.read_csv('TEM00-Doppelspalt-Short.txt',sep='\s+',header=None)
data = pd.DataFrame(data)
x = data[1]
y = data[2]
def expf(i0,g,k,y0,d):
return i0*((np.sin(g*(k-y0)))/(g*(k-y0)))**2*np.cos(d*(k-y0))**2
popt, pcov =curve_fit(expf, x, y, p0 = (13, 20, 2, 4))
g,k,y0,d = popt
plt.figure(figsize = (8,6), dpi = 600)
plt.xlabel(r'Wavelength [$\mu$m]',fontsize=12)
plt.ylabel('Value [Cnts]', fontsize=12)
plt.plot(x, y,'ko')
plt.plot(x, expf(x,g,k,y0,d))
a_patch=mp.Patch(color='k', label="$TEM_{00}$ Doubleslit ShortMode")
plt.legend(handles=[a_patch],loc="upper left")
plt.show()
Here is my datafile:
Data File of Intensity

Contours Not Plotting

I'm trying to plot contours of ash deposit depth using Basemap and matplotlib. For some reason, my contours aren't showing up and I can't see what I'm missing.
import os
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from netCDF4 import Dataset
from mpl_toolkits.basemap import Basemap
url = "BigAsh_DepoThick.nc"
data = Dataset(url, mode="r")
times = data.variables["time"]
lats = data.variables["Lat"][:]
lons = data.variables["Lon"][:]
depths = data.variables["DepoThick"][:,:,:]
fig=plt.figure(figsize=(16,8))
# Create the map
m = Basemap(llcrnrlon=-150,llcrnrlat=10,urcrnrlon=-60,urcrnrlat=70,
projection='merc', resolution ='l')
m.drawcoastlines(linewidth=1)
m.drawstates(linewidth=1)
m.drawcountries(linewidth=1)
m.fillcontinents(color='gray')
plons, plats = np.meshgrid(lons, lats)
x, y = m(plons, plats)
cp = m.contourf(x, y, depths[-1,:,:], 100)
cbar = plt.colorbar(cp)
cbar.set_label("Ash Depth [mm]")
plt.title("Mt. St. Helens Ash Depth")
plt.show()

Python Point density plots in polar stereographic projection

I have a point cloud of magnetization directions with azimut (declination between 0° and 360°) and inclination between 0° and 90°. I display these points in a polar azimuthal equidistant projection (using matplotlib basemap). That means 90° inclination will point directly in the center of the plot and the declination runs clockwise.
My problem is that I want to also plot isolines around these point clouds, which should represent where the highest density of point/directions is located. What is the easiest way to do this? Nice would be to mark the isoline which encircles 50% is my data. If Iam not mistaken - this would be the median.
So far I've fiddled around with gaussian_kde and the outlier detection of sklearn (1 and 2), but the results are not as expected.
Any ideas?
Edit #1:
First gaussian_kde
import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as stats
from mpl_toolkits.basemap import Basemap
m = Basemap(projection='spaeqd',boundinglat=0,lon_0=180,resolution='l',round=True)
m.drawparallels(np.arange(-80.,1.,10.),labels=[False,True,True,False])
m.drawmeridians(np.arange(-180.,181.,30.),labels=[True,False,False,True])
#data
x, y = m(m1,-m2) #m2 is negative because I to plot in the southern hemisphere!
#set up the grid for evaluation of the KDE
yi = np.arange(0,360.1,1)
xi = np.arange(-90,1,1)
xx,yy = np.meshgrid(xi,yi)
X, Y = m(xx,yy) # to have it in my basemap projection
#setup the gaussian kde and evaluate it
#pretty much similiar to the scipy.stats docs
positions = np.vstack([X.ravel(), Y.ravel()])
values = np.vstack([x, y])
kernel = stats.gaussian_kde(values)
Z = np.reshape(kernel(positions).T, X.shape)
#plot orginal points and probaility density function
ax = plt.gca()
ax.scatter(x,y,c = 'Crimson')
TOT = ax.contour(X,Y,Z,cmap=plt.cm.Reds)
plt.show()
Then sklearn:
import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as stats
from mpl_toolkits.basemap import Basemap
from sklearn import svm
from sklearn.covariance import EllipticEnvelope
m = Basemap(projection='spaeqd',boundinglat=0,lon_0=180,resolution='l',round=True)
m.drawparallels(np.arange(-80.,1.,10.),labels=[False,True,True,False])
m.drawmeridians(np.arange(-180.,181.,30.),labels=[True,False,False,True])
#data
x, y = m(m1,-m2) #m2 is negative because I to plot in the southern hemisphere!
#Similar to examples in sklearn docs
outliers_fraction = 0.5
oneclass_svm = svm.OneClassSVM(nu=0.95 * outliers_fraction + 0.05,\
kernel="rbf", gamma=0.1,verbose=True)
#seup grid
yi = np.arange(0,360.1,1)
xi = np.arange(-90,1,1)
R,T = np.meshgrid(xi,yi)
xx, yy = m(T,R)
x, y = m(m1,-m2)
#standardize data as suggested by docs
x_std = (x-x.mean())/x.std()
y_std = (y-y.mean())/y.std()
values = np.vstack([x_std, y_std])
#fit data and calculate threshold - this should mark my median - according to value of outliers_fraction
oneclass_svm.fit(values.T)
y_pred = oneclass_svm.decision_function(values.T).ravel()
threshold = stats.scoreatpercentile(y_pred, 100 * outliers_fraction)
y_pred = y_pred > threshold
#Target vector for evaluation
TV = np.c_[xx.ravel(), yy.ravel()]
TV = (TV-TV.mean(axis=0))/TV.std(axis=0) #must be standardized as well
# evaluation - This is now shifted in the plot ad does not fit my point cloud anymore - because of the standadrization
Z = oneclass_svm.decision_function(TV)
Z = Z.reshape(xx.shape)
#plotting - very similar to the example in the docs
ax = plt.gca()
ax.contourf(xx, yy, Z, levels=np.linspace(Z.min(), threshold, 7), \
cmap=plt.cm.Blues_r)
ax.contour(xx, yy, Z, levels=[threshold],
linewidths=2, colors='red')
ax.contourf(xx, yy, Z, levels=[threshold, Z.max()],
colors='orange')
ax.scatter(x, y,s=30, marker='s',c = 'RoyalBlue',label = 'Mr')
plt.show()
The EllipticEvelope works, but it is not that want I want.
Ok, I think I might found a solution. But it should not work in every case. It should fail in my opinion when the data is multimodal distributed.
Nevertheless, here is my though process:
So the Probalibity Density Function (PDF) is essentially the same as a continuous histogram. So I used np.percentile to calculate the upper and lower 25% percentile of both vectors. The I've searched for the value of the PDF at these perctiles and this should be the Isoline that i want.
Of course this should also work in the polar stereographic (or any other) projection.
Here is a litte example code of two gamma distributed data sets in a crossplot:
import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as stats
from scipy.interpolate import LinearNDInterpolator, RegularGridInterpolator
#generate some data
x = np.random.gamma(10,0.8,1e4)
y = np.random.gamma(4,0.3,1e4)
#set up the data and grid for the 2D PDF
values = np.vstack([x,y])
pdf_x = np.linspace(x.min(),x.max(),1e2)
pdf_y = np.linspace(y.min(),y.max(),1e2)
X,Y = np.meshgrid(pdf_x,pdf_y)
kernel = stats.gaussian_kde(values)
#evaluate the PDF at every grid location
positions = np.vstack([X.ravel(), Y.ravel()])
Z = np.reshape(kernel(positions).T, X.shape)
#upper and lower quartiles of x and y data
xql = np.percentile(x,25)
xqu = np.percentile(x,75)
yql = np.percentile(y,25)
yqu = np.percentile(y,75)
#set up the interpolator - I could also use RegularGridInterpolator - should be faster
Interp = LinearNDInterpolator((X.flatten(),Y.flatten()),Z.flatten())
#1D example to illustrate what I mean
plt.figure()
kernel2 = stats.gaussian_kde(x)
plt.hist(x,30,normed=True)
plt.plot(pdf_x,kernel2(pdf_x),'r--',linewidth=2)
#plot vertical lines at the upper and lower quartiles
plt.vlines(np.percentile(x,25),0,0.2,color='red')
plt.vlines(np.percentile(x,75),0,0.2,color='red')
#Scatterplot / Crossplot with PDF and 25 and 75% isolines
plt.figure()
plt.scatter(x,y)
#search for the isolines defining the upper and lower quartiles
#the lower quartiles isoline should encircle 75% of the data
levels = [Interp(xql,yql),Interp(xqu,yqu)]
plt.contour(X,Y,Z,levels=levels,colors='orange')
plt.show()
To finish up I will give a quick example of what it looks in a polar stereographic projection:
import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as stats
from scipy.interpolate import LinearNDInterpolator
from mpl_toolkits.basemap import Basemap
#set up the coordinate projection
m = Basemap(projection='spaeqd',boundinglat=0,lon_0=180,\
resolution='l',round=True,suppress_ticks=True)
parallelGrid = np.arange(-80.,1.,10.)
meridianGrid = np.arange(-180.0,180.1,30)
m.drawparallels(parallelGrid,labels=[False,False,False,False])
m.drawmeridians(meridianGrid,labels=[False,False,False,False],labelstyle='+/-',fmt='%i')
#Found this on stackoverflow - labels it exactly how I want it
ax = plt.gca()
ax.text(0.5,1.025,'N',transform=ax.transAxes,\
horizontalalignment='center',verticalalignment='bottom',size=25)
for para in np.arange(30,360,30):
x= (1.1*0.5*np.sin(np.deg2rad(para)))+0.5
y= (1.1*0.5*np.cos(np.deg2rad(para)))+0.5
ax.text(x,y,u'%i\N{DEGREE SIGN}'%para,transform=ax.transAxes,\
horizontalalignment='center',verticalalignment='center')
#generate some data
x = np.random.randint(180,225,size=15)
y = np.random.randint(30,40,size=15)
#into projection
x,y = m(x,-y)
values = np.vstack([x,y])
pdf_x = np.arange(0,361,1)
pdf_y = np.arange(0,91,1)
#into projection
X,Y = np.meshgrid(pdf_x,pdf_y)
X,Y = m(X,-Y)
kernel = stats.gaussian_kde(values)
positions = np.vstack([X.ravel(), Y.ravel()])
Z = np.reshape(kernel(positions).T, X.shape)
xql = np.percentile(x,25)
xqu = np.percentile(x,75)
yql = np.percentile(y,25)
yqu = np.percentile(y,75)
Interp = LinearNDInterpolator((X.flatten(),Y.flatten()),Z.flatten())
ax = plt.gca()
ax.scatter(x,y)
levels = [Interp(xql,yql),Interp(xqu,yqu)]
ax.contour(X,Y,Z,levels=levels,colors='red')
plt.show()

Strange behavior of matplotlib's griddata

I have a .txt file with values
x1 y1 z1
x2 y2 z2
etc.
With my previous little experience I was trying to draw a contourf, with this code
import numpy as np
import matplotlib
from matplotlib import rc
import matplotlib.mlab as ml
from pylab import *
rc('font', family='serif')
rc('font', serif='Times New Roman')
rc('font', size='9')
rc('text', usetex=True)
from matplotlib.mlab import griddata
import matplotlib.pyplot as plt
import numpy.ma as ma
from numpy.random import uniform
from matplotlib.colors import LogNorm
matplotlib.use('pgf')
fig = plt.figure()
data = np.genfromtxt('Velocidad.txt')
matplotlib.rcParams['xtick.direction'] = 'out'
matplotlib.rcParams['ytick.direction'] = 'out'
rc('text', usetex=True)
rc('font', family='serif')
x = data[:,0]
y = data[:,1]
z = data[:,2]
xi = np.linspace(0,3000.0, 400)
yi = np.linspace(0,4.0, 200)
zi = griddata(x,y,z,xi,yi,interp='nn')
CS = plt.contourf(xi,yi,zi,200,cmap=plt.cm.jet,rasterized=True)
plt.colorbar()
plt.xlim(0,3000)
plt.ylim(0,4.0)
plt.ylabel(r'$t$')
plt.xlabel(r'$x$')
plt.title(r' Contour de $v(x,t)$')
plt.savefig("CampoVel.png", dpi=100)
plt.show()
the problem is the output:
When I see this picture and I look at the data (which is here, in this link) and I don't understand those discontinuities in x=750 and x=1875. And those strange vertical lines all over the plot. Looking at the data I would expect something smooth, at least in those positions, but the output obviously isn't. Is this a problem of griddata()? How can I solve it?
I have been told that as my data is regularly spaced on X and Y, I shouldn't use griddata(), but I have looked examples and I can't get the code to work.
If you simply reshape your data after loading it and skip the griddata thing, doing this:
data = data.reshape(81, 201, 3)
x = data[...,0]
y = data[...,1]
z = data[...,2]
CS = plt.contourf(x,y,z,200,cmap=plt.cm.jet,rasterized=True)
plt.colorbar()
plt.show()
You get this:

Categories