West London Alliance Benchmarking Quantitative Analysis, 2012 to 2021

The following analysis is carried out for the 40 Town Centre zones in the WLA area with additional analysis for all significant business clusters (those with more than 15 commercial activity entities within 150 metres of each other - shown in purple) occurring within the hinterlands of each Town Centre, defined by the voroni polygons in Figure 1 below.

Town Centres and Extended Clustered Activity Zones
Town Centres and Extended Clustered Activity Zones

Reading in Analysis Data

This document contains various data processing and analysis / visualisation scripts to explore and benchmark Planning Use Class E evolution across the five West London Alliance Boroughs (Hounslow, Hillingdon, Barnet, Brent and Ealing).

Firstly, read in commerical activity data on all 40 Town Centres obtained from https://openlocal.uk/

###Read Data and then create several new columns
alldata <- read_excel("./project/class_e_floor_area_aggregations_combined_new.xlsx", 
                      col_types = c("date", "text", "text", "text", "numeric", 
                                    "text", "text", "numeric", "numeric", 
                                    "numeric", "numeric")) %>% 
  mutate(floor_area_all = floor_area_official + floor_area_clustered) %>% 
  mutate(count_all = count_official + count_clustered) %>% 
  mutate(avg_fl_area_official = floor_area_official / count_official) %>% 
  mutate(avg_fl_area_clustered = floor_area_clustered / count_clustered) %>% 
  mutate(avg_fl_area_all = floor_area_all / (count_official+count_clustered)) %>% 
  mutate(new_date = ymd(period))

#print table
kable(alldata[1:5,1:8], caption = "Open Local Data Sample")
Open Local Data Sample
period sitename planning_authority town_centre_class area_km2 category status floor_area_official
2012-12-31 Ealing Ealing Metropolitan 6.807 c all 9953.28
2012-12-31 Ealing Ealing Metropolitan 6.807 c occupied 9182.60
2012-12-31 Ealing Ealing Metropolitan 6.807 c void 770.68
2012-12-31 Ealing Ealing Metropolitan 6.807 a all 126276.61
2012-12-31 Ealing Ealing Metropolitan 6.807 a occupied 125434.48

Initial Summary Statistics - Commercial Floor Area and Business Activities

Below are some summary tables and plots aggregating all data according to class E sub-class activity across the three time slices (2012, 2017 and 2021) in this study. Note that NA refers to totals across all class E categories in the period.

Class E sub-groups are classified as follows:

Class E Category Sub-division Class Description
E(a) Retail Display or retail sale of goods, other than hot food
E(b) Food Sale of food and drink for consumption (mostly) on the premises
E(c) Services Provision of Services:
(i) Financial services,
(ii) Professional services (other than health or medical services), or
(iii) Other appropriate services in a commercial, business or service locality
E(d) Sport&Rec Indoor sport, recreation or fitness (not involving motorised vehicles or firearms or use as a swimming pool or skating rink,)
E(e) Medical Provision of medical or health services (except the use of premises attached to the residence of the consultant or practitioner)
E(f) Nursery Creche, day nursery or day centre (not including a residential use)
E(g) Office Uses which can be carried out in a residential area without detriment to its amenity:
(i) Offices to carry out any operational or administrative functions,
(ii) Research and development of products or processes
(iii) Industrial processes
Related Sui Generis Related Including Takeaway Food Outlet (Predominantly Off Premises), cinemas, drive in restaurant, drive through restaurant, bingo hall, concert hall

2012 Statistics

2012 Summary Statistics by Class E sub-class, official town centre areas
category official_floor_total official_count official_avg_fl_area
a 1411942.76 10859 128.9467
b 93135.58 620 146.1042
c 150866.81 757 198.3808
d 96031.10 96 900.3812
e 64960.10 553 119.4924
f 0.00 0 0.0000
g 4084525.96 9657 370.0817
related 11447.66 33 329.7403
NA 5945446.81 22633 239.6413
## Warning in options(scipen = 10000): invalid 'scipen' 10000, used 9999

2017 Statistics

