Add a graph plot to another one in matplotlib - matplotlib

How can make a sum of two plot from matplotlib axes class?
For example I have an idea like this:
>> fig, ax1 = plt.subplots()
>> ax1.plot(x1, y1)
>> fig, ax2 = plt.subplots()
>> ax2.plot(x2, y2)
I want to have something like:
>> ax = ax1 + ax2
Someone have an idea or suggest, how to deal with it?
Regards!

Related

Change rotation of tick label on subplots

How do you change rotation of tick label on subplot in matplotlib?
I think the easiest solution is:
fig, ax = plt.subplots(1)
ax.plot(range(13))
plt.xticks(rotation='vertical')
If you really need to use the ax object you can try doing something like:
fig, ax = plt.subplots(1)
ax.plot(range(13))
xticks = ax.get_xticks()
ax.set_xticks(xticks)
ax.set_xticklabels(xticks, rotation='vertical')

How to stack the graphs in such a way that the share a common scale along x-axis

The following code is for generating the 3 subplots. And on all the 3 subplots scale is mentioned. I want to stack them in such a way that x-axis and y-axis scale appear once like this. Can I get this plot with plt.subplot() or fig.add_axes is compulsory for this? I actually want to do this with subplots because in fig.add_subplot I havve to specify the width and height of each plot that I don't want.
`fig,axes = plt.figure(nrow=3, ncolmn=1)
ax1 = fig.add_subplot(311)
ax2 = fig.add_subplot(312)
ax3 = fig.add_subplot(313)
ind1 =[1,2,3]
ind2 = [4,5,6]
for i in range(len(3)):
data1=np.load(..)
data2=np.load(..)
axes[i].plot(data1, data2)`
Here is one solution using subplots_adjust where you put the space between two plots to 0 using hspace. Also, use sharex=True to have a shared x-axis
fig, axes = plt.subplots(nrows=3, ncols=1,sharex=True)
x = np.linspace(0, 2*np.pi, 100)
y = np.sin(x)
for i, ax in enumerate(axes.ravel()): # or axes.flatten() or axes.flat
ax.plot(x, y, label='File %d' %i)
ax.legend()
fig.text(0.5, 0.01, 'X-label', ha='center')
fig.text(0.01, 0.5, 'Y-label', va='center', rotation='vertical')
plt.tight_layout() # To get a better spacing between the subplots
plt.subplots_adjust(hspace=.0)

Matplotlib - how to combine a list of AxesSubplot into one figure with multiple subplots? [duplicate]

Looking at the matplotlib documentation, it seems the standard way to add an AxesSubplot to a Figure is to use Figure.add_subplot:
from matplotlib import pyplot
fig = pyplot.figure()
ax = fig.add_subplot(1,1,1)
ax.hist( some params .... )
I would like to be able to create AxesSubPlot-like objects independently of the figure, so I can use them in different figures. Something like
fig = pyplot.figure()
histoA = some_axes_subplot_maker.hist( some params ..... )
histoA = some_axes_subplot_maker.hist( some other params ..... )
# make one figure with both plots
fig.add_subaxes(histo1, 211)
fig.add_subaxes(histo1, 212)
fig2 = pyplot.figure()
# make a figure with the first plot only
fig2.add_subaxes(histo1, 111)
Is this possible in matplotlib and if so, how can I do this?
Update: I have not managed to decouple creation of Axes and Figures, but following examples in the answers below, can easily re-use previously created axes in new or olf Figure instances. This can be illustrated with a simple function:
def plot_axes(ax, fig=None, geometry=(1,1,1)):
if fig is None:
fig = plt.figure()
if ax.get_geometry() != geometry :
ax.change_geometry(*geometry)
ax = fig.axes.append(ax)
return fig
Typically, you just pass the axes instance to a function.
For example:
import matplotlib.pyplot as plt
import numpy as np
def main():
x = np.linspace(0, 6 * np.pi, 100)
fig1, (ax1, ax2) = plt.subplots(nrows=2)
plot(x, np.sin(x), ax1)
plot(x, np.random.random(100), ax2)
fig2 = plt.figure()
plot(x, np.cos(x))
plt.show()
def plot(x, y, ax=None):
if ax is None:
ax = plt.gca()
line, = ax.plot(x, y, 'go')
ax.set_ylabel('Yabba dabba do!')
return line
if __name__ == '__main__':
main()
To respond to your question, you could always do something like this:
def subplot(data, fig=None, index=111):
if fig is None:
fig = plt.figure()
ax = fig.add_subplot(index)
ax.plot(data)
Also, you can simply add an axes instance to another figure:
import matplotlib.pyplot as plt
fig1, ax = plt.subplots()
ax.plot(range(10))
fig2 = plt.figure()
fig2.axes.append(ax)
plt.show()
Resizing it to match other subplot "shapes" is also possible, but it's going to quickly become more trouble than it's worth. The approach of just passing around a figure or axes instance (or list of instances) is much simpler for complex cases, in my experience...
The following shows how to "move" an axes from one figure to another. This is the intended functionality of #JoeKington's last example, which in newer matplotlib versions is not working anymore, because axes cannot live in several figures at once.
You would first need to remove the axes from the first figure, then append it to the next figure and give it some position to live in.
import matplotlib.pyplot as plt
fig1, ax = plt.subplots()
ax.plot(range(10))
ax.remove()
fig2 = plt.figure()
ax.figure=fig2
fig2.axes.append(ax)
fig2.add_axes(ax)
dummy = fig2.add_subplot(111)
ax.set_position(dummy.get_position())
dummy.remove()
plt.close(fig1)
plt.show()
For line plots, you can deal with the Line2D objects themselves:
fig1 = pylab.figure()
ax1 = fig1.add_subplot(111)
lines = ax1.plot(scipy.randn(10))
fig2 = pylab.figure()
ax2 = fig2.add_subplot(111)
ax2.add_line(lines[0])
TL;DR based partly on Joe nice answer.
Opt.1: fig.add_subplot()
def fcn_return_plot():
return plt.plot(np.random.random((10,)))
n = 4
fig = plt.figure(figsize=(n*3,2))
#fig, ax = plt.subplots(1, n, sharey=True, figsize=(n*3,2)) # also works
for index in list(range(n)):
fig.add_subplot(1, n, index + 1)
fcn_return_plot()
plt.title(f"plot: {index}", fontsize=20)
Opt.2: pass ax[index] to a function that returns ax[index].plot()
def fcn_return_plot_input_ax(ax=None):
if ax is None:
ax = plt.gca()
return ax.plot(np.random.random((10,)))
n = 4
fig, ax = plt.subplots(1, n, sharey=True, figsize=(n*3,2))
for index in list(range(n)):
fcn_return_plot_input_ax(ax[index])
ax[index].set_title(f"plot: {index}", fontsize=20)
Outputs respect.
Note: Opt.1 plt.title() changed in opt.2 to ax[index].set_title(). Find more Matplotlib Gotchas in Van der Plas book.
To go deeper in the rabbit hole. Extending my previous answer, one could return a whole ax, and not ax.plot() only. E.g.
If dataframe had 100 tests of 20 types (here id):
dfA = pd.DataFrame(np.random.random((100,3)), columns = ['y1', 'y2', 'y3'])
dfB = pd.DataFrame(np.repeat(list(range(20)),5), columns = ['id'])
dfC = dfA.join(dfB)
And the plot function (this is the key of this whole answer):
def plot_feature_each_id(df, feature, id_range=[], ax=None, legend_bool=False):
feature = df[feature]
if not len(id_range): id_range=set(df['id'])
legend_arr = []
for k in id_range:
pass
mask = (df['id'] == k)
ax.plot(feature[mask])
legend_arr.append(f"id: {k}")
if legend_bool: ax.legend(legend_arr)
return ax
We can achieve:
feature_arr = dfC.drop('id',1).columns
id_range= np.random.randint(len(set(dfC.id)), size=(10,))
n = len(feature_arr)
fig, ax = plt.subplots(1, n, figsize=(n*6,4));
for i,k in enumerate(feature_arr):
plot_feature_each_id(dfC, k, np.sort(id_range), ax[i], legend_bool=(i+1==n))
ax[i].set_title(k, fontsize=20)
ax[i].set_xlabel("test nr. (id)", fontsize=20)

