Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add population weight #1

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"php": ">=7.2.5",
"ext-ctype": "*",
"ext-iconv": "*",
"ext-json": "*",
"composer/package-versions-deprecated": "1.11.99.1",
"doctrine/annotations": "^1.0",
"doctrine/doctrine-bundle": "^2.2",
Expand Down
2 changes: 2 additions & 0 deletions config/packages/framework.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,5 @@ framework:
#fragments: true
php_errors:
log: true
cache:
app: cache.adapter.array
74 changes: 37 additions & 37 deletions data/cantons.csv
Original file line number Diff line number Diff line change
@@ -1,37 +1,37 @@
id;canton;text;language
AG;AG;Alle Schulen, kant. Daten;de
AI1;AI;Alle Schulen;de
AI2;AI;Oberegg;de
AR;AR;Alle Schulen;de
BE1;BE;BE-d: Kindergarten, Volksschulen;de
BE2;BE;BE-f: Ecole obligatoire;fr
BL;BL;Alle Schulen;de
BS;BS;Alle Schulen;de
FL;FL;Alle Schulen;de
FR1;FR;Ecoles primaires (ville);fr
FR2;FR;Ecoles sec. II;fr
GE;GE;Toutes les écoles;fr
GL;GL;Alle Schulen;de
GR1;GR;Bündner Kantonsschule;de
GR2;GR;Chur Volksschule;de
GR3;GR;Davos Volksschule;de
GR4;GR;Mesolcina;de
JU;JU;Ecoles publiques;fr
LU;LU;Alle Schulen;de
NE;NE;Ecole obligatoire;fr
NW1;NW;Mittelschule;de
NW2;NW;Volksschule;de
OW1;OW;Alle Schulen ausser Engelberg;de
OW2;OW;Engelberg Volksschule und Gymnasium;de
SG;SG;Alle Schulen;de
SH;SH;Alle Schulen;de
SO;SO;Mittel- und Berufsschulen;de
SZ;SZ;Volksschule;de
TG;TG;Alle Schulen;de
TI;TI;Tutte le scuole;it
UR;UR;Alle Schulen;de
VD;VD;Toutes les écoles;fr
VS1;VS;Oberwallis;de
VS2;VS;Romand;fr
ZG;ZG;Öffentlich-rechtliche Schulen;de
ZH;ZH;Alle Schulen;de
id;canton;text;language;weight.count;weight.population
AG;AG;Alle Schulen, kant. Daten;de;1;678207
AI1;AI;Alle Schulen;de;0.5;27617
AI2;AI;Oberegg;de;0.5;27617
AR;AR;Alle Schulen;de;1;16145
BE1;BE;BE-d: Kindergarten, Volksschulen;de;0.5;517488
BE2;BE;BE-f: Ecole obligatoire;fr;0.5;517489
BL;BL;Alle Schulen;de;1;194766
BS;BS;Alle Schulen;de;1;288132
FL;FL;Alle Schulen;de;1;38749
FR1;FR;Ecoles primaires (ville);fr;0.5;159357
FR2;FR;Ecoles sec. II;fr;0.5;159357
GE;GE;Toutes les écoles;fr;1;499480
GL;GL;Alle Schulen;de;1;40403
GR1;GR;Bündner Kantonsschule;de;0.25;49595
GR2;GR;Chur Volksschule;de;0.25;49595
GR3;GR;Davos Volksschule;de;0.25;49595
GR4;GR;Mesolcina;de;0.25;49594
JU;JU;Ecoles publiques;fr;1;73419
LU;LU;Alle Schulen;de;1;409557
NE;NE;Ecole obligatoire;fr;1;176850
NW1;NW;Mittelschule;de;1;21611
NW2;NW;Volksschule;de;1;21612
OW1;OW;Alle Schulen ausser Engelberg;de;1;18920
OW2;OW;Engelberg Volksschule und Gymnasium;de;1;18921
SG;SG;Alle Schulen;de;1;507697
SH;SH;Alle Schulen;de;1;81991
SO;SO;Mittel- und Berufsschulen;de;1;273194
SZ;SZ;Volksschule;de;1;159165
TG;TG;Alle Schulen;de;1;276472
TI;TI;Tutte le scuole;it;1;353343
UR;UR;Alle Schulen;de;1;36433
VD;VD;Toutes les écoles;fr;1;799145
VS1;VS;Oberwallis;de;0.5;171977
VS2;VS;Romand;fr;0.5;171977
ZG;ZG;Öffentlich-rechtliche Schulen;de;1;126837
ZH;ZH;Alle Schulen;de;1;1520968
22 changes: 12 additions & 10 deletions src/Controller/AppController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace App\Controller;