2017 Summary Statistics by Class E sub-class, official town centre areas
category official_floor_total official_count official_avg_fl_area
a 1930870.43 13364 148.3179
b 140752.90 841 156.4230
c 195261.97 1098 184.2143
d 149178.82 170 754.4934
e 75362.21 631 123.3043
f 500.10 1 500.1000
g 6183100.81 15505 333.7029
related 14907.27 54 294.0705
NA 8727167.21 31716 243.2246

2021 Statistics

2021 Summary Statistics by Class E sub-class, official town centre areas
category official_floor_total official_count official_avg_fl_area
a 2068268.31 14134 155.7339
b 151931.21 908 155.2032
c 214903.95 1382 173.0289
d 178690.78 204 791.4091
e 79473.63 647 127.4994
f 500.10 1 500.1000
g 6935123.43 18404 330.3531
related 17537.70 65 263.2854
NA 9666963.84 35787 240.5294

Key Points:

  • Retail is the dominant use class (both in terms of floor space and business counts) in Town Centres across the WLA study area with Office closely following. Other use classes are much less prevalent across town centre areas.
  • In each town centre, dividing the total floor area by counts of businesses gives an average floor area for each use class. Most activities occupy average floor areas of around 125-150 sq m, with the exception of sports and recreation activities.
  • Steady growth in both total floor area and number of businesses is evident across the whole WLA area and for all Class E sub-groups

Changes over the 10-year study period

The next section presents change statistics from the beginning to the end of the study period

#change_table_2012_2021 <-
  #summary_table_2021[2:4] - summary_table_2012[2:4]
  
change_tab_2012_2021_official <- sum_tab_2021_official %>% 
  mutate(official_floor_total = sum_tab_2021_official[2]-sum_tab_2012_official[2]) %>% 
  mutate(official_count       = sum_tab_2021_official[3]-sum_tab_2012_official[3]) %>% 
  mutate(official_avg_fl_area = sum_tab_2021_official[4]-sum_tab_2012_official[4]) 

#class(change_tab_2012_2021_official$official_count)
#write_csv(change_tab_2012_2021_official, "change_tab_2012_2021_official.csv")

change_tab_2012_2021_official %>% 
  filter(category!="NA") %>% 
  ggplot(aes(category, official_floor_total$official_floor_total)) +
  geom_col(aes(fill=category)) +
  xlab("Class E sub-class") +
  ylab("Total Floor Area (sq m)") +
  ggtitle("WLA Change, 2012-2021, in Total Floor Area by Class E subgroup")#+

#ggsave("./plots/WLA-2021-Avg-Floor-Area-by-Class-E-subgroup.png")

change_tab_2012_2021_official %>% 
  filter(category!="NA") %>% 
  ggplot(aes(category, official_count$official_count)) +
  geom_col(aes(fill=category)) +
  xlab("Class E sub-class") +
  ylab("Count of businesses") +
  ggtitle("WLA Change, 2012-2021, in business count Class E subgroup")#+

#ggsave("./plots/WLA-2021-Avg-Floor-Area-by-Class-E-subgroup.png")

change_tab_2012_2021_official %>% 
  filter(category!="NA") %>% 
  ggplot(aes(category, official_avg_fl_area$official_avg_fl_area)) +
  geom_col(aes(fill=category)) +
  xlab("Class E sub-class") +
  ylab("Avg Floor Area (sq m)") +
  ggtitle("WLA Change, 2012-2021, in Average Floor Area by Class E subgroup")#+

#ggsave("./plots/WLA-2021-Avg-Floor-Area-by-Class-E-subgroup.png")
## Warning in options(scipen = 10000): invalid 'scipen' 10000, used 9999

Borough Averages

#####Summary - official town centre areas (count business / total floor area)
#####by borough, over time by class E
#options(scipen = 10000)
alldata %>% 
  #filter(is.na(category)) %>% 
  filter(category!="NA") %>% 
  #filter(category=="a") %>% 
  filter(status=="all") %>% 
  filter(planning_authority!="Brent") %>% 
  group_by(new_date, planning_authority, category) %>% 
  summarise(official_floor_total = sum(floor_area_official), 
            official_count = sum(count_official), 
            official_avg_fl_area = mean(avg_fl_area_official)) %>% 
  ggplot(aes(new_date, official_floor_total, colour=status)) +
  geom_line(aes(colour=category)) + 
  facet_wrap(vars(planning_authority), labeller = label_wrap_gen(width = 12, multi_line = TRUE)) +
  xlab("Year") +
  ylab("Total Floor Area (sq m)") +
  ggtitle("Change in Total Floor Area", subtitle = "All WLA Boroughs")+
  guides(x = guide_axis(angle = 90))
