Skip to content

Commit

Permalink
Actually check whether holidays may impact a given query (#136)
Browse files Browse the repository at this point in the history
* return holidays ISODOW

* little formatting changes

* check for relevance of holidays in output stage

* only return holidays within date range

* check for holiday relevance bfore displaing those options

* drop the math symbols

they only really made sense in my head anyway; probably just confusing to the user

* update documentation
  • Loading branch information
Nate-Wessel authored Jul 16, 2024
1 parent 3f69745 commit 46a4215
Show file tree
Hide file tree
Showing 8 changed files with 47 additions and 22 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ The app can return results in either CSV or JSON format. The fields in either ca
| `timeRange` | Text description of the time-of-day range included in the query. |
| `dateRange` | Text description of the range of dates included in the query. |
| `daysOfWeek` | Text description of the days of week included in the query. |
| `holidaysIncluded` | Boolean, indicating if statutory holidays where (True) or were not (False) included in the query. |
| `holidaysIncluded` | Boolean, indicating if statutory holidays where (True) or were not (False) included in the query. If there are no holidays within the date range, will return `NA`. |
| `hoursInRange` | The total number of hours that are theoretically within the scope of the query's various parameters. This does not imply that data is/was available at all times. It's possible to construct requests with zero hours in range such as e.g `2023-01-01` to `2023-01-02`, Mondays only (There's only one Sunday in that range). Impossible combinations are included in the output for clarity and completeness but are not actually executed against the API and should return an error. |
| `mean_travel_time_minutes` | The mean travel time in minutes is given as a floating point number rounded to three decimal places. Where insufficient data was available to complete the request, the value will be null. |
| `mean_travel_time_seconds` | Same as above, but measured in seconds. |
Expand Down
21 changes: 17 additions & 4 deletions backend/app/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,11 +131,24 @@ def get_date_bounds():
def get_holidays():
"Return dates of all known holidays in ascending order"
connection = getConnection()
query = f"""
SELECT
dt::text,
EXTRACT(ISODOW FROM dt)::int,
holiday
FROM ref.holiday
WHERE dt >= %(minDate)s AND dt < %(maxDate)s
ORDER BY dt;
"""
with connection:
with connection.cursor() as cursor:
cursor.execute(
"SELECT dt::text, holiday FROM ref.holiday ORDER BY dt;"
)
dates = [{'date': dt, 'name': nm} for (dt, nm) in cursor.fetchall()]
cursor.execute(query, get_date_bounds())
dates = [
{
'date': dt,
'dow': dow,
'name': nm
} for (dt, dow, nm) in cursor.fetchall()
]
connection.close()
return dates
12 changes: 5 additions & 7 deletions frontend/src/Sidebar/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,10 @@ export default function SidebarContent(){
>
<Welcome/>
<CorridorsContainer/>
<div className='big-math-symbol'>&#xd7;</div>
<TimeRangesContainer/>
<div className='big-math-symbol'>&#xd7;</div>
<DateRangesContainer/>
<div className='big-math-symbol'>&#xd7;</div>
<DaysContainer/>
<div className='big-math-symbol'>&#xd7;</div>
<HolidaysContainer/>
<div className='big-math-symbol'>=</div>
<ResultsContainer/>
</div>
)
Expand Down Expand Up @@ -101,6 +96,9 @@ function DaysContainer(){

function HolidaysContainer(){
const { logActivity, data } = useContext(DataContext)
if( ! data.travelTimeQueries.some(ttq=>ttq.holidaysAreRelevant) ){
return
}
let options = data.holidayOptions
let included, excluded
if(options.length == 1){
Expand All @@ -115,7 +113,7 @@ function HolidaysContainer(){
data.excludeHolidays()
}else if(option=='yeah'){
data.includeHolidays()
}else{
}else{ // yeah no, eh?
data.includeAndExcludeHolidays()
}
logActivity(`include holidays? ${option}`)
Expand Down Expand Up @@ -155,7 +153,7 @@ function Welcome(){
<h2>Toronto Historic Travel Times</h2>
<p>
This application allows you to query averaged motor vehicle travel
times across the city, as far back as 2012. Data come from a small
times across the city, as far back as 2017. Data come from a small
sample of probe vehicles that report their location data
to <a href="https://www.here.com/">Here</a>. For more information on
this application and our methodology
Expand Down
6 changes: 1 addition & 5 deletions frontend/src/Sidebar/sidebar.css
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,13 @@
border: 1px solid lightgrey;
border-radius: 5px;
padding: 5px;
margin-bottom: 8px;
}

.user-created-factor-container > * {
margin: 5px 0;
}

.big-math-symbol {
text-align: center;
font-size: 2em;
}

.factor {
border-radius: 2px;
padding: 5px;
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/dateRange.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ export class DateRange extends Factor {
return this.#dataContext.dateRange.maxDate ?? new Date()
}
get minDate(){
// default to today if actual max date not known (yet)
// default to last known value if actual max date not known (yet)
return this.#dataContext.dateRange.minDate ?? new Date('2017-09-01')
}
}
Expand Down
4 changes: 4 additions & 0 deletions frontend/src/days.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ export class Days extends Factor {
get isComplete(){
return this.#days.size > 0
}
get ISODOWs(){
// returns a copy just to be safe
return new Set(this.#days)
}
addDay(number){
if( daylist.map(d=>d.iso).includes(parseInt(number)) ){
this.#days.add(parseInt(number))
Expand Down
4 changes: 1 addition & 3 deletions frontend/src/holidayOption.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,5 @@ export class HolidayOption extends Factor {
this.#includeHolidays = includeHolidays
}
get holidaysIncluded(){ return this.#includeHolidays }
get holidays(){
return this.#dataContext.holidays
}
get holidays(){ return this.#dataContext.holidays }
}
18 changes: 17 additions & 1 deletion frontend/src/travelTimeQuery.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,19 @@ export class TravelTimeQuery {
let numDays = this.dateRange.daysInRange(this.days,this.#holidayOption)
return hoursPerDay * numDays
}
get holidaysAreRelevant(){ // are holidays actually relevant for this query?
const isodows = this.#days.ISODOWs
const minDate = this.#dateRange.startDateFormatted
const maxDate = this.#dateRange.endDateFormatted
const holidays = this.#holidayOption.holidays.filter( holiday => {
return (
isodows.has(holiday.dow)
&& holiday.date >= minDate
&& holiday.date < maxDate
)
} )
return holidays.length > 0
}
resultsRecord(type='json'){
// map used instead of object to preserve insertion order
const record = new Map()
Expand All @@ -60,7 +73,10 @@ export class TravelTimeQuery {
record.set('timeRange',this.timeRange.name)
record.set('dateRange',this.dateRange.name)
record.set('daysOfWeek', this.days.name)
record.set('holidaysIncluded', this.#holidayOption.holidaysIncluded)
record.set(
'holidaysIncluded',
this.holidaysAreRelevant ? this.#holidayOption.holidaysIncluded : 'NA'
)
record.set('hoursInRange', this.hoursInRange)
record.set('mean_travel_time_minutes', this.#results?.travel_time?.minutes)
record.set('mean_travel_time_seconds', this.#results?.travel_time?.seconds)
Expand Down

0 comments on commit 46a4215

Please sign in to comment.