I have an array of x,y values that I got from a contour plot and I want to plot these values. Because it is a circle inside a circle pyplot draws an arbitrary line between the circles. Does anyone know of a way to remove this line?
I tried sorting the points which does not work. The only way I can think of removing this line is by manually moving the values to a new array and plotting them separately. However I have several of these cases and would prefer not to sift through every data point.
#Plotted contours of a variable
cs1 = ax1.contourf(x,z,refl0,clevs)
#Get the contour lines for the 10th contour of the plot
p1 = cs1.collections[10].get_paths()[0]
v = p1.vertices
x1=v[:,0]
y1=v[:,1]
#Plot the contour lines
ax1 = plt.subplot(111)
ax1.plot(x1,y1)
Here is a generic example code
import numpy as np
from matplotlib import pyplot as plt
x= np.arange(-100,100,10)
y= np.arange(-100,100,10)
#Make a random circular function
xi,yi = np.meshgrid(x,y)
z= 2*xi +xi**2 -yi +yi**2
#This is the contour plot of the data
ax = plt.subplot(111)
clevs = np.arange(-100,110,10)*100
cs1 = ax.contourf(xi,yi,z,clevs)
plt.show()
#Get the contour lines for the 10th contour of the above plot
p1 = cs1.collections[11].get_paths()[0]
v = p1.vertices
x1=v[:,0]
y1=v[:,1]
#Plot the contour lines
ax1 = plt.subplot(111)
ax1.plot(x1,y1)
plt.show()
If the aim is to draw two specific contour lines, you can simply select the levels in question and do a contour plot of them:
import numpy as np
from matplotlib import pyplot as plt
x= np.arange(-100,100,10)
y= np.arange(-100,100,10)
#Make a random circular function
xi,yi = np.meshgrid(x,y)
z= 2*xi +xi**2 -yi +yi**2
ax = plt.subplot(111)
clevs = np.arange(-100,110,10)*100
cs1 = ax.contourf(xi,yi,z,clevs)
# chose level number 11 and 12 and draw them in black.
cs2 = ax.contour(xi,yi,z,clevs[11:13], colors="k")
plt.show()
Related
I have three variables for my plot and I colour by the fourth variable. I have made a scatter plot via the following code, but I want a contour plot. My code:
import numpy as np
import matplotlib.pyplot as plt
a=np.linspace(4.0,14.0,3)
b=np.linspace(0.5,2.5,3)
c=np.linspace(0.0,1.0,3)
d=np.random.rand(len(a),len(b),len(c)) #colour by this variable
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
z,y,x=np.meshgrid(c,a,b)
img = ax.scatter(x, y, z, c=d, cmap='RdGy')
fig.colorbar(img, pad=0.2).set_label('colour')
ax.set_xlabel('c')
ax.set_ylabel('a')
ax.set_zlabel('b')
I want a filled contour instead of scatter plot. I know mayavi.mlab has this feature, but I cannot import mlab for some reason. Is there an alternative, or is there a better way of presenting this data?
Here is how I would present this 3-dimensional data. Each plot is a cross-section through the cube. This makes sense intuitively.
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(4.0, 14.0, 3)
y = np.linspace(0.5, 2.5, 3)
z = np.linspace(0.0, 1.0, 3)
data = np.random.rand(len(x), len(y), len(z))
fig, axes = plt.subplots(len(z), 1, figsize=(3.5, 9),
sharex=True,sharey=True)
for i, (ax, d) in enumerate(zip(axes, data.swapaxes(0, 2))):
ax.contour(x, y, d)
ax.set_ylabel('y')
ax.grid()
ax.set_title(f"z = {z[i]}")
axes[-1].set_xlabel('x')
plt.tight_layout()
plt.show()
My advice: 3D plots are rarely used for serious data visualization. While they look cool, it is virtually impossible to read any data points with any accuracy.
Same thing goes for colours. I recommend labelling the contours rather than using a colour map.
You can always use a filled contour plot to add colours as well.
I haven't found an answer to this yet: I have a grid defined in a text file with four columns: (lon,lat,depth,slip). Each row is a grid point.
I can generate a scatter plot of these points using the following simple code:
# Main imports:
import numpy as np
from pylab import *
from mpl_toolkits.mplot3d import Axes3D
# Read the grid:
points = np.loadtxt("grid.txt")
# Retrieve parameters from the grid:
lon = points[:,0]
lat = points[:,1]
depth = points[:,2]
slip = points[:,3]
# 3-D plot of the model:
fig = figure(1)
ax = fig.add_subplot(111, projection='3d')
p = ax.scatter(lon, lat, depth, c=slip, vmin=0, vmax=max(slip), s=30, edgecolor='none', marker='o')
fig.colorbar(p)
title("Published finite fault in 3-D")
ax.set_xlabel("Longitude [degrees]")
ax.set_ylabel("Latitude [degrees]")
ax.set_zlabel("Depth [km]")
ax.invert_zaxis()
jet()
grid()
show()
And I get the following figure:
What I want to do is to be able to interpolate those points to create a "continuous" surface grid and plot it in both 2-D and 3-D plots. Therefore, somehow I've to consider all (lon,lat,depth,slip) in the interpolation. I'd appreciate your suggestions. Thanks in advance!
I'm a bit late, but if your data grid is properly ordered, you could resolve your iusse using plot_surface reshaping your 1D data to 2D.
An example supposing you're using a 10x10 grid:
# Main imports:
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
# Set the fourth dimension`
color_dimension = slip.reshape(10,10)
# normalize the colours
minn, maxx = color_dimension.min(), color_dimension.max()
norm = matplotlib.colors.Normalize(minn, maxx)
# color map
m = plt.cm.ScalarMappable(norm=norm, cmap='hot')
m.set_array([])
fcolors = m.to_rgba(color_dimension)
# plot
fig = plt.figure()
ax = fig.gca(projection='3d')
#reshape 1D data to 2D
g=ax.plot_surface(lat.reshape(10, 10), lon.reshape(10, 10), depth.reshape(10, 10), cmap='hot',rstride=1, cstride=1, facecolors=fcolors, vmin=minn, vmax=maxx, shade=False)
cbar=fig.colorbar(g,aspect=50)
cbar.set_label('slip', rotation=270, fontsize=14)
title("Published finite fault in 3-D")
ax.set_xlabel("Longitude [degrees]")
ax.set_ylabel("Latitude [degrees]")
ax.set_zlabel("Depth [km]")
ax.invert_zaxis()
plt.show()
I plotted a contourf plot with 9x11 points. When I plot the contourf plot then I expect to see lines between data points (since there is no other data in between the data points). But for example in the 0.9 level there are some parts (especially between x=2 and x=4) which are not linear. What can be the reason for that?
plt.figure()
x=np.linspace(0,10,11)
y=np.linspace(0,10,11)
X,Y = np.meshgrid(x,y)
levels = np.arange(0,1.01,0.1)
norm = cm.colors.Normalize(vmax=1, vmin=0)
cmap = cm.PRGn
CS1 = plt.contourf(X, Y, data,levels=levels,cmap=cm.get_cmap(cmap,
len(levels) - 1),norm=norm)
plt.xticks(np.arange(11),np.arange(11))
plt.yticks(np.arange(11),np.arange(250,855,55))
plt.xlim([0,8])
plt.colorbar(CS1)
plt.grid()
plt.show()
It's supposed to be that way: contourf colours in the area between the lines and contour draws the lines. See the examples.
Maybe the following plot helps to understand a contour plot better.
Here we plot a contour of an array with 3x3 points. The value of the middle point (6) is much larger than the other values. We chose levels of 3 and 5 where to plot the contour lines. Those lines are calculated by the contour as to interpolate the data.
Using more points will then allow to use more lines and make them look more smooth.
import matplotlib.pyplot as plt
import numpy as np
X,Y = np.meshgrid(np.arange(3), np.arange(3))
Z = np.array([[1,1,1],[2,6,2],[1,1,1]])
fig, ax=plt.subplots()
cs = ax.contour(X,Y,Z, levels=[3,5])
cs2 = ax.contourf(X,Y,Z, levels=[1,3,5,6], alpha=0.3)
plt.clabel(cs, cs.levels, inline=False)
plt.colorbar(cs2)
ax.scatter(X,Y)
for x,y,z in zip(X.flatten(), Y.flatten(), Z.flatten()):
ax.text(x,y,z)
plt.show()
In the example below I want to add contour labels to a filled contour. I do the same for regular contours, and the result seems to be correct. For the filled contours, however, the labels are off. Is this a bug or did I misunderstand something?
import matplotlib.pyplot as plt
import numpy
X,Z = numpy.meshgrid(range(5),range(5))
V = numpy.zeros([len(X),len(X[0])])
for kx in range(len(X[0])):
for kz in range(len(X)):
V[kz][kx] = X[kx][kz]
fig = plt.figure(figsize=(12,8))
ax1 = fig.add_subplot(121)
CS1 = ax1.contour(X,Z,V,range(5))
ax1.clabel(CS1,fontsize=16,colors='k')
cb1 = fig.colorbar(CS1)
ax2 = fig.add_subplot(122)
CS2 = ax2.contourf(X,Z,V,range(5))
ax2.clabel(CS2,fontsize=16,colors='k')
cb2 = fig.colorbar(CS2)
fig.savefig('contour')
The recent versions of Matplotlib have improved in this aspect. I ran your code on matplotlib 2.0.2, and got the following plots:
import matplotlib.pyplot as plt
import numpy
X,Z = numpy.meshgrid(range(5),range(5))
V = numpy.zeros([len(X),len(X[0])])
for kx in range(len(X[0])):
for kz in range(len(X)):
V[kz][kx] = X[kx][kz]
fig = plt.figure(figsize=(12,8))
ax1 = fig.add_subplot(121)
CS1 = ax1.contour(X,Z,V,range(5))
ax1.clabel(CS1,fontsize=16,colors='k')
cb1 = fig.colorbar(CS1)
ax2 = fig.add_subplot(122)
CS2 = ax2.contourf(X,Z,V,range(5))
ax2.clabel(CS2,fontsize=16,colors='k')
cb2 = fig.colorbar(CS2)
fig.savefig('contour')
This certainly looks better but it doesn't solve the problem completely. We want the labels on the filled contour plot to look like the labels in the contour line plot. Now as tom pointed out, we can't do that easily since clabel is designed to work with contour and not contourf. There is a not-so-neat workaround for this. What we can do is to first create the contour plot, whose labels can be easily manipulated with clabel function and then we fill this plot using contourf.
import matplotlib.pyplot as plt
import numpy
X,Z = numpy.meshgrid(range(5),range(5))
V = numpy.zeros([len(X),len(X[0])])
for kx in range(len(X[0])):
for kz in range(len(X)):
V[kz][kx] = X[kx][kz]
fig = plt.figure(figsize=(12,8))
ax1 = fig.add_subplot(121)
CS1 = ax1.contour(X,Z,V,range(5))
ax1.clabel(CS1,fontsize=16,colors='k')
cb1 = fig.colorbar(CS1)
ax2 = fig.add_subplot(122)
CS2 = ax2.contour(X,Z,V,range(5)) # Creating the contour plot
ax2.clabel(CS2,fontsize=16,colors='k')
CS3 = ax2.contourf(X,Z,V,range(5)) # Creating another filled contour plot on top
cb2 = fig.colorbar(CS3) # Display colorbar for filled contour plot
fig.savefig('contour')
I would still like these labels to be centred in the different regions of the plot, but I couldn't find a way to do that.
x,y are positions of the circles and r is the radius - all vectors.I want to plot them all at once. Something like:
import matplotlib.pyplot as plt
from matplotlib.patches Circle
#define x,y,r vectors
fig = plt.figure()
ax1 = fig.add_subplot(1,1,1)
plt.Circle((x,y),r,color='r')
plt.show()
Thanks.
plt.scatter allows you to define a radius of the points plotted.
From the doc
matplotlib.pyplot.scatter(x, y, s=20, c='b', marker='o')
[...]
s:
size in points^2. It is a scalar or an array of the same length as x and y.
Playing with facecolor and edgecolor you should be able to get what you want
You can find an example in How to set_gid() for each bubble in matplot scatter chart?
I am not informed about the Circles patch, but here is how you can do it with the standard plot command:
import numpy as np
import matplotlib.pyplot as plt
x = np.array([0.2,0.4])
y = np.array([0.2,1.2])
r = np.array([0.5,0.3])
phi = np.linspace(0.0,2*np.pi,100)
na=np.newaxis
# the first axis of these arrays varies the angle,
# the second varies the circles
x_line = x[na,:]+r[na,:]*np.sin(phi[:,na])
y_line = y[na,:]+r[na,:]*np.cos(phi[:,na])
plt.plot(x_line,y_line,'-')
plt.show()
The basic idea is to give the plt.plot(...) command two 2D arrays. In that case they are interpreted as a list of plots. Espacially for many plots (=many circles) this is much faster, than plotting circle by circle.