Tight layout for matplotlib 3d surface plot - python-2.7

I am trying to create a 3d surface plot in matplotlib. the plot surface works fine using ax.plot_surface api. But I couldn't find a way to remove the padding surrounding the subplot. In fact, I don't need the outer axes that go from 0.0 to 1.0 at all. How can i remove the padding? I already tried many suggestions from stackoverflow like "ax.autoscale_view('tight')" and "fig.tight_layout()". autoscale_view don't change anything and fig.tight_layout() is not available in the matplotlib version i am using. For strict compatibility requirements i have to use a very old (Version 0.99) version of matplotlib. Any ideas ?
For completeness I have added a sample source code i am using:
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure(figsize = (18,12))
rect = fig.add_subplot(2, 3, 2).get_position()
ax = Axes3D(fig, rect)
X = np.arange(-5, 5, 0.025)
Y = np.arange(-5, 5, 0.025)
X, Y = np.meshgrid(X, Y)
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R)
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.jet)
ax.view_init(azim=-90, elev=90)
ax.axis('off')
plt.show()

Related

Plotting a 3d line intersecting a surface in mplot3d (matplotlib python)

I am trying to plot a surface and a line which is passing through it. I want to have a plot where the portion of the line which is behind the surface, is hidden.
I tried this in matplotlib but the portion of the line behind the surface is also visible.
Line intersecting a surface
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
x = np.arange(0,10,1)
y = np.arange(0,10,1)
z = np.arange(0,10,1)
X, Y = np.meshgrid(x,y)
Z= np.ones((len(x),len(x)))*5
fig = plt.figure()
ax1 = fig.gca(projection='3d')
ax1.plot_surface(X, Y, Z, color='red', edgecolor='black')
ax1.plot(x,y,z,'-',color='black',linewidth=4)
plt.show()
In matplotlib, there is a concept of the zorder. Objects with a higher zorder are plotted in a layer on top of objects with a lower zorder, as per the docs. By default, the patch has a higher zorder than the line, which is why your red surface appears to block out the line. Here I have created a new set of coordinates for the background and foreground parts of the line, by selecting indices where z <= 5 or z >= 5 respectively. Then I plot these two sets of points separately, setting the zorder for all three - the surface and both of the lines.
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
x = np.arange(0, 10, 1)
y = np.arange(0, 10, 1)
z = np.arange(0, 10, 1)
x_background = x[z <= 5]
y_background = y[z <= 5]
z_background = z[z <= 5]
x_foreground = x[z >= 5]
y_foreground = y[z >= 5]
z_foreground = z[z >= 5]
X, Y = np.meshgrid(x, y)
Z = np.ones((len(x), len(x))) * 5
fig = plt.figure()
ax1 = fig.gca(projection='3d')
ax1.plot_surface(X, Y, Z, color='red', edgecolor='black', zorder=1)
ax1.plot(
z_background, z_background, z_background, '-', color='black', linewidth=4,
zorder=2)
ax1.plot(
z_foreground, z_foreground, z_foreground, '-', color='black', linewidth=4,
zorder=3)
plt.show()
Hope this helps!

Matplotlib: how to animate pcolormesh with large data set

