{% 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' }}.

{# ------------------------------------------------------------------ #} {# 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 %}

{{ 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 %} {% 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 %}

{{ 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 #} {# 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 %} {# ------------------------------------------------------------------ #} {# 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 %}
{# ------------------------------------------------------------------ #} {# Reading time #} {# ------------------------------------------------------------------ #} {% if with_read_time %}

Reading Time

Average
{{ "%.1f" % stats.avg_reading_time }} min
Quickest
{% if stats.min_reading_time_post %} {{ stats.min_reading_time_post.title }} — {{ stats.min_reading_time }} min {% else %} {{ stats.min_reading_time }} min {% endif %}
Longest
{% if stats.max_reading_time_post %} {{ stats.max_reading_time_post.title }} — {{ stats.max_reading_time }} min {% else %} {{ stats.max_reading_time }} min {% endif %}
{% endif %} {# ------------------------------------------------------------------ #} {# Blog time span #} {# ------------------------------------------------------------------ #} {% if stats.earliest_post_date and stats.latest_post_date %}

Blog Lifespan

First post
{% if stats.earliest_post %} {{ stats.earliest_post_date.strftime("%Y-%m-%d") }} {% else %} {{ stats.earliest_post_date.strftime("%Y-%m-%d") }} {% endif %}
Latest post
{% if stats.latest_post %} {{ stats.latest_post_date.strftime("%Y-%m-%d") }} {% else %} {{ stats.latest_post_date.strftime("%Y-%m-%d") }} {% endif %}
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

{% 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 %} {% endfor %}
# Days Start Date End Date Posts
{{ loop.index }} {{ streak.days }} {{ streak.start_date.strftime('%Y-%m-%d') }} {{ streak.end_date.strftime('%Y-%m-%d') }} {{ streak.post_count }}
{% endif %} {# ------------------------------------------------------------------ #} {# Tags, categories and links overview #} {# ------------------------------------------------------------------ #}

Content Overview

Unique external links
{{ stats.unique_external_link_count }}
{# ------------------------------------------------------------------ #} {# Top 20 linked domains #} {# ------------------------------------------------------------------ #} {% if stats.top_domains %}

Top Linked Domains

{% for domain, count in stats.top_domains %} {% endfor %}
# Domain Links
{{ loop.index }} {{ domain }} {{ count }}
{% endif %} {# ------------------------------------------------------------------ #} {# Top 20 internal links (backlinks) #} {# ------------------------------------------------------------------ #} {% if stats.top_internal_links %}

Top Internal Links

{% for post, count in stats.top_internal_links %} {% endfor %}
# Post Links
{{ loop.index }} {{ post.title }} {{ count }}
{% endif %}
{% endblock %}