plotting with meshgrid and imshow - numpy

Imshow and meshgrid are not working the way I thought. I have some function defined for a given (x,y) point in 2D that returns a scalar f(x,y). I want to visualize the function f using imshow.
x = np.linspace(0,4)
y = np.linspace(0,1)
X,Y = np.meshgrid(x,y)
Z = np.zeros((50,50))
for i in range(50):
for j in range(50):
Z[i,j] = f(X[i,j],Y[i,j])
fig = plt.figure()
plt.imshow(Z,extent=[0,4,1,0])
plt.show()
This works as expected except in the extent I think it should be [0,4,0,1]... Am I defining the Z[i,j] to each (x,y) pair incorrectly? An explanation for how this works would be great! Thanks!

As far as I am aware, the imshow is normally used to display an image. The extent is then used to define how large it should be, say you might want to give an image as the background of the plot.
Instead I think you will find it more intuitive to use pcolor, a demo can be found here. It works much the same as imshow so you can just supply Z. However, you can also give it the X and Y arrays. This way you can really check if your supplying the values correctly:
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0,4)
y = np.linspace(0,1)
def f(x, y):
return y * np.sin(x)
X, Y = np.meshgrid(x,y)
Z = np.zeros((50,50))
for i in range(50):
for j in range(50):
Z[i,j] = f(X[i,j],Y[i,j])
plt.pcolor(X, Y, Z)
plt.show()
I have added a function to show it works. Note that if your function is able to handle numpy arrays you can replace the initialisation of Z and the nested for loops with
X, Y = np.meshgrid(x,y)
Z = f(X, Y)
This is cleaner and will be faster to compute.

Related

Get data from mplot3d graph

I can’t find out how to get data from an mplot3d graph. Something similar to the 2D style:
line.get_xdata()
Is it possible?
Line3D
You can get get the original data from the (private) _verts3d attribute
xdata, ydata, zdata = line._verts3d
print(xdata)
Complete example
import matplotlib as mpl
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import matplotlib.pyplot as plt
mpl.rcParams['legend.fontsize'] = 10
fig = plt.figure()
ax = fig.gca(projection='3d')
# Prepare arrays x, y, z
x = np.arange(5)
y = np.arange(5)*4
z = np.arange(5)*100
line, = ax.plot(x, y, z, label='curve')
fig.canvas.draw()
xdata, ydata, zdata = line._verts3d
print(xdata) # This prints [0 1 2 3 4]
plt.show()
Some explanation: The problem with get_data or get_xdata is that it will return the projected coordinates once the figure is drawn. So while before drawing the figure, line.get_xdata() would indeed return the correct values, after drawing, it would return something like
[ -6.14413090e-02 -3.08824862e-02 -3.33066907e-17 3.12113190e-02 6.27567511e-02]
in the above example, which is the x component of the 3D coordinates projected onto 2D.
There is a pull request to matplotlib, which would allow to get the data via methods get_data_3d. This is still not merged, but might allow the above to be done without using private arguments in a future version of matplotlib.
Poly3DCollection
For a plot_surface plot this looks similar, except that the attribute to look at is the ._vec
surf = ax.plot_surface(X, Y, Z)
xdata, ydata, zdata, _ = surf._vec
print(xdata)
This issue was filed on Github and there is contribution that adds new get_data_3d and set_data_3d methods. Unfortunately, these changes is likely not yet available in distributions. So you might have to continue using private variable line._verts3d.
See more here: https://github.com/matplotlib/matplotlib/issues/8914

PyPlot and Julia can't plot x^2

I want to plot a simple function, but i can't figured out how to do it.
this code works fine
using PyPlot
x = linspace(0,10,1000); y = log(x);
plot(x, y, color="blue", linewidth=2.0, linestyle="-")
but the next code do not work
using PyPlot
x = linspace(0,10,1000); y = x^2;
plot(x, y, color="blue", linewidth=2.0, linestyle="-")
i can't figure out how to multiply x by x.
You need to use an elementwise exponentiation: x.^2.
using PyPlot
x = linspace(0,10,1000); y = x.^2;
plot(x, y, color="blue", linewidth=2.0, linestyle="-")
In Julia v0.5 and later, you should also use the elementwise version of log: y = log.(x). The old automatically-broadcasted functions like sin, log, etc. are scheduled for deprecation in the v0.6 release cycle.
Plots.jl allows a different approach, where you just specify the function to plot and the bounds to plot it in:
using Plots
plot(x->x^2, -3, 3)
Here, x->x^2 is an anonymous function. Alternatively, you can define a standard Julia function:
f(x) = x^2
plot(f, -3, 3)