I am using matplotlib.pyplot to animate some array data. The data is in the form of an intensity map, so I have a mesh of x and y locations, and a value associated with those locations.
The difficulty is that I cannot simply update the intensity data because the x and y locations change as well.
For example, I can get something like this work, but it requires having an over-determined x and y grid first that will cover the entire range:
cax = ax.pcolormesh(x, y, G[:-1, :-1, 0],
vmin=-1, vmax=1, cmap='Blues')
fig.colorbar(cax)
def animate(i):
cax.set_array(G[:-1, :-1, i].flatten())
This works, but I end up with a fairly large intensity array filled mostly with zeros.
I have found an example here that allows the x and y values to be changed. Here is a modified MWE:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
fig2 = plt.figure()
x = np.arange(-9, 10)
y = np.arange(-9, 10).reshape(-1, 1)
base = np.hypot(x, y)
ims = []
for add in np.arange(15):
x = np.arange(-9+add, 10+add)
y = np.arange(-9+add, 10+add)
x, y = np.meshgrid(x, y)
ims.append((plt.pcolormesh(x, y, base + add, norm=plt.Normalize(0, 30)),))
im_ani = animation.ArtistAnimation(fig2, ims, interval=50, repeat_delay=3000,
blit=True)
plt.show()
The issue here is two-fold. First, I have about 3000 frames, so the list ims becomes unmanageable. Secondly, how can I get the data to clear between frames and not show every frame all at once? Perhaps there's a better way altogether?
Bonus: using a slider could be an alternative to an animation. I've used Slider on these types of data before, but only by initializing a huge x and y grid.
Thanks for the help! Apologies if I'm not using the proper tags.
I may misunderstand the problem here, but using a FuncAnimation seems more appropriate here.
With blitting
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
fig, ax = plt.subplots()
x = np.arange(-9, 10)
y = np.arange(-9, 10).reshape(-1, 1)
base = np.hypot(x, y)
def animate(i):
x = np.arange(-9+i, 10+i)
y = np.arange(-9+i, 10+i)
x, y = np.meshgrid(x, y)
pc = ax.pcolormesh(x, y, base + i, norm=plt.Normalize(0, 30))
return pc,
ax.axis([-9,30,-9,30])
im_ani = animation.FuncAnimation(fig, animate, frames=30, interval=50,
repeat_delay=3000, blit=True)
plt.show()
Without blitting
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
fig, ax = plt.subplots()
x = np.arange(-9, 10)
y = np.arange(-9, 10).reshape(-1, 1)
base = np.hypot(x, y)
store=[]
def animate(i):
x = np.arange(-9+i, 10+i)
y = np.arange(-9+i, 10+i)
x, y = np.meshgrid(x, y)
if store:
store[0].remove()
del store[0]
pc = ax.pcolormesh(x, y, base + i, norm=plt.Normalize(0, 30))
store.append(pc)
ax.axis([-9,30,-9,30])
im_ani = animation.FuncAnimation(fig, animate, frames=30, interval=50,
repeat_delay=3000)
plt.show()

How to produce MATLAB plot (interpolation) in Matplotlib (Numpy)?

I am trying to follow a MATLAB example of meshgrid + interpolation. The example code is found HERE. On that site, I am going through the following example: Example – Displaying Nonuniform Data on a Surface.
Now, I would like to produce a similar plot in Python (Numpy + Matplotlib) to what is shown there in MATLAB. This is the plot that MATLAB produces:
I am having trouble with doing this in Python. Here is my code and my output in Python 2.7:
from matplotlib.mlab import griddata
import matplotlib.pyplot as plt
from matplotlib import cm
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
x = np.random.rand(200)*16 - 8
y = np.random.rand(200)*16 - 8
r = np.sqrt(x**2 + y**2)
z = np.sin(r)/r
xi = np.linspace(min(x),max(x), 100)
yi = np.linspace(min(y),max(y), 200)
X,Y = np.meshgrid(xi,yi)
Z = griddata(x, y, z, X, Y, interp='linear')
fig = plt.figure()
ax = fig.gca(projection='3d')
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1,cmap=cm.jet)
Here is the result of my attempt at doing this with matplotlib and NumPy..
Could someone please help me recreate the MATLAB plot in matplotlib, as either a mesh or a surface plot?
So it seems that the major differences in the look have to do with the default number of lines plotted by matlab, which can be adjusted by increasing rstride and cstride. In terms of color, in order for the colormap to be scaled properly it is probably best in this case to set your limits, vmin and vmax because when automatically set, it will use the min and max of Z, but in this case, they are both nan, so you could use np.nanmin and np.nanmax.
from matplotlib.mlab import griddata
import matplotlib.pyplot as plt
from matplotlib import cm
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
x = np.random.rand(200)*16 - 8
y = np.random.rand(200)*16 - 8
r = np.sqrt(x**2 + y**2)
z = np.sin(r)/r
xi = np.linspace(min(x),max(x), 100)
yi = np.linspace(min(y),max(y), 200)
X,Y = np.meshgrid(xi,yi)
Z = griddata(x, y, z, X, Y, interp='linear')
fig = plt.figure()
ax = fig.gca(projection='3d')
surf = ax.plot_surface(X, Y, Z, rstride=5, cstride=5, cmap=cm.jet, vmin=np.nanmin(Z), vmax=np.nanmax(Z), shade=False)
scat = ax.scatter(x, y, z)
In matplotlib unfortunately I get some annoying overlapping/'clipping' problems, where Axes3d doesn't always properly determine the order in which object should be displayed.

Colouring the surface of a sphere with a set of scalar values in matplotlib

I am rather new to matplotlib (and this is also my first question here). I'm trying to represent the scalp surface potential as recorded by an EEG. So far I have a two-dimensional figure of a sphere projection, which I generated using contourf, and pretty much boils down to an ordinary heat map.
Is there any way this can be done on half a sphere?, i.e. generating a 3D sphere with surface colours given by a list of values? Something like this, http://embal.gforge.inria.fr/img/inverse.jpg, but I have more than enough with just half a sphere.
I have seen a few related questions (for example, Matplotlib 3d colour plot - is it possible?), but they either don't really address my question or remain unanswered to date.
I have also spent the morning looking through countless examples. In most of what I've found, the colour at one particular point of a surface is indicative of its Z value, but I don't want that... I want to draw the surface, then specify the colours with the data I have.
You can use plot_trisurf and assign a custom field to the underlying ScalarMappable through set_array method.
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import matplotlib.tri as mtri
(n, m) = (250, 250)
# Meshing a unit sphere according to n, m
theta = np.linspace(0, 2 * np.pi, num=n, endpoint=False)
phi = np.linspace(np.pi * (-0.5 + 1./(m+1)), np.pi*0.5, num=m, endpoint=False)
theta, phi = np.meshgrid(theta, phi)
theta, phi = theta.ravel(), phi.ravel()
theta = np.append(theta, [0.]) # Adding the north pole...
phi = np.append(phi, [np.pi*0.5])
mesh_x, mesh_y = ((np.pi*0.5 - phi)*np.cos(theta), (np.pi*0.5 - phi)*np.sin(theta))
triangles = mtri.Triangulation(mesh_x, mesh_y).triangles
x, y, z = np.cos(phi)*np.cos(theta), np.cos(phi)*np.sin(theta), np.sin(phi)
# Defining a custom color scalar field
vals = np.sin(6*phi) * np.sin(3*theta)
colors = np.mean(vals[triangles], axis=1)
# Plotting
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
cmap = plt.get_cmap('Blues')
triang = mtri.Triangulation(x, y, triangles)
collec = ax.plot_trisurf(triang, z, cmap=cmap, shade=False, linewidth=0.)
collec.set_array(colors)
collec.autoscale()
plt.show()

Color image segmentation with Python

I have many pictures as below:
My objective is to identify those "beads", try to mark it with a circle, and count the detected numbers.
I tried to use image segmentation algorithms via Python and the source codes are as below:
from matplotlib import pyplot as plt
from skimage import data
from skimage.feature import blob_dog, blob_log, blob_doh
from math import sqrt
from skimage.color import rgb2gray
from scipy import misc # try
image = misc.imread('test.jpg')
image_gray = rgb2gray(image)
blobs_log = blob_log(image_gray, max_sigma=10, num_sigma=5, threshold=.1)
# Compute radii in the 3rd column.
blobs_log[:, 2] = blobs_log[:, 2] * sqrt(2)
blobs_dog = blob_dog(image_gray, max_sigma=2, threshold=.051)
blobs_dog[:, 2] = blobs_dog[:, 2] * sqrt(2)
blobs_doh = blob_doh(image_gray, max_sigma=2, threshold=.01)
blobs_list = [blobs_log, blobs_dog, blobs_doh]
colors = ['yellow', 'lime', 'red']
titles = ['Laplacian of Gaussian', 'Difference of Gaussian',
'Determinant of Hessian']
sequence = zip(blobs_list, colors, titles)
for blobs, color, title in sequence:
fig, ax = plt.subplots(1, 1)
ax.set_title(title)
ax.imshow(image, interpolation='nearest')
for blob in blobs:
y, x, r = blob
c = plt.Circle((x, y), r, color=color, linewidth=2, fill=False)
ax.add_patch(c)
plt.show()
The best results obtained so far are still unsatisfactory:
How can I improve it ?
You could use Gimp or Photoshop and test some filters and colors changes to differentiate the circles from the background. Brightness and Contrast adjustments may work. Then you can apply an Edge detector to detect the circles.
by converting this image to grayscale you have effectively thrown away the most powerful cue you have to segment the beads - their distinctive green color. try running the same code but replace
image_gray = rgb2gray(image)
with
image_gray = image[:,:,1]