infos de fraicheur de données
This commit is contained in:
parent
4eb95d5b95
commit
b41bbc9696
6 changed files with 573 additions and 0 deletions
|
@ -13,6 +13,8 @@ use App\Service\Motocultrice;
|
|||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use function uuid_create;
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
|
||||
final class AdminController extends AbstractController
|
||||
{
|
||||
|
@ -781,4 +783,158 @@ final class AdminController extends AbstractController
|
|||
$this->addFlash('success', 'Email envoyé avec succès à ' . $place->getName() . ' le ' . $place->getLastContactAttemptDate()->format('d/m/Y H:i:s'));
|
||||
return $this->redirectToRoute('app_public_index');
|
||||
}
|
||||
|
||||
#[Route('/admin/fraicheur/histogramme', name: 'admin_fraicheur_histogramme')]
|
||||
public function showFraicheurHistogramme(): Response
|
||||
{
|
||||
$jsonPath = $this->getParameter('kernel.project_dir') . '/var/fraicheur_osm.json';
|
||||
if (!file_exists($jsonPath)) {
|
||||
// Générer le fichier si absent
|
||||
$this->calculateFraicheur();
|
||||
}
|
||||
return $this->render('admin/fraicheur_histogramme.html.twig');
|
||||
}
|
||||
|
||||
#[Route('/admin/fraicheur/calculate', name: 'admin_fraicheur_calculate')]
|
||||
public function calculateFraicheur(): Response
|
||||
{
|
||||
$filesystem = new Filesystem();
|
||||
$jsonPath = $this->getParameter('kernel.project_dir') . '/var/fraicheur_osm.json';
|
||||
$now = new \DateTime();
|
||||
// Si le fichier existe et a moins de 12h, on ne régénère pas
|
||||
if ($filesystem->exists($jsonPath)) {
|
||||
$fileMTime = filemtime($jsonPath);
|
||||
if ($fileMTime && ($now->getTimestamp() - $fileMTime) < 43200) { // 12h = 43200s
|
||||
return $this->redirectToRoute('admin_fraicheur_histogramme');
|
||||
}
|
||||
}
|
||||
$places = $this->entityManager->getRepository(Place::class)->findAll();
|
||||
$histogram = [];
|
||||
$total = 0;
|
||||
foreach ($places as $place) {
|
||||
$date = $place->getOsmDataDate();
|
||||
if ($date) {
|
||||
$key = $date->format('Y-m');
|
||||
if (!isset($histogram[$key])) {
|
||||
$histogram[$key] = 0;
|
||||
}
|
||||
$histogram[$key]++;
|
||||
$total++;
|
||||
}
|
||||
}
|
||||
ksort($histogram);
|
||||
$data = [
|
||||
'generated_at' => $now->format('c'),
|
||||
'total' => $total,
|
||||
'histogram' => $histogram
|
||||
];
|
||||
$filesystem->dumpFile($jsonPath, json_encode($data, JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE));
|
||||
|
||||
// --- Distribution villes selon lieux/habitants ---
|
||||
$distJsonPath = $this->getParameter('kernel.project_dir') . '/var/distribution_villes_lieux_par_habitant.json';
|
||||
// Toujours régénérer
|
||||
$statsRepo = $this->entityManager->getRepository(Stats::class);
|
||||
$allStats = $statsRepo->findAll();
|
||||
$histogram_lieux_par_habitant = [];
|
||||
$histogram_habitants_par_lieu = [];
|
||||
$totalVilles = 0;
|
||||
foreach ($allStats as $stat) {
|
||||
$places = $stat->getPlacesCount();
|
||||
$population = $stat->getPopulation();
|
||||
if ($places && $population && $population > 0) {
|
||||
// lieux par habitant (pas de 0.01)
|
||||
$ratio_lph = round($places / $population, 4);
|
||||
$bin_lph = round(floor($ratio_lph / 0.01) * 0.01, 2);
|
||||
if (!isset($histogram_lieux_par_habitant[$bin_lph])) $histogram_lieux_par_habitant[$bin_lph] = 0;
|
||||
$histogram_lieux_par_habitant[$bin_lph]++;
|
||||
// habitants par lieu (pas de 10)
|
||||
$ratio_hpl = ceil($population / $places);
|
||||
$bin_hpl = ceil($ratio_hpl / 10) * 10;
|
||||
if (!isset($histogram_habitants_par_lieu[$bin_hpl])) $histogram_habitants_par_lieu[$bin_hpl] = 0;
|
||||
$histogram_habitants_par_lieu[$bin_hpl]++;
|
||||
$totalVilles++;
|
||||
}
|
||||
}
|
||||
ksort($histogram_lieux_par_habitant);
|
||||
ksort($histogram_habitants_par_lieu);
|
||||
$distData = [
|
||||
'generated_at' => $now->format('c'),
|
||||
'total_villes' => $totalVilles,
|
||||
'histogram_001' => $histogram_lieux_par_habitant,
|
||||
'histogram_10' => $histogram_habitants_par_lieu
|
||||
];
|
||||
$filesystem->dumpFile($distJsonPath, json_encode($distData, JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE));
|
||||
|
||||
return $this->redirectToRoute('admin_fraicheur_histogramme');
|
||||
}
|
||||
|
||||
#[Route('/admin/fraicheur/download', name: 'admin_fraicheur_download')]
|
||||
public function downloadFraicheur(): JsonResponse
|
||||
{
|
||||
$jsonPath = $this->getParameter('kernel.project_dir') . '/var/fraicheur_osm.json';
|
||||
if (!file_exists($jsonPath)) {
|
||||
return new JsonResponse(['error' => 'Fichier non généré'], 404);
|
||||
}
|
||||
$content = file_get_contents($jsonPath);
|
||||
$data = json_decode($content, true);
|
||||
return new JsonResponse($data);
|
||||
}
|
||||
|
||||
#[Route('/admin/distribution_villes_lieux_par_habitant_download', name: 'admin_distribution_villes_lieux_par_habitant_download')]
|
||||
public function downloadDistributionVillesLieuxParHabitant(): JsonResponse
|
||||
{
|
||||
$jsonPath = $this->getParameter('kernel.project_dir') . '/var/distribution_villes_lieux_par_habitant.json';
|
||||
if (!file_exists($jsonPath)) {
|
||||
// Générer à la volée si absent
|
||||
$now = new \DateTime();
|
||||
$filesystem = new \Symfony\Component\Filesystem\Filesystem();
|
||||
$statsRepo = $this->entityManager->getRepository(\App\Entity\Stats::class);
|
||||
$allStats = $statsRepo->findAll();
|
||||
$distribution = [];
|
||||
$histogram = [];
|
||||
$totalVilles = 0;
|
||||
foreach ($allStats as $stat) {
|
||||
$places = $stat->getPlacesCount();
|
||||
$population = $stat->getPopulation();
|
||||
if ($places && $population && $population > 0) {
|
||||
$ratio = round($places / $population, 4); // lieux par habitant
|
||||
$bin = round(floor($ratio / 0.01) * 0.01, 2); // pas de 0.01
|
||||
if (!isset($histogram[$bin])) $histogram[$bin] = 0;
|
||||
$histogram[$bin]++;
|
||||
$totalVilles++;
|
||||
}
|
||||
}
|
||||
ksort($histogram);
|
||||
$distData = [
|
||||
'generated_at' => $now->format('c'),
|
||||
'total_villes' => $totalVilles,
|
||||
'histogram_001' => $histogram
|
||||
];
|
||||
$filesystem->dumpFile($jsonPath, json_encode($distData, JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE));
|
||||
}
|
||||
$content = file_get_contents($jsonPath);
|
||||
$data = json_decode($content, true);
|
||||
return new JsonResponse($data);
|
||||
}
|
||||
|
||||
#[Route('/admin/distribution_villes_lieux_par_habitant_villes', name: 'admin_distribution_villes_lieux_par_habitant_villes')]
|
||||
public function downloadDistributionVillesLieuxParHabitantVilles(): JsonResponse
|
||||
{
|
||||
$statsRepo = $this->entityManager->getRepository(\App\Entity\Stats::class);
|
||||
$allStats = $statsRepo->findAll();
|
||||
$villesByBin = [];
|
||||
foreach ($allStats as $stat) {
|
||||
$places = $stat->getPlacesCount();
|
||||
$population = $stat->getPopulation();
|
||||
$name = $stat->getName();
|
||||
if ($places && $population && $population > 0 && $name) {
|
||||
$ratio = round($places / $population, 4); // lieux par habitant
|
||||
$bin = round(floor($ratio / 0.01) * 0.01, 2); // pas de 0.01
|
||||
if (!isset($villesByBin[$bin])) $villesByBin[$bin] = [];
|
||||
$villesByBin[$bin][] = $name;
|
||||
}
|
||||
}
|
||||
ksort($villesByBin);
|
||||
return new JsonResponse(['villes_by_bin' => $villesByBin]);
|
||||
}
|
||||
}
|
||||
|
|
143
src/Controller/FraicheurController.php
Normal file
143
src/Controller/FraicheurController.php
Normal file
|
@ -0,0 +1,143 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use App\Entity\Place;
|
||||
use App\Entity\Stats;
|
||||
|
||||
class FraicheurController extends AbstractController
|
||||
{
|
||||
public function __construct(private EntityManagerInterface $entityManager) {}
|
||||
|
||||
#[Route('/admin/fraicheur/histogramme', name: 'admin_fraicheur_histogramme')]
|
||||
public function showFraicheurHistogramme(): Response
|
||||
{
|
||||
$jsonPath = $this->getParameter('kernel.project_dir') . '/var/fraicheur_osm.json';
|
||||
if (!file_exists($jsonPath)) {
|
||||
$this->calculateFraicheur();
|
||||
}
|
||||
return $this->render('admin/fraicheur_histogramme.html.twig');
|
||||
}
|
||||
|
||||
#[Route('/admin/fraicheur/calculate', name: 'admin_fraicheur_calculate')]
|
||||
public function calculateFraicheur(): Response
|
||||
{
|
||||
$filesystem = new Filesystem();
|
||||
$jsonPath = $this->getParameter('kernel.project_dir') . '/var/fraicheur_osm.json';
|
||||
$now = new \DateTime();
|
||||
$places = $this->entityManager->getRepository(Place::class)->findAll();
|
||||
$histogram = [];
|
||||
$total = 0;
|
||||
foreach ($places as $place) {
|
||||
$date = $place->getOsmDataDate();
|
||||
if ($date) {
|
||||
$key = $date->format('Y-m');
|
||||
if (!isset($histogram[$key])) {
|
||||
$histogram[$key] = 0;
|
||||
}
|
||||
$histogram[$key]++;
|
||||
$total++;
|
||||
}
|
||||
}
|
||||
ksort($histogram);
|
||||
$data = [
|
||||
'generated_at' => $now->format('c'),
|
||||
'total' => $total,
|
||||
'histogram' => $histogram
|
||||
];
|
||||
$filesystem->dumpFile($jsonPath, json_encode($data, JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE));
|
||||
|
||||
// --- Distribution villes selon lieux/habitants ---
|
||||
$distJsonPath = $this->getParameter('kernel.project_dir') . '/var/distribution_villes_lieux_par_habitant.json';
|
||||
$statsRepo = $this->entityManager->getRepository(Stats::class);
|
||||
$allStats = $statsRepo->findAll();
|
||||
$histogram_lieux_par_habitant = [];
|
||||
$histogram_habitants_par_lieu = [];
|
||||
$villesByBinLph = [];
|
||||
$villesByBinHpl = [];
|
||||
$totalVilles = 0;
|
||||
foreach ($allStats as $stat) {
|
||||
$places = $stat->getPlacesCount();
|
||||
$population = $stat->getPopulation();
|
||||
$name = $stat->getName();
|
||||
if ($places && $population && $population > 0 && $name) {
|
||||
// lieux par habitant (pas de 0.01)
|
||||
$ratio_lph = $places / $population;
|
||||
$bin_lph = number_format(floor($ratio_lph / 0.01) * 0.01, 2, '.', '');
|
||||
if (!isset($histogram_lieux_par_habitant[$bin_lph])) $histogram_lieux_par_habitant[$bin_lph] = 0;
|
||||
$histogram_lieux_par_habitant[$bin_lph]++;
|
||||
if (!isset($villesByBinLph[$bin_lph])) $villesByBinLph[$bin_lph] = [];
|
||||
$villesByBinLph[$bin_lph][] = $name;
|
||||
// habitants par lieu (pas de 10)
|
||||
$ratio_hpl = $population / $places;
|
||||
$bin_hpl = (string)(ceil($ratio_hpl / 10) * 10);
|
||||
if (!isset($histogram_habitants_par_lieu[$bin_hpl])) $histogram_habitants_par_lieu[$bin_hpl] = 0;
|
||||
$histogram_habitants_par_lieu[$bin_hpl]++;
|
||||
if (!isset($villesByBinHpl[$bin_hpl])) $villesByBinHpl[$bin_hpl] = [];
|
||||
$villesByBinHpl[$bin_hpl][] = $name;
|
||||
$totalVilles++;
|
||||
}
|
||||
}
|
||||
ksort($histogram_lieux_par_habitant);
|
||||
ksort($histogram_habitants_par_lieu);
|
||||
ksort($villesByBinLph);
|
||||
ksort($villesByBinHpl);
|
||||
$distData = [
|
||||
'generated_at' => $now->format('c'),
|
||||
'total_villes' => $totalVilles,
|
||||
'histogram_001' => $histogram_lieux_par_habitant,
|
||||
'histogram_10' => $histogram_habitants_par_lieu,
|
||||
'villes_by_bin_001' => $villesByBinLph,
|
||||
'villes_by_bin_10' => $villesByBinHpl
|
||||
];
|
||||
$filesystem->dumpFile($distJsonPath, json_encode($distData, JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE));
|
||||
|
||||
return $this->redirectToRoute('admin_fraicheur_histogramme');
|
||||
}
|
||||
|
||||
#[Route('/admin/fraicheur/download', name: 'admin_fraicheur_download')]
|
||||
public function downloadFraicheur(): JsonResponse
|
||||
{
|
||||
$jsonPath = $this->getParameter('kernel.project_dir') . '/var/fraicheur_osm.json';
|
||||
if (!file_exists($jsonPath)) {
|
||||
return new JsonResponse(['error' => 'Fichier non généré'], 404);
|
||||
}
|
||||
$content = file_get_contents($jsonPath);
|
||||
$data = json_decode($content, true);
|
||||
return new JsonResponse($data);
|
||||
}
|
||||
|
||||
#[Route('/admin/distribution_villes_lieux_par_habitant_download', name: 'admin_distribution_villes_lieux_par_habitant_download')]
|
||||
public function downloadDistributionVillesLieuxParHabitant(): JsonResponse
|
||||
{
|
||||
$jsonPath = $this->getParameter('kernel.project_dir') . '/var/distribution_villes_lieux_par_habitant.json';
|
||||
if (!file_exists($jsonPath)) {
|
||||
$this->calculateFraicheur();
|
||||
}
|
||||
$content = file_get_contents($jsonPath);
|
||||
$data = json_decode($content, true);
|
||||
return new JsonResponse($data);
|
||||
}
|
||||
|
||||
#[Route('/admin/distribution_villes_lieux_par_habitant_villes', name: 'admin_distribution_villes_lieux_par_habitant_villes')]
|
||||
public function downloadDistributionVillesLieuxParHabitantVilles(): JsonResponse
|
||||
{
|
||||
$jsonPath = $this->getParameter('kernel.project_dir') . '/var/distribution_villes_lieux_par_habitant.json';
|
||||
if (!file_exists($jsonPath)) {
|
||||
$this->calculateFraicheur();
|
||||
}
|
||||
$content = file_get_contents($jsonPath);
|
||||
$data = json_decode($content, true);
|
||||
// On renvoie les deux listes de villes par bin
|
||||
return new JsonResponse([
|
||||
'villes_by_bin_001' => $data['villes_by_bin_001'] ?? [],
|
||||
'villes_by_bin_10' => $data['villes_by_bin_10'] ?? []
|
||||
]);
|
||||
}
|
||||
}
|
260
templates/admin/fraicheur_histogramme.html.twig
Normal file
260
templates/admin/fraicheur_histogramme.html.twig
Normal file
|
@ -0,0 +1,260 @@
|
|||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block title %}Histogramme de fraîcheur OSM{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<div class="container mt-4">
|
||||
<h1>Histogramme de fraîcheur des données OSM</h1>
|
||||
<h2>Par année</h2>
|
||||
<canvas id="fraicheurHistogrammeAnnee" width="800" height="400" style="max-width:100%; margin: 20px 0;"></canvas>
|
||||
<h2>Par trimestre</h2>
|
||||
<canvas id="fraicheurHistogrammeTrimestre" width="800" height="400" style="max-width:100%; margin: 20px 0;"></canvas>
|
||||
|
||||
<h2>Par mois</h2>
|
||||
<canvas id="fraicheurHistogramme" width="800" height="400" style="max-width:100%; margin: 20px 0;"></canvas>
|
||||
|
||||
<h2>Distribution des villes selon le nombre d'habitants par lieu (par pas de 10)</h2>
|
||||
<canvas id="distributionHabitantsParLieu" width="800" height="400" style="max-width:100%; margin: 20px 0;"></canvas>
|
||||
<div id="fraicheurMeta" class="mb-3"></div>
|
||||
<a href="{{ path('admin_fraicheur_calculate') }}" class="btn btn-primary">Régénérer les statistiques</a>
|
||||
<a href="{{ path('admin_fraicheur_download') }}" class="btn btn-secondary">Télécharger le JSON des lieux</a>
|
||||
<a href="{{ path('admin_distribution_villes_lieux_par_habitant_download') }}" class="btn btn-secondary">Télécharger le JSON villes/lieux/habitant</a>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block javascripts %}
|
||||
{{ parent() }}
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
fetch('/admin/fraicheur/download')
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
if(data.error){
|
||||
document.getElementById('fraicheurMeta').innerHTML = '<div class="alert alert-danger">'+data.error+'</div>';
|
||||
return;
|
||||
}
|
||||
const ctx = document.getElementById('fraicheurHistogramme').getContext('2d');
|
||||
const labels = Object.keys(data.histogram);
|
||||
const values = Object.values(data.histogram);
|
||||
document.getElementById('fraicheurMeta').innerHTML =
|
||||
'<b>Date de génération :</b> ' + data.generated_at + '<br>' +
|
||||
'<b>Total lieux :</b> ' + data.total;
|
||||
new Chart(ctx, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: labels,
|
||||
datasets: [{
|
||||
label: 'Nombre de lieux modifiés ce mois',
|
||||
data: values,
|
||||
backgroundColor: 'rgba(54, 162, 235, 0.7)',
|
||||
borderColor: 'rgba(54, 162, 235, 1)',
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: true,
|
||||
plugins: {
|
||||
legend: { display: false },
|
||||
title: { display: true, text: 'Fraîcheur des données OSM (par mois)' }
|
||||
},
|
||||
scales: {
|
||||
y: { beginAtZero: true, title: { display: true, text: 'Nombre de lieux' } },
|
||||
x: { title: { display: true, text: 'Mois' } }
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Agrégation par trimestre
|
||||
const trimestreAgg = {};
|
||||
for(const key in data.histogram){
|
||||
// key = YYYY-MM
|
||||
const [year, month] = key.split('-');
|
||||
const m = parseInt(month, 10);
|
||||
let trimestre = 1;
|
||||
if(m >= 4 && m <= 6) trimestre = 2;
|
||||
else if(m >= 7 && m <= 9) trimestre = 3;
|
||||
else if(m >= 10 && m <= 12) trimestre = 4;
|
||||
const trimestreKey = `${year}-T${trimestre}`;
|
||||
if(!trimestreAgg[trimestreKey]) trimestreAgg[trimestreKey] = 0;
|
||||
trimestreAgg[trimestreKey] += data.histogram[key];
|
||||
}
|
||||
const trimestreLabels = Object.keys(trimestreAgg).sort();
|
||||
const trimestreValues = trimestreLabels.map(k => trimestreAgg[k]);
|
||||
const ctxTrim = document.getElementById('fraicheurHistogrammeTrimestre').getContext('2d');
|
||||
new Chart(ctxTrim, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: trimestreLabels,
|
||||
datasets: [{
|
||||
label: 'Nombre de lieux modifiés ce trimestre',
|
||||
data: trimestreValues,
|
||||
backgroundColor: 'rgba(255, 159, 64, 0.7)',
|
||||
borderColor: 'rgba(255, 159, 64, 1)',
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: true,
|
||||
plugins: {
|
||||
legend: { display: false },
|
||||
title: { display: true, text: 'Fraîcheur des données OSM (par trimestre)' }
|
||||
},
|
||||
scales: {
|
||||
y: { beginAtZero: true, title: { display: true, text: 'Nombre de lieux' } },
|
||||
x: { title: { display: true, text: 'Trimestre' } }
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Agrégation par année
|
||||
const anneeAgg = {};
|
||||
for(const key in data.histogram){
|
||||
// key = YYYY-MM
|
||||
const [year] = key.split('-');
|
||||
if(!anneeAgg[year]) anneeAgg[year] = 0;
|
||||
anneeAgg[year] += data.histogram[key];
|
||||
}
|
||||
const anneeLabels = Object.keys(anneeAgg).sort();
|
||||
const anneeValues = anneeLabels.map(k => anneeAgg[k]);
|
||||
const ctxAnnee = document.getElementById('fraicheurHistogrammeAnnee').getContext('2d');
|
||||
new Chart(ctxAnnee, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: anneeLabels,
|
||||
datasets: [{
|
||||
label: 'Nombre de lieux modifiés cette année',
|
||||
data: anneeValues,
|
||||
backgroundColor: 'rgba(75, 192, 192, 0.7)',
|
||||
borderColor: 'rgba(75, 192, 192, 1)',
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: true,
|
||||
plugins: {
|
||||
legend: { display: false },
|
||||
title: { display: true, text: 'Fraîcheur des données OSM (par année)' }
|
||||
},
|
||||
scales: {
|
||||
y: { beginAtZero: true, title: { display: true, text: 'Nombre de lieux' } },
|
||||
x: { title: { display: true, text: 'Année' } }
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Histogramme distribution villes/lieux/habitant
|
||||
fetch('/admin/distribution_villes_lieux_par_habitant_download')
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
if(data.error){
|
||||
document.getElementById('distributionVillesLieuxParHabitant').insertAdjacentHTML('afterend', '<div class="alert alert-danger">Erreur de chargement des données : '+data.error+'</div>');
|
||||
return;
|
||||
}
|
||||
// Histogramme habitants par lieu (pas de 10)
|
||||
fetch('/admin/distribution_villes_lieux_par_habitant_villes')
|
||||
.then(r2 => r2.json())
|
||||
.then(villesData => {
|
||||
// Histogramme habitants par lieu
|
||||
if(!data.histogram_10){
|
||||
document.getElementById('distributionHabitantsParLieu').insertAdjacentHTML('afterend', '<div class="alert alert-danger">Erreur : données histogram_10 absentes. Cliquez sur "Régénérer les statistiques".</div>');
|
||||
return;
|
||||
}
|
||||
const ctxHPL = document.getElementById('distributionHabitantsParLieu').getContext('2d');
|
||||
const labelsHPL = Object.keys(data.histogram_10);
|
||||
const valuesHPL = Object.values(data.histogram_10);
|
||||
const villesByBin10 = villesData.villes_by_bin_10 || {};
|
||||
console.log('HPL', labelsHPL, villesByBin10);
|
||||
new Chart(ctxHPL, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: labelsHPL,
|
||||
datasets: [{
|
||||
label: "Nombre de villes",
|
||||
data: valuesHPL,
|
||||
backgroundColor: 'rgba(255, 99, 132, 0.7)',
|
||||
borderColor: 'rgba(255, 99, 132, 1)',
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: true,
|
||||
plugins: {
|
||||
legend: { display: false },
|
||||
title: { display: true, text: "Distribution des villes par habitants/lieu (par pas de 10)" },
|
||||
tooltip: {
|
||||
callbacks: {
|
||||
afterBody: function(context) {
|
||||
const bin = context[0].label;
|
||||
const villes = villesByBin10[bin] || [];
|
||||
if(villes.length > 0){
|
||||
return ['Villes :'].concat(villes.map(v => '• ' + v));
|
||||
}
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
y: { beginAtZero: true, title: { display: true, text: 'Nombre de villes' } },
|
||||
x: { title: { display: true, text: 'Habitants par lieu (arrondi à 10)' } }
|
||||
}
|
||||
}
|
||||
});
|
||||
// Histogramme lieux/habitant (pas de 0.01)
|
||||
if(!data.histogram_001){
|
||||
document.getElementById('distributionVillesLieuxParHabitant').insertAdjacentHTML('afterend', '<div class="alert alert-danger">Erreur : données histogram_001 absentes. Cliquez sur "Régénérer les statistiques".</div>');
|
||||
return;
|
||||
}
|
||||
const ctx = document.getElementById('distributionVillesLieuxParHabitant').getContext('2d');
|
||||
const labels = Object.keys(data.histogram_001);
|
||||
const values = Object.values(data.histogram_001);
|
||||
const villesByBin001 = villesData.villes_by_bin_001 || {};
|
||||
console.log('LPH', labels, villesByBin001);
|
||||
new Chart(ctx, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: labels,
|
||||
datasets: [{
|
||||
label: "Nombre de villes",
|
||||
data: values,
|
||||
backgroundColor: 'rgba(153, 102, 255, 0.7)',
|
||||
borderColor: 'rgba(153, 102, 255, 1)',
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: true,
|
||||
plugins: {
|
||||
legend: { display: false },
|
||||
title: { display: true, text: "Distribution des villes par lieux/habitant (par pas de 0,01)" },
|
||||
tooltip: {
|
||||
callbacks: {
|
||||
afterBody: function(context) {
|
||||
const bin = context[0].label;
|
||||
const villes = villesByBin001[bin] || [];
|
||||
if(villes.length > 0){
|
||||
return ['Villes :'].concat(villes.map(v => '• ' + v));
|
||||
}
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
y: { beginAtZero: true, title: { display: true, text: 'Nombre de villes' } },
|
||||
x: { title: { display: true, text: 'Lieux par habitant (arrondi à 0,01)' } }
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
|
@ -513,6 +513,7 @@
|
|||
x: { title: { display: true, text: 'Trimestre' } }
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
} else if (modifCanvas) {
|
||||
modifCanvas.parentNode.innerHTML = '<div class="alert alert-info">Aucune donnée de modification disponible pour cette ville.</div>';
|
||||
|
|
|
@ -100,6 +100,13 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<p class="mb-2">
|
||||
<a href="https://osm-commerces.cipherbliss.com/api/v1/stats_geojson" target="_blank">Documentation de l'API (GeoJSON)</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -35,6 +35,12 @@
|
|||
<i class="bi bi-clock-fill"></i>
|
||||
{{ 'display.latest_changes'|trans }}</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{{ path('admin_fraicheur_histogramme') }}">
|
||||
<i class="bi bi-clock-history"></i>
|
||||
Fraîcheur de la donnée
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue