1

I have a data set that looks similar to the below, but is much longer:

   Sample Name Treatment Replicate  Time Congener  Concentration (ng/L)
0     Blank-1     Blank         1     0   PbTx-1                     0
1      Ctrl-1      Ctrl         1     0   PbTx-1                  8800
2      Ctrl-2      Ctrl         2     0   PbTx-1                  7500
3      Ctrl-3      Ctrl         3     0   PbTx-1                  9100
4     10ppm-1     10ppm         1     0   PbTx-1                  9800

I am attempting to create a group (array?) of subplots that shows each time period in a different plot, comparing each treatment, with each congener represented, that has a single legend for the entire plot with 4 columns below the "treatment" x-label.

This link goes to the almost perfect graph, except all the legends are visible

This is the code I used to generate the nearly perfect graph, but with visible legends:

#Setting the variables outside of the actual arguments to improve readability
first_dimension = "Treatment"
second_dimension = "Concentration (ng/L)"
third_dimension = "Congener"

#Setting the y-axis limit for toxin
ylim_toxin = td['Concentration (ng/L)'].max() * 1.05
    
#This gets the total number of subplots
num_plots = len(treatments)
fig, axes = plt.subplots(ncols = num_plots, sharey=True, sharex=True, figsize = (5*num_plots,5))

#Removes the space between the plots, so they share an X and are lined up nicely by time the sample was taken
fig.subplots_adjust(hspace=0, wspace=0)

#Set overarching title based on previously input project name
fig.suptitle(f'{pdate}', fontweight='bold')
fig.supxlabel(f'Treatment')

    
#Create a bar plot of the data using seaborn, looping through the treatments list and each axis using count
count = 0
for ax in axes:
    axes[count].set_title(f"T = {treatments[count]}")
    treat = treatments[count]
    tdtreat = td.loc[td['Time'] == treat]
    sns.barplot(
                x = first_dimension , 
                y = second_dimension , 
                hue = third_dimension , 
                data = tdtreat ,
                capsize = 0.05 ,
                errwidth = '1' ,
                errcolor = '0' ,
                edgecolor="0" ,
                errorbar = 'sd',
                ax = ax)
    count = count + 1
    
ax.set(xlabel=None)
ax.set(ylabel=None)
    
#Setting a y-label with supylabel created a y label that was far to the left, simply labelling the first y-axis
axes[0].set_ylabel("Concentration (ng/L)", fontsize = 12)

I managed to get the following graph, with the one legend moved to the bottom and stretched out perfectly into four columns, but the other legends are still visible:

Graph with one legend in correct location

I have attempted setting the legend equal to False to remove all legends, then add one back in, but it says " 'Rectangle' object has no property 'legend'":

sns.barplot(x = first_dimension , 
            y = second_dimension , 
            hue = third_dimension , 
            data = tdtreat ,
            capsize = 0.05 ,
            errwidth = '1' ,
            errcolor = '0' ,
            edgecolor="0" ,
            errorbar = 'sd',
            ax = ax,
            legend = False)

I have attempted adding "ax.legend_.set_visible(False)", but I get the error "'NoneType' object has no attribute 'set_visible'":

count = 0
for ax in axes:
    axes[count].set_title(f"T = {treatments[count]}")
    ax.legend_.set_visible(False)
    treat = treatments[count]
    tdtreat = td.loc[td['Time'] == treat]
    sns.barplot(x = first_dimension , 
                y = second_dimension , 
                hue = third_dimension , 
                data = tdtreat ,
                capsize = 0.05 ,
                errwidth = '1' ,
                errcolor = '0' ,
                edgecolor="0" ,
                errorbar = 'sd',
                ax = ax)
    count = count + 1
    
ax.set(xlabel=None)
ax.set(ylabel=None)

I have tried updating the seaborn package, along with all other packages in the anaconda terminal, yet it still produces these errors.

As mentioned in this prior question on how to remove matplotlib legends, I attempted "ax.get_legend().remove()" and yet I got "'NoneType' object has no attribute 'remove'" as an error.

This question addressed the none type, "You have a variable that is equal to None and you're attempting to access an attribute of it called 'something'."

I'm not sure why the axis would be "None" when the axis appears to be there..

Thank you very much.

medium-dimensional
  • 1,974
  • 10
  • 19
  • Welcome to SO! If I have to summarise your question, can I say you want to remove all legend boxes but one? Where do you wish to position such a legend box? – medium-dimensional Dec 22 '22 at 16:13
  • 1
    Thank you! Yes, that's a much more succinct way to put it. I'm aiming to place it, like this image (https://i.stack.imgur.com/3EGQR.png) in the bottom center, below the x axis label. – RedTideSide Dec 22 '22 at 16:26
  • Thanks! Does this answer your question? https://stackoverflow.com/questions/62252493/create-a-single-legend-for-multiple-plot-in-matplotlib-seaborn – medium-dimensional Dec 22 '22 at 18:05
  • 1
    You are trying to remove the legend before it exists. – mwaskom Dec 22 '22 at 19:18
  • Yes, I needed to make the sns.barplot into ax = sns.barplot, then I was able to use ax.get_legend().remove(), followed by the addition of the handles, labels, mentioned in that question. Thank you very much. – RedTideSide Dec 22 '22 at 19:24
  • @mwaskom Ah, I hadn't realized that. I had tried adding the "ax.get_legend().remove()" outside of the loop, but it didn't appreciate that either. I had assumed that would act on the plot after everything was created. – RedTideSide Dec 26 '22 at 17:13

0 Answers0