This might be a very simple question, but I just could not get the trick for this problem .
I want to plot multiple subplots, but when I have done that and use my defined axis limits, I find there is overlapping of axis. Y axis should be same in each column. Any tips to remove this:
My simplified script is here:
column = 2
num=len(sta_files)
fig, axes = plt.subplots(nrows=num, ncols=column,figsize=(15,15))
n=0
for event_file in sta_files:
axes[n,0].plot(np.arange(0,len(st[0].data))*1/sampling_rate,
st[0].data+i,color='k',linewidth=0.7)
axes[n,0].set_xlim((0, 35))
spl2 = st[0]
fig = spl2.spectrogram(show=False, axes=axes[n,1])
mappable = axes[n,1].images[0]
Here is my output:
Related
I have created a grid of subplots to my liking.
I initiated the plotting by defining fig,ax = plt.subplots(2,6,figsize=(24,8))
So far so good. I filled those subplots with their respective content. Now I want to plot a single or two particular subplot in isolation. I tried:
ax[idx][idx].plot()
This does not work and returns an empty list
I have tried:
fig_single,ax_single = plt.subplots(2,1)
ax_single[0]=ax[idx][0]
ax_single[1]=ax[idx][1]
This returns:
TypeError: 'AxesSubplot' object does not support item assignment
How do I proceed without plotting those subplots again by calling the respective plot functions?
You're close.
fig,ax = plt.subplots(nrows=2,ncols=6,sharex=False,sharey=False,figsize=(24,8))
#set either sharex=True or sharey=True if you wish axis limits to be shared
#=> very handy for interactive exploration of timeseries data, ...
r=0 #first row
c=0 #first column
ax[r,c].plot() #plot your data, instead of ax[r][c].plot()
ax[r,c].set_title() #name title for a subplot
ax[r,c].set_ylabel('Ylabel ') #ylabel for a subplot
ax[r,c].set_xlabel('X axis label') #xlabel for a subplot
A more complete/flexible method is to assign r,c:
for i in range(nrows*ncols):
r,c = np.divmod(i,ncols)
ax[r,c].plot() #....
You can afterwards still make modifications, e.g. set_ylim, set_title, ...
So if you want to name the label of the 11th subplot:
ax[2,4].set_ylabel('11th subplot ylabel')
You will often want to make use of fig.tight_layout() at the end, so that the figure uses the available area correctly.
Complete example:
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0,180,180)
nrows = 2
ncols = 6
fig,ax = plt.subplots(nrows=nrows,ncols=ncols,sharex=False,sharey=False,figsize=(24,8))
for i in range(nrows*ncols):
r,c = np.divmod(i,ncols)
y = np.sin(x*180/np.pi*(i+1))
ax[r,c].plot(x,y)
ax[r,c].set_title('%s'%i)
fig.suptitle('Overall figure title')
fig.tight_layout()
My plot function creates horizontal bars per year for data with different size. I have to change the figure size for each set of subplots.
I need to place my two legends on lower center of each figure below the x axis label. The positions need to vary depending on the figure size and remain consistent. So for all produced figures, the legends would look like this figure.
Find a snippet of my dataframe here. I have tried to simplify the code as much as I could and I know the plot is missing some element, but I just want to get to my question's answer, not to create a perfect plot here. I understand probably I need to create a variable for my anchor bounding box but I don't know how. Here is my code:
def plot_bars(data,ax):
""" Plots a single chart of work plan for a specific routeid
data: dataframe with section length and year
Returns: None"""
ax.barh(df['year'], df['sec_len'] , left = df['sec_begin'])
ax.set_yticklabels('')
def plot_fig(df):
# Draw the plots
ax_set = df[['routeid','num_bars']].drop_duplicates('routeid')
route_set = ax_set['routeid'].values
h_ratios = ax_set['num_bars'].values
len_ratio = h_ratios.sum()/BARS_PER_PAGE # Global constant set to 40 based on experiencing
fig, axes = plt.subplots(len(route_set), 1, squeeze=False, sharex=True
, gridspec_kw={'height_ratios':h_ratios}
, figsize=(10.25,7.5*len_ratio))
for i, r in enumerate(route_set):
plot_bars(df[df['routeid']==r], axes[i,0])
plt.xlabel('Section length')
## legends
fig.legend(labels=['Legend2'], loc=8, bbox_to_anchor=(0.5, -0.45))
fig.legend( labels=['Legend1'], loc = 8, bbox_to_anchor=(0.5, -0.3))
## Title
fig.suptitle('title', fontsize=16, y=1)
fig.subplots_adjust(hspace=0, top = 1-0.03/len_ratio)
for df in df_list:
plot_fig(df)
The problem is when the figure size changes, the legends move as in these pictures:
here
here
I think the problem boils down to having the correct relative position with respect to the xlabel, so are right that you need to calculate the bbox_to_anchor using the position of the xlabel and the height/width of the axes. Something like this:
fig, (ax, ax1) = plt.subplots(nrows=2, figsize=(5, 4), gridspec_kw={'height_ratios':[4, 1]})
ax.plot(range(10), range(10), label="myLabel")
ax.set_xlabel("xlabel")
x, y = ax.xaxis.get_label().get_position() # position of xlabel
h, w = ax.bbox.height, ax.bbox.width # height and width of the Axes
leg_pos = [x + 0 / w, y - 55 / h] # this needs to be adjusted according to your needs
fig.legend(loc="lower center", bbox_to_anchor=leg_pos, bbox_transform=ax.transAxes)
plt.show()
I wish to clarify two queries in this post.
I have a pandas df like below picture.
1. Plotting problem : .
When i try to plot column 0 with column 1, the values gets sorted.
example : in col_0 I have values starting from 112 till 0.
the values gets sorted in ascending order and the graph shows reversed X axis plot when i use the below code.
plt.plot(df.col_0, df.col_1)
What will be best way to avoid sorting X axis values. ?
2. All paramaters in single graph
I would like to plot all the params in a single plot. Except X axis all other params values are between 0 to 1 (same scale)
What will be best pythonic way of doing.
Any help would be appreciated.
Try to draw the series/dataframe against the index:
col_to_draw = [col for col in df.columns if col!='col0']
# if your data frame is indexed as 0,1,2,... ignore this step
tmp_df = df.reset_index()
ax = tmp_df[col_to_draw].plot(figsize=(10,6))
xtick_vals = ax.get_xticks()
ax.set_xticklabels(tmp_df.col0[xtick_vals].tolist())
Output:
I don't understand what you mean by they get sorted - does it not plot 112, 0.90178 and connect it to 110.89899, 0.90779, etc?
To share the X axis but have 2 Y axes that certain sets are plotted on, use twinx
fig, ax1 = plt.subplots()
ax1.plot(df.col_0, df.col_1)
ax2 = ax1.twinx()
ax2.plot(df.col_0, df.col_2)
re: how to plot in the order you want
I believe your intention is to actually plot these values vs. time or index. To that end, I suggest:
fig, ax1 = plt.subplots()
ax1.plot(df['Time'], df.col_0) # or df.index, df.col_0
ax2 = ax1.twinx()
ax2.plot(df['Time'], df.col_1)
I am plotting 2 lines and a dot, X axis is a date range. The dot is most important, but it appears on the boundary of the plot. I want to "expand" the plot further right so that the dot position is more visible.
In other words I want to expand the X axis without adding new values to Y values of lines. However if I just add a few dates to X values of lines I get the "x and y dimensions must be equal" error. I tried to add a few np.NaN values to Y so that dimensions are equal, but then I get an error "integer required".
My plot:
My code:
fig1 = plt.figure()
ax1 = fig1.add_subplot(111)
plot_x = train_original.index.values
train_y = train_original.values
ax1.plot(plot_x, train_y, 'grey')
x = np.concatenate([np.array([train_original.index.values[-1]]), test_original.index.values])
y = np.concatenate([np.array([train_original.dropna().values[-1]]), test_original.dropna().values])
ax1.plot(x, y, color='grey')
ax1.plot(list(predicted.index.values), list(predicted.values), 'ro')
ax1.axvline(x=train_end, alpha=0.7, linestyle='--',color='blue')
plt.show()
There are a couple of ways to do this.
An easy, automatic way to do this, without needing knowledge of the existing xlim is to use ax.margins. This will add a certain fraction of the data limits to either side of the plot. For example:
ax.margins(x=0.1)
will add 10% of the current x range to both ends of the plot.
Another method is to explicitly set the x limits using ax.set_xlim.
Just change the xlim(). Something like:
xmin, xmax = plt.xlim() # return the current xlim
plt.xlim(xmax=xmax+1)
Is there any way in a panel of NxM subplots to just have the axes being shown for the left column and bottom row.
A|N|N|N
A|N|N|N
A|N|N|N
A|A|A|A
Where A = axis and N = no axis
Sometimes my subplots are 10x8, 3x4, 4x9 etc. and they all have the same x and y axis. I just want it to appear on the very left and the very bottom of that subset. At the moment I have to know which axis it is plotting to and do
if (figi-1) % 7 != 0:
ax.set_yticklabels([])
if figi < 29:
ax1.set_xticklabels([])
I want to generalise this for any NxM panel arrangement without having to know before hand.
Thanks.
EDIT: I have found a way to do the y-axis. I setup the number of panels wide using:
nwide = 12
nhigh = 5
Which means I can just do
if (figi-1) % nwide != 0:
ax.set_yticklabels([])
Any ideas for bottom?
EDIT: Worked it out. x-axis is as follows:
if figi < (nwide*nhigh) - nwide:
ax.set_xticklabels([])
The best solution is probably pyplot.subplots(). You can do like:
fig, axes = pyplot.subplots(nrows=3, ncols=4, sharex=True, sharey=True)
and then only the left and bottom axes will have the labels displayed.
To access each subplot you can get it from axes like you do in a matrix: ax = axes[i,j]
To control the tick positions you can use:
ax.xaxis.set_tick_position('bottom')
ax.yaxis.set_tick_position('left')
To set an axis label you can do:
ax.set_label_text('Something')