1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
|
#!/usr/bin/env ruby
require 'bundler/inline'
gemfile do
source 'https://rubygems.org'
gem 'activesupport'
gem 'actionview'
gem 'csv'
end
require 'action_view'
require 'action_view/helpers'
require 'active_support'
require 'active_support/core_ext/string'
require 'csv'
require 'erb'
# https://data.calgary.ca/Demographics/Census-by-Community-2019/rkfr-buzb/about_data
# CLASS,CLASS_CODE,COMM_CODE,NAME,SECTOR,SRG,COMM_STRUCTURE,CNSS_YR,FOIP_IND,RES_CNT,DWELL_CNT,PRSCH_CHLD,ELECT_CNT,EMPLYD_CNT,OWNSHP_CNT,DOG_CNT,CAT_CNT,PUB_SCH,SEP_SCH,PUBSEP_SCH,OTHER_SCH,UNKNWN_SCH,SING_FAMLY,DUPLEX,MULTI_PLEX,APARTMENT,TOWN_HOUSE,MANUF_HOME,CONV_STRUC,COMUNL_HSE,RES_COMM,OTHER_RES,NURSING_HM,OTHER_INST,HOTEL_CNT,OTHER_MISC,APT_NO_RES,APT_OCCPD,APT_OWNED,APT_PERSON,APT_VACANT,APT_UC,APT_NA,CNV_NO_RES,CNV_OCCPD,CNV_OWNED,CNV_PERSON,CNV_VACANT,CNV_UC,CNV_NA,DUP_NO_RES,DUP_OCCPD,DUP_OWNED,DUP_PERSON,DUP_VACANT,DUP_UC,DUP_NA,MFH_NO_RES,MFH_OCCPD,MFH_OWNED,MFH_PERSON,MFH_VACANT,MFH_UC,MFH_NA,MUL_NO_RES,MUL_OCCPD,MUL_OWNED,MUL_PERSON,MUL_VACANT,MUL_UC,MUL_NA,OTH_NO_RES,OTH_OCCPD,OTH_OWNED,OTH_PERSON,OTH_VACANT,OTH_UC,OTH_NA,TWN_NO_RES,TWN_OCCPD,TWN_OWNED,TWN_PERSON,TWN_VACANT,TWN_UC,TWN_NA,SF_NO_RES,SF_OCCPD,SF_OWNED,SF_PERSON,SF_VACANT,SF_UC,SF_NA,OTH_STRTY,DWELSZ_1,DWELSZ_2,DWELSZ_3,DWELSZ_4_5,DWELSZ_6,MALE_CNT,FEMALE_CNT,MALE_0_4,MALE_5_14,MALE_15_19,MALE_20_24,MALE_25_34,MALE_35_44,MALE_45_54,MALE_55_64,MALE_65_74,MALE_75,FEM_0_4,FEM_5_14,FEM_15_19,FEM_20_24,FEM_25_34,FEM_35_44,FEM_45_54,FEM_55_64,FEM_65_74,FEM_75,MF_0_4,MF_5_14,MF_15_19,MF_20_24,MF_25_34,MF_35_44,MF_45_54,MF_55_64,MF_65_74,MF_75,OTHER_CNT,OTHER_0_4,OTHER_5_14,OTHER_15_19,OTHER_20_24,OTHER_25_34,OTHER_35_44,OTHER_45_54,OTHER_55_64,OTHER_65_74,OTHER_75,multipolygon
class Community
include ActionView::Helpers::NumberHelper
def initialize(row)
@row = row
end
def name
self[:name]
end
def percent(key)
return 0 if self[:res_cnt].to_i.zero?
((self[key].to_f / self[:res_cnt].to_f) * 100).round(1)
end
def homepage_url
"https://www.calgary.ca/communities/profiles/#{name.parameterize}.html"
end
def profile_url
"https://www.calgary.ca/content/dam/www/csps/cns/documents/community_social_statistics/community-profiles/#{name.parameterize}.pdf"
end
def projection_url
"https://www.calgary.ca/content/dam/www/csps/cns/documents/community_social_statistics/#{name.parameterize}-pp.pdf"
end
def [](key)
@row.fetch(key.to_s.upcase)
end
def <=>(other)
[self[:sector], self.name] <=> [other[:sector], other.name]
end
def properties
Enumerator.new do |yielder|
Property.each do |property|
yielder.yield property if property[:comm_code] == self[:comm_code]
end
end
end
def create_content_in(dir)
target_dir = "#{dir}/#{self[:comm_code].parameterize}"
FileUtils.mkdir_p(target_dir, verbose: true)
create_readme_in(target_dir)
end
private
def create_readme_in(dir)
erb = ERB.new(IO.read("templates/community.md.erb"), trim_mode: "-")
IO.write("#{dir}/README.md", erb.result(binding))
end
end
class Census
include Enumerable
def initialize(path)
@path = path
end
def sectors
map { |x| x[:sector] }.uniq
end
def each
CSV.foreach(@path, headers: true) do |row|
community = Community.new(row)
yield community if community[:class].include?("Residential")
end
end
def create_content_in(dir)
FileUtils.mkdir_p(dir, verbose: true)
erb = ERB.new(IO.read("templates/city.md.erb"), trim_mode: "-")
IO.write("#{dir}/README.md", erb.result(binding))
each do |community|
community.create_content_in(dir)
end
end
end
# https://data.calgary.ca/Government/Current-Year-Property-Assessments-Parcel-/4bsw-nn7w/about_data
# ROLL_YEAR,ROLL_NUMBER,ADDRESS,ASSESSED_VALUE,ASSESSMENT_CLASS,ASSESSMENT_CLASS_DESCRIPTION,RE_ASSESSED_VALUE,NR_ASSESSED_VALUE,FL_ASSESSED_VALUE,COMM_CODE,COMM_NAME,YEAR_OF_CONSTRUCTION,LAND_USE_DESIGNATION,PROPERTY_TYPE,LAND_SIZE_SM,LAND_SIZE_SF,LAND_SIZE_AC,MOD_DATE,SUB_PROPERTY_USE,MULTIPOLYGON,UNIQUE_KEY
class Property
def initialize(row)
@row = row
end
def [](key)
@row.fetch(key.to_s.upcase)
end
def residential?
self[:assessment_class_description] == "Residential"
end
def <=>(other)
[self[:comm_code], self[:address]] <=> [other[:comm_code], other[:address]]
end
class << self
def each(path = "data/Current_Year_Property_Assessments__Parcel__20240524.csv")
@properties ||= CSV
.read(path, headers: true)
.map { |x| Property.new(x) }
.sort
@properties.each do |property|
yield property if property.residential?
end
end
end
end
Census
.new("data/Census_by_Community_2019_20240524.csv")
.create_content_in("yyc")
|