0

unfortunately i have already tried different things i have found so. how can i create a common legend at the top of the figure for my three subplots? The following code didn't work and the execution was stuck, below you will also find the whole code snippet. Actually I thought I could handle it by myself, but i definitely need your help.

fig.tight_layout()
handles, labels = axs[0].get_legend_handles_labels()
fig.legend(handles, labels, fontsize=fs, loc='upper center', bbox_to_anchor=(0.5, 1.05), ncol=4)

Here my whole code snippet:


df = pd.read_csv('energy_production_ver4.csv', sep=",")

# Figure Properties
fs = 4  # 30
lw = 2  # 3
width_bars=0.5
ec = 'dimgray'

# Create Subplots
fig, axs = plt.subplots(3, sharex=True, sharey=True, num=None, figsize=(25, 16), dpi=300, facecolor='w',
                        edgecolor='k')  # 26 15
plt.rc('text', usetex=True)
plt.rc('font', family='serif')
plt.rc('font', size=fs-1)
plt.gcf().subplots_adjust(bottom=0.15)

#adjust Time Stamp to desired format

temp_x=df["DateTimeStamp"]
y1 = df['Production']
y2 = df['Consumption']
y3 = df['Production CHP 22kW']
y4 = df['Battery charge']
y5 = df['Battery discharge']
y6 = df['Grid supply']
y7 = df['Feed in grid']

# axs[0].grid(True, linestyle=':')
axs[0].yaxis.grid(linestyle=':')
axs[0].tick_params(axis='both', labelsize=fs)
axs[0].bar(temp_x, y1, label=r'$PV^\mathrm{s}$', color='blue', linewidth=lw / 2, width=width_bars)
axs[0].bar(temp_x, y2, label=r'$EV^\mathrm{s}$', color='orange', linewidth=lw / 2, width=width_bars)
axs[0].bar(temp_x, y3, label=r'CHP', color='green', linewidth=lw / 2, width=width_bars)
axs[0].set_ylabel(r'Energy in MWh', fontsize=fs)


axs[1].yaxis.grid(linestyle=':')
axs[1].tick_params(axis='both', labelsize=fs)
axs[1].bar(temp_x, y4, label=r'$BSS^\mathrm{CH}$', color='red', linewidth=lw / 2, width=width_bars)
axs[1].bar(temp_x, y5, label=r'$BSS^\mathrm{d}$', color='purple', linewidth=lw / 2, width=width_bars)
axs[1].set_ylabel(r'Energy in MWh', fontsize=fs)


axs[2].yaxis.grid(linestyle=':')
axs[2].tick_params(axis='both', labelsize=fs)
axs[2].bar(temp_x, y6, label=r'$GRID^\mathrm{CH}$', color='brown', linewidth=lw / 2, width=width_bars)
axs[2].bar(temp_x, y7, label=r'$GRID^\mathrm{d}$', color='pink', linewidth=lw / 2, width=width_bars)
axs[2].set_ylabel(r'Energy in MWh', fontsize=fs)



plt.xticks(rotation=90)
handles, labels = axs.get_legend_handles_labels() #does not work?
fig.legend(handles, labels, fontsize=fs, loc='upper center', bbox_to_anchor=(0.5, 1.05), ncol=4)

plt.show()
marv_97
  • 37
  • 6
  • Could you please post your full code with your error message? I think I know where there is a problem (you're accessing all axes, not just one) but half of your variables here are not defined and I want to be sure before I answer your question. – My Work Sep 22 '21 at 10:02
  • Thank you! Do appreciate it. I've posted it. Can you please help me? – marv_97 Sep 22 '21 at 10:32
  • Please provide enough code so others can better understand or reproduce the problem. – Community Sep 29 '21 at 11:25

1 Answers1

0

The general idea works (I believe this post or this one is your source or works for one axis). The problem here is that you have several axes wrapped in the axs (which is a numpy array) so when you do what you write, you would be getting something like

AttributeError: 'numpy.ndarray' object has no attribute 'get_legend_handles_labels'

The way around this is to go over all the axes and concat the legends (their labels and handles), eg. in the following way:

...
handles,labels=[],[]
for ax in axs.flatten():
    h, l = ax.get_legend_handles_labels()
    handles+=h
    labels+=l

fig.legend(handles, labels, fontsize=fs, loc='upper center', bbox_to_anchor=(0.5, 1.05), ncol=4)
My Work
  • 2,143
  • 2
  • 19
  • 47
  • "Thank you for your help! If I apply your suggestion, I'll get the following error message : TimeoutError: Lock error: Matplotlib failed to acquire the following lock file: [C:\Users...] This maybe due to another process holding this lock file. If you are sure no other Matplotlib process is running, remove this file and try again." If I don't use a legend (respectively your suggestion), this error message will not show up and the code runs successfully. – marv_97 Sep 22 '21 at 11:53
  • I believe that's another issue for another question. I'm not getting anything like that and tbh I have never seen this error message before. I'd recommend cleaning your environment and maybe check other posts like https://stackoverflow.com/questions/50141983/python-matplotlib-matplotlib-cbook-timeouterror-lockerror, https://stackoverflow.com/questions/58647755/encountering-time-out-error-in-the-middle-of-a-matplotlib-for-loop, or checking your tex – My Work Sep 22 '21 at 12:07
  • Thanks for your help! It worked for me! – marv_97 Sep 22 '21 at 19:20
  • You're welcome. If the problem is solved, then mark the answer as accepted. – My Work Sep 22 '21 at 19:59