Mathew K Analytics

Lesson 59 · Social Media Content Analytics

Best Practices for Visualizing Engagement Data

In this lesson, we will learn how to visualize and analyze engagement metrics from real-world social media datasets. Understanding engagement is important…

⬇ Download notebookOpen in Colab ↗

📓 Full notebook

Download .ipynb

Best Practices for Visualizing Engagement Data#

  • In this lesson, we will learn how to visualize and analyze engagement metrics from real-world social media datasets.
  • Understanding engagement is important for content creators and businesses to improve content and connect with the audience.
  • You will learn to extract actionable insights for content strategy using best practices in data visualization.
  • We will cover engagement rate, trends, benchmarking, error detection, and create practical, clear social media reports.
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
warnings.filterwarnings('ignore')

Core Social Media Analytics Concepts#

  • Social media datasets often represent content items like videos or posts, each with engagement metrics.
  • Key metrics include: views, likes, comments, shares, click-through rate (CTR), watch time, and engagement rate.
  • Engagement rate is usually (likes + comments + shares) divided by views or followers, showing relative interaction.
  • Beginners may confuse total counts for performance without adjusting for audience size.
  • Ratios like CTR and engagement rate help standardize comparisons across content or creators.
  • Consistent metric definitions and grouping logic are critical for accurate analysis.
# Load Social Media Content Dataset for Engagement Examples
np.random.seed(42)
n_posts = 500
views = np.random.randint(100, 100000, n_posts)
df = pd.DataFrame({
    'post_id': range(1, n_posts+1),
    'platform': np.random.choice(['YouTube','Instagram','TikTok'], n_posts),
    'date': pd.date_range('2023-01-01', periods=n_posts, freq='6h'),
    'views': views,
    'likes': (views * np.random.uniform(0.02, 0.15, n_posts)).astype(int),
    'comments': (views * np.random.uniform(0.001, 0.05, n_posts)).astype(int),
    'shares': (views * np.random.uniform(0.001, 0.03, n_posts)).astype(int)
})
print(df.head(3))
   post_id   platform                date  views  likes  comments  shares
0        1  Instagram 2023-01-01 00:00:00  15895   2356       116     253
1        2  Instagram 2023-01-01 06:00:00    960     94        16      26
2        3  Instagram 2023-01-01 12:00:00  76920   3910      2879    1185

Example 1: Calculate Engagement Rate for Each Post#

  • Engagement rate is a standard way to compare how well content performs relative to its reach.
  • For posts, a basic engagement rate formula is:
  • (likes + comments + shares) / views * 100
  • This shows the percentage of viewers who interacted with a post in any way.
df['engagement_rate'] = ((df['likes'] + df['comments'] + df['shares']) / df['views']) * 100
df['engagement_rate'] = df['engagement_rate'].round(2)
print(df[['post_id', 'platform', 'views', 'likes', 'comments', 'shares', 'engagement_rate']].head(5))
   post_id   platform  views  likes  comments  shares  engagement_rate
0        1  Instagram  15895   2356       116     253            17.14
1        2  Instagram    960     94        16      26            14.17
2        3  Instagram  76920   3910      2879    1185            10.37
3        4    YouTube  54986   1827       488    1637             7.19
4        5  Instagram   6365    253       261     163            10.64

Example 2: Visualize Engagement Rates by Platform#

  • A common mistake is to compare engagement rates across platforms using absolute counts.
  • Visualization helps highlight differences in audience behavior between YouTube, Instagram, and TikTok.
plt.figure(figsize=(8,5))
sns.boxplot(x='platform', y='engagement_rate', data=df, palette='Set2')
plt.title('Engagement Rate Distribution by Platform')
plt.ylabel('Engagement Rate (%)')
plt.xlabel('Platform')
plt.show()
No description has been provided for this image

Example 3: Identify Top-Performing Posts#

  • To find what works best, we can look at the top 10 posts by engagement rate.
  • Visualizing these can reveal what type of content drives high interaction.
top_posts = df.sort_values('engagement_rate', ascending=False).head(10)
plt.figure(figsize=(10,6))
sns.barplot(x='engagement_rate', y='post_id', data=top_posts, hue='platform', dodge=False)
plt.title('Top 10 Posts by Engagement Rate')
plt.ylabel('Post ID')
plt.xlabel('Engagement Rate (%)')
plt.legend(title='Platform')
plt.show()
No description has been provided for this image

Example 4: Engagement Trends Over Time (Beginner)#

  • Tracking engagement metrics across time reveals trends, cycles, or spikes.
  • Line plots quickly show changes and help spot patterns like growth or sudden viral events.
daily = df.set_index('date').resample('D').agg({'views':'sum','likes':'sum','comments':'sum','shares':'sum'})
daily['engagement_rate'] = ((daily['likes'] + daily['comments'] + daily['shares']) / daily['views'] * 100).round(2)
plt.figure(figsize=(12,5))
plt.plot(daily.index, daily['engagement_rate'], marker='o')
plt.title('Engagement Rate Over Time')
plt.ylabel('Engagement Rate (%)')
plt.xlabel('Date')
plt.grid(True, alpha=0.2)
plt.show()
No description has been provided for this image

