NicolasLeGland

INSEE, 2010-2020, nombre de décès

Oct 27th, 2020 (edited)
678
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 32.38 KB | None | 0 0
  1. <?php
  2. assert_options(ASSERT_BAIL, 1);
  3. date_default_timezone_set('UTC');
  4.  
  5. // https://pastebin.com/s4VZwcYY
  6.  
  7. function sublime_normalize_workspace($file)
  8. {
  9.     assert(true === is_string($file));
  10.     assert(true === is_file($file));
  11.  
  12.     $content = file_get_contents($file);
  13.     assert(true === is_string($content));
  14.  
  15.     $data = json_decode($content);
  16.     unset($data->auto_complete);
  17.     unset($data->expanded_folders);
  18.     unset($data->file_history);
  19.     unset($data->find_state->find_history);
  20.     foreach ($data->groups as &$group)
  21.     {
  22.         foreach ($group->sheets as &$sheet) foreach (array
  23.         (
  24.             'selection',
  25.             'translation.x',
  26.             'translation.y',
  27.         )
  28.         as $property)
  29.         {
  30.             unset($sheet->settings->$property);
  31.         }
  32.     }
  33.  
  34.     file_put_contents($file, str_replace("\n", PHP_EOL, str_replace(array("\r\n", "\r"), "\n", preg_replace(array_keys($map = array
  35.     (
  36.         '/^(\t*)("[^"]+":) ([{[])/m' => '\1\2'."\n".'\1\3',
  37.         '/^(\t*)\[]/m' => '\1['."\n".'\1]',
  38.         '/^(\t*)\{}/m' => '\1{'."\n".'\1}',
  39.     )
  40.     ), array_values($map), preg_replace_callback('/^ +/m', function ($match)
  41.     {
  42.         return str_replace('    ', "\t", $match[0]);
  43.     }
  44.     , json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRESERVE_ZERO_FRACTION))))));
  45. }
  46. $file = substr(__FILE__, 0, -3).'sublime-workspace';
  47. if (true === is_file($file))
  48. {
  49.     sublime_normalize_workspace($file);
  50. }
  51.  
  52. // https://www.insee.fr/fr/information/4190491
  53. foreach (array
  54. (
  55.     array('7ed71ef5f78579e05d77e50bed090cb169852bda', '2010-01-01', '2018-12-31', 'https://www.insee.fr/fr/statistiques/fichier/4769950/deces-2010-2018-csv.zip'),
  56.     array('24a1e0fef31c5ad5c7eed1a00c954259909158d4', '2018-01-01', '2018-12-31', 'https://www.insee.fr/fr/statistiques/fichier/4190491/Deces_2018.zip'),
  57.     array('d32de660b525422907ed938d31a1cd525e69c705', '2019-01-01', '2019-12-31', 'https://www.insee.fr/fr/statistiques/fichier/4190491/Deces_2019.zip'),
  58.     array('b9625e7ea21b7224084d18328a2ed7a22ee3cb17', '2020-01-01', '2020-12-31', 'https://www.insee.fr/fr/statistiques/fichier/4190491/Deces_2020.zip'),
  59.     array('1f599e2852b3def54e80e082b8f4827677172322', '2021-01-01', '2021-01-31', 'https://www.insee.fr/fr/statistiques/fichier/4190491/Deces_2021_M01.zip'),
  60. )
  61. as $file)
  62. {
  63.     list($hash, $begin, $end, $source) = $file;
  64.     $target = substr(__FILE__, 0, -4).'-2-'.$begin.'-'.$end.'.zip';
  65.     if (true !== is_file($target))
  66.     {
  67.         echo 'download archive from ', $begin, ' to ', $end, PHP_EOL;
  68.         $content = file_get_contents($source);
  69.         assert(true === is_string($content));
  70.         assert(sha1($content) === $hash);
  71.         $result = file_put_contents($target, $content);
  72.         assert(strlen($content) === $result);
  73.         assert(true === is_file($target));
  74.         assert(strlen($content) === filesize($target));
  75.     }
  76. }
  77.  
  78. foreach (array
  79. (
  80.     array('e1534a56eab1573b0105d68976f1ad12ccf0fbf3', '2010-01-01', '2010-12-31', '2010-01-01-2018-12-31', 'deces-2010'),
  81.     array('cc2f5ac5032995b174bd4ac4d0c7bdffb1308d2c', '2011-01-01', '2011-12-31', '2010-01-01-2018-12-31', 'deces-2011'),
  82.     array('ecf924ab4be6f27b78f10fa04522f3393ade059f', '2012-01-01', '2012-12-31', '2010-01-01-2018-12-31', 'deces-2012'),
  83.     array('b7cb22efe9783b7d777b8d5fd02545218641c3c9', '2013-01-01', '2013-12-31', '2010-01-01-2018-12-31', 'deces-2013'),
  84.     array('d4c543359d6ff25fb500a09314f7a10c73accff6', '2014-01-01', '2014-12-31', '2010-01-01-2018-12-31', 'deces-2014'),
  85.     array('a3ffdd5510042aa1b3173706a491a66b69679e45', '2015-01-01', '2015-12-31', '2010-01-01-2018-12-31', 'deces-2015'),
  86.     array('9ed276678a94856801685e0cbab20a2d4d15f170', '2016-01-01', '2016-12-31', '2010-01-01-2018-12-31', 'deces-2016'),
  87.     array('717ff6411ad28618fc07f418d7cc166930fefc30', '2017-01-01', '2017-12-31', '2010-01-01-2018-12-31', 'deces-2017'),
  88.     array('e072fbb64b928d01fd355dee5507153c2e0d6700', '2018-01-01', '2018-12-31', '2018-01-01-2018-12-31', 'deces-2018'),
  89.     array('3ba9419aff67752acd7e91fa61a6afb6ad4a6aab', '2019-01-01', '2019-12-31', '2019-01-01-2019-12-31', 'deces-2019'),
  90.     array('0e7c6ff2d4b6a2efef399a9d031fcb23810fa41e', '2020-01-01', '2020-12-31', '2020-01-01-2020-12-31', 'deces_2020'),
  91.     array('3231cf18ec319afb8a13c962ddb0f520ba7a6293', '2021-01-01', '2021-01-31', '2021-01-01-2021-01-31', 'Deces_2021_M01'),
  92. )
  93. as $file)
  94. {
  95.     list($hash, $begin, $end, $archive, $name) = $file;
  96.     $target = substr(__FILE__, 0, -4).'-3-'.$begin.'-'.$end.'.csv';
  97.     if (true !== is_file($target))
  98.     {
  99.         echo 'extract data from ', $begin, ' to ', $end, PHP_EOL;
  100.         $source = substr(__FILE__, 0, -4).'-2-'.$archive.'.zip';
  101.         assert(true === is_file($source));
  102.         $zip = new ZipArchive();
  103.         assert(true === is_object($zip));
  104.         assert('ZipArchive' === get_class($zip));
  105.         assert('fbe34874de4c3b1729f048eb50447b773cddb2d5' === sha1(serialize($zip)));
  106.         $result = $zip->open($source);
  107.         assert(true === $result);
  108.         assert($zip->filename === $source);
  109.         $name .= '.csv';
  110.         $entry = $zip->statName($name);
  111.         assert(true === is_array($entry));
  112.         assert($entry['name'] === $name);
  113.         $content = $zip->getFromName($name);
  114.         assert(strlen($content) === $entry['size']);
  115.         assert(sha1($content) === $hash);
  116.         $result = file_put_contents($target, $content);
  117.         assert(strlen($content) === $result);
  118.         assert(true === is_file($target));
  119.         $result = $zip->close();
  120.         assert(true === $result);
  121.         assert('fbe34874de4c3b1729f048eb50447b773cddb2d5' === sha1(serialize($zip)));
  122.     }
  123. }
  124.  
  125. $target = substr(__FILE__, 0, -4).'-4.txt';
  126. if (true !== is_file($target))
  127. {
  128.     $year_map = array();
  129.     foreach (array
  130.     (
  131.         array('2010-01-01', '2010-12-31'),
  132.         array('2011-01-01', '2011-12-31'),
  133.         array('2012-01-01', '2012-12-31'),
  134.         array('2013-01-01', '2013-12-31'),
  135.         array('2014-01-01', '2014-12-31'),
  136.         array('2015-01-01', '2015-12-31'),
  137.         array('2016-01-01', '2016-12-31'),
  138.         array('2017-01-01', '2017-12-31'),
  139.         array('2018-01-01', '2018-12-31'),
  140.         array('2019-01-01', '2019-12-31'),
  141.         array('2020-01-01', '2020-12-31'),
  142.         array('2021-01-01', '2021-01-31'),
  143.     )
  144.     as $file)
  145.     {
  146.         list($begin, $end) = $file;
  147.         echo 'reading data from ', $begin, ' to ', $end, PHP_EOL;
  148.         $line_list = explode("\r\n", file_get_contents(substr(__FILE__, 0, -4).'-3-'.$begin.'-'.$end.'.csv'));
  149.         $line = array_shift($line_list);
  150.         assert('"nomprenom";"sexe";"datenaiss";"lieunaiss";"commnaiss";"paysnaiss";"datedeces";"lieudeces";"actedeces"' === $line);
  151.         $line = array_pop($line_list);
  152.         assert('' === $line);
  153.         foreach ($line_list as $line)
  154.         {
  155.             assert('"' === $line[0]);
  156.             assert('"' === substr($line, -1));
  157.             $line = explode('";"', substr($line, 1, -1));
  158.             assert(9 === count($line));
  159.             assert(1 === preg_match('/^[0-9]{4}[012][0-9][0123][0-9]$/', $line[2]));
  160.             assert(1 === preg_match('/^[0-9]{4}[012][0-9]/', $line[6]));
  161.             $code = strtolower(substr($line[7], 0, 2));
  162.             assert(1 === preg_match('/^(?:|2[ab]|[0-9]{2})$/', $code));
  163.             if (!(('2a' === $code) || ('2b' === $code) || ('' === $code)))
  164.             {
  165.                 $code = (int)$code;
  166.                 assert((0 < $code) && ($code < 100));
  167.             }
  168.             ++$year_map[(int)(substr($line[6], 0, 4))][(int)(substr($line[6], 4, 2))][(int)(substr($line[6], 6, 2))][$line[7]];
  169.         }
  170.     }
  171.     ksort($year_map);
  172.     foreach ($year_map as $year => $month_map)
  173.     {
  174.         ksort($year_map[$year]);
  175.         foreach ($month_map as $month => $day_map)
  176.         {
  177.             ksort($year_map[$year][$month]);
  178.             foreach (array_keys($day_map) as $day)
  179.             {
  180.                 ksort($year_map[$year][$month][$day]);
  181.             }
  182.         }
  183.     }
  184.     $content = serialize($year_map);
  185.     assert('4a85dc1e2b48b55d1005167a263ba4c5949771f7' === sha1($content));
  186.     $result = file_put_contents($target, $content);
  187.     assert(strlen($content) === $result);
  188.     assert(true === is_file($target));
  189.     assert(strlen($content) === filesize($target));
  190. }
  191.  
  192. function render_table($target, $year_map, $filter = '', $template_map = array())
  193. {
  194.     assert(true === is_string($target));
  195.     assert(true === is_array($year_map));
  196.     assert(true === is_string($filter));
  197.     assert(true === is_array($template_map));
  198.     echo 'rendering 2017-01-01 to 2020-12-31 ', str_replace('-', ' ', substr($target, strlen(__FILE__) - 1, -4)), PHP_EOL;
  199.  
  200.     if (array() !== $template_map)
  201.     {
  202.         $template_total = array();
  203.         $template_subtotal = array();
  204.         foreach ($template_map as $template_month => $template_list)
  205.         {
  206.             if (true === in_array($template_month, array('total', 'subtotal'), true))
  207.             {
  208.                 continue;
  209.             }
  210.             foreach ($template_list as $template_year => $template_count)
  211.             {
  212.                 $template_total[$template_year] += $template_count;
  213.                 if ($template_month <= 9)
  214.                 {
  215.                     $template_subtotal[$template_year] += $template_count;                 
  216.                 }
  217.             }
  218.         }
  219.         for ($template_year = 2017; $template_year <= 2020; ++$template_year)
  220.         {
  221.             $difference = $template_map['subtotal'][$template_year] - $template_subtotal[$template_year];
  222.             assert((0 <= $difference) && ($difference <= 10));
  223.             if (true === array_key_exists($template_year, $template_map['total']))
  224.             {
  225.                 $difference = $template_map['total'][$template_year] - $template_total[$template_year];
  226.                 assert((0 <= $difference) && ($difference <= 15));
  227.             }
  228.         }
  229.     }
  230.  
  231.     $target_image = imagecreatefromjpeg(substr(__FILE__, 0, -4).'-1-template.jpg');
  232.     assert(true === is_resource($target_image));
  233.     assert('gd' === get_resource_type($target_image));
  234.     assert(true === imageistruecolor($target_image));
  235.     $render_image = imagecreatetruecolor(imagesx($target_image) << 2, imagesy($target_image) << 2);
  236.     assert(true === is_resource($render_image));
  237.     assert('gd' === get_resource_type($render_image));
  238.     assert(true === imageistruecolor($render_image));
  239.     $result = imagealphablending($render_image, false);
  240.     assert(true === $result);
  241.     $result = imagefilledrectangle($render_image, 0, 0, imagesx($render_image) - 1, imagesy($render_image) - 1, 0x7FFF00FF);
  242.     assert(true === $result);
  243.     $result = imagealphablending($render_image, true);
  244.     assert(true === $result);
  245.     $render_font = str_replace('/', DIRECTORY_SEPARATOR, 'C:/Windows/Fonts/calibrib.ttf');
  246.     $result = imageantialias($render_image, true);
  247.     assert(true === $result);
  248.     $render_size = 48;
  249.     $target_x = 122;
  250.     foreach (array
  251.     (
  252.         2017 => array(87, 0x8899BB),
  253.         2018 => array(88, 0x444477),
  254.         2019 => array(87, 0x222233),
  255.         2020 => array(87, 0x000000),
  256.     )
  257.     as $target_year => $target_list)
  258.     {
  259.         list($target_width, $render_color) = $target_list;
  260.         $render_x = $target_x << 2;
  261.         $render_width = $target_width << 2;
  262.         $target_y = 276;
  263.         foreach (array
  264.         (
  265.             1 => 18,
  266.             2 => 18,
  267.             3 => 19,
  268.             4 => 18,
  269.             5 => 18,
  270.             6 => 19,
  271.             7 => 18,
  272.             8 => 18,
  273.             9 => 18,
  274.             'subtotal' => 28,
  275.             10 => 33,
  276.             11 => 17,
  277.             12 => 17,
  278.             'total' => 17,
  279.         )
  280.         as $target_month => $target_height)
  281.         {
  282.             if ('subtotal' === $target_month)
  283.             {
  284.                 $render_begin = $target_year.'-01-01';
  285.                 $render_end   = $target_year.'-09-30';
  286.             }
  287.             else if ('total' === $target_month)
  288.             {
  289.                 $render_begin = $target_year.'-01-01';
  290.                 $render_end   = $target_year.'-12-31';
  291.             }
  292.             else
  293.             {
  294.                 $render_begin = $target_year.'-'.substr('0'.$target_month, -2).'-01';
  295.                 $render_end   = $target_year.'-'.substr('0'.$target_month, -2).'-31';
  296.             }
  297.             $render_count = 0;
  298.             foreach ($year_map as $source_year => $month_map)
  299.             {
  300.                 foreach ($month_map as $source_month => $day_map)
  301.                 {
  302.                     foreach ($day_map as $source_day => $area_map)
  303.                     {
  304.                         $source_date = $source_year.'-'.substr('0'.$source_month, -2).'-'.substr('0'.$source_day, -2);
  305.                         if (($render_begin <= $source_date) && ($source_date <= $render_end))
  306.                         {
  307.                             if ('' === $filter)
  308.                             {
  309.                                 $render_count += array_sum($area_map);
  310.                             }
  311.                             else
  312.                             {
  313.                                 foreach ($area_map as $area_code => $area_count)
  314.                                 {
  315.                                     if (0 === preg_match($filter, $area_code))
  316.                                     {
  317.                                         $render_count += $area_count;
  318.                                     }
  319.                                 }
  320.                             }
  321.                         }
  322.                     }
  323.                 }
  324.             }
  325.             if (0 !== $render_count)
  326.             {
  327.                 $text_color = $render_color;
  328.                 if (array() !== $template_map)
  329.                 {
  330.                     $template_count = 1;
  331.                     if ((true === array_key_exists($target_month, $template_map)) && (true === array_key_exists($target_year, $template_map[$target_month])))
  332.                     {
  333.                         $template_count = max(1, $template_map[$target_month][$target_year]);
  334.                     }
  335.                     $error_ratio = $render_count / $template_count;
  336.                     if (($error_ratio < 0.95) || (1.05 < $error_ratio))
  337.                     {
  338.                         $text_color = 0xFF0000;
  339.                     }
  340.                 }
  341.                 $render_text = number_format($render_count, 0, '.', ' ');
  342.                 $render_y = $target_y << 2;
  343.                 $render_height = $target_height << 2;
  344.                 $result = imagefilledrectangle($render_image, $render_x, $render_y, $render_x + $render_width - 1, $render_y + $render_height - 1, 0xFFFFFF);
  345.                 assert(true === $result);
  346.                 $text_box = imagettfbbox($render_size, 0, $render_font, $render_text);
  347.                 assert(true === is_array($text_box));
  348.                 assert(array(0, 1, 2, 3, 4, 5, 6, 7) === array_keys($text_box));
  349.                 assert(array(true) === array_unique(array_map('is_integer', $text_box)));
  350.                 $text_width = max($text_box[0], $text_box[2], $text_box[4], $text_box[6]) - min($text_box[0], $text_box[2], $text_box[4], $text_box[6]);
  351.                 assert(0 < $text_width);
  352.                 $text_height = max($text_box[1], $text_box[3], $text_box[5], $text_box[7]) - min($text_box[1], $text_box[3], $text_box[5], $text_box[7]);
  353.                 assert(0 < $text_height);
  354.                 $text_x = $render_x + $render_width - $text_width - 24;
  355.                 $text_y = $render_y + $render_height - 8;
  356.                 if ('subtotal' === $month)
  357.                 {
  358.                     $text_y -= 12;
  359.                 }
  360.                 $result = imagettftext($render_image, $render_size, 0, $text_x, $text_y, $text_color, $render_font, $render_text);
  361.                 assert(true === is_array($result));
  362.                 assert(array(0, 1, 2, 3, 4, 5, 6, 7) === array_keys($result));
  363.                 assert(array(true) === array_unique(array_map('is_integer', $result)));
  364.             }
  365.             $target_y += $target_height + 3;
  366.         }
  367.         $target_x += $target_width + 2;
  368.     }
  369.     $render_x = 32 << 2;
  370.     $render_y = 597 << 2;
  371.     $render_width = 446 << 2;
  372.     $render_height = 24 << 2;
  373.     $result = imagefilledrectangle($render_image, $render_x, $render_y, $render_x + $render_width - 1, $render_y + $render_height - 1, 0xFFFFFF);
  374.     assert(true === $result);
  375.     $result = imagettftext($render_image, 48, 0, $render_x + 8, $render_y + $render_height - 16, 0xBBAA99, $render_font, 'https://twitter.com/nicolaslegland/status/1320752230824366081');
  376.     assert(true === is_array($result));
  377.     assert(array(0, 1, 2, 3, 4, 5, 6, 7) === array_keys($result));
  378.     assert(array(true) === array_unique(array_map('is_integer', $result)));
  379.     $result = imagecopyresampled($target_image, $render_image, 0, 0, 0, 0, imagesx($target_image), imagesy($target_image), imagesx($render_image), imagesy($render_image));
  380.     assert(true === $result);
  381.     assert(true === $result);
  382.     $result = imagedestroy($render_image);
  383.     assert(true === $result);
  384.     $result = imagepng($target_image, $target, 9, PNG_ALL_FILTERS);
  385.     assert(true === $result);
  386.     assert(true === is_file($target));
  387.     $result = imagedestroy($target_image);
  388.     assert(true === $result);
  389. }
  390.  
  391. $year_map = unserialize(file_get_contents($target));
  392.  
  393. $target = substr(__FILE__, 0, -4).'-5-table-metropole.png';
  394. if (true !== is_file($target))
  395. {
  396.     render_table($target, $year_map, '/^9[7-9]/');
  397.     assert('7165871b50ca1650152f6c7f1dab5197835450c4' === sha1_file($target));
  398. }
  399.  
  400. $target = substr(__FILE__, 0, -4).'-5-table-world.png';
  401. if (true !== is_file($target))
  402. {
  403.     render_table($target, $year_map);
  404.     assert('8f77f1820db6e4f2208c1c0243b21fe5a67b105b' === sha1_file($target));
  405. }
  406.  
  407. $target = substr(__FILE__, 0, -4).'-5-table-world-etchebest.png';
  408. if (true !== is_file($target))
  409. {
  410.     render_table($target, $year_map, '', array
  411.     (
  412.              1 => array(2017 => 84917,  2018 => 79753,  2019 => 80155,  2020 => 73404),
  413.              2 => array(2017 => 53169,  2018 => 52819,  2019 => 56462,  2020 => 54805),
  414.              3 => array(2017 => 50817,  2018 => 61072,  2019 => 54331,  2020 => 60501),
  415.              4 => array(2017 => 47497,  2018 => 51008,  2019 => 49719,  2020 => 67213),
  416.              5 => array(2017 => 48910,  2018 => 48427,  2019 => 49672,  2020 => 49121),
  417.              6 => array(2017 => 44898,  2018 => 45568,  2019 => 46992,  2020 => 40069),
  418.              7 => array(2017 => 46818,  2018 => 48862,  2019 => 48670,  2020 => 47407),
  419.              8 => array(2017 => 47027,  2018 => 47761,  2019 => 47566,  2020 => 49171),
  420.              9 => array(2017 => 46504,  2018 => 46192,  2019 => 46796,  2020 => 40056),
  421.     'subtotal' => array(2017 => 470557, 2018 => 481462, 2019 => 480363, 2020 => 481747),
  422.             10 => array(2017 => 49625,  2018 => 50101,  2019 => 50503),
  423.             11 => array(2017 => 49659,  2018 => 49415,  2019 => 51812),
  424.             12 => array(2017 => 43186,  2018 => 39146,  2019 => 42694),
  425.        'total' => array(2017 => 613027, 2018 => 620124, 2019 => 625372),
  426.     ));
  427.     assert('979f97265197ce791e58806ea164d97a0b4dee2d' === sha1_file($target));
  428. }
  429.  
  430. $target = substr(__FILE__, 0, -4).'-5-table-world-december.png';
  431. if (true !== is_file($target))
  432. {
  433.     render_table($target, $year_map, '', array
  434.     (
  435.              1 => array(2017 => 68969,  2018 => 60625,  2019 => 61210,  2020 => 58020),
  436.              2 => array(2017 => 53294,  2018 => 52911,  2019 => 56511,  2020 => 51975),
  437.              3 => array(2017 => 50965,  2018 => 61207,  2019 => 54393,  2020 => 63721),
  438.              4 => array(2017 => 47683,  2018 => 51121,  2019 => 49797,  2020 => 67538),
  439.              5 => array(2017 => 49113,  2018 => 48560,  2019 => 49757,  2020 => 49652),
  440.              6 => array(2017 => 45176,  2018 => 45702,  2019 => 47083,  2020 => 46770),
  441.              7 => array(2017 => 47146,  2018 => 49056,  2019 => 48834,  2020 => 47703),
  442.              8 => array(2017 => 47434,  2018 => 48039,  2019 => 47734,  2020 => 49781),
  443.              9 => array(2017 => 46925,  2018 => 46495,  2019 => 46828,  2020 => 49789),
  444.     'subtotal' => array(2017 => 456715, 2018 => 463726, 2019 => 462153, 2020 => 484955),
  445.             10 => array(2017 => 50255,  2018 => 50673,  2019 => 51061,  2021 => 58460),
  446.             11 => array(2017 => 50813,  2018 => 50438,  2019 => 52605,  2021 => 66169),
  447.             12 => array(2017 => 57793,  2018 => 53745,  2019 => 55660,  2021 => 53974),
  448.        'total' => array(2017 => 615578, 2018 => 618587, 2019 => 621482, 2021 => 663560),
  449.     ));
  450.     assert('bc2738adb15cc7396b48ca8f57e2682d472bab54' === sha1_file($target));
  451. }
  452.  
  453. function render_curve($year_map, $target, $step, $maximum, $smooth = false, $filter = '/^(?:$|[^9]|9[^7-9])/', $description = '')
  454. {
  455.     assert(true === is_array($year_map));
  456.     assert(true === is_string($target));
  457.     assert(true === is_integer($step));
  458.     assert(true === is_integer($maximum));
  459.     assert(true === is_string($filter));
  460.     assert(true === is_string($description));
  461.     echo 'rendering 2010-01-01 to 2020-12-31 curve';
  462.     if ('' !== $description)
  463.     {
  464.         echo ' for ', preg_replace('/&([A-Za-z])(?:acute|circ|grave);/', '\1', $description);
  465.     }
  466.     if (true === $smooth)
  467.     {
  468.         echo ' smooth';
  469.     }
  470.     echo PHP_EOL;
  471.     $line_map = array();
  472.     foreach ($year_map as $year => $month_map)
  473.     {
  474.         if (($year < 2010) || (2020 < $year))
  475.         {
  476.             continue;
  477.         }
  478.         $line_map[$year] = array();
  479.         foreach ($month_map as $month => $day_map)
  480.         {
  481.             if ($month < 1)
  482.             {
  483.                 continue;
  484.             }
  485.             foreach ($day_map as $day => $area_map)
  486.             {
  487.                 if ($day < 1)
  488.                 {
  489.                     continue;
  490.                 }
  491.                 $count = 0;
  492.                 foreach ($area_map as $area_code => $area_count)
  493.                 {
  494.                     if (1 === preg_match($filter, $area_code))
  495.                     {
  496.                         $count += $area_count;
  497.                     }
  498.                 }
  499.                 $line_map[$year][] = $count;
  500.             }
  501.         }
  502.         if (true === in_array($year, array(2012, 2016, 2020), true))
  503.         {
  504.             assert(count($line_map[$year]) === 366);
  505.         }
  506.         else
  507.         {
  508.             assert(count($line_map[$year]) === 365);
  509.         }
  510.     }
  511.     $target_width = 1024;
  512.     $target_height = 512;
  513.     $border_size = 0;
  514.     $margin_size = 8;
  515.     $padding_size = 0;
  516.     $render_width = ($target_width - (2 * ($margin_size + $border_size + $padding_size))) * 16;
  517.     $render_height = ($target_height - (2 * ($margin_size + $border_size + $padding_size))) * 16;
  518.     $render_image = imagecreate($render_width, $render_height);
  519.     assert(true === is_resource($render_image));
  520.     assert('gd' === get_resource_type($render_image));
  521.     assert(false === imageistruecolor($render_image));
  522.     for ($level = 0; 256 !== $level; ++$level)
  523.     {
  524.         $color = imagecolorallocate($render_image, $level, $level, $level);
  525.         assert($level === $color);
  526.     }
  527.     $result = imagefilledrectangle($render_image, 0, 0, $render_width - 1, $render_height - 1, 255);
  528.     assert(true === $result);
  529.     for ($month = 2; $month <= 12; ++$month)
  530.     {
  531.         $x = (int)(round(((strtotime('1970-'.substr('0'.$month, -2).'-01') / 86400) * ($render_width - 1)) / 364));
  532.         $x = ($x >> 4) << 4;
  533.         $result = imagefilledrectangle($render_image, $x - 16, 0, $x + 15, $render_height - 1, 0xEE);
  534.         assert(true === $result);
  535.     }
  536.     $font = str_replace('/', DIRECTORY_SEPARATOR, 'C:/Windows/Fonts/calibrib.ttf');
  537.     $size = 160;
  538.     for ($count = $step; $count <= $maximum; $count += $step)
  539.     {
  540.         $y = (int)(round((($maximum - $count) * ($render_height - 1)) / $maximum));
  541.         if ($count < $maximum)
  542.         {
  543.             $result = imagefilledrectangle($render_image, 0, $y - 16, $render_width - 1, $y + 15, 0xEE);
  544.             assert(true === $result);
  545.         }
  546.         $result = imagettftext($render_image, $size, 0, 0, $y + $size + 32, 0x7F, $font, $count);
  547.         assert(true === is_array($result));
  548.         assert(array(0, 1, 2, 3, 4, 5, 6, 7) === array_keys($result));
  549.         assert(array(true) === array_unique(array_map('is_integer', $result)));
  550.     }
  551.     $y = imagesy($render_image) - 128;
  552.     foreach (array_map('html_entity_decode', array
  553.     (
  554.         'Janvier', 'F&eacute;vrier', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Ao&ucirc;t', 'Septembre', 'Octobre', 'Novembre', 'D&eacute;cembre',
  555.     )
  556.     ) as $month => $text)
  557.     {
  558.         $x = (int)(round(((strtotime('1970-'.substr('0'.($month + 1), -2).'-01') / 86400) * ($render_width - 1)) / 364)) + 32;
  559.         $result = imagettftext($render_image, $size, 0, $x, $y, 0x7F, $font, $text);
  560.         assert(true === is_array($result));
  561.         assert(array(0, 1, 2, 3, 4, 5, 6, 7) === array_keys($result));
  562.         assert(array(true) === array_unique(array_map('is_integer', $result)));    
  563.     }
  564.     foreach (array
  565.     (
  566.         'https://twitter.com/nicolaslegland/status/1320752230824366081',
  567.         'https://www.insee.fr/fr/information/4190491',
  568.         'https://pastebin.com/s4VZwcYY',
  569.     )
  570.     as $index => $text)
  571.     {
  572.         $text_box = imagettfbbox($size, 0, $font, $text);
  573.         assert(true === is_array($text_box));
  574.         assert(array(0, 1, 2, 3, 4, 5, 6, 7) === array_keys($text_box));
  575.         assert(array(true) === array_unique(array_map('is_integer', $text_box)));
  576.         $text_width = max($text_box[0], $text_box[2], $text_box[4], $text_box[6]) - min($text_box[0], $text_box[2], $text_box[4], $text_box[6]);
  577.         assert(0 < $text_width);
  578.         $result = imagettftext($render_image, $size, 0, $render_width - $text_width - 32, 640 + (192 * $index), 0xBF, $font, $text);
  579.         assert(true === is_array($result));
  580.         assert(array(0, 1, 2, 3, 4, 5, 6, 7) === array_keys($result));
  581.         assert(array(true) === array_unique(array_map('is_integer', $result)));
  582.     }
  583.     $caption_x = 896;
  584.     $caption_y = 192;
  585.     $text = html_entity_decode('D&eacute;c&egrave;s quotidiens');
  586.     $text_box = imagettfbbox($size, 0, $font, $text);
  587.     assert(true === is_array($text_box));
  588.     assert(array(0, 1, 2, 3, 4, 5, 6, 7) === array_keys($text_box));
  589.     assert(array(true) === array_unique(array_map('is_integer', $text_box)));
  590.     $text_width = max($text_box[0], $text_box[2], $text_box[4], $text_box[6]) - min($text_box[0], $text_box[2], $text_box[4], $text_box[6]);
  591.     assert(0 < $text_width);
  592.     $result = imagettftext($render_image, $size, 0, $caption_x, $caption_y, 0x7F, $font, $text);
  593.     assert(true === is_array($result));
  594.     assert(array(0, 1, 2, 3, 4, 5, 6, 7) === array_keys($result));
  595.     assert(array(true) === array_unique(array_map('is_integer', $result)));
  596.     $text = '2010-2019';
  597.     $text_box = imagettfbbox($size, 0, $font, $text);
  598.     assert(true === is_array($text_box));
  599.     assert(array(0, 1, 2, 3, 4, 5, 6, 7) === array_keys($text_box));
  600.     assert(array(true) === array_unique(array_map('is_integer', $text_box)));
  601.     $text_width = max($text_box[0], $text_box[2], $text_box[4], $text_box[6]) - min($text_box[0], $text_box[2], $text_box[4], $text_box[6]);
  602.     assert(0 < $text_width);
  603.     $result = imagettftext($render_image, $size, 0, $caption_x, $caption_y + 192, 0xBF, $font, $text);
  604.     assert(true === is_array($result));
  605.     assert(array(0, 1, 2, 3, 4, 5, 6, 7) === array_keys($result));
  606.     assert(array(true) === array_unique(array_map('is_integer', $result)));
  607.     $caption_width = $text_width;
  608.     for ($year = 2010; 2020 !== $year; ++$year)
  609.     {
  610.         $box_x = $caption_x + $caption_width + 128 + (($year - 2010) * 192);
  611.         $box_color = 240 + (8 * (2010 - $year));
  612.         $result = imagefilledrectangle($render_image, $box_x, $caption_y + 64, $box_x + 127, $caption_y + 191, $box_color);
  613.         assert(true === $result);
  614.     }
  615.     $text = '2020';
  616.     $text_box = imagettfbbox($size, 0, $font, $text);
  617.     assert(true === is_array($text_box));
  618.     assert(array(0, 1, 2, 3, 4, 5, 6, 7) === array_keys($text_box));
  619.     assert(array(true) === array_unique(array_map('is_integer', $text_box)));
  620.     $text_width = max($text_box[0], $text_box[2], $text_box[4], $text_box[6]) - min($text_box[0], $text_box[2], $text_box[4], $text_box[6]);
  621.     assert(0 < $text_width);
  622.     $result = imagettftext($render_image, $size, 0, $caption_x + $caption_width - $text_width, $caption_y + 384, 0xBF, $font, $text);
  623.     assert(true === is_array($result));
  624.     assert(array(0, 1, 2, 3, 4, 5, 6, 7) === array_keys($result));
  625.     assert(array(true) === array_unique(array_map('is_integer', $result)));
  626.     $box_x = $caption_x + $caption_width + 128;
  627.     $result = imagefilledrectangle($render_image, $box_x, $caption_y + 256, $box_x + 127, $caption_y + 383, 0x00);
  628.     assert(true === $result);
  629.     $size = 320;
  630.     if ('' === $description)
  631.     {
  632.         $text = 'France';
  633.     }
  634.     else
  635.     {
  636.         $text = html_entity_decode($description);
  637.     }
  638.     $text_box = imagettfbbox($size, 0, $font, $text);
  639.     assert(true === is_array($text_box));
  640.     assert(array(0, 1, 2, 3, 4, 5, 6, 7) === array_keys($text_box));
  641.     assert(array(true) === array_unique(array_map('is_integer', $text_box)));
  642.     $text_width = max($text_box[0], $text_box[2], $text_box[4], $text_box[6]) - min($text_box[0], $text_box[2], $text_box[4], $text_box[6]);
  643.     assert(0 < $text_width);
  644.     $result = imagettftext($render_image, $size, 0, $render_width - $text_width - 64, 384, 0x7F, $font, $text);
  645.     assert(true === is_array($result));
  646.     assert(array(0, 1, 2, 3, 4, 5, 6, 7) === array_keys($result));
  647.     assert(array(true) === array_unique(array_map('is_integer', $result)));
  648.     $result = imagesetthickness($render_image, 24);
  649.     assert(true === $result);
  650.     foreach ($line_map as $year => $point_map)
  651.     {
  652.         if (2020 === $year)
  653.         {
  654.             $color = 0;
  655.         }
  656.         else
  657.         {
  658.             $color = 240 + (8 * (2010 - $year));
  659.         }
  660.         $length = count($point_map);
  661.         $previous_x = null;
  662.         $previous_y = null;
  663.         foreach ($point_map as $index => $count)
  664.         {
  665.             if (true === $smooth)
  666.             {
  667.                 $smooth_begin = $index - 3;
  668.                 $smooth_end = $index + 4;
  669.                 $smooth_total = 0;
  670.                 for ($smooth_index = $smooth_begin; $smooth_end !== $smooth_index; ++$smooth_index)
  671.                 {
  672.                     if ($smooth_index < 0)
  673.                     {
  674.                         $smooth_year = $year - 1;
  675.                         $smooth_day = count($line_map[$smooth_year]) + $smooth_index;
  676.                     }
  677.                     else if ($length <= $smooth_index)
  678.                     {
  679.                         $smooth_year = $year + 1;
  680.                         $smooth_day = $smooth_index - $length;
  681.                     }
  682.                     else
  683.                     {
  684.                         $smooth_year = $year;
  685.                         $smooth_day = $smooth_index;
  686.                     }
  687.                     if ((true === array_key_exists($smooth_year, $line_map)) && (true === array_key_exists($smooth_day, $line_map[$smooth_year])))
  688.                     {
  689.                         $smooth_total += $line_map[$smooth_year][$smooth_day];
  690.                     }
  691.                     else
  692.                     {
  693.                         assert(true === in_array($smooth_year, array(2009, 2021), true));
  694.                         $smooth_total += $count;
  695.                     }
  696.                 }
  697.                 $count = $smooth_total / 7;
  698.             }
  699.  
  700.             $x = (int)(round(($index * ($render_width - 1)) / ($length - 1)));
  701.             $y = (int)(round((($maximum - $count) * ($render_height - 1)) / $maximum));
  702.             assert(0 <= $x);
  703.             assert($x < $render_width);
  704.             assert(0 <= $y);
  705.             assert($y < $render_height);
  706.             if (null === $previous_x)
  707.             {
  708.                 assert(null === $previous_y);
  709.                 $previous_x = $x;
  710.                 $previous_y = $y;
  711.             }
  712.             else
  713.             {
  714.                 assert(true === is_integer($previous_x));
  715.                 assert(true === is_integer($previous_y));
  716.                 imageline($render_image, $previous_x, $previous_y, $x, $y, $color);
  717.                 $previous_x = $x;
  718.                 $previous_y = $y;
  719.             }
  720.         }
  721.     }
  722.     $target_image = imagecreatetruecolor($target_width, $target_height);
  723.     assert(true === is_resource($target_image));
  724.     assert('gd' === get_resource_type($target_image));
  725.     assert(true === imageistruecolor($target_image));
  726.     $result = imagefilledrectangle($target_image, 0, 0, $target_width - 1, $target_height - 1, 0xFFFFFF);
  727.     assert(true === $result);
  728.     $result = imagefilledrectangle($target_image, $margin_size, $margin_size, $target_width - $margin_size - 1, $target_height - $margin_size - 1, 0xEEEEEE);
  729.     assert(true === $result);
  730.     $result = imagefilledrectangle($target_image, $margin_size + $border_size, $margin_size + $border_size, $target_width - $margin_size - $border_size - 1, $target_height - $margin_size - $border_size - 1, 0xFFFFFF);
  731.     assert(true === $result);
  732.     $result = imagecopyresampled
  733.     (
  734.         $target_image, $render_image,
  735.         $margin_size + $border_size + $padding_size, $margin_size + $border_size + $padding_size,
  736.         0, 0,
  737.         $target_width - (2 * ($margin_size + $border_size + $padding_size)), $target_height - (2 * ($margin_size + $border_size + $padding_size)),
  738.         $render_width, $render_height
  739.     );
  740.     assert(true === $result);
  741.     $result = imagedestroy($render_image);
  742.     assert(true === $result);
  743.     $result = imagepng($target_image, $target, 9, PNG_ALL_FILTERS);
  744.     assert(true === $result);
  745.     assert(true === is_file($target));
  746.     $result = imagedestroy($target_image);
  747.     assert(true === $result);
  748. }
  749.  
  750. $target = substr(__FILE__, 0, -4).'-6-curve.png';
  751. if (true !== is_file($target))
  752. {
  753.     render_curve($year_map, $target, 1000, 4000);
  754.     assert('ecfffb289bc3566293253794e1ddd50a1b479728' === sha1_file($target));
  755. }
  756.  
  757. $target = substr(__FILE__, 0, -4).'-6-curve-smooth.png';
  758. if (true !== is_file($target))
  759. {
  760.     render_curve($year_map, $target, 1000, 4000, true);
  761.     assert('880231127a76b14831d2a923f5d8defd4bf40dee' === sha1_file($target));
  762. }
  763.  
  764. foreach (array
  765. (
  766.     array(7, 'cbc2436af126ec845d3a73c500480e7372eee7cb', '1566de136bbdf7c6b9d5738bf3a1f9f30639a88d', 50, 250, '/^(?:22|29|35|56)/', 'Bretagne'),
  767.     array(7, 'aacd1fd074c2abbfeaa5abc4510d7a03e353048b', '3fc310ae037db308a0dfe8bcdd206467303032c2', 10, 40, '/^(?:2[AB])/', 'Corse'),
  768.     array(7, '4f64f3f505165873a957ba56f15788628c3942d8', '9e17b840c0dfb07075c1ffa845894ab165bc0e68', 250, 1000, '/^(?:75|77|78|91|92|93|94|95)/', '&Icirc;le-de-France'),
  769.     array(7, '100c84c8fc1f738899bc089b52982926d9b36ad9', '12146da9295b5ca72401d4c79954fbbd5ba623de', 50, 200, '/^(?:14|27|50|61|76)/', 'Normandie'),
  770.     array(7, '7b02cdb74cd67dfaf9e061aad2844659ae6a8d3f', 'ca8ec1efaccb4ace8ba276f9082d088e3dd6e4cc', 100, 400, '/^(?:04|05|06|13|83|84)/', 'Provence-Alpes-C&ocirc;te d\'Azur'),
  771.  
  772.     array(8, '0fa8c7a90ec44dfb8c3408a76a4a1978ae495f6f', 'a208fb3eb39ddb1a0c042a08ad60ca022d858799', 50, 200, '/^13/', 'Bouches-du-Rh&ocirc;ne'),
  773.     array(8, '4acf0cb6dde4a30e63ac9efbcb4c74ef0b309ac6', '1ccc54797ab6539788743e52533c08e2a55f1581', 25, 100, '/^35/', 'Ille-et-Vilaine'),
  774.     array(8, '6d46d2e8da152dd7f934ffb9f1f359a44e5f4957', '43d8ec96f53446191c67c0b218c212404b9a3b62', 25, 100, '/^57/', 'Moselle'),
  775.     array(8, '4e685ef8eeb0d97f3da4c158bdc76fa0d785f0e7', '98b6dfe0c855208b20dcc0126af313201335eabd', 25, 100, '/^68/', 'Haut-Rhin'),
  776.  
  777.     array(9, 'a0a5147ad958f1d76ab9820d50ae42dc5a683d17', '78b67c3d0774875cba36d0c7907d054c1809bf09', 10,  50, '/^69(?:00[1-9]|123|38[1-9])$/', 'Lyon'),
  778.     array(9, '380e78d3e9b0f2a4b67360537d3e0c5a79ad53ba', '2e22d83bf4ee078ab94021ddf526f198cc77aaee', 10,  40, '/^130(?:0[1-9]|1[0-6])$/', 'Marseille'),
  779.     array(9, '75d405c7ffde8725129bb1abda1de4bdba740771', 'f651bc1f2328e6877f85b0305a2f4773e24547ad', 50, 200, '/^75/', 'Paris'),
  780.     array(9, 'f1d7eb39494aaa421cfc507c26720a065ca7bb6d', '8d8a06262fa2d47c3503a053b99bbfb7144e5042', 10,  30, '/^35(?:[027]00|238)$/', 'Rennes'),
  781. )
  782. as $list)
  783. {
  784.     list($group, $hash_sharp, $hash_smooth, $step, $maximum, $filter, $description) = $list;
  785.     $name = strtolower(preg_replace('/&([A-Za-z])(?:acute|circ);/', '\1', $description));
  786.     $target = substr(__FILE__, 0, -4).'-'.$group.'-curve-'.$name.'.png';
  787.     if (true !== is_file($target))
  788.     {
  789.         render_curve($year_map, $target, $step, $maximum, false, $filter, $description);
  790.         assert($hash_sharp === sha1_file($target));
  791.     }
  792.     $target = substr(__FILE__, 0, -4).'-'.$group.'-curve-'.$name.'-smooth.png';
  793.     if (true !== is_file($target))
  794.     {
  795.         render_curve($year_map, $target, $step, $maximum, true, $filter, $description);
  796.         assert($hash_smooth === sha1_file($target));
  797.     }
  798. }
  799.  
  800.  
Advertisement
Add Comment
Please, Sign In to add comment