DREAL Normandie Demande Potentielle en Logements
  • Contexte et objectifs
  • Méthodo
    • Le zonage d’étude
    • La demande potentielle en logements - le concept
    • Les projections de ménages
    • Les projections du parc
  • Résultats
    • Résultat régional
    • Résultats par département
    • Résultats par zone d’étude
    • Les fiches territoire

Contenu

  • Estimation de la demande potentielle en logements à horizon 2035
  • Décomposition par effets
  • Dynamique de la demande potentielle en logements (pour 1000 ménages)

Estimation de la demande potentielle en logements à horizon 2035

Sur le graphe suivant, la fourchette de sensibilité aux hypothèses a été représentée pour chacune des 34 zones. Selon les territoires, on constate que cette sensibilité aux hypothèses est plus ou moins importante ; généralement, plus le territoire est urbain, plus la fourchette est grande.

Code
data_DPL_scenarios_t = transpose (data_DPL_scenarios)

// mettre à jour librairie plot pour faire des round corners
Plot = import("https://cdn.jsdelivr.net/npm/@observablehq/plot/+esm")

// doc :
// https://observablehq.com/@observablehq/input-table
Inputs.table(data_DPL_scenarios_t,{
  header: {
    "valeur": "Nb de logements / an"
  },
  format: {
    "valeur": d => Math.round(d)
  }
})
Code
logt_comm_periode = { 
  let result = [];
  for (let i = 0; i < 34; i++) {
  result.push(
    {
      "Libellé zonage": data_DPL_scenarios_t[i]["Libellé zonage"],
      periode: "lgts commencés 2015-2019",
      "Logts ordinaires commencés /an": data_DPL_scenarios_t[i]["Logts ordinaires commencés /an sur [2015-2019]"]
    },
    {
      "Libellé zonage": data_DPL_scenarios_t[i]["Libellé zonage"],
      periode: "lgts commencés 2020-2023 (Sitadel)",
      "Logts ordinaires commencés /an": data_DPL_scenarios_t[i]["Logts ordinaires commencés /an sur [2020-2023]"]
    }
  );
  }
return result;
}
Code
Plot.plot({
  marginLeft: 50,
  marginRight: 100,
  marginTop: 50,
  marginBottom: 150,
  height: 600,
  width: 1100,
  style: {
    fontSize: 12,
  },
  y: {domain:[-200,2600], ticks: 14, tickFormat: d => d.toLocaleString('fr-FR'),grid: true, label: "Nb de logements / an"},
  x: {tickRotate: -30, label: "", inset: 10},
  color: {
    legend: true,
    domain: ["lgts commencés 2015-2019","lgts commencés 2020-2023 (Sitadel)"], // les catégories de fill
    range: ["orange", "#16fa53"] // les couleurs choisies
  },
  subtitle: "Estimation de la demande potentielle en logements à horizon 2035 (moyenne annuelle)",

  marks: [
    Plot.barY(data_DPL_scenarios_t, {
      x: "Libellé zonage", 
      y1: "Tendanciel BAS", 
      y2: "Tendanciel HAUT", 
      fill: "steelblue",
      r: 3
    }),
    
    Plot.dot(data_DPL_scenarios_t, {
      x: "Libellé zonage", 
      y: "Tendanciel BAS",
      fill: "steelblue",
      symbol: "diamond",
      r: 5,
      tip: {
        format: {          
          y: d => Math.round(d).toLocaleString('fr-FR'),              
                }
           }
    }),
    
    Plot.dot(data_DPL_scenarios_t, {
      x: "Libellé zonage", 
      y: "Tendanciel HAUT",
      fill: "steelblue",
      symbol: "diamond",
      r: 5,
      tip: {
        format: {          
          y: d => Math.round(d).toLocaleString('fr-FR'),              
                }
           }
    }),
    
    Plot.dot(data_DPL_scenarios_t, {
      x: "Libellé zonage", 
      y: "Tendanciel CENTRAL",
      fill: "black",
      symbol: "star",
      sort: {x: "y"},
      r: 4,
      tip: {
        format: {          
          y: d => Math.round(d).toLocaleString('fr-FR'),              
                }
           }
    }),
    
    Plot.ruleY([0]),
    
    Plot.text(data_DPL_scenarios_t, {
      x: "Libellé zonage", 
      y: "Tendanciel CENTRAL", 
      //dx: 5,
      dy: -10,
      text: d => Math.round(d["Tendanciel CENTRAL"]).toLocaleString('fr-FR'),
      fill:"black", 
      fontSize :10
    }),
    
   Plot.tickY(logt_comm_periode, {
      x: "Libellé zonage",
      y: "Logts ordinaires commencés /an",
      stroke: "periode",
      strokeWidth: 2,
      fill: "periode",
      tip: true
      })
  ]
})

Décomposition par effets

