2

I am trying to create an animation showing the availability of health care clinics during a week. The opening hours could for example be Monday-Thursday 07:30-17:00, Friday 08:00-15:00. I don´t see how to define these reoccuring dates in the temporal controller. Since the clinics do close in the afternoon, I can´t just set a starting time/date for Monday and a corresponding ending on Friday.

Is this use case covered? I don´t see any other solution than creating a copy of the clinic for each day and specifying opening hours for each copy.

1 Answer 1

2

Principle: data driven visibility together with Temporal Controller

This is a great question and the solution gave a bit of a headache as the settings of Temporal Controller seem not to allow it. However, looking in another part, its perfectly possible.

The trick is to use data driven visibility of the layer. Using expressions instead of fixed fields, you have almost unlimited possibilities to define complex conditions to define when your layer is visible and when not, using diffent timestamp fields and variables @map_start_time (beginning of the current animation frame) and @map_end_time (end of current frame).

You find a project + layer to download here that demonstrates version 2, where I included a fictive holiday (closed whole day) for Nov. 8th, 2022, but special extended opening hours the next day - the rest are regular opening hours as defined by you: https://drive.switch.ch/index.php/s/GbHH3N4A6DMXyaU

This is how the result looks (version 2 from the linked project): the symbol appears only when the shop is open. The label shows date and time and tells about reason for opening/closing:

enter image description here

Implementation

  1. In Layer Properties > Temporal tab, you can just define one single start and stop time. However, you can set the configuration to Redraw Layer Only: like this, the layer redrawn every time the temporal range changes.

    enter image description here

  2. Now you can define a data driven visibility of the layer. In Layer Styling, select the Symbol layer and define a data driven override for Enable symbol layer > Edit (see next screenshot below).

    For the exact expression to introduce, there are different options available - see next sections for the variants.

    Screenshot: the current animation frame ranges from 2022-11-07 (Monday) 13:30 to the same day at 14:30 (interval of 1 hour). As the attribute table shows, this is inside the opening hours on mondays (open 7:30 to 17:00) and thus, the pharmacy-symbol shows up: enter image description here

Version 1: based on timestamp attribute fields

Insert this expression:

```
"monday_open" < @map_start_time and "monday_close" > @map_end_time 
OR
"tuesday_open" < @map_start_time and "tuesday_close" > @map_end_time
```

Explanation: monday_open is a datetime attribute field that contains opening hours on mondays, monday_close closing time on mondays and so on. So the expression checks if the current animation frame (variables @map_start_time and @map_end_time) lies within one of the opening hours (attribute values "monday_open"/"monday_close" etc.): opening hour monday or opening hour tuesday [or opening hour wednesday and so on...]. If so, the symbol layer shows on the map canvas, otherwise not.

Version 2: based on expressions only

You can even have a layer without any timestamp attributes at all and define visibility based on expressions only. Then you have to include all opening and closing times inside of the expression.

I created a complex expression with a semi-regular pattern (MO to THU 8am to 5 pm, FRI 8 am to 3 pm) and some individual exceptions for certain dates (based on the realistic assumption that there are exceptions on certain dates due to extended or reduced special opening hours or on holidays when the shop remains closed the whole day). You can add additional exceptions as you want. See the comments in the expression below for further explanations. You can download to project to run the animation from here https://drive.switch.ch/index.php/s/GbHH3N4A6DMXyaU

enter image description here

Use this expression:

case

/*
Condition: exclude from opening hours animation time frames that end at midnight (= 0:00 h of the next day). Without this condition, time frame from 23:00 h (11 p.m.) of day 1 to midnight (0:00 a.m. of next day) would be shown as open because we use the expression `make_time (17,00,0) >= to_time(@map_end_time)` as condition and midnight is later (larger) then defined closing time of 17:00 (5 p.m.), but is not shown as 24:00 (12 p.m.) of the current day, but as 0:00 a.m. of the next day.
*/

when to_time(@map_end_time) = make_time(0,0,0) 
then 0

/*
In the first section, define exceptions from the rules you define below (regular opening hours per weekday). If at certain individual dates, there are special opening hours like e.g. extending opening hours until 19:00 h at Nov. 9th, 2022 or closing on public holidays like Dec. 25th, 2022 (X-mas), then define it before the actual rule. 
As help for case function states: "CASE (...) return a result for the first condition met. The conditions are evaluated sequentially, and if a condition is true, the evaluation stops, and the corresponding result is returned."
So first check if the current date is a special case and if so, go to the general rules.
*/

when to_date (@map_start_time) =  make_date (2022,11,8) -- individual day with no opening hours (e.g. holidays)
then 0  -- closed (no opening hours on this day)

when to_date (@map_start_time) =  make_date (2022,11,9) -- individual day with special (reduced/expanded) opening hours
then make_time(7,30,0) <= to_time(@map_start_time) and make_time (19,00,0) >= to_time(@map_end_time) -- define special opening hours

/*
General rules for opening hours. Use the following section to define regular opening hours for each weekday. The function day_of_week() returns 0 for sunday, 1 for monday etc. Here, weekdays from monday to friday are defined. With the else 0 line at the end you define that on all other days (sturday and sunday), there are no opening hours.
*/

when day_of_week (@map_start_time) = 1  -- monday
then make_time(7,30,0) <= to_time(@map_start_time) and make_time (17,00,0) >= to_time(@map_end_time)  -- define monday opening hours

when day_of_week (@map_start_time) = 2  -- tuesday
then make_time(7,30,0) <= to_time(@map_start_time) and make_time (17,00,0) >= to_time(@map_end_time)  -- define tuesday opening hours

when day_of_week (@map_start_time) = 3  -- wednesday
then make_time(7,30,0) <= to_time(@map_start_time) and make_time (17,00,0) >= to_time(@map_end_time)  -- define wednesday opening hours

when day_of_week (@map_start_time) = 4  -- thursday
then make_time(7,30,0) <= to_time(@map_start_time) and make_time (17,00,0) >= to_time(@map_end_time)  -- define thursday opening hours

when day_of_week (@map_start_time) = 5  -- friday
then make_time(8,0,0) <= to_time(@map_start_time) and make_time (15,00,0) >= to_time(@map_end_time)  -- define friday opening hours

else 0

end

Version 3

Still another option would be to store the opening / close times in a separate, data only table (see https://gis.stackexchange.com/a/444497/88814) and use expressions to access the values from there. This is especially helpful if you have not only one, but a lot of features (shops) with different opening/closing times.

In the data table, create a new feature for each shop (with a shop id linking to the feature in the geometry layer) and add the (regular and exceptional) opening hours as attribute values. Than set expressions as in the solutions above.

1
  • Thank you, this seems to be what I was looking for. I´ll need some time to test it with my own data.
    – johnrobot
    Nov 17, 2022 at 14:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.