use App\Domain\Canton;
use App\Domain\HolidayManager;
use App\Form\HolidayFormType;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
Expand Down Expand Up @@ -31,17 +32,14 @@ public function data(Request $request, HolidayManager $holidayManager): Response
$form = $this->createForm(HolidayFormType::class);
$form->handleRequest($request);

$dates = $form->isSubmitted() && $form->isValid()
? $holidayManager->getDatesByCantons($form->getData()['cantons'])
: $holidayManager->getDates()
;

$heatmap = [];
foreach ($dates as $date) {
$heatmap[$date->getTimestamp()] = ($heatmap[$date->getTimestamp()] ?? 0) + 1;
$cantons = [];
$weightType = Canton::WEIGHT_TYPE_COUNT;
if ($form->isSubmitted() && $form->isValid()) {
$cantons = $form->getData()['cantons'];
$weightType = $form->getData()['canton_weight_type'];
}

return $this->json($heatmap);
return $this->json($holidayManager->getWeightedTimestamps($weightType, $cantons));
}


Expand All @@ -50,6 +48,10 @@ public function data(Request $request, HolidayManager $holidayManager): Response
*/
public function cantons(\DateTime $date, HolidayManager $holidayManager): Response
{
return $this->json($holidayManager->getCantonsByDate($date));
$cantons = array_map(function (Canton $canton) {
return $canton->id;
}, $holidayManager->getCantonsByDate($date));

return $this->json($cantons);
}
}
4 changes: 4 additions & 0 deletions src/Domain/Canton.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,14 @@

