Multi-year historical trends in Toronto’s shelter system — actively homeless, housing exits, and chronic homelessness from January 2018 to present, with interactive filters.
Author
Miriam Marling
data =FileAttachment("../data/shelter_flow.json").json()
viewof selectedMonth = Inputs.select(monthOptions, {label:"Month",format: d => d.label,value: monthOptions[0],width:160})
filtered = data.filter(d => {const groupMatch = d.population_group=== selectedGroupconst yearMatch = selectedYear ==="All"|| d.flow_date.slice(0,4) === selectedYearconst monthMatch = selectedMonth.value==="All"||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:newDate(y, m -1, day),month: d.flow_date.slice(0,7)} }).sort((a, b) => a.date- b.date)// Short month names used in tick labels.MON = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]// Actual time span in months between first and last filtered row.// This governs tick density — NOT the data point count, which is misleading// when one specific month is selected across many years (few points, huge span).spanMonths = filtered.length<2?1:Math.round((filtered[filtered.length-1].date- filtered[0].date)/ (30.44*24*3600*1000))// Three axis display modes for LINE charts:// dense — many years, all months (filtered.length > 20, spanMonths > 18)// → yearly ticks, year-only label ("2019")// sparse — specific month across all years (filtered.length ≤ 20, spanMonths > 18)// → yearly ticks, "Mon-YYYY" label ("Jan-2018")// single — one year selected (spanMonths ≤ 18)// → monthly ticks, "Mon" with year on January ("Jan-2018", "Feb", …)xLineDense = spanMonths >18&& filtered.length>20xLineSingle = spanMonths <=18xLine = ({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?`Jul ${y}`:""// sparse: specific month across all yearsreturn m ===0?`Jan-${y}`: m ===6?`Jul-${y}`:`${MON[m]}-${y}` }})// Helper: first and last day of a month as Date objects (local time).// Used by rectY bar charts to draw bars spanning exactly one calendar month.monthStart = d =>newDate(d.date.getFullYear(), d.date.getMonth(),1)monthEnd = d =>newDate(d.date.getFullYear(), d.date.getMonth() +1,1)// Mid-month date used to anchor pointerX tooltip snapping.monthMid = d =>newDate(d.date.getFullYear(), d.date.getMonth(),15)// Shared y formatter — no scientific notation.fmtN = d => d.toLocaleString()fmtPct = d => (d *100).toFixed(0) +"%"
Toronto publishes monthly data on its taxed shelter system, and the City’s own dashboards do a good job presenting the headline numbers. This section goes a step further: interactive filters on every chart, a clear note on what the data captures and what it leaves out, and findings that usually stay buried in technical documentation.
The data covers every month from January 2018 to the most recent published month, sourced directly from the City of Toronto’s Shelter System Flow dataset. New data loads automatically each month, usually around the 15th, after the City publishes the prior month’s figures.
This dashboard is also available as an Oracle APEX dashboard built on the same database — useful if you want to see how the same data renders in Oracle’s native low-code platform, or if you’re curious about the SQL and APEX configuration behind it.
How to read this data
These numbers reflect the shelter system, not all homelessness. The data captures people who used a City-funded overnight service at least once in the past three months. It doesn’t include people sleeping outside, in shelters that aren’t City-funded, or staying temporarily with friends or family. The City estimates that roughly 18% of people experiencing absolute homelessness in Toronto aren’t reflected in these numbers. Trends here reflect changes in the shelter system specifically — not in total homelessness in the city.
Key terms
The dashboards use a few terms that have specific meanings worth knowing before you read the charts.
Actively homeless. A person who has used City-funded shelter services at least once in the past three months and hasn’t been recorded as moving to permanent housing. This is the headline number on every dashboard. Because it looks back three months, the count includes people who may not be in shelter on any given night.
Chronic homelessness. The federal definition: someone who has spent at least 180 nights in shelter over the past year, or at least 546 nights over the past three years. A person can meet this definition while still actively in the shelter system — they don’t need to have left and returned.
Inflow categories (people entering the shelter system this month):
Newly Identified. People entering the shelter system for the first time. One exception for the “Chronic” group: in that row, this column counts people who became chronically homeless during the reporting month, regardless of how long they’d already been using the shelter system.
Returned from Permanent Housing. People who previously moved to permanent housing and have come back to the shelter system.
Returned to Shelter. People who were in the system, didn’t use it for at least three months, and have now returned.
Outflow categories (people leaving the shelter system this month):
Moved to Permanent Housing. People who left the shelter system for permanent housing.
Became Inactive. People who haven’t used shelter services in the past three months, including the reporting month.