pythonmatplotlibbar-chartsubplot

Unexpected result with function to plot subplotting


I create the next function to plotting barplotd and I want to use this function to make subplots, but when I try it I don't get the result I expect:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

def plotsApilate(data,posColInit,posColEnd, tittleComplement, ax=None):
  data['total']=data.iloc[:,posColInit:posColEnd].sum(axis=1)
  data= data.sort_values(by='total', ascending=True).drop('total', axis=1)
  if ax is None:
      # Gráfico de barras apiladas horizontales
      fig, ax = plt.subplots(figsize=(8,9))

  data.set_index('variable')[['negative', 'neutral', 'positiv']].plot(kind='barh', stacked=True, ax=ax )


  # Show tikcs
  for container in ax.containers:
      ax.bar_label(container, label_type='center',fontsize=6)

  plt.title('Kind of Category' + ' ' + tittleComplement)
  plt.xlabel('Quantity')
  plt.ylabel('Variables')
  plt.legend(title='Legend:')
  plt.show()

# EXAMPLE
Categories= ['CAT1', 'CAT2', 'CAT3', 'CAT4', 'CAT5', 'CAT6']
negative1 = np.random.randint(0, 100, 6)
neutral1= np.random.randint(0, 100, 6)
positiv1= np.random.randint(0, 100, 6)
negative2 = np.random.randint(42, 100, 6)
neutral2= np.random.randint(42, 100, 6)
positiv2= np.random.randint(42, 100, 6)

# CreaTE dataframes
data1 = {'variable': Categories, 'negative': negative1, 'positiv': positiv1, 'neutral': neutral1}
df1 = pd.DataFrame(data1)

data2 = {'variable': Categories, 'negative': negative2, 'positiv': positiv2, 'neutral': neutral2}
df2 = pd.DataFrame(data2 )


# Create figure and subplots
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 6))

# Ploting 1st DF
plotsApilate(df1, 2,4,'XXX', ax1)

# Ploting 2nd DF
plotsApilate(df2, 2,4,'YYY', ax2)

# fix design
plt.tight_layout()

plt.show()

I have the next resut, what is the error in the code? I want one graph for each df.

enter image description here


Solution

  • The call to plt.show within the function interrupts your example when you have only plotted the first data set. So that is why you get the first figure with only the left-hand chart. The titles for the first data set are on the wrong subplot because you use plt.title, etc, which uses the active axes. If you have not explicitly set an active axes with plt.sca, this will be the most recently created axes.

    When you try to plot the second data set, the axes you want is on a figure that has been closed down. The plt functions therefore create a new figure, so all you get is the title, labels and an empty legend.

    So my solution is

    Keeping your example as-is and just changing the function:

    def plotsApilate(data,posColInit,posColEnd, tittleComplement, ax=None):
      data['total']=data.iloc[:,posColInit:posColEnd].sum(axis=1)
      data= data.sort_values(by='total', ascending=True).drop('total', axis=1)
      if ax is None:
          # Gráfico de barras apiladas horizontales
          fig, ax = plt.subplots(figsize=(8,9))
    
      data.set_index('variable')[['negative', 'neutral', 'positiv']].plot(kind='barh', stacked=True, ax=ax )
    
    
      # Show tikcs
      for container in ax.containers:
          ax.bar_label(container, label_type='center',fontsize=6)
    
      ax.set_title('Kind of Category' + ' ' + tittleComplement)
      ax.set_xlabel('Quantity')
      ax.set_ylabel('Variables')
      ax.legend(title='Legend:')
    

    enter image description here