Basemap plotting a contour figure over coastlines - python

I am trying to superimpose a contour plot onto a basemap plot of coastlines. Right now it either plots both separately or just the basemap.
Xa = np.linspace(-93.6683,-93.2683,25)
Ya = np.linspace(29.005,29.405,25)
plt.figure()
m = Basemap(width=1200000,height=900000,projection='lcc',resolution='f',lat_1=29.205,lat_2=29.5,lat_0=29.205,lon_0=-93,4683)
m.drawcoastlines()
plt.contourf(Ya,Xa,Result.reshape(len(Xa),len(Ya)))
plt.colorbar()
plt.show()
The Result in the code are the concentrations that are plotted as a contour. I would add them, but there are 625 values for concentration from running my code.
Im wondering how I can write the plotting part of my code to be able to superimpose the two graphs. Thanks!

You would want to use basemap's contour function here. This has however some particularities.
It accepts only 2D arrays as input, meaning, you need to create a meshgrid of coordinates first.
and the input must be the mapped coordinates, x,y = m(X,Y)
Also pay attention to the dimensions. The first dimension of a numpy array is the y axis, the second dimension is the x axis.
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
import numpy as np
Xa = np.linspace(-93.6683,-93.2683,25)
Ya = np.linspace(29.005,29.405,25)
X,Y = np.meshgrid(Xa,Ya)
Result = np.random.rand(len(Ya)*len(Xa))
m = Basemap(width=1200000,height=900000,projection='lcc',resolution='c',
lat_1=29.205,lat_2=29.5,lat_0=29.205,lon_0=-93.4683)
m.drawcoastlines()
mx,my = m(X,Y)
m.contourf(mx,my,Result.reshape(len(Ya),len(Xa)))
plt.colorbar()
plt.show()

Related

Plotting 2D scalar velocity field with matplotlib

