Matplotlib Subplot Labels Disappear - pandas

I want to prepare some hexbin plots from Pandas. My initial code is:
fig = plt.figure(figsize=(11,8))
ax1 = fig.add_subplot(111)
df2.plot(kind='hexbin', x='var1', y='var2', C='var3', reduce_C_function=np.median, gridsize=25,vmin=0, vmax=40,ax=ax1)
ax1.set_xlim([-5,2])
ax1.set_ylim([0,7])
However when I change this to:
fig = plt.figure(figsize=(11,8))
ax1 = fig.add_subplot(221)
ax2 = fig.add_subplot(222)
ax3 = fig.add_subplot(223)
ax4 = fig.add_subplot(224)
And plot create four subplots similar to the first example it turns off the xlabels and xticklabels.
What code to I need to switch them back on? And is this something I can do as a defaults?

Related

Unable to show legend on the graph for each subplot

I am trying to show the legend for each subplot but it doesn't seem like working. There is a box on the upper right of the subplot but it's empty. This is my code which I have tried. Also is there anyway I can enlarge the first subplot?
XWD_TO = data.iloc[:,0:1]
VAS_AX = data.iloc[:,1:2]
BTC_AUD = data.iloc[:,2:]
# Daily data chart of XWD.TO and VAS.AX (need to fix legend)
#fig = plt.figure()
fig, (ax1, ax2) = plt.subplots(2, sharex=True, sharey=True)
fig.suptitle('Daily Volatility')
ax1 = plt.subplot(211)
ax1.set_title("XWD.TO and VAS.AX")
ax1.plot(XWD_TO,c='orange')
ax1.plot(VAS_AX,c='green')
ax1.legend(loc = "upper right")
ax2 = plt.subplot(212)
ax2.set_title("BTC-AUD")
ax2.plot(BTC_AUD,c='blue')
plt.show()
You need to label each subplot. I have edited your code a bit. Hope it helps.
XWD_TO = data.iloc[:,0:1]
VAS_AX = data.iloc[:,1:2]
BTC_AUD = data.iloc[:,2:]
# Daily data chart of XWD.TO and VAS.AX (need to fix legend)
#fig = plt.figure()
fig, (ax1, ax2) = plt.subplots(2, sharex=True, sharey=True)
fig.suptitle('Daily Volatility')
ax1.set_title("XWD.TO and VAS.AX")
ax1.plot(XWD_TO,c='orange',label='XWD_TO')
ax1.plot(VAS_AX,c='green',label='VAS_AX'))
ax1.legend(loc = "upper right")
ax2.set_title("BTC-AUD")
ax2.plot(BTC_AUD,c='blue',label='BTC_AUD')
ax2.legend(loc = "upper right")
plt.show()

Matplotlib doesn't show both datasets points on the figure when I want to create scatter plot with

I'm sure that I've done all things right but in the end the result I got is a sccatter plot that only shows the second datasets data.
fig = plt.figure()
ax1 = fig.add_subplot(111)
ax1.scatter(train["ENGINESIZE"], train["CO2EMISSIONS"], color = "green")
ax1.scatter(test["ENGINESIZE"], test["CO2EMISSIONS"], color = "red")
plt.xlabel("Engine Size")
plt.ylabel("Emission")
plt.show()
Here You can see what's going on in my output in link below.
It shows only red data(test data) in the output.
Where is the "output link below", please? For now I can only imagine what you are describing.
Also it helps if both plots have the same axis. That is, both have the same x-axis and then they can vary on their y-axis.
If so:
fig, ax = plt.subplots()
df.plot(kind = 'scatter', x= train["ENGINESIZE"], y = train["CO2EMISSIONS"], color = {'g'}, ax = ax)
df.plot(kind = 'scatter', x= test["ENGINESIZE"], y = test["CO2EMISSIONS"], color = {'r'}, ax = ax)
plt.xlabel()

Barplots overlapping with blank subplot in Matplotlib

I am trying to make two subplots as a row in matplot lib.
Here is my code
fig, (ax1, ax2) = plt.subplots(1,2)
ax1 = plt.bar(x="Topic", height='perc', data=df1)
ax2 = plt.bar(x="Topic", height='perc', data=df2)
What is happening is that the barplots overlap eachother and leave col1 empty.
How can I fix this

Matplotlib add_subplot does not add to the expected position

fig = plt.figure(figsize=(10,30))
ax1 = fig.add_subplot(1,1,1)
ax2 = fig.add_subplot(2,1,2)
ax3 = fig.add_subplot(3,1,3)
ax1.imshow(np.ones((100,200,3))) # white
ax2.imshow(np.zeros((100,200,3))) # black
ax3.imshow(np.zeros((100,200,3))) # black
The above code yields the below image
ax1 the white image is where I expected to be. the ax2, ax3, the black images are overlapped with each other
Figured it out!
Turns out add_subplot requires the overal dimensions. So the correct way to write it this
fig = plt.figure(figsize=(10,15))
ax1 = fig.add_subplot(3,1,1)
ax2 = fig.add_subplot(3,1,2)
ax3 = fig.add_subplot(3,1,3)

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)