Sign in

Jens von Bergmann

@jensvb.bsky.social
9.9K followers 620 following 2.7K posts

Data, analysis, visualization, #CensusMapper, transportation cyclist. 📍Vancouver, BC

PostsRepliesMedia
Jens von Bergmann @jensvb.bsky.social · 2h
It's coming along. Dot placement is fixed, now folding in census data for multi-value dot-density maps. Testing out structural type of dwellings. Fairly responsive, fun to play with. Kind of crazy what one can get done in just one day nowadays. And yes, this is prototyping a CensusMapper upgrade.
040
Jens von Bergmann @jensvb.bsky.social · 5h
Pickup and drop-off landed. Toronto is back where it should be. (Also picked up secondary dwelling units this time around.)
re-geocoded toronto
220
Jens von Bergmann @jensvb.bsky.social · 7h
Fun times, the NAR is consistently shifted ~15-18m west, 6-9m south in the Toronto area. Not great. This needs fixing, ideally upstream in StatCan data, but this will take a while and I'll have to monkey patch a fix for now. Will have to measure the extent of this. (Guessing StatCan messed up CRS.)
Toronto addresses are systematically shifted
260
Jens von Bergmann @jensvb.bsky.social · 8h
Still struggling with clean matching and identification. Most work out quite well, but lots of edge cases to check in and verify. Could also spread out the jitter radius for dwelling units in large buildings to smooth things out a bit. Or bring in building footprint data, but that has quirks too.
140
Jens von Bergmann @jensvb.bsky.social · 8h
By-product of this: Verifying how census geographies match up against other data sources like the NAR, RNF, ODB, RQA, GHSL. Good news, generally quite well. Some issues in rural areas. The one exception is urban Toronto where the census geographies have problems. E.g. this sliver.
https://censusmapper.ca/maps/3053?z=17.23&lat=43.6680&lng=-79.3721
250
Jens von Bergmann @jensvb.bsky.social · 9h
Haven't had time to check out cool new technology recently, but decided to try parquet and DuckDB-WASM for cheap interactive Canada-wide dot-density maps. This is running in the browser backed by remote hosted parquet. Still lots of room for improvement, but this already works quite well.
2592
Jens von Bergmann @jensvb.bsky.social · 10/10/2026
It's detailed in the GitHub issue linked above. CCRI people will have better vision into this, from the outside it looks like the CCRI version is truncated and researchers relying on the CCRI version get wrong results.
https://github.com/mountainMath/canpumf/issues/32
000
Jens von Bergmann @jensvb.bsky.social · 10/10/2026
The missing labels, and suggested fill-ins for many (but not all) of them are in the linked GitHub issue above. You have to expand the detail dropdown (▶) to see them, otherwise they would clog up too much of the text.
000
Jens von Bergmann @jensvb.bsky.social · 09/10/2026
In principle this is pretty nice should not take too much to onboard.
example of 1881 full sample data
000
Jens von Bergmann @jensvb.bsky.social · 09/10/2026
Ok, I took a look at the data. Imported the CCRI 1911 that was on Borealis, and in principle this works. For the 1921 census I still have not found a place where it's actually available, some pointers to where it can be found would be appreciated. The only place I found it has a broken link to it.
example of usage of 1911 census 5% sample
200
Jens von Bergmann @jensvb.bsky.social · 09/10/2026
Sneak peek into some upcoming feature enhancements in canpumf. Stacked old and new vintage monthly LFS PUMF is getting a simplified API and is blazing fast. Auto-updates to ensure newly released data is always included, harmonizes columns under the hood and queries on 50 years run in milliseconds.
library(tidyverse)
library(canpumf)

lfs_pariticpation <- get_pumf("LFS_TIMELINE",refresh = "auto") |>
  mutate(in_labour_force=LFSSTAT != "Not in labour force") |>
  add_lfs_columns("SURVDATE") |>
  summarize(Value=sum(FINALWT), .by=c(SURVDATE, GENDER_SEX, in_labour_force)) |>
  mutate(rate=Value/sum(Value),.by=c(SURVDATE, GENDER_SEX)) |>
  filter(in_labour_force ) |>
  collect()

ggplot(lfs_pariticpation, aes(x = SURVDATE, y = rate, colour = GENDER_SEX)) +
  geom_line(alpha = 0.3) +
  geom_smooth(method = "loess", span = 0.05, se = FALSE, linewidth = 0.8) +
  geom_vline(xintercept = as.Date("2006-01-01"), linetype = "dashed") +
  scale_y_continuous(labels = scales::percent) +
  labs(title = "Labour force participation rate by gender/sex, 1976 onward",
       subtitle = "Monthly, not seasonally adjusted; dashed line: LFS_HIST to LFS",
       x = NULL, y = "Paricipation rate", colour = NULL,
       caption = "StatCan LFS PUMF (1976-2005 via Borealis/ODESI)")
