Griddata creating bad shapes scipy - python

I am using this code to visualise my data using griddata. The code looks like this:
import math
import numpy as np
from scipy.interpolate import griddata
import matplotlib.pyplot as plt
**THE LIST C=DATA IS IN THE LINK ABOVE**
cx=np.asarray([row[0] for row in C])
cy=np.asarray([row[1] for row in C])
cz=np.asarray([row[2] for row in C])
xi = np.linspace(22.4,22.5,10)
yi = np.linspace(37,37.1,10)
# grid the data.
zi = griddata((cx, cy), cz, (xi[None,:], yi[:,None]), method='nearest')
plt.contourf(xi,yi,zi,300,cmap=plt.cm.jet)
# draw colorbar
plt.colorbar()
plt.xlim(xmin=22.4,xmax=22.5)
plt.ylim(ymin=37,ymax=37.1)
plt.title('no diamonds please')
plt.show()
As you can see there are some diamond shaped shapes which in fact should have been like the contours of a gaussian like for example shown here
Am i doing something wrong? Should i use some other tool instead of griddata? I had problems using sagemath for this and now switched to ""pure" python. Noob level keep in mind :)

Silly as it is, the answer is just to increase the value of "stepsize" in linspace like i.e:
xi = np.linspace(22.4,22.5,100)

Related

Smooth Contourf plot completely filled

I have the data with (X,Y,Z) values. I tried to make a density plot with Z values for intensity. However the plot I get is not smooth and and has polytope i.e not completely filled.
The following is the code with the Data
but I want to obtain smooth and completely filled plot
import numpy as np
from scipy.interpolate import griddata
import matplotlib.pyplot as plt
import xlrd
location = "~/Desktop/Data.xlsx"
data = xlrd.open_workbook(location)
sheet = data.sheet_by_index(0)
sample=2000
x=np.array(sheet.col_values(0))[0:sample]
y=np.array(sheet.col_values(1))[0:sample]
z=np.hamming(9000)[0:sample]
print z
def plot_contour(x,y,z,resolution = 500,contour_method='cubic'):
resolution = str(resolution)+'j'
X,Y = np.mgrid[min(x):max(x):complex(resolution), min(y):max(y):complex(resolution)]
points = [[a,b] for a,b in zip(x,y)]
Z = griddata(points, z, (X, Y), method=contour_method)
return X,Y,Z
X,Y,Z = plot_contour(x,y,z,resolution = 500,contour_method='linear')
plt.style.context("seaborn-deep")
plt.contourf(X,Y,Z)
plt.colorbar()
plt.show()
This is the output:
This is what I want to achieve using contourplotf:
plt.contourf() is not the main problem here, it's just working with the data it has. The problem is the linear interpolation in scipy.interpolate.griddata().
I recommend not using griddata, but instead using one of the following methods:
scipy.interpolate.Rbf() — this is what you were using before (see my previous answer).
verde — an awesome gridding package.
sklearn.gaussian_process — or some other prediction model.
All of these methods will fill in the grid. If you plot the result with plt.imshow() you'll get the type of plot you show in your question — that is not a plt.contourf() plot.
Here's a demo notebook showing all of these approaches (including griddata).

Plotting a 2D contour plot from binned xyz data

