Plot 3D Contour from an Image using extent with Matplotlib - python

As I present here (in 2D), I'm wondering if how I could "scale" an image input to be plotted to a range in the plot. To be more clear, this is what I need:
I have a 400 * 400 image that is generated based on a function which interval is -1..1. So, I do a translate to save this data, like this:
x = Utils.translate(pos_x, 0, self.width, -1, 1)
y = Utils.translate(pos_y, 0, self.height, -1, 1)
data = Utils.map_position_to_function(x, y)
I.e, first I map its position to my range and then I calculate de f(x, y) based on this "new position" and save the data. Also, as I save this image, I do a translate in data so it fits in a 0..255 range, generating a grayscale image.
The problem is that, later, I have to represent the image contour in the function range. So, I have an image, 400 * 400, that I have to represent in a plot which range is -1..1.
In 2D, I could do this with this code:
im = plt.array(Image.open('Mean.png').convert('L'))
plt.figure()
CS = plt.contour(im, origin='image', extent=[-1, 1, -1, 1])
plt.clabel(CS, inline=1, fontsize=10)
plt.savefig("CountorLevel2D.png")
In 3D, I tried this:
fig = plt.figure()
ax = fig.gca(projection='3d')
row = np.linspace(0, 400, 400)
X,Y = np.meshgrid(row,row)
CS = ax.contour(X, Y, im, cmap=cm.coolwarm, extent=[-1, 1, -1, 1])
plt.clabel(CS, inline=1, fontsize=10)
plt.savefig("ContourLevel3D.png")
But the X and Y are still in the 0..400 range. I don't know what is wrong, or what I have to do to have X and Y in -1..1 range. Besides, no label is shown.
Also, as im is an image, I read values which ranges between 0..255 values. How could I present this in an -1..1 range too?
Thanks in advance. (:

Try this insted:
fig = plt.figure()
ax = fig.gca(projection='3d')
row = np.linspace(-1, 1, 400)
X,Y = np.meshgrid(row,row)
CS = ax.contour(X, Y, im, cmap=cm.coolwarm)
plt.clabel(CS, inline=1, fontsize=10)
plt.savefig("ContourLevel3D.png")

Related

Filling in a grid in numpy

I want to achieve the following. I have a x-y plot with a function y dependent on x. The plot consists of a mesh of squares. When a function point is inside the function block, the block changes color. I have attached an example:
I want to make an simillar figure, but I want to be able to make the gridsize variable.
I know how to make a plot with plt.plot(), but I'm not familliar with making a grid and filling in that grid if the function point falls in a square. Can somebody refer to numpy or mathplotlib functions that can help?
Thanks
here is a piece of code that should work for graphs centered around (min(X)-max(X)) and (min(Y),max(Y)) :
import numpy as np
def grid_plot(X,Y,resx,resy) :
d_x=resx/(np.max(X)-np.min(X))
d_y=resy/(np.max(Y)-np.min(Y))
mat=np.zeros((resy,resx))
for i in range(len(X)) :
mat[int((Y[i]-np.min(Y))*d_y),resx-int((X[i]-np.min(X))*d_x)]=1
return mat
You can use np.histogram2d to create a 2D histogram and plot the locations with count greater than zero with imshow:
import numpy as np
import matplotlib.pyplot as plt
# Input data
x = np.linspace(-2, 2, 300)
y = np.sin(x)
# Plot limits
x_min, x_max = -3, 3
y_min, y_max = -2, 2
plt.figure(figsize=(8, 3))
# First plot
resolution = 25
xg = np.linspace(x_min, x_max, resolution)
yg = np.linspace(y_min, y_max, resolution)
h, _, _ = np.histogram2d(x, y, (xg, yg))
plt.subplot(121)
# Transpose because imshow swaps X and Y axes
plt.imshow(h.T > 0, origin='lower', extent=(xg[0], xg[-1], yg[0], yg[-1]))
# Show grid
plt.gca().set_xticks([], minor=False)
plt.gca().set_xticks(xg, minor=True)
plt.gca().set_yticks([], minor=False)
plt.gca().set_yticks(yg, minor=True)
plt.grid(True, 'minor')
# Second plot
resolution = 50
xg = np.linspace(x_min, x_max, resolution)
yg = np.linspace(y_min, y_max, resolution)
h, _, _ = np.histogram2d(x, y, (xg, yg))
plt.subplot(122)
plt.imshow(h.T > 0, origin='lower', extent=(xg[0], xg[-1], yg[0], yg[-1]))
plt.gca().set_xticks([], minor=False)
plt.gca().set_xticks(xg, minor=True)
plt.gca().set_yticks([], minor=False)
plt.gca().set_yticks(yg, minor=True)
plt.grid(True, 'minor')
# Show plot
plt.tight_layout()
plt.show()
Result:

Matrix Contour Plot of 3 Parameters

I have run an MCMC chain for parameter estimation and have obtained accepted parameter values. I have 3 parameters and about 300 000 accepted values for each parameter.
I would now like to do a contour plot (doable) but in a 3-choose-2 triangular matrix type (a very specific requirement) Please see the attached photo contour-plot. The image shows some unrelated contour-plots from a paper but I want to have a similar type of plot for my parameters.
In total, I will have 6 plots: 3 single parameter histograms (like the top plot in each column in the image) and 3-choose-2 = 3 contour plots (as the lower triangle). Again, I need it to look as much as possible like the image.
How to achieve this on Python?
Update:
I have been able to write the below code which gives me a plot as my-plot-here.
However, I need an exact / as best as possible match with the type of figure 1. i.e. I need my xticks, yticks to show inside and not outside, the spaces between the figues to go away, a better way to show the left vertical plot labels (I'm currently using set_ylabel), the outer crooked contour level to go away, and have detailed (long-short) ticks along the x-axis of the pdfs.
def plot_histogram_fig(param, nbins, subplot_index, subplot_title):
counts, bins = np.histogram(param, bins = nbins)
plotcounts = np.insert(counts, -1, counts[-1])
bincentres = (bins[:-1] + bins[1:])/2
ax = fig.add_subplot(3, 3, subplot_index)
#ax.step(bins, plotcounts, where='post', c='y')
ax.plot(bincentres, counts, 'b')
#ax.plot([bins[np.argmax(counts)], bins[np.argmax(counts)]], [0, np.max(counts)], 'y')
ax.set_yticks([])
return [ax, counts, bincentres]
def plot_contour_fig(p1, p2, nbins, subplot_index):
H, xedges, yedges = np.histogram2d(p1, p2, bins = nbins)
Z = H.T
#Z_gauss = scipy.ndimage.gaussian_filter(Z, sigma = 0.8, order = 0) #filtering
X, Y = np.meshgrid(xedges[:-1], yedges[:-1])
ax = fig.add_subplot(3, 3, subplot_index)
im = ax.contour(X, Y, Z, levels = 6)
#plt.colorbar(im, ax = ax)
ax.clabel(im, inline=True, fontsize=4)
return [ax, H, xedges, yedges]
nbins = 50
fig = plt.figure(figsize = (10, 6))
#Histograms
ax1 = plot_histogram_fig(all_alphas, nbins, 1, subplot_title = 'alpha')
ax1[0].set_xticks([])
ax1[0].set_ylabel('alpha')
ax5 = plot_histogram_fig(all_betas, nbins, 5, subplot_title = 'beta')
ax5[0].set_xticks([])
ax9 = plot_histogram_fig(all_gammas, nbins, 9, subplot_title = 'gamma')
ax9[0].set_title('gamma', y = -0.5)
#Contours
ax4 = plot_contour_fig(all_alphas, all_betas, nbins, 4)
ax4[0].set_xticklabels([])
ax4[0].set_ylabel('beta')
ax7 = plot_contour_fig(all_alphas, all_gammas, nbins, 7)
ax7[0].set_title('alpha', y = -0.5)
ax7[0].set_ylabel('gamma')
ax8 = plot_contour_fig(all_betas, all_gammas, nbins, 8)
ax8[0].set_yticklabels([])
ax8[0].set_title('beta', y = -0.5)
plt.show()
all_alphas, all_betas, all_gammas are 1d numpy arrays storing the accepted parameter values.

How to increase color resolution in python matplotlib colormap

I am making a colormap of a 2D numpy meshgrid:
X, Y = np.meshgrid(fields, frequencies)
cs = ax.contourf(X, Y, fields_freqs_abs_grid, cmap="viridis", N=256)
The values in fields_freqs_abs_grid, which are plotted by color, have already been logarithmically scaled.
The colormap produced by python's matplotlib is coarse -- it scales over 8 colors even though I use "N=256" for the number of RGB pixels. Increasing N to 2048 did not change anything. A plot using the MatLab language on the same data produces a colormap with significantly higher color resolution. How do I increase the number of colors mapped in Python?
The result is:
But I want the result to be:
Thank you!
Warren Weckesser's comments definitely works and can give you a high resolution image. I implemented his idea in the example below.
In regarding to use contourf(), I'm not sure if this is a version dependent issue, but in the most recent version,
contourf() doesn't have a kwarg for N.
As you can see in the document, you want to use N as an arg (in syntax: contourf(X,Y,Z,N)) to specify how many levels you want to plot rather than the number of RGB pixels. contourf() draws filled contours and the resolution depends on the number of levels to draw. Your N=256 won't do anything and contourf() will automatically choose 7 levels.
The following code is modified from the official example, comparing resolutions with different N. In case there is a version issue, this code gives the following plot with python 3.5.2; matplotlib 1.5.3:
import numpy as np
import matplotlib.pyplot as plt
delta = 0.025
x = y = np.arange(-3.0, 3.01, delta)
X, Y = np.meshgrid(x, y)
Z1 = plt.mlab.bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0)
Z2 = plt.mlab.bivariate_normal(X, Y, 1.5, 0.5, 1, 1)
Z = 10 * (Z1 - Z2)
fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2)
fig.set_size_inches(8, 6)
# Your code sample
CS1 = ax1.contourf(X, Y, Z, cmap="viridis", N=256)
ax1.set_title('Your code sample')
ax1.set_xlabel('word length anomaly')
ax1.set_ylabel('sentence length anomaly')
cbar1 = fig.colorbar(CS1, ax=ax1)
# Contour up to N=7 automatically-chosen levels,
# which should give the same as your code.
N = 7
CS2 = ax2.contourf(X, Y, Z, N, cmap="viridis")
ax2.set_title('N=7')
ax2.set_xlabel('word length anomaly')
ax2.set_ylabel('sentence length anomaly')
cbar2 = fig.colorbar(CS2, ax=ax2)
# Contour up to N=100 automatically-chosen levels.
# The resolution is still not as high as using imshow().
N = 100
CS3 = ax3.contourf(X, Y, Z, N, cmap="viridis")
ax3.set_title('N=100')
ax3.set_xlabel('word length anomaly')
ax3.set_ylabel('sentence length anomaly')
cbar3 = fig.colorbar(CS3, ax=ax3)
IM = ax4.imshow(Z, cmap="viridis", origin='lower', extent=(-3, 3, -3, 3))
ax4.set_title("Warren Weckesser's idea")
ax4.set_xlabel('word length anomaly')
ax4.set_ylabel('sentence length anomaly')
cbar4 = fig.colorbar(IM, ax=ax4)
fig.tight_layout()
plt.show()