class Canton
{
const WEIGHT_TYPE_COUNT = 'count';
const WEIGHT_TYPE_POPULATION = 'population';

public $id;
public $canton;
public $text;
public $language;
public $weight;

public function __toString(): string
{
Expand Down
7 changes: 6 additions & 1 deletion src/Domain/Holiday.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,18 @@ class Holiday
{
public $cantonId;
public $periods;
private $dates;

/**
* @return \DateTime[]
*/
public function getDates(): array
{
return array_merge(...array_map(function ($range) {
if (null !== $this->dates) {
return $this->dates;
}

return $this->dates = array_merge(...array_map(function ($range) {
[$start, $end] = explode('-', $range);

return iterator_to_array(new \DatePeriod(new \DateTime($start), new \DateInterval('P1D'), new \DateTime($end)));
Expand Down
64 changes: 49 additions & 15 deletions src/Domain/HolidayManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,42 +4,49 @@

use Symfony\Component\Finder\Finder;
use Symfony\Component\Serializer\SerializerInterface;
use Symfony\Contracts\Cache\CacheInterface;
use Symfony\Contracts\Cache\ItemInterface;

class HolidayManager
{
private $serializer;
private $projectDir;
private $cache;

public function __construct(SerializerInterface $serializer, $projectDir)
public function __construct(SerializerInterface $serializer, $projectDir, CacheInterface $cache)
{
$this->serializer = $serializer;
$this->projectDir = $projectDir;
$this->cache = $cache;
}

/**
* @return Holiday[]
*/
public function getHolidays(): array
{
$finder = (new Finder())
->in($this->projectDir.'/data/holidays')
;
return $this->cache->get('holidays', function (ItemInterface $item) {
$finder = (new Finder())
->in($this->projectDir.'/data/holidays')
;

$holidays = [];
foreach ($finder as $file) {
$holidays[] = $this->serializer->deserialize($file->getContents(), Holiday::class.'[]', 'csv');
}
$holidays = [];
foreach ($finder as $file) {
$holidays[] = $this->serializer->deserialize($file->getContents(), Holiday::class.'[]', 'csv');
}

return array_merge(...$holidays);
return array_merge(...$holidays);
});
}

/**
* @return Canton[]
*/
public function getCantons(): array
{
return $this->serializer->deserialize(file_get_contents($this->projectDir.'/data/cantons.csv'), Canton::class.'[]', 'csv');

return $this->cache->get('cantons', function (ItemInterface $item) {
return $this->serializer->deserialize(file_get_contents($this->projectDir.'/data/cantons.csv'), Canton::class.'[]', 'csv');
});
}

public function getCanton(string $id): Canton
Expand Down Expand Up @@ -72,17 +79,44 @@ public function getDatesByCantons(array $cantons = []): array
}

/**
* @return string[]
* @return Canton[]
*/
public function getCantonsByDate(\DateTime $date): array
{
$filtered = array_filter($this->getHolidays(), function (Holiday $holiday) use ($date) {
return in_array($date, $holiday->getDates(), false);
});

return array_values(array_map(function (Holiday $holiday) {
return $holiday->cantonId;
}, $filtered));
return array_map(function (Holiday $holiday) {
return $this->getCanton($holiday->cantonId);
}, $filtered);
}

/**
* @param Canton[] $cantons
*/
public function getWeightedTimestamps(string $weightType, array $cantons = []): array
{
$timestamps = [];
foreach ($this->getHolidays() as $holiday) {
$canton = $this->getCanton($holiday->cantonId);
if ($cantons && !in_array($canton, $cantons, false)) {
continue;
}
$weight = $canton->weight[$weightType];
foreach ($holiday->getDates() as $date) {
$timestamps[$date->getTimestamp()] = ($timestamps[$date->getTimestamp()] ?? 0) + $weight;
}
}

return $timestamps;
}

public function getBoundariesWeights(string $weightType): array
{
$timestamps = $this->getWeightedTimestamps($weightType);

return [min($timestamps), max($timestamps)];
}

/**
Expand Down
18 changes: 18 additions & 0 deletions src/Form/HolidayFormType.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,24 @@ public function buildForm(FormBuilderInterface $builder, array $options)
return s($canton->language)->upper();
}
])
->add('canton_weight_type', ChoiceType::class, [
'choices' => [
'by cantons count' => Canton::WEIGHT_TYPE_COUNT,
'by cantons population' => Canton::WEIGHT_TYPE_POPULATION,
],
'choice_attr' => [
'by cantons count' => ['data-legend' => json_encode($this->legend(Canton::WEIGHT_TYPE_COUNT))],
'by cantons population' => ['data-legend' => json_encode($this->legend(Canton::WEIGHT_TYPE_POPULATION))],
],
'help' => 'Defines the weight of each canton on the heatmap',
])
;
}

private function legend(string $weightType): array
{
[$min, $max] = $this->holidayManager->getBoundariesWeights($weightType);

return array_map('ceil', range($min, $max, ($max - $min) / 3));
}
}
6 changes: 5 additions & 1 deletion templates/app/index.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
{% block javascripts %}
{{ parent() }}
<script type="text/javascript">
var $options = $('select option');
var $options = $('select#holiday_form_cantons option');
var cal = new CalHeatMap();
cal.init({
domain: "month",
Expand Down Expand Up @@ -87,5 +87,9 @@
$('#year').get(0).text++;
resetCantons();
}
$('select#holiday_form_canton_weight_type').change(function() {
var legend = $(this).children("option:selected").data('legend');
cal.setLegend(legend);
});
</script>
{% endblock %}