BonQuery
  • Home
  • Left in the Cold
  • Audits
    • INDEPENDENT OVERSIGHT
    • Discrepancy Tracker
    • Emergency Occupancy Audit
    • Central Intake Audit
    • About the Data
  • Shelter Dashboards
    • Inside Toronto’s Shelter System
    • Monthly System Flow Replication
    • Year-to-Date Capacity Match
    • Historical Trend Lines
    • Referral Requests Analysis
    • Daily Occupancy & Capacity
  • About
  • Accueil
  • Laissés dans le froid
  • Audits
    • SURVEILLANCE INDÉPENDANTE
    • Suivi des divergences
    • Audit de l’occupation d’urgence
    • Audit de l’admission centrale
    • À propos des données
  • Tableaux de bord
    • Le réseau de refuges de Toronto
    • Réplication du flux mensuel
    • Concordance année en cours
    • Tendances historiques
    • Analyse des demandes d’orientation
    • Occupation et capacité quotidiennes
  • À propos
  • FR
  • EN

Tendances historiques

Réseau de refuges de Toronto — séries chronologiques pluriannuelles

Tendances historiques pluriannuelles du réseau de refuges de Toronto — itinérance active, sorties vers le logement et itinérance chronique de janvier 2018 à aujourd’hui, avec filtres interactifs.

Auteur(-trice)

Miriam Marling

data = FileAttachment("../data/shelter_flow.json").json()
populationGroups = [
  "All Population",
  ...Array.from(new Set(data.map(d => d.population_group)))
    .filter(g => g !== "All Population")
    .sort()
]

availableYears = [
  "Toutes",
  ...Array.from(new Set(data.map(d => d.flow_date.slice(0, 4)))).sort()
]

monthOptions = [
  {label: "Tous", value: "Tous"},
  ...Array.from({length: 12}, (_, i) => ({
    label: new Date(2000, i).toLocaleString("fr-CA", {month: "long"}),
    value: String(i + 1)
  }))
]
viewof selectedGroup = Inputs.select(populationGroups, {
  label: "Groupe de population", value: "All Population", width: 220
})
viewof selectedYear = Inputs.select(availableYears, {
  label: "Année", value: "Toutes", width: 120
})
viewof selectedMonth = Inputs.select(monthOptions, {
  label: "Mois", format: d => d.label, value: monthOptions[0], width: 160
})
filtered = data
  .filter(d => {
    const groupMatch = d.population_group === selectedGroup
    const yearMatch  = selectedYear === "Toutes" || d.flow_date.slice(0, 4) === selectedYear
    const monthMatch = selectedMonth.value === "Tous" ||
                       parseInt(d.flow_date.slice(5, 7)) === parseInt(selectedMonth.value)
    return groupMatch && yearMatch && monthMatch
  })
  .map(d => {
    const [y, m, day] = d.flow_date.split("-").map(Number)
    return {...d, date: new Date(y, m - 1, day), month: d.flow_date.slice(0, 7)}
  })
  .sort((a, b) => a.date - b.date)

MON = ["janv.","févr.","mars","avr.","mai","juin",
       "juill.","août","sept.","oct.","nov.","déc."]

spanMonths = filtered.length < 2 ? 1 :
  Math.round((filtered[filtered.length-1].date - filtered[0].date)
             / (30.44 * 24 * 3600 * 1000))

xLineDense  = spanMonths > 18 && filtered.length > 20
xLineSingle = spanMonths <= 18

xLine = ({
  type: "time",
  label: null,
  ticks: xLineSingle ? d3.utcMonth.every(1) : 8,
  tickFormat: d => {
    const m = d.getMonth(), y = d.getFullYear()
    if (xLineSingle)  return m === 0 ? `${MON[m]}-${y}` : MON[m]
    if (xLineDense)   return m === 0 ? String(y) : m === 6 ? `juill. ${y}` : ""
    return m === 0 ? `janv.-${y}` : m === 6 ? `juill.-${y}` : `${MON[m]}-${y}`
  }
})

monthStart = d => new Date(d.date.getFullYear(), d.date.getMonth(), 1)
monthEnd   = d => new Date(d.date.getFullYear(), d.date.getMonth() + 1, 1)
monthMid   = d => new Date(d.date.getFullYear(), d.date.getMonth(), 15)

fmtN   = d => d.toLocaleString("fr-CA")
fmtPct = d => (d * 100).toFixed(0) + " %"