I have the following dataframe which I'm trying to plot,
x,y,u,v
-0.157806993154554,-0.05,0.000601310515776,0.003318849951029
-0.374687807296859,-0.35,-0.001057069515809,2.9686838388443E-05
-1,-0.323693574077183,-0.002539682900533,-0.008748378604651
-0.486242955499287,-0.35,-0.001797694480047,0.000218112021685
-0.54184300562917,-0.05,0.001513708615676,0.001884449273348
0,-0.31108016382718,5.28732780367136E-05,-0.000818025320768
-0.428046308037431,-0.35,-0.001458290731534,8.22432339191437E-05
-0.343159653530217,-0.05,0.00112508633174,0.002580288797617
-0.386254219645565,-0.35,-0.001139726256952,2.6945024728775E-05
-0.600252053226546,-0.05,0.001246933126822,0.00207519903779
-1,-0.061575842243108,-0.000705834245309,0.043682213872671
0,-0.052056831172645,0.009899478405714,-0.003894355148077
-0.903283837058102,-0.35,5.81557396799326E-05,-0.001065131276846
-0.418202966058798,-0.05,0.001158628845587,0.002409461885691
-0.809266339501268,-0.35,0.000290673458949,-2.0977109670639E-05
0,-0.066616962597653,2.92772892862558E-05,0.001737955957651
-0.090282152608,-0.35,0.00151876010932,0.001403901726007
-1,-0.173440678035212,-0.007741978392005,0.006023477762938
-1,-0.155079864747918,-0.00761691480875,0.007886063307524
-0.222728396757266,-0.35,0.000686463201419,0.000264558941126
where u,v and x,y are positional coordinates and the velocity vectors at that point. (full dataset - https://pastebin.pl/view/0f60b48e)
I want to plot my data like so (Contour lines and arrows are not required.) .
How do I do this?
So far I've tried:
import numpy as np
import matplotlib.pyplot as plt
# Meshgrid
#x, y = np.meshgrid(box_df['x'], box_df['y'])
x,y = box_df['x'], box_df['y']
# Directional vectors
#u, v = np.meshgrid(box_df['u'], box_df['v'])
u = box_df['u']
v = box_df['v']
# Plotting Vector Field with QUIVER
plt.quiver(x, y, u, v, color='g')
plt.title('Vector Field')
# Show plot with gird
plt.grid()
If you want to plot a scalar field with irregular data points, you can either interpolate between data points to form a regular grid, or you can use matplotlib.pyplot.tricontour and tricontourf to interpolate for you to fill.
Using tricontour you could try:
import numpy as np
import matplotlib.pyplot as plt
x, y = box_df.x, box_df.y
# make scalar field
speed = np.hypot(box_df.u, box_df.v)
# Plotting scalar field with tricontour
plt.tricontourf(x, y, speed)
plt.title('Scalar Field')
# Show plot with gird
plt.grid()
However it appears that you only have data around the edge of a rectangle, so interpolation into the interior of the rectangle is likely to be poor.

How to extract polar plot information in Python?

I want to extract polar coordinates from the plot. There exists a matrix that has 10 rows and 2 columns a and b. This matrix has the numbers that created the polar plot.
But what I am looking for is a matrix that has the polar coordinates that are already plotted.
Example: the first row (meaning, information about the first point) would include the x,y,radius and theta/angle or any other useful information from the plot that were previously not there in the original matrix.
Think of polar plotting as a transformation that was implemented on the matrix in the for loop and I want to extract the new numbers resulted from the output polar plot.
import matplotlib.pyplot as plt
sample= [1,2,3,4,5,6,7,8,9,10]
fig = plt.figure()
fig.add_subplot(111, projection='polar')
data = sample
for i in data:
a=i+min(data)
b=i+max(data)
plt.polar(a,b, '.', c='black')
plt.show()
Even after your clarification I am a little confused by the code example. But I am pretty sure the code below answers your question.
import numpy as np
import matplotlib.pyplot as plt
x = np.random.random((10,1)) # same as "a" in your example
y = np.random.random((10,1)) # same as "b" in your example
plt.plot(x,y)
plt.title("Rectangular coordinates")
plt.show()
th = np.arctan2(y,x)
r = np.sqrt(x**2 + y**2)
# Should show the same plot as above, just with different margins/aspect ratio/grid lines
plt.polar(th,r)
plt.title("Polar coordinates")
plt.show()
It's just as easy to go in reverse, getting the rectangular coordinates if you assume your random data is representing data in polar coordinates.

How to overlay contour plot on 3-D surface plot with matplotlib or plotly?

I have a 3-D surface plot that shows x and y coordinates and depths. I also have a 2-D contourf plot with x and y coordinates and the filled contours at the different locations. If I know the depths at the coordinates in the contourf plot, is there a way I can show the contours on the 3-D surface plot?
I have created a 3-D surface plot using plotly with the code below:
import plotly.graph_objects as go
import oceansdb
import numpy as np
import matplotlib.pyplot as plt
Xa = np.linspace(29.005,29.405,200)
Ya = np.linspace(-93.6683,-93.2683,200)
db = oceansdb.ETOPO()
dcont = db['topography'].extract(lat=Xa, lon=Ya)
depth = dcont['height']
fig = go.Figure(data=[go.Surface(z=depth, x=Xa, y=Ya)])
fig.show()
Say my contourf plot can be created with the code below:
X = np.array([29.1,29.15,29.2,29.25])
Y = np.array([-93.5,-93.45,-93.4,-93.35])
r = np.array([0,0,0,2,3,0,0,6,7,8,9,1,9,0,0,0])
plt.figure()
plt.contourf(X,Y,r.reshape(len(X),len(Y)))
plt.show()
Assuming that the depth at each location can be determined using the oceansdb module, can I overlay the contour plot on the surface plot at the correct depth?
Using matplotlib the short answer is "yes", but there are two buts you have face:
Visualizing 3d data is difficult, and overlapping multiple datasets is more often than not confusing beyond the simplest cases
Matplotlib has a 2d renderer, so even though you can plot multiple objects in the same 3d figure, there will often be rendering artifacts (in particular, two objects can typically be either fully in front of or behind one another).
The key methods you need are Axes3D.contour or Axes3D.contourf. Here are these in action with your example data:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D # this enables 3d axes
X = np.array([29.1,29.15,29.2,29.25])
Y = np.array([-93.5,-93.45,-93.4,-93.35])
r = np.array([0,0,0,2,3,0,0,6,7,8,9,1,9,0,0,0]).reshape(X.size, Y.size)
# plot your 2d contourf for reference
fig,ax = plt.subplots()
ax.contourf(X, Y, r)
# plot in 3d using contourf
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.contourf(X, Y, r)
# plot in 3d using contour
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.contour(X, Y, r)
plt.show()
Here's your 2d contourf plot:
Here's the 3d contourf version:
And here's the 3d contour version:
As you can see the difference between the latter two is that contourf also plots horizontal planes for each level (just like terraces), whereas contour only plots the level lines themselves.
Since repeated plots using the same axes will accumulate plots there's nothing stopping you from superimposing either of these 3d contour plots on your original surface. However, in line with my earlier warnings you'll have to watch if the contours are rendered correctly over the surface (under all view angles), and even if so the result might not be all that transparent for conveying information. I personally tend to find contourf much easier to comprehend than contour on a 3d plot, but I suspect that if we put these on top of full surface plots the latter will fare better.

How to make spatial plot of irregular geographical data

I have lat=[13.7,21,23.7,10.6,34.5,20.7,33.1,15.5]
lon=[65.7,87.5,69.8,98.3,67,79.8,88.8,77.9] and
val=[234,310,287,279,298,280,279,321]
How can I make a spatial plot these data over map ? My code look like
lat=[13.7,21,23.7,10.6,34.5,20.7,33.1,15.5]
lon=[65.7,87.5,69.8,98.3,67,79.8,88.8,77.9]
val=[234,310,287,279,298,280,279,321]
lon, lat = np.meshgrid(lon, lat)
m = Basemap(projection='merc', resolution=None,
llcrnrlat=0, urcrnrlat=40,
llcrnrlon=60, urcrnrlon=100, )
m.contourf(lon,lat,val)
To be able to use contourf, you need gridded data (i.e. if you have an 8x8 lon-lat grid, you need 64 z values). As you have only (lon,lat,z) triplets, it is better to use a tricontourf plot. However, Basemap does not have that function, but has an additional tri keyword for the contourf function:
import numpy as np
from matplotlib import pyplot as plt
from mpl_toolkits import basemap
lat=np.array([13.7,21,23.7,10.6,34.5,20.7,33.1,15.5])
lon=np.array([65.7,87.5,69.8,98.3,67,79.8,88.8,77.9])
val=np.array([234,310,287,279,298,280,279,321])
#lon, lat = np.meshgrid(lon, lat) <-- do not use this
m = basemap.Basemap(projection='merc', resolution=None,
llcrnrlat=0, urcrnrlat=40,
llcrnrlon=60, urcrnrlon=100, )
##need to convert coordinates
x,y = m(lon,lat)
##add the `tri=True` kwarg
m.contourf(x,y,val, tri=True)
plt.show()

Creating intersecting images in matplotlib with imshow or other function

I have two 3-D arrays of ground penetrating radar data. Each array is basically a collection of time-lapse 2-D images, where time is increasing along the third dimension. I want to create a 3-D plot which intersects a 2-D image from each array.
I'm essentially trying to create a fence plot. Some examples of this type of plot are found on these sites:
http://www.geogiga.com/images/products/seismapper_3d_seismic_color.gif
http://www.usna.edu/Users/oceano/pguth/website/so461web/seismic_refl/fence.png
I typically use imshow to individually display the 2-D images for analysis. However, my research into the functionality of imshow suggests it doesn't work with the 3D axes. Is there some way around this? Or is there another plotting function which could replicate imshow functionality but can be combined with 3D axes?
There might be better ways, but at least you can always make a planar mesh and color it:
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
# create a 21 x 21 vertex mesh
xx, yy = np.meshgrid(np.linspace(0,1,21), np.linspace(0,1,21))
# create some dummy data (20 x 20) for the image
data = np.random.random((20, 20))
# create vertices for a rotated mesh (3D rotation matrix)
X = np.sqrt(1./3) * xx + np.sqrt(1./3) * yy
Y = -np.sqrt(1./3) * xx + np.sqrt(1./3) * yy
Z = np.sqrt(1./3) * xx - np.sqrt(1./3) * yy
# create the figure
fig = plt.figure()
# show the reference image
ax1 = fig.add_subplot(121)
ax1.imshow(data, cmap=plt.cm.BrBG, interpolation='nearest', origin='lower', extent=[0,1,0,1])
# show the 3D rotated projection
ax2 = fig.add_subplot(122, projection='3d')
ax2.plot_surface(X, Y, Z, rstride=1, cstride=1, facecolors=plt.cm.BrBG(data), shade=False)
This creates:
(Please note, I was not very careful with the rotation matrix, you will have to create your own projection. It might really be a good idea to use a real rotation matrix.)
Just note that there is a slight problem with the fence poles and fences, i.e. the grid has one more vertex compared to the number of patches.
The approach above is not very efficient if you have high-resolution images. It may not even be useful with them. Then the other possibility is to use a backend which supports affine image transforms. Unfortunately, you will then have to calculate the transforms yourself. It is not hideously difficult, but still a bit clumsy, and then you do not get a real 3D image which could be rotated around, etc.
For this approach, see http://matplotlib.org/examples/api/demo_affine_image.html
Alternateively, you can use OpenCV and its cv2.warpAffine function to warp your image before showing it with imshow. If you fill the surroundings with transparent color, you can then layer images to get a result which looks like your example iamge.
Just to give you an idea of the possibilities of plot_surface, I tried to warp Lena around a semi-cylinder:
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
# create a 513 x 513 vertex mesh
xx, yy = np.meshgrid(np.linspace(0,1,513), np.linspace(0,1,513))
# create vertices for a rotated mesh (3D rotation matrix)
theta = np.pi*xx
X = np.cos(theta)
Y = np.sin(theta)
Z = yy
# create the figure
fig = plt.figure()
# show the 3D rotated projection
ax = fig.add_subplot(111, projection='3d')
ax.plot_surface(X, Y, Z, rstride=1, cstride=1, facecolors=plt.imread('/tmp/lena.jpg')/255., shade=False)
She indeed bends well, but all operations on the image are quite slow:
If you're happy to contemplate using a different plotting library (ie not matplotlib) then it might be worth considering mayavi / tvtk (although the learning curve is a little steep). The closest I've seen to what you want is the scalar cut planes in
http://wiki.scipy.org/Cookbook/MayaVi/Examples
The bulk of the documentation is at:
http://docs.enthought.com/mayavi/mayavi/index.html
There is no way of doing this with matplotlib. #DrV's answer is an approximation. Matplotlib does not actually show each individual pixel of the original image but some rescaled image. rstride and cstride allow you to help specify how the image gets scaled, however, the output will not be the exact image.

Categories

Resources