Si l’on s’intéresse au scénario central, on peut connaître de façon plus précise l’origine de cette demande. Le graphique suivant présente les résultats du scénario central pour le zonage d’étude (34 zones) et permet d’apprécier le « profil » de la demande pour chaque territoire. Certaines composantes peuvent diminuer le résultat, cela résulte soit d’un effet démographique négatif, soit d’une possible mobilisation du parc existant pour répondre aux besoins en résidences principales.

Code
data_long_central_ojs = transpose (data_long_central)

// doc :
// https://observablehq.com/@observablehq/input-table
Inputs.table(data_long_central_ojs,{
  header: {
    "valeur": "Nb de logements / an"
  },
  format: {
    "valeur": d => Math.round(d)
  }
})

Décomposition de l’évolution annuelle du nombre de ménages en Normandie selon le type d’effet (scénario central)

Code
colorPalette = { return {
  "Ménage par an – effet nouvelle population": "#83caff",  // Bleu
  "Ménage par an – effet déformation pyramide des âges": "#9999ff",  // Violet
  "Ménage par an – effet évolution des modes de cohabitation": "#198a8a",  // Cyan
  "Renouvellement par an": "#c5000b",  // Rouge
  "Vacance par an": "#ffd320",  // Jaune
  "Résidences Secondaires et Logts Occasion. par an": "#81d41a"  // Vert
}};

Plot.plot({
  marginLeft: 50,
  marginRight: 100,
  marginBottom: 150,
  height: 600,
  width: 1200,
  style: {
    fontSize: 12,
  },
  x: {tickRotate: -30, label: ""},
  y: {grid: true, 
      label: "Nb de logts / an",
      tickFormat: y => y.toLocaleString('fr-FR')
     },
  color: {legend: true, domain: Object.keys(colorPalette), range: Object.values(colorPalette)},

  marks: [
    Plot.barY(data_long_central_ojs.filter(d => d.effet != "Moyenne annuelle Demande Potentielle logements"), {
      x: "Libellé zonage", 
      y: "valeur", 
      fill: "effet", 
      tip: true,
    }),
    
    Plot.ruleY([0]),

    // Cercle pour le fond de texte
    Plot.dotY(data_long_central_ojs.filter(d => d.effet == "Moyenne annuelle Demande Potentielle logements"), {
      x: "Libellé zonage", 
      y: "valeur",
      fill: "white",
      stroke: "black",
      sort: {x: "y"},
      r:12
    }),
    
    Plot.text(data_long_central_ojs.filter(d => d.effet == "Moyenne annuelle Demande Potentielle logements"), {
      x: "Libellé zonage", 
      y: "valeur", 
      text: d => Math.round(d.valeur).toLocaleString('fr-FR'),
      fontSize :10, 
      textAnchor: "middle" 
    })

  ]
})

L’origine de la demande potentielle en logements diffère fortement d’une zone à l’autre.

À l’échelle de chaque zonage d’étude, la part de la demande potentielle en logements liée à l’évolution des ménages (= résidences principales) et celle liée à l’évolution du parc représentent respectivement :

Code
data_DPL_part_parcs_t = transpose (data_DPL_part_parc)

Inputs.table(data_DPL_part_parcs_t.map(
  d => ({...d,
  "Part ménages": new Intl.NumberFormat("fr-FR", {
    minimumFractionDigits: 0,
    maximumFractionDigits: 0
  }).format(d["Part ménages"] * 100) + " %",
  "Part parc": new Intl.NumberFormat("fr-FR", {
    minimumFractionDigits: 0,
    maximumFractionDigits: 0
  }).format(d["Part parc"] * 100) + " %"
})))


Dynamique de la demande potentielle en logements (pour 1000 ménages)

  • Cartographie
  • Scatterplot
  • Histogramme
Code
bertin = require("bertin") // le ggplot de la carto en javascript

// on charge le géojson
zonage = FileAttachment("data/zonage.geojson").json()

// import {view} from "@neocartocnrs/geoverview"
// view(zonage)