La Ville de Toronto publie mensuellement des données sur son réseau de refuges, et ses propres tableaux de bord présentent bien les chiffres principaux. Cette section va plus loin : filtres interactifs sur chaque graphique, une note explicite sur ce que les données couvrent et ce qu’elles excluent, et des conclusions qui restent habituellement enfouies dans la documentation technique.

Les données couvrent chaque mois de janvier 2018 au mois le plus récemment publié, directement issues du jeu de données Flux du réseau de refuges de la Ville de Toronto. Les nouvelles données se chargent automatiquement chaque mois, généralement vers le 15, après que la Ville publie les chiffres du mois précédent.


Personnes en situation d’itinérance active au cours des 3 derniers mois

Plot.plot({
  width, height: 380, marginLeft: 70,
  x: xLine,
  y: {label: "Personnes en situation d'itinérance active", grid: true, tickFormat: fmtN},
  marks: [
    Plot.ruleY([0]),
    Plot.line(filtered, {x: "date", y: "actively_homeless", stroke: "#FF2D55", strokeWidth: 2}),
    Plot.dot(filtered,  {x: "date", y: "actively_homeless", fill:   "#FF2D55", r: 2}),
    Plot.tip(filtered, Plot.pointerX({
      x: "date", y: "actively_homeless",
      title: d => `${d.month}\n${d.actively_homeless.toLocaleString("fr-CA")} personnes`
    }))
  ]
})

Variation nette (entrées moins sorties) par mois

netData = filtered.map(d => ({
  date: d.date, month: d.month,
  net_change: d.newly_identified + d.returned_from_housing + d.returned_to_shelter
              - d.moved_to_housing - d.became_inactive
}))

Plot.plot({
  width, height: 380, marginLeft: 70,
  x: xLine,
  y: {label: "Variation nette (personnes)", grid: true, tickFormat: fmtN},
  marks: [
    Plot.ruleY([0], {stroke: getComputedStyle(document.body).getPropertyValue("--bq-fg-secondary"), strokeWidth: 1.5}),
    Plot.line(netData, {x: "date", y: "net_change", stroke: "#5856D6", strokeWidth: 2}),
    Plot.dot(netData,  {x: "date", y: "net_change", fill:   "#5856D6", r: 2}),
    Plot.tip(netData, Plot.pointerX({
      x: "date", y: "net_change",
      title: d => {
        const sign = d.net_change >= 0 ? "+" : ""
        return `${d.month}\n${sign}${d.net_change.toLocaleString("fr-CA")} personnes`
      }
    }))
  ]
})

Total des entrées et sorties par mois

totalRectData = filtered.map(d => {
  const inflow  = d.newly_identified + d.returned_from_housing + d.returned_to_shelter
  const outflow = d.moved_to_housing + d.became_inactive
  const lbl     = `${MON[parseInt(d.month.slice(5,7))-1]}-${d.month.slice(0,4)}`
  return {
    x1: monthStart(d), x2: monthEnd(d), xMid: monthMid(d),
    inflow, outflow,
    tipTitle: `${lbl}\nEntrées :  +${inflow.toLocaleString("fr-CA")}\nSorties : −${outflow.toLocaleString("fr-CA")}\nNet :      ${(inflow-outflow)>=0?"+":""}${(inflow-outflow).toLocaleString("fr-CA")}`
  }
})

Plot.plot({
  width, height: 380, marginLeft: 70,
  x: xLine,
  y: {label: "Personnes", grid: true, tickFormat: fmtN},
  color: {domain: ["Entrées","Sorties"], range: ["#E63946","#66CC66"], legend: true},
  marks: [
    Plot.ruleY([0]),
    Plot.rectY(totalRectData, {x1: "x1", x2: "x2", y1: 0, y2: "inflow",         fill: "#E63946", insetLeft: 0.5, insetRight: 0.5}),
    Plot.rectY(totalRectData, {x1: "x1", x2: "x2", y1: d => -d.outflow, y2: 0,  fill: "#66CC66", insetLeft: 0.5, insetRight: 0.5}),
    Plot.tip(totalRectData, Plot.pointerX({x: "xMid", title: d => d.tipTitle}))
  ]
})

Entrées et sorties détaillées par mois

detailedFlowTypes = [
  "Entrées – Nouvellement repérés",
  "Entrées – Retour du logement permanent",
  "Entrées – Retour au refuge",
  "Sorties – Devenus inactifs",
  "Sorties – Accès au logement permanent"
]

