I am trying to make a contour plot like:
Using a table of data like 3 columns in a txt file, with a long number of lines.
Using this code:
import numpy as np
import matplotlib.pyplot as plt
import scipy.interpolate
data = np.loadtxt(r'dataa.txt')
a = [data[:,0]]
b = [data[:,1]]
n = [data[:,2]]
x = np.asarray(a)
y = np.asarray(b)
z = np.asarray(n)
print "x = ", x
print "y = ", y
print "z = ", z
fig=plt.figure()
CF = contour(x,y,z,colors = 'k')
plt.xlabel("X")
plt.ylabel("Y")
plt.colorbar()
plt.show()
I don't know why, it is not working. Python gives me the right axes for the values that I am expecting to see, but in the graph is just a blank and I know that it is importing the data in right way because it shows me my values before the plot.
Example of table: (the diference is because my table has 90000 lines)
Using this code:
import numpy as np
import matplotlib.pyplot as plt
import scipy.interpolate
N = 1000 #number of points for plotting/interpolation
x, y, z = np.genfromtxt(r'dataa.txt', unpack=True)
xi = np.linspace(x.min(), x.max(), N)
yi = np.linspace(y.min(), y.max(), N)
zi = scipy.interpolate.griddata((x, y), z, (xi[None,:], yi[:,None]), method='cubic')
fig = plt.figure()
plt.contour(xi, yi, zi)
plt.xlabel("X")
plt.ylabel("Y")
plt.show()
Ive got this result:
I think I've got the advices wrongly.
Followup from my comment... first, I would replace all these lines:
data = np.loadtxt(r'dataa.txt')
a = [data[:,0]]
b = [data[:,1]]
n = [data[:,2]]
x = np.asarray(a)
y = np.asarray(b)
z = np.asarray(n)
With:
x, y, z = np.genfromtxt(r'dataa.txt', unpack=True)
Your original code is adding an extra axis at the front, since [data[:,0]] is a list of arrays with one element. The result is that x.shape will be (1, N) instead if (N,). All of this can be done automatically using the last line above, or you could just use the same data loading and say:
x = data[:,0]
y = data[:,1]
z = data[:,2]
since those slices will give you an array back.
However, you're not quite done, because plt.contour expects you to give it a 2d array for z, not a 1d array of values. Right now, you seem to have z values at given x, y points, but contour expects you to give it a 2d array, like an image.
Before I can answer that, I need to know how x and y are spaced. If regularly, you can just populate an array pretty easily. If not regularly, you basically have to interpolate before you can make a contour plot.
To do the interpolation, use
import numpy as np
import matplotlib.pyplot as plt
import scipy.interpolate
N = 1000 #number of points for plotting/interpolation
x, y, z = np.genfromtxt(r'dataa.txt', unpack=True)
xi = np.linspace(x.min(), x.max(), N)
yi = np.linspace(y.min(), y.max(), N)
zi = scipy.interpolate.griddata((x, y), z, (xi[None,:], yi[:,None]), method='cubic')
fig = plt.figure()
plt.contour(xi, yi, zi)
plt.xlabel("X")
plt.ylabel("Y")
plt.show()
The code below worked for me:
import scipy.interpolate
import numpy as np
N = 500 #number of points for plotting/interpolation
x, y, z = np.genfromtxt(r'data.dat', unpack=True)
xll = x.min(); xul = x.max(); yll = y.min(); yul = y.max()
xi = np.linspace(xll, xul, N)
yi = np.linspace(yll, yul, N)
zi = scipy.interpolate.griddata((x, y), z, (xi[None,:], yi[:,None]), method='cubic')
contours = plt.contour(xi, yi, zi, 6, colors='black')
plt.clabel(contours, inline=True, fontsize=7)
plt.imshow(zi, extent=[xll, xul, yll, yul], origin='lower', cmap=plt.cm.jet, alpha=0.9)
plt.xlabel(r'$x$')
plt.ylabel(r'$y$')
plt.clim(0, 1)
plt.colorbar()
plt.show()
Related
Very simple, if I plot x^2+y^2=z it makes this shape on python it will make this shape:
When I would like to plot it this way:
Below is my code, I am new so I copied it from the internet and have changed the line with the function to plot.
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(-4*np.pi,4*np.pi,50)
y = np.linspace(-4*np.pi,4*np.pi,50)
z = x**2+y**2
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot(x,y,z)
plt.show()
Also, how do I make it more high definition and smooth, this is a graph of z=sin(x)
You need to define a 2D mathematical domain with numpy.meshgrid, then you can compute the surface on that domain:
X, Y = np.meshgrid(x, y)
Z = X**2 + Y**2
In order to increase the smoothness of the surface, you have in increase the number of point N you use to compute x and y arrays:
Complete code
import matplotlib.pyplot as plt
import numpy as np
N = 50
x = np.linspace(-4*np.pi, 4*np.pi, N)
y = np.linspace(-4*np.pi, 4*np.pi, N)
X, Y = np.meshgrid(x, y)
Z = X**2 + Y**2
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot_surface(X, Y, Z)
plt.show()
These meshgrid is a little confusing to use for me. I'm trying to do a scatter plot with the x and y coordinates with a contour plot overlaid on the scatter with a continuous spread for the z coordinates. Similar to an elevation map.
If I use meshgrid with the x,y, and z coordinates then I get 3D array for each which is still the incorrect input.
df_xyz = pd.read_table("https://pastebin.com/raw/f87krHFK", sep="\t", index_col=0)
x = df_xyz.iloc[:,0].values
y = df_xyz.iloc[:,1].values
z = df_xyz.iloc[:,2].values
XX, YY = np.meshgrid(x,y)
with plt.style.context("seaborn-white"):
fig, ax = plt.subplots(figsize=(13,8))
ax.scatter(x,y, color="black", linewidth=1, edgecolor="ivory", s=50)
ax.contourf(XX,YY,z)
# TypeError: Input z must be a 2D array.
XX, YY, ZZ = np.meshgrid(x,y,z)
with plt.style.context("seaborn-white"):
fig, ax = plt.subplots(figsize=(13,8))
ax.scatter(x,y, color="black", linewidth=1, edgecolor="ivory", s=50)
ax.contourf(XX,YY,ZZ)
# TypeError: Input z must be a 2D array.
Here's my current output:
I am trying to do something similar to this:
import pandas as pd
import numpy as np
from scipy.interpolate import griddata
import matplotlib.pyplot as plt
%matplotlib inline
df_xyz = pd.read_table("https://pastebin.com/raw/f87krHFK", sep="\t", index_col=0)
x = df_xyz.iloc[:,0].values
y = df_xyz.iloc[:,1].values
z = df_xyz.iloc[:,2].values
def plot_contour(x,y,z,resolution = 50,contour_method='linear'):
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 = 50,contour_method='linear')
with plt.style.context("seaborn-white"):
fig, ax = plt.subplots(figsize=(13,8))
ax.scatter(x,y, color="black", linewidth=1, edgecolor="ivory", s=50)
ax.contourf(X,Y,Z)
Is it possible to plot multiple surfaces in one pyplot figure? Here is my attempt. The ax.plot_surface command seems to reset the figure, as I only get a single plane in the resulting plot. I am hoping to produce "stacked" planes, each with distinctive colors, and a color bar showing the numeric value of each color. Currently my colors show up wrong.
import numpy as np
import pandas as pd
import matplotlib
import matplotlib.pyplot as plt
from matplotlib import cm
from mpl_toolkits.mplot3d import Axes3D
import pylab
from scipy.interpolate import griddata
dat = open('ex.csv', 'w')
dat.write('x,y,z,c\n')
for x in range(20):
for y in range(20):
for c in range(0,7):
dat.write(','.join([str(s) for s in [x,y,x+y+c,c/10.0,'\n']]))
dat.close()
fig = matplotlib.pyplot.gcf()
dat = np.genfromtxt('ex.csv', delimiter=',',skip_header=1)
X_dat = dat[:,0]
Y_dat = dat[:,1]
Z_dat = dat[:,2]
C_dat = dat[:,3]
ax1 = fig.add_subplot(111, projection='3d')
for color in np.unique(C_dat):
X, Y, Z, C = np.array([]), np.array([]), np.array([]), np.array([])
for i in range(len(X_dat)):
if C_dat[i]==color:
X = np.append(X,X_dat[i])
Y = np.append(Y,Y_dat[i])
Z = np.append(Z,Z_dat[i])
C = np.append(C,C_dat[i])
xi = np.linspace(X.min(),X.max(),100)
yi = np.linspace(Y.min(),Y.max(),100)
zi = griddata((X, Y), Z, (xi[None,:], yi[:,None]), method='cubic')
ci = griddata((X, Y), C, (xi[None,:], yi[:,None]), method='cubic')
xig, yig = np.meshgrid(xi, yi)
surf = ax1.plot_surface(xig, yig, zi,facecolors=cm.rainbow(ci), alpha = 0.7)
xi = np.linspace(X_dat.min(),X_dat.max(),100)
yi = np.linspace(Y_dat.min(),Y_dat.max(),100)
ci = griddata((X_dat, Y_dat), C_dat, (xi[None,:], yi[:,None]), method='cubic')
m = cm.ScalarMappable(cmap=cm.rainbow)
m.set_array(ci)
col = plt.colorbar(m)
plt.show()
(there should be a red plane)
Move the line
ax1 = fig.add_subplot(111, projection='3d')
outside of the for color in... loop. By recreating the axes each iteration, you hide the previously created surfaces
EDIT (to answer second question about colormaps)
You need to normalise your data. Currently, you have facecolors in the range 0 to 0.6, so when you feed the maximum (0.6) to cm.rainbow, you get green, not red (since it expects a range of 0 to 1).
Here's a modified script, which I think works as it should. We use Normalise from matplotlib.colors with a vmin and vmax determined from your C_dat data. Then, use facecolors=cm.rainbow(norm(ci)) to set the colors of your surfaces.
You also then want to set the array of your ScalarMappable using the values in C_dat, so we don't need to use griddata again here.
import numpy as np
import pandas as pd
import matplotlib
import matplotlib.pyplot as plt
from matplotlib import cm
import matplotlib.colors as colors
from mpl_toolkits.mplot3d import Axes3D
import pylab
from scipy.interpolate import griddata
dat = open('ex.csv', 'w')
dat.write('x,y,z,c\n')
for x in range(20):
for y in range(20):
for c in range(0,7):
dat.write(','.join([str(s) for s in [x,y,x+y+c,c/10.0,'\n']]))
dat.close()
fig = matplotlib.pyplot.gcf()
dat = np.genfromtxt('ex.csv', delimiter=',',skip_header=1)
X_dat = dat[:,0]
Y_dat = dat[:,1]
Z_dat = dat[:,2]
C_dat = dat[:,3]
# Create a Normalize instance.
norm = colors.Normalize(vmin=C_dat.min(),vmax=C_dat.max())
ax1 = fig.add_subplot(111, projection='3d')
for color in np.unique(C_dat):
X, Y, Z, C = np.array([]), np.array([]), np.array([]), np.array([])
for i in range(len(X_dat)):
if C_dat[i]==color:
X = np.append(X,X_dat[i])
Y = np.append(Y,Y_dat[i])
Z = np.append(Z,Z_dat[i])
C = np.append(C,C_dat[i])
xi = np.linspace(X.min(),X.max(),100)
yi = np.linspace(Y.min(),Y.max(),100)
zi = griddata((X, Y), Z, (xi[None,:], yi[:,None]), method='cubic')
ci = griddata((X, Y), C, (xi[None,:], yi[:,None]), method='cubic')
xig, yig = np.meshgrid(xi, yi)
# Note the use of norm in the facecolors option
surf = ax1.plot_surface(xig, yig, zi,facecolors=cm.rainbow(norm(ci)), alpha = 0.7)
m = cm.ScalarMappable(cmap=cm.rainbow)
m.set_array(np.unique(C_dat))
col = plt.colorbar(m)
plt.show()
I have some 3D data e.g. d=[x, y, z, f]
where z is a column of numbers in Z, used as color information.
f is a flag which is
0 if x and y have some specific values (ugly^^)
1 if x and y are ok
So for the good data d[ d[:,3] == 1 ] I want to generate a profile
plt.imshow(resampled.T, extent=extent, vmin=MIN, vmax=MAX, origin='lower')
and for the ugly data d[ d[:,3] == 0 ] I want to just use a specific color, e.g. black
Is there a way to realize that?
EDIT: Combining the comments of #eumiro and #Rutger Kassies, I have now the following result
Which is satisfying I think.
For the sake of completeness (or maybe there are some optimization I'm not aware of^^), here is the code and the data:
import numpy as np
from matplotlib.mlab import griddata
import matplotlib
import matplotlib.pyplot as plt
def plotprofile(x, y, z0, name='dummy', save=1):
#plt.figure()
N = 50j
z = z0[:,0]
extent = (min(x), max(x), min(y), max(y))
xs,ys = np.mgrid[extent[0]:extent[1]:N, extent[2]:extent[3]:N]
resampled = griddata(x, y, z, xs, ys)
cmap = plt.get_cmap()
cmap.set_bad(color = 'k', alpha = 1.)
#plt.imshow(resampled.T, cmap='Greys', extent=extent, origin='lower', interpolation='spline36')
plt.imshow(resampled.T, cmap=cmap, extent=extent, origin='lower', vmin=min(z), vmax=-min(z),interpolation='spline36')
cbar=plt.colorbar()
s=20
plt.ylabel(r"$y$", size=s)
plt.xlabel(r"$x", size=s)
plt.xlim([x.min(),x.max()])
plt.ylim([y.min(),y.max()])
if save:
for end in ["pdf", "png", "eps"]:
print "save %s.%s"%(name,end)
plt.savefig("%s.%s"%(name,end))
else:
plt.show()
plt.clf()
if __name__ == '__main__':
filename = 'data.txt'
data = np.loadtxt(filename)
x = data[:,0]
y = data[:,1]
z = data[:,3:]
plotprofile(x, y, z, 'dummy', 0)
Can't you create just a normal colourmap in z by using f to mask z?
dd = d[:, :3]
dd[:,2] = dd[:,2] * d[:,3]
Then convert to an image like this:
M = dd.max(0)
m = dd.min(0)
x = np.arange(m[0], M[0] + 1)
y = np.arange(m[1], M[1] + 1)
[X, Y] = np.meshgrid(x, y)
Z = np.zeros_like(X)
for num in range(0,size(dd, 0)):
Z[dd[num, 0], dd[num, 1]] = dd[num, 2]
Now you should be able to plot Z like a normal image or as a surface against [X, Y]
I' m trying to plot a 3d surface with python in fact i have this code:
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
import matplotlib.pyplot as plt
from numpy import *
def f(x,y):
r=x**2 + y**2
return r
n=4.
b=1.
a=-b
h=(2*b)/n
print h
hx=h ##This line##
fig = plt.figure()
ax = Axes3D(fig)
X = arange(a, b+hx, hx)
Y = arange(a, b+h, h)
n = len(X)
m = len(Y)
Z = zeros([n,m])
for i in arange(n):
for j in arange(m):
Z[i,j] = f(X[i],Y[j])
X, Y = meshgrid(X, Y)
ax.plot_surface(Y, X, Z, rstride=1, cstride=1, cmap=cm.jet)
ax.set_xlabel("X Axis")
ax.set_ylabel("Y Axis")
ax.set_zlabel("Z Axis")
plt.show()
This runs Ok and show me the graph I am looking. But when I change ##This line## into hx=h/2. And run it, the graph goes to hell, it's horrible and impossible to understand. I want to have a closer grid in X than Y axis. How I can do this??
Of course this is an example I am solving a partial differential equation, and i need to have a grid closer in one axis than the other one to have numerical estability.
You have flipped your dimensions
Z = zeros([m,n])
for i in arange(n):
for j in arange(m):
Z[j,i] = f(X[i],Y[j])
X, Y = meshgrid(X, Y)
works for any ratio of n to m.
With the function you have, you can use numpy's broadcasting and write this whole section as
X, Y = meshgrid(X, Y)
Z = f(X,Y)
which is both easier to read and faster.
I would re-write this whole block of code as:
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
import matplotlib.pyplot as plt
from numpy import *
def f(x,y):
r=x**2 + y**2
return r
n = 5
m = 10
b = 1.
a = -b
fig = plt.figure()
ax = Axes3D(fig)
X = linspace(a,b,n)
Y = linspace(a,b,m)
X, Y = meshgrid(X, Y)
Z = f(X,Y)
ax.plot_surface(Y, X, Z, rstride=1, cstride=1, cmap=cm.jet)
ax.set_xlabel("X Axis")
ax.set_ylabel("Y Axis")
ax.set_zlabel("Z Axis")
plt.show()