diff --git a/nummi/history/locale/fr_FR/LC_MESSAGES/django.mo b/nummi/history/locale/fr_FR/LC_MESSAGES/django.mo
index c369f8d..cdfe26f 100644
Binary files a/nummi/history/locale/fr_FR/LC_MESSAGES/django.mo and b/nummi/history/locale/fr_FR/LC_MESSAGES/django.mo differ
diff --git a/nummi/history/locale/fr_FR/LC_MESSAGES/django.po b/nummi/history/locale/fr_FR/LC_MESSAGES/django.po
index 463e67e..3df2dfa 100644
--- a/nummi/history/locale/fr_FR/LC_MESSAGES/django.po
+++ b/nummi/history/locale/fr_FR/LC_MESSAGES/django.po
@@ -7,7 +7,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: \n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-04-22 15:16+0200\n"
+"POT-Creation-Date: 2023-12-28 15:45+0100\n"
 "PO-Revision-Date: 2023-04-22 15:18+0200\n"
 "Last-Translator: Edgar P. Burkhart <traduction@edgarpierre.fr>\n"
 "Language-Team: \n"
@@ -28,3 +28,7 @@ msgstr "Dépenses"
 #: .\history\templates\history\plot.html:17
 msgid "Income"
 msgstr "Revenus"
+
+#: .\history\templates\history\plot.html:68
+msgid "Year"
+msgstr "Année"
diff --git a/nummi/history/templates/history/plot.html b/nummi/history/templates/history/plot.html
index 43d94ef..cba9e18 100644
--- a/nummi/history/templates/history/plot.html
+++ b/nummi/history/templates/history/plot.html
@@ -61,3 +61,42 @@
         </tbody>
     </table>
 </div>
+<div class="calendar">
+    <table class="full-width">
+        <thead>
+            <tr>
+                <th scope="col">{% translate "Year" %}</th>
+                <th scope="col">01</th>
+                <th scope="col">02</th>
+                <th scope="col">03</th>
+                <th scope="col">04</th>
+                <th scope="col">05</th>
+                <th scope="col">06</th>
+                <th scope="col">07</th>
+                <th scope="col">08</th>
+                <th scope="col">09</th>
+                <th scope="col">10</th>
+                <th scope="col">11</th>
+                <th scope="col">12</th>
+            </tr>
+        </thead>
+        <tbody>
+            {% spaceless %}
+                {% for year in history.years %}
+                    <tr>
+                        <th>{{ year.y }}</th>
+                        {% for m in year.d %}
+                            {% if m %}
+                                <td class="{% if m.sum > 0 %}p{% else %}m{% endif %}"
+                                    style="opacity: calc( sin( abs({% widthratio m.sum history.years_max 100 %}) / 400 * 1turn ) )">
+                                </td>
+                            {% else %}
+                                <td></td>
+                            {% endif %}
+                        {% endfor %}
+                    </tr>
+                {% endfor %}
+            {% endspaceless %}
+        </tbody>
+    </table>
+</div>
diff --git a/nummi/history/utils.py b/nummi/history/utils.py
index ef0a353..adf1c35 100644
--- a/nummi/history/utils.py
+++ b/nummi/history/utils.py
@@ -1,6 +1,8 @@
+import datetime
+
 from django.db import models
 from django.db.models import Func, Max, Min, Q, Sum, Value
-from django.db.models.functions import Now, TruncMonth
+from django.db.models.functions import Abs, Now, TruncMonth
 
 
 class GenerateMonth(Func):
@@ -22,11 +24,17 @@ def history(transaction_set):
             )
         )
         .annotate(
-            sum_m=Value(0), sum_p=Value(0), sum=Value(0), has_transactions=Value(0)
+            sum_m=Value(0),
+            sum_p=Value(0),
+            sum=Value(0),
+            has_transactions=Value(0),
         )
         .difference(
             _transaction_month.annotate(
-                sum_m=Value(0), sum_p=Value(0), sum=Value(0), has_transactions=Value(0)
+                sum_m=Value(0),
+                sum_p=Value(0),
+                sum=Value(0),
+                has_transactions=Value(0),
             )
         )
     )
@@ -39,10 +47,25 @@ def history(transaction_set):
 
     return {
         "data": _history.union(_months).order_by("-month"),
+        "years": [
+            {
+                "y": y,
+                "d": [
+                    _history.filter(month=datetime.date(y, m + 1, 1)).first()
+                    for m in range(12)
+                ],
+            }
+            for y in range(
+                _transaction_month.first()["month"].year,
+                _transaction_month.last()["month"].year - 1,
+                -1,
+            )
+        ],
         "max": max(
             _history.aggregate(
                 max=Max("sum_p", default=0),
                 min=-Min("sum_m", default=0),
             ).values(),
         ),
+        "years_max": _history.aggregate(max=Max(Abs("sum")))["max"],
     }
diff --git a/nummi/main/static/main/css/plot.css b/nummi/main/static/main/css/plot.css
index 15fc7ab..a55a06f 100644
--- a/nummi/main/static/main/css/plot.css
+++ b/nummi/main/static/main/css/plot.css
@@ -74,3 +74,28 @@ table.full-width col.bar {
 .plot tfoot {
   background: var(--bg-01);
 }
+
+.calendar {
+  margin-top: var(--gap);
+}
+.calendar .p {
+  background: var(--green);
+}
+.calendar .o-0 {
+  opacity: 0.1;
+}
+.calendar .o-1 {
+  opacity: 0.5;
+}
+.calendar .o-2 {
+  opacity: 0.75;
+}
+.calendar .o-3 {
+  opacity: 0.9;
+}
+.calendar .o-4 {
+  opacity: 1;
+}
+.calendar .m {
+  background: var(--red);
+}
