Unlisted
Edited
Oct 5, 2023
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
graph_svg = DOM.download(await serialize(map_chart), selectedEncoding+'-indices-tourisme-'+select_pays+'.svg', 'Download as svg')
Insert cell
graph_png = DOM.download(await rasterize(map_chart), selectedEncoding+'-indices-tourisme-'+select_pays+'.png', "Download map as PNG")
Insert cell
csvBtn = button(raw_data_banque, 'raw_data_banque.csv');
Insert cell
Insert cell
Insert cell
Insert cell
height = width*0.6
Insert cell
//margin_dept = ({top: 100, right: 20, bottom: 100, left: 120})
Insert cell
md`## Synthèse en chiffre`
Insert cell
printTable(data_banque .slice(0, 10))
Insert cell
viewof selectedRamp = select({
title: 'Réglages ',
description: 'Choisissez la rampe de couleur du graphique',
options: (colorRamps).flat(), ////
value: 'Oranges' // Inferno
})
Insert cell
ramp(selectedRamp)
Insert cell
viewof bgColor = color({
value: "#1a1a1a",
description: 'Choisissez la couleur de fond du graphique',
})
Insert cell
viewof textColor = color({
value: "#333",
description: 'Choisissez la couleur du texte',
})
Insert cell
md`# DATA
depuis le site open data gouv permet de charger directement le fichier de données mis à jour quotidiennement`
Insert cell
parse = d3.utcParse('%Y-%m')
// parse("2020-03") return 2020-03-01
Insert cell
function dateFr(date){
var jours = new Array("dim", "lun", "mar", "mer", "jeu", "ven", "sam");
var mois = new Array("jan", "fev", "mars", "avr", "mai", "juin", "juil", "aout", "sep", "oct", "nov", "dec");
//var message = date.getDate() + " "; // numero du jour
var message = mois[date.getMonth()] + " "; // mois
message += date.getFullYear();
return message;
}
Insert cell
md`### Raw_DATA_Banque`
Insert cell
/*
chargement des données brutes BPCE 40Mo
raw_data_banque= d3.dsv(';',"https://raw.githubusercontent.com/AlainOttenheimer/Touristoscope/master/data/indices-tourisme-v2.csv", d => {
const g = {
annee: d.ANNEE,
mois: d.MOIS,
date : parse(d['Mois de l\'année']),
date_texte : dateFr(parse(d['Mois de l\'année'])),
volume : d3.format(".2f")(d.Volume),
valeur : d3.format(".2f")(d.Valeur),
insee_reg :d['Code INSEE Région'],
dest_dept_nom : d['Nom du Département'],
dest_reg_name : d['Région de destination'],
dest_dept_nb : d['Département de destination'][0] !="2" ? parseInt(d['Département de destination'].split("-")[0]).toString() : d['Département de destination'].split("-")[0],
origine_pays : d['Pays d\'origine']
};
return g
})
*/
// Chargement des données filtrées et mise en forme 20Mo
raw_data_banque=d3.dsv(',',"https://raw.githubusercontent.com/AlainOttenheimer/Touristoscope/master/data/indices-tourisme-light.csv", d => {
const g = {
date : parse(d['Mois de l\'année']),
date_texte : dateFr(parse(d['Mois de l\'année'])),
volume : d3.format(".2f")(d.Volume),
valeur : d3.format(".2f")(d.Valeur),
insee_reg :d['Code INSEE Région'],
dest_dept_nom : d['Département de destination'].split("-")[1],
dest_dept_nb : d['Département de destination'][0] !="2" ? parseInt(d['Département de destination'].split("-")[0]).toString() : d['Département de destination'].split("-")[0],
origine_pays : d['Pays d\'origine']
};
return g
})
Insert cell
md`### Raw_DATA_Banque for selected country`
Insert cell
data_banque = raw_data_banque.filter(d=>d.origine_pays == select_pays)
Insert cell
md`### DATA Name Country for En to Fr Translation `
Insert cell
code_name_country = d3.csvParse(await FileAttachment("country-codes_extract.csv").text(), d3.autoType).filter(d=> d.official_name_en != null);
Insert cell
md`### DATA country population`
Insert cell
population_country = d3.csvParse(await FileAttachment("API_SP.POP.TOTL_DS2_en_csv_v2_1345178_extract.csv") .text(), d3.autoType);
Insert cell
md`### Merge DATA Name & Country population`
Insert cell
merge = (a1,a2) =>
a1.map(itm => ({
...a2.find((item) => item.dep === itm.dep),
...itm
}));
Insert cell
country_data = {return merge (code_name_country,population_country).map(obj => {
return {
country_name_en: obj.official_name_en,
country_name_fr : obj.official_name_fr,
population_2019 : obj['2019'],
}}).filter(d=>d.country_name_fr == select_pays)}
Insert cell
md`### Merge Raw_DATA_Banque for selected country et country data `
Insert cell
data_set = {return merge (data_banque,country_data).map(obj => {
return {
//annee: obj.annee,
//mois: obj.mois,
date : obj.date,
date_txt : obj.date_texte,
volume : +obj.volume,
valeur : +obj.valeur,
insee_reg :obj.insee_reg,
dest_dept_nom : obj.dest_dept_nom,
//dest_reg_name : obj.dest_reg_name,
dest_dept_nb : obj.dest_dept_nb,
org_country_en: obj.country_name_en,
population_2019 : obj.population_2019,
org_country_fr : obj.country_name_fr,
}}).sort((a, b) => a.dest_dept_nb - b.dest_dept_nb)}
Insert cell
md`## DATA department position on the map`
Insert cell
/*raw_mosaique = d3.csv(
"https://raw.githubusercontent.com/ToulouseDataViz/COVID-19/master/data/raw_mosaique.csv",
d3.autoType
)*/

