I'm trying to make a 2d plot using pyplot. I'm reading in a file with several columns, each of which contains around 100 values between 1 and 10. I'm plotting column 5 against column 6, which is fine.
What I also want to do is label the resulting line with integer values from column 0. So the line will have 11 points on, at the positions (x,y) where column 0 is an integer. I'd also like those points to be labelled with that integer.
I'd really appreciate any help with this, its driving me crazy!
From your question, I'm not 100% clear exactly what you're wanting to do.
Do you just want to label every vertex in a line? Or do you only want to label vertices that are integers? Or do you want to interpolate where integer "crossings" would line along the line and label those?
First off, for loading your text file, look into numpy.loadtxt, if you aren't already. In your particular case, you could do something like:
z, x, y = np.loadtxt('data.txt', usecols=[0, 5, 6]).T
At any rate, as a quick example of the simplest option (labeling every vertex):
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(10)
y = 2 * x
z = x ** 2
fig, ax = plt.subplots()
ax.plot(x, y, 'bo-')
for X, Y, Z in zip(x, y, z):
# Annotate the points 5 _points_ above and to the left of the vertex
ax.annotate('{}'.format(Z), xy=(X,Y), xytext=(-5, 5), ha='right',
textcoords='offset points')
plt.show()
Now, for the second option, we might have something more like this (Similar to what #mathematical.coffee suggested):
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(-0.6, 5.6, 0.2)
y = 2 * x
z = x**2
fig, ax = plt.subplots()
ax.plot(x, y, 'bo-')
# Note the threshold... I'm assuming you want 1.000001 to be considered an int.
# Otherwise, you'd use "z % 1 == 0", but beware exact float comparisons!!
integers = z % 1 < 1e-6
for (X, Y, Z) in zip(x[integers], y[integers], z[integers]):
ax.annotate('{:.0f}'.format(Z), xy=(X,Y), xytext=(-10, 10), ha='right',
textcoords='offset points',
arrowprops=dict(arrowstyle='->', shrinkA=0))
plt.show()
Related
I am not really sure if this is possible to do, but essentially I have a list of data corresponding to x, y and z coordinates.
Below image shows the result when I plot these points using a scatter graph (which I created using Python pyplot library).
My question is, is there any way of plotting the graph of a plane that passes through all of these points instead of plotting them as single points?
When I searched online all I found was resources telling me how to find equation of plane passing though 3 points but as you can see I have many points.
Any help will be appreciated.
Let's say that to have your plot you use this code
fig, ax = plt.subplots(subplot_kw=dict(projection='3d'))
ax.scatter(x, y, z)
plt.show()
and let's say that you know nrows, ncols, the number of rows (y) and columns (x) of your base grid.
If these assumptions are correct, then you can use this code to plot a surface connecting the points
fig, ax = plt.subplots(subplot_kw=dict(projection='3d'))
ax.plot_surface(*(v.reshape(nrows, ncols) for v in (x, y, z)))
plt.xlabel('x') ; plt.ylabel('y')
plt.show()
or, if you want something fancier,
fig, ax = plt.subplots(subplot_kw=dict(projection='3d'),
layout='constrained')
surf = ax.plot_surface(*(v.reshape(nrows, ncols) for v in(x, y, z)),
cmap='Blues_r', ec='gray', lw=0.2)
plt.xlabel('x') ; plt.ylabel('y')
plt.colorbar(surf)
plt.show()
The prelude to my code, if you want to check my results, is
import numpy as np
import matplotlib.pyplot as plt
nrows, ncols = 63, 126
x = np.linspace(0, 12.5, ncols)
y = np.linspace(-6.2, 6.2, nrows)
X, Y = np.meshgrid(x, y)
x, y = (V.flatten() for V in (X, Y))
z = np.sin(x)-np.cos(y)
fig, ax = ...
...
This question already has answers here:
How to plot a gradient color line in matplotlib?
(7 answers)
Closed 3 years ago.
So I have a normal scatter plot:
import numpy as np
import matplotlib.pyplot as plt
import random
x = np.random.random_sample((100,))
x = np.sort(x)
y = x + np.sin(np.pi * x)
z = 5 * x
fig = plt.figure()
plot = plt.scatter(x, y, s= 10, c = z, cmap='coolwarm')
fig.colorbar(plot)
plt.grid(True, 'both')
plt.show()
that produces a plot something like this
However, I would really like to add a line to scatter and connect these points. It may sound ridiculous since it is easy to follow the points in given case, but imagine if the data would be more scattered and possibly multiple datasets ...
So my goal is to add a line to the scatter above, but the color of the line should change according to value of 'z', the same way scatter plot does. Is that even possible?
EDIT:
The x, y, z provided above is just random data to explain the problem. In reality, you can imagine the points (x, y) coordinates are given from an experiment meaning in general there is no relation between x, y, z or even if it is, it is NOT known upfront.
You can add another scatterplot using np.linspace() function:
import numpy as np
import matplotlib.pyplot as plt
import random
x = np.random.random_sample((100,))
x = np.sort(x)
y = x + np.sin(np.pi * x)
z = 5 * x
fig = plt.figure()
plot = plt.scatter(x, y, s= 10, c = z, cmap='coolwarm')
fig.colorbar(plot)
plt.grid(True, 'both')
# add another scatterplot
x_line = np.linspace(np.min(x), np.max(x), num=1000)
y_line = x_line + np.sin(np.pi * x_line)
z_line = 5 * x_line
plt.scatter(x_line, y_line, c=z_line, s=0.1, cmap='coolwarm')
plt.show()
Okay, apologies for this question but I'm pulling my hair out here.
I have a data structure loaded in python in the form:
[(1,0,#),(1,1,#),(1,2,#),(1,3,#),(2,0,#),(2,1,#) ... (26,3,#)]
with # being a different number each time that I wish to represent on the z-axis. You can see that x and y are always integers.
Plotting a scatter graph is simple:
x,y,z = zip(*data)
fig = plt.figure()
ax = fig.gca(projection = '3d')
surface = ax.scatter(x, y, z)
plt.show()
But when it comes to surfaces, I can see two methods:
1) Call ax.plot_trisurf(), which should work with 1D arrays similar to ax.scatter() and apparently works here, but for me gives me an error:
"AttributeError: Axes3D subplot object has not attribute 'plot_trisurf'"
This error also appears if I use the example source code at:
http://matplotlib.org/mpl_toolkits/mplot3d/tutorial.html#tri-surface-plots, suggesting it's something wrong with my installation - my Matplotlib version is 1.1.1rc,. This error does not appear if, for example, ax.plot_surface() is called, nor ax.scatter().
2) Use meshgrid() or griddata() in combination with ax.plot_surface() - in either case, after two days' of pouring over the documentation and examples, I still don't understand how to correctly use these in my case, particularly when it comes to generating the values for Z.
Any help would be much appreciated.
To address your first question (1) I believe you need to import Axes3D from the mplot3d library, even if you're not directly calling it. Maybe try adding
from mpl_toolkits.mplot3d import Axes3D
before your main code (this line triggered a memory while reading the tutorial).
As for (2), X, Y and Z need to be matrix (2d array) type objects. This can get confusing, but you may consider an example:
# two arrays - one for each axis
x = np.arange(-5, 5, 0.25)
y = np.arange(-5, 5, 0.25)
# create a mesh / matrix like object from the arrays
X, Y = np.meshgrid(x, y)
# create Z values - also in a mesh like shape
Z = np.sin(np.sqrt(X**2 + Y**2))
# plot!
surface = ax.plot_surface(X, Y, Z)
Here is an example of how could you extract your z-values from data
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
import matplotlib.pyplot as plt
import numpy as np
data = [(j,i,i**2 + j) for j in range(1,27) for i in range(4)]
print data
fig = plt.figure()
ax = fig.gca(projection='3d')
X = np.arange(0, 4, 1)
Y = np.arange(1, 27, 1)
X, Y = np.meshgrid(X, Y)
print X.shape
print Y.shape
Z = np.array([z for _,_,z in data]).reshape(26,4)
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.coolwarm,
linewidth=0, antialiased=True)
fig.colorbar(surf, shrink=0.5, aspect=5)
plt.xlabel('X')
plt.ylabel('Y')
plt.show()
I want to plot red, blue and green colors on the three axis and an array which stores the value corresoding to each combination of color in python2.7....when i run my program either becomes unresponsive for 24 hours or it gives me memory error. Here is my code:
import pylab
import math
from itertools import product
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
import matplotlib.pyplot as plt
import numpy as np
N=[]
p=np.zeros((256,256,256))
S=[]
fig=plt.figure()
ax=fig.gca(projection='3d')
X=np.arange(0,256,1) #for one of the features either red, blue or green
Y=np.arange(0,256,1)
X,Y = np.meshgrid(X,Y)
R=np.sqrt(X**2 + Y**2)
Z=R/np.sqrt(2)
N=p.flatten();
N=(p[i,j,k] for k in Z)
surf=ax.plot_surface(X,Y,Z, rstride=1, cstride=1,
facecolors=cm.jet(N),
linewidth=0, antialiased=False, shade=False)
plt.show()
Please help. I have read the previous posts, and have used them, still I am getting memory error. Here p is a containing values of combinations of red, green and blue. For simplicity I have initialized it to zero...it is giving the following error..colset.append(fcolors[rs][cs])
IndexError: index out of bounds
First, your program is slow because you're doing a lot of unnecessary work building N. You're building a 70 MB list a few bytes at a time (256*256*256=16,777,216 appends!). A better (faster, memory efficient) way to build p is to use numpy's array broadcasting, and then reuse p to make N:
import numpy as np
a = np.arange(256)
p = a[:,np.newaxis,np.newaxis] * a[np.newaxis,:,np.newaxis] * a[np.newaxis,np.newaxis,:]
N = p.flatten()
Second and more importantly, you're not using plot_surface() correctly. According to the docs, X, Y and Z should be 2D arrays. X and Y lay down a 2D grid and Z provides the "height" for each point on that 2D grid. If you want to manually set the facecolor, it should also be a 2D array. You should look at the example in the docs for a working example.
EDIT:
I'm not sure what your plot is intended to look like, so lets walk through the MPL demo.
Make the necessary imports and create an axis object (yours does this correctly):
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.gca(projection='3d')
Next, make an X/Y grid and corresponding Z. In your program, X, Y and Z are 1D. They describe a line in 3D space, not a surface.
X = np.arange(-5, 5, 0.25)
Y = np.arange(-5, 5, 0.25)
X, Y = np.meshgrid(X, Y) # <-- returns a 2D grid from initial 1D arrays
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R)
Lets first plot the simplest thing possible. No colors, default anti-aliasing, lines, etc.
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1)
plt.show()
Now add a colors. Note that the color comes from the Z component.
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.jet)
plt.show()
Now manually control the colors (MPL inspiration).
colortuple = ('y', 'k') # only use two colors: yellow and black
xlen, ylen = X.shape # get length of
colors = np.empty(X.shape, dtype=str) # make a 2D array of strings
for i in range(xlen):
for j in range(ylen):
index = (i + j) % 2 # alternating 0's and 1's
colors[i,j] = colortuple[index]
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1,
facecolors=colors)
If you want to color based on some other metric, you can create your own colormap. There are many answered questions on how to do that.
Edit 2:
Colors can also be specified as RGB sequences. For something like your red on X, green on Y description you could do this:
xlen, ylen = X.shape
colors = np.zeros((xlen,ylen,3))
jspan = np.linspace(0., 1., ylen)
ispan = np.linspace(0., 1., xlen)
for i in range(xlen):
colors[i,:,0] = jspan
for j in range(ylen):
colors[:,j,1] = ispan
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, facecolors=colors,)
I'm trying to make a 2d plot using pyplot. I'm reading in a file with several columns, each of which contains around 100 values between 1 and 10. I'm plotting column 5 against column 6, which is fine.
What I also want to do is label the resulting line with integer values from column 0. So the line will have 11 points on, at the positions (x,y) where column 0 is an integer. I'd also like those points to be labelled with that integer.
I'd really appreciate any help with this, its driving me crazy!
From your question, I'm not 100% clear exactly what you're wanting to do.
Do you just want to label every vertex in a line? Or do you only want to label vertices that are integers? Or do you want to interpolate where integer "crossings" would line along the line and label those?
First off, for loading your text file, look into numpy.loadtxt, if you aren't already. In your particular case, you could do something like:
z, x, y = np.loadtxt('data.txt', usecols=[0, 5, 6]).T
At any rate, as a quick example of the simplest option (labeling every vertex):
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(10)
y = 2 * x
z = x ** 2
fig, ax = plt.subplots()
ax.plot(x, y, 'bo-')
for X, Y, Z in zip(x, y, z):
# Annotate the points 5 _points_ above and to the left of the vertex
ax.annotate('{}'.format(Z), xy=(X,Y), xytext=(-5, 5), ha='right',
textcoords='offset points')
plt.show()
Now, for the second option, we might have something more like this (Similar to what #mathematical.coffee suggested):
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(-0.6, 5.6, 0.2)
y = 2 * x
z = x**2
fig, ax = plt.subplots()
ax.plot(x, y, 'bo-')
# Note the threshold... I'm assuming you want 1.000001 to be considered an int.
# Otherwise, you'd use "z % 1 == 0", but beware exact float comparisons!!
integers = z % 1 < 1e-6
for (X, Y, Z) in zip(x[integers], y[integers], z[integers]):
ax.annotate('{:.0f}'.format(Z), xy=(X,Y), xytext=(-10, 10), ha='right',
textcoords='offset points',
arrowprops=dict(arrowstyle='->', shrinkA=0))
plt.show()