Matplotlib draw_bar_plot: |labels| ≠ |bars|

Question:
My code works well in Spyder and Jupyter, but when running it on Replit, it returns an error:

Traceback (most recent call last):
File “main.py”, line 73, in
draw_bar_plot(df_2)
File “main.py”, line 62, in draw_bar_plot
ax.bar(x + offset, measurement, width, label=attribute)
File “/home/runner/ExpensiveTraumatic
Businesses/venv/lib/python3.10/site-p
ackages/matplotlib/**init** .py”, line 1442, in inner
return func(ax, *map(sanitize_sequence, args), **kwargs)
File “/home/runner/Expensive Traumatic
ackages/matplotlib/axes/_axes.py”, line 2436, in bar
raise ValueError(f’number of labels ({len(patch_labels)}) ’
ValueError: number of labels (2) does not match number of bars (4).

Current behavior:

Desired behavior

Repl link:
https://replit.com/@Constantin2609/ExpensiveTraumaticBusinesses#main.py

Here below is my code:

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

# Use Pandas to import the data from "fcc-forum-pageviews.csv". Set the index to the date column.
import os

os.getcwd()

df_raw = pd.read_csv("fcc_forum_pageviews.csv", parse_dates=["date"], index_col="date")
df_raw.rename(columns={"value": "page_views"}, inplace=True)
df_1 = df_raw.applymap(lambda x: x.strip() if isinstance(x, str) else x)
# df_1.head()

# Clean the data by filtering out days when the page views were in the top 2.5%
# of the dataset or bottom 2.5% of the dataset.

cond_1 = df_1["page_views"] <= df_1["page_views"].quantile(0.975)
cond_2 = df_1["page_views"] >= df_1["page_views"].quantile(0.025)
df_2 = df_1.loc[cond_1 & cond_2]

# Create a draw_line_plot function that uses Matplotlib to draw a line chart similar to "examples/Figure_1.png". The title should
# be Daily freeCodeCamp Forum Page Views 5/2016-12/2019.
# The label on the x axis should be Date and the label on the y axis should be Page Views.


def draw_line_plot(x, y):
    plt.figure(figsize=(16, 5))
    plt.plot(x, y, color="red")
    plt.title("Daily freeCodeCamp Forum Page Views 5/2016-12/2019")
    plt.xlabel("Date")
    plt.ylabel("Page Views 5/2016-12/2019")


draw_line_plot(df_2.index, df_2["page_views"])

# Create a draw_bar_plot function that draws a bar chart similar to
# "examples/Figure_2.png".
# It should show average daily page views for each month grouped by year.
# The legend should show month labels and have a title of Months.
# On the chart, the label on the x axis should be Years and the label on the
# y axis should be Average Page Views.

df_2_2 = df_2.reset_index()
df_2_2["Year"] = df_2_2.date.dt.to_period("Y")
df_2_2["Month"] = df_2_2.date.dt.to_period("M")
# df_2_2

df_2_3 = df_2_2[["Year", "Month", "page_views"]]

df_3_gr = (
    df_2_3.groupby(["Year", "Month"], as_index=False)
    .mean()
    .rename(columns={"page_views": "average_page_views"})
)
# df_3_gr.head()

df_3_gr.Year.astype(int).dtypes

df_3_gr["month"] = df_3_gr["Month"].astype(str).str[-2:]
df_gr = df_3_gr[["Year", "month", "average_page_views"]]
# df_gr.head()

df_piv = df_gr.pivot(index="Year", columns="month")
# df_piv


def draw_bar_plot(df):
    df = df.reset_index()
    df["Year"] = df.date.dt.to_period("Y")
    df["Month"] = df.date.dt.to_period("M")
    df = df[["Year", "Month", "page_views"]]
    df_3_gr = (
        df.groupby(["Year", "Month"], as_index=False)
        .mean()
        .rename(columns={"page_views": "average_page_views"})
    )
    df_3_gr["month"] = df_3_gr["Month"].astype(str).str[-2:]
    df_gr = df_3_gr[["Year", "month", "average_page_views"]]
    df_piv = df_gr.pivot(index="Year", columns="month")

    x = np.arange(len(df_piv.index.astype(int)))  # the label locations
    width = 0.05  # the width of the bars
    multiplier = 0

    fig, ax = plt.subplots(layout="constrained")

    for attribute, measurement in df_piv.items():
        offset = width * multiplier
        rects = ax.bar(x + offset, measurement, width, label=attribute)
        multiplier += 1
    # Add text for labels, and custom x-axis tick labels, etc.
    ax.set_ylabel("Average Page Views")
    ax.set_xlabel("Year")
    ax.set_xticks(x + width + 0.22, df_piv.index)
    ax.legend(
        loc="upper left",
        title="Month",
        labels=[
            "Jan",
            "Feb",
            "Mar",
            "Apr",
            "May",
            "Jun",
            "Jul",
            "Aug",
            "Sep",
            "Oct",
            "Nov",
            "Dec",
        ],
    )

    plt.show()


draw_bar_plot(df_2)

ValueError: number of labels (2) does not match number of bars (4).

Acording to the error the number of labels (2) does not match the number of bars (4).
Try to use a single label for each group of bars.
For example you can create a month labels

x = np.arange(len(df_piv.index.astype(int)))  # the label locations
    width = .05  # the width of the bars
    month_labels = ['Jan', 'Feb', 'Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']

and change the ‘for’ to

for i, (attribute, measurement) in enumerate(df_piv.items()):
        offset = width * i
        rects = ax.bar(x + offset, measurement, width, label=month_labels[i])

Which then we change the text for labels too

# Add text for labels, and custom x-axis tick labels, etc.
    ax.set_ylabel('Average Page Views')
    ax.set_xlabel('Year')
    ax.set_xticks(x + width * 5)
    ax.set_xticklabels(df_piv.index.astype(int))
    ax.legend(loc='upper left', title='Month', labels=month_labels)

    plt.show()

Try to see if it works.

Hi, dear WindLother!

The error hasn’t appeared after I had made the changes with the ‘for’ loop and assigned the ‘month_labels’ variable, as you advised me. The chart of the first function (draw_line_plot) is shown in the output screen. But the ‘Run’ button never gets unpressed and shows being under process.

Yet I’m much happier with the things having got off the stalemate. I appreciate your help.

Run in Shell

pkill -1 Xvnc

Yeah. It has ceased the everlasting process… Still I’m not quite sure, if Replit.com liked my code.
Thanx for the hint

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.