Griding with python - python

I am trying to plot a picture like this in python.
I have three parameters for ploting.
x:
[ 0.03570416 0.05201517 0.05418171 0.01868341 0.07116423 0.07547471]
y:
[-0.32079484 -0.53330218 -1.02866859 -0.94808545 -0.51682506 -0.26788337]
z:
[-0.32079484 -0.53330218 -1.02866859 -0.94808545 -0.51682506 -0.26788337]
so x is x-axis and y is y-axis. however z is the intensity of the pixel.
I come up with this code:
z = np.array(reals)
x = np.array(ra)
y = np.array(dec)
nrows, ncols = 10, 10
grid = z.reshape((nrows, ncols))
plt.imshow(grid, extent=(x.min(), x.max(), y.max(), y.min()), interpolation='nearest', cmap=cm.gist_rainbow)
plt.title('This is a phase function')
plt.xlabel('ra')
plt.ylabel('dec')
plt.show()
However I get this error:
grid = z.reshape((nrows, ncols))
ValueError: total size of new array must be unchanged
ra, dec and reals are normal arrays with the same size. I calculated them before and then I create the numpy arrays with them

The data you show is not consistent with making an image, but you could make a scatter plot with it.
The two basic types of plots for z values at (x,y) coordinate pairs are:
scatter plots, where for each (x,y) pair, a z-value is specified.
image (imshow, pcolor, pcolormesh, contour), where an x-axis with m regularly spaced values, and a y-axis with n regularly spaced values are specified, and then an array of z-values with size (m,n) is given.
Your data looks more like the former type, so I'm suggesting a scatter plot.
Here's what a scatter plot looks like (btw, your y and z values are the same, which if probably a mistake):
import numpy as np
import matplotlib.pyplot as plt
x = np.array([ 0.03570416, 0.05201517, 0.05418171, 0.01868341, 0.07116423, 0.07547471])
y = np.array([-0.32079484, -0.53330218, -1.02866859, -0.94808545, -0.51682506, -0.26788337])
z = np.array([-0.32079484, -0.53330218, -1.02866859, -0.94808545, -0.51682506, -0.26788337])
plt.scatter(x, y, c=z, s =250)
plt.show()

Related

colormap from a matrix in python

I have a 2D output matrix (say, Z) which was calculated as a function of two variables x,y.
x varies in a non-uniform manner like [1e-5,5e-5,1e-4,5e-4,1e-3,5e-3,1e-2]
y varies in a uniform manner like [300,400,500,600,700,800]
[ say, Z = np.random.rand(7,6) ]
I was trying to plot a colormap of the matrix Z by first creating a meshgrid for x,y and then using the pcolormesh. Since, my x values are non-uniform, I do not kn ow how to proceed. Any inputs would be greatly appreciated.
No need for meshgrids; regarding the non-uniform axes: In your case a log-scale works fine:
import numpy as np
from matplotlib import pyplot as plt
x = [1e-5,5e-5,1e-4,5e-4,1e-3,5e-3,1e-2]
y = [300,400,500,600,700,800]
# either enlarge x and y by one number (right-most
# endpoint for those bins), or make Z smaller as I did
Z = np.random.rand(6,5)
fig = plt.figure()
ax = fig.gca()
ax.pcolormesh(x,y,Z.T)
ax.set_xscale("log")
fig.show()

Scale a 2D array logarithmically in Python

I have a 2D array of spectrogram data which I am scaling with scikit-image for display in a web browser. I would like to scale the array logarithmically in the y-axis."
I can plot the data logarithmically in the y-axis using Matplotlib, but I want access to the 2D array representation of this newly scaled image, but Matplotlib only provides the original, unscaled array. Scikit-image scales 2D arrays linearly, but not logarithmically.
# plot a log-scaled z
w, h = z.shape
fig, ax = plt.subplots()
ax.set_yscale('symlog')
mesh = ax.pcolormesh(np.arange(h+1), np.arange(w+1), z)
# get the array of z
logimg = mesh.get_array().reshape(mesh._meshHeight, mesh._meshWidth)
Let's start with some example data:
import numpy as np
from scipy.interpolate import interp1d
import matplotlib.pylab as plt
# some 2D example data
x, y = np.arange(30)+1, np.arange(20)+1
x_grid, y_grid = np.meshgrid(x, y)
z_grid = np.cos(2*np.pi*x_grid/10) + np.sin(2*np.pi*y_grid/4)
# Graph 1
plt.pcolormesh(x, np.log(y), z_grid);
plt.xlabel('x'); plt.ylabel('log(y) (non regular spacing)');
Here is a graph with log(y) as vertical axis. The sampling along y is then non uniform (the data are unchanged, they are only drawn on a deformed grid):
In order to get deformed data on a regular grid, an interpolation is performed between log(y) and a new regular y grid:
# Interpolation of the transformed data on a regular new y axis
ylog_interpolation = interp1d(np.log(y), z_grid.T)
new_y = np.linspace(min(np.log(y)), max(np.log(y)), len(y))
new_z_grid = ylog_interpolation(new_y).T
# axis
plt.pcolormesh(x, new_y, new_z_grid);
plt.xlabel('x'); plt.ylabel('new y (regular spacing)');
Now, the grid is regular but the data are deformed, new_z_grid can be exported as an image.

How do I interpolate a 2D gridded point cloud to a continuous area?