## `summarise()` has grouped output by 'new_date', 'planning_authority'. You can
## override using the `.groups` argument.

Key Points:

  • Growth in the total floor area given over to Class E activities is evident across all sub-groups. It is unclear whether this growth is through conversion of existing buildings or new-build.
  • The total number of businesses across all sectors has grown, although the total number of new office-based businesses is the highest.
  • Conversely growth in the number of businesses masks a serious down-sizing of the average floor area of office-based businesses by around 30 sq m. Office sub-division to get below tax-paying thresholds is likely driving this trend.
  • Overall trends and those at borough level mask significant variation in activities and growth for each town centre area.

Initial Summary Statistics - Occupancy and Vacancy

The table below reveals the changes in occupancy and vacancy across the whole WLA area between 2012 and 2021

###### Occupied ######
sum_tab_official <- alldata %>% 
  filter(status=="occupied") %>% 
  group_by(category, period) %>% 
  summarise(official_floor_total = sum(floor_area_official), 
            official_count = sum(count_official), 
            official_avg_fl_area = mean(avg_fl_area_official)) 
## `summarise()` has grouped output by 'category'. You can override using the
## `.groups` argument.
kable(sum_tab_official, caption = "Occupancy Statistics by Class E sub-class, official town centre areas")
Occupancy Statistics by Class E sub-class, official town centre areas
category period official_floor_total official_count official_avg_fl_area
a 2012-12-31 1388241.74 10859 127.0517
a 2017-12-31 1829583.66 13364 141.9861
a 2021-12-31 1945346.92 14134 147.8271
b 2012-12-31 91235.39 620 142.5566
b 2017-12-31 132711.19 841 146.4505
b 2021-12-31 136643.65 908 140.6114
c 2012-12-31 146727.79 757 194.4983
c 2017-12-31 175023.26 1098 167.8045
c 2021-12-31 187943.23 1382 150.8867
d 2012-12-31 95129.88 95 914.2446
d 2017-12-31 147879.08 168 766.1621
d 2021-12-31 172150.80 200 781.6833
e 2012-12-31 64189.27 553 117.7553
e 2017-12-31 73768.66 631 121.0415
e 2021-12-31 75694.46 646 117.3804
f 2017-12-31 500.10 1 500.1000
f 2021-12-31 500.10 1 500.1000
g 2012-12-31 3980894.88 9657 360.8674
g 2017-12-31 5473088.88 15505 298.4220
g 2021-12-31 5840814.90 18404 281.8008
related 2012-12-31 11447.66 33 329.7403
related 2017-12-31 13479.39 52 259.0814
related 2021-12-31 13435.13 63 197.5725
NA 2012-12-31 5810403.45 22633 234.5973
NA 2017-12-31 7881490.19 31716 222.5152
NA 2021-12-31 8388322.15 35787 210.7763
###### void ######
sum_tab_official <- alldata %>% 
  filter(status=="void") %>% 
  group_by(category, period) %>% 
  summarise(official_floor_total = sum(floor_area_official), 
            official_count = sum(count_official), 
            official_avg_fl_area = mean(avg_fl_area_official)) 
## `summarise()` has grouped output by 'category'. You can override using the
## `.groups` argument.
kable(sum_tab_official, caption = "Vacancy Statistics by Class E sub-class, official town centre areas")
Vacancy Statistics by Class E sub-class, official town centre areas
category period official_floor_total official_count official_avg_fl_area
a 2012-12-31 23671.32 10094 2.143325
a 2017-12-31 101286.77 13364 6.331805
a 2021-12-31 122921.39 14134 7.906781
b 2012-12-31 1760.29 98 18.987472
b 2017-12-31 7761.51 637 13.834118
b 2021-12-31 15027.59 769 19.863682
c 2012-12-31 3992.32 355 14.697418
c 2017-12-31 20063.07 925 24.747728
c 2021-12-31 26501.90 1207 30.721353
d 2012-12-31 893.72 7 297.068333
d 2017-12-31 1157.61 24 108.170769
d 2021-12-31 3460.57 71 59.780587
e 2012-12-31 191.20 52 4.706315
e 2017-12-31 1018.73 109 8.261295
e 2021-12-31 3476.60 183 49.055973
g 2012-12-31 102861.06 9201 10.614819
g 2017-12-31 710011.93 15489 36.185569
g 2021-12-31 1094134.94 18303 51.053244
related 2017-12-31 1105.44 4 276.360000
related 2021-12-31 3734.50 27 256.803836
NA 2012-12-31 135043.36 22633 5.043996
NA 2017-12-31 845677.02 31716 20.709397
NA 2021-12-31 1278641.69 35787 29.753074