050
Jens von Bergmann @jensvb.bsky.social · 05/10/2026
🎼 Fog on the water … 🎶
0220
Jens von Bergmann @jensvb.bsky.social · 02/10/2026
A type of failure to return to pre-pandemic levels I can get fully behind. Still not liking the trend though, it's high time we turn this around for good. canviz.mountainmath.ca/plot?v=74726
Timeline of sales of fuel for road motor vehicles.
0193
Jens von Bergmann @jensvb.bsky.social · 30/09/2026
I guess in an environment where everyone gets used to highly discretionary permitting things like bribery and kickbacks just get casually referred to as getting someone to “work magic” and help “navigating” city hall.
He was, for decades, the city’s preeminent “permit expediter,” leaning on the many workers he placed within the city’s building department to work magic for clients navigating San Francisco’s treacherous construction landscape.
092
Jens von Bergmann @jensvb.bsky.social · 25/09/2026
2025 fertility rate estimates came out yesterday, posting the obligatory annual graph. Overall Canada TFR remained steady at 1.26. (As a reminder, TFR is a synthetic measure and general cautions apply, especially if you want to write about this in the news media or have arguments about this.)
Total Fertility Rate across Canadian provinces
190
Jens von Bergmann @jensvb.bsky.social · 25/09/2026
Historical LFS microdata differs somewhat from their modern 2006+ version, it gets stored in a separate local DuckDB. `get_lfs_timeline` harmonizes the two and hands back a single lazy connection to the joint tables for simple and fast cross-database operations. Code runs in a fraction of a second.
library(tidyverse)
library(canpumf)

lfs_tl <- get_lfs_timeline(refresh = "auto")

lfs_unemployment <- lfs_tl |>
  filter(LFSSTAT != "Not in labour force") |>
  add_lfs_SURVDATE() |>
  summarize(Value=sum(FINALWT), .by=c(SURVDATE, GENDER_SEX, LFSSTAT)) |>
  mutate(rate=Value/sum(Value),.by=c(SURVDATE, GENDER_SEX)) |>
  filter(LFSSTAT == "Unemployed") |>
  collect()

ggplot(lfs_unemployment, aes(x = SURVDATE, y = rate, colour = GENDER_SEX)) +
  geom_line(alpha = 0.3) +
  geom_smooth(method = "loess", span = 0.05, se = FALSE, linewidth = 0.8) +
  geom_vline(xintercept = as.Date("2006-01-01"), linetype = "dashed") +
  scale_y_continuous(labels = scales::percent) +
  labs(title = "Unemployment rate by gender/sex, 1976 onward",
       subtitle = "Monthly, not seasonally adjusted; dashed line: LFS_HIST to LFS",
       x = NULL, y = "Unemployment rate", colour = NULL,
       caption = "StatCan LFS PUMF (1976-2005 via Borealis/ODESI)")
120
Jens von Bergmann @jensvb.bsky.social · 23/09/2026
Current status: mojibake warrior é, twice-cooked. I peel back one code page – then another. Still é.
GitHub issue documenting fix for mojibake en-dash shipped by StatCan
041
Jens von Bergmann @jensvb.bsky.social · 23/09/2026
New quarterly population estimates out today. Important to note that StatCan made changes to how they estimate the non-permanent resident population in Canada. And that led to noticeable back-corrections, in particular for work permit holders.
NPR population in Canada by type of permitChanges for this release
As part of this release, Statistics Canada is applying two new adjustments to the estimates of non-permanent residents to more accurately measure the presence of permit holders in Canada.

The first adjustment is based on data sources recently acquired by Statistics Canada. The second adjustment responds to a migration context that has evolved rapidly over the past few years.

For the first adjustment, data on entries and exits from the Canada Border Services Agency (CBSA) were used to estimate, at an aggregate level, the proportion of permit holders who left Canada before their permits expired.

At the same time, the increase in the number of permit extensions and the time required to process them has made it increasingly important to better account for individuals who remain in Canada while their extension application is being processed (i.e., on maintained status). The second adjustment therefore aims to better anticipate permit extensions that are not yet reflected in the Immigration, Refugees and Citizenship Canada (IRCC) administrative data available when the preliminary demographic estimates are produced.