raw_mosaique = d3.csv(
"https://raw.githubusercontent.com/ToulouseDataViz/COVID-19/master/data/raw_mosaique_old.csv",
d3.autoType
)
Insert cell
mosaique =raw_mosaique //.filter(d => d.INSEE_DEP !="96" & d.INSEE_DEP !="97" & d.INSEE_DEP !="98" & d.INSEE_DEP !="99")
Insert cell
dept_traduction = d3.scaleOrdinal()
.domain(raw_mosaique.map(d=>d.INSEE_DEP))
.range(raw_mosaique.map(d=>d.NOM_DEP_M)).unknown(" ");
Insert cell
md`## DATA treatment for map display`
Insert cell
md `### Liste des jours extraite du jeu de données`
Insert cell
Mapjour = new Map(data_set.map(c => [c.date_txt, c]))
Insert cell
jour_list = Array.from(Mapjour.keys())
Insert cell
md`### liste des pays extraite du jeu de données`
Insert cell
Mappays = new Map(raw_data_banque.map(c => [c.origine_pays, c]))
Insert cell
data_pays_list = Array.from(Mappays.keys()).sort()
Insert cell
md`### Regroupements par département`
Insert cell
nesting= d3.nest()
.key(d => d.dest_dept_nb)
.entries(data_set);
Insert cell
nested_data_set = {
return nesting.map(obj => {
return {
key : obj.key,
valeur : obj.values.map(obj => {
return {
key : obj.date,
value : obj.valeur , nom_dept : obj.dest_dept_nom, insee_reg : obj.insee_reg, dest_dept_nb : obj.dest_dept_nb}}),
volume : obj.values.map(obj => {
return {
key : obj.date,
value : obj.volume , nom_dept : obj.dest_dept_nom, nom_reg : obj.dest_reg_name, dest_dept_nb : obj.dest_dept_nb}}),
}})}
Insert cell
md`### Association des raw DATA Banque et des DATA department position`
Insert cell
cartogram_data_ = mosaique.map(obj => Object.assign({}, obj, {
data: nested_data_set.find(d => d.key === obj.INSEE_DEP.toString()),
})).filter(d=>d.INSEE_DEP !='971' & d.INSEE_DEP !='972' & d.INSEE_DEP !='973' & d.INSEE_DEP !='974' & d.INSEE_DEP !='976' )
Insert cell
md`### Traitement additionel pour le cas des absences de données `
Insert cell
Insert cell
md`# Calcul du total par pays `
Insert cell
sum_selectEncoding = d3.sum(raw_data_banque.map(d=>d[selectedEncoding]))
Insert cell
total_pays = d3.nest()
.key(d=>d.origine_pays)
.rollup(function(v) { return {
dest_dept_nom : "all_pays",
volume : d3.sum(v, d=> d.volume),
valeur : d3.sum(v, d=> d.valeur),
volume_pourcent : 100*d3.sum(v, d=> d.volume)/sum_selectEncoding,
valeur_pourcent : 100*d3.sum(v, d=> d.valeur)/sum_selectEncoding,
}; })
.entries(raw_data_banque)
.sort((a, b) => b.value[selectedEncoding] - a.value[selectedEncoding])
.slice(0, 40)
Insert cell
md`# Calcul du total par départements `
Insert cell
total_dept = d3.nest()
.key(d => dept_traduction(d.dest_dept_nb))
.rollup(function(v) { return {
dest_dept_nom : "all_dept",
volume : d3.sum(v, d=> d.volume),
valeur : d3.sum(v, d=> d.valeur),
volume_pourcent : 100*d3.sum(v, d=> d.volume)/sum_selectEncoding,
valeur_pourcent : 100*d3.sum(v, d=> d.valeur)/sum_selectEncoding,
}; })
.entries(raw_data_banque)
.sort((a, b) => b.value[selectedEncoding] - a.value[selectedEncoding])
.slice(0,40)
Insert cell
md`# Calcul du total par date`
Insert cell
total_deptByCountry = d3.nest()
.key(d => d.date)
.rollup(function(v) { return {
volume : d3.sum(v, d=> d.volume),
valeur : d3.sum(v, d=> d.valeur),
}; })
.entries(raw_data_banque)
.sort((a, b) => new Date (a.key) - new Date(b.key))
Insert cell
md`## Style for row chart total pays`
Insert cell
html`
<style>
.axisColor line{
stroke: #fff;
}

.axisColor path{
stroke: #fff;
}

.axisColor text{
fill: orange;
}
</style>`