detailedColors = ["#E63946","#FFD600","#FB8C00","#512DA8","#66CC66"]

detailRectData = filtered.flatMap(d => {
  const x1 = monthStart(d), x2 = monthEnd(d), xMid = monthMid(d)
  const ni = d.newly_identified, rfh = d.returned_from_housing,
        rts = d.returned_to_shelter, bi = d.became_inactive, mh = d.moved_to_housing
  return [
    {x1, x2, xMid, type: "Entrées – Nouvellement repérés",           y1: 0,       y2: ni},
    {x1, x2, xMid, type: "Entrées – Retour du logement permanent",   y1: ni,      y2: ni+rfh},
    {x1, x2, xMid, type: "Entrées – Retour au refuge",               y1: ni+rfh,  y2: ni+rfh+rts},
    {x1, x2, xMid, type: "Sorties – Devenus inactifs",               y1: 0,       y2: -bi},
    {x1, x2, xMid, type: "Sorties – Accès au logement permanent",    y1: -bi,     y2: -(bi+mh)}
  ]
})

detailTipData = filtered.map(d => {
  const lbl = `${MON[parseInt(d.month.slice(5,7))-1]}-${d.month.slice(0,4)}`
  return {
    xMid: monthMid(d),
    tipTitle: [
      lbl,
      `Nouvellement repérés :       +${d.newly_identified.toLocaleString("fr-CA")}`,
      `Retour du logement perm. :   +${d.returned_from_housing.toLocaleString("fr-CA")}`,
      `Retour au refuge :           +${d.returned_to_shelter.toLocaleString("fr-CA")}`,
      `Devenus inactifs :           −${d.became_inactive.toLocaleString("fr-CA")}`,
      `Accès au logement perm. :    −${d.moved_to_housing.toLocaleString("fr-CA")}`
    ].join("\n")
  }
})

Plot.plot({
  width, height: 420, marginLeft: 70,
  x: xLine,
  y: {label: "Personnes", grid: true, tickFormat: fmtN},
  color: {domain: detailedFlowTypes, range: detailedColors, legend: true},
  marks: [
    Plot.ruleY([0]),
    Plot.rectY(detailRectData, {x1: "x1", x2: "x2", y1: "y1", y2: "y2", fill: "type", insetLeft: 0.5, insetRight: 0.5}),
    Plot.tip(detailTipData, Plot.pointerX({x: "xMid", title: d => d.tipTitle}))
  ]
})

Âge des personnes en situation d’itinérance active au cours des 3 derniers mois

ageBandDefs = [
  {key: "age_under_16", label: "Moins de 16 ans"},
  {key: "age_16_24",    label: "16–24"},
  {key: "age_25_34",    label: "25–34"},
  {key: "age_35_44",    label: "35–44"},
  {key: "age_45_54",    label: "45–54"},
  {key: "age_55_64",    label: "55–64"},
  {key: "age_65_over",  label: "65+"}
]

ageData = filtered.flatMap(d => {
  const total = ageBandDefs.reduce((s, b) => s + (d[b.key] || 0), 0)
  return ageBandDefs.map(b => ({
    date: d.date, month: d.month, band: b.label,
    pct: total > 0 ? d[b.key] / total : null
  }))
})

Plot.plot({
  width, height: 400, marginLeft: 60,
  x: xLine,
  y: {label: "Part du total par groupe d'âge", grid: true, tickFormat: fmtPct},
  color: {legend: true},
  marks: [
    Plot.ruleY([0]),
    Plot.line(ageData, {x: "date", y: "pct", stroke: "band", strokeWidth: 1.8}),
    Plot.tip(ageData, Plot.pointerX({
      x: "date", y: "pct", stroke: "band",
      title: d => {
        const lbl = `${MON[parseInt(d.month.slice(5,7))-1]} ${d.month.slice(0,4)}`
        return `${d.band} — ${lbl}\n${(d.pct * 100).toFixed(1)} %`
      }
    }))
  ]
})

Genre des personnes en situation d’itinérance active au cours des 3 derniers mois

genderDefs = [
  {key: "gender_male",                label: "Hommes"},
  {key: "gender_female",              label: "Femmes"},
  {key: "gender_trans_nb_two_spirit", label: "Trans, non binaires ou bispirituels"}
]

