{% extends "base.html" %}
{% block title %}Blog Statistics - {{ site_title }}{% endblock %}
{% block meta_tags %}
{% from '_listing_meta_tags.html' import listing_meta_tags with context %}
{{ listing_meta_tags("Blog Statistics - " ~ site_title) }}
{% endblock %}
{% block extra_head %}
{% endblock %}
{% block content %}
Blog Statistics
{% set total_posts = stats.posts_per_hour | sum %}
Statistics for {{ total_posts }} post{{ '' if total_posts == 1 else 's' }}.
{# ------------------------------------------------------------------ #}
{# Tags, categories and links overview #}
{# ------------------------------------------------------------------ #}
Content Overview¶
- Unique external links
- {{ stats.unique_external_link_count }}
{# ------------------------------------------------------------------ #}
{# Helper macro: render a histogram as a CSS bar chart #}
{# ------------------------------------------------------------------ #}
{% macro histogram(title, labels, counts, label_step=1) %}
{% set max_count = counts | max if counts | max > 0 else 1 %}
{% set section_id = title | lower | replace(' ', '-') %}
{{ title }}¶
{% for i in range(labels | length) %}
{% set pct = (counts[i] / max_count * 100) | round(1) %}
{{ counts[i] }}
{% if loop.index0 % label_step == 0 or loop.last %}
{{ labels[i] }}
{% else %}
{{ labels[i] }}
{% endif %}
{% endfor %}
{% endmacro %}
{# Posts per hour of day #}
{% set hour_labels = [] %}
{% for h in range(24) %}{% set _ = hour_labels.append("%02d" % h) %}{% endfor %}
{{ histogram("Posts by Hour of Day", hour_labels, stats.posts_per_hour, label_step=2) }}
{# Posts per day of week #}
{{ histogram("Posts by Day of Week", ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"], stats.posts_per_weekday) }}
{# Posts per month of year #}
{{ histogram("Posts by Month of Year", ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], stats.posts_per_month) }}
{# ------------------------------------------------------------------ #}
{# Helper macro: render a horizontal bar chart (posts per year) #}
{# ------------------------------------------------------------------ #}
{% macro hbarchart(title, rows) %}
{% if rows %}
{% set max_count = rows | map(attribute=1) | max %}
{% set axis_max = ((max_count + 9) // 10 * 10) if max_count > 0 else 10 %}
{% set section_id = title | lower | replace(' ', '-') %}
{{ title }}¶
{% for year, count in rows %}
{% set pct = (count / axis_max * 100) | round(1) %}
{% set year_url = '/' ~ year ~ '/' ~ pagination_page1_suffix %}
{% if count > 0 %}
{{ year }}{% else %}{{ year }}{% endif %}
{% if count > 0 %}
{% endif %}
{{ count }}
{% endfor %}
{% endif %}
{% endmacro %}
{# Posts per year #}
{{ hbarchart("Posts per Year", stats.posts_per_year) }}
{# ------------------------------------------------------------------ #}
{# Streak chart: responsive month variants (3 / 6 / 9 months) #}
{# ------------------------------------------------------------------ #}
{% if stats.streak_variants %}
{% for variant in stats.streak_variants %}
{% set count = variant.posts_count %}
{{ count }} post{{ '' if count == 1 else 's' }} between {{ variant.first_date }} and {{ variant.last_date }}¶
{# Row 1, Col 1: spacer (aligns month labels with DOW labels column) #}
{# Row 1, Col 2: month labels positioned by column #}
{% for label, col_start in variant.month_label_positions %}
{{ label }}
{% endfor %}
{# Row 2, Col 1: day-of-week labels #}
Sun
Mon
Tue
Wed
Thu
Fri
Sat
{# Row 2, Col 2: streak cells #}
{% for week in variant.weeks %}
{% for cell in week %}
{% if cell is none %}
{% else %}
{% if cell.count == 0 %}
{% set level = 0 %}
{% elif cell.count == 1 %}
{% set level = 1 %}
{% elif cell.count <= 3 %}
{% set level = 2 %}
{% elif cell.count <= 6 %}
{% set level = 3 %}
{% else %}
{% set level = 4 %}
{% endif %}
{% set day_label = cell.date.strftime('%Y-%m-%d') ~ ': ' ~ cell.count ~ ' post' ~ ('' if cell.count == 1 else 's') %}
{% if cell.count > 0 %}
{% set day_url = '/' ~ cell.date.year ~ '/' ~ '%02d'|format(cell.date.month) ~ '/' ~ '%02d'|format(cell.date.day) ~ '/' ~ pagination_page1_suffix %}
{% else %}
{% endif %}
{% endif %}
{% endfor %}
{% endfor %}
{% endfor %}
{% endif %}
{# ------------------------------------------------------------------ #}
{# Blog time span #}
{# ------------------------------------------------------------------ #}
{% if stats.earliest_post_date and stats.latest_post_date %}
Blog Lifespan¶
- Span
-
{% set span = stats.blog_span_days %}
{% if span is none %}
—
{% elif span >= 365 %}
{{ "%.1f" % (span / 365.25) }} year{{ '' if (span / 365.25) | round(1) == 1.0 else 's' }}
{% else %}
{{ span }} day{{ '' if span == 1 else 's' }}
{% endif %}
{% endif %}
{# ------------------------------------------------------------------ #}
{# Longest Posting Streaks #}
{# ------------------------------------------------------------------ #}
{% if stats.longest_streaks %}
Longest Streaks¶
| # |
Days |
Start Date |
End Date |
Posts |
{% for streak in stats.longest_streaks %}
{% set start_url = '/' ~ streak.start_date.year ~ '/' ~ '%02d'|format(streak.start_date.month) ~ '/' ~ '%02d'|format(streak.start_date.day) ~ '/' ~ pagination_page1_suffix %}
{% set end_url = '/' ~ streak.end_date.year ~ '/' ~ '%02d'|format(streak.end_date.month) ~ '/' ~ '%02d'|format(streak.end_date.day) ~ '/' ~ pagination_page1_suffix %}
| {{ loop.index }} |
{{ streak.days }} |
{{ streak.start_date.strftime('%Y-%m-%d') }} |
{{ streak.end_date.strftime('%Y-%m-%d') }} |
{{ streak.post_count }} |
{% endfor %}
{% endif %}
{# ------------------------------------------------------------------ #}
{# Word count #}
{# ------------------------------------------------------------------ #}
{% if stats.show_word_count %}
Word Count¶
- Average
- {{ "%.0f" % stats.avg_word_count }} word{{ '' if ("%.0f" % stats.avg_word_count) | int == 1 else 's' }}
- Shortest
-
{% if stats.min_word_count_post %}
{{ stats.min_word_count_post.title }}
— {{ stats.min_word_count }} word{{ '' if stats.min_word_count == 1 else 's' }}
{% else %}
{{ stats.min_word_count }} word{{ '' if stats.min_word_count == 1 else 's' }}
{% endif %}
- Longest
-
{% if stats.max_word_count_post %}
{{ stats.max_word_count_post.title }}
— {{ stats.max_word_count }} word{{ '' if stats.max_word_count == 1 else 's' }}
{% else %}
{{ stats.max_word_count }} word{{ '' if stats.max_word_count == 1 else 's' }}
{% endif %}
{% endif %}
{# ------------------------------------------------------------------ #}
{# Reading time #}
{# ------------------------------------------------------------------ #}
{% if with_read_time and stats.show_reading_time %}
Reading Time¶
- Average
- {{ "%.1f" % stats.avg_reading_time }} min
{% endif %}
{# ------------------------------------------------------------------ #}
{# Focus by Year #}
{# ------------------------------------------------------------------ #}
{% if stats.focus_by_year %}
Focus by Year¶
{% for year, terms in stats.focus_by_year | dictsort(reverse=true) %}
{% if terms %}
{% set year_url = '/' ~ year ~ '/' ~ pagination_page1_suffix %}
- {{ year }}
-
{% for term in terms %}
{{ term.word }}
{{- ", " if not loop.last else "" -}}
{% endfor %}
{% else %}
- {{ year }}
- …
{% endif %}
{% endfor %}
{% endif %}
{# ------------------------------------------------------------------ #}
{# Gunning Fog Index #}
{# ------------------------------------------------------------------ #}
{% if with_gfi %}
Gunning Fog Index¶
- Mean
- {{ "%.2f" % stats.gfi_mean }}
- Median
- {{ "%.2f" % stats.gfi_median }}
- Mode
- {{ "%.2f" % stats.gfi_mode }}
{{ histogram("Posts by Gunning Fog Index", ["<= 6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", ">= 17"], stats.gfi_histogram) }}
{% if stats.gfi_highest %}
Highest Gunning Fog Index¶
| # |
Post |
Index |
{% for post in stats.gfi_highest %}
| {{ loop.index }} |
{{ post.title }} |
{{ "%.2f" % post.gfi }} |
{% endfor %}
{% endif %}
{% if stats.gfi_lowest %}
Lowest Gunning Fog Index¶
| # |
Post |
Index |
{% for post in stats.gfi_lowest %}
| {{ loop.index }} |
{{ post.title }} |
{{ "%.2f" % post.gfi }} |
{% endfor %}
{% endif %}
{% endif %}
{# ------------------------------------------------------------------ #}
{# Top 20 linked domains #}
{# ------------------------------------------------------------------ #}
{% if stats.top_domains %}
Top Linked Domains¶
| # |
Domain |
Links |
{% for domain, count in stats.top_domains %}
| {{ loop.index }} |
{{ domain }}
|
{{ count }} |
{% endfor %}
{% endif %}
{# ------------------------------------------------------------------ #}
{# Top 20 internal links (backlinks) #}
{# ------------------------------------------------------------------ #}
{% if stats.top_internal_links %}
Top Internal Links¶
| # |
Post |
Links |
{% for post, count in stats.top_internal_links %}
| {{ loop.index }} |
{{ post.title }} |
{{ count }} |
{% endfor %}
{% endif %}
{% endblock %}