Plot on the same twin scale

I would like to plot three set of data, one with one y ax and the other two with another ax. As now I write the code as:
fig, ax1 = plt.subplots()
ax2 = ax1.twinx()
ax3 = ax1.twinx()
ax1.plot(a)
ax2.plot(b, "r")
ax3.plot(c, "y")
plt.show()
In this way, on the right side of the picture I have two different scales. How can I have only one? How can I make so that "a" data are plotted on the left y ax and "b" and "c" data are plotted on the right side? (with the exact same scale)
Thank you!
Remove ax3 from the code. It has no purpose. Then call ax2.plot(c, "y") to show the c data on ax2, just as you did with the data b.
fig, ax1 = plt.subplots()
ax2 = ax1.twinx()
ax3 = ax1.twinx()
ax1.plot(a)
ax2.plot(b, "r")
ax2.plot(c, "y")
plt.show()

How to print values/scale on the y-axis of a bar plot

This is what I have done so far. My problen, however, is that I can't print the values/scale on the y-axis of a bar plot? Any ideas? What other stylings whould I add?
import seaborn as sb
from matplotlib import pyplot
%matplotlib inline
sb.axes_style("white")
sb.set_style("ticks")
sb.set_context("talk")
x1 = np.array(['U', 'G'])
x2 = np.array(['H', 'W'])
f, (ax1, ax2) = pyplot.subplots(1, 2, figsize=(12, 6))
y1 = np.array([831824, 3306662])
y2 = np.array([1798043, 1508619])
sb.barplot(x1, y1, ci=None, palette="Blues", hline=.0001, ax=ax1)
sb.barplot(x1, y2, ci=None, palette="Reds", hline=.0001, ax=ax2)
ax1.set_ylabel("Occurences")
ax1.set_xlabel("Totals")
ax2.set_ylabel("Occurences")
ax2.set_xlabel("Types")
sb.despine(bottom=True)
pyplot.setp(f.axes, yticks=[])
pyplot.tight_layout(h_pad=3)
sb.despine()
Based on #john-cipponeri's answer:
Using functions operating on axes called using pyplot.* only operate on the last opened axis, in your case ax2, which is the the right plot. Use the axis instance to take it effect where you want. Replace tour last block of your code with this one and I hope it corresponds to your expected plot:
ax1.grid(axis='y', linestyle='-')
ax2.grid(axis='y', linestyle='-')
pyplot.tight_layout(h_pad=3)
sb.despine()
You can try a line style.
pyplot.grid(axis='y', linestyle='-')