Insert cell
md`### Recherche des dates min et max du jeu de données global `
Insert cell
minmaxValues = ({
date_min: d3.min(raw_data_banque.map(d=>d.date)),
date_max: new Date(d3.max(raw_data_banque.map(d=>d.date)).getTime())
})
Insert cell
date_max_plusUnMois = new Date (minmaxValues.date_max.getFullYear()+','+(minmaxValues.date_max.getMonth()+2)+',01')
Insert cell
md`### Calcul du nombre de mois entre date min et date max`
Insert cell
month_number = 12*(minmaxValues.date_max.getFullYear() - minmaxValues.date_min.getFullYear()) + minmaxValues.date_max.getMonth() - minmaxValues.date_min.getMonth()+1
Insert cell
maxValues = ({
y: select_scale=='Auto' ? checkVar(selectedEncoding) : select_scale})

Insert cell
md`### Configuration`
Insert cell
button = (data, filename = 'data.csv') => {
if (!data) throw new Error('Array of data required as first argument');

let downloadData;
if (filename.includes('.csv')) {
downloadData = new Blob([d3.csvFormat(data)], { type: "text/csv" });
} else {
downloadData = new Blob([JSON.stringify(data, null, 2)], {
type: "application/json"
});
}

const size = (downloadData.size / 1024).toFixed(0);
const button = DOM.download(
downloadData,
filename,
//`Download ${filename} (~${size} KB)`
`Download ${filename}`
);
return button;
}
Insert cell
//parseDate = d3.timeParse('%d/%m/%Y');
parseDate = d3.utcParse('%d/%m/%Y');
Insert cell
format = d3.format(".0f");
Insert cell
//formatDateTitle =d3.timeFormat("%e %B %Y")
Insert cell
function checkVar (variable){
if(variable == "valeur")
return Math.round(d3.max(data_set.map(d=>d.valeur).flat()))
if(variable == "volume")
return Math.round(d3.max(data_set.map(d=>d.volume).flat()))
}
Insert cell
getText = d => {
let text
switch(selectedEncoding) {
case 'valeur': {
text = `${"Valeur : "+d3.format('.1f')(d.value)+"\n"}`
break
}
case 'volume': {
text = `${"Volume : "+d3.format('.1f')(d.value)+"\n"}`
break
}
default:
text = `${d.value}`
break
}
return `${d3.timeFormat("%b %y")(d.key)}\n${text}Département - ${get_dep_name (d.dest_dept_nb)} `
}
Insert cell
//dept_text = mosaique.map(d=>d.INSEE_DEP+ " - "+d.NOM_DEP)
Insert cell
function get_dep_name (number){
var nom_dep= mosaique.find(d=> d.INSEE_DEP == number).NOM_DEP
return nom_dep
}
Insert cell
get_range = ramp => {
const maxRange = 4
if (d3[`scheme${ramp}`] === undefined) {
// this is a sequential, multi-hue value
// so we'll need to do some minor work
const sequentialScale = d3.scaleSequential(d3[`interpolate${ramp}`])
.domain(z.domain())
return [
0,
maxValues[`highest_${selectedEncoding}`] / 2,
maxValues[`highest_${selectedEncoding}`]
].map(d => sequentialScale(d))
} else {
// use a scheme!
return d3[`scheme${ramp}`][maxRange]
}
}
Insert cell
get_value = (d, key=selectedEncoding) => {
// return data based on data key
const { value } = cartogram_data
.find(v => v.INSEE_DEP == d.dest_dept_nb)
.data[key]
.find(v => v.key === d.key)
return value
}
Insert cell
get_values = key => nested_data_set.map(d => d[key].map(d => d.value)).flat()
Insert cell
clusterScale = scaleCluster()
.domain(get_values(selectedEncoding))
.range(get_range(selectedRamp))
// Actual color scheme: ['rgb(251, 172, 165)', 'rgb(214, 48, 147)', 'rgb(73, 0, 106)']
Insert cell
colorRamps = [
['Blues', 'Greens', 'Greys', 'Oranges', 'Purples', 'Reds'],
['BuGn', 'BuPu', 'GnBu', 'OrRd', 'PuBuGn', 'PuBu', 'PuRd', 'RdPu', 'YlGnBu', 'YlGn', 'YlOrBr', 'YlOrRd'],
['Viridis', 'Inferno', 'Magma', 'Plasma', 'Warm', 'Cool', 'CubehelixDefault'],
['BrBG', 'PRGn', 'PiYG', 'PuOr', 'RdBu', 'RdGy', 'RdYlBu', 'RdYlGn', 'Spectral'],
['Rainbow', 'Sinebow']
]
Insert cell
path = d3.geoPath()
Insert cell
x= d3.scaleTime()
.domain([minmaxValues.date_min, minmaxValues.date_max])
.range([0, ratioHW*state_size])
Insert cell
z = d3.scaleLinear()
.domain([0, maxValues.y])
.range([state_size, 0]);