// on récupère la donnée préparée avec R et on passe d'un format colonne à un format javascript
data_wide_ojs = transpose(data_wide)
Code
data_wide_ojs_geojson = bertin.merge(zonage, "zones_dp_1", data_wide_ojs, "id", true)
Code
bertin.draw({
  params: { projection:"Mercator", margin: 50, width: 800},
  layers: [
    {
      type: "bubble",
      geojson: data_wide_ojs_geojson,
      stroke:"black",
      values: "Moyenne annuelle Demande Potentielle logements",
      k: 25,
      tooltip: [
        "$Libellé zonage", 
        d=> Math.round(d.properties["Moyenne annuelle Demande Potentielle logements"])+        " logts/an"
        ],
        fill: {
        type: "split",
        values: "Moyenne annuelle Demande Potentielle logements",
        colors: ["#7df558", "#F25842"],
        split: 0
      },
      leg_round: -1,
      leg_title: `Moyenne annuelle DPL`,
      leg_x: 10,
      leg_y: 10,
      leg_stroke: "#d15406"
    },
    
    {
      type: "layer",
      geojson: data_wide_ojs_geojson,
      fill: {
        type: "choro",
        values: "demande potentielle annuelle pour 1000 ménages",
        breaks : [-5, 0, 5, 10, 15],
        colors: ["#fce9e8", "#c9e2f5", "#7aaacf", "#033a91"],
        leg_round: -1,
        leg_title: "DPL annuelle pour 1000 ménages",
        leg_x: 300,
        leg_y: 40
            },
      tooltip: [
        "$Libellé zonage", 
        d=> Math.round(d.properties["demande potentielle annuelle pour 1000 ménages"])+        " logts/an pour 1000 ménages"
              ],
      stroke: "black",
      strokeWidth: 2.5
    },
    
        { 
      type: "layer",
      geojson: zonage, 
      fill: "white", 
      fillOpacity: 0.1, 
      stroke: "black",
      strokeWidth: 2.5
    },
  ]
})
Code
data_DPL_central_rythme_t = transpose (data_DPL_central_rythme)
Code
Plot.plot({
  marginLeft: 100,
  marginRight: 100,
  marginTop: 50,
  //height: 1100,
  width: 900,
  style: {
    fontSize: 12,
  },
  y: {tickFormat: d => d.toLocaleString('fr-FR'),grid: true, label: "Nb de lgts / an pour 1000 ménages"},
  x: {tickFormat: d => d.toLocaleString('fr-FR'),label: "DPL par an"},
  subtitle: "Demande potentielle en logements à horizon 2035 (moyenne annuelle)",

  marks: [
    Plot.dot(data_DPL_central_rythme_t, {
      x: "Moyenne annuelle Demande Potentielle logements", 
      y: "demande potentielle annuelle pour 1000 ménages",
      channels: {Nom_zone: "Libellé zonage"},
      tip: {
        format: {          
          x: d => Math.round(d).toLocaleString('fr-FR'),
          y: d => (Math.round(d*10)/10).toLocaleString('fr-FR'),
                }
           }
    }),
    
    Plot.dot(data_DPL_central_rythme_t,
        Plot.pointer({
            x: "Moyenne annuelle Demande Potentielle logements",
            y: "demande potentielle annuelle pour 1000 ménages",
            fill: "red",
            r: 8
                    })
            ),
            
    Plot.text(data_DPL_central_rythme_t, {x: "Moyenne annuelle Demande Potentielle logements", y: "demande potentielle annuelle pour 1000 ménages", text: (d) => d["Libellé zonage"], dy: -6, lineAnchor: "bottom", fontSize:7}),
    
   Plot.ruleY([0]),
   Plot.ruleX([0]),
  ]
})
Code
{
  const v1 = (d) => d["Moyenne annuelle Demande Potentielle logements"];
  const v2 = (d) => d["demande potentielle annuelle pour 1000 ménages"];
  const y2 = d3.scaleLinear(d3.extent(data_DPL_central_rythme_t, v2), [-2, d3.max(data_DPL_central_rythme_t, v1)]);
  
  return Plot.plot({
    marginLeft: 100,
    marginRight: 100,
    marginTop: 50,
    marginBottom: 150,
    width: 900,
    style: {fontSize: 12},
    x: {tickRotate: -30, tickFormat: d => d.toLocaleString('fr-FR'),label: ""},
    y: {axis: "left", tickFormat: d => d.toLocaleString('fr-FR'), grid: true, label: "DPL lgt/an"},
    subtitle: "Demande potentielle en logements à horizon 2035 (moyenne annuelle)",
    
    marks: [
      Plot.axisY(y2.ticks(), {color: "orange", anchor: "right", label: "DPL/an pour 1000 ménages", y: y2, tickFormat: y2.tickFormat()}),
      
      Plot.barY(data_DPL_central_rythme_t, {
      x: "Libellé zonage", 
      y: v1,
      fill: "steelblue",
      tip: {
        format: {y: d => (Math.round(d).toLocaleString('fr-FR'))}
           }
    }),
    
      Plot.ruleY([0]),

      Plot.dotY(data_DPL_central_rythme_t, Plot.mapY((D) => D.map(y2), {
          x: "Libellé zonage",
          y: v2,
          sort: {x:"-y"},
          fill: "orange",
          channels: {"DPL/an pour 1000 ménages": d => d["demande potentielle annuelle pour 1000 ménages"].toLocaleString('fr-FR'), zone: "Libellé zonage"},
          tip: { format: {
                x: false,
                y: false
                      }},
            }
          )
        )
    ]
  });
}
Retour au sommet