I'm using matplotlib. Code:
for new_counter in range(counter+1):
print new_counter
Qbers = final_data[(final_data["Dataset"]==counter) & (final_data["Qber"] > 0) ]
x1 = Qbers.index.tolist()
y1 = Qbers["Qber"].tolist()
Raws = final_data[(final_data["Dataset"]==counter) & (final_data["Raw key"] > 0) ]
x2 = Raws.index.tolist()
y2 = Raws["Raw key"].tolist()
# Two subplots, the axes array is 1-d http://matplotlib.org/examples/pylab_examples/subplots_demo.html
f, axarr = plt.subplots(2, sharex=True)
axarr[0].grid()
axarr[0].plot(x1, y1)
axarr[0].set_title('Sharing X axis')
axarr[1].grid()
axarr[1].plot(x2, y2)
plt.savefig(str(counter)+'foo.eps')
plt.clf()
I'm receiving only file with last plot, and with my data I should receive 6 of them. How to fix that? Additional question: How to prevent creation of interactive window with plot?
It looks like you are not generating unique file names. You probably want:
plt.savefig(str(new_counter)+'foo.eps')
Related
I am facing a simple problem I can't figure out: I am trying to plot multiple graphs with Matplotlib, but in separated graphs. This is an example code with random numbers:
import numpy as np
import matplotlib.pyplot as plt
x1 = np.random.normal(10, 1, 100)
x2 = np.random.uniform(8, 12, 100)
fig, ax = plt.subplots()
ax.plot(np.sort(x1), label = 'Normal')
ax.plot(np.sort(x2), label = 'Uniform')
plt.legend()
plt.show()
In this way I get 1 graph with 2 lines (the ax objects). I know that I can use Subplot to get 2 graphs next to each other, but what I want is to plot two different graphs, 1 for each variable, with 1 line each, all at once without starting a new code a initializing a new graph from the beginning.
Without using subplots, I think one (quite ugly) way to do this is
x1 = np.random.normal(10, 1, 100)
x2 = np.random.uniform(8, 12, 100)
data = [x1, x2]
label_list = ['Normal', 'Uniform']
for i, x in enumerate(data):
fig = plt.figure()
plt.plot(np.sort(x), label = label_list[i])
plt.legend()
plt.show()
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
If I have the following plotting routine that plots a scatter plot and corresponding linear regression and combines the legend handles:
import pandas as pd
from scipy.stats import linregress
import numpy as np
import matplotlib.pyplot as plt
#data and Regression
x = np.arange(0,5,1)
y = np.arange(0,10,2)
df = pd.DataFrame(data = {'x':x,'y':y})
s, intcpt, r, p, serr = linregress(df.x, df.y)
xHat = np.linspace(0,5,100)
# do the plotting
fig,ax = plt.subplots()
df.plot(x='x',y='y',ax=ax,label='series1',ls=' ',marker='x',c='blue')
ls_handle, = ax.plot(xHat, s*xHat + intcpt, linestyle='-', marker=None, c='blue')
handle2merge = [ls_handle]
handles, labels = ax.get_legend_handles_labels()
handle_combined = zip(handles, handle2merge)
ax.legend(handle_combined, labels)
Which returns the where the marker and line handles are merged looking like:
Now I want to plot another dataset in a similar fashion:
#get current axis handles and labels
handle_start, label_start = ax.get_legend_handles_labels()
#second dataset and regression
x1 = np.arange(0,5,1)
y1 = np.arange(0,2.5,0.5)
df1 = pd.DataFrame(data = {'x':x1,'y':y1})
s1, intcpt1, r1, p1, serr1 = linregress(df1.x, df1.y)
xHat1 = np.linspace(0,5,100)
#plot second data set on same figure
marker_handle2, = ax.plot(df1.x, df1.y, marker = 'x', zorder=10,c='k', linestyle=' ')
line_handle2, = ax.plot(xHat, s1*xHat1 + intcpt1, linestyle='--', marker=None, c='k')
new_line_handles = [line_handle2]
new_marker_handles= [marker_handle2]
ax.legend(handle_start + zip(new_marker_handles,new_line_handles), label_start + ['series2'])
This returns a plot where the handles for series1 legend handle only contains the marker.
Why is len(handle_start)=1 when I constructed the handle with handle_combined = zip(handles, handle2merge)?
I have poked around the code a little. What you are doing is passing a list of tuples to ax.legend, which apparently draws each Artist in each tuple as one entry in the legend. I have actually not come across this behaviour before; it could be a bug, or unintended use of ax.legend.
Nevertheless, I think that in this case, since you know what your lines should look like beforehand, instead of going the roundabout way with zip and stuff, you could just pass a custom Line2D to legend directly:
import numpy as np
from scipy.stats import linregress
from matplotlib import pyplot as plt
from matplotlib import lines
x1 = np.arange(0, 5, 1)
y1 = np.arange(0, 10, 2)
x2 = np.arange(0, 5, 1)
y2 = np.arange(0, 2.5, 0.5)
m1, c1, r1, p1, serr1 = linregress(x1, y1)
m2, c2, r2, p2, serr2 = linregress(x2, y2)
x_pred = np.linspace(0,5,100)
fig, ax = plt.subplots()
first_line, = ax.plot(x_pred, x_pred * m1 + c1, ls='-', c='blue')
first_scatter = ax.scatter(x1, y1, marker='x', c='blue')
second_line, = ax.plot(x_pred, x_pred * m2 + c2, ls='--', c='black')
second_scatter = ax.scatter(x2, y2, marker='x', c='black')
ax.legend([lines.Line2D([0], [0], marker='x', ls='-', c='blue'),
lines.Line2D([0], [0], marker='x', ls='--', c='black')],
['series_1', 'series_2'])
I cleaned up your code a little, but feel free to take only the last line and the necessary import.
In the last line, just use the already created merged handle handle_combined instead of the handle_start.
ax.legend(handle_combined + list(zip(new_marker_handles,new_line_handles)),
label_start + ['series2'])
The length is 1 but if you look into the contents of the list, it is a tuple consisting of two objects. If you print handle_combined, you get a list of two Line2D objects, one of which is marker and the other is the line.
print (handle_combined)
# [(<matplotlib.lines.Line2D object at xxxxxxxxx>, <matplotlib.lines.Line2D object at xxxxxxxxx>)]
However, if you print handle_start, it returns just a single Line2D object
print (handle_start)
# [<matplotlib.lines.Line2D object at xxxxxxxxx>]
I have two sets of arrays x1, y1, t1 and x2, y2, t1 -- x data, y data and time measurement.
I would like to plot two these sets as lines with time as an x argument in plot(), so that lines are aligned with respect to time precedence of events.
However, I would also like to see the corresponding x1 and x2 on the plot in a form of xlabels (say at the top and at the bottom of the plot), as well as have two scales for y values (i.e. on the left and on the right of the figure).
import numpy as np
t1 = np.linspace(0, 10, 10)
y1 = np.arange(10)
x1 = (np.cumsum(np.random.rand(10)) * 1000000000).astype(int)
x1 = (x1 / 100000).astype(int) * 10
x2 = (np.cumsum(np.random.rand(10)) * 1000000000).astype(int)
x2 = (x2 / 1000000).astype(int)
y2 = 2 * np.arange(10)
t2 = np.linspace(0, 10, 10) + 2
from matplotlib import pyplot as plt
fig, ax1 = plt.subplots()
ax1.plot(t1, y1)
ax1.set_ylabel("y1 label")
ax1.set_xticklabels(x1)
ax1.set_xlabel("x1 label")
ax2 = ax1.twinx()
ax2.plot(t2, y2, c='r')
ax2.set_ylabel("y2 label")
ax3 = ax2.twiny()
ax3.xaxis.set_ticks_position('top')
ax3.set_xticklabels(x2);
ax3.set_xlabel("x2 label")
The code produces
which is good, but has two problems:
xlabels are not aligned with the data: blue line on the plot starts at x1 ticklabel 104500, while x1[0] = 29380.
I an unable to apply sci format for the x1 and x2 ticks, i.e. the line
ax1.ticklabel_format(style='sci', axis='x', scilimits=(0,0))
fails with This method only works with the ScalarFormatter, which is reasonable, since I have replaced labels of ticks, not ticks themselves. On the other hand, I cannot assign x1 to xticks, since this will change limits of xaxis.
How could I overcome two these problems?
I have a script with some plots ( see example code). After some other things i want to add a new plot to an existing one. But when i try that it add the plot by the last created figure(now fig2).
I can't figure out how to change that...
import matplotlib.pylab as plt
import numpy as np
n = 10
x1 = np.arange(n)
y1 = np.arange(n)
fig1 = plt.figure()
ax1 = fig1.add_subplot(111)
ax1.plot(x1,y1)
fig1.show()
x2 = np.arange(10)
y2 = n/x2
# add new data and create new figure
fig2 = plt.figure()
ax2 = fig2.add_subplot(111)
ax2.plot(x2,y2)
fig2.show()
# do something with data to compare with new data
y1_geq = y1 >= y2
y1_a = y1**2
ax1.plot(y1_geq.nonzero()[0],y1[y1_geq],'ro')
fig1.canvas.draw
Since your code is not runnable without errors I'll provide a sample snippet showing how to plot several data in same graph/diagram:
import matplotlib.pyplot as plt
xvals = [i for i in range(0, 10)]
yvals1 = [i**2 for i in range(0, 10)]
yvals2 = [i**3 for i in range(0, 10)]
f, ax = plt.subplots(1)
ax.plot(xvals, yvals1)
ax.plot(xvals, yvals2)
So the basic idea is to call ax.plot() for all datasets you need to plot into the same plot.