In September each year, with the release of demographic estimates for July 1, Statistics Canada updates previous estimates. For this release, non-permanent resident estimates, and consequently population estimates, have been updated from July 1, 2021, onward. The larger-than-usual update in 2026 to the previously released estimates of the number of non-permanent residents can be attributed to two factors. First, the more recent versions of IRCC's administrative data this year contain substantially more records reflecting permit extensions that were not yet present in the data used to produce preliminary estimates. Second, the new adjustments described above are now incorporated into the estimates.

These adjustments allow the demographic estimates to better capture the moment when permit holders are leaving—or not leaving—the countr…
0101
Jens von Bergmann @jensvb.bsky.social · 21/09/2026
2024 Canadian Housing Survey data came out today, lots of things to look through. One item that will likely get people talking is forced moves. It's a difficult metric to interpret, but there seems to be a COVID dip and now a jump in 2024 across all regions. canviz.mountainmath.ca/plot?v=13757...
Forced moves in past 5 years.
1232
Jens von Bergmann @jensvb.bsky.social · 20/09/2026
Quick example of nondeterministic nature of NTILE in sql. DuckDB optimizing and parallelizes queries that mess up row order. SQL: SELECT PPSORT, NTILE(10) OVER (ORDER BY SHELCO) AS shelter_bins (This can be made deterministic by providing more sorting columns that make the order deterministic.)
```{r setup}
library(tidyverse)
library(canpumf)
```

```{r}
d <- get_pumf("Census","2021")

nt1 <- d |> 
  mutate(shelter_bins = ntile(SHELCO,10)) |> 
  select(PPSORT,shelter_bins) |> 
  collect()

nt2 <- d |> 
  mutate(shelter_bins = ntile(SHELCO,10)) |> 
  select(PPSORT,shelter_bins) |> 
  collect()

full_join(nt1,nt2,by="PPSORT") |> 
  count(shelter_bins.x==shelter_bins.y)


close_pumf(d)
```
051
Jens von Bergmann @jensvb.bsky.social · 16/09/2026
That’s was kind of forced by the zoning at the time. To achieve that form and density lot coverage had to be low. Some did not do anything with the rest of the lot, some added a swimming pool or a tennis court, some did both. Here is what it looks like a block over:
Kitsilano mid-rises and how their lot was used.
030
Jens von Bergmann @jensvb.bsky.social · 16/09/2026
11 stories, it got built. The last one in Kits. (See the two buildings in the background for reference.)
Image of the building people protested in 1974.
1110
Jens von Bergmann @jensvb.bsky.social · 16/09/2026
Randomly thought of this photo today taken by David Ley in 1974 of people protesting the construction of what would be the last mid-rise in Kitsilano before the downzoning. Apartments build in the 60s and 70s are now often celebrated as Vancouver's (relatively) affordable housing stock.
A bulldozer-blocking anti-high-rise protest in the Vancouver neighbourhood of Kitsilano in 1974. Among the attendees, wearing a tie, is a city-paid community organiser. Photo: David Ley

