forked from robinhouston/cartograms
-
Notifications
You must be signed in to change notification settings - Fork 5
/
NOTES.txt
315 lines (215 loc) · 12.5 KB
/
NOTES.txt
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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
# Install PostGIS
psql < /usr/local/share/postgis/postgis.sql
# Load the standard SRSs
psql < /usr/local/share/postgis/spatial_ref_sys.sql
# Add World Robinson as well
# from http://spatialreference.org/ref/esri/54030/postgis/
psql <<END
INSERT into spatial_ref_sys (
srid, auth_name, auth_srid,
proj4text, srtext
) values (
954030, 'esri', 54030,
'+proj=robin +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ',
'PROJCS["World_Robinson",GEOGCS["GCS_WGS_1984",DATUM["WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]],PROJECTION["Robinson"],PARAMETER["False_Easting",0],PARAMETER["False_Northing",0],PARAMETER["Central_Meridian",0],UNIT["Meter",1],AUTHORITY["EPSG","54030"]]'
);
END
# Load the shape file
shp2pgsql -W LATIN1 -s 4326 TM_WORLD_BORDERS-0/TM_WORLD_BORDERS-0.3.shp country | psql
# If you forget the -s 4326, you can fix it up with:
select UpdateGeometrySRID('country', 'the_geom', 4326);
# Getting the geometry data out again (in the projection of choice, here Robinson)
\t on
select ST_AsText(ST_Transform(the_geom,954030)) from country where iso2='FR';
select ST_AsSVG(ST_Transform(the_geom,954030)) from country where iso2='FR';
# To simplify the path
select ST_AsSVG(ST_Simplify(ST_Transform(the_geom,954030), 10000)) from country where iso2='FR';
# To round off to 1 decimal place
select ST_AsSVG(ST_Transform(the_geom,954030), 0, 1) from country where iso2='FR';
# The outline of the whole Robinson map (on the lhs)
select ST_AsText(ST_Transform(ST_Segmentize(ST_GeomFromText('LINESTRING(-180 -90,-180 90)', 4326), 1), 954030));
# so incidentally the bounding rectangle is
# -17005833.3305252 -8625154.47184994,17005833.3305252 8625154.47184994
# The whole boundary all around:
select ST_AsSVG(ST_Transform(ST_Segmentize(ST_GeomFromText('POLYGON((-180 -90,-180 90,180 90,180 -90,-180 -90))', 4326), 5), 954030));
# Here’s a nice World Robinson map in SVG format:
# http://upload.wikimedia.org/wikipedia/commons/0/03/BlankMap-World6.svg
# Note that PROJ.4 has an error in its implementation of the Robinson projection:
# http://osgeo-org.1803224.n2.nabble.com/Robinson-projection-td6445718.html
# I’ve just discovered http://polymaps.org/, “A JavaScript library for image- and vector-tiled maps using SVG.”
# Interesting bug:
robin=# select ST_AsSVG(ST_Simplify(ST_Transform(the_geom,954030), 10000)) from country where iso2='CX';
ERROR: invalid memory alloc request size 18446744073709551614
# Algorithm for simplifying polygons: Douglas–Peucker algorithm
# http://www.cs.ubc.ca/~snoeyink/papers/DPsimp.arch
# as implemented by the PostGIS ST_Simplify and ST_SimplifyPreserveTopology commands
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="442.84" width="863.21002" viewBox="82.992 45.607 2528.5721 1428.3294">
<defs />
<style type="text/css">
#GB { fill: red; }
</style>
<path id="FR" d="…"/>
</svg>
# All the countries as paths
\o |mate -
select '<path id="'||iso2||'" d="'|| ST_AsSVG(ST_GeomFromText(ST_AsText(ST_Simplify(ST_Transform(the_geom,954030), 10000))), 0, 0) ||'"/>' from country;
\o
# Procedure for making a cartogram:
## One-off preparation
psql < grid.sql
## Load the data for this cartogram
bin/load-data.py "carbon reserves" data/carbon-reserves.csv countries Code TOTAL
## Generate the starting density grid
bin/density-grid.py "carbon reserves" world-robinson 10000 > work/carbon-reserves.density
## Run cart to generate the grid distortion
cart 1500 750 work/carbon-reserves.density work/carbon-reserves.cart
## Generate the map
bin/as-svg.py --dataset "carbon reserves" --cart work/carbon-reserves.cart --map world-robinson > maps/carbon-reserves.svg
# Upload an SVG file to S3
gzip -9 maps/carbon-reserves.anim.no-data-marked.svg
aws put "Content-type: image/svg+xml" "Content-Encoding: gzip" "x-amz-acl:public-read" \
s3.boskent.com/cartograms/carbon-reserves.anim.no-data-marked.svg \
maps/carbon-reserves.anim.no-data-marked.svg.gz
# Making a dataset of the population numbers
insert into dataset (name) values ('pop2005');
insert into data_value (
dataset_id, country_gid, value
) (
select currval('dataset_id_seq'::regclass), gid, pop2005
from country
where country.area > 0
);
$ bin/density-grid.py pop2005 > work/pop2005.density
$ cart 1500 750 work/pop2005.density work/pop2005.cart
$ bin/as-svg.py pop2005 work/pop2005.cart | gzip -c -9 > maps/pop2005.svg
aws put "Content-type: image/svg+xml" "Content-Encoding: gzip" "x-amz-acl:public-read" \
s3.boskent.com/cartograms/pop2005.svg \
maps/pop2005.svg.gz
\t on
\a
\f ,
\o data/imagine.csv
select name, area from region where region.division_id = (select id from division where name = 'utas');
\o
$ bin/load-data.py imagine data/imagine.csv utas name weight
$ bin/density-grid.py imagine os-britain > work/imagine.density
$ cart 750 1500 work/imagine.density work/imagine.cart
$ bin/as-svg.py imagine os-britain work/imagine.cart > maps/imagine.svg
aws put "Content-type: image/svg+xml" "Content-Encoding: gzip" "x-amz-acl:public-read" \
s3.boskent.com/cartograms/imagine.svg \
maps/imagine.svg.gz
$ bin/load-data.py ONS-2010-population data/population-by-region.csv utas Code Population
$ bin/density-grid.py ONS-2010-population os-britain > work/gb-population-2010.density
$ cart 1449 2100 work/gb-population-2010.density work/gb-population-2010.cart
with t as (select ST_Transform(location, 27700) p from fms_problem)
select '<circle cx="' || round(ST_X(t.p)) || '" cy="'|| round(ST_Y(t.p))||'" r="500"/>' from t;
$ bin/as-svg.py --dataset=ONS-2010-population --map=os-britain --cart=work/gb-population-2010.cart --circles=fms_problem --static --simplification 100 --stroke-width 600 -o maps/fms-reports-static-normalised.svg
$ bin/as-svg.py --map=os-britain --circles=fms_problem --static --simplification 100 --stroke-width 600 -o maps/fms-reports-static.svg
$ svgtopng maps/fms-reports-static.svg
$ svgtopng maps/fms-reports-static-normalised.svg
bin/carter.py --dataset=ONS-2010-population --map=os-britain && \
bin/as-svg.py --dataset=ONS-2010-population --map=os-britain \
--cart=work/gb-population-2010.cart \
--circles=fms_problem \
--static --simplification 100 --stroke-width 600 \
-o maps/fms-reports-static-normalised.svg && \
svgtopng -f maps/fms-reports-static-normalised.svg
aws put "Content-type: image/png" "x-amz-acl:public-read" \
s3.boskent.com/cartograms/fixmystreet/reports-cartogram.png \
maps/fms-reports-static-normalised.png
aws put "Content-type: image/png" "x-amz-acl:public-read" \
s3.boskent.com/cartograms/fixmystreet/reports.png \
maps/fms-reports-static.png
$ bin/load-data.py ONS-2010-population-districts data/population-by-region.csv districts Code Population
$ bin/density-grid.py ONS-2010-population-districts os-britain-districts > work/gb-population-2010-districts.density && cart 1623 2100 work/gb-population-2010-districts.density work/gb-population-2010-districts.cart
$ bin/as-svg.py --dataset=ONS-2010-population-districts --map=os-britain-districts --cart=work/gb-population-2010-districts.cart --circles=fms_problem --static --simplification 100 --stroke-width 600 -o maps/fms-reports-districts-normalised.svg && svgtopng -f maps/fms-reports-districts-normalised.svg
$ svgtopng maps/fms-reports-districts.svg
Robin-Houstons-MacBook-Pro:cartograms robin$ bin/as-svg.py --map=os-britain-districts --circles=fms_problem --static --simplification 100 --stroke-width 600 -o maps/fms-reports-districts.svg && svgtopng maps/fms-reports-districts.svg
aws put "Content-type: image/png" "x-amz-acl:public-read" \
s3.boskent.com/cartograms/fixmystreet/dis/reports.png \
maps/fms-reports-districts.png
aws put "Content-type: image/png" "x-amz-acl:public-read" \
s3.boskent.com/cartograms/fixmystreet/dis/reports-cartogram.png \
maps/fms-reports-districts-normalised.png
# Making a movie
bin/as-png.py --map=os-britain --dataset=ONS-2010-population --cart=work/gb-population-2010.cart --circles=fms_problem --simplification 100 --stroke-width 600 --anim-frames=36 -o /tmp/frame-%03d.png
ffmpeg -f image2 -i /tmp/frame-%03d.png -r 12 -s 541x700 /tmp/fms.avi
aws put "Content-type: video/avi" "x-amz-acl:public-read" \
s3.boskent.com/cartograms/fixmystreet/reports.avi \
/tmp/fms.avi
for i in {0..35}
do
f="$(printf "/tmp/frame-%03d.png" $i)"
g="$(printf "/tmp/frame-%03d.png" $[71 - $i])"
cp $f $g
done
ffmpeg -f image2 -i /tmp/frame-%03d.png -r 12 -s 541x700 /tmp/fms.gif
# Increase the delay on the key frames, using a hex editor.
# 21 f9 04 .. (04 00) change 04 00 to 64 00
aws put "Content-type: image/gif" "x-amz-acl:public-read" \
s3.boskent.com/cartograms/fixmystreet/reports-anim.gif \
/tmp/fms.gif
# And of the finer-grained version
bin/as-png.py --map=os-britain-districts --dataset=ONS-2010-population-districts \
--cart=work/gb-population-2010-districts.cart \
--circles=fms_problem \
--simplification 100 --stroke-width 600 \
--anim-frames=36 -o /tmp/frame-%03d.png
for i in {0..34}
do
f="$(printf "/tmp/frame-%03d.png" $i)"
g="$(printf "/tmp/frame-%03d.png" $[70 - $i])"
cp $f $g
done
ffmpeg -f image2 -i /tmp/frame-%03d.png -r 12 -s 541x700 /tmp/fms.gif
# Increase the delay on the key frames, using a hex editor.
# 21 f9 04 .. (04 00) change 04 00 to 64 00
aws put "Content-type: image/gif" "x-amz-acl:public-read" \
s3.boskent.com/cartograms/fixmystreet/dis/reports-anim.gif \
/tmp/fms.gif
# Or maybe MPEG-4 is more sensible? ;-)
cat <<CAT > /tmp/fms-anim.html
<!doctype html>
<meta charset=utf-8>
<meta name=viewport content="height=760,width=600">
<title>All the problems ever reported on FixMyStreet.com</title>
<body style="width: 600px">
<video style="margin: auto" autoplay loop controls width=540 height=700 onplay="this.removeAttribute('controls')" onpause="this.controls=true" onended="this.play()">
<source src="fms.m4v" type="video/mp4">
<source src="fms.ogv" type="video/ogg">
</video>
</body>
CAT
# A little explanation of some of this:
# - Firefox supports Ogg Theora; Safari and iOS support H.264 MPEG-4;
# so we need both.
# - Firefox does not currently support the loop attribute, so the
# onended handler is for her benefit.
# - iOS does not support autoplay, so we need controls or else iOS
# users have no way to start the video. We remove the controls
# when the video has started playing.
# - Sometimes iOS will pause the video by itself for no obvious reason,
# in which case we must restore the controls, hence the onpause handler.
aws put "Content-type: text/html" "x-amz-acl:public-read" \
s3.boskent.com/cartograms/fixmystreet/dis/reports-anim.html \
/tmp/fms-anim.html
ffmpeg -f image2 -i /tmp/frame-%03d.png -r 12 -s 540x700 -vcodec libx264 -crf 21 -acodec aac -ac 2 -ab 192000 -strict experimental -refs 3 -y /tmp/fms.m4v
aws put "Content-type: video/mp4" "x-amz-acl:public-read" \
s3.boskent.com/cartograms/fixmystreet/dis/fms.m4v \
/tmp/fms.m4v
ffmpeg -f image2 -i /tmp/frame-%03d.png -r 12 -s 540x700 -vcodec libtheora -acodec libvorbis -b 1024k -y /tmp/fms.ogv
aws put "Content-type: video/ogg" "x-amz-acl:public-read" \
s3.boskent.com/cartograms/fixmystreet/dis/fms.ogv \
/tmp/fms.ogv
# CAIT emissions data
bin/load-data.py "CAIT carbon annual total" data/CAIT\ emissions\ data\ with\ country\ codes.csv countries "Country code" "Annual emissions (MtCO2e, 2008, excludes land use)"
bin/density-grid.py "CAIT carbon annual total" world-robinson > work/cait-annual-total.density && cart 1500 750 work/cait-annual-total.density work/cait-annual-total.cart
bin/as-svg.py --dataset "CAIT carbon annual total" --cart work/cait-annual-total.cart --map world-robinson --json --simplification 20000 > data/cait-annual-total.json
bin/load-data.py "CAIT carbon historical total" data/CAIT\ emissions\ data\ with\ country\ codes.csv countries "Country code" "Historical emissions (MtCO2e, 1850–2008, from energy)"
bin/density-grid.py "CAIT carbon historical total" world-robinson > work/cait-historical-total.density && cart 1500 750 work/cait-historical-total.density work/cait-historical-total.cart
bin/as-svg.py --dataset "CAIT carbon historical total" --cart work/cait-historical-total.cart --map world-robinson --json --simplification 20000 > data/cait-historical-total.json
# World population data
bin/load-data.py "World population (World Bank, 2010)" data/world-bank-population.csv countries "Country code" "Population (2010)"
# carbonmap.org
# see bin/adhoc/load-carbonmap-data.sh