Curso matplotlib - Gráfico de barras verticais (agrupado)
Para gerar um gráfico de barras agrupado, é necessário gerar uma série de elementos de gráficos de barra com um mesmo valor de x (arbitrário). Mas os valores em x devem estar espaçados de acordo com a largura da barra.
Para exemplificar este caso, seguimos utilizando um conjunto de dados de preço de frutas, mas agora temos o preço de cada uma das frutas em 4 lojas diferentes:
frutas = ['Banana Caturra', 'Laranja Pêra', 'Limão Tahiti', 'Maçã Gala', 'Mamão Formosa']
loja_1 = [1.77, 2.49, 2.29, 3.98, 2.98]
loja_2 = [0.99, 3.15, 4.71, 5.19, 4.49]
loja_3 = [3.68, 2.97, 2.58, 4.77, 6.25]
loja_4 = [2.49, 2.99, 2.79, 3.96, 4.99]
Para plotar o gráfico de forma mais simples, vamos criar um numpy array com valores igualmente espaçados (para facilitar), pois é mais simples manipular as posições das barras. Como no exemplo temos 5 produtos, vou criar um array com 5 elementos. Mas antes de criar este array, é preciso importar o numpy:
import numpy as np
Agora criamos o array para manipular o eixo x:
x = np.arange(5)
x
array([0, 1, 2, 3, 4])
Também é importante criar um variável para especificar a largura da barra (neste caso, todas as barras terão a mesma largura):
width_bar = 0.3
Inicialmente, vamos plotar os dados da loja 1 (que corresponde aos dados que estamos utilizando até o momento):
plt.figure(figsize=(8,6))
plt.bar(x, loja_1, label='Loja 1', width=width_bar)
plt.legend()
plt.show()
Figura 1 - Gráfico de barras verticais agrupado.

Agora vamos adicionar um novo elemento de plt.bar() para a loja 2:
plt.figure(figsize=(8,6))
plt.bar(x, loja_1, label='Loja 1', width=width_bar)
plt.bar(x, loja_2, label='Loja 2', width=width_bar)
plt.legend()
plt.show()
Figura 2 - Gráfico de barras verticais agrupado.

Observe que as barras foram sobrepostas, sendo que os dados da loja 2 estão por cima dos dados da loja 1. Isto aconteceu pois os valores de x são iguais para os dois conjuntos de dados.
Para deixar as barras lado a lado, podemos reduzir a posição (em x) de um do conjunto de dados em exatamente a largura das barras, ou seja:
x - width_bar
array([-0.3, 0.7, 1.7, 2.7, 3.7])
Dessa forma:
plt.figure(figsize=(8,6))
plt.bar(x, loja_1, label='Loja 1', width=width_bar)
plt.bar(x-width_bar, loja_2, label='Loja 2', width=width_bar)
plt.legend()
plt.show()
Figura 3 - Gráfico de barras verticais agrupado.

Observe que o tick acabou ficando no meio da barra da loja 1, e não no centro de cada grupo. Para resolver isto, no caso de termos apenas 2 elementos de gráfico de barras, passamos o parâmetro align='edge' para ambos os elementos:
plt.figure(figsize=(8,6))
plt.bar(x, loja_1, label='Loja 1', width=width_bar, align='edge')
plt.bar(x-width_bar, loja_2, label='Loja 2', width=width_bar, align='edge')
plt.legend()
plt.show()
Figura 4 - Gráfico de barras verticais agrupado.

Seguindo a mesma lógica, podemos adicionar os dados da loja 3, somando ao array x a largura das barras:
plt.figure(figsize=(8,6))
plt.bar(x, loja_1, label='Loja 1', width=width_bar)
plt.bar(x-width_bar, loja_2, label='Loja 2', width=width_bar)
plt.bar(x+width_bar, loja_3, label='Loja 3', width=width_bar)
plt.legend()
plt.show()
Figura 5 - Gráfico de barras verticais agrupado.

E para adicionar a quarta loja, seguimos a mesma lógica, utilizando uma maior distância para as barras mais externas:
plt.figure(figsize=(8,6))
plt.bar(x-2*width_bar, loja_1, label='Loja 1', width=width_bar, align='edge')
plt.bar(x-width_bar, loja_2, label='Loja 2', width=width_bar, align='edge')
plt.bar(x+width_bar, loja_3, label='Loja 3', width=-width_bar, align='edge')
plt.bar(x+2*width_bar, loja_4, label='Loja 4', width=-width_bar, align='edge')
plt.legend()
plt.show()
Figura 6 - Gráfico de barras verticais agrupado.

Mas observe que as barras de cada produto se sobrepuseram, o que aconteceu pois a largura da barra esta grande em relação aos valores de x. Poderíamos contornar isto aumentando os valores no array x (e mais espaçados) ou reduzir a largura da barra.
Ao reduzir a largura da barra para 0.1 por exemplo:
width_bar = 0.1
plt.figure(figsize=(8,6))
plt.bar(x-2*width_bar, loja_1, label='Loja 1', width=width_bar, align='edge')
plt.bar(x-width_bar, loja_2, label='Loja 2', width=width_bar, align='edge')
plt.bar(x+width_bar, loja_3, label='Loja 3', width=-width_bar, align='edge')
plt.bar(x+2*width_bar, loja_4, label='Loja 4', width=-width_bar, align='edge')
plt.legend()
plt.show()
Figura 7 - Gráfico de barras verticais agrupado.

Mas se aumentar o tamanho e espaçamento de x:
x = np.arange(0,10,2)
x
array([0, 2, 4, 6, 8])
E aumentar o tamanho da barra par 0.3, obtemos este gráfico:
width_bar = 0.3
plt.figure(figsize=(8,6))
plt.bar(x-2*width_bar, loja_1, label='Loja 1', width=width_bar, align='edge')
plt.bar(x-width_bar, loja_2, label='Loja 2', width=width_bar, align='edge')
plt.bar(x+width_bar, loja_3, label='Loja 3', width=-width_bar, align='edge')
plt.bar(x+2*width_bar, loja_4, label='Loja 4', width=-width_bar, align='edge')
plt.legend()
plt.show()
Figura 8 - Gráfico de barras verticais agrupado.

É possível substituir os números do eixo x pelo nome dos produtos que estão armazenados na variável frutas, o que fazemos utilizando o plt.xticks(). Neste caso, passamos como primeiro parâmetro os valores originais do eixo x (que é a variável x neste caso), e passamos como segundo parâmetro uma sequência com os valores que irão substituir os valores de x.
plt.figure(figsize=(8,6))
plt.bar(x-2*width_bar, loja_1, label='Loja 1', width=width_bar, align='edge')
plt.bar(x-width_bar, loja_2, label='Loja 2', width=width_bar, align='edge')
plt.bar(x+width_bar, loja_3, label='Loja 3', width=-width_bar, align='edge')
plt.bar(x+2*width_bar, loja_4, label='Loja 4', width=-width_bar, align='edge')
plt.legend()
plt.xticks(x, frutas)
plt.show()
Figura 9 - Gráfico de barras verticais agrupado.