I have a 2 dimensional Numpy NDarray filled with floats between 0 and about 8. This 2 dimensional arrays size is (1000, 1600) and there are about 1400 values, (the points in the point cloud), the remaining values are None, so matplotlib does not plot these values. You can see the plotted table in the image below. What I'd like to have is, the None-values interpolated with the values next to it to have a gradientlike heatmap. This pointcloud represents the shape of a roof and I want to process this data to an image I can give into a neural network to detect the type of roof.
The code I used for this plot is pretty short,
import matplotlib.pyplot as plt
plt.clf()
#plotGrid is the numpy.ndarray with shape (1000, 1600) and dtype float
plt.imshow(plotGrid, cmap='gray', interpolation='nearest')
plt.colorbar()
plt.show()
Image (click to enlarge and see points):
tricontourf
You might use a tricontour / tricontourf plot of the valid values. To this end, you first need to filter out all nan values (you should indeed make the invalid values np.nan instead of None).
Those values, together with their coordinates can be put into plt.tricontourf() to obtain a contour plot without the need of manual interpolation.
import matplotlib.pyplot as plt
import numpy as np
# Generate some example data
f = lambda x,y : np.exp((-(x-150)**2-(y-150)**2)/3.e3)
plotGrid = np.zeros((300,300))*np.nan
coo = np.random.randint(5,295, size=(150,2) )
for x,y in coo:
plotGrid[y,x] = f(x,y)
#plotGrid is now a numpy.ndarray with shape (300,300), mostly np.nan, and dtype float
# filter out nan values and get coordinates.
x,y = np.indices(plotGrid.shape)
x,y,z = x[~np.isnan(plotGrid)], y[~np.isnan(plotGrid)], plotGrid[~np.isnan(plotGrid)]
plt.tricontourf(x,y,z)
plt.colorbar()
plt.show()
tripcolor
Using tripcolor is another option then:
plt.tripcolor(x,y,z, shading='gouraud')
interpolate and contourf
You can also interpolate the data on a grid first, using matplotlib.mlab.griddata, and then either use a normal contourf plot,
xi = np.linspace(0, plotGrid.shape[1], plotGrid.shape[1])
yi = np.linspace(0, plotGrid.shape[0], plotGrid.shape[0])
zi = mlab.griddata(x, y, z, xi, yi, interp='linear')
plt.contourf(xi, yi, zi, 15)
interpolate and imshow
Or in the same manner use an imshow plot,
plt.imshow(zi)
I think scipy.interpolate.interp2d does what you need:
import scipy.interpolate
z_all = plotGrid.astype(float) # convert nones to nan
x_all, y_all = np.indices(plotGrid.shape) # get x and y coordinates
# convert to 1d arrays of coordinates
valid = ~np.isnan(z_all)
x, y, z = x_all[valid], y_all[valid], z_all[valid]
# interpolate
interp = scipy.interpolate.interp2d(x, y, z)
filled_data = interp(x_all[:,0], y_all[0,:]) # this is kinda gross, but `interp` doesn't
# do normal broadcasting
plt.imshow(filled_data)

How to do 4D plot in matplotlib without np.meshgrid?

I know that I can do a 4D plot in matplotlib with the following code, with the fourth dimension shown as a colormap:
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from matplotlib import cm
fig = plt.figure()
ax = fig.add_subplot(111,projection= '3d' )
x = np.arange(100)/ 101
y = np.sin(x) + np.cos(x)
X,Y = np.meshgrid(x,y)
Z = (X**2) / (Y**2)
A = np.sin(Z)
ax.plot_surface(X,Y, Z, facecolors=cm.Oranges(A))
plt.show()
But what if my data is not a function of the other data? How do I do this without np.meshgrid? (In other words, my Z series cannot be a function of the output of the X,Y which is the output of np.meshgrid(x,y), because Z is not a function of X and Y.)
A surface plot is a mapping of 2D points to a 1D value, i.e. for each pair of (x,y) coordinates you need exactly one z coordinate. So while it isn't strictly necessary to have Z being a function of X and Y, those arrays to plot need to have the same number of elements.
For a plot_surface the restriction is to have X and Y as gridded 2D data. Z does not have to be 2D but needs to have the same number of elements.
This requirement can be weakened using a plot_trisurf where the only requirement is that there is a strict mapping of x,y,z, i.e. the ith value in X and Y corresponds to the ith value in Z.
In any case, even if there is no analytic function to map X and Y to Z, Z still needs to be some kind of mapping. Otherwise it is even questionable what information the resulting plot would convey.

How do I use Matplotlib pyplot pcolor to provide distinct color to each grid in my plot

I have built some fairly simple logarithmic matplotlib scatter plots. I am happy with the results thus far, but I need to change the color of each grid area.
Current Plot:
I would like to understand how I could do the following:
I appreciate any help. Thanks.
Plot a small image underneath the scatter plot, with an integer indicating the tile color. You can then use pcolor to plot the image, with edgecolors to define the borders. The code below does this, with cell color defined as the maximum of cell index i, j, which happens to match your grid.
import numpy as np
import matplotlib.pyplot as plt
# define grid
nx, ny = 6, 5
x, y = np.arange(nx), np.arange(ny)
xx, yy = np.meshgrid(x, y)
z = np.maximum(xx, yy)
# create random points
npoints = 30
data_x = 10**(np.random.rand(npoints)*nx)
data_y = 10**(np.random.rand(npoints)*ny-1)
# plot grid then points
plt.pcolor(10.**x, 10.**(y-1), z, edgecolors='k')
plt.loglog(data_x, data_y, '.w')
plt.axis([1,10**5,0.1,10**3])
plt.show()
Note that you could also use zorder=n to force the scatter plot above the image.

Categories