0Pricing
Pandas & NumPy Academy · Lesson

Visualising User Journeys

Plot the funnel as a horizontal bar chart and the retention matrix as a heatmap to communicate findings to stakeholders.

Visualising User Journeys 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.

Why Visualise User Journeys?

Raw event tables and conversion rates as numbers are hard to communicate to non-technical stakeholders. Visual representations of user journeys — funnel charts, retention heatmaps, and Sankey diagrams — make patterns immediately apparent. The goal is not to replace the numbers but to present them in a form where insights are self-evident at a glance, reducing the cognitive load on the audience.

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

# Assume funnel_summary and retention_pct are already computed
print('Visualisation libraries loaded')

Horizontal Bar Chart for Funnel

A horizontal bar chart is the simplest and most widely understood funnel visualisation. Each bar represents a funnel step; bar length represents the user count. Sort steps from top to bottom in funnel order so the chart reads as a widening funnel. Use a single contrasting colour for all bars so attention stays on the values, not the colour variety.

FUNNEL_STEPS = ['homepage', 'product_page', 'add_to_cart', 'checkout', 'purchase']
users = [10000, 7200, 4100, 2300, 980]

fig, ax = plt.subplots(figsize=(9, 5))
bars = ax.barh(FUNNEL_STEPS[::-1], users[::-1], color='steelblue', height=0.6)
ax.set_xlabel('Unique Users')
ax.set_title('Conversion Funnel')
plt.tight_layout()
plt.show()

Annotating Conversion Rates on the Chart

Add conversion rate annotations at the right edge of each bar using ax.text(). Show both the absolute user count and the step-to-step conversion percentage so the chart communicates everything needed without a separate data table. Position the text slightly outside the bar end with a small horizontal offset so it does not overlap the bar fill colour.

conversions = [None, 72.0, 56.9, 56.1, 42.6]

for i, (u, c) in enumerate(zip(users[::-1], conversions[::-1])):
    label = f'{u:,} users'
    if c is not None:
        label += f'  ({c}% conv)'
    ax.text(u + 100, i, label, va='center', fontsize=9)

plt.tight_layout()
plt.show()

Retention Heatmap Revisited

The retention heatmap is the standard output of cohort analysis. Each row is a cohort, each column is a week offset, and each cell is coloured by retention percentage. Use the RdYlGn colormap (red = low, green = high) with explicit vmin=0, vmax=100 so the colour scale is consistent across presentations and does not rescale per heatmap.

import numpy as np

# Simulated retention data for illustration
data = [[100, 55, 42, 38, 35, 33],
        [100, 52, 40, 36, 33, 0],
        [100, 58, 45, 41, 0, 0],
        [100, 60, 48, 0, 0, 0]]
retention_pct = pd.DataFrame(data, columns=range(6),
                             index=['Wk1', 'Wk2', 'Wk3', 'Wk4'])

fig, ax = plt.subplots(figsize=(10, 4))
sns.heatmap(retention_pct, annot=True, fmt='.0f', cmap='RdYlGn',
            vmin=0, vmax=100, linewidths=0.5, ax=ax)
ax.set_title('Cohort Retention Heatmap')
plt.tight_layout()
plt.show()

Masking Incomplete Cohort Cells

Newer cohorts have not yet had time to complete all week offsets. Those cells should appear blank rather than as 0 % so readers do not mistake absent data for zero retention. Create a boolean mask where the cell value is 0 and the column index exceeds the number of weeks the cohort has existed, then pass it to sns.heatmap(mask=...).

mask = retention_pct == 0  # cells with no data yet

fig, ax = plt.subplots(figsize=(10, 4))
sns.heatmap(retention_pct, annot=True, fmt='.0f', cmap='RdYlGn',
            vmin=0, vmax=100, linewidths=0.5,
            mask=mask, ax=ax)
ax.set_title('Cohort Retention (incomplete cells masked)')
plt.tight_layout()
plt.show()

Plotting the Average Retention Curve

Visualise the average retention curve by plotting the column means of the retention matrix. This single line summarises the overall product retention profile. Add a shaded band for ±1 standard deviation to show cohort variability. A narrow band means cohorts behave similarly; a wide band suggests important cohort-level differences worth investigating.

avg = retention_pct.mean(axis=0)
std = retention_pct.std(axis=0)

fig, ax = plt.subplots(figsize=(8, 4))
ax.plot(avg.index, avg, marker='o', color='steelblue', linewidth=2)
ax.fill_between(avg.index, avg - std, avg + std, alpha=0.2, color='steelblue')
ax.set_xlabel('Week Number')
ax.set_ylabel('Avg Retention %')
ax.set_title('Average Cohort Retention Curve')
plt.tight_layout()
plt.show()

Segmented Funnel: Desktop vs. Mobile

Plotting funnels for different segments side by side reveals whether product problems are global or device-specific. Create a grouped bar chart with two bar groups per funnel step using ax.bar() with an x-offset. Alternatively, draw two separate funnel charts in a 1×2 subplot grid using plt.subplots(1, 2) for cleaner comparison.