Plotting image Red channel by intensity

Okay, So i'm trying to take the red channel of an image, and plot it (preferably 3d) to an image. The image is 480x640 (or thereabouts), and is taken from a webcam. I'm currently using scipy, numpy, and python to get the image, extract he red channel, and process it. That all works.
However, when i try to plot it, 2 different problems occur, depending on how I try to plot:
1) Width mismatch, it doesn't like that the image isn't square.
2) It only plots one row of the image (x val = 0, all y vals).
I've attached the relevent code. Comments are everywhere, for when i try different ways.
fig = plt.figure()
#ax = Axes3D(fig)
#ax = fig.add_subplot(111, projection='3d')
X = [range(480), range(480)]
Y = [range(480), range(480)]
#X = range(len(self.R))
#Y = range(len(self.R))
'''
surf = ax.plot_surface(X, Y, np.resize(self.R, (480, 480)) , rstride=1, cstride=10, cmap=cm.jet, linewidth=0, antialiased=False)
ax.set_zlim3d(0.0, 255.0)
ax.w_zaxis.set_major_locator(LinearLocator(100))
ax.w_zaxis.set_major_formatter(FormatStrFormatter('%.03f'))
m = cm.ScalarMappable(cmap=cm.jet)
m.set_array(self.frame_in)
fig.colorbar(m)
np.savetxt("tmp.txt", self.R)
'''
#np.savetxt("tmp.out", self.R[0])
#np.savetxt("tmp.out1", self.R[1])
#np.savetxt("tmp.txt", self.frame_in, "[ %s ]", "\t")
#plt.subplot(212)
#x, y = self.R.shape
#x = range(x)
#y = range(y)
#X, Y = np.meshgrid(x, y)
plt.scatter(X, Y, self.R)
#plt.pcolormesh(self.R)
#plt.colorbar()
#ax.scatter(x, y, self.R, c='r', marker='o')
plt.show()
I can clean up the code if needed, but i wanted everyone to see the multiple ways i've tried. Am i missing something really stupid simple? It doesn't make sense that it will work with the first row, and not all of them.
Thanks in advance!
Try using pyplot.imshow:
plt.cmap('Reds')
plt.imshow(self.R)
plt.show()