EDIT: I responded in the comments but I've tried the method in the marked post - my z data is not calculated form my x and y so I can't use a function like that.
I have xyz data that looks like the below:
NEW:the xyz data in the file i produce - I extract these as x,y,z
And am desperately trying to get a plot that has x against y with z as the colour.
y is binned data that goes from (for instance) 2.5 to 0.5 in uneven bins. So the y values are all the same for one set of x and z data. The x data is temperature and the z is density info.
So I'm expecting a plot that looks like a bunch of stacked rectangles where there is a gradient of colour for one bin of y values which spans lots of x values.
However all the codes I've tried don't like my z values and the best I can do is:
The axes look right but the colour bar goes from the bottom to the top of the y axis instead of plotting one z value for each x value at the correct y value
I got this to work with this code:
import matplotlib.cm as cm
from matplotlib.colors import LogNorm
import numpy as np
import scipy.interpolate
data=pandas.read_csv('Data.csv',delimiter=',', header=0,index_col=False)
x=data.tempbin
y=data.sizefracbin
z=data.den
x=x.values
y=y.values
z=z.values
X,Y=np.meshgrid(x,y)
Z=[]
for i in range(len(x)):
Z.append(z)
Z=np.array(Z)
plt.pcolormesh(X,Y,Z)
plt.colorbar()
plt.show()
I've tried everything I could find online such as in the post here: matplotlib 2D plot from x,y,z values
But either there is a problem reshaping my z values or it just gives me empty plots with various errors all to do (I think) with my z values.
Am I missing something? Thank you for your help!
Edit in reponse to : ImportanceOfBeingErnest
I tried this :
import matplotlib.cm as cm
from matplotlib.colors import LogNorm
import numpy as np
import scipy.interpolate
data=pandas.read_csv('Data.csv',delimiter=',', header=0,index_col=False)
data.sort_values('sizefrac')
x=data.tempbin
y=data.sizefrac
z=data.INP
x=x.values
y=y.values
z=z.values
X=x[1:].reshape(N,N)
Y=y[1:].reshape(N,N)
Z=z[1:].reshape(N,N)
plt.pcolormesh(X,Y,Z)
plt.colorbar()
plt.show()
and got a very empty plot. Just showed me the axes and colourbar as in my attached image but pure white inside the axes! No error or anything...
And the reshaping I need to remove a data point from each because otherwise the reshaping won't work
Adapting the linked question to you problem, you should get:
import numpy as np
import matplotlib.pyplot as plt
x = list(range(10))*10
y = np.repeat(list(range(10)), 10)
# build random z data
z = np.multiply(x, y)
N = int(len(z)**.5)
Z = z.reshape(N, N)
plt.imshow(Z[::-1], extent=(np.amin(x), np.amax(x), np.amin(y), np.amax(y)), aspect = 'auto')
plt.show()
The answer was found by Silmathoron in a comment on his answer above - the answer above did not help but in the comments he noticed that the X,Y data was not gridded in w way which would create rectangles on the plot and also mentioned that Z needed to be one smaller than X and Y - from this I could fix my code - thanks all

Plotting 1-D dataset with radial symmetry around the origin in Python

This is likely a very basic question, but my python knowledge is somewhat limited and I've had some trouble deciphering other questions+answers, so I'm hoping someone here can help...
I have a set of 1-D data points (the number of molecules at each point along a radius, essentially) that I want to plot as a 2-D radially symmetrical image. I want to rotate it around an origin (0,0).
Basically, I have something like
but I want something like
I've seen this done relatively easily with functions or defined vectors (i.e. with scipy's interpolate module), but I don't have a function or randomly-generated data -- I have a list. I know there must be a simple way to do this, but I'd really appreciate it if someone could point me in the right direction!
I've included a really really small example dataset (plotted as a line in log scale) for people to play with if they feel so inclined:
import numpy as np
import matplotlib.pyplot as plt
rad25 = np.array([25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1])
O_rad25 = np.array([1.01E+15,3.00E+14,1.20E+14,5.63E+13,2.90E+13,1.59E+13,9.21E+12,5.53E+12,3.43E+12,2.18E+12,1.42E+12,9.44E+11,6.38E+11,4.37E+11,3.03E+11,2.13E+11,1.51E+11,1.08E+11,7.77E+10,5.60E+10,4.02E+10,2.84E+10,1.94E+10,1.20E+10,5.78E+09])
plt.plot(rad25,O_rad25)
plt.yscale('log')
plt.xlabel('Radius (distance from center in um)')
plt.ylabel('Number of molecules')
plt.show()
You need to create an array of values from 0 - 360 degrees, and then create a meshgrid from this array and your array of values. This can then be plotted on a radially projected subplot.
Something like this, but with your data of cause:
import numpy as np
import matplotlib.pyplot as plt
# Swap out with your data
radialVals = np.linspace(0,1)
azm = np.linspace(0, 2 * np.pi)
r, th = np.meshgrid(radialVals, azm)
z = (r ** 2.0) / 4.0
plt.subplot(projection="polar")
plt.pcolormesh(th, r, z)
plt.plot(azm, r, ls='none')
plt.grid()
plt.show()
I borrowed some from Jon's answer (his is very nearly correct), and added a colorbar to illustrate, but this should get you what you want. Since you know your radius and that your data has radial symmetry, a polar plot is the natural choice.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import colors
fig, ax = plt.subplots(subplot_kw=dict(projection='polar'))
azm = np.linspace(0, 2 * np.pi)
r, th = np.meshgrid(rad25, azm)
z = np.tile(O_rad25, (r.shape[0], 1))
plt.pcolormesh(th, r, z, norm=colors.LogNorm(O_rad25.min(), O_rad25.max()))
plt.colorbar(label='Number of Molecules')

