I'm new to python and attempting to chart some time series data. I'm using pyplot to create 3 stacked line charts which have the same x-axis (dates), but a different scale for the y-axes. However, each y-axis, as well as the x-axis for the bottom chart, have overlapping labels. There are labels generated from 0 to 1, as well as axis labels from my data set. How do I turn 'off' the auto-generated 0 to 1 labels on the y-axes and the bottom x-axis?
fig, ax = plt.subplots(3,1,sharex='all', squeeze=False, figsize=(12,8))
ax = fig.add_subplot(3,1,1)
plt.plot(df1['date'], df1['value'])
ax2 = fig.add_subplot(3,1,2)
plt.plot(df2['date'], df2['value'])
ax3 = fig.add_subplot(3,1,3)
plt.plot(df3['date'], df3['value'])
plt.show()
You can see the issue in the below picture. Any help is greatly appreciated!
You have already created subplots with all the axes in the initial assignment
fig, ax = plt.subplots(3,1,sharex='all', squeeze=False, figsize=(12,8))
therefore the following assignements of
ax = fig.add_subplot(3,1,1)
ax2 = fig.add_subplot(3,1,2)
ax3 = fig.add_subplot(3,1,3)
are not only unnecessary, but they seem to overlap the already created subplots (if you change it to add_subplot(2,1,1) you will notice it just starts dividing figure again and overlaying axes on top of each other).
What you want to do, is access the axes created in plt.subplots() call:
fig, ax = plt.subplots(3,1,sharex='all', squeeze=False, figsize=(12,8))
ax[0].plot(df1['date'], df1['value'])
ax[1].plot(df2['date'], df2['value'])
ax[2].plot(df3['date'], df3['value'])
plt.show()
Simulated Output:
Data from seaborn tips dataset
Related
As per this question, moving the xticks and labels of an AxesSubplot object can be done with ax.xaxis.tick_top(). However, I cannot get this to work with multiple axes inside a figure.
Essentially, I want to move the xticks to the very top of the figure (only displayed at the top for the subplots in the first row).
Here's a silly example of what I'm trying to do:
fig, axs = plt.subplots(nrows=2, ncols=2, sharex=True, sharey=True)
fig.set_figheight(5)
fig.set_figwidth(10)
for ax in axs.flatten():
ax.xaxis.tick_top()
plt.show()
Which shows
My desired result is this same figure but with the xticks and xticklabels at the top of the two plots in the first row.
Credits to #BigBen for the sharex comment. It is indeed what's preventing tick_top to work.
To get your results, you can combine using tick_top for the two top plots and use tick_params for the bottom two:
fig, axs = plt.subplots(2, 2, sharex=False) # Do not share xaxis
for ax in axs.flatten()[0:2]:
ax.xaxis.tick_top()
for ax in axs.flatten()[2:]:
ax.tick_params(axis='x',which='both',labelbottom=False)
See a live implementation here.
I have an assignment where I am trying to replicate the following subplots
I successfully replicated the three non-polar plots, but I cannot figure out how to set the fourth plot to polar. Here is what I have so far with my code, only including code relevant to the polar plot.
nmax=101 # choose a high number to "smooth out" lines in plots
x = np.linspace(0,20,nmax) # create an array x
y = np.exp(-x/4)*np.sin(x) # y for the top two subplots
fig, axs = plt.subplots(2, 2)
# bottom right subplot controls
axs[1, 1].polar(x, y)
This will give the error, AttributeError: 'AxesSubplot' object has no attribute 'polar'. How would I set the subplot to polar so I can replicate the plot?
You might have to define each axis separately, rather than using plt.subplots
fig = plt.figure()
ax1 = plt.subplot(221)
ax2 = plt.subplot(222)
ax3 = plt.subplot(223)
ax4 = plt.subplot(224, projection = 'polar')
I have a pandas data frame, region, containing the prices of flats (Flat) and detached properties (Detached) in areas of the UK over time (the column Month). I'm trying to obtain plots of the change in price over time of both flats and detached properties, so that the plots have two different y axes - both of the average price but in different scales.
I've achieved this by using twinx(), however using the code below I get obviously get two figures. The first of these figures is exactly what I want, but I then get a second figure of blank plots. I have attached a screenshot of the kind of plot I want below.
When removing the second fig line fig, ax2 = ..., I get the error NameError: name 'ax2' is not defined. Also bringing the line ax2 = ax.twinx() outside of the loop gives the error AttributeError: 'numpy.ndarray' object has no attribute 'twinx'. I can't seem to figure out how to get this plot to work without having the duplicate blank figure, any help is much appreciated.
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
region_list = sorted(region['Area'].unique().tolist())
fig, ax = plt.subplots(nrows=len(region_list), figsize=(13.8,len(region_list)*7))
fig, ax2 = plt.subplots(nrows=len(region_list), figsize=(13.8,len(region_list)*7))
for i in region_list:
ind = region_list.index(i)
filt = region['Area'] == i
ax2[ind] = ax[ind].twinx()
ax[ind].plot(region.loc[filt]['Month'],region.loc[filt]['Flat'], color='red', marker='o')
ax[ind].set_ylabel('Average price of flats', color='red', fontsize=14)
ax2[ind].plot(region.loc[filt]['Month'],region.loc[filt]['Detached'],color='blue',marker='o')
ax2[ind].set_ylabel('Average price of detached properties',color='blue',fontsize=14)
ax[ind].set_title(i, size=14)
ax[ind].xaxis.set_tick_params(labelsize=10)
ax[ind].yaxis.set_tick_params(labelsize=10)
plt.tight_layout()
When creating a secondary axis for a subplot, the result is a new object, and can't be referenced using array indices like the subplot axes (unless you specifically add the new twin axes to an array).
You've probably seen the following:
# with one axis
fig, ax = plt.subplots()
ax2 = ax.twinx()
ax2.plot(...)
But with multiple subplots, the same logic applies:
# with one axis
fig, axes = plt.subplots(1, 2)
ax2 = axes[0].twinx()
ax2.plot(...) # secondary axis on subplot 0
ax2 = axes[1].twinx()
ax2.plot(...) # secondary axis on subplot 1
In your case:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
region_list = sorted(region['Area'].unique().tolist())
fig, ax = plt.subplots(nrows=len(region_list), figsize=(13.8,len(region_list)*7))
# don't add a second plot - this would be blank
# fig, ax2 = plt.subplots(nrows=len(region_list), figsize=(13.8,len(region_list)*7))
for i in region_list:
ind = region_list.index(i)
filt = region['Area'] == i
# don't index into ax2
# ax2[ind] = ax[ind].twinx()
# instead, create a local variable ax2 which is the secondary axis
# on the subplot ax[ind]
ax2 = ax[ind].twinx()
ax[ind].plot(region.loc[filt]['Month'],region.loc[filt]['Flat'], color='red', marker='o')
ax[ind].set_ylabel('Average price of flats', color='red', fontsize=14)
ax2.plot(region.loc[filt]['Month'],region.loc[filt]['Detached'],color='blue',marker='o')
ax2.set_ylabel('Average price of detached properties',color='blue',fontsize=14)
ax[ind].set_title(i, size=14)
ax[ind].xaxis.set_tick_params(labelsize=10)
ax[ind].yaxis.set_tick_params(labelsize=10)
plt.tight_layout()
I am trying to make the below grid of plots a little bit cleaner. I don't want the tick marks on the left side and the bottom to overlap. I have tried to despine the axes by trying the below code, but it doesn't seem to work. Anyone have any suggestions?
fig, ax = plt.subplots(figsize=(15,10))
cols = ['x6', 'x7', 'x16', 'x17']
subset = df[cols]
normed_df = (subset-subset.min())/(subset.max()-subset.min())
style.use('seaborn-darkgrid')
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
ax.spines['left'].set_visible(False)
ax.spines['bottom'].set_visible(False)
for sp in range(4):
ax = fig.add_subplot(2,2, sp+1)
ax.hist(normed_df[cols[sp]], density=True)
normed_df[cols[sp]].plot.kde(ax=ax)
ax.tick_params(bottom="off", top="off", left="off", right="off")
After running the above code, I am getting the following plots, however, the ticks are still overlapping.
either do what #Arne suggested:
fig, ax = plt.subplots(rows, cols) #makes a grid of subplots
or make your first two lines this:
fig, ax = plt.subplots(figsize=(15,10))
ax.axis('off')
this will remove the axis around the entire subplot before adding your additional subplots
When you call plt.subplots() without specifying a grid, it creates those axes across the whole figure whose tick marks and labels interfere with your subplot tick labels in the final plot. So change your first line of code to this:
fig, ax = plt.subplots(2, 2, figsize=(15,10))
I am trying to get the values of xticks from one plot and then use these values for another plot but set the new ticks as 10 to the power of the other plot's ticks. The following lines doesn't do the job I am aiming for
labels=[item for item in ax1.get_xticklabels()]
ax2.set_xticklabels(['$10^{{{:d}}}$'.format(int(i)) for i in labels])
I will appreciate for any suggestion.
What about sharing axes ? This will fix the same limits and number of ticks for ax1 and ax2 :
fig, ax = plt.subplots(1, 2, sharex=True)
ax1 = ax[0]
ax2 = ax[1]
Then your code will do the trick since you are sure that both subplots have the same xticks
labels = [item for item in ax2.get_xticklabels()]
ax2.set_xticklabels(['$10^{{{:d}}}$'.format(int(i)) for i in labels])