Taken from https://www.scmp.com/news/world/united-states-canada/article/2089031/david-and-goliath-priceless-vancouver-academic
88020
Jens von Bergmann @jensvb.bsky.social · 16/09/2026
To make this concrete, here is what it looks like after filtering on the province names. And the unicode hack to also reach the other three Atlantic provinces. One could argue it's sloppy data analysis if people don't carefully inspect their data, but ... Anyway, get the newest cansim📦!
Demonstrating how filtering by provinces is broken by non-breaking white-space, and a unicode hack to fix this for non-cansim users.
020
Jens von Bergmann @jensvb.bsky.social · 16/09/2026
Here is one way this issue comes up: Number of people consuming Cannabis in the Atlantic provinces. The cansim package fixes character issues, manual table download and reading does not. Only NB survives in the manual process. This can't be solved by copy-pasting province names from table.
Example demonstrating how non-breaking whitespace characters can mess up analysis. The provinces that get filtered on were copy-pasted from the table output, but copy-paste silently converts non-breaking whitespace to space in R or python. The respective labels are unreachable without technical workarounds.
120
Jens von Bergmann @jensvb.bsky.social · 15/09/2026
Update on this, cansim users should update to the latest version (v0.5.0). The issue with StatCan mixing "non-breaking white space" characters into dimension and member names persists and is getting worse. ⚠️People downloading data directly or using other tools should take note and exercise caution.
Updated summary of label issues in StatCan data.
192
Jens von Bergmann @jensvb.bsky.social · 12/09/2026
Reading older literature on housing, this one is from 1993, is always interesting. Things have moved very little since then.
ZONING IN INNER-CITY LOW-DENSITY RESIDENTIAL
NEIGHBOURHOODS
Perhaps the strongest evidence for the economic significance of land-use controls is the persistence of low-density residential neighbourhoods in the central areas of Toronto and Vancouver. In both cities, the unanticipated intrusion of high-density residential developments in middle and upper-income low-den-sity neighbourhoods in the 196os led to political pressures for more protective zoning. The result in both cities was a virtual cessation of high-rise development in existing low-density neighbourhoods where, moreover, citizen pressure on politicians has led to the progressive enactment of increasingly detailed regulation of low-scale redevelopment.7
The Vancouver and Toronto experiences provide illuminating evidence of the nature of the demand for certainty which underlies the pressure for zoning controls in existing neighbourhoods. On the margin, the shadow price associated with the density constraints built into zoning regulations would appear to be high. & Nevertheless, the demand for inner-city land used for single-family housing has been increased by the perceived stability of land uses in such areas, and this has encouraged substantial investment in the renovation of inner-city housing along with an increase in its market value.
The value of single-family housing in inner-city low-density neighbour-hoods has been increased by restrictive zoning, whereas the value of land assemblies has fallen. Because of the risks inherent in land assembly, much of the return from redevelopment to higher densities accrues to speculators who assemble land. Without restrictive zoning, the difference between the value of
1222
Jens von Bergmann @jensvb.bsky.social · 05/09/2026
Amazing chart, took me a while to decipher. It's annual (July 1st previous year to July 1st reference year) absolute population change for cities with quite different base population, only showing select years and dropping the others, but connecting with a line graph. Misattributed to BC Stats.
Stupefying chart crime
4231
Jens von Bergmann @jensvb.bsky.social · 31/08/2026
At least it did not take Digital Services Canada to make the one-line change. Hope it does not stop there but also kick off broader discussions on how digital services should be restructured in today’s political reality.
Updated HICC map with proper naming of Lake Ontario
0134
Jens von Bergmann @jensvb.bsky.social · 31/08/2026
Also, this problem doesn't magically disapper only by switching map data providers. Open Street Map data also has different tags serving different purposes. Relying on everyone always picking the right tag is asking for trouble, better to set up dedicated Canadian map servers.
OSM data for Lake Ontario
1232
Jens von Bergmann @jensvb.bsky.social · 31/08/2026
The Lake Ontario discussion is tiring. People south of the border, get your shit together. Infantile renaming of bodies of water is the least of your problems. People north of the border, get your shit together. Quick check on where Digital Service Canada messed up:
Side by side view of google baseman as deployed by HICC and one with an added region parameter.
1459
Jens von Bergmann @jensvb.bsky.social · 28/08/2026
GDP up, StatCan down
Statistics Canada
Technical difficulties
We're sorry! We are currently experiencing some technical difficulties with sections of our website and are working to fix this problem as soon as possible. Please check out the latest issue of The Daily and key data tables. We apologize for any inconvenience.
1413
Jens von Bergmann @jensvb.bsky.social · 27/08/2026
These visual symbols hit hard.Here is a picture I took almost exactly 6 years ago and it already did not reach the lake back then.
0153
Jens von Bergmann @jensvb.bsky.social · 26/08/2026
Here is what it looks like from up north. Still annoying that it gives a nod to the US naming in parenthesis.
120
Jens von Bergmann @jensvb.bsky.social · 25/08/2026
I always wonder how much of the shift of du/worker is simply shifts in allocation between repair construction and new construction.
120
Jens von Bergmann @jensvb.bsky.social · 24/08/2026
Happy one year anniversary of the resurrection of this phone. Inadvertently dropped in ankle deep water of the rising tides, presumed dead, it faithfully notified its owner the next day when freed from the ocean’s grip.
iPhone emerging from the tides
1191
Jens von Bergmann @jensvb.bsky.social · 18/08/2026
Biology 101 FTW
020
Jens von Bergmann @jensvb.bsky.social · 17/08/2026
Rents (combined existing and turnover tenants) in Canada are now growing slower than non-shelter cost CPI in most markets.
rents adjusted for non-shelter CPI
0266
Jens von Bergmann @jensvb.bsky.social · 16/08/2026
Current status: Implementing a downstream workaround in the cansim package so that data columns are accessible without users having to go to monkey-patch special characters into strings. Tired of responding to package users running into this. But really, StatCan should fix this on their end.
The characters looked for are the zero width ones (U+200B, U+FEFF) and the space-like ones that are
not a plain space (U+00A0, U+0009, U+000A, U+000D). A name is counted once per language, however
many of these characters it holds.

Overall

