How to change the names in matplotlib legend box? - python

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)

Related

Subplots within a for-loop

I want to create subplots within a loop, but the outcome is not excactly what I imagined. I want scatter plots in one big plot. The data originates from the matching columns of two dataframes DF and dfr. DFand dfr have the same amount of rows columns and indexes. The first two columns of both dataframes should be excluded.
This is my approach, but I get i plots with one subplot each. What am I missing?
measurements = 9
for i in range(2,measurements+1):
try:
x = DF.iloc[1:,i]
y = dfr.iloc[1:,i]
inds = ~np.logical_or(np.isnan(x), np.isnan(y))
x = x[inds]
y = y[inds]
xy = np.vstack([x,y])
z = gaussian_kde(xy)(xy)
b, m = polyfit(x, y, 1)
fig, ax = plt.subplots(measurements+1,facecolor='w', edgecolor='k')
ax[i].scatter(x, y, c=z, s=50, cmap='jet', edgecolor='', label=None, picker=True, zorder= 2)
ax[i].plot(x, b + m * x, '-')
except KeyError:
continue
plt.show()
Currently I get several plots, but i would like to have one with multipile subplots.
Indeed, you have to put fig, ax = plt.subplots() out of the loop.
A few other things :
Setting edgecolor='' that way might raise an error. Remove it, or add a specific color.
I am sure if using try and except KeyError is relevant in your code. Python raises a KeyError whenever a dict() object is requested (using the format a = adict[key]) and the key is not in the dictionary. Maybe for: x = x[inds] ? if so, I would suggest do this check earlier in your process.
Try this :
measurements = 9
fig, ax = plt.subplots(measurements+1, facecolor='w', edgecolor='k')
for i in range(2, measurements+1):
try:
x = DF.iloc[1:,i]
y = dfr.iloc[1:,i]
inds = ~np.logical_or(np.isnan(x), np.isnan(y))
x = x[inds]
y = y[inds]
xy = np.vstack([x,y])
z = stats.gaussian_kde(xy)(xy)
b, m = np.polyfit(x, y, 1)
ax[i].scatter(x, y, c=z, s=50, cmap='jet', label=None, picker=True, zorder= 2)
ax[i].plot(x, b + m * x, '-')
except KeyError:
# Temporarily pass but ideally, do something
pass
plt.show()

Matplotlib Draw a Constant y Axis

I want to use matpoltlib to make a plot that with a constant y axis(always from 0 to 14 and the gap is 1), since I want to make labels for them and my dot values will be(x, y) where y is from 0 to 14 gap 1, and a changing x axis. I already tried to play with y ticks. And here is my code for that:
fig, ax = plt.subplots()
fig.canvas.draw()
plt.yticks(np.arange(0, 14, 1))
labels = [item.get_text() for item in ax.get_yticklabels()]
labels[1] = 'Not Detected'
labels[2] = 'A/G'
labels[3] = 'G/G'
labels[4] = 'C/T'
labels[5] = 'C/C'
labels[6] = 'A/A'
labels[7] = '-1'
labels[8] = 'ε3/ε3'
labels[9] = 'A/C'
labels[10] = 'T/T'
labels[11] = 'C/G'
labels[12] = 'ε2/ε3'
labels[13] = 'G/T'
ax.set_yticklabels(labels)
what I'm thinking about is to use some values or lines with white color so those y axis will appear. But I'm looking for a more efficient way of doing it. And here is the diagram I generated with the current code. It only shows C/C right now and I want all labels to appear in the diagram.
I tried draw white points with:
x1 = np.arange(n)
y1 = np.arange(1,15,1)
plt.scatter(x1,y1,color = 'white')
Which did give me what I want: But I was wondering whether there is a lib setting that can do this.
I would recommend just using a fixed locator and fixed formatter for your y axis. The function, ax.set_yticklabels() is simply a convenience wrapper for these tick methods.
I would also recommend having your y_labels in a list or using a loop structure as this is a more generalizable and modifiable implementation.
If I'm understanding the goals of your plot correctly, something like this may work well for you.
import matplotlib.pyplot as plt
import numpy as np
import matplotlib as mpl
#make some data
x = np.arange(25)
y = np.random.randint(1, 14, size=25)
#convert y labels to a list
y_labels = [
'Not Detected','A/G','G/G','C/T','C/C','A/A',
'-1','ε3/ε3', 'A/C','T/T','C/G','ε2/ε3','G/T'
]
#define figure/ax and set figsize
fig, ax = plt.subplots(figsize=(12,8))
#plot data, s is marker size, it's points squared
ax.scatter(x, y, marker='x', s=10**2, color='#5d2287', linewidth=2)
#set major locator and formatter to fixed, add grid, hide top/right spines
locator = ax.yaxis.set_major_locator(mpl.ticker.FixedLocator(np.arange(1, 14)))
formatter = ax.yaxis.set_major_formatter(mpl.ticker.FixedFormatter(y_labels))
grid = ax.grid(axis='y', dashes=(8,3), alpha=0.3, color='gray')
spines = [ax.spines[x].set_visible(False) for x in ['top','right']]
params = ax.tick_params(labelsize=12) #increase label font size

Problem with drawing multiple lines using matplotlib with Python

I am new to python and trying to create a plot with one y variable and two x variables. I want the two lines to show up in the same plot with different labels and colors/makrers. Here is my code to attempt:
y = lambda x: x**(-3)
z = lambda x: x**(-10)
x_grid = np.linspace(1,10, 10)
v_y = []
v_z = []
for i in x_grid:
vy=y(i)
v_y.append(vy)
v_y_array = np.array(v_y)
for j in x_grid:
vz=y(j)
v_z.append(vz)
v_z_array = np.array(v_z)
fig, ax = plt.subplots()
line1, = ax.plot(x_grid, v_y_array, 'b--', label='function 1')
line2, = ax.plot(x_grid, v_z_array, 'r--', label='function 1')
ax.legend()
plt.show()
However, the figure only shows the second line and ignores the first.
But if I try to do the following, it works out fine.
y = lambda x: x**(-3)
z = lambda x: x**(-10)
x_grid = np.linspace(1,10, 10)
v_y = []
v_z = []
for i in x_grid:
vy=y(i)
v_y.append(vy)
v_y_array = np.array(v_y)
for j in x_grid:
vz=y(j)
v_z.append(vz)
v_z_array = np.array(v_z)
fig,ax=plt.subplots()
ax.plot(x_grid,v_y_array,'r--', v_z_array, 'b--', label='x**(-3) function')
ax.set_title('Two Functions')
ax.legend(['x**(-3) function','x**(-10) function'])
plt.show()
I wonder what was the problem with my first set of codes that won't produce the figure that I want?
The reason why the red and blue lines don't overlap in the second plot lies in the official documentation.
ax.plot(x_grid, v_y_array,'r--', v_z_array, 'b--', label='x**(-3) function')
The first set of three arguments x_grid, v_y_array,'r--', v_z_array, follows this pattern:
plot(x, y, 'bo') # plot x and y using blue circle markers
The second set has only two arguments: v_z_array, 'b--', and follow this pattern:
plot(y) # plot y using x as index array 0..N-1
plot(y, 'r+') # ditto, but with red plusses
Thus, the second set is infering a sequence of x values that equals range(0, 10)(values from 0 to 9 inclusive), while the first set of arguments uses x_gridwhich equals range(1, 11) (values from 1 to 10 inclusive).

Jupyter | How to use matplotlib to plot multiple lines on only one plot in a for loop and keeping the previous lines?

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()

Pyplot Errorbars with different x- and y-error

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})

Categories

Resources