Assigned | Thursday, 8 February |
Due | Wednesday, 14 February, 11:59 p.m. |
Contents
- Introduction
- Part 1: Data
- Part 2: Sunlight
- Part 3: Moonlight
- Part 4: Visualization
- Challenge exercise
- Check blocks (autograder compatibility)
- Assignment guidelines
- Submitting the assignment
Introduction
We love sunny days, and as winter begins to fade, the hours of daylight are beginning to grow. In this assignment, we’ll use our experience working with tables to process solar and lunar temporal information and to visualize how the hours of sunlight and moonlight vary over time.
Task: Since you’ll be working with tables, at the top of your file, add the line
include shared-gdrive("dcic-2021", "1wyQZj_L0qqV9Ekgr9au6RX2iqt2Ga8Ep")
And remember, for help with table functions, refer
to this
documentation, which goes with the dcic-2021
functions,
rather than the official Pyret documentation.
Part 1: Data
Some kindly astronomers have shared a data set with us, which they’ve made available as a Google sheet.
Task:
Copy the unique ID – the long string of letters, numbers, and
underscores – in the spreadsheet URL and use it to
load it into a Pyret table named celestial-data
. Refer to
the code for loading a table from a spreadsheet, seen in class
and in
the textbook.
To ensure the autograder works for your program, use the column names
year, month, day, age-of-moon, sun-rise, sun-culm, sun-set, moon-rise, moon-culm, moon-set
We won’t use all of the columns in this spreadsheet. This is perfectly normal when working with real data sets!
Task: To test the functions we’ll write, we also need a small table of test data. Use the following table or make up your own examples:
test-data = table: year, month, day, sun-rise, sun-set, moon-rise, moon-set row: 2021, 9, 30, "06:30", "18:30", "00:00", "16:00" row: 2022, 3, 22, "07:00", "18:00", "23:00", "08:30" end
You should use your test-data
table to write examples
for each function in a where
block.
While the autograder won’t deduct points for missing
tests, your instructor will!
Doing so before you write the body of the function will ensure you
understand how the function is supposed to work.
Part 2: Sunlight
To compute the hours of sunlight, we’ll need to know the elapsed time
between sunrise and sunset. It’s complex to do this with times expressed
as hours and minutes, e.g., "06:30"
, so we’ll
first write a function to convert a time to minutes.
Task: Write a function
fun mins-since-midnight(time :: String) -> Number: ... end
Given a time as a string (like those in the table), it should convert it to the number of minutes since midnight.
Hints:
- For each function on the assignment, try writing examples
in the
where
block before you write the body of the function. This ensures you understand how the function is supposed to work! - Since the times are strings, you may want to review the documentation listing the functions Pyret provides for working with strings. How could you find just the hours in the string? Just the minutes? Some of the string functions you’ll see in the documentation produce a list. Although you may have seen lists in class, you don’t need to use lists to solve this problem!
After you’ve identified the hours and minutes, you’ll need to use the function
string-to-number
. Despite its name, the output is not a number! It’ssome
number if the string can be converted andnone
if it can’t. For this assignment, the strings can always be converted to numbers, so you only need to worry about thesome
case. To get the number out, use.value
:››› string-to-number("06") some(6) ››› string-to-number("06").value 6
Now that you can convert the sunrise and sunset times to minutes since midnight, it’s not too hard to compute how many minutes are in between.
Task: Write a function
fun elapsed-mins(start-time :: String, end-time :: String) -> Number: ... end
It should compute the minutes the elapsed between the given start time and end time, provided as strings like those found in the table.
And now we’re ready to add a new column to the table containing the hours of sunlight.
Task:
Make a table named celestial-data-sun
that has a new column
called "sunlight"
that contains the number
of hours of sunlight for each day.
Remember: To do this, you’ll need to define a function that
you’ll pass as an input to
build-column
,
and it will need to convert the elapsed minutes to hours.
Part 3: Moonlight
Now that we’ve computed the hours of sunlight, it seems like it
should be simple to compute the hours of moonlight – just swap the
column names "sun-rise"
and "sun-set"
for "moon-rise"
and "moon-set"
.
This works for some of the rows in our table:
››› good-night = test-data.row-n(0) ››› elapsed-mins(good-night["moon-rise"], good-night["moon-set"]) 960
But not for others:
››› bad-night = test-data.row-n(1) ››› elapsed-mins(bad-night["moon-rise"], bad-night["moon-set"]) -870
Why is this? The moon rose at 23:00 (i.e., 11 p.m.) on one day and set at 8:30 a.m. the next.
Let’s extend our code to handle this!
Task: Write a function
fun mins-before-midnight(time :: String) -> Number: ... end
Don’t repeat the code from mins-since-midnight
! Instead,
think how you can use a call to that function in your definition. The body
of this function only needs to be one line!
Now we can improve elapsed-mins
. Let’s leave our original
version (which works for sunlight) and define a new one:
Task: Write a function
fun elapsed-mins-improved(start-time :: String, end-time :: String) -> Number: ... end
When the start time is before the end time, it should work
just like elapsed-mins
.
When the start time is after the end time (that is, it’s the next day), the function should instead take the minutes from the start time until midnight (which you just wrote a function to do) and add them to the minutes from midnight until the end time.
With elapsed-mins-improved
, we’re ready to compute
the hours of moonlight for each day in the table.
Task:
Make a table named celestial-data-sun-moon
that has a new
column called "moonlight"
that contains the
number of hours of moonlight for each day.
Be sure you are starting with celestial-data-sun
from
Part 1! We want to end up with a single table that has columns
for both hours of sunlight and hours of moonlight.
Part 4: Visualization (coach-free)
While we can look at the numbers we added to the table, it’s much nicer to get a graphic overview.
We’ll draw bar charts, but, unfortunately, none of the columns in the table give a good label for the bars. Since each bar is for one day, they should be labeled with the date.
Task:
Make a new table, celestial-data-to-plot
, that has a column
"date"
giving the abbreviated date for each row,
e.g., "9/30"
for September 30.
Task: Display bar charts for the hours of sunlight and moonlight. To do this, call
bar-chart(celestial-data-to-plot, "date", "sunlight")
and
bar-chart(celestial-data-to-plot, "date", "moonlight")
If everything’s worked right, you should see a very clear trend for the hours of sunlight and a very clear repeating pattern for hours of moonlight!
Challenge exercise (coach-free)
The spreadsheet we loaded the table from in Part 1 actually has
two sheets. The one we used, celestial
is a cleaned version
of the original data, which is on the sheet
named tricky
.
In that original data, some of the times are missing. This is because
it’s possible for moon rise, moon culm., or moon set to be on
a different day (e.g., the moon rose the day before or set
the following day). We removed these troublesome rows for you
in celestial
.
Task:
Change your program to load its data from the tricky
sheet.
To make it still work, automatically remove the rows that are missing a
time in any of the columns.
Check blocks (autograder compatibility)
Task:
Copy the following check
block into the
bottom of your program and run it:
check "Tables exist and have the right names": celestial-data.row-n(0) test-data.row-n(0) celestial-data-sun.row-n(0) celestial-data-sun-moon.row-n(0) celestial-data-to-plot.row-n(0) end
Task:
Copy the following check
block into the
bottom of your program and run it:
check "Functions exist and have correct inputs": mins-since-midnight("00:00") elapsed-mins("00:00", "00:01") mins-before-midnight("00:00") elapsed-mins-improved("00:00", "00:01") end
Assignment guidelines
As with Assignment 2, you are expected to follow good Pyret style, including writing docstrings and examples for each function. Review the Testing and Style Guidelines and ask questions if anything’s unclear!
Submitting the assignment
- Download your file (File → Download) and ensure
it’s named
asmt03.arr
. - Upload your assignment on Gradescope.
Note: You can submit as many times as you want before the deadline. Only your latest submission will be graded.