genderData = filtered.flatMap(d => {
  const total = genderDefs.reduce((s, g) => s + (d[g.key] || 0), 0)
  return genderDefs.map(g => ({
    date: d.date, month: d.month, gender: g.label,
    pct: total > 0 ? d[g.key] / total : null
  }))
})

Plot.plot({
  width, height: 400, marginLeft: 60,
  x: xLine,
  y: {label: "Part du total par genre", grid: true, tickFormat: fmtPct},
  color: {legend: true},
  marks: [
    Plot.ruleY([0]),
    Plot.line(genderData, {x: "date", y: "pct", stroke: "gender", strokeWidth: 1.8}),
    Plot.tip(genderData, Plot.pointerX({
      x: "date", y: "pct", stroke: "gender",
      title: d => {
        const lbl = `${MON[parseInt(d.month.slice(5,7))-1]} ${d.month.slice(0,4)}`
        return `${d.gender} — ${lbl}\n${(d.pct * 100).toFixed(1)} %`
      }
    }))
  ]
})

Consulter les autres tableaux de bord :

  • Portrait mensuel
  • Comparaison annuelle cumulative

Ce tableau de bord est également disponible en tant que tableau de bord Oracle APEX reposant sur la même base de données — utile pour voir comment les mêmes données s’affichent dans la plateforme native à faible code d’Oracle, ou pour explorer le SQL et la configuration APEX sous-jacents.

Comment lire ces données

Ces chiffres reflètent le réseau de refuges, et non l’ensemble du phénomène de l’itinérance. Les données recensent les personnes ayant utilisé un service d’hébergement de nuit financé par la Ville au moins une fois au cours des trois derniers mois. Elles n’incluent pas les personnes qui dorment à l’extérieur, dans des refuges non financés par la Ville, ou qui séjournent temporairement chez des amis ou de la famille. La Ville estime qu’environ 18 % des personnes en situation d’itinérance absolue à Toronto ne sont pas reflétées dans ces chiffres. Les tendances présentées ici reflètent les changements dans le réseau de refuges spécifiquement — et non dans l’ensemble de l’itinérance dans la ville.

Définitions clés

Les tableaux de bord utilisent quelques termes ayant des significations précises qu’il vaut la peine de connaître avant de lire les graphiques.

Itinérance active. Une personne ayant utilisé les services d’hébergement financés par la Ville au moins une fois au cours des trois derniers mois et dont le déménagement vers un logement permanent n’a pas été enregistré. C’est le chiffre principal de chaque tableau de bord. Comme il remonte à trois mois en arrière, ce dénombrement inclut des personnes qui peuvent ne pas être en refuge un soir donné.

Itinérance chronique. La définition fédérale : une personne ayant passé au moins 180 nuits en refuge au cours de l’année écoulée, ou au moins 546 nuits au cours des trois dernières années. Une personne peut satisfaire à cette définition tout en étant encore dans le réseau de refuges — elle n’a pas besoin d’être partie et revenue.

Catégories d’entrées (personnes intégrant le réseau de refuges ce mois-ci) :

  • Nouvellement repérés. Personnes entrant dans le réseau de refuges pour la première fois. Exception pour le groupe « Chronique » : dans ce cas, cette colonne comptabilise les personnes devenues en situation d’itinérance chronique au cours du mois de référence, quelle que soit la durée de leur utilisation antérieure du réseau.
  • Retour du logement permanent. Personnes ayant précédemment accédé à un logement permanent et revenues dans le réseau de refuges.
  • Retour au refuge. Personnes qui étaient dans le réseau, ne l’ont pas utilisé pendant au moins trois mois, et y sont revenues.

Catégories de sorties (personnes quittant le réseau de refuges ce mois-ci) :

  • Accès au logement permanent. Personnes ayant quitté le réseau de refuges pour un logement permanent.
  • Devenus inactifs. Personnes n’ayant pas utilisé les services d’hébergement au cours des trois derniers mois, y compris le mois de référence.

Définitions basées sur la page Données sur les flux du réseau de refuges de la Ville de Toronto.

Lire toutes les conclusions →

Source des données

Toutes les données proviennent du jeu de données Flux du réseau de refuges de Toronto de la Ville de Toronto, publié mensuellement sur le portail de données ouvertes de la Ville.

Contient des informations sous licence Licence du gouvernement ouvert – Toronto.

 

Un audit de données indépendant pour les résidents de Toronto. / An independent data audit for Toronto residents.
© 2026 Miriam Marling · BonQuery