steps = ['Homepage', 'Product', 'Cart', 'Checkout', 'Purchase']
desktop = [5000, 3800, 2300, 1500, 700]
mobile = [5000, 3400, 1800, 900, 280]

x = range(len(steps))
fig, ax = plt.subplots(figsize=(10, 5))
ax.bar([i - 0.2 for i in x], desktop, width=0.4, label='Desktop', color='steelblue')
ax.bar([i + 0.2 for i in x], mobile, width=0.4, label='Mobile', color='darkorange')
ax.set_xticks(list(x))
ax.set_xticklabels(steps)
ax.legend()
ax.set_title('Funnel by Device Type')
plt.tight_layout()
plt.show()

Event Frequency Distribution

Visualising the distribution of events per session shows whether sessions cluster around a small number of events (suggesting users achieve their goal quickly) or span a wide range (suggesting complex journeys or confusion). Plot with ax.hist() on the event_count column, using a log scale on the y-axis if the distribution is highly right-skewed.

import numpy as np

event_counts = pd.Series([3, 5, 2, 8, 1, 12, 3, 4, 6, 20, 2, 3, 1, 7, 5])

fig, ax = plt.subplots(figsize=(8, 4))
ax.hist(event_counts, bins=15, color='steelblue', edgecolor='white')
ax.set_xlabel('Events per Session')
ax.set_ylabel('Number of Sessions')
ax.set_title('Session Event Frequency Distribution')
plt.tight_layout()
plt.show()

Top Event Sequences

Show the most common two-event sequences (bigrams) in the clickstream to understand typical user paths. Group by session, sort by event_rank, and extract consecutive pairs using zip(events, events[1:]). Count pair frequencies with a Counter and plot the top 10 as a horizontal bar chart. This reveals which navigation paths dominate user behaviour.

from collections import Counter

events_per_session = [['homepage', 'product_page', 'add_to_cart'],
                       ['homepage', 'search', 'product_page'],
                       ['homepage', 'product_page', 'purchase']]

bigrams = Counter()
for session in events_per_session:
    for pair in zip(session, session[1:]):
        bigrams[pair] += 1

print(bigrams.most_common(5))

Session Duration Distribution

A histogram of session durations reveals whether users engage briefly (under 2 minutes), moderately, or deeply. Use a log-scale x-axis if a small number of very long sessions would compress the bulk of data into the leftmost bin. Overlay a vertical line at the median with ax.axvline() to anchor the audience's interpretation of 'typical' session length.

durations = pd.Series([1.2, 3.5, 0.5, 12.3, 2.1, 8.7, 1.8, 0.3, 45.1, 4.6])

fig, ax = plt.subplots(figsize=(8, 4))
ax.hist(durations, bins=20, color='steelblue', edgecolor='white')
ax.axvline(durations.median(), color='red', linestyle='--', label=f'Median: {durations.median():.1f} min')
ax.set_xlabel('Session Duration (min)')
ax.set_ylabel('Sessions')
ax.legend()
plt.tight_layout()
plt.show()

Saving the Dashboard Figure

Combine multiple visualisations into a single dashboard figure using a grid of subplots with plt.subplots(2, 2, figsize=(14, 10)). Assign the funnel bar chart, retention heatmap, average retention curve, and event distribution to each panel. Save to PNG for web delivery or to PDF for printable reports. A unified figure is easier to share than four separate files.

fig, axes = plt.subplots(2, 2, figsize=(14, 10))

# Panel 1: funnel
axes[0, 0].barh(FUNNEL_STEPS[::-1], users[::-1], color='steelblue')
axes[0, 0].set_title('Funnel')

# Panel 2: retention heatmap
sns.heatmap(retention_pct, ax=axes[0, 1], cmap='RdYlGn', annot=True, fmt='.0f', vmin=0, vmax=100)
axes[0, 1].set_title('Cohort Retention')

fig.suptitle('User Journey Dashboard', fontsize=16)
plt.tight_layout()
fig.savefig('user_journey_dashboard.png', dpi=150, bbox_inches='tight')
print('Dashboard saved')

Quick Check

Test your understanding of Data Analysis concepts from this lesson.

Lesson Recap

In this lesson you learned: creating annotated funnel bar charts and retention heatmaps, plotting average retention curves with variability bands, and combining multiple charts into a single dashboard figure saved to PNG. Next up we explore detecting and removing duplicate records in advanced data cleaning.

Frequently asked questions

Is the “Visualising User Journeys” lesson free?

Yes — the full text of “Visualising User Journeys” 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 “Visualising User Journeys”?

Plot the funnel as a horizontal bar chart and the retention matrix as a heatmap to communicate findings to stakeholders. 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 “Visualising User Journeys” 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.

All lessons in this course

  1. Sessionisation and Event Sequencing
  2. Funnel Analysis
  3. Cohort Retention Table
  4. Visualising User Journeys
← Back to Pandas & NumPy Academy