I am trying to create an errorbar plot with different x- and y-errors. Let's say i have the following data:
x = [[item%20 for item in reversed(range(50,55))] for _ in range(13)]
y = [[item%20 for item in reversed(range(20,25))] for _ in range(13)]
fig, ax = plt.subplots()
ax.set_xscale('log')
for i in range(len(x)):
plt.errorbar(x=[x[0][i]], y=[y[0][i]], xerr=x[i][1:3], yerr=y[i][1:3], ls='None', label='B{}D{}'.format(x[i][3],y[i][4]))
plt.legend(prop={'size': 6})
Now this will create an error:
ValueError: err must be [ scalar | N, Nx1 or 2xN array-like ]
However, I do not understand this error, as my error has the shape (2, N=1), just like ma data is N=1.
When I transpose my data and plot it, it works just fine, but I want to plot every datapoint with a different labelm marker and color.
For me it would also be okay to plot all errorbars at once and change the colors, markers and assign a label afterwards, however I do not know how to do so. However, I believe that I am doing a simple mistake which would make that approach unnecessary.
Any help is highly appreciated :)
if you are plotting one point at a time, your errors should be shaped (2,1), not (2,) as they are in your code.
Furthermore, I think you had an error in the way you were getting your x,y values.
x = [[item for item in reversed(range(50,55))] for _ in range(13)]
y = [[item for item in reversed(range(20,25))] for _ in range(13)]
fig, ax = plt.subplots()
ax.set_xscale('log')
for i in range(len(x)):
X = x[i][0]
Y = y[i][0]
dx = np.array(x[i][1:3]).reshape((2,1))
dy = np.array(y[i][1:3]).reshape((2,1))
print(X,Y,dx,dy)
plt.errorbar(x=X, y=Y, xerr=dx, yerr=dy, ls='None', label='B{}D{}'.format(x[i][3],y[i][4]))
plt.legend(prop={'size': 6})
Related
I am trying to plot 5 lines on a plot in a for-loop. In every iteration, the values of x and y appended to an np.array and then plotted on a figure.
The problem that I have is that I want all the lines on one plot as their x values are always the same but the values of y will change.
Here is how I do it:
for i in range (0,5):
for epoch in range(0, num_epochs):
x = np.append(x,epoch)
y = np.append(y,accuracy)
z = np.append(z, running_loss/j)
fig, axs = plt.subplots(2)
fig.suptitle('Model Evlauation')
axs[0].plot(x, y)
axs[1].plot(x, z)
axs[0].set_xlabel('Number of epochs')
axs[1].set_xlabel('Number of epochs')
axs[0].set_ylabel('Accuracy')
axs[1].set_ylabel('Loss')
fig.tight_layout(pad=2)
plt.show()
in this way, I get 5 different figures and each one includes only one line:
while I want something like the following figure:
When you put the subplots in the for loop, it is set again every time. So instead you want:
fig, axs = plt.subplots(2)
for i in range (0,5):
for epoch in range(0, num_epochs):
x = np.append(x,epoch)
y = np.append(y,accuracy)
z = np.append(z, running_loss/j)
axs[0].plot(x, y)
axs[1].plot(x, z)
fig.suptitle('Model Evlauation')
axs[0].set_xlabel('Number of epochs')
axs[1].set_xlabel('Number of epochs')
axs[0].set_ylabel('Accuracy')
axs[1].set_ylabel('Loss')
fig.tight_layout(pad=2)
plt.show()
I have some z=f(x,y) data which i would like to plot. The issue is that (x,y) are not part of a "nice" rectangle, but rather arbitrary parallelograms, as shown in the attached image (this particular one is also a rectangle, but you could think of more general cases). So I am having a hard time figuring out how I can use plot_surface in this case, as this usually will take x and y as 2d arrays, and here my x-and y-values are 1d. Thanks.
Abritrary points can be supplied as 1D arrays to matplotlib.Axes3D.plot_trisurf. It doesn't matter whether they follow a specific structure.
Other methods which would depend on the structure of the data would be
Interpolate the points on a regular rectangular grid. This can be accomplished using scipy.interpolate.griddata. See example here
Reshape the input arrays such that they live on a regular and then use plot_surface(). Depending on the order by which the points are supplied, this could be a very easy solution for a grid with "parallelogramic" shape.
As can be seen from the sphere example, plot_surface() also works in cases of very unequal grid shapes, as long as it's structured in a regular way.
Here are some examples:
For completeness, find here the code that produces the above image:
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
f = lambda x,y: np.sin(x+0.4*y)*0.23+1
fig = plt.figure(figsize=(5,6))
plt.subplots_adjust(left=0.1, top=0.95,wspace=0.01)
ax0 = fig.add_subplot(322, projection="3d")
ma = 6*(np.random.rand(100)-0.5)
mb = 6*(np.random.rand(100)-0.5)
phi = np.pi/4
x = 1.7*ma*np.cos(phi) + 1.7*mb*np.sin(phi)
y = -1.2*ma*np.sin(phi) +1.2* mb*np.cos(phi)
z = f(x,y)
ax0.plot_trisurf(x,y,z)
ax1 = fig.add_subplot(321)
ax0.set_title("random plot_trisurf()")
ax1.set_aspect("equal")
ax1.scatter(x,y, marker="+", alpha=0.4)
for i in range(len(x)):
ax1.text(x[i],y[i], i , ha="center", va="center", fontsize=6)
n = 10
a = np.linspace(-3, 3, n)
ma, mb = np.meshgrid(a,a)
phi = np.pi/4
xm = 1.7*ma*np.cos(phi) + 1.7*mb*np.sin(phi)
ym = -1.2*ma*np.sin(phi) +1.2* mb*np.cos(phi)
shuf = np.c_[xm.flatten(), ym.flatten()]
np.random.shuffle(shuf)
x = shuf[:,0]
y = shuf[:,1]
z = f(x,y)
ax2 = fig.add_subplot(324, projection="3d")
ax2.plot_trisurf(x,y,z)
ax3 = fig.add_subplot(323)
ax2.set_title("unstructured plot_trisurf()")
ax3.set_aspect("equal")
ax3.scatter(x,y, marker="+", alpha=0.4)
for i in range(len(x)):
ax3.text(x[i],y[i], i , ha="center", va="center", fontsize=6)
x = xm.flatten()
y = ym.flatten()
z = f(x,y)
X = x.reshape(10,10)
Y = y.reshape(10,10)
Z = z.reshape(10,10)
ax4 = fig.add_subplot(326, projection="3d")
ax4.plot_surface(X,Y,Z)
ax5 = fig.add_subplot(325)
ax4.set_title("regular plot_surf()")
ax5.set_aspect("equal")
ax5.scatter(x,y, marker="+", alpha=0.4)
for i in range(len(x)):
ax5.text(x[i],y[i], i , ha="center", va="center", fontsize=6)
for axes in [ax0, ax2,ax4]:
axes.set_xlim([-3.5,3.5])
axes.set_ylim([-3.5,3.5])
axes.set_zlim([0.9,2.0])
axes.axis("off")
plt.savefig(__file__+".png")
plt.show()
If your data is in order, and you know the size of the parallgram, a reshape will probably suffice:
ax.surface(x.reshape(10, 10), y.reshape(10, 10), z.reshape(10, 10))
Will work if the parallelogram has 10 points on each side, and the points are ordered in a zigzag pattern
I have a bunch of data that I need to see in some understandable manner. here what I've done so far:
..................................
features = []
for i in range(len(variance_list[0][:])):
for j in range(len(variance_list)):
features.append(variance_list[j][i])
plt.plot(features)
features.clear()
plt.xlabel('classes ')
plt.ylabel('features')
plt.show()
The result looks as followed:
So I've tried to plot this in 3D as followed :
for i in range(len(variance_list[0][:])):
for j in range(len(variance_list)):
Axes3D.plot(i,j,variance_list[j][i],label='parametric curve')
plt.show()
I get the following error message:
1510 # many other traditional positional arguments occur
1511 # such as the color, linestyle and/or marker.
-> 1512 had_data = self.has_data()
1513 zs = kwargs.pop('zs', 0)
1514 zdir = kwargs.pop('zdir', 'z')
AttributeError: 'int' object has no attribute 'has_data'
Any idea what I'm missing, or how may I solve this
in addition to cosmos' suggestion, there is a difference in x,y lines and the z var
variance_list=[[np.random.rand()**2*(j+1) for _ in range(10)] for j in range(4)]
fig = plt.figure()
ax = fig.gca(projection='3d')
for j in range(len(variance_list)):
ax.plot(range(len(variance_list[0])),variance_list[j],j,label='parametric curve')
plt.show()
instead of Axes3D.plot it should be:
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.plot(...)
according to mplot3d docs
I have file in.txt, which have many rows. and 1-20 columns (it's undefined). and contains numbers.
I draw a graphic with this code
y=np.loadtxt('in.txt')
t=np.arange(len(y))*1
plt.subplot(211)
plt.title(r'in')
plt.grid(1)
plt.plot(t,y, label = 'in')
plt.legend(borderpad = 0.1, labelspacing = 0.1)
plt.show()
It is what I have now (in this example I have 10 columns in file in.txt)
But, rather than all names in legend are "in", I want names like "1", "2", "3" etc. (from 1 to n, where n is a number of columns in my in.txt file)
One way you could do this is by plotting each line in an iteration of a for-loop. For example:
y = np.random.random((3,5)) # create fake data
t = np.arange(len(y))
plt.subplot(211)
plt.title(r'in')
plt.grid(1)
for col_indx in range(y.shape[1]):
plt.plot(t, y[:,col_indx], label = col_indx)
plt.legend(borderpad = 0.1, labelspacing = 0.1)
plt.show()
Alternatively, and I'd recommend this solution in your case, is to use the optional arguments of the call to plt.legend. Like this:
plt.plot(t, y)
plt.legend(range((len(y)))
Check out the doc-string of plt.legend when you want to go a bit more advanced.
If you wanted to start labelling using a 1-based index, rather than zero-based, don't forget to add +1 in the label and the range ;-)
You are taking advantage of the broadcasting in plot for the x/y, but the kwargs do not also get broadcast. Either
x = np.arange(25)
y = np.random.rand(25, 6)
fig, ax = plt.subplots()
for j, _y in enumerate(y.T, start=1):
ax.plot(x, _y, label=str(j))
ax.legend(borderpad=0.1, labelspacing=0.1)
or
fig, ax = plt.subplots()
lns = ax.plot(x, y)
labels = [str(j) for j in range(1, y.shape[1] + 1)]
ax.legend(handles=lns, labels=labels, borderpad=0.1, labelspacing=0.1)
I'm trying to plot some data using pyplot, and then 'zoom in' by using xlim() the x axis. However, the new plot doesn't rescale the y axis when I do this - am I doing something wrong?
Example - in this code, the plot y-axis range still takes a maximum of 20, rather than 10.:
from pylab import *
x = range(20)
y = range(20)
xlim(0,10)
autoscale(enable=True, axis='y', tight=None)
scatter(x,y)
show()
close()
Realize this is an ancient question, but this is how I've (messily) gotten around the issue:
use .plot() instead of .scatter()
access plot data later (even after a figure is returned somewhere) with ax.get_lines()[0].get_xydata()
use that data to rescale y axis to xlims
Snippet should work:
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
x = range(20)
y = range(20)
xlims = [0, 10]
ax.set_xlim(xlims)
ax.plot(x, y, marker='.', ls='')
# pull plot data
data = ax.get_lines()[0].get_xydata()
# cut out data in xlims window
data = data[np.logical_and(data[:, 0] >= xlims[0], data[:, 0] <= xlims[1])]
# rescale y
ax.set_ylim(np.min(data[:, 1]), np.max(data[:, 1]))
plt.show()
I don't know, though you could try manually filtering the points with
scatter([(a,b) for a,b in zip(x,y) if a>0 and a<10])