Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion posts/foreign-buyer-tax-vancouver-toronto/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@

<div class="text">

<details class="details-block" style="margin-bottom: 60px;">
<details class="details-block data-methods" style="margin-bottom: 60px;">
<summary>About the dynamic difference-in-differences models</summary>
<p>
A standard difference-in-differences model compares one group's change over time to another group's change, before and after a policy, and treats the gap between them as the estimated effect. A dynamic version, also called an event study, estimates that gap separately for each year rather than assuming one constant effect for the whole post-policy period. That makes it possible to see how the effect builds or fades over time, and to check that taxed and untaxed areas were not already trending apart before the tax existed.
Expand Down
68 changes: 68 additions & 0 deletions posts/sidewalk-coverage-toronto/+page.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<script>
import ChartFrame from '$lib/ChartFrame.svelte';
import charts from './charts.js';
import meta from './meta.json';
import SidewalkCoverageMap from './charts/sidewalk-coverage-map.svelte';
</script>

<div class="text">

<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
</p>
<p>
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>

</div>

<ChartFrame meta={charts['sidewalk-coverage-map']} authors={meta.authors} license={meta.license} chartKey="sidewalk-coverage-map">
<SidewalkCoverageMap />
</ChartFrame>

<div class="text">

<p>
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.
</p>
<p>
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit.
</p>

</div>

<div class = "text">

<div class="details-block data-methods">

<h2>Data sources and processing</h2>

<p>
This data draws two sources from the City of Toronto: a 2019 baseline of where sidewalks were missing, and two overlapping records of what's been built or planned as of 2026. Each data source is described below, along with how we combined them.
</p>

<p>
Overall, the map on this page is meant to show citywide patterns, not to confirm the status of a specific address or segment. If you want to know whether a sidewalk is planned, underway, or completed on your own street, the city's <a href="https://www.toronto.ca/services-payments/streets-parking-transportation/sidewalk-tours-wayfinding/sidewalks-in-toronto/sidewalk-programs-policies-and-bylaws/" target="_blank" rel="noopener noreferrer">Sidewalk Programs, Policies and By-laws</a> page is where to find further information.
</p>

<p>
The <a href="https://open.toronto.ca/dataset/pedestrian-network/" target="_blank" rel="noopener noreferrer">Pedestrian Network </a> layer comes from the City of Toronto's Open Data portal, first published in August 2019 by the City. At the time of writing, the portal lists the data as "last refreshed" in February 2026, but that date reflects when the files were last re-exported, not necessarily when the underlying sidewalk geometry was last checked. The dataset's own documentation dates to January 2020, and there's no changelog indicating what, if anything, has been updated since. We thus treat it here as a snapshot of sidewalk coverage circa 2019–2020 rather than a more up-to-date inventory. It's the baseline for the map on this page: each road segment is coded by whether a sidewalk exists on both sides, one side, neither side, or not at all.
</p>

<p>
The <a href="https://open.toronto.ca/dataset/sidewalk-construction-program/" target="_blank" rel="noopener noreferrer">Sidewalk Construction Program</a> dataset, on the Open Data portal, lists locations currently in the city's active pipeline for new sidewalk installation. 96 locations at the time of writing, with planned start years from 2023 to 2027. Every record in it is marked with an "Active" status, but there is no "completed" status and no changelog, so as of this dataset's last refresh (February 2026) it tells us only what was planned or underway at that time. Some of it may since have been completed.
</p>

<p>
As well, each year since 2020, Transportation Services has reported new missing-sidewalk installations to the Infrastructure and Environment Committee. All seven reports are linked from the city's <a href="https://www.toronto.ca/services-payments/streets-parking-transportation/sidewalk-tours-wayfinding/sidewalks-in-toronto/sidewalk-programs-policies-and-bylaws/" target="_blank" rel="noopener noreferrer">Sidewalk Programs, Policies and By-laws</a> page.
</p>

<p>
We then matched the council-report locations against the Sidewalk Construction Program records by street name. 62 matched, and where they did, the "from/to" descriptions lined up almost exactly, confirming the Construction Program dataset is fed by these same annual reports rather than being an independent source. For the remaining 75 locations, which don't (yet, or ever) appear in the Construction Program list, we located them on the ground by matching their street names relative to the City's <a href="https://open.toronto.ca/dataset/toronto-centreline-tcl/" target="_blank" rel="noopener noreferrer">Centreline (TCL)</a> dataset, then used that location to pull the corresponding geometry. Eleven street names existed in more than one part of the city (e.g. two separate Hillside Drives), so we used each report's stated ward, matched against the City's <a href="https://open.toronto.ca/dataset/city-wards/" target="_blank" rel="noopener noreferrer">ward boundaries</a>, to keep only the correct one. This resolved almost all of the locations to the right street and general location.
</p>



</div>

</div>
26 changes: 26 additions & 0 deletions posts/sidewalk-coverage-toronto/charts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { resolveDownloads } from '$lib/downloads.js';

const dataUrls = import.meta.glob('./data/*', { eager: true, query: '?url', import: 'default' });
const pngUrls = import.meta.glob('./published/*/*.png', {
eager: true,
query: '?url',
import: 'default'
});
const embedMeta = import.meta.glob('./published/*/embed.json', {
eager: true,
import: 'default'
});

const charts = {
'sidewalk-coverage-map': {
authors: ['Jeff Allen'],
title: 'Mapping sidewalk coverage in Toronto',
subtitle: '71% of streets have sidewalks on both sides; 13% have no sidewalks at all',
source: 'City of Toronto: Pedestrian Network Data (2019) and Sidewalk Construction Program and annual council reports (2020-2026)',
alt: "Map of every street in Toronto, colored by sidewalk coverage: blue for sidewalks on both sides, yellow for one side only, and red for no sidewalk. Blue dominates downtown and older neighbourhoods; red and yellow cluster in the inner suburbs, especially parts of Etobicoke, North York, and Scarborough. A few black lines mark streets with a new or planned sidewalk installation since 2020.",
widths: [1440, 1080],
graphicVerb: 'created'
}
};