Example 5: Audience Behavior by Post Time#

  • The time a post is published can impact engagement.
  • Let us see if certain hours of day have higher engagement rates.
df['hour'] = df['date'].dt.hour
hourly = df.groupby('hour')['engagement_rate'].mean()
plt.figure(figsize=(10,5))
sns.lineplot(x=hourly.index, y=hourly.values, marker='o')
plt.title('Average Engagement Rate by Posting Hour')
plt.xlabel('Hour of Day')
plt.ylabel('Avg Engagement Rate (%)')
plt.xticks(np.arange(0,24,2))
plt.show()
No description has been provided for this image

Example 6: Heatmap of Engagement by Platform and Hour (Intermediate)#

  • Heatmaps help visualize patterns along two categorical axes, like platform and posting hour.
  • This can reveal platform-specific timing strategies.
pivot = df.pivot_table(values='engagement_rate', index='platform', columns='hour', aggfunc='mean')
plt.figure(figsize=(12,5))
sns.heatmap(pivot, annot=True, fmt='.1f', cmap='coolwarm', cbar_kws={'label': 'Engagement Rate (%)'})
plt.title('Engagement Rate Heatmap by Platform and Posting Hour')
plt.xlabel('Hour of Day')
plt.ylabel('Platform')
plt.show()
No description has been provided for this image

Example 7: Compare Engagement Metrics with PairPlot (Intermediate)#

  • Sometimes, exploring relationships among metrics helps explain why some posts succeed.
  • Pair plots can reveal connections between likes, comments, shares, and engagement rate.
sns.pairplot(df, vars=['views','likes','comments','shares','engagement_rate'], hue='platform', diag_kind='kde')
plt.suptitle('Pairwise Relationships Among Engagement Metrics', y=1.02)
plt.show()
No description has been provided for this image

Example 8: Platform Benchmarking (Intermediate)#

  • Benchmarking compares your posts to a platform's typical performance.
  • Let us compute and visualize the median engagement rate by platform for a fairer comparison.
bench = df.groupby('platform')['engagement_rate'].median().reset_index()
plt.figure(figsize=(7,4))
sns.barplot(x='platform', y='engagement_rate', data=bench, palette='pastel')
plt.title('Median Engagement Rate Benchmark by Platform')
plt.ylabel('Median Engagement Rate (%)')
plt.xlabel('Platform')
plt.show()
No description has been provided for this image

Example 9: Error - Missing Engagement Values#

  • Real datasets sometimes have missing likes, comments, or shares.
  • Let us simulate this problem and show how to handle it in a visual context.
df_missing = df.copy()
rand_idx = np.random.choice(df_missing.index, size=20, replace=False)
df_missing.loc[rand_idx, 'likes'] = np.nan
df_missing['engagement_rate'] = ((df_missing['likes'].fillna(0) + df_missing['comments'] + df_missing['shares']) / df_missing['views']) * 100
plt.figure(figsize=(8,5))
sns.histplot(df['engagement_rate'], color='blue', label='Original', kde=True, stat='density')
sns.histplot(df_missing['engagement_rate'], color='red', label='Missing likes', kde=True, stat='density', alpha=0.5)
plt.legend()
plt.title('Effect of Missing Values on Engagement Rate Distribution')
plt.xlabel('Engagement Rate (%)')
plt.show()
No description has been provided for this image

Example 10: Error - Incorrect Aggregation of Engagement Data#

  • Beginners sometimes sum likes, comments, and shares across all posts and divide by total views.
  • This can mislead if platforms or time periods behave differently.
  • Let us compare the wrong method to the recommended one.
# Incorrect: aggregate then calculate
incorrect = ((df['likes'].sum() + df['comments'].sum() + df['shares'].sum()) / df['views'].sum()) * 100
# Recommended: average post engagement rate
correct = df['engagement_rate'].mean()
print(f"Incorrect total-based engagement rate: {incorrect:.2f}%")
print(f"Correct average post engagement rate:   {correct:.2f}%")
Incorrect total-based engagement rate: 12.77%
Correct average post engagement rate:   12.61%

Example 11: Error - Misinterpreting CTR or Engagement Rate Ratios#

  • CTR and engagement rates should be compared only among similar content or periods.
  • Mixing unrelated categories or inconsistent definitions can produce misleading results.
# Suppose we mix platforms: TikTok and YouTube have very different engagement patterns.
df_grouped = df.groupby('platform')['engagement_rate'].mean()
plt.figure(figsize=(7,4))
df_grouped.plot(kind='bar', color=['red','blue','green'])
plt.title('Mean Engagement Rate (Be Cautious Mixing Platforms!)')
plt.ylabel('Engagement Rate (%)')
plt.xlabel('Platform')
plt.show()
No description has been provided for this image

Example 12: Error - Incorrect Grouping by Content Categories#

  • Grouping by the wrong content attribute can mix up insights.
  • Let us see what happens if we group by post ID instead of platform, and then correct it.
