Adds ability to generate graphs for custom areas

This commit adds the ability to generate individual PNG and SVG graphs
for custom areas, defined as the union of several "Àrees Bàsiques de
Salut" (ABS) in the config/customAreas.php file.

Change-Id: I27f34b4a8f520a38c55eed224554b470c5ba2938
diff --git a/cron/includes/generation.php b/cron/includes/generation.php
new file mode 100644
index 0000000..623113f
--- /dev/null
+++ b/cron/includes/generation.php
@@ -0,0 +1,124 @@
+<?php
+if (php_sapi_name() != "cli")
+  exit();
+
+// Funció per obtenir el nombre de casos nous al dia originalDay+translation
+// a partir de les dades de la regió (dataRegio).
+function getSumDay($originalDay, $translation, &$dataRegio) {
+  if ($translation >= 0)
+    $day = (clone $originalDay)->add(new DateInterval("P".abs($translation)."D"));
+  else
+    $day = (clone $originalDay)->sub(new DateInterval("P".abs($translation)."D"));
+
+  foreach ($dataRegio as $row) {
+    $rowDay = new DateTime($row["data"]);
+    if ($day == $rowDay) return $row["sum_numcasos"];
+  }
+
+  return 0;
+}
+
+// Funció per fer una consulta a la taula de dades
+function query($soql, $resource = "xuwf-dxjd") {
+  $url = "https://analisi.transparenciacatalunya.cat/resource/".$resource.".json?\$query=".urlencode($soql);
+  $raw = file_get_contents($url);
+  if ($raw === false) return null;
+  return json_decode($raw, true);
+}
+
+// Funció per generar les dades de cada regió
+function generateSummary(&$dataRegio, $habitants){
+  $summary = [];
+
+  // Veiem quin és el primer i l'últim dia de la sèrie
+  $oldestDay = new DateTime("today");
+  $newestDay = new DateTime();
+  $newestDay->setTimestamp(0);
+
+  foreach ($dataRegio as $row) {
+    $date = new DateTime($row["data"]);
+    if ($date < $oldestDay) $oldestDay = $date;
+    if ($date > $newestDay) $newestDay = $date;
+  }
+
+  // Si l'últim dia és avui, posem que sigui ahir, perquè no volem informació
+  // incompleta sobre avui.
+  if ($oldestDay == (new DateTime("today")))
+    $oldestDay = new DateTime("yesterday");
+
+  // Ara calculem les rhos.
+  $rhos = [];
+
+  // Considerem cada dia a partir de 6 dies després del primer dia, i fins al
+  // dia anterior a l'últim dia (extrems inclosos)
+  for ($currentDate = (clone $oldestDay)->add(new DateInterval("P6D"));
+  $currentDate < $newestDay;
+  $currentDate->add(new DateInterval("P1D"))) {
+    // Calculem la rho (velocitat reproductiva efectiva) per aquell dia.
+    // Fórmula: https://biocomsc.upc.edu/en/shared/avaluacio_risc.pdf
+    $num = getSumDay($currentDate, 1, $dataRegio) +
+           getSumDay($currentDate, 0, $dataRegio) +
+           getSumDay($currentDate, -1, $dataRegio);
+
+    $den = getSumDay($currentDate, -4, $dataRegio) +
+           getSumDay($currentDate, -5, $dataRegio) +
+           getSumDay($currentDate, -6, $dataRegio);
+
+    if ($num != 0 && $den == 0) continue;
+
+    $rho = ($num == 0 ? 0 : $num/$den);
+
+    $rhos[] = [
+      "data" => $currentDate->format("c"),
+      "rho" => $rho
+    ];
+  }
+
+  // Considerem cada dia a partir de 13 dies després del primer dia, i fins el
+  // dia anterior a l'últim dia (extrems inclosos)
+  for ($currentDate = (clone $oldestDay)->add(new DateInterval("P13D"));
+    $currentDate < $newestDay;
+    $currentDate->add(new DateInterval("P1D"))) {
+    // Calculem Rho_7 i IA_14
+    // Rho_7(t) := \sum_{i=0}^{7} Rho(t - i)
+    // IA_14(t) := \sum_{i=0}^{14} N(t - i),
+    //   on N(j) és el nombre de casos nous confirmats per PCR el dia j.
+    $sum = 0;
+
+    $p13Date = (clone $currentDate)->sub(new DateInterval("P13D"));
+    $p6Date = (clone $currentDate)->sub(new DateInterval("P6D"));
+
+    foreach ($dataRegio as $row) {
+      $date = new DateTime($row["data"]);
+      if ($date >= $p13Date && $date <= $currentDate) {
+        $sum += $row["sum_numcasos"];
+      }
+    }
+
+    $rhoAverage = 0;
+    $rhoCount = 0;
+
+    foreach ($rhos as $row) {
+      $date = new DateTime($row["data"]);
+      if ($date >= $p6Date && $date <= $currentDate) {
+        ++$rhoCount;
+        $rhoAverage += $row["rho"];
+      }
+    }
+
+    // Si no hem trobat rhos (rhoCount == 0) és perquè el numerador no era 0
+    // però el denominador era sempre 0 al calcular les rhos. Aleshores, tot i
+    // que no poguem calcular la rho_7 a causa de no poder calcular les rho_t
+    // individuals, aquest fet ens indica que el creixement ha sigut altíssim,
+    // i per tant posem una rho_7 de 1000000000, que se surt de la gràfica.
+    $rhoAverage = ($rhoCount == 0 ? 1000000000 : $rhoAverage/$rhoCount);
+
+    $summary[] = [
+      "data" => $currentDate->format("d/m/y"),
+      "ia14" => $sum*(1e5/$habitants),
+      "rho7" => $rhoAverage
+    ];
+  }
+
+  return $summary;
+}
diff --git a/cron/includes/plotAllGraphs.gnu b/cron/includes/plotAllGraphs.gnu
new file mode 100644
index 0000000..ae0914e
--- /dev/null
+++ b/cron/includes/plotAllGraphs.gnu
@@ -0,0 +1,28 @@
+set xlabel "Casos actius per 10^5 habitants"
+set ylabel "Mitjana taxa de creixement darrers 7 dies"
+set title font "Helvetica,20"
+
+set xrange[0:675]
+set yrange[0:5]
+set samples 400
+
+set multiplot layout 3,3
+set key off
+set tics out scale 0.5,0.2
+
+min(a, b) = (a < b ? a : b)
+
+n = 9
+array fileNames[n] = ["TerresDeLEbre.dat", "CampDeTarragona.dat", "AltPirineuAran.dat", "Lleida.dat", "Girona.dat", "CatalunyaCentral.dat", "BarcelonaCiutat.dat", "MetropolitaSud.dat", "MetropolitaNord.dat"]
+array prettyNames[n] = ["Terres de l'Ebre", "Camp de Tarragona", "Alt Pirineu, Aran", "Lleida", "Girona", "Catalunya central", "Barcelona ciutat", "Metropolità sud", "Metropolità nord"]
+
+# The different colored areas correspond to the classification of the EPG values defined on page 8 at https://biocomsc.upc.edu/en/shared/20200506_report_web_51.pdf
+
+do for [i = 1:n] {
+  lastUpdated = system("tail -n 1 ".filesPrefix.fileNames[i]." | awk '{print $1;}'")
+  graphTitle = prettyNames[i]
+  graphDataFile = filesPrefix.fileNames[i]
+  load "includes/plotSingleGraph.gnu"
+}
+
+unset multiplot
diff --git a/cron/includes/plotCustomGraph.gnu b/cron/includes/plotCustomGraph.gnu
new file mode 100644
index 0000000..acf66aa
--- /dev/null
+++ b/cron/includes/plotCustomGraph.gnu
@@ -0,0 +1,19 @@
+set xlabel "Casos actius per 10^5 habitants"
+set ylabel "Mitjana taxa de creixement darrers 7 dies"
+set title font "Helvetica,20"
+
+set yrange[0:5]
+set xrange[0:800]
+set samples 400
+
+set key off
+set tics out scale 0.5,0.2
+
+min(a, b) = (a < b ? a : b)
+
+# The different colored areas correspond to the classification of the EPG values defined on page 8 at https://biocomsc.upc.edu/en/shared/20200506_report_web_51.pdf
+
+lastUpdated = system("tail -n 1 ".fileName." | awk '{print $1;}'")
+graphTitle = name
+graphDataFile = fileName
+load "includes/plotSingleGraph.gnu"
diff --git a/cron/includes/plotSingleGraph.gnu b/cron/includes/plotSingleGraph.gnu
new file mode 100644
index 0000000..152fd11
--- /dev/null
+++ b/cron/includes/plotSingleGraph.gnu
@@ -0,0 +1,2 @@
+set title graphTitle."\n{/*0.4 Última dada (punt negre): ".lastUpdated."}"
+plot 6*x w filledcurve y1=0 lt rgb "#ff9494", 100/x w filledcurve y1=0 lt rgb "#ffe494", 70/x w filledcurve y1=0 lt rgb "#dbff94", 30/x w filledcurve y1=0 lt rgb "#a0ff94", graphDataFile u 2:3 w lp pt 6 lt rgb "black", "< tail -n 1 ".graphDataFile u 2:3 w lp pt 7 lt rgb "black"