The PPMR web map serves as a health logistics data visualization tool to highlight the reach and impact of the USAID | DELIVER PROJECT. The map highlights the Average Monthly Consumption (AMC) of eleven unique contraceptive methods by country, displaying the breakdown of AMC by donor program alongside its respective data source.
All data from this initial round of mapping is from the May 2012 quarterly report. Data from subsequent quarterly reports is to be added once it is available, along with the technical infrastructure to allow for layer switching between months.
This documentation will address the following:
- Software requirements for project replication
- Data processing
- Geospatial file alteration and production
- Map production and design
- MapBox hosting
- Microsite template alteration and design
- Logo alteration for site integration
To replicate the process of map production the following software is required:
- Quantum GIS - referred to as QGIS
- SQLite - also known as Base
- TileMill
- Apache OpenOffice or Microsoft Excel
- Inkscape - for logo alteration
All software listed above is open source and free of charge, and is both Windows and Mac OS X compatible.
All data was processed using a combination of Base and OpenOffice.
To begin, the original data file PPMR_Data_Flat_Output_2012-07-11.csv
was imported into Base as table data
and saved as database ppmr.sqlite
. The schema for table data
was altered such that each column containing numerical data was identified as type 'INTEGER' and each column containing text was identified as type 'TEXT'. This is done by right clicking on the table data
in the sidebar, selecting 'Alter...' and entering the appropriate label into each 'Type' field, as in the picture below:
Rows labeled with country names 'Anyland' and 'Multiple' were deleted and the column month_name
was added for the purpose of displaying the date in the map interactivity, using the following script:
delete from data where country_name = 'Anyland' or country_name = 'Multiple';
alter table data add column month_name text;
update data set month_name = 'May' where month = 5;
The table may_final
was created from the table data
, filtering all data by month (May) and status (Final):
create table may_final as select * from data where month = 5 and status_id = 2;
Unique data tables were then created for each contraceptive method from the table may_final
:
create table may_injectable as select * from may_final where method_id = 1;
create table may_comb_oral_contra as select * from may_final where method_id = 2;
create table may_implant as select * from may_final where method_id = 3;
create table may_iud as select * from may_final where method_id = 4;
create table may_3_mo_inject as select * from may_final where method_id = 5 or product_name = '3-month Injectable' or product_name = 'All Injectables';
create table may_emerg_contra as select * from may_final where method_id = 6;
create table may_fem_condom as select * from may_final where method_id = 7;
create table may_prog_oral_contra as select * from may_final where method_id = 8;
create table may_male_condom as select * from may_final where method_id = 9;
create table may_other as select * from may_final where method_id = 10;
create table may_1_mo_inject as select * from may_final where method_id = 11 or product_name = '1-month Injectable';
create table may_2_mo_inject as select * from may_final where method_id = 12 or product_name = '2-month Injectable';
Each method table was then processed for integration with TileMill. First, the Average Monthly Consumption (AMC) for each method was calculated by country as column country_amc_total
. The overall supply chain level for each country was also produced as column country_supply_chain_level_id
with associated country_supply_chain_level_name
column, for purposes of the Supply Chain Level layer on the map. In this case the table data
is to be replaced with the appropriate method table name from above, e.g. may_male_condom
, and repeated for each method.
create table data_2 as select *, sum(amc) as country_amc_total,
group_concat(distinct supply_chain_level_id) as supply_concat
from data
group by country_name;
alter table data_2 add column country_supply_chain_level_id integer;
update data_2 set country_supply_chain_level_id = 1 where supply_concat = '1';
update data_2 set country_supply_chain_level_id = 4 where supply_concat like '%4%';
update data_2 set country_supply_chain_level_id = 2 where supply_concat not like '%4%' and supply_concat != '1';
alter table data_2 add column country_supply_chain_level_name text;
update data_2 set country_supply_chain_level_name = 'All' where country_supply_chain_level_id = 4;
update data_2 set country_supply_chain_level_name = 'Central' where country_supply_chain_level_id = 1;
update data_2 set country_supply_chain_level_name = 'Central + Other' where country_supply_chain_level_id = 2;
The AMC total per program was then calculated by country as column program_amc_total
. Again, the table data
is to be replaced with the appropriate method table name and repeated for each method:
create table data_3 as select *, sum(amc) as program_amc_total
from data
group by country_name, program_name;
Tables data_2
and data_3
were then joined on column country_id
to produce table data_4
with both columns country_amc_total
and program_amc_total
, along with all other columns to be used:
create table data_4 as select
a.country_id,
a.country_name,
a.program_id,
a.program_name,
a.program_amc_total,
a.data_source_id,
a.data_source_name,
a.method_id,
a.method_name,
a.year,
a.month_name,
b.country_amc_total,
b.country_supply_chain_level_id,
b.country_supply_chain_level_name
from data_3 a
join data_2 b on a.country_id = b.country_id;
In order to add comma separators to the country_amc_total
and program_amc_total
columns for map interactivity, table data_4
was exported as a text file data_4.txt
, converted to CSV as data_4.csv
and opened in OpenOffice for alteration. To export a table in Base select the table you wish to export, click on the 'Export' feature in the upper left and select 'Text' from the export prompt:
In OpenOffice the column country_amc_total
was copied and the duplicate renamed country_amc_tooltip
. All cells for columns country_amc_tooltip
and program_amc_total
were then formatted as comma separated values and the file was imported back into the ppmr.sqlite
database replacing the original table data_4
. To do this, the original table data_4
was dropped by right clicking it in the sidebar and selecting 'Drop...', selecting the 'Import' feature in the upper left, navigating to the altered file and adding it as new table data_4
:
Table data_5
(renamed for each method, adding '_final' to each original table name e.g. may_male_condom_final
for the male condom method) was then produced including all necessary columns for map integration, including the program_amc_tooltip
column as a concatenation of each program with the associated AMC total and data source for the purpose of the AMC breakdown table for map interactivity. Tables data_2
, data_3
, and data_4
are automatically dropped, leaving only the final table for each method in the database:
create table data_5 as select
country_id,
country_name,
method_id,
method_name,
year,
month_name,
country_amc_total,
country_amc_tooltip,
group_concat('<tr><td align="left">' || program_name || '</td><td align="right">' || program_amc_total || '</td><td align="left">' || data_source_name || '</td></tr>', ' ') as program_amc_tooltip,
country_supply_chain_level_id,
country_supply_chain_level_name
from data_4
group by country_id;
DROP TABLE data_4;
DROP TABLE data_3;
DROP TABLE data_2;
Finally, the may_country_supply_chain_level
table for the Supply Chain level map was produced from table may_final
so as to include all countries with data for the month of May:
create table may_country_supply_chain_level as select country_id, country_name,
group_concat(distinct supply_chain_level_id) as supply_concat,
month_name,
year
from may_final
group by country_name;
alter table may_country_supply_chain_level add column country_supply_chain_level_id integer;
update may_country_supply_chain_level set country_supply_chain_level_id = 1 where supply_concat = '1';
update may_country_supply_chain_level set country_supply_chain_level_id = 4 where supply_concat like '%4%';
update may_country_supply_chain_level set country_supply_chain_level_id = 2 where supply_concat not like '%4%' and supply_concat != '1';
alter table may_country_supply_chain_level add column country_supply_chain_level_name text;
update may_country_supply_chain_level set country_supply_chain_level_name = 'All' where country_supply_chain_level_id = 4;
update may_country_supply_chain_level set country_supply_chain_level_name = 'Central' where country_supply_chain_level_id = 1;
update may_country_supply_chain_level set country_supply_chain_level_name = 'Central + Other' where country_supply_chain_level_id = 2;
Housing the data in .sqlite
file format is convenient because it allows for an easy join with geospatial files that are also in .sqlite
format in TileMill, meaning the original ne_10m_admin_0_countries.shp
world shapefile needed to be converted. To do so, open the file in QGIS, right click on the layer and select 'Save as...' making sure the format is set to 'SQLite', name the file (I used world.sqlite
) and select 'OK':
Next, there needs to be a field on which to join the world.sqlite
file with the data to be visualized in the ppmr.sqlite
database. For this purpose the country_id
column was added to the world.sqlite
file's attribute
table, matching the country_id
with the appropriate country code using the following script:
alter table attributes add column country_id integer;
update attributes set country_id = 1 where ne_10m_adm = "AFG";
update attributes set country_id = 3 where ne_10m_adm = "BGD";
update attributes set country_id = 4 where ne_10m_adm = "BFA";
update attributes set country_id = 8 where ne_10m_adm = "CIV";
update attributes set country_id = 10 where ne_10m_adm = "COD";
update attributes set country_id = 13 where ne_10m_adm = "ETH";
update attributes set country_id = 15 where ne_10m_adm = "GMB";
update attributes set country_id = 16 where ne_10m_adm = "GHA";
update attributes set country_id = 18 where ne_10m_adm = "HTI";
update attributes set country_id = 20 where ne_10m_adm = "KEN";
update attributes set country_id = 21 where ne_10m_adm = "LBR";
update attributes set country_id = 24 where ne_10m_adm = "MLI";
update attributes set country_id = 25 where ne_10m_adm = "MRT";
update attributes set country_id = 26 where ne_10m_adm = "MOZ";
update attributes set country_id = 28 where ne_10m_adm = "NPL";
update attributes set country_id = 31 where ne_10m_adm = "NGA";
update attributes set country_id = 32 where ne_10m_adm = "PAK";
update attributes set country_id = 34 where ne_10m_adm = "RWA";
update attributes set country_id = 37 where ne_10m_adm = "UGA";
update attributes set country_id = 38 where ne_10m_adm = "ZMB";
update attributes set country_id = 39 where ne_10m_adm = "TZA";
update attributes set country_id = 40 where ne_10m_adm = "TGO";
update attributes set country_id = 41 where ne_10m_adm = "ZWE";
update attributes set country_id = 45 where ne_10m_adm = "BEN";
If additional countries are to be visualized for subsequent quarterly reports this process will have to be updated accordingly. The world.sqlite
spatial file is now ready for integration with TileMill.
The world.sqlite
file alone, however, will not allow for the production of country labels to be overlayed on top of the choropleth base maps. So, a world_centroid.sqlite
file was created for this purpose. To begin, repeat the process of converting the ne_10m_admin_0_countries.shp
world shapefile to .sqlite
format, this time keeping the original name ne_10m_admin_0_countries.sqlite
. Next, open the newly created file in QGIS by selecting 'Layer' in the toolbar, 'Add Vector Layer', 'Browse' by 'Files of type: SQLite' and select the file.
Select the newly added layer in the 'Layers' sidebar then select 'Vector' in the toolbar, 'Geometry Tools', 'Polygon centroids':
Save as shapefile (only temporary), click 'OK', and select 'Yes' when prompted to add layer to the TOC, which should produce an image like this:
Select the newly created centroids layer and repeat the process to save it in .sqlite
format as world_centroid.sqlite
, then repeat the process for adding the country_id
column as well. The world_centroid.sqlite
file is now ready for integration with TileMill, to be used as a country label layer.
The first step to map production is creating the base map. With one stable world base map underlying the data specific to each method the site will operate as efficiently as possible, avoiding refreshing the entire world map every time the user switches between layers. For this purpose the base map was kept simple, with minimal styling to avoid bogging down map performance or cluttering the workspace.
To begin, open TileMill and select 'New Project' in the upper left hand corner. Label the filename deliver-base-map
and the project name DELIVER | Base Map
:
For this map, no additional layers needed to be added, only styling changes need to be made as follows:
Map {
background-color: #abd8e2;
}
#countries {
line-color: #888;
line-width: 2;
line-join: round;
polygon-pattern-file:url('../../polygon-pattern/stripe.png');
[zoom <= 3] {line-width:1;}
}
The line polygon-pattern-file:url('../../polygon-pattern/stripe.png');
is what produces the striped polygon-fill for the map, generated from the stripe.png
file housed in the polygon-pattern
folder in the MapBox
folder /documents/MapBox/polygon-pattern/stripe.png
. This file is only housed here, rather than each project folder, as it allows for each project to refer back to it in the polygon-pattern-file:url();
. The base map is ready to go.
Each method map is a combination of a choropleth layer, with each country distinguished by a unique color associated with a range of data classifications (in this case the darker the color the higher the AMC), with an overlaying country labels layer on top. Let's use the 2-month injectable method as an example, the process for which is to be repeated for each additional method.
To begin, select 'New Project' as before and this time label the filename deliver-2-month-injectable-may
and the project name DELIVER | 2 Month Injectable May
. The filename and project name are standardized for each method, with the filename following the structure deliver-method-name-may
and the project name following the structure DELIVER | Project Name May
.
In the newly created map navigate to toolbar in the lower left hand corner, select the 'Layers' feature at the bottom of the stack and delete the preloaded #countries
layer by clicking on the trash can icon:
Navigate back to the 'Layers' feature and this time select 'Add layer' and select the 'SQLite' tab on the top of the menu. The 'ID' field is the layer's unique name to which you will assign styling commands in Carto (TileMill's styling language) in the style.mss
sidebar to alter the appearance of the layer - label this 2-mo-inject
. For 'Datasource' navigate to the world.sqlite
spatial file created earlier, and for 'Attach DB' enter the filepath to the ppmr.sqlite
database created earlier as well, which should look something like this: ppmr@/Users/chad/Documents/deliver-usaid/data/ppmr.sqlite
. Notice how the name of the database with the '@' symbol preceding the filepath. For the 'SRS' projection remember to select WGS84
as this is the projection used by Natural Earth Data - the source of world spatial data. So far, the menu should look something like this:
Finally, the 'Table or subquery' field is where the join between .sqlite
files is made, along with the assignment of data classifications. Each method map is assigned a range of six data classifications, with class6 = 0 and classes 1-5 representing a range appropriate to the data for each method:
(select *, cast(`country_amc_total` as real)<0 as class0,
cast(`country_amc_total` as real)<1000 as class1,
cast(`country_amc_total` as real)>=1000 and
cast(`country_amc_total` as real)<5000 as class2,
cast(`country_amc_total` as real)>=5000 and
cast(`country_amc_total` as real)<10000 as class3,
cast(`country_amc_total` as real)>=10000 and
cast(`country_amc_total` as real)<15000 as class4,
cast(`country_amc_total` as real)>=15000 as class5,
cast(`country_amc_total` as real)=0 as class6 from
attributes join ppmr.may_2_mo_inject_final on
may_2_mo_inject_final.country_id = attributes.country_id
order by cast(`country_amc_total` as real) desc)
The attribute
table from the world.sqlite
spatial file is joined with the appropriate method table, in this case may_2_mo_inject_final
, from the ppmr.sqlite
database on the country_id
column. This way, only the countries with data for each method will show up in the method map, while the underlying base map (once hosted together on the site) will show 'No Data' for all others.
For each method, the range of data classifications is to be adjusted in the 'Table' field, while the table name associated with the ppmr.sqlite
database is to be changed accordingly as well. Otherwise, this query will stay the same. Once the query is set, click 'Save' and the layer is added, although the map will remain blank until styling has been assigned in the style.mss
sidebar.
Before doing so, navigate back to the 'Layers' feature and add another layer - what will be the country labels layer. This time label the ID country-labels
and for 'Datasource' navigate to the world_centroid.sqlite
file. Keep the 'Attach DB' and 'SRS' fields the same as the #2-mo-inject
layer. For 'Table or subquery' this join is much more straightforward as data classifications are not involved. Simply join the attributes
table from the world_centroid.sqlite
spatial file to the appropriate method table, may_2_mo_inject_final
in the ppmr.sqlite
database on the country_id
column:
(select * from attributes join ppmr.may_2_mo_inject_final on
may_2_mo_inject_final.country_id = attributes.country_id)
Click 'Save' and the layer is added, although again the map will remain blank until styling has been assigned, which we will move onto now. The Carto for all method maps is the same:
#country-labels {
text-name:"[country_name]";
text-face-name: "Gill Sans MT Bold";
text-fill: #111;
text-halo-fill: #eee;
text-halo-radius: 1px;
text-allow-overlap: true;
text-opacity: 1;
[zoom = 2]{ text-size: 8; text-allow-overlap: false;}
[zoom = 3]{ text-size: 9; text-allow-overlap: false;}
[zoom = 4]{ text-size: 12; }
[zoom = 5]{ text-size: 15; }
[zoom = 6]{ text-size: 18; }
[zoom = 7]{ text-size: 22; }
[zoom = 8]{ text-size: 30; }
}
@c1: #FDE3B8;
@c2: #FCCB8B;
@c3: #FC8D59;
@c4: #D46B36;
@c5: #BB3C01;
@c6: #fef7ea;
#2-mo-inject {
polygon-fill:#f6f6f6;
polygon-gamma:0.5;
[class0 = 1]{polygon-fill:#fff;}
line-width:1;
[zoom < 6]{line-opacity:0.5;}
[class1 = 1]{polygon-fill:@c1; line-color:darken(@c1,75);}
[class2 = 1]{polygon-fill:@c2; line-color:darken(@c2,65);}
[class3 = 1]{polygon-fill:@c3; line-color:darken(@c3,60);}
[class4 = 1]{polygon-fill:@c4; line-color:darken(@c4,55);}
[class5 = 1]{polygon-fill:@c5; line-color:darken(@c4,55);}
[class6 = 1]{polygon-fill:@c6; line-color:darken(@c6,90);}
}
The only thing to be changed for each map is the method layer name, in this case #2-mo-inject
. To clarify a couple of commands:
[zoom = 2]{ text-size: 8; text-allow-overlap: false;}
[zoom = 3]{ text-size: 9; text-allow-overlap: false;}
This prevents the #country-labels
layer from overlapping the country names at zoom 2 and 3, intended to reduce clutter and make the map easier to read. As the user zooms in beyond Z3 text-allow-overlap: true;
is initiated and all country labels appear.
@c1: #FDE3B8;
@c2: #FCCB8B;
@c3: #FC8D59;
@c4: #D46B36;
@c5: #BB3C01;
@c6: #fef7ea;
These are the color designations for each data classification, @c6
representing class 6 (0), and @c1
-@c5
representing classes 1-5.
[class1 = 1]{polygon-fill:@c1; line-color:darken(@c1,75);}
[class2 = 1]{polygon-fill:@c2; line-color:darken(@c2,65);}
[class3 = 1]{polygon-fill:@c3; line-color:darken(@c3,60);}
[class4 = 1]{polygon-fill:@c4; line-color:darken(@c4,55);}
[class5 = 1]{polygon-fill:@c5; line-color:darken(@c4,55);}
[class6 = 1]{polygon-fill:@c6; line-color:darken(@c6,90);}
These commands assign the polygon-fill for each classification, with the country borders for each styled as a darker shade of the original polygon-fill.
The map should now look like this:
To activate and assign tooltips, or the box that appears when you interact with the map and hover over active countries (what I refer to as interactivity), navigate to the toolbar in the lower left hand corner and select the interaction editor on the top of the stack. Select 'Teaser' in the menu, navigate to the layer list for interaction data and select the 2-mo-inject
layer:
The HTML for the interactivity is the same for all method maps, the style for which is assigned in the style.css
of the microsite template. The data displayed is automated through 'Mustache tags', e.g. {{{country_name}}}, feeding the data for the activated country directly from the database and into the interactivity on the map.
<div class='my-tooltip'>
<div class='tooltip-title'>{{{country_name}}}</div>
<div class='tooltip-date'>{{{month_name}}}, {{{year}}}</div>
<div class='tooltip-subtitle'>Average Monthly Consumption: <span>{{{country_amc_tooltip}}}</span></div>
<table><th>Program Name</th><th>AMC</th><th>Source</th>
{{{program_amc_tooltip}}}
</table>
</div>
To produce the legend navigate to the interaction editor again which should automatically bring you to the 'Legend' menu. The HTML for the legend is also the same for all method maps, the style for which is also assigned in the style.css
of the microsite template.
<div class='my-legend'>
<div class='legend-title'>Method: 2-Month Injectable</div>
<div class='legend-amc'>Average Monthly Consumption (Thousands)</div>
<div class='legend-scale'>
<ul class='legend-labels'>
<li><span style='background:#fef7ea;'></span>0</li>
<li><span style='background:#FDE3B8;'></span>< 1</li>
<li><span style='background:#FCCB8B;'></span>< 5</li>
<li><span style='background:#FC8D59;'></span>< 10</li>
<li><span style='background:#D46B36;'></span>< 15</li>
<li><span style='background:#BB3C01;'></span>15+</li>
<span class='space'>
<li><img src='https://img.skitch.com/20111222-q65jt21u1qmxh8j2bsf1hdhkpq.jpg'>No Data</li>
</span>
</ul>
</div>
<div class='legend-source'>Compiled by: <a href="http://deliver.jsi.com/">USAID | DELIVER PROJECT</a></div>
</div>
The only changes that need to be made with each method is the method name in the legend-title
div class, in this case labeled Method: 2-Month Injectable
, and the data ranges for classes 1-5:
<li><span style='background:#FDE3B8;'></span>< 1</li>
<li><span style='background:#FCCB8B;'></span>< 5</li>
<li><span style='background:#FC8D59;'></span>< 10</li>
<li><span style='background:#D46B36;'></span>< 15</li>
<li><span style='background:#BB3C01;'></span>15+</li>
Once the interactivity and legend fields have been completed select 'Save' and the completed map should now look like this (with the mouse hovering over the DRC):
Finally, for the supply chain level map, create a new project with filename deliver-supply-chain-level-may
and a project name DELIVER | Supply Chain Level May
. Add the method layer as before, this time labeling it #supply-chain
and replacing the query with the following:
(select * from attributes join ppmr.may_country_supply_chain_level on
may_country_supply_chain_level.country_id = attributes.country_id)
The Carto for the #country-labels
layer remains the same as for the method maps, while it is as follows for the #supply-chain
layer:
#supply-chain {
polygon-fill:#f6f6f6;
polygon-gamma:0.5;
[zoom < 6]{line-opacity:0.5;}
[country_supply_chain_level_id = 1]
{polygon-fill:@c1; line-color:darken(@c1,75);}
[country_supply_chain_level_id = 2]
{polygon-fill:@c3; line-color:darken(@c3,60);}
[country_supply_chain_level_id = 4]
{polygon-fill:@c5; line-color:darken(@c4,55);}
}
The color designation is the same for countries with supply chain level 'Central' as it is for data class 1 in the method maps, while 'Central + All' is the same as class 3, and 'All' is the same as class 5. Notice the darker the color, the more detailed or comprehensive the supply chain level.
The HTML for the interactivity is as follows, with the #supply-chain
layer activated:
<div class='my-tooltip'>
<div class='tooltip-title'>{{{country_name}}}</div>
<div class='tooltip-date'>{{{month_name}}}, {{{year}}}</div>
<div class='tooltip-subtitle'>Supply Chain Level: <span>{{{country_supply_chain_level_name}}}</span></div>
While the HTML for the legend is as follows:
<div class='supply-legend'>
<div class='legend-supply-title'>Supply Chain Level</div>
<div class='legend-supply-scale'>
<ul class='legend-supply-labels'>
<li><span style='background:#FDE3B8;'></span>Central</li>
<li><span style='background:#FC8D59;'></span>Central + Other</li>
<li><span style='background:#BB3C01;'></span>All</li>
<span class='space'>
<li><img src='https://img.skitch.com/20111222-q65jt21u1qmxh8j2bsf1hdhkpq.jpg'>No Data</li>
</span>
</ul>
</div>
<div class='legend-supply-source'>Compiled by: <a href="http://deliver.jsi.com/">USAID | DELIVER PROJECT</a></div>
</div>
As with the method maps, the supply chain level map's legend and interactivity styling is assigned through the style.css
in the microsite template. The supply chain level map should now look like this (again with the mouse hovering over the DRC):
To authorize TileMill to upload maps directly to the MapBox account, navigate to 'Settings' in the main menu and select 'Authorize' next to 'MapBox':
A prompt should then appear with a menu to log in:
Followed by another prompt asking for authorization - select 'Authorize'. If successful, the following prompt will appear on the main menu upon completion:
Upon successfully authorizing the account, navigate to the map to be uploaded, select 'Export' in the upper right hand corner and click 'Upload':
Set the zoom extent to 2-8 and the bounds -180,-85.0511,180,85.0511
. The center of the map will vary based on the method, which will be addressed during the microsite template overview:
Select 'Upload' and the 'View Exports' list will appear:
Once completed the upload time bar will disappear and the layer will display a check mark next to it, as in the DELIVER | Supply Chain Level May
and DELIVER | Progestin-Only Oral Contraceptive May
maps shown in the screenshot above. To view these maps online, open a web browser and navigate to http://mapbox.com. Select 'Login' in the upper right hand corner of the landing page and enter the appropriate username (usaid-deliver-project) and password (JohnSnow). The account page should appear like so:
Repeat for each map, and once uploaded they are ready for integration with the microsite template.
This project uses the Data Exploration map site template produced by MapBox, the source code for which is hosted on github and available for public use. The project comes with a variety of folders, a number of which are not necessary for the purposes of this project including: fonts
, graphic-src
, and tilemill
. The readme.md
file is not necessary to the function of the site, but serves as a good reference when deciphering what elements to alter in order to redesign the site as desired. The index.html
and style.css
are the only two documents that will need to be altered for the purposes of this project.
Let's start with what was removed from the original index.html
.
The site's shortcut icon (accompanying the tab title in a web browser) was removed:
<link rel="shortcut icon" href="img/favicon.ico" type="image/x-icon" />
The entire 'content' section, alongside 'branding' and 'about' were removed:
<div id="content">
<div id='branding'></div>
<div id="about">
<h1>DC's Changing Landscape</h1>
<p>Over the past few years, Washington DC has been undergoing economic, social, and demographic shifts. Property values in particular have been changing rapidly as parts of the city undergo aggressive development. See how these factors are shaping DC.</p>
<div data-control="geocode" id="search">
<form class="geocode">
<input placeholder="Search for an address" type="text">
<input type="submit" />
<div id="geocode-error"></div>
</form>
</div>
</div>
</div>
The legend was removed:
<div class="wax-legends">
<div class="wax-legend" style="display: block; ">
<div class="scale">
<label><a href="http://data.dc.gov/Main_DataCatalog.aspx?id=10">% Change in property value '10-'11</a></label>
<div><img src="img/grid-scale-2.png" /></div>
<div>
<span>< -20</span>
<span>< -10</span>
<span>< -5</span>
<span>< 0</span>
<span>0</span>
<span>> 0</span>
<span>> 5</span>
<span>> 10</span>
<span>> 20</span>
</div>
</div>
<div>
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAa0lEQVQIHWNkaPjPpPhitcn/f4xZDP8ZXjD8/tLBIvhsNe9/BqZ1jAwM0gyMDL8ZWHhYmLj/fmIGCzCAwH/mf8wM6kzizH8////PMBEsxvD/HdPf/5MY/wNFGMNWM0tzfhdgZeL7e39+wAcAdhYlGm+mTIMAAAAASUVORK5CYII=" style="margin-bottom: 2px;">
<label><a href="http://data.dc.gov/Main_DataCatalog.aspx?id=5">Construction project</a></label>
</div>
<div>
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAV0lEQVQIHWP8//8/AxgwMjIyQDmM/52D4xkYmGYzMDIwAwX7GfasLgEKhn4GCvBAlDP8Y3h/j4MJKPAXKsAAVPmP4ezZP0wM/xkigIIfgfR3BgbGcpC5AExlIK8M2/cpAAAAAElFTkSuQmCC" style="margin-bottom: 2px;">
<label><a href="http://data.dc.gov/Main_DataCatalog.aspx?id=3">Crime incident</a></label>
</div>
</div>
</div>
And the markers.js support was removed <script src="ext/mmg.js"></script>
alongside the mmg.js
file in the ext
folder (this javascript library is only necessary if dropping markers on the map, which is unnecessary for this project).
Now, for what was altered in the original index.html
.
The title <title>DC's Changing Landscape</title>
was changed to <title>USAID | DELIVER PROJECT</title>
.
The layer elements were altered from this:
<div id="projects" class="layers">
<a data-control="layer" href="#building">Building Permits, 2011</a>
<a data-control="layer" href="#construction">City Construction Projects, 2011</a>
</div>
<div id="crime" class="layers">
<a data-control="layer" href="#crime">Total Crime, 2011</a>
<a data-control="layer" href="#robbery">Robbery, 2011</a>
<a data-control="layer" href="#theft">Theft, 2011</a>
<a data-control="layer" href="#auto">Theft from Auto, 2011</a>
</div>
To this:
<div id="projects" class="layers">
<a class='active' data-control="layer" href="#supply_chain">Supply Chain Level</a>
</div>
<div id="method" class="layers">
<a data-control="layer" href="#inject_1">1-Month Injectable</a>
<a data-control="layer" href="#inject_2">2-Month Injectable</a>
<a data-control="layer" href="#inject_3">3-Month Injectable</a>
<a data-control="layer" href="#comb_oral">Combined Oral Contraceptive</a>
<a data-control="layer" href="#emerg_contra">Emergency Contraceptive</a>
<a data-control="layer" href="#fem_condom">Female Condom</a>
<a data-control="layer" href="#implant">Implant</a>
<a data-control="layer" href="#iud">IUD</a>
<a data-control="layer" href="#male_condom">Male Condom</a>
<a data-control="layer" href="#other">Cycle Beads</a>
<a data-control="layer" href="#prog_oral">Progestin-Only Oral Contraceptive</a>
</div>
Creating a layer for each method, with the supply chain level map differentiated from the method maps. The layer script was altered from this:
<script type="text/javascript">
var main = Map('map', {
api: 'http://a.tiles.mapbox.com/v3/examples.map-20v6611k,mapbox.dc-property-values.jsonp',
center: {
lat: 38.9090033656251,
lon: -77.014396158891,
zoom: 13
},
zoomRange: [0, 15],
features: [
'zoomwheel',
'movetips',
'zoombox',
'zoompan',
'share'
]
});
main.layers({
building: {
api: 'http://a.tiles.mapbox.com/v3/mapbox.dc-building.jsonp',
center: {
lat: 38.910606275724,
lon: -77.00126406355,
zoom: 14,
ease: 500
}
},
construction: {
api: 'http://a.tiles.mapbox.com/v3/mapbox.dc-construction.jsonp',
center: { zoom: 12, ease: 1000 }
},
crime: {
api: 'http://a.tiles.mapbox.com/v3/mapbox.dc-crime.jsonp',
center: { zoom: 13, ease: 1000 }
},
robbery: { api: 'http://a.tiles.mapbox.com/v3/mapbox.dc-crime-robbery.jsonp' },
theft: { api: 'http://a.tiles.mapbox.com/v3/mapbox.dc-crime-theft.jsonp' },
auto: { api: 'http://a.tiles.mapbox.com/v3/mapbox.dc-crime-auto.jsonp' }
});
</script>
To this:
<script type="text/javascript">
var main = Map('map', {
api: 'http://a.tiles.mapbox.com/v3/usaid-deliver-project.deliver-base-map.jsonp',
center: {
lat: 12.555,
lon: 8.4380,
zoom: 3
},
zoomRange: [2, 8],
features: [
'zoomwheel',
'tooltips',
'legend',
'zoombox',
'zoompan',
'share'
]
}, function() {
main.setOverlay('supply_chain');
});
main.layers({
supply_chain: {
api: 'http://a.tiles.mapbox.com/v3/usaid-deliver-project.deliver-supply-chain-level-may.jsonp',
center: {
lat: 12.555,
lon: 8.4380,
zoom: 3,
ease: 1000
}
},
inject_1: {
api: 'http://a.tiles.mapbox.com/v3/usaid-deliver-project.deliver-1-month-injectable-may.jsonp',
center: {
lat: 11.006,
lon: -2.813,
zoom: 5,
ease: 1000
}
},
inject_2: {
api: 'http://a.tiles.mapbox.com/v3/usaid-deliver-project.deliver-2-month-injectable-may.jsonp',
center: {
lat: 10.532,
lon: 24.610,
zoom: 3,
ease: 1000
}
},
inject_3: {
api: 'http://a.tiles.mapbox.com/v3/usaid-deliver-project.deliver-3-month-injectable-may.jsonp',
center: {
lat: 12.555,
lon: 8.4380,
zoom: 3,
ease: 1000
}
},
comb_oral: {
api: 'http://a.tiles.mapbox.com/v3/usaid-deliver-project.deliver-combined-oral-contraceptive-may.jsonp',
center: {
lat: 12.555,
lon: 8.4380,
zoom: 3,
ease: 1000
}
},
emerg_contra: {
api: 'http://a.tiles.mapbox.com/v3/usaid-deliver-project.deliver-emergency-contraceptive-may.jsonp',
center: {
lat: 12.684,
lon: 24.609,
zoom: 3,
ease: 1000
}
},
fem_condom: {
api: 'http://a.tiles.mapbox.com/v3/usaid-deliver-project.deliver-female-condom-may.jsonp',
center: {
lat: 4.478,
lon: 12.656,
zoom: 4,
ease: 1000
}
},
implant: {
api: 'http://a.tiles.mapbox.com/v3/usaid-deliver-project.deliver-implant-may.jsonp',
center: {
lat: 12.555,
lon: 8.4380,
zoom: 3,
ease: 1000
}
},
iud: {
api: 'http://a.tiles.mapbox.com/v3/usaid-deliver-project.deliver-iud-may.jsonp',
center: {
lat: 12.555,
lon: 8.4380,
zoom: 3,
ease: 1000
}
},
male_condom: {
api: 'http://a.tiles.mapbox.com/v3/usaid-deliver-project.deliver-male-condom-may.jsonp',
center: {
lat: 12.555,
lon: 8.4380,
zoom: 3,
ease: 1000
}
},
other: {
api: 'http://a.tiles.mapbox.com/v3/usaid-deliver-project.deliver-cycle-beads-may.jsonp',
center: {
lat: 9.796,
lon: -33.662,
zoom: 3,
ease: 1000
}
},
prog_oral: {
api: 'http://a.tiles.mapbox.com/v3/usaid-deliver-project.deliver-progestin-only-oral-contraceptive-may.jsonp',
center: {
lat: 12.555,
lon: 8.4380,
zoom: 3,
ease: 1000
}
}
});
</script>
With the movetips
feature removed (interactivity that moves along with your mouse) and the tooltips
and legend
features added, allowing for the interactivity to remain in one location at all times and for the legend to update depending on the active layer (as the legend varies per method because of the different data classifications).
The var main = Map
is the base map that is to stay activated throughout site navigation:
var main = Map('map', {
api: 'http://a.tiles.mapbox.com/v3/usaid-deliver-project.deliver-base-map.jsonp',
center: {
lat: 12.555,
lon: 8.4380,
zoom: 3
},
While the center lat
, lon
, and zoom
are set for each layer, with the ease
set for the speed of the transitions between each layer (the higher the number the longer the transition). The api
specifies the MapBox hosting url that the site is to pull from for each map.
This function function() {main.setOverlay('supply_chain');}
was added to assign the supply chain level map to activate upon navigating to the site (without this function only the base map would appear at first).
Two elements were added to the original index.html
. The USAID | DELIVER PROJECT logo, housed in the branding
folder (the alteration of which is to be explained later):
<div id='logo'>
<a href="http://deliver.jsi.com/" target="_blank"><img src="branding/logo.png" width="400"></a>
</div>
And the TileMill and MapBox attribution:
<div id='attribution'><h7>Maps designed in <a href="http://mapbox.com/tilemill">TileMill</a>, hosted on <a href="http://mapbox.com">MapBox</a></h7>.
</div>
Both of these elements sit in the lower left hand corner of the site.
To add a new map layer to the site, simply add a new layer to the element list like this:
<a data-control="layer" href="#inject_1">1-Month Injectable</a>
Then add the script to the site configuration like this:
inject_1: {
api: 'http://a.tiles.mapbox.com/v3/usaid-deliver-project.deliver-1-month-injectable-may.jsonp',
center: {
lat: 11.006,
lon: -2.813,
zoom: 5,
ease: 1000
}
},
Making sure the names match up (#inject_1
in the element list, inject_1
in the script) and that the api
and center coordinates are adjusted appropriately.
For the style.css
, let's walk through the different elements of the map and site framework that the CSS is controlling. Starting from the top, under Typography
:
h7 {
font: 90%/14px 'Gill Sans MT', 'Gill Sans', Calibri, 'Trebuchet MS', sans-serif;
text-align: left;
color: #333;
}
a {
color:#888;
text-decoration:none;
}
h7
is assigning style to the attribution, as discussed in the index.html
additions, while a
is assigning style to the hyperlinks included in this element.
Under 'Layout':
.layers {
position: absolute;
width: 120px;
left: 10px;
top: 10px;
}
.layers a {
padding: 10px;
margin: 2px 0;
border: 1px solid #333;
background: white;
color: #333;
}
.layers a:hover, .layers a:focus, .layers a.active {
background: #004990;
color: white;
}
.layers#method {
position: absolute;
top: 60px;
left: 10px;
}
#method.layers a:hover, #method.layers a:focus, #method.layers a.active {
background: #004990;
color: white;
}
.layers a {
font: bold 85% 'Gill Sans MT', 'Gill Sans', Calibri, 'Trebuchet MS', sans-serif;
width: 110px;
float: left;
margin-right: 20px;
}
These rules are assigning style to the layer list in the sidebar of the map, with .layers a
representing active layers, .layers
representing the size of the layer boxes and positioning of the supply chain level map layer box, and .layers#method
representing the positioning of the method layers boxes.
Under Map
:
.wax-tooltip {
top: 10px;
right: 10px;
overflow: visible;
max-width: none;
border: 1px solid #333;
}
.wax-tooltip .my-tooltip {
font-family: 'Gill Sans MT', 'Gill Sans', Calibri, 'Trebuchet MS', sans-serif;
}
.wax-tooltip .tooltip-title {
font-size: 150%;
font-weight: bold;
padding: 5px 0px 4px 5px;
}
.wax-tooltip .tooltip-subtitle {
font-size: 100%;
line-height: 16px;
padding: 0px 0px 8px 5px;
}
.wax-tooltip .tooltip-subtitle span {
font-weight: bold;
}
.wax-tooltip .tooltip-date {
font-size: 100%;
line-height: 16px;
padding: 0px 0px 4px 5px;;
}
.wax-tooltip table {
font: 90%/16px 'Gill Sans MT', 'Gill Sans', Calibri, 'Trebuchet MS', sans-serif;
width: 100%;
padding-bottom: 5px;
border-collapse: collapse;
border-style: hidden;
}
.wax-tooltip table th, table td {
padding: 2px 5px 5px 5px;
border: 1px solid black;
vertical-align: top;
font-size: 100%
}
.wax-tooltip table th {
text-align: left;
}
.wax-tooltip table th {
font-weight: bold;
vertical-align: middle;
}
.wax-tooltip table td {
vertical-align: top;
}
These rules are assigning style to the HTML in the interactivity, while these:
.wax-legend .my-legend {
font-family: 'Gill Sans MT', 'Gill Sans', Calibri, 'Trebuchet MS', sans-serif;
}
.wax-legend .legend-title {
font: bold 100%/16px 'Gill Sans MT', 'Gill Sans', Calibri, 'Trebuchet MS', sans-serif;
text-align: left;
}
.wax-legend .legend-amc {
text-align: left;
font: regular 100%/16px 'Gill Sans MT', 'Gill Sans', Calibri, 'Trebuchet MS', sans-serif;
margin-bottom: 4px;
}
.wax-legend .legend-scale ul {
margin: 0;
padding: 0;
float: left;
list-style: none;
}
.wax-legend .legend-scale ul li {
display: block;
float: left;
width: 45px;
text-align: center;
font-size: 85%;
list-style: none;
}
.wax-legend ul.legend-labels li span {
display: block;
float: left;
height: 14px;
width: 45px;
}
.wax-legend .legend-source {
font-size: 100%;
line-height: 16px;
clear: both;
}
.wax-legend a {
font-size: 90%;
line-height: 14px;
color: #327f8f;
}
.wax-legend .space {
margin-left: 4px;
float: right;
font-size: 100%;
line-height: 13px;
}
Are assigning style to the HTML in the legend for all method maps, and these:
.wax-legend .supply-legend {
font-family: 'Gill Sans MT', 'Gill Sans', Calibri, 'Trebuchet MS', sans-serif;
}
.wax-legend .legend-supply-title {
font: bold 100%/16px 'Gill Sans MT', 'Gill Sans', Calibri, 'Trebuchet MS', sans-serif;
text-align: left;
padding-bottom: 8px;
}
.wax-legend .legend-supply-scale ul {
margin: 0;
padding: 0;
float: left;
list-style: none;
}
.wax-legend .legend-supply-scale ul li {
display: block;
float: left;
width: 52px;
text-align: center;
font-size: 85%;
list-style: none;
line-height: 14px;
}
.wax-legend ul.legend-supply-labels li span {
display: block;
float: left;
height: 15px;
width: 52px;
}
.wax-legend .legend-supply-source {
font-size: 100%;
line-height: 16px;
clear: both;
padding-top: 4px;
}
Are assigning style to the HTML in the legend for the supply chain level map.
#logo
is assigning positioning to the USAID | DELIVER PROJECT logo, while #attribution
is assigning positioning to the TileMill and MapBox attribution. Everything else under the /* SHARE */
and /* EMBED */
headlines are assigning style and positioning to the share and map embed features, preloaded with the microsite template.
The final piece to this documentation is a quick tutorial on how to alter the original USAID | DELIVER PROJECT logo for map integration.
- To begin, open the original logo
logo-original.jpg
in Inkscape. - Using the 'Select and transform objects' tool (represented by the mouse pointer icon) click and drag over the entire logo to select the image.
- Navigate to 'Path' in the top toolbar and select 'Trace Bitmap...'
- Under the 'Multiple scans' menu in the 'Mode' tab check the 'Colors' oval and the 'Remove background' box and deselect the 'Smooth' box.
- In the 'Options' tab deselect the 'Smooth corners' box, then click 'OK'.
- Click and drag the newly created layer away from the original layer underneath and remove the original layer by selecting the image and hitting
delete
. - Select the new layer and navigate to 'File' in the top toolbar, 'Export Bitmap...', and set the 'Width' under 'Bitmap size' to 500.
- Enter
logo.png
into the 'Filename' field and click 'Export'.
The logo has now been converted to .png
with the background removed, and it is now ready for map integration. See the 'Microsite Template Alternation and Design' section above for details on how this logo is integrated into the site.