# Wrong: aggregates each post (no aggregation)
by_post = df.groupby('post_id')['engagement_rate'].mean()
print('Median engagement rate per post:', by_post.median())
# Correct: group by platform
by_platform = df.groupby('platform')['engagement_rate'].median()
print('Median engagement rate per platform:')
print(by_platform)
Median engagement rate per post: 12.695
Median engagement rate per platform:
platform
Instagram    12.79
TikTok       12.90
YouTube      12.01
Name: engagement_rate, dtype: float64

Best Practices: Visualization Patterns for Social Media Engagement#

  • Use ratio-based metrics (engagement rate, CTR) to compare fairly across posts, platforms, and creators.
  • Always handle missing or zero values explicitly in calculations and plots.
  • Benchmark performance: compare results against platform medians or quartiles, not just absolute numbers.
  • Segment data by relevant categories like platform, time, or content type for clearer insights.
  • Use clear axis labels, legends, and chart titles to communicate findings.
  • Avoid visual clutter. Show reference lines or highlights for goals or benchmarks.
  • Visualize trends over time, optimal posting times, and outlier performances.

Example 13: Growth Trend Analysis (Advanced)#

  • To understand long-term content success, analyze growth in engagement over weeks or months.
  • Visualize rolling averages to smooth day-to-day noise and reveal real trends.
daily['rolling_engagement'] = daily['engagement_rate'].rolling(14, min_periods=1).mean()
plt.figure(figsize=(12,5))
plt.plot(daily.index, daily['engagement_rate'], alpha=0.4, label='Daily Engagement Rate')
plt.plot(daily.index, daily['rolling_engagement'], color='red', label='14-day Rolling Avg')
plt.title('Long-Term Engagement Trend (14-day Rolling Average)')
plt.xlabel('Date')
plt.ylabel('Engagement Rate (%)')
plt.legend()
plt.show()
No description has been provided for this image

Example 14: Content Optimization - Detect Viral Posts (Advanced)#

  • Posts far above the engagement benchmark are candidates for deeper analysis.
  • Let us flag and review such viral posts.
benchmark = df['engagement_rate'].median()
viral = df[df['engagement_rate'] > benchmark * 2]
print(f"Engagement median: {benchmark:.2f}%, Viral threshold: {benchmark*2:.2f}%")
print(f"Found {len(viral)} viral posts out of {len(df)}.")
print(viral[['post_id','platform','engagement_rate']].head())
Engagement median: 12.70%, Viral threshold: 25.39%
Found 0 viral posts out of 500.
Empty DataFrame
Columns: [post_id, platform, engagement_rate]
Index: []

Example 15: Consistent Visualization for Content Strategy#

  • Always use the same metric definitions and chart types across reports.
  • This allows teams and stakeholders to compare results over time and make informed decisions.
# Here is a reusable function for visualizing engagement rate across categories
def plot_engagement_rate_by_category(df, category):
    means = df.groupby(category)['engagement_rate'].mean()
    plt.figure(figsize=(7,4))
    sns.barplot(x=means.index, y=means.values, palette='muted')
    plt.title(f'Average Engagement Rate by {category.capitalize()}')
    plt.ylabel('Avg Engagement Rate (%)')
    plt.xlabel(category.capitalize())
    plt.show()

plot_engagement_rate_by_category(df, 'platform')
No description has been provided for this image

Example 16: End-to-End Strategy Recommendation (Mini Project)#

  • Scenario: You are consulting for a brand wanting to boost Instagram engagement.
  • Use all the steps above to analyze where, when, and how to post for maximum effect.
insta = df[df['platform']=='Instagram']
best_hour = insta.groupby('hour')['engagement_rate'].mean().idxmax()
best_posts = insta.sort_values('engagement_rate', ascending=False).head(5)
print(f"Best posting hour on Instagram: {best_hour}:00")
print("Top 5 engaging Instagram posts:")
print(best_posts[['post_id','date','views','likes','engagement_rate']])
Best posting hour on Instagram: 12:00
Top 5 engaging Instagram posts:
     post_id                date  views  likes  engagement_rate
351      352 2023-03-29 18:00:00  74643  10653            21.78
10        11 2023-01-03 12:00:00  16123   2202            21.21
56        57 2023-01-15 00:00:00  36020   5239            20.09
182      183 2023-02-15 12:00:00  61473   8909            20.03
276      277 2023-03-11 00:00:00  96701  13427            19.93

YouTube Call-to-Action Example#

  • For more tutorials, subscribe to the data science YouTube channel and leave a comment with your most valuable visualization insight!

Practice: Build Your Own Social Media Engagement Dashboard#

  • Try combining line charts, barplots, and heatmaps with customized colors and labels.
  • Summarize your findings with clear recommendations for content strategy.
  • Share your best practice visualizations with a study group or in a classroom demo.
  • Thank you for learning! For more, visit our YouTube series.

Found this useful?

All lessons, notebooks and datasets here are free. If they helped you, a coffee keeps new lessons coming.