Get started (or continue) with dynamic web content creation. This assignment will introduce (or reintroduce) you to JavaScript and how it can be used to manipulate HTML and SVG content.
There are three parts for this 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 may not use D3 or any other external libraries for any of this assignment except for loading data. The Mozilla Developer Network documentation serves as a great reference for the technologies involved in this assignment. In addition, Scott Murray’s Interactive Data Visualization for the Web is a useful reference (see Chapter 3).
The assignment is due at 11:59pm on Monday, February 10.
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 a2.tar.gz
(or
a2.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 (style.css
not
C:\My Documents\Jane\NIU\CSCI627\assignment2\styles.css
).
If you submit multiple files, you may need to zip them in order for
Blackboard to accept the submission. The filename of the main HTML
document should be a2.html
.
This assignment deals with data about the Chicago Department of Public Health’s food inspections. The city makes this data publicly available on its data portal. We wish to examine the number of inspections by month over the past couple of years. I have processed the raw data and grouped it by month in JavaScript file that is available online. You will create three visualizations from this data: a table, a horizontal bar chart, and a vertical bar chart.
The attributes of this data include:
year
: the yearmonth
: the monthPass
: the number of establishments that passed
inspectionPass w/ Conditions
: the number of establishments that
passed inspection with conditionsFail
: the number of establishments that failed
inspectionOut of Business
: the number of establishments that were
out of businessNo Entry
: the number of establishments that could not
be enteredNot Ready
: the number of establishments that were not
ready for inspectionBusiness Not Located
: a string
represented the establishments that could not be located
or "NA"
if there were noneYou will create three visualizations from this data: a table, a horizontal bar chart, and a vertical bar chart. Note that only CSCI 627 students need to complete Part 3b, but CS 490 students may complete it for extra credit.
Like Assignment 1, start by creating an HTML web page with the title “Assignment 2”. It should contain the following text:
You should load the data via a d3.json
call using the
full url: https://gist.githubusercontent.com/dakoop/f9e24fdf5340a374f1c100f2982338a7/raw/d6a880d9ea0536a69a6c9068e5a6bd0c1b5a55cf/food-inspections.json.
Outside of Observable, this requires including the d3-fetch
library. In Observable, File
Attachments could also be used, but make sure you do not
edit the contents of the file before uploading it; if you edit
the file instead of using JavaScript to process it, points will be
deducted. Once you load the file, you should see an array of objects,
one for each month. In Observable, you can view the output of your code,
but if you’re in another environment, consider using the
console.log
function to print your updated data to the
Console (a tab in Developer Tools panel of your browser). The data for
August 2024 looks like:
year: 2024, month: 8, Out of Business: 126, Fail: 290, Pass: 796, Business Not Located: "2", No Entry: 129, Pass w/ Conditions: 213, Not Ready: 27} {
We will be processing this data to convert the strings to numbers, compute the total inspections, and then render a table of the values.
In this section, do not use loops. Use Array
functions map
, filter
, reduce
,
and/or forEach
. Also, do not change the
order of the data items (i.e. do not sort the array). First, note that
the Business Not Located
may be zero, but that is indicated
with the value “NA” and thus the column has string
values. Create a new array where these values have been converted to
integers and “NA” values are set to zero. Do not modify
the array in place; use the spread
syntax to copy over most values and add or overwrite others. Second,
create another new array where each object has a
Total Inspections
column that sums all the different
inspection results (all columns except year and month). Again,
do not modify the array in place; create new objects
using the spread
syntax. The full output is available here.
parseInt
method that will convert a
string into an integer.{key1: var1, key2: var2}
).obj = {key1: var1, key2: var2}
,
{...obj, key2: 13}
overwrites the key2 value with the new
value 13.Once you have verified that your function works correctly, display
the results in text on your web page. If you were not
able to get part a to work correctly, you may store the output here in a JavaScript variable. To create the
table, you will need to dynamically create HTML elements in your web
page. You may either create a <div>
element for the
table and add the necessary elements to it using JavaScript, or use
templating to dynamically create the rows. I recommend using Observable
, but you may also use innerHTML
and template
literals. Your table should have 10 columns: one for the year, one
for month, and one for each of the counts. Add headers
to the top of the table to indicate what is shown in each column. Your
table should be sorted, but do this by creating a copy
of the array using toSorted
(leave the original array unsorted).
document.getElementById
or document.querySelector
function to get a reference to the parent div
element.Now, let’s create a more visual representation of this data using a bar chart that shows the total inspections by month using the same data as in Part 1a. Important: Do not sort the data from Part 1a! The bar chart should be horizontal, meaning that bars grow from the left to the right side of the canvas. Add axes labels to indicate the starting and ending month as well as range of values. For this assignment, the labels do not need to be precise.
Create an svg
element with width 400px and height 400px.
Then, add svg elements using JavaScript to create the bars and labels.
The visualization must accurately represent the data, but you should
experiment with the design of the chart (thickness of lines, number of
labels, spacing, axes scales, colors) to find a visualization that
communicates the data well. Here, templating should again work well, but
you may also use the addEltToSvg
helper method we saw in
class:
function addEltToSvg(name, attrs, appendTo)
{var element = document.createElementNS("http://www.w3.org/2000/svg", name);
if (attrs === undefined) attrs = {};
for (var key in attrs) {
.setAttributeNS(null, key, attrs[key]);
element
}if (appendTo) {
.appendChild(element);
appendTo
}return element;
}
Now, redo Part 2 but as a vertical bar chart, meaning that bars grow from the bottom to the top of the canvas. Again, add axes labels to indicate the starting and ending months as well as range of values. Again, use JavaScript or templates to add the SVG elements. Here, the SVG is 400x300 pixels.
Now, update your code for the vertical bar chart so that a user can
highlight a group of bars by quarters. A quarter is three consecutive
months of the year. Specifically, given a quarter (e.g. 2nd Quarter of
2023), change the appearance of all of those quarters’s
bars (e.g. 2023-04, 2023-05, 2023-06) to stand out from the others. This
should be static; you should not update the highlighted
bar based on where the mouse is. In either case, use the
class
attribute to specify the style of the highlighted
bars and write the corresponding CSS to specify the change to the style.
If using Observable, you can use an input to set a
variable that you can use reactively in your template.
= html`<input type="range" id="quarter" min="0" max="7" value="0"></input>`; viewof quarter
Now, other cells can reference the variable quarter
and
any time the slider moves, those cells will reactively execute. Note
that the quarters start at 0 which is the 1st quarter of 2023, and 7 is
the 4th quarter of 2024.
The other approach is to add the following HTML after your vertical barchart:
<div id="controls">
<label for="quarter">Quarter:</label>
2023-1<input type="range" id="quarter" min="0" max="7" value="1"></input>
2024-4</div>
and JavaScript code:
document.getElementById('quarter').onchange=(function() { highlightQuarter(this.value); });
and finally, define a function highlightQuarter
that
will highlight the specified quarters. (You could also put this directly
in the onchange
function if you wish.) In addition, if you
wish to use a different input to trigger the highlighting (e.g. a text
field), this is also ok. However, you may not simply
have the user define the variable (quarter = 3
); it must
use an <input>
element as we are trying to improve
user interaction.
setAttribute
calls.