Python / PyPlot- How can I specify the x/y-axis on plt.imshow?

Often when I want to visualise 3D data I do the following
import numpy as np
import matplotlib.pyplot as plt
X, Y = np.mgrid[:10, :20]
z = x**2 + y
plt.imshow(z)
plt.show()
The problem with this is that often I want to set the x and y variables instead of being "pixels". I know plt.contourf does what I want but the problem with that is the quality is no where near as good as plt.imshow
The solution I'm trying to work towards is getting the plt.contourf syntax to work for plt.imshow.
Any ideas?
EDIT:
The solution should also work on the following use case:
import numpy as np
import matplotlib.pyplot as plt
R, P = np.mgrid[:10, :2*np.pi:np.pi/50]
plt.contourf(R*np.cos(P), R*np.sin(P), R) # <--- need better function
# plt.imshow(R*np.cos(P), R*np.sin(P), R) # something like this
plt.show()
The best way I found to do what I want is to use the plt.contourf
so the following would do what I want.
import numpy as np
import matplotlib.pyplot as plt
R, P = np.mgrid[:10, :2*np.pi:np.pi/50]
N = 50
plt.contourf(R*np.cos(P), R*np.sin(P), R, N) # <--- need better function
plt.pcolormesh(R*np.cos(P), R*np.sin(P), R) # <--- exactly what I want
# plt.imshow(R*np.cos(P), R*np.sin(P), R) # something like this
plt.show()
Tweaking N gets you a good enough image in contourf. The only thing I don't like about this is the very fact you might need to tweak the N value.

Matplotlib tripcolor bug?

I want to use tripcolor from matplotlib.pyplot to view the colored contours of some of my data.
The data is extracted from an XY plane at z=cst using Paraview. I directly export the data in csv from Paraview which triangulates the plane for me.
The problem is that depending on the plane position (ie the mesh) tripcolor gives me sometimes good or bad results.
Here is a simple example code and results to illustrate it:
Code
import matplotlib.pyplot as plt
import numpy as np
p,u,v,w,x,y,z = np.loadtxt('./bad.csv',delimiter=',',skiprows=1,usecols=(0,1,2,3,4,5,6),unpack=True)
NbLevels = 256
plt.figure()
plt.gca().set_aspect('equal')
plt.tripcolor(x,y,w,NbLevels,cmap=plt.cm.hot_r,edgecolor='black')
cbar = plt.colorbar()
cbar.set_label('Velocity magnitude',labelpad=10)
plt.show()
Results with tripcolor
Here is the file that causes the problem.
I've heard that matplotlib's tripcolor is sometimes buggy, so is it a bug or not ?
As highlighted by #Hooked this is the normal behaviour for a Delaunay triangulation.
To remove unwanted triangles you should provide your own Triangulation by passing explicitly the triangles.
This is quite easy in your case as your data is almost structured: I suggest performing a Delaunay triangulation in the plane (r, theta) then passing these triangles to the initial (x, y) arrays. You can make use of the the built-in TriAnalyzer class to remove very flat triangles from the (r, theta) triangulation (they might exists due to round-off errors).
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.tri as mtri
p,u,v,w,x,y,z = np.loadtxt('./bad.csv',delimiter=',',skiprows=1,usecols=(0,1,2,3,4,5,6),unpack=True)
r = np.sqrt(y**2 + x**2)
tan = (y / x)
aux_tri = mtri.Triangulation(r/np.max(r), tan/np.max(tan))
triang = mtri.Triangulation(x, y, aux_tri.triangles)
triang.set_mask(mtri.TriAnalyzer(aux_tri).get_flat_tri_mask())
NbLevels = 256
plt.figure()
plt.gca().set_aspect('equal')
plt.tripcolor(triang, w, NbLevels, cmap=plt.cm.jet, edgecolor='black')
cbar = plt.colorbar()
cbar.set_label('Velocity magnitude',labelpad=10)
plt.show()
It's probably because the Delaunay triangulation called by Paraview created a convex hull of the points (as it should). To test this, I used matplotlib.tri.Triangulation and plotted the resulting mesh from the x-y values:
import matplotlib.tri as tri
plt.scatter(x,y)
w[:] = 1
triang = tri.Triangulation(x, y)
plt.tripcolor(triang,w,alpha=.2)
which shows the same effect. It may be possible to remove the unwanted triangles from the mesh, either by hand, or using a non-convex boundary finder.

Categories