diff --git a/ezmashup/territoires_data.php b/ezmashup/territoires_data.php
index 0d90091ba4716b862c8c98eb72e61b3d0be0228a..1921c272f22f5f582bf9b6a8920c78ecb7435d3a 100644
--- a/ezmashup/territoires_data.php
+++ b/ezmashup/territoires_data.php
@@ -222,10 +222,7 @@ function territoires_data_feed_action_definir_url(string $action, array $feed, s
 		if ($categorie) {
 			$url = parametre_url($url, 'c', $categorie);
 		}
-	} elseif (
-		defined('_DIR_PLUGIN_TERRITOIRES_STAT')
-		and ($action === 'analyser')
-	) {
+	} elseif ($action === 'analyser') {
 		// Pour une analyse statistique, on renvoie vers une page d'affichage du feed et de ces caractéristiques
 		// techniques et statistiques.
 		$url = parametre_url(
diff --git a/lang/territoires_data_fr.php b/lang/territoires_data_fr.php
index 85658cdde0800432898a3a168ebdccca803eecda..5b1c8b2fd9af92e557e38644c127ef75d6cc0ce9 100644
--- a/lang/territoires_data_fr.php
+++ b/lang/territoires_data_fr.php
@@ -9,6 +9,8 @@ $GLOBALS[$GLOBALS['idx_lang']] = array(
 
 	// B
 	'bouton_recharger' => 'Recharger la configuration des jeux de données',
+	'bouton_territoire_feed_analyser' => 'Analyser',
+	'bouton_territoire_feed_modifier' => 'Modifier le jeu de données',
 
 	// E
 	'erreur_ecriture_config' => 'Erreur d’écriture du fichier de configuration du feed',
@@ -78,6 +80,32 @@ $GLOBALS[$GLOBALS['idx_lang']] = array(
 	'label_feed_version' => 'Version',
 	'label_id' => 'Identifiant',
 	'label_titre' => 'Libellé',
+	'label_territoire_feed_id'  => 'Identifiant du jeu',
+	'label_territoire_feed_credit'  => 'Crédits des sources',
+	'label_territoire_feed_fournisseur' => 'Fournisseur',
+	'label_territoire_feed_update' => 'Publication',
+	'label_vue_discretisation'  => 'Choix d\'une discrétisation',
+	'label_vue_distribution' => 'Analyse de la distribution',
+	'label_vue_choroplethe'  => 'Représentaiton choroplèthe',
+	'label_serie_effectif'  => 'effectif',
+	'label_serie_min'  => 'minimum',
+	'label_serie_max'  => 'maximum',
+	'label_serie_etendue'  => 'étendue',
+	'label_serie_moyenne'  => 'moyenne',
+	'label_serie_mediane'  => 'médiane',
+	'label_serie_quartiles'  => 'quartiles',
+	'label_serie_q1'  => 'Q1',
+	'label_serie_q2'  => 'Q2',
+	'label_serie_q3'  => 'Q3',
+	'label_serie_variance'  => 'variance',
+	'label_serie_ecart_type'  => 'écart type',
+	'label_serie_iq'  => 'interquartile',
+	'label_serie_cv'  => 'variation',
+	'label_serie_asymetrie_fisher'  => 'asymétrie (Fisher)',
+	'label_serie_asymetrie_yule'  => 'asymétrie (Yule)',
+	'label_serie_asymetrie_pearson'  => 'asymétrie (Pearson)',
+	'label_serie_kurtosis_fisher'  => 'aplatissement (Fisher)',
+	'label_serie_kurtosis_pearson'  => 'aplatissement (Pearson)',
 	'legende_extra_format' => 'Affichage des valeurs',
 	'legende_extra_identite' => 'Identification de la nature de données',
 	'legende_feed_credit' => 'Licence & Crédits',
diff --git a/modeles/graphique.html b/modeles/graphique.html
new file mode 100755
index 0000000000000000000000000000000000000000..cca24e0e0c78ff6fc95eb4950ed5c3bc2c3149bc
--- /dev/null
+++ b/modeles/graphique.html
@@ -0,0 +1,132 @@
+[(#REM)
+
+	Modèle pour produire des graphiques de feed avec Chart.js
+
+	Paramètres :
+	**obligatoires
+	*recommandés
+
+	<!-- Conteneur -->
+	- id_graphique    : Identifiant unique du graphe, par défaut généré aléatoirement
+	- *conteneur_class : Classes supplémentaires du conteneur
+
+	<!-- Données et textes -->
+	- **type :        Type de graphique (string)
+                      bar (défaut) | pie | line | horizontalBar | radar | doughnut | polarArea | bubble | scatter | area | mixed
+	- **classes :     Liste des classes de la série avec leur effectif, leurs bornes et d'autres attributs (array)
+	- *labels :       Labels utilisés en abscisse (string|array)
+
+]
+[(#REM)
+	============================
+	1) Normaliser les paramètres
+	============================
+]
+[(#REM) Base ]
+#SET{id_graphique, #ENV{id_graphique, #VAL{territoire_feed_graphique_}|uniqid}}
+#SET{type, #ENV{type, bar}|trim|strtolower}
+#SET{couleur, #ENV{couleur, '#bdc8d0'}}
+
+#SET{data, #ENV{classes}|array_column{effectif}}
+#SET{labels, #VAL{strval}|array_map{#ENV{classes}|array_keys}}
+#SET{binf, #ENV{classes}|array_column{binf}}
+#SET{bsup, #ENV{classes}|array_column{bsup}}
+#SET{tooltip_labels_n, Effectif}
+#SET{tooltip_labels_binf, Borne inférieure}
+#SET{tooltip_labels_bsup, Borne supérieure}
+
+[(#REM) Options ]
+#SET{options, #ARRAY}
+
+[(#REM)
+	========================
+	3) Affichage du graphique
+	========================
+]
+
+<div
+	class="spip-chart-wrap[ spip-chart-align-(#ENV{align})][ (#ENV{conteneur_class})]"
+	style="position:relative; max-width:100%;"
+>
+	<canvas id="#GET{id_graphique}" class="spip-chart-canvas"></canvas>
+</div>
+
+<script>
+var jQChartjsLoader;
+(function () {
+	function draw_this_chartjs() {
+		jQuery(function($){
+			var conteneur[_(#GET{id_graphique})] = $("[#(#GET{id_graphique})]");
+			var spipChart[_(#GET{id_graphique})] = new Chart(conteneur[_(#GET{id_graphique})], {
+				type: ['(#GET{type})'],
+				data: {
+					labels:   [(#GET{labels}|json_encode)],
+					datasets: [{
+						label: '',
+						data: [(#GET{data}|json_encode)],
+						backgroundColor: ['(#GET{couleur})'],
+						borderColor: ['(#GET{couleur})'],
+						fill: true,
+						binf: [(#GET{binf}|json_encode)],
+						bsup: [(#GET{bsup}|json_encode)]
+					}]
+				},
+				options: {
+					responsive: true,
+					title: {
+						display: true,
+						text: ['(#ENV{titre})']
+					},
+					legend: false,
+					tooltips: {
+						enabled: true,
+						callbacks: {
+							title: function(tooltipItems) {
+								return '';
+							},
+							label: function(tooltipItem) {
+								return '';
+							},
+							footer: function(tooltipItems) {
+								let label_n = ['(#GET{tooltip_labels_n}|label_ponctuer)'];
+								let label_binf = ['(#GET{tooltip_labels_binf}|label_ponctuer)'];
+								let label_bsup = ['(#GET{tooltip_labels_bsup}|label_ponctuer)'];
+								let texte = '';
+								let dataset = tooltipItems[0].dataset;
+								let index = tooltipItems[0].dataIndex;
+								let n = dataset.data[index];
+								let binf = dataset.binf[index];
+								let bsup = dataset.bsup[index];
+								texte += label_n + ' ' + n + "\n";
+                                texte += label_binf + ' ' + binf + "\n";
+                                texte += label_bsup + ' ' + bsup;
+								return texte;
+							}
+						}
+					}
+				}
+			});
+		});
+	}
+
+	if (typeof jQuery.ajax === "undefined") {
+		jQuery(init_chartjs);
+	} else {
+		init_chartjs();
+	}
+	function init_chartjs() {
+		// Charger le javascript une seule fois si plusieurs graphiques
+		if (typeof Chart === "undefined") {
+			if (typeof jQChartjsLoader === "undefined") {
+				jQChartjsLoader = jQuery.ajax({url: '[(#CHEMIN{lib/chartjs/chart.js})]', dataType: 'script', cache: true});
+			}
+			jQChartjsLoader.done(draw_this_chartjs);
+		} else {
+			draw_this_chartjs();
+		}
+	}
+})();
+
+</script>
+
+#FILTRE{compacte}
diff --git a/paquet.xml b/paquet.xml
index 9afc2257889f3031e3138b359bb877bf49e4dbc2..96509783cb7e2aeae473b4bf6eae17619c73e910 100644
--- a/paquet.xml
+++ b/paquet.xml
@@ -17,9 +17,12 @@
     <pipeline nom="autoriser" inclure="territoires_data_autorisations.php" />
     <pipeline nom="affiche_milieu" inclure="territoires_data_pipelines.php" />
     <pipeline nom="post_depeupler_territoire" inclure="territoires_data_pipelines.php" />
+    <pipeline nom="feed_action_completer_liste" inclure="territoires_data_pipelines.php" />
 
-	<necessite nom="ezmashup" compatibilite="[1.1.4;]" />
     <necessite nom="territoires" compatibilite="[2.0.0;]" />
+	<necessite nom="ezmashup" compatibilite="[1.1.4;]" />
     <necessite nom="ezcache" compatibilite="[1.5.3;[" />
     <necessite nom="cvtupload" compatibilite="[2.1.6;]" />
+    <necessite nom="ezmath" compatibilite="[1.0.0-dev;]" />
+    <utilise nom="chartjs" compatibilite="[2.2.0;]" />
 </paquet>
diff --git a/prive/squelettes/contenu/territoire_feed.html b/prive/squelettes/contenu/territoire_feed.html
new file mode 100644
index 0000000000000000000000000000000000000000..3832dc84d6cd19a5e82b28bd4734b91a8f5eeae2
--- /dev/null
+++ b/prive/squelettes/contenu/territoire_feed.html
@@ -0,0 +1,57 @@
+[(#REM) <!-- On rajoute le plugin territoires_data dans le env, car c'est ce plugin qui fournit les feeds -->]
+#SET{plugin, territoires_data}
+[(#AUTORISER{voir, feed, #ENV{feed_id}, #NULL, #ARRAY{plugin, #GET{plugin}}}|sinon_interdire_acces)]
+<BOUCLE_territoire_feed(FEEDS){plugin=#GET{plugin}}{feed_id}{si #ENV{exec}|=={territoire_feed}}>
+[(#REM) <!-- Fiche du feed -->]
+[(#BOITE_OUVRIR{[
+	[(#AUTORISER{modifier, feed, #FEED_ID, #NULL, #ARRAY{plugin, #CHAMP_SQL{plugin}}})
+		[(#FEED_URL_ACTION{#CHAMP_SQL{plugin}, editer, #FEED_ID, #SELF|parametre_url{redirect, ''}}
+			|icone_verticale{<:territoires_data:bouton_territoire_feed_modifier:>, feed-24, edit, #LANG_RIGHT})]
+	]
+
+	<h1>(#TITLE)[(#CHEMIN_IMAGE{territoire_feed-24.svg}|balise_img{territoire_feed,cadre-icone})]</h1>
+
+],simple fiche_objet})]
+
+<!--affiche_milieu-->
+
+<div id="wysiwyg">
+	<INCLURE{fond=prive/squelettes/inclure/inc-territoire_feed_detail,
+		plugin,
+		feed_id,
+		ajax=wysiwyg,
+		wysiwyg=1} />
+</div>
+#BOITE_FERMER
+
+[(#REM) <!-- Statistiques standard sur la série (toujours visibles) --> ]
+<INCLURE{fond=prive/squelettes/inclure/inc-territoire_feed_statistique,
+	plugin,
+	feed_id} />
+
+[(#REM) <!-- Onglets de premier niveau pour accéder aux différentes vues du feed -->]
+#SET{vue, #ENV{vue, distribution}}
+<B_territoire_feed_vues>
+<div class="onglets_simple">
+	<ul class="vue">
+<BOUCLE_territoire_feed_vues(DATA) {source table, #LISTE{distribution, discretisation}}>
+		#SET{libelle, #VAL{territoires_data:label_vue_}|concat{#VALEUR}|_T}
+		[<li>
+			(#SELF
+				|parametre_url{vue, #VALEUR}
+				|lien_ou_expose{
+					[(#GET{libelle}|spip_ucfirst)],
+					#GET{vue}|=={#VALEUR}})
+		</li>]
+</BOUCLE_territoire_feed_vues>
+	</ul>
+	<div class="nettoyeur"></div>
+</div>
+</B_territoire_feed_vues>
+
+[(#REM) <!-- Contenu de chaque onglet --> ]
+<INCLURE{fond=prive/squelettes/inclure/inc-territoire_feed_#GET{vue},
+	plugin,
+	feed_id,
+	ajax} />
+</BOUCLE_territoire_feed>
diff --git a/prive/squelettes/inclure/inc-territoire_feed_detail.html b/prive/squelettes/inclure/inc-territoire_feed_detail.html
new file mode 100644
index 0000000000000000000000000000000000000000..b91f9ddfbe5d20e5033d7c81e3c28eb3475b1b2d
--- /dev/null
+++ b/prive/squelettes/inclure/inc-territoire_feed_detail.html
@@ -0,0 +1,34 @@
+[(#REM) <!-- Détails d'un feed
+
+	Affiche le détail d'un feed, en particulier, les informations sur la cible.
+
+	@param string plugin
+	       Préfixe du plugin utilisateur (obligatoire, non nul).
+	@param string feed_id
+           Identifiant du feed (obligatoire, non nul).
+-->]
+<BOUCLE_feed_details(FEEDS){plugin}{feed_id}>
+	[(#REM) <!-- Description du feed --> ]
+	[<div class="champ contenu_descriptif[ (#DESCRIPTION*|strlen|?{'',vide})]">
+		<div dir="#LANG_DIR" class="texte">(#DESCRIPTION)</div>
+	</div>]
+
+	[(#REM) <!-- Liste des crédits des sources --> ]
+	<B_credits>
+	<div class="champ contenu_credits">
+		<:territoires_data:label_territoire_feed_credit:/>
+	<BOUCLE_credits(DATA) {source table, #SOURCES_BASIC}>
+		<dl class="source_feed">
+			[<dt><:territoires_data:label_feed_licence|label_ponctuer:></dt>
+			<dd>(#VALEUR{source/license})</dd>]
+			[<dt><:territoires_data:label_territoire_feed_update|label_ponctuer:></dt>
+			<dd>(#VALEUR{source/last_update})</dd>]
+			[<dt><:territoires_data:label_feed_version|label_ponctuer:></dt>
+			<dd>(#VALEUR{source/version})</dd>]
+			[<dt><:territoires_data:label_territoire_feed_fournisseur|label_ponctuer:></dt>
+			<dd>(#VALEUR{provider/name})</dd>]
+		</dl>
+	</BOUCLE_credits>
+	</div>
+	</B_credits>
+</BOUCLE_feed_details>
diff --git a/prive/squelettes/inclure/inc-territoire_feed_discretisation.html b/prive/squelettes/inclure/inc-territoire_feed_discretisation.html
new file mode 100644
index 0000000000000000000000000000000000000000..a88d643e3d71007c3d88817f76c5da6fc68408fe
--- /dev/null
+++ b/prive/squelettes/inclure/inc-territoire_feed_discretisation.html
@@ -0,0 +1 @@
+[(#REM) <!-- Liste des indicateur de forme & graphique de base --> ]
diff --git a/prive/squelettes/inclure/inc-territoire_feed_distribution.html b/prive/squelettes/inclure/inc-territoire_feed_distribution.html
new file mode 100644
index 0000000000000000000000000000000000000000..8c3cd0c7c044a36f82e2c97f1cf4a930b5b94896
--- /dev/null
+++ b/prive/squelettes/inclure/inc-territoire_feed_distribution.html
@@ -0,0 +1,36 @@
+[(#REM) <!-- Liste indicateurs de form
+
+	Affiche dans 1 tableau les indicateurs de variation, d'asymétrie et d'aplatissement d'un feed
+	et un graphique représentatif de la distribution (histogramme des effectifs pour un nombre de classes donné)
+
+	@param string plugin
+	       Préfixe du plugin utilisateur (obligatoire, non nul).
+	@param string feed_id
+           Identifiant du feed (obligatoire, non nul).
+-->]
+
+[(#REM) <!-- Statistiques descriptives du feed (position, dispersion) --> ]
+#SET{statistiques, #SERIE_STATISTIQUES{#ENV{plugin}, #ENV{feed_id}}}
+
+<div class="statistique_feed">
+	[(#REM) <!-- Indicateurs de forme --> ]
+	<INCLURE{fond=prive/squelettes/inclure/inc-territoire_feed_indicateurs,
+		plugin,
+		feed_id,
+		statistiques=#GET{statistiques},
+		indicateurs=#LISTE{cv, asymetrie_fisher, kurtosis_fisher}} />
+
+	[(#REM) <!-- Histogramme de classes de la série pour visualiser la forme --> ]
+	#SET{nb_classes, #GET{statistiques/effectif}|<{50}|?{10, 25}}
+	#SET{discretisation, #SERIE_DISCRETISATION{#ENV{plugin}, #ENV{feed_id}, equivalence, #GET{nb_classes}}}
+	#SET{data, #GET{discretisation/classes}|array_column{effectif}}
+	#SET{labels, #GET{discretisation/classes}|array_keys}
+	#MODELE{
+		graphique,
+		id_graphique=histo,
+		type=bar,
+		classes=#GET{discretisation/classes},
+		titre='Effectif par classe',
+		conteneur_class=graphique
+	}
+</div>
diff --git a/prive/squelettes/inclure/inc-territoire_feed_indicateurs.html b/prive/squelettes/inclure/inc-territoire_feed_indicateurs.html
new file mode 100644
index 0000000000000000000000000000000000000000..15330f1826909f145017184a4596ddab4fffde10
--- /dev/null
+++ b/prive/squelettes/inclure/inc-territoire_feed_indicateurs.html
@@ -0,0 +1,28 @@
+[(#REM) <!-- Affiche dans un tableau, les indicateurs statistiques demandés.
+
+	@param string plugin
+	       Préfixe du plugin utilisateur (obligatoire, non nul).
+	@param string feed_id
+           Identifiant du feed (obligatoire, non nul).
+	@param string titre
+           Titre du tableau (caption) ou vide si aucun titre.
+	@param array indicateurs
+           Liste des identifiants d'indicateurs.
+	@param array statistiques
+           Tableau de toutes les statistiques du feed
+-->]
+<B_ind_indicateurs>
+<div class="liste-objets indicateurs">
+	<table class="spip liste">
+		[<caption><strong class="caption">(#ENV*{titre})</strong></caption>]
+		<tbody>
+<BOUCLE_ind_indicateurs(DATA){source table, #ENV{indicateurs}}>
+			<tr>
+				<td class="titre principale">[(#VAL{territoires_data:label_serie_}|concat{#VALEUR}|_T|spip_ucfirst)]</td>
+				<td class="valeur">[(#ENV{statistiques/#VALEUR})]</td>
+			</tr>
+</BOUCLE_ind_indicateurs>
+		</tbody>
+	</table>
+</div>
+</B_ind_indicateurs>
diff --git a/prive/squelettes/inclure/inc-territoire_feed_statistique.html b/prive/squelettes/inclure/inc-territoire_feed_statistique.html
new file mode 100644
index 0000000000000000000000000000000000000000..e6062bff7f992a6bf2718ee5d9c8960eac67e5f3
--- /dev/null
+++ b/prive/squelettes/inclure/inc-territoire_feed_statistique.html
@@ -0,0 +1,35 @@
+[(#REM) <!-- Liste des statistiques descriptives du feed (position, dispersion)
+
+	Affiche dans 3 tableaux, les différentes statistiques descriptives d'un feed.
+
+	@param string plugin
+	       Préfixe du plugin utilisateur (obligatoire, non nul).
+	@param string feed_id
+           Identifiant du feed (obligatoire, non nul).
+-->]
+
+[(#REM) <!-- Statistiques descriptives du feed (position, dispersion) --> ]
+#SET{statistiques, #SERIE_STATISTIQUES{#ENV{plugin}, #ENV{feed_id}}}
+
+<div class="statistique_feed">
+	[(#REM) <!-- Indicateurs de base --> ]
+	<INCLURE{fond=prive/squelettes/inclure/inc-territoire_feed_indicateurs,
+		plugin,
+		feed_id,
+		statistiques=#GET{statistiques},
+		indicateurs=#LISTE{effectif, min, max}} />
+
+	[(#REM) <!-- Indicateurs de position --> ]
+	<INCLURE{fond=prive/squelettes/inclure/inc-territoire_feed_indicateurs,
+		plugin,
+		feed_id,
+		statistiques=#GET{statistiques},
+		indicateurs=#LISTE{moyenne, mediane, q1, q2, q3}} />
+
+	[(#REM) <!-- Indicateurs de dispersion --> ]
+	<INCLURE{fond=prive/squelettes/inclure/inc-territoire_feed_indicateurs,
+		plugin,
+		feed_id,
+		statistiques=#GET{statistiques},
+		indicateurs=#LISTE{etendue, ecart_type, iq}} />
+</div>
diff --git a/prive/squelettes/navigation/territoire_feed.html b/prive/squelettes/navigation/territoire_feed.html
new file mode 100644
index 0000000000000000000000000000000000000000..60bb0db0ba845882636834113212f966ece07a35
--- /dev/null
+++ b/prive/squelettes/navigation/territoire_feed.html
@@ -0,0 +1,45 @@
+#BOITE_OUVRIR{'', info}
+<BOUCLE_territoire_feed(FEEDS){feed_id}>
+<div class="infos">
+	[(#REM) <!-- L'id du feed de territoire -->]
+	<div class="numero">
+		<:territoires_data:label_territoire_feed_id|label_ponctuer:/>
+		<br>#FEED_ID
+	</div>
+	[(#REM) <!-- Le type de territoire concerné -->]
+	<div class="numero">
+		<span class="label"><:territoires_data:label_feed_type_territoire|label_ponctuer:/></span>
+		[(#CHEMIN_IMAGE{[type_(#TAGS|table_valeur{type})-xx.svg]}
+			|image_reduire{32,32}
+			|inserer_attribut{alt, logo_type}
+			|inserer_attribut{style, 'margin: 0 auto'}
+			|inserer_attribut{class, 'clearfix icone-type'})]
+		[(#VAL{territoire:type_}|concat{#TAGS|table_valeur{type}}|_T)]
+	</div>
+	[(#REM) <!-- Pays concerné eventuellement -->]
+	<B_pays>
+	<div class="numero">
+	<BOUCLE_pays(TERRITOIRES){iso_territoire=#TAGS|table_valeur{pays}}>
+		<span class="label"><:territoire:type_country|label_ponctuer:/></span>
+		[<br>(#NOM_USAGE)]
+	</BOUCLE_pays>
+	</div>
+	</B_pays>
+
+	[(#REM) <!-- Nature des données (extra) -->]
+	[(#SET{extra, #MAPPING|table_valeur{static_fields/extra}})]
+	#SET{config_extra, #CONFIG{territoires_data/extras/#GET{extra}}}
+	<div class="numero extra">
+		<span class="label"><:territoire_extra:titre_extra|spip_ucfirst|label_ponctuer:></span>
+		<br>[(#GET{config_extra/label}|typo)]
+	</div>
+	<dl class="extra">
+		<dt><:territoire_extra:champ_extra_format|spip_ucfirst|label_ponctuer:></dt>
+		<dd>[(#GET{config_extra/format}|territoire_extra_format_traduire)]</dd>
+		<dt><:territoire_extra:champ_extra_unite|spip_ucfirst|label_ponctuer:></dt>
+		<dd>[(#GET{config_extra/unite}|territoire_unite_traduire)]</dd>
+	</dl>
+
+</div>
+</BOUCLE_territoire_feed>
+#BOITE_FERMER
diff --git a/prive/style_prive_plugin_territoires_data.html b/prive/style_prive_plugin_territoires_data.html
index 9d7912254af401c13ab4fbc9642f9c7f67e4d1b8..bb9f91cb5081270d3ff3964113113e3c664e13ef 100644
--- a/prive/style_prive_plugin_territoires_data.html
+++ b/prive/style_prive_plugin_territoires_data.html
@@ -22,3 +22,22 @@
 .liste-objets.territoire_extras tr td {line-height: 1;}
 .liste-objets.territoire_extras table caption {line-height: 0.4;}
 .liste-objets.territoire_extras td.extra {text-align: right;}
+
+/* Boite d'infos */
+#navigation .infos .numero  p.prefixe { font-size: 1.3em; text-transform: lowercase; }
+#navigation .infos .numero span.label { font-weight: normal; }
+#navigation .infos .numero.extra { border-bottom: 0; }
+#navigation .infos dl.extra { font-size: 0.9em; display: flex; flex-wrap: wrap; align-items: flex-start; }
+#navigation .infos dl.extra dt { flex-basis: 25%; flex-grow: 0; flex-shrink: 0; }
+#navigation .infos dl.extra dd { margin-bottom: 0; flex-basis: 75%; flex-grow: 1; flex-shrink: 0; }
+
+/* Fiche feed - crédits */
+#wysiwyg .contenu_credits dl.source_feed { margin-top: 0.5em; font-size: 0.9em; display: flex; flex-wrap: wrap; align-items: flex-start; }
+#wysiwyg .contenu_credits dl.source_feed dt { flex-basis: 15%; flex-grow: 0; flex-shrink: 0; text-align: right; }
+#wysiwyg .contenu_credits dl.source_feed dd { margin-bottom: 0; margin-#ENV{left}: 1%; flex-basis: 84%; flex-grow: 1; flex-shrink: 0; }
+
+/* Fiche feed - onglet statistique */
+#contenu .statistique_feed { display: flex; flex-wrap: wrap; justify-content: space-between; }
+#contenu .statistique_feed div.indicateurs { margin-top: 1em; margin-bottom: 0; flex-basis: 32%; flex-grow: 0; flex-shrink: 0; }
+#contenu .statistique_feed div.indicateurs .valeur { text-align: #ENV{right}; }
+#contenu .statistique_feed div.graphique { margin-top: 1em; margin-bottom: 0; flex-basis: 66%; flex-grow: 0; flex-shrink: 0; }
diff --git a/territoires_data_autorisations.php b/territoires_data_autorisations.php
index 2cf11d06d95647c3965a101c1f6c4d9e599d6ea9..410c022f4cd6cdb33f1d88ac2d2035bbe1b8de23 100644
--- a/territoires_data_autorisations.php
+++ b/territoires_data_autorisations.php
@@ -220,3 +220,40 @@ function autoriser_territoireunite_supprimer_dist($faire, $type, $id, $qui, $opt
 
 	return $autorise;
 }
+
+/**
+ * Autorisation, pour tous les feeds de statistiques, d'analyser les données d'un feed (se rendre vers une page
+ * d'analyse statistique). Il faut :
+ * - posséder l'autorisation minimale `ezmashup`
+ * - fournir un identifiant de feed existant
+ * - que le feed soit actif et que son type d'extra soit `stat` (Statistiques)
+ *
+ * @param string         $faire   Action demandée : `analyser`
+ * @param string         $type    Type d'objet sur lequel appliquer l'action : `feed`
+ * @param int            $id      Identifiant de l'objet : celui du feed sur lequel appliquer l'action
+ * @param null|array|int $qui     L'initiateur de l'action:
+ *                                - si null on prend alors visiteur_session
+ *                                - un id_auteur (on regarde dans la base)
+ *                                - un tableau auteur complet, y compris [restreint]
+ * @param null|array     $options Tableau d'options sous forme de tableau associatif : `plugin`, préfixe du plugin utilisateur
+ *
+ * @return bool `true`si l'auteur est autorisée à exécuter l'action, `false` sinon.
+**/
+function autoriser_feed_analyser_dist($faire, $type, $id, $qui, $options) {
+	// Initialisation de l'autorisation à non autorisé par défaut.
+	$autorise = false;
+
+	if (
+		autoriser('ezmashup', $type, $id, $qui, $options)
+		and $id
+		and is_string($id)
+		and include_spip('inc/ezmashup_feed')
+		and ($feed = feed_lire($options['plugin'], $id))
+		and ($feed['is_active'] === 'oui')
+		and ($feed['category'] === 'territory_stat')
+	) {
+		$autorise = true;
+	}
+
+	return $autorise;
+}
diff --git a/territoires_data_fonctions.php b/territoires_data_fonctions.php
index d09cfa1a1f5c9d2a478b5a912c74cf438e1baf70..009e53c582a665b5cdf6f35dae7636baba289767 100644
--- a/territoires_data_fonctions.php
+++ b/territoires_data_fonctions.php
@@ -173,3 +173,176 @@ function territoire_unite_traduire(string $unite_id) : string {
 
 	return $unites[$unite_id];
 }
+
+/**
+ * Compile la balise `#SERIE_STATISTIQUES` qui les principaux indicateurs statistiques d'une série quantitative.
+ * La signature de la balise est : `#SERIE_STATISTIQUES{plugin, feed_id[, precision]}`.
+ *
+ * @balise
+ *
+ * @param Champ $p Pile au niveau de la balise.
+ *
+ * @return Champ Pile complétée par le code à générer.
+ **/
+function balise_SERIE_STATISTIQUES_dist(Champ $p) : Champ {
+	// Récupération des arguments de la balise.
+	// -- Identifiant du feed
+	$plugin = interprete_argument_balise(1, $p);
+	$plugin = isset($plugin) ? str_replace('\'', '"', $plugin) : '""';
+	// -- Identifiant du feed
+	$id_feed = interprete_argument_balise(2, $p);
+	$id_feed = isset($id_feed) ? str_replace('\'', '"', $id_feed) : '""';
+	// -- Précision des staistiques réelles calculées
+	$precision = interprete_argument_balise(3, $p);
+	$precision = $precision ?? '2';
+
+	// Calcul de la balise
+	$p->code = "territoire_feed_compiler_statistiques({$plugin}, {$id_feed}, {$precision})";
+
+	return $p;
+}
+
+function territoire_feed_compiler_statistiques(string $plugin, string $id_feed, ?int $precision = 2) : array {
+	// Initialisation en statique pour le feed
+	static $statistiques = [];
+
+	if (!isset($statistiques[$plugin][$id_feed][$precision])) {
+		$statistiques[$plugin][$id_feed][$precision] = [];
+
+		if (
+			// Récupérer la série dans la table des extras de territoire et l'identifiant de l'extra
+			($extra = territoire_feed_lire_extra($plugin, $id_feed))
+			and ($serie = territoire_feed_lire_serie($plugin, $id_feed))
+		) {
+			// On acquiert les statistiques
+			include_spip('inc/ezmath_statistique');
+			$statistiques_feed = serie_statistiques($serie);
+
+			// Choix des informations, réorganisation et affichage des valeurs (pas d'erreur on a déjà écarté la série vide).
+			// -- lecture du format de l'extra et détermination du nombre de décimales
+			include_spip('inc/config');
+			$format = lire_config("territoires_data/extras/{$extra}/format", '');
+			$decimales = $format === 'integer'
+				? 0
+				: (int) str_replace('float', '', $format);
+
+			// -- Entier : effectif
+			// -- Format de l'extra : min, max, médiane, quartiles, étendue, interquartile
+			// -- Réel avec la précision fournie : le reste des statistiques
+			foreach ($statistiques_feed as $_indicateur => $_valeur) {
+				if ($_indicateur === 'effectif') {
+					$statistiques_feed[$_indicateur] = number_format((float) $_valeur, 0, ',', '&nbsp;');
+				} elseif (in_array($_indicateur, ['min', 'max', 'mediane', 'q1', 'q2', 'q3', 'etendue', 'iq'])) {
+					$statistiques_feed[$_indicateur] = number_format((float) $_valeur, $decimales, ',', '&nbsp;');
+				} else {
+					$statistiques_feed[$_indicateur] = number_format((float) $_valeur, $precision, ',', '&nbsp;');
+				}
+			}
+
+			// Stockage des statistiques du feed
+			$statistiques[$plugin][$id_feed][$precision] = $statistiques_feed;
+		}
+	}
+
+	return $statistiques[$plugin][$id_feed][$precision];
+}
+
+
+/**
+ * Compile la balise `#SERIE_DISCRETISATION` qui renvoie les classes et la série discrétisées.
+ * La signature de la balise est : `#SERIE_STATISTIQUES{plugin, feed_id[, precision]}`.
+ *
+ * @balise
+ *
+ * @param Champ $p Pile au niveau de la balise.
+ *
+ * @return Champ Pile complétée par le code à générer.
+ **/
+function balise_SERIE_DISCRETISATION_dist(Champ $p) : Champ {
+	// Récupération des arguments de la balise.
+	// -- Identifiant du feed
+	$plugin = interprete_argument_balise(1, $p);
+	$plugin = isset($plugin) ? str_replace('\'', '"', $plugin) : '""';
+	// -- Identifiant du feed
+	$id_feed = interprete_argument_balise(2, $p);
+	$id_feed = isset($id_feed) ? str_replace('\'', '"', $id_feed) : '""';
+	// -- Méthode de discrétisation
+	$methode = interprete_argument_balise(3, $p);
+	$methode = isset($methode) ? str_replace('\'', '"', $methode) : '""';
+	// -- Nombre de classes
+	$nb_classes = interprete_argument_balise(4, $p);
+	$nb_classes = $nb_classes ?? '5';
+
+	// Calcul de la balise
+	$p->code = "territoire_feed_discretiser_serie({$plugin}, {$id_feed}, {$methode}, {$nb_classes})";
+
+	return $p;
+}
+
+function territoire_feed_discretiser_serie(string $plugin, string $id_feed, ?string $methode = 'equivalence', ?int $nb_classes = 5) : array {
+	// Initialisation pour le feed
+	$discretisations = [];
+
+	if ($serie = territoire_feed_lire_serie($plugin, $id_feed)) {
+		// On acquiert les classes et la série discrétisée
+		include_spip('inc/ezmath_discretisation');
+		$discretisation_feed = serie_discretisation($serie, $methode, $nb_classes);
+		if (!empty($discretisation_feed['classes'])) {
+			$discretisations = $discretisation_feed;
+
+			// Ajout des indice donnant le nombre de classe idéal
+			$discretisation_feed['indices'] = [
+				'hunstberger' => serie_indice_hunstberger($serie),
+				'brooks' => serie_indice_brooks($serie),
+				'yule' => serie_indice_yule($serie),
+				'scott' => serie_indice_scott($serie),
+				'diaconis' => serie_indice_diaconis($serie),
+			];
+		}
+	}
+
+	return $discretisations;
+}
+
+function territoire_feed_lire_serie(string $plugin, string $id_feed) : array {
+	// Initialisation en statique pour le feed
+	static $series = [];
+
+	if (!isset($series[$plugin][$id_feed])) {
+		$series[$plugin][$id_feed] = [];
+
+		// Récupérer la série dans la table des extras de territoire
+		$select = ['iso_territoire', 'valeur'];
+		$where = [
+//			'plugin=' . sql_quote($plugin), // A rajouter plus tard
+			'feed_id=' . sql_quote($id_feed),
+		];
+		$serie = sql_allfetsel($select, 'spip_territoires_extras', $where);
+		if ($serie) {
+			$series[$plugin][$id_feed] = array_column($serie, 'valeur', 'iso_territoire');
+		}
+	}
+
+	return $series[$plugin][$id_feed];
+}
+
+function territoire_feed_lire_extra(string $plugin, string $id_feed) : string {
+	// Initialisation en statique pour le feed
+	static $extras = [];
+
+	if (!isset($extras[$plugin][$id_feed])) {
+		$extras[$plugin][$id_feed] = '';
+
+		// Récupérer la série dans la table des extras de territoire
+		$where = [
+//			'plugin=' . sql_quote($plugin), // A rajouter plus tard
+			'feed_id=' . sql_quote($id_feed),
+		];
+		$extra = sql_getfetsel('extra', 'spip_territoires_extras', $where);
+		if ($extra) {
+			$extras[$plugin][$id_feed] = $extra;
+		}
+	}
+
+	return $extras[$plugin][$id_feed];
+}
diff --git a/territoires_data_pipelines.php b/territoires_data_pipelines.php
index efa6de9ce4327838909868c08323b1731e90fcf9..59ea07f0e1844b46d2d6930e75b0f82374fbba6b 100644
--- a/territoires_data_pipelines.php
+++ b/territoires_data_pipelines.php
@@ -129,3 +129,21 @@ function territoires_data_post_depeupler_territoire(array $flux) : array {
 
 	return $flux;
 }
+function territoires_data_feed_action_completer_liste($flux) {
+	if ($flux['args']['plugin'] === 'territoires_data') {
+		$actions = [
+			'analyser' => [
+				'name' => '<:territoires_data:bouton_territoire_feed_analyser:>',
+				'icon' => '',
+				'type' => 'redirect',
+				'auth' => 'analyser',
+				'feed' => true,
+				'menu' => 'actionner',
+				'bord' => true
+			],
+		];
+		$flux['data'] = array_merge($flux['data'], $actions);
+	}
+
+	return $flux;
+}