Grid Lines below the contour in Matplotlib

I have one question about the grid lines matplotlib.
I am not sure if this is possible to do or not.
I am plotting the following graph as shown in the image.
I won't give the entire code, since it is involving reading of files.
However the important part of code is here -
X, Y = np.meshgrid(smallX, smallY)
Z = np.zeros((len(X),len(X[0])))
plt.contourf(X, Y, Z, levels, cmap=cm.gray_r, zorder = 1)
plt.colorbar()
...
# Set Border width zero
[i.set_linewidth(0) for i in ax.spines.itervalues()]
gridLineWidth=0.1
ax.set_axisbelow(False)
gridlines = ax.get_xgridlines()+ax.get_ygridlines()
#ax.set_axisbelow(True)
plt.setp(gridlines, 'zorder', 5)
ax.yaxis.grid(True, linewidth=gridLineWidth, linestyle='-', color='0.6')
ax.xaxis.grid(False)
ax.xaxis.set_ticks_position('none')
ax.yaxis.set_ticks_position('none')
Now, my questions is like this -
If I put the grid lines below the contour, they disappear since they are below it.
If I put the grid line above the contour, they looks like what they are looking now.
However, what I would like to have is the grid lines should be visible, but should be below the black portion of the contour. I am not sure if that is possible.
Thank You !
In addition to specifying the z-order of the contours and the gridlines, you could also try masking the zero values of your contoured data.
Here's a small example:
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(-2*np.pi, 2*np.pi, 0.1)
y = np.arange(-2*np.pi, 2*np.pi, 0.1)
X, Y = np.meshgrid(x, y)
Z = np.sin(X) - np.cos(Y)
Z = np.ma.masked_less(Z, 0) # you use mask_equal(yourData, yourMagicValue)
fig, ax = plt.subplots()
ax.contourf(Z, zorder=5, cmap=plt.cm.coolwarm)
ax.xaxis.grid(True, zorder=0)
ax.yaxis.grid(True, zorder=0)
And the output:

Categories

Resources