Learn to create geospatial and treemap visualizations and apply colormaps.
There are three parts to the assignment. You may complete the assignment in a single HTML file or use multiple files (e.g. one for CSS, one for HTML, and one for JavaScript). You should use D3 v7 and Observable Plot for this assignment as directed (Part 1 using D3, Parts 2&3 using either or both). All visualization should be done using D3 calls except where instructed otherwise. You may use other libraries, but you must credit them in the HTML file you turn in. Extensive documentation for D3 is available, and Vadim Ogievetsky’s example-based introduction that we went through in class is also a useful reference. The D3 and Observable Plot Map Examples may also help. Finally, the courselet on color in data visualization should help you understand the details of colormapping as implemented with Plot: download, view
The assignment is due at 11:59pm on Wednesday, April 2.
You should submit any files required for this assignment on Blackboard. For Observable, do
not publish your notebook; instead, (1) share it with me
(@dakoop
) and (2) use the “Export -> Download Code”
option and turn in that file renamed to a4.tar.gz
(or
a4.tgz
) file to Blackboard. Please do both of these steps
as (1) is easier for me to grade, but (2) makes it possible to persist
the state of the submission. If you complete the assignment outside of
Observable, you may complete the assignment in a single HTML file or use
multiple files (e.g. one for HTML and one for CSS). Note that the files
should be linked to the main HTML document accordingly in a
relative manner (styles.css
not
C:\My Documents\Jane\NIU\CSCI627\assignment4\styles.css
).
If you submit multiple files, you may need to zip them in order for
Blackboard to accept the submission.
In this assignment, we will examine information about corn and soybean production in Illinois. This data comes from the USDA’s Census of Agriculture through the QuickStats service. Specifically, we are interested in how much of each crop different counties and agricultural districts produce in Illinois. This data has been extracted and is available online. To create maps, we will use data with the outlines of each Illinois county. This file is in a GeoJSON format that D3 and Observable Plot can handle. In addition, the boundaries have been simplified. The goal of the assignment is to understand crop production across Illinois.
Like Assignment 1, make sure your assignment contains the following text:
If you used any additional JavaScript libraries or code references, please append a note to this section indicating their usage to the text above (e.g. “I used the jQuery library to write callback functions.”) Include links to the projects used. You do not need to adhere to any particular style for this text, but I would suggest using headings to separate the sections of the assignment.
Use D3 for this part of the assignment.
Create a map that shows the Illinois county boundaries. You will only need the GeoJSON data for this part of the assignment. Remember that you will need a projection for the map. For this assignment, we will use the Illinois East State Plane projection. Noah Veltman has provided a handy list of these in d3.geo format here.
For the map, you will want to use each county as a separate feature.
You can access mapData.features
to obtain this array. Each
feature has a number of properties that can be useful for the next
steps. If you wish, you could implement a tooltip using the
COUNTY_NAM
attribute to show a county’s name (for a data
item d
, this is stored in
d.properties.COUNTY_NAM
). You can load the mapData via
d3.json
.
mapData
is the variable
loaded by d3.json
, mapData.features
is a list
of all of the counties.d3.geoPath
can have an associated projection is used to translate GeoJSON features
into paths on screen.Create a second Illinois map that colors the counties based on the
agricultural district they belong to. The districts are defined by the
AgDistrict
property in the crop production json. In order
to color the counties, we want to look up the district given the county.
In the GeoJSON file you used in Part 1a, there is a CO_FIPS
property that can be used to match with the CountyANSI
value in the crop production json file. Given a GeoJSON feature
d
, a county’s properties are accessed from the
properties
object as d.properties
. Thus,
d.properties.CO_FIPS
gives the county’s code. It is
probably worth creating a new lookup from the original data in the form
of a Map
or an Object that looks something like
{31: "Northeast", 139: "East Southeast", ...}
where the
keys are the CountyANSI
values, and the values are the
AgDistricts. Pick an appropriate colormap for this data. A list of color
schemes is here.
You may use either D3 or Observable Plot (or both) for this part of the assignment. The projection in Part 1a can be translated to Plot:
{ type: "transverse-mercator", rotate: [88 + 20 / 60, -36 - 40 / 60] }
You will create three visualizations with different colormaps.
Using the crop production data in concert with the GeoJSON data, create a new choropleth map that shows the 2023 corn harvest by county. The colormap should accurately convey the amount for each county. Create a legend so a viewer can understand the values.
A sample entry of the crop data looks like
"Year":2022,"AgDistrict":"Northeast","County":"Boone","CountyANSI":7,"CornAcresPlanted":68700,"CornAcresHarvested":67400,"CornYield":209.2,"SoybeansAcresHarvested":50400,"SoybeansAcresPlanted":50600,"SoybeansProduction":3135000,"SoybeansYield":62.2},
[{"Year":2023,"AgDistrict":"Northeast","County":"Boone","CountyANSI":7,"CornAcresPlanted":70500,"CornAcresHarvested":69700,"CornYield":212.7,"SoybeansAcresHarvested":48600,"SoybeansAcresPlanted":48800,"SoybeansProduction":2897000,"SoybeansYield":59.6},
{...]
For this part, you will need to use only the 2023 CornAcresHarvested
data. As with Part 1, I would suggest writing code to create a Map
so that given a CountyANSI
value, you can obtain its
data.
What is a problem with this visualization? Think about what acres is measuring…
Create a second choropleth visualization, but this time, show the
yield for corn in 2023. This was calculated as the
number of bushels per acre and stored in the CornYield
field. This provides a picture of which counties’ corn platings were
most productive. Remember to include a legend.
Create a third choropleth visualization, but this time, show the difference in corn acres harvested vs the soybean acres harvested in 2023. You still should be able to compute this directly, given the a map from the county code to the data for that county. You will need to use a different colormap than in part a. Again, add a legend.
unknown
option. In D3, check if the value is
null before passing it to the scale.d3.scaleSequential
can help with colormapping. Remember to check the type of the values you
are displaying to determine a correct colormap.Now, we wish to better understand crop production by county and agricultural district. To do so, we can create a treemap using the values for one of the crops (e.g. corn) and the hierarchy ag district -> county. To help users understand the data, we will label the agricultural districts and counties, but we can do this selectively so counties with little production are not labeled. You may use D3 or Observable Plot or both for this part. D3 contains the functions to create the hierarchy and treemap.
To create the hierarchy, we can first group the data by ag district
and county using d3.group
. Then, we can pass this result to
d3.hierarchy
to build the tree. Note that maps can be passed directly without
transformation. Make sure to specify which attribute to sum and how to
sort. We can now pass this hierarchy to the d3.treemap layout
function to calculate the rectangles. Use the squarify layout (this is
the default).
From the treemap t
, you can extract all leaves via
t.leaves()
to draw the visualization. Use the
x0, x1, y0, y1
coordinates to draw each leaf rectangle. The
color should reflect the ag district. Add a tooltip that shows the ag
district, county, and value, when a county is highlighted. Include the
“Other Counties” data as a separate district. Create a treemap for the
2023 SoybeansAcresHarvested
.
.parent
property. All leaves will be at the same depth so
you can extract all nodes for districts via the correct mapping of
leaves to parents (or grandparents).Set
will eliminate duplicated nodes (e.g. from districts)selectAll
statements do not select
already created objects! For example, calling
svg.selectAll(
text)
twice on the same svg will
bind the already created rectangles on the second call. You can attach a
class name (text.district
) to the object type to avoid
this.foo
of a leaf d
in
stored in d.data.foo
, but extracting a district/county
label is at d.data[0]
.text-anchor: middle
style property.For extra credit, CS 490 students may complete Part 3. In addition, all students may implement a way for users to interactively update which year (or crop) is shown for the visualizations shown in Part 2 or Part 3 (up to 20 points).