Level	Names scanned (per language)	English	French	Total
Cube title	8,226	4	9	13
Dimension name	29,741	6	114	120
Member name	2,282,860	1,985	5,260	7,245
1,995	5,383	7,378
Those 7,378 affected names are 1,859 distinct strings — the same bad name is repeated across tables.

803 of 8,226 tables (9.8%) carry at least one affected name:

English side affected: 253 tables (3.1%)
French side affected: 676 tables (8.2%)
both sides: 126 · English only: 127 · French only: 550
The French side is affected about 2.7× as often as the English side. Most of it comes from French
typographic convention being encoded with a non-breaking space — 12<U+00A0>derniers mois,
15<U+00A0>ans, <U+00A0>: — which is correct typography but is not something a user can type or
paste when it lands in a column name or a factor level.
180
Jens von Bergmann @jensvb.bsky.social · 15/08/2026
Fun new StatCan dataset that mixes housing starts data with proximity to transit.
housing starts in Metro Vancouver near high-capacity transit
3193
Jens von Bergmann @jensvb.bsky.social · 15/08/2026
Fiery sunset
Paddleboarder on the sunset
1341
Jens von Bergmann @jensvb.bsky.social · 09/08/2026
This closely resembles the thinking outlined in a CoV planning report in 1958. (Never mind that in modern planning the use of the term "blight" is highly contentious, given the way the term has been instrumenalized in the past.)
Except from CoV report "AFARTMENT ZONING", TECHNICAL FLANNING BOARD 29th August, 1958.
2150
Jens von Bergmann @jensvb.bsky.social · 08/08/2026
Ok, now I have to go read this. I only know this from this summary table but never read the references to the critiques.
Examples of issues with selection in “what is your estimated”.
120
Jens von Bergmann @jensvb.bsky.social · 07/08/2026
A lot of the housing discourse around minimum standards is cursed, shallow, and focused on vibes instead of outcomes. Literally, "this might further exclusion, but the vibes are good".
South Park underpants gnome meme

Minimum standards -> ? -> Poor people benefit
1213
Jens von Bergmann @jensvb.bsky.social · 06/08/2026
Historically west sides of mid-latitude cities have been more desirable and expensive because prevailing winds blowing noxious city smells away. We have regulated most of those smelly land uses away, but those same winds, plus local topography, also act on wildfire smoke.
1224
Jens von Bergmann @jensvb.bsky.social · 30/07/2026
Not sure “legacy” is the right word. Clearly some legacy processes are involved to get to this point, but this is the 2021 data release that went straight to the NDM. This is what StatCan had to say about this when I asked:
Footnotes
We reported this issue to StatCan at the time, and the answer we got was that this behaviour was “requested by the Census team”. The underlying mechanism is different from the IVT files though, the underlying database has the data and it serves it when it’s requested as CSV. But the census division requested the API use a ‘Default replacement symbol’ of 0 instead of the usual ‘Not available’, and this is what drops zeros from the API response.↩︎
010
Jens von Bergmann @jensvb.bsky.social · 30/07/2026
One side benefit of cracking the IVT encoding is to have context for quirks (and bugs) in modern census data releases. Most glaringly, the NDM API drops data for some census data queries. A couple of years ago we added a loud warning in the cansim 📦, now we understand how this echos IVT behaviour.
Example where the NDM drops data and the cansim package warns against potential data loss
140
Jens von Bergmann @jensvb.bsky.social · 22/07/2026
You almost have to feel sorry for him. Numbers totally detached from reality trying to anchor an unhinged arguments put on UBC letterhead in a desperate attempt to establish authority.
Open Letter to Vancouver Council on the "Villages Plan"
Subject: Serious Concerns with Vancouver’s Villages Plan
Dear Mayor and Council,
I write to challenge key elements of the Villages Plan.
Together with the recently approved Official Development Plan and Broadway Plan, the City is now granting
private owners of more than 80,000 parcels the right to build roughly 700,000 new housing units. This
represents enough capacity to house an extra 1.4 million people—more than double Vancouver’s current
population of 670,000. At today’s 1% annual population growth rate, this single decision delivers over 100
years of future housing supply. Yet even the projects already in the approval pipeline (roughly 78,000 units)
would satisfy 30 years of trend growth.
121146
Jens von Bergmann @jensvb.bsky.social · 16/07/2026
When you design the fire trucks to fit your streets instead of the streets to fit your fire trucks.
Right-sized fire truckFire trucks in action in alleywayi
1352
Jens von Bergmann @jensvb.bsky.social · 13/07/2026
View from the 8th house from the bottom
View from the 8th house from the bottom
090