Vacancy over time for each Town Centre area

alldata %>% 
  #filter(is.na(category)) %>% 
  filter(category!="NA") %>% 
  #filter(category=="a") %>% 
  filter(status=="void") %>% 
  filter(planning_authority!="Brent") %>% 
  group_by(new_date, planning_authority, category) %>% 
  summarise(official_floor_total = sum(floor_area_official), 
            official_count = sum(count_official), 
            official_avg_fl_area = mean(avg_fl_area_official)) %>% 
  ggplot(aes(new_date, official_floor_total, colour=status)) +
  geom_line(aes(colour=category)) + 
  facet_wrap(vars(planning_authority), labeller = label_wrap_gen(width = 12, multi_line = TRUE)) +
  xlab("Year") +
  ylab("Total Floor Area (sq m)") +
  ggtitle("Change in Vacant Total Floor Area", subtitle = "All WLA Boroughs")+
  guides(x = guide_axis(angle = 90))
## `summarise()` has grouped output by 'new_date', 'planning_authority'. You can
## override using the `.groups` argument.

Key Points

  • Growth in overall floor space and counts business premises in town centre areas across the WLA area masks the fact that much of that growth is in premises that remain vacant
  • Taking retail and office premises, most of the growth occurred between 2012 and 2017, with a slowing in growth to 2021
  • The average floor areas of most occupied premises have remained relatively static across most sub-class groups, however occupied office space has reduced in size from an average of around 170 sq m to 113 sq m.
  • Growth in vacant retail and, in particular, office space is quite dramatic over the 10 year period
  • vacant spaces are on average quite small, however the size of vacant commercial space has increased across the board with the average vacant office space now at just over 30 sq m, up from around 10 sq m in 2012.
  • At the borough and town centre levels growth in vacant office space is driving vacancy rates in many place, particularly in Ealing where Ealing Town Centre itself shows a huge growth in vacant office space

Planning Use Class Change Over Time

Benchmarking Against the Study Area

The preceding analysis has presented a picture of commercial (class E) activity in the 40 town centres within WLA study area between 2012 and 2021 using, principally, total floor area statistics with other information on counts of businesses and average floor sizes. The analysis covered both vacant and occupied buildings.

However, while raw figures tell part of the story, comparison against ‘expected’ profiles can shed more light. The following analysis defines our expected situation as the WLA area average.

To begin, we explore local class E activity proportions for each Town Centre Area:

Observations

At the borough level, we see some small movement in activity level proportions - mainly relating to relative reductions in retail activities and increases in office activity between 2012 and 2021, but these are relatively minor.

When comparing these patterns with the WLA average, it becomes clear that Barnet and Ealing represent something approaching the average with Hillingdon showing well above average office activities and Hounslow, above average retail activities.

These variations are, of course, more pronounced for some Town Centre Areas. Below these profiles are provided for, first, occupied businesses, then vacant business properties:

####Occupied Businesses 2021

####Vacant Businesses, 2021

Activivity Outside of Designated Town Centre Areas

As is shown in Figure 1, the research team have identified a number of Class E business activity clusters outside of the boundaries of the official town centre areas.

Allocating these business clusters to their nearest Town Centre are and then including these businesses in the analysis presents quite a different picture of business activity in the WLA study area.