Insert cell
xAxis = g => g
.attr('transform', d => `translate(${x_column(d)}, ${y_column(d)+(z(0) - z(maxValues.y))})`)
.call(d3.axisBottom(x).ticks(12).tickSize(3).tickSizeOuter(0).tickFormat(() => ""))
Insert cell
x_column = ({column}) => 0.4*column * (state_size + state_padding)
Insert cell
y_column = ({row}) => 0.4*row * (state_size + state_padding)
Insert cell
margin = ({top: 40, right: 20, bottom: 20, left: 20})
Insert cell
ratioHW = 1.25
Insert cell
state_padding = 0
Insert cell
state_size = (width/ offset) ///
Insert cell
offset = 25
Insert cell
md`### Libraries and imports`
Insert cell
//https://observablehq.com/@jeremiak/download-data-button
Insert cell
import { printTable } from '@uwdata/data-utilities'
Insert cell
scaleCluster = require('d3-scale-cluster@1.3.1/dist/d3-scale-cluster.min.js')
Insert cell
d3 = require("d3@5", "d3-svg-legend@2", "d3-scale-chromatic@1.3.3","d3-regression", "d3-array@2")
Insert cell
import {select, color, radio, slider} from "@jashkenas/inputs"
Insert cell
import {ramp} from "@mbostock/d3-color-schemes"
Insert cell
import {rasterize, serialize} from "@mbostock/saving-svg"
Insert cell
axios = require("axios@0.19.0/dist/axios.js");
Insert cell
cheerio = require('https://bundle.run/cheerio@1.0.0-rc.2')
Insert cell
import {toDataURL} from '@mootari/embedding-fonts-into-an-svg'
Insert cell
footnote = (referencingCellName, number, text) => {
return html`<ol start=\"${number}"><li><a href="#${referencingCellName}">^</a> ${text}</li></ol>`;
}
Insert cell
//
Insert cell
footnote1 = footnote("paragraph1", 1, "ANNEXE 1")
Insert cell
md`
Le groupe BPCE publie des données en open data sur le site https://bpce.opendatasoft.com/explore/?sort=modified
https://bpce.opendatasoft.com/explore/?sort=modified

Indices Tourisme Destination 9 septembre 2020 17:48

Paiements de proximité des étrangers par département de destination

https://bpce.opendatasoft.com/explore/dataset/indices-tourisme-v2/information/?disjunctive.nom_reg&disjunctive.departement&disjunctive.cou_text_fr

Meta données associées

| Colonne | Type | Description \(FR\) | exemple |
|---------|-----------------|--------------------------------------------------------------------|-----------------------------------------|
| ANNEE | integer | Année de la mesure |2020 |
| Mois de l\'année | integer | Date de la mesure | 2017-04 |
| MOIS | date | mois de la mesure | 4 |
| Volume | real |Il s’agit du nombre de paiements effectués en proximité chez les 400 000 commerçants, artisans, etc. qui ont un contrat d’acceptation monétique avec Banque Populaire. | |
| Valeur | real |Valeur | |
| Code INSEE Région | integer | Code de la région associé au département concerné | 76 |
| Nom du Département | string | nom du département | Haute-Garonne |
| Région de destination | string | Nom de la région associé au département concerné | OCCITANIE |
|Département de destination | string | Département de destination | 31-Haute-Garonne |
| Pays d\'origine | string | Pays d\'origine | Allemagne |
Exemple de visualisation
https://donnees-territoire.banquepopulaire.fr/cas-usage.html onglet destination

---

Non utilisé dans cette application

Le site propose aussi un fichier
Indices Tourisme Origine 9 septembre 2020 17:50

Montant et nombre de dépenses issues de cartes étrangères par pays d'origine

https://bpce.opendatasoft.com/explore/dataset/indices-tourisme-origine/information/?disjunctive.cou_text_fr&disjunctive.nom_reg&disjunctive.departement

Meta données associées

Nom Région

Département de destination

Pays d'origine

Nombre de transactions

Montant des transactions

Mois de l'année


Exemple de visualisation
https://donnees-territoire.banquepopulaire.fr/cas-usage.html onglet origine

Réference BPCE https://donnees-territoire.banquepopulaire.fr/

Dans l’ensemble des données de paiement par carte bancaire, il est possible d’identifier les dépenses de proximité issues des cartes bancaires détenues par les étrangers. La France étant la première destination touristique au monde, devant l’Espagne, avec près de 90 millions de touristes étrangers en 2018, il nous a semblé intéressant de les représenter.
Comment lire ces chiffres?

Un indice mensuel en volume (nombre de transactions) et en valeur (montant des transactions) – base 1 000 000 en janvier 2017 – a donc été déterminé sur la base des codes IIN (Issuer Identification Number) qui permet de s’assurer du pays d’émission de la carte bancaire. L’indice est calculé sur la base du nombre de cartes de paiement étrangères distinctes utilisées pour les paiements.
Si les dépenses de proximité des étrangers représentaient 1 million de transactions (indice en nombre) ou 1 million d'euros (indice en montant), alors les paiements en provenance du Canada dans le département du Rhône (69) représentent 480 (en montant) et 863 (en nombre) en juillet 2018.
Comment les représenter visuellement ?

Définition

L'indice d'une grandeur est le rapport entre la valeur de cette grandeur au cours d'une période courante et sa valeur au cours d'une période de base. Il mesure la variation relative de la valeur entre la période de base et la période courante. Souvent, on multiplie le rapport par 100 ; on dit : indice base 100 à telle période.

Les indices permettent de calculer et de comparer facilement les évolutions de plusieurs grandeurs entre deux périodes données.

Par Origine : carte du monde par pays affichant la provenance des dépenses de proximité des étrangers par carte bancaire en nombre de transactions et montant des transactions. Il est possible de filtrer par département ou région de destination et de définir une période pour affiner la visualisation.

Par Destination : carte de France par département et/ou région affichant les dépenses de proximité des étrangers par carte bancaire en nombre de transactions et montant des transactions. Il est possible de filtrer par pays d’origine et de définir une période pour affiner la visualisation

L’évolution permet d’afficher une représentation dynamique en utilisant toujours les mêmes filtres et les Tops les principaux contributeurs, par département et/ou région de destination ou par pays d’origine.

`

Insert cell
footnote2 = footnote("paragraph1", 2, "ANNEXE 2")
Insert cell
md`
Explorateur de données inspiré de https://observablehq.com/@aboutaaron/small-multiple-chart-cartogram

Explorateur de données inspiré de http://www.toulouse-dataviz.fr/covidoscope/html/index_covidOscope.html

Markdown-Style Footnotes Refined :https://observablehq.com/@jashkenas/markdown-style-footnotes#paragraph2
`
Insert cell
footnote3 = footnote("paragraph1", 3, "ANNEXE 3")
Insert cell
md`
To do list :
- bloquer le zoom lors d'une action sur les sélecteurs
- nice() pour les echelles des ordonnées.
- regroupement de tous les pays et ajout "all country " dans le sélecteur de pays
https://observablehq.com/@d3/d3-group
https://observablehq.com/@t829702/d3-group-and-rollup-sortby-get-topn
- Charger les open data directement depuis le site open data soft BPCE

`
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more