Javier
Javier

Reputation: 513

How to plot multiple bar charts using a loop?

I have this df:

      Month   Sector      CWD
2592    1      COAST1     0.0
2593    2      COAST1     1.0
2594    3      COAST1     2.0
2595    4      COAST1     2.0
2596    5      COAST1     5.0
  ...           ...  ...
4363    8      COAST1     0.0
4364    9      COAST1     4.0
4365   10      COAST1     1.0
4366   11      COAST1     2.0
4367   12      COAST1     0.0
2592    1      COAST2     0.0
2593    2      COAST2     1.0
2594    3      COAST2     2.0
2595    4      COAST2     2.0
2596    5      COAST2     5.0
  ...           ...  ...
4363    8      COAST2     0.0
4364    9      COAST2     4.0
4365   10      COAST2     1.0
4366   11      COAST2     2.0
4367   12      COAST2     0.0
2592    1      JUNGL1     3.0
2593    2      JUNGL1     1.0
2594    3      JUNGL1     0.0
2595    4      JUNGL1     5.0
2596    5      JUNGL1     5.0
  ...           ...  ...
4363    8      JUNGL1     0.0
4364    9      JUNGL1     0.0
4365   10      JUNGL1     0.0
4366   11      JUNGL1     0.0
4367   12      JUNGL1     0.0
  ...           ...  ...

I want to plot grouped bar charts by df['Sector'] with x=df['Month'] and y=df['CWD']. Each df['Sector'] must have a bar (with different color). I want a graphic like this: enter image description here

But there are more than 30 kind of Sectors. So i must plot 30 bars for each df['Month'] value. I tried this code:

fig = plt.figure('Graphic', figsize=(20,15), dpi=300)

ax1 = fig.add_axes([0.2, 0.25, 0.80, 0.60])

width=0.25
i=0
for i in df:
    bar1 = plt.bar(df['Month']+width*i, df['CWD'], width, color = 'r')

But i get this error: TypeError: can't multiply sequence by non-int of type 'float'

PD: I need to iterate the color too (with random colors).

Would you mind to help me? Thanks in advance.

Upvotes: 1

Views: 428

Answers (1)

Laurent
Laurent

Reputation: 13478

With the following toy dataframe:

import pandas as pd

df = pd.DataFrame({"Month": [1, 2, 3, 4, 5, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 8, 9, 10, 11, 12, 7, 7, 7, 6, 6, 6], "Sector": ["COAST1", "COAST1", "COAST1", "COAST1", "COAST1", "COAST1", "COAST1", "COAST1", "COAST1", "COAST1", "COAST2", "COAST2", "COAST2", "COAST2", "COAST2", "COAST2", "COAST2", "COAST2", "COAST2", "COAST2", "JUNGL1", "JUNGL1", "JUNGL1", "JUNGL1", "JUNGL1", "JUNGL1", "JUNGL1", "JUNGL1", "JUNGL1", "JUNGL1", "COAST1", "JUNGL1", "COAST2", "JUNGL1", "JUNGL1", "COAST1"], "CWD": [9.0, 1.0, 2.0, 8.0, 5.0, 8.0, 4.0, 6.0, 2.0, 3.0, 5.0, 1.0, 2.0, 5.0, 4.0, 8.0, 1.0, 1.0, 2.0, 9.0, 3.0, 8.0, 6.0, 7.0, 5.0, 1.0, 6.0, 4.0, 9.0, 2.0, 3.0, 4.0, 5.0, 8.0, 7.0, 2.0]})

Here is one way to do it:

import matplotlib
import numpy as np
from matplotlib import pyplot as plt

# Setup
df = df.sort_values(by=["Month", "Sector"]).reset_index(drop=True)
fig, ax = plt.subplots(nrows=1, ncols=1, figsize=(10, 3))
width = 1

# Define colors for each unique sector
cm = plt.get_cmap("gist_rainbow")
mapping = {sector: cm(i * 100) for i, sector in enumerate(df["Sector"].unique())}
df["Colors"] = df["Sector"].apply(lambda x: mapping[x])
df["Colors"] = df["Colors"].apply(
    lambda x: matplotlib.colors.rgb2hex(x, keep_alpha=True)
)
# Plot bars
for i in df["Month"].unique():
    ax.bar(
        x=[
            i * 10 + x * width * 2
            for x in range(1, df.loc[df["Month"] == i].shape[0] + 1)
        ],
        height=df.loc[df["Month"] == i, "CWD"],
        width=width,
        color=df.loc[df["Month"] == i, "Colors"].tolist(),
    )

# Position ticks and labels on x-axis
ax.set_xticks(
    ticks=[
        np.mean(
            [
                i * 10 + x * width * 2
                for x in range(1, df.loc[df["Month"] == i].shape[0] + 1)
            ]
        )
        for i in df["Month"].unique()
    ]
)
ax.set_xticklabels(df["Month"].unique(), fontsize=10)
# In a Jupyter cell
fig

Output:

enter image description here

Upvotes: 1

Related Questions