clustered_long_2021_props %>% 
  #filter(is.na(category)) %>% 
  #filter(category!="NA") %>% 
  filter(status=="all") %>% 
  filter(category!=c("NA")) %>% 
  #filter(category!=c("a")) %>% 
  filter(planning_authority=="Barnet") %>% 
  ggplot(aes(category, value, fill=category)) +
  geom_col(aes(colour=category)) + 
  facet_wrap(vars(sitename), labeller = label_wrap_gen(width = 12, multi_line = TRUE)) +
  xlab("category") +
  ylab("Proportion of Town Centre Floor Area") +
  ggtitle(label="Extended Town Centre Activity Proportions, 2021", subtitle = "Barnet") +
  guides(x = guide_axis(angle = 90))
## Warning: Removed 24 rows containing missing values or values outside the scale range
## (`geom_col()`).

clustered_long_2021_props %>% 
  #filter(is.na(category)) %>% 
  #filter(category!="NA") %>% 
  filter(status=="all") %>% 
  filter(category!=c("NA")) %>% 
  #filter(category!=c("a")) %>% 
  filter(planning_authority=="Ealing") %>% 
  ggplot(aes(category, value, fill=category)) +
  geom_col(aes(colour=category)) + 
  facet_wrap(vars(sitename), labeller = label_wrap_gen(width = 12, multi_line = TRUE)) +
  xlab("category") +
  ylab("Proportion of Town Centre Floor Area") +
  ggtitle(label="Extended Town Centre Activity Proportions, 2021", subtitle = "Ealing") +
  guides(x = guide_axis(angle = 90))
## Warning: Removed 8 rows containing missing values or values outside the scale range
## (`geom_col()`).

clustered_long_2021_props %>% 
  #filter(is.na(category)) %>% 
  #filter(category!="NA") %>% 
  filter(status=="all") %>% 
  filter(category!=c("NA")) %>% 
  #filter(category!=c("a")) %>% 
  filter(planning_authority=="Harrow") %>% 
  ggplot(aes(category, value, fill=category)) +
  geom_col(aes(colour=category)) + 
  facet_wrap(vars(sitename), labeller = label_wrap_gen(width = 12, multi_line = TRUE)) +
  xlab("category") +
  ylab("Proportion of Town Centre Floor Area") +
  ggtitle(label="Extended Town Centre Activity Proportions, 2021", subtitle = "Harrow") +
  guides(x = guide_axis(angle = 90))
## Warning: Removed 12 rows containing missing values or values outside the scale range
## (`geom_col()`).

clustered_long_2021_props %>% 
  #filter(is.na(category)) %>% 
  #filter(category!="NA") %>% 
  filter(status=="all") %>% 
  filter(category!=c("NA")) %>% 
  #filter(category!=c("a")) %>% 
  filter(planning_authority=="Hillingdon") %>% 
  ggplot(aes(category, value, fill=category)) +
  geom_col(aes(colour=category)) + 
  facet_wrap(vars(sitename), labeller = label_wrap_gen(width = 12, multi_line = TRUE)) +
  xlab("category") +
  ylab("Proportion of Town Centre Floor Area") +
  ggtitle(label="Extended Town Centre Activity Proportions, 2021", subtitle = "Hillingdon") +
  guides(x = guide_axis(angle = 90))
## Warning: Removed 8 rows containing missing values or values outside the scale range
## (`geom_col()`).

clustered_long_2021_props %>% 
  #filter(is.na(category)) %>% 
  #filter(category!="NA") %>% 
  filter(status=="all") %>% 
  filter(category!=c("NA")) %>% 
  #filter(category!=c("a")) %>% 
  filter(planning_authority=="Hounslow") %>% 
  ggplot(aes(category, value, fill=category)) +
  geom_col(aes(colour=category)) + 
  facet_wrap(vars(sitename), labeller = label_wrap_gen(width = 12, multi_line = TRUE)) +
  xlab("category") +
  ylab("Proportion of Town Centre Floor Area") +
  ggtitle(label="Extended Town Centre Activity Proportions, 2021", subtitle = "Hounslow") +
  guides(x = guide_axis(angle = 90))
## Warning: Removed 6 rows containing missing values or values outside the scale range
## (`geom_col()`).

###### Occupied ######
sum_tab_clustered1 <- alldata %>% 
  filter(status=="occupied") %>% 
  group_by(category, period) %>% 
  summarise(clustered_floor_total = sum(floor_area_clustered), 
            clustered_count = sum(count_clustered), 
            clustered_avg_fl_area = mean(avg_fl_area_clustered)) 