matplotlib streamline with the area of divergence and convergence

I ploted streamlines using the u and v. How do i determine whether divergence or convergence was occurring and plot those shapes in same figure with matplotlib?
streamline test, red is divergence and blue is convergence.
You can colour streamlines in any way you want, so get whatever form of divergence you want and use that,
import numpy as np
import matplotlib.pyplot as plt
Y, X = np.mgrid[-3:3:100j, -3:3:100j]
U = -1 - X**2 + Y
V = 1 + X - Y**2
divUV = reduce(np.add,np.gradient(U)) + reduce(np.add,np.gradient(V))
fig, ax = plt.subplots()
strm = ax.streamplot(X, Y, U, V, color=divUV, cmap=plt.cm.RdBu)
fig.colorbar(strm.lines)
plt.show()
Not sure the divergence looks right here but you get the idea. Alternatively, you could overlay a colormesh with transparency,
cm = ax.pcolormesh(X, Y, divU, cmap=plt.cm.RdBu, alpha=0.4)
fig.colorbar(cm)

Picking a new color for each contour component in matplotlib

Sometimes a specific contour level has several components. For instance:
import numpy as np
import matplotlib.pyplot as plt
delta = 1./100
x = np.arange(-2.0, 3.0, delta)
y = np.arange(-3.0, 3.0, delta)
X, Y = np.meshgrid(x, y)
Z = Y * Y - X * X * X + X
plt.figure()
CS = plt.contour(X, Y, Z, [0])
How do I color each component using its own color?
I found a way to do it! :) But it's hacky, so I'll leave my answer un-accepted until someone comes up with a better way to do it. Here is my solution (matplotlib 1.4.3).
As noted in the comments, what I asked is not something that matplotlib.contour knows how to do. But after investigating the code a little bit I came up with a solution that works and isn't too bad.
Behind the scenes, a class called QuadContourSet is used to store all the contour paths in "line collections", one line collection per level. The line collections are styled all together.
My idea was to subclass this class and replace the function _get_allsegs_and_allkinds with a function that separates the line collections to one line collection per component, instead of per-level. This is hacky so I named it HackyContourSet but it's good enough for my purposes.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import contour
class HackyContourSet(contour.QuadContourSet):
def _get_allsegs_and_allkinds(self):
allkinds = None
allsegs = []
for level in self.levels:
nlist = self.Cntr.trace(level)
nseg = len(nlist) // 2
segs = nlist[:nseg]
# Original code: allsegs.append(segs) - put all level segments in a
# collection. New code: Put each segment in a separate collection.
for seg in segs:
allsegs.append([seg])
# The following line is needed to make QuadContourSet think there are
# more levels, so it would actually draw the additional collections.
self.levels = [0] * len(allsegs)
return allsegs, allkinds
####################
delta = 1./100
x = np.arange(-2.0, 3.0, delta)
y = np.arange(-3.0, 3.0, delta)
X, Y = np.meshgrid(x, y)
Z = Y * Y - X * X * X + X
plt.figure()
plt.cla()
axes = plt.gca()
CS = HackyContourSet(axes, X, Y, Z, [0], colors=list('rb'))

Using matplotlibs contourf function with 1D vectors

I have a large data set with files containing three also large single column vectors (backazimuth, frequency and power) for every day in a month. I would like to display the data on a polar plot using something like contourf. However, I am not sure how to reshape the power data into a 2D array. An example is below,
from pylab import *
x=rand(100)
y=rand(100)
z = rand(100) # 1D
BAZ, FREQ = meshgrid(x, y)
ax = plt.subplot(111, polar=True)
contourf(BAZ, FREQ, z) # z needs to be 2D
Any know how I can reshape z so this will work???
thanks,
David
From link in tiago's comment above answer is,
x=rand(100)
y=rand(100)
z = rand(100)
xgrid = np.linspace(x.min(), x.max(), 100)
ygrid = np.linspace(y.min(), y.max(), 100)
xgrid, ygrid = np.meshgrid(xgrid, ygrid)
zgrid = griddata((x,y),z, (xgrid, ygrid))
ax = plt.subplot(111, polar=True)
contourf(xgrid, ygrid, zgrid)
Thanks,
D.