Monthly Trend Visualisation
Plot monthly revenue as a line chart, overlay a 3-month moving average, and annotate peak and trough months.
Monthly Trend Visualisation is a free Pandas & NumPy Academy lesson on CoddyKit — lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Pandas & NumPy Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
Computing Monthly Revenue Totals
Before plotting, aggregate the sales DataFrame to monthly totals. Group by the year_month Period column and sum revenue. Convert the PeriodIndex to a DatetimeIndex with .to_timestamp() so Matplotlib's date formatter renders tick labels correctly. Sorting by index ensures the line chart flows left to right chronologically.
import pandas as pd
import matplotlib.pyplot as plt
df = pd.read_parquet('sales_features.parquet')
monthly = df.groupby('year_month')['revenue'].sum().sort_index()
monthly.index = monthly.index.to_timestamp()
print(monthly.head())Plotting the Monthly Revenue Line Chart
Create a Figure and Axes with plt.subplots(figsize=(12, 5)) and call ax.plot() to draw the monthly revenue trend. Use marker='o' to place a dot at each month so individual data points are visible even when the line is smooth. Set the colour and line width to make the primary trend stand out from any overlays you add later.
fig, ax = plt.subplots(figsize=(12, 5))
ax.plot(monthly.index, monthly.values,
color='steelblue', linewidth=2, marker='o', markersize=5,
label='Monthly Revenue')
ax.set_title('Monthly Revenue Trend')
ax.set_xlabel('Month')
ax.set_ylabel('Revenue (USD)')
plt.tight_layout()
plt.show()Overlaying a 3-Month Moving Average
A raw monthly revenue line can appear jagged due to seasonal noise. Overlay a 3-month rolling average computed with monthly.rolling(3).mean() to show the underlying trend more clearly. Plot it as a dashed line in a contrasting colour so it stands out from the raw series without obscuring it.
rolling_avg = monthly.rolling(3).mean()
ax.plot(rolling_avg.index, rolling_avg.values,
color='darkorange', linewidth=2, linestyle='--',
label='3-Month Moving Avg')
ax.legend()
plt.show()Annotating the Peak Month
Use ax.annotate() to mark the month with the highest revenue. Find the peak with monthly.idxmax() and its value with monthly.max(). The annotation arrow points from a text label to the peak data point, making the insight immediately visible to any reader of the chart, including those who receive it as a PNG or PDF.
peak_date = monthly.idxmax()
peak_val = monthly.max()
ax.annotate(f'Peak: ${peak_val:,.0f}',
xy=(peak_date, peak_val),
xytext=(peak_date, peak_val * 1.1),
arrowprops=dict(arrowstyle='->', color='red'),
color='red', fontsize=10)
plt.show()Annotating the Trough Month
Similarly, mark the month with the lowest revenue using monthly.idxmin() to flag potential seasonality or disruptions. Annotations on both the peak and trough provide a complete story: they let stakeholders see not only the best month but also how far revenue can dip, which informs cash-flow planning.
trough_date = monthly.idxmin()
trough_val = monthly.min()
ax.annotate(f'Trough: ${trough_val:,.0f}',
xy=(trough_date, trough_val),
xytext=(trough_date, trough_val * 0.85),
arrowprops=dict(arrowstyle='->', color='navy'),
color='navy', fontsize=10)
plt.show()Formatting Date Tick Labels
Matplotlib's default date tick labels often overlap or use an unreadable format. Import mdates from matplotlib and set a MonthLocator and DateFormatter to control tick frequency and label format. Rotating tick labels by 45 degrees prevents overlap on a 12-month axis.
import matplotlib.dates as mdates
ax.xaxis.set_major_locator(mdates.MonthLocator())
ax.xaxis.set_major_formatter(mdates.DateFormatter('%b %Y'))
plt.xticks(rotation=45, ha='right')
plt.tight_layout()
plt.show()Adding a Shaded Region for Q4
Highlight the Q4 period (October–December) with a shaded background using ax.axvspan(). This makes seasonal patterns immediately visible: if the peak consistently falls within the shaded zone, Q4 is a key selling period worth targeting with promotions. The alpha parameter controls the shading transparency.
import datetime
q4_start = datetime.datetime(2023, 10, 1)
q4_end = datetime.datetime(2023, 12, 31)
ax.axvspan(q4_start, q4_end, alpha=0.15, color='gold', label='Q4')
ax.legend()
plt.show()Plotting Revenue by Category Over Time
Create a multi-line chart where each line represents a product category. Pivot the monthly-by-category DataFrame so columns are categories and the index is time, then iterate over columns and call ax.plot() for each. Matplotlib automatically assigns a different colour to each line when called repeatedly on the same Axes.
monthly_cat = df.groupby(['year_month', 'category'])['revenue'].sum().unstack('category')
monthly_cat.index = monthly_cat.index.to_timestamp()
fig, ax = plt.subplots(figsize=(12, 6))
for col in monthly_cat.columns:
ax.plot(monthly_cat.index, monthly_cat[col], label=col, linewidth=1.5)
ax.legend(loc='upper left', fontsize=8)
ax.set_title('Monthly Revenue by Category')
plt.tight_layout()
plt.show()Stacked Bar Chart for Monthly Revenue
A stacked bar chart shows the total monthly revenue while also revealing each category's contribution to the stack. Use monthly_cat.plot(kind='bar', stacked=True, ax=ax) directly on the pivoted DataFrame. Stacked bars are best when you have fewer than six categories, otherwise the colours become hard to distinguish.
fig, ax = plt.subplots(figsize=(12, 5))
monthly_cat.plot(kind='bar', stacked=True, ax=ax, colormap='tab10')
ax.set_title('Monthly Revenue by Category (Stacked)')
ax.set_xlabel('Month')
ax.set_ylabel('Revenue')
ax.legend(loc='upper left', fontsize=8)
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()Month-over-Month Growth Rate
Plot the month-over-month percentage growth rate alongside the revenue to give context: a visually small bar in January might represent a 20 % growth jump from the prior month. Compute growth with monthly.pct_change() * 100 and plot it on a secondary y-axis using ax.twinx() to share the same x-axis without conflating units.
growth = monthly.pct_change() * 100
fig, ax1 = plt.subplots(figsize=(12, 5))
ax2 = ax1.twinx()
ax1.bar(monthly.index, monthly.values, width=20, color='steelblue', alpha=0.6, label='Revenue')
ax2.plot(growth.index, growth.values, color='red', marker='o', label='MoM Growth %')
ax1.set_ylabel('Revenue')
ax2.set_ylabel('MoM Growth %')
plt.title('Revenue and Month-over-Month Growth')
plt.tight_layout()
plt.show()Saving the Figure for Reports
Use fig.savefig('monthly_trend.png', dpi=150, bbox_inches='tight') to produce a high-resolution PNG suitable for slide decks or web dashboards. The bbox_inches='tight' argument trims excess white space, and dpi=150 gives a sharp image without an excessively large file. Save to PDF as well for print-quality reports.
fig.savefig('monthly_trend.png', dpi=150, bbox_inches='tight')
fig.savefig('monthly_trend.pdf', bbox_inches='tight')
print('Figure saved as PNG and PDF')Quick Check
Test your understanding of Data Analysis concepts from this lesson.
Lesson Recap
In this lesson you learned: computing monthly revenue totals and plotting them as a line chart, overlaying a rolling average and annotating peak and trough months, and saving publication-quality figures to PNG and PDF. Next up we explore sessionisation and event sequencing in user behaviour data.
Frequently asked questions
Is the “Monthly Trend Visualisation” lesson free?
Yes — the full text of “Monthly Trend Visualisation” is free to read here on the web, and the Pandas & NumPy Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Pandas & NumPy Academy course, upgrade to CoddyKit PRO.
What will I learn in “Monthly Trend Visualisation”?
Plot monthly revenue as a line chart, overlay a 3-month moving average, and annotate peak and trough months. You practise Pandas & NumPy Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Pandas & NumPy Academy?
No prior experience is required. Pandas & NumPy Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Monthly Trend Visualisation” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Pandas & NumPy Academy lesson?
Yes. Every Pandas & NumPy Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.