## `summarise()` has grouped output by 'category'. You can override using the
## `.groups` argument.
kable(sum_tab_clustered1, caption = "Occupancy Statistics by Class E sub-class, extended town centre areas")
Occupancy Statistics by Class E sub-class, extended town centre areas
category period clustered_floor_total clustered_count clustered_avg_fl_area
a 2012-12-31 1092107.37 8740 118.2277
a 2017-12-31 1459756.74 11470 122.1455
a 2021-12-31 1558738.59 12188 123.5197
b 2012-12-31 76776.96 524 134.8916
b 2017-12-31 113111.11 739 141.7731
b 2021-12-31 116535.59 802 136.1855
c 2012-12-31 109156.81 630 172.5493
c 2017-12-31 137216.92 958 156.3115
c 2021-12-31 149544.45 1238 137.0113
d 2012-12-31 35608.25 37 1040.7409
d 2017-12-31 69177.65 77 848.9172
d 2021-12-31 102044.40 98 1073.2805
e 2012-12-31 20111.37 175 113.6455
e 2017-12-31 26513.13 229 115.5208
e 2021-12-31 26307.97 244 101.0037
f 2017-12-31 500.10 1 500.1000
f 2021-12-31 500.10 1 500.1000
g 2012-12-31 1980280.94 7237 237.9487
g 2017-12-31 3498590.98 12998 224.5846
g 2021-12-31 3786133.48 15773 196.0901
related 2012-12-31 8951.46 24 353.3503
related 2017-12-31 6717.25 32 237.1149
related 2021-12-31 5049.82 38 150.1801
NA 2012-12-31 3322993.16 17368 170.6960
NA 2017-12-31 5311583.88 26506 175.7196
NA 2021-12-31 5744854.40 30386 162.6197
###### void ######
sum_tab_clustered2 <- alldata %>% 
  filter(status=="void") %>% 
  group_by(category, period) %>% 
  summarise(clustered_floor_total = sum(floor_area_clustered), 
            clustered_count = sum(count_clustered), 
            clustered_avg_fl_area = mean(avg_fl_area_clustered)) 
## `summarise()` has grouped output by 'category'. You can override using the
## `.groups` argument.
kable(sum_tab_clustered2, caption = "Vacancy Statistics by Class E sub-class, extended town centre areas")
Vacancy Statistics by Class E sub-class, extended town centre areas
category period clustered_floor_total clustered_count clustered_avg_fl_area
a 2012-12-31 18877.83 8130 2.027728
a 2017-12-31 91033.79 11470 6.565734
a 2021-12-31 116168.72 12188 8.239907
b 2012-12-31 1760.29 85 20.633241
b 2017-12-31 7187.49 562 13.693519
b 2021-12-31 14181.97 679 21.260606
c 2012-12-31 3549.85 296 19.906993
c 2017-12-31 17790.64 814 25.174840
c 2021-12-31 23372.48 1097 29.519685
d 2012-12-31 893.72 6 303.060000
d 2017-12-31 1157.61 10 228.061111
d 2021-12-31 3460.57 39 161.362364
e 2012-12-31 191.20 23 11.995952
e 2017-12-31 736.75 41 19.186168
e 2021-12-31 3001.03 81 76.106133
g 2012-12-31 56879.44 6945 7.946650
g 2017-12-31 502545.09 12987 30.909108
g 2021-12-31 785806.85 15682 41.139438
related 2017-12-31 1105.44 3 446.537500
related 2021-12-31 3734.50 23 304.912056
NA 2012-12-31 82358.63 17368 3.863517
NA 2017-12-31 621556.81 26506 18.581572
NA 2021-12-31 949849.47 30386 24.315994

Key Observations

  • Our analysis has shown that ignoring class E activity outside of Town Centre areas significantly under-estimates economic activity across the WLA boroughs
  • Office floor space and unit counts dominates outside of Town Centre areas, both in terms of occupany and vacancy statistics
  • the average floor area for retail businesses drops by around 20 sq m outside of Town Centre areas, while it increases by some 80 sq m for office space.
  • the average floor area for office space has been noticably decreasing since 2012 outside of town centre areas as well
  • vacancy statistics are driven by office vacancy and it is this class E sub-class which has shown the most increase in terms of counts and vacant floor space across the whole WLA area.