export default resolveDownloads(charts, { dataUrls, pngUrls, embedMeta });
139 changes: 139 additions & 0 deletions posts/sidewalk-coverage-toronto/charts/sidewalk-coverage-map.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
<script>
import mapImage from '../images/toronto-sidewalks-qgis-for-web-labels.png';

// Sampled from the rendered PNG's own line colors, so the legend matches what's drawn.
// Grouped by source: the first three come from the 2019 PedNet baseline, the last
// from combining the Sidewalk Construction Program with the annual council reports.
const legendGroups = [
{
title: '2019 baseline',
items: [
{ color: '#44bde9', label: 'Sidewalk on both sides' },
{ color: '#f2c400', label: 'Sidewalk on one side only' },
{ color: '#dc230d', label: 'No sidewalk' }
]
},
{
title: 'Since 2020',
items: [{ color: '#090909', label: 'New or planned sidewalk' }]
}
];
</script>

<div class="map">
<img src={mapImage} width="2040" height="1084" alt="" />

<!-- ward/area svg labels to come, positioned in this same 2040x1084 space -->

<div class="legend">
<div class="legend-title">Toronto streets</div>
{#each legendGroups as group, i}
<div class="legend-group" class:first={i === 0}>
<div class="legend-group-title">{group.title}</div>
{#each group.items as item}
<div class="legend-row">
<span class="swatch" style="background: {item.color};"></span>
<span class="legend-label">{item.label}</span>
</div>
{/each}
</div>
{/each}
</div>
</div>

<style>
.map {
position: relative;
}

img {
display: block;
width: 100%;
height: auto;
}

.legend {
position: absolute;
right: 12px;
bottom: 12px;
width: 220px;
box-sizing: border-box;
padding: 10px 12px 12px;
background: rgba(255, 255, 255, 0.9);
border: solid 1px var(--brandGray20);
}

@media (min-width: 1440px) {
.legend {
right: 22px;
bottom: 22px;
}
}

.legend-title {
font-family: OpenSansBold;
font-weight: normal;
font-size: 11px;
line-height: 14px;
color: var(--brandGray90);
margin-bottom: 8px;
}

@media (min-width: 1440px) {
.legend-title {
font-size: 13px;
line-height: 16px;
}
}

.legend-group {
margin-top: 12px;
}

.legend-group.first {
margin-top: 0;
}

.legend-group-title {
font-family: OpenSans;
font-style: italic;
font-size: 10px;
color: var(--brandGray60);
margin-bottom: 4px;
}

@media (min-width: 1440px) {
.legend-group-title {
font-size: 12px;
}
}

.legend-row {
display: flex;
align-items: center;
gap: 6px;
margin-top: 6px;
}

.legend-row:first-of-type {
margin-top: 0;
}

.swatch {
width: 16px;
height: 3px;
flex-shrink: 0;
}

.legend-label {
font-family: OpenSans;
font-size: 11px;
color: var(--brandGray90);
}

@media (min-width: 1440px) {
.legend-label {
font-size: 13px;
}
}
</style>
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions posts/sidewalk-coverage-toronto/meta.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"title": "Mapping sidewalk coverage in Toronto",
"type": "post",
"summary": "71% of streets have sidewalks on both sides; 13% have no sidewalks at all.",
"authors": ["Kosta Diochnos", "Jeff Allen"],
"published": "2026-10-15",
"license": "CC-BY-4.0",
"protected": true,
"geography": ["Toronto"],
"tags": ["urban","active travel","walking", "accessibility"],
"documents": []
}
8 changes: 6 additions & 2 deletions src/lib/ChartFrame.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
// same override pattern as meta.graphicVerb ?? 'created' below.
const chartLicense = $derived(meta.license ?? license);

// meta.authors (set per-chart in charts.js) overrides the post-level author
// list, for posts where not every listed author worked on every chart.
const chartAuthors = $derived(meta.authors ?? authors);


// Derived from the current route's slug so a folder rename (which changes the
// slug) updates these links everywhere automatically, with nothing hardcoded.
Expand Down Expand Up @@ -199,8 +203,8 @@
{#if meta.note}
<p class="chart-source"><strong>Note:</strong> {meta.note}</p>
{/if}
{#if authors && authors.length > 0}
<p class="chart-credit">Graphic {meta.graphicVerb ?? 'created'} by {formatAuthorList(authors)}</p>
{#if chartAuthors && chartAuthors.length > 0}
<p class="chart-credit">Graphic {meta.graphicVerb ?? 'created'} by {formatAuthorList(chartAuthors)}</p>
{/if}
</div>

Expand Down
26 changes: 24 additions & 2 deletions src/lib/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -260,11 +260,33 @@ li {
margin-bottom: 12px;
}

.details-block p {
.data-methods h2 {
font-size: 22px;
margin-top: 24px;
margin-bottom: 12px;
padding-bottom: 8px;
border-bottom: solid 1px var(--brandYellow);
}

.data-methods h2:first-child {
margin-top: 0;
}

.data-methods h3 {
font-size: 18px;
margin-top: 20px;
}

.data-methods h4 {
font-size: 16px;
}

.data-methods p,
.data-methods li {
font-size: 16px;
line-height: 24px;
}

.details-block p:last-child {
.data-methods p:last-child {
padding-bottom: 0;
}
Loading