Is it wine o’clock?

[This article was first published on Maëlle, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

Emojis were again quite en vogue this week on Twitter with Romain François doing some awesome stuff for the emo package, in particular this teeny tiny animated clock. It reminded me of my own emoji animated clock that I had done a while ago for representing time-use data. Time for me to present its genesis!

I’m actually not a Quantified Self person, but at my work time-use data was collected for an epidemiology project: information about people activities and locations throughout one day can help unraveling sources of exposure to air pollution. I’ve therefore spent some time thinking about how to represent such data. In particular, my colleague Margaux directed a fantastic video about our project. We introduced some real data from our project in it, including an animated clock that I made with emoji-coding of indoor-outdoor location. I’ll present code and data for producing a similar clock with my own agenda on some Wednesday evenings of last year.

Loading the time-use data

I logged data from my Wednesday in a rather ok format.

<span class="n">library</span><span class="p">(</span><span class="s2">"magrittr"</span><span class="p">)</span><span class="w">
</span><span class="n">date</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="s2">"2016-03-10"</span><span class="w">
</span><span class="n">activities</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">readr</span><span class="o">::</span><span class="n">read_csv2</span><span class="p">(</span><span class="s2">"data/2017-08-12-wineoclock-timeuse.csv"</span><span class="p">,</span><span class="w">
                               </span><span class="n">col_types</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"ccc"</span><span class="p">)</span><span class="w"> </span><span class="o">%>%</span><span class="w">
  </span><span class="n">dplyr</span><span class="o">::</span><span class="n">mutate</span><span class="p">(</span><span class="n">start</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">lubridate</span><span class="o">::</span><span class="n">ymd_hms</span><span class="p">(</span><span class="n">paste0</span><span class="p">(</span><span class="n">date</span><span class="p">,</span><span class="w"> </span><span class="n">start</span><span class="p">,</span><span class="w"> </span><span class="s2">":00"</span><span class="p">)),</span><span class="w">
         </span><span class="n">end</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">lubridate</span><span class="o">::</span><span class="n">ymd_hms</span><span class="p">(</span><span class="n">paste0</span><span class="p">(</span><span class="n">date</span><span class="p">,</span><span class="w"> </span><span class="n">end</span><span class="p">,</span><span class="w"> </span><span class="s2">":00"</span><span class="p">)))</span><span class="w">
</span><span class="n">knitr</span><span class="o">::</span><span class="n">kable</span><span class="p">(</span><span class="n">activities</span><span class="p">)</span><span class="w">
</span>
start end activity
2016-03-10 00:00:00 2016-03-10 06:30:00 sleeping
2016-03-10 06:30:00 2016-03-10 07:00:00 coffee
2016-03-10 07:00:00 2016-03-10 08:00:00 running
2016-03-10 08:00:00 2016-03-10 09:30:00 train
2016-03-10 09:30:00 2016-03-10 17:00:00 computer
2016-03-10 17:00:00 2016-03-10 18:00:00 train
2016-03-10 18:00:00 2016-03-10 20:00:00 school
2016-03-10 20:00:00 2016-03-10 20:30:00 pizza
2016-03-10 20:30:00 2016-03-10 22:00:00 dancer
2016-03-10 22:00:00 2016-03-10 22:30:00 wine_glass
2016-03-10 22:30:00 2016-03-10 23:59:00 sleeping

When I prepared this visualization ggimage didn’t exist so I knew I’d have to use emojis from emojifont to represent my activities, therefore I directly entered the activities as emojis. My Wednesdays at that time were quite varied, I started the day with breakfast (how original), then some time at the gym, followed by a rather short workday due to my taking a Catalan class at the end of the afternoon. The evening was spent enjoying a quick and cheap pizza dinner with my husband before our salsa class and sometimes treating ourselves to a wine glass at the small and rather shabby-looking bar at the end of our street, whose name really was Small bar.

Making the animated clock

I didn’t have to think about how to draw and animated a clock with ggplot2 because somebody already had: I used code from this gist of Drew Conway’s.

<span class="c1"># Generate digitial clock face
</span><span class="n">first_nine</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="s1">'00'</span><span class="p">,</span><span class="w"> </span><span class="s1">'01'</span><span class="p">,</span><span class="w"> </span><span class="s1">'02'</span><span class="p">,</span><span class="w"> </span><span class="s1">'03'</span><span class="p">,</span><span class="w"> </span><span class="s1">'04'</span><span class="p">,</span><span class="w"> </span><span class="s1">'05'</span><span class="p">,</span><span class="w"> </span><span class="s1">'06'</span><span class="p">,</span><span class="w"> </span><span class="s1">'07'</span><span class="p">,</span><span class="w"> </span><span class="s1">'08'</span><span class="p">,</span><span class="w"> </span><span class="s1">'09'</span><span class="p">)</span><span class="w">
</span><span class="n">hours</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="n">first_nine</span><span class="p">,</span><span class="w"> </span><span class="nf">as.character</span><span class="p">(</span><span class="n">seq</span><span class="p">(</span><span class="m">10</span><span class="p">,</span><span class="m">23</span><span class="p">,</span><span class="m">1</span><span class="p">)))</span><span class="w">
</span><span class="n">mins</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="n">first_nine</span><span class="p">,</span><span class="w"> </span><span class="nf">as.character</span><span class="p">(</span><span class="n">seq</span><span class="p">(</span><span class="m">10</span><span class="p">,</span><span class="m">59</span><span class="p">,</span><span class="m">1</span><span class="p">)))</span><span class="w">
</span><span class="n">time_chars_l</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">lapply</span><span class="p">(</span><span class="n">hours</span><span class="p">,</span><span class="w"> </span><span class="k">function</span><span class="p">(</span><span class="n">h</span><span class="p">)</span><span class="w"> </span><span class="n">paste</span><span class="p">(</span><span class="n">h</span><span class="p">,</span><span class="w"> </span><span class="s1">':'</span><span class="p">,</span><span class="w"> </span><span class="n">mins</span><span class="p">,</span><span class="w"> </span><span class="n">sep</span><span class="o">=</span><span class="s1">''</span><span class="p">))</span><span class="w">
</span><span class="n">time_chars</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">do.call</span><span class="p">(</span><span class="n">c</span><span class="p">,</span><span class="w"> </span><span class="n">time_chars_l</span><span class="p">)</span><span class="w">

</span><span class="c1"># Generate analog clock face
</span><span class="n">hour_pos</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">seq</span><span class="p">(</span><span class="m">0</span><span class="p">,</span><span class="w"> </span><span class="m">12</span><span class="p">,</span><span class="w"> </span><span class="m">12</span><span class="o">/</span><span class="p">(</span><span class="m">12</span><span class="o">*</span><span class="m">60</span><span class="p">))[</span><span class="m">1</span><span class="o">:</span><span class="m">720</span><span class="p">]</span><span class="w">
</span><span class="n">min_pos</span><span class="w"> </span><span class="o"><-</span><span class="n">seq</span><span class="p">(</span><span class="m">0</span><span class="p">,</span><span class="m">12</span><span class="p">,</span><span class="w"> </span><span class="m">12</span><span class="o">/</span><span class="m">60</span><span class="p">)[</span><span class="m">1</span><span class="o">:</span><span class="m">60</span><span class="p">]</span><span class="w">
</span><span class="n">hour_pos</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">rep</span><span class="p">(</span><span class="n">hour_pos</span><span class="p">,</span><span class="w"> </span><span class="m">2</span><span class="p">)</span><span class="w">
</span><span class="n">all_times</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">dplyr</span><span class="o">::</span><span class="n">tbl_df</span><span class="p">(</span><span class="n">cbind</span><span class="p">(</span><span class="n">hour_pos</span><span class="p">,</span><span class="w"> </span><span class="n">min_pos</span><span class="p">))</span><span class="w"> </span><span class="o">%>%</span><span class="w">
  </span><span class="n">dplyr</span><span class="o">::</span><span class="n">mutate</span><span class="p">(</span><span class="n">index</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">time_chars</span><span class="p">)</span><span class="w"> </span><span class="o">%>%</span><span class="w">
  </span><span class="n">dplyr</span><span class="o">::</span><span class="n">mutate</span><span class="p">(</span><span class="n">time</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">lubridate</span><span class="o">::</span><span class="n">ymd_hms</span><span class="p">(</span><span class="n">paste0</span><span class="p">(</span><span class="n">date</span><span class="p">,</span><span class="w"> </span><span class="n">index</span><span class="p">,</span><span class="w"> </span><span class="s2">":00"</span><span class="p">)))</span><span class="w"> 
</span>

I then needed to join the all_times table, containing many snapshots of the time, with my time-use table made of intervals (start and end of each activity). Another package born in the meantime, fuzzyjoin, would have allowed me to write more efficient code, and I was so sad when looking at the old code that I re-wrote it.

<span class="n">all_times</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">dplyr</span><span class="o">::</span><span class="n">mutate</span><span class="p">(</span><span class="n">all_times</span><span class="p">,</span><span class="w"> </span><span class="n">start</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">time</span><span class="p">,</span><span class="w"> </span><span class="n">end</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">time</span><span class="p">)</span><span class="w">
</span><span class="n">all_times</span><span class="w">  </span><span class="o"><-</span><span class="w"> </span><span class="n">fuzzyjoin</span><span class="o">::</span><span class="n">interval_left_join</span><span class="p">(</span><span class="n">all_times</span><span class="p">,</span><span class="w"> </span><span class="n">activities</span><span class="p">)</span><span class="w">
</span><span class="n">knitr</span><span class="o">::</span><span class="n">kable</span><span class="p">(</span><span class="n">all_times</span><span class="p">[</span><span class="m">1</span><span class="o">:</span><span class="m">10</span><span class="p">,])</span><span class="w">
</span>
hour_pos min_pos index time start.x end.x start.y end.y activity
0.0000000 0.0 00:00 2016-03-10 00:00:00 2016-03-10 00:00:00 2016-03-10 00:00:00 2016-03-10 2016-03-10 06:30:00 sleeping
0.0166667 0.2 00:01 2016-03-10 00:01:00 2016-03-10 00:01:00 2016-03-10 00:01:00 2016-03-10 2016-03-10 06:30:00 sleeping
0.0333333 0.4 00:02 2016-03-10 00:02:00 2016-03-10 00:02:00 2016-03-10 00:02:00 2016-03-10 2016-03-10 06:30:00 sleeping
0.0500000 0.6 00:03 2016-03-10 00:03:00 2016-03-10 00:03:00 2016-03-10 00:03:00 2016-03-10 2016-03-10 06:30:00 sleeping
0.0666667 0.8 00:04 2016-03-10 00:04:00 2016-03-10 00:04:00 2016-03-10 00:04:00 2016-03-10 2016-03-10 06:30:00 sleeping
0.0833333 1.0 00:05 2016-03-10 00:05:00 2016-03-10 00:05:00 2016-03-10 00:05:00 2016-03-10 2016-03-10 06:30:00 sleeping
0.1000000 1.2 00:06 2016-03-10 00:06:00 2016-03-10 00:06:00 2016-03-10 00:06:00 2016-03-10 2016-03-10 06:30:00 sleeping
0.1166667 1.4 00:07 2016-03-10 00:07:00 2016-03-10 00:07:00 2016-03-10 00:07:00 2016-03-10 2016-03-10 06:30:00 sleeping
0.1333333 1.6 00:08 2016-03-10 00:08:00 2016-03-10 00:08:00 2016-03-10 00:08:00 2016-03-10 2016-03-10 06:30:00 sleeping
0.1500000 1.8 00:09 2016-03-10 00:09:00 2016-03-10 00:09:00 2016-03-10 00:09:00 2016-03-10 2016-03-10 06:30:00 sleeping

Then I could continue using the code from the gist, this step generating stuff for the two clock hands.

<span class="n">all_times</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">all_times</span><span class="w"> </span><span class="o">%>%</span><span class="w"> 
  </span><span class="n">dplyr</span><span class="o">::</span><span class="n">select</span><span class="p">(</span><span class="o">-</span><span class="w"> </span><span class="n">start.x</span><span class="p">,</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">end.x</span><span class="p">,</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">start.y</span><span class="p">,</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">end.y</span><span class="p">)</span><span class="w"> </span><span class="o">%>%</span><span class="w">
  </span><span class="n">tidyr</span><span class="o">::</span><span class="n">gather</span><span class="p">(</span><span class="n">name</span><span class="p">,</span><span class="w"> </span><span class="n">time.info</span><span class="p">,</span><span class="w"> </span><span class="m">1</span><span class="o">:</span><span class="m">2</span><span class="p">)</span><span class="w"> </span><span class="o">%>%</span><span class="w">
  </span><span class="n">dplyr</span><span class="o">::</span><span class="n">arrange</span><span class="p">(</span><span class="n">index</span><span class="p">)</span><span class="w"> </span><span class="o">%>%</span><span class="w">
  </span><span class="n">dplyr</span><span class="o">::</span><span class="n">mutate</span><span class="p">(</span><span class="n">hands</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ifelse</span><span class="p">(</span><span class="n">name</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s2">"hour_pos"</span><span class="p">,</span><span class="w"> </span><span class="m">0.5</span><span class="p">,</span><span class="w"> </span><span class="m">1</span><span class="p">))</span><span class="w">
</span>

I decided to only plot a subset of my exciting day.

<span class="n">all_times</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">dplyr</span><span class="o">::</span><span class="n">filter</span><span class="p">(</span><span class="n">all_times</span><span class="p">,</span><span class="w"> 
                           </span><span class="n">time</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="n">lubridate</span><span class="o">::</span><span class="n">ymd_hms</span><span class="p">(</span><span class="s2">"2016-03-10 15:00:00"</span><span class="p">),</span><span class="w">
                           </span><span class="n">time</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">lubridate</span><span class="o">::</span><span class="n">ymd_hms</span><span class="p">(</span><span class="s2">"2016-03-10 23:00:00"</span><span class="p">)</span><span class="w"> </span><span class="p">)</span><span class="w">
</span>

Last but not least, I plotted the clock. Nowadays I’d probably stick to magick for animating the plot but gganimate is awesome too anyway.

<span class="n">library</span><span class="p">(</span><span class="s2">"ggplot2"</span><span class="p">)</span><span class="w">
</span><span class="n">emojifont</span><span class="o">::</span><span class="n">load.emojifont</span><span class="p">(</span><span class="s1">'OpenSansEmoji.ttf'</span><span class="p">)</span><span class="w">
</span><span class="n">clock</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">ggplot</span><span class="p">(</span><span class="n">all_times</span><span class="p">,</span><span class="w"> </span><span class="n">aes</span><span class="p">(</span><span class="n">xmin</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">time.info</span><span class="p">,</span><span class="w">
                               </span><span class="n">xmax</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">time.info</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="m">0.03</span><span class="p">,</span><span class="w"> 
                               </span><span class="n">ymin</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">0</span><span class="p">,</span><span class="w">
                               </span><span class="n">ymax</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">hands</span><span class="p">,</span><span class="w">
                              </span><span class="n">frame</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">index</span><span class="p">))</span><span class="w">
</span><span class="n">clock</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">clock</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">geom_rect</span><span class="p">()</span><span class="w">
</span><span class="n">clock</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">clock</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">theme_bw</span><span class="p">()</span><span class="w">
</span><span class="n">clock</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">clock</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">coord_polar</span><span class="p">()</span><span class="w">
</span><span class="n">clock</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">clock</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">scale_x_continuous</span><span class="p">(</span><span class="n">limits</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span><span class="m">12</span><span class="p">),</span><span class="w"> 
                                    </span><span class="n">breaks</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">0</span><span class="o">:</span><span class="m">11</span><span class="p">,</span><span class="w">
                     </span><span class="n">labels</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="m">12</span><span class="p">,</span><span class="w"> </span><span class="m">1</span><span class="o">:</span><span class="m">11</span><span class="p">))</span><span class="w">
</span><span class="n">clock</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">clock</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">scale_y_continuous</span><span class="p">(</span><span class="n">limits</span><span class="o">=</span><span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span><span class="m">1.1</span><span class="p">))</span><span class="w"> 
</span><span class="n">clock</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">clock</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">coord_polar</span><span class="p">()</span><span class="w">
</span><span class="n">clock</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">clock</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">geom_text</span><span class="p">(</span><span class="n">aes</span><span class="p">(</span><span class="n">x</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">0</span><span class="p">,</span><span class="w">
                               </span><span class="n">y</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">0</span><span class="p">,</span><span class="w">
                               </span><span class="n">label</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">emojifont</span><span class="o">::</span><span class="n">emoji</span><span class="p">(</span><span class="n">activity</span><span class="p">)),</span><span class="w">
                          </span><span class="n">family</span><span class="o">=</span><span class="s2">"OpenSansEmoji"</span><span class="p">,</span><span class="w"> 
                          </span><span class="n">size</span><span class="o">=</span><span class="m">20</span><span class="p">)</span><span class="w">
</span><span class="n">clock</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">clock</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">theme</span><span class="p">(</span><span class="n">legend.position</span><span class="o">=</span><span class="s2">"none"</span><span class="p">,</span><span class="w">
                      </span><span class="n">axis.text.y</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">element_blank</span><span class="p">(),</span><span class="w">
                      </span><span class="n">axis.ticks.y</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">element_blank</span><span class="p">(),</span><span class="w">
                      </span><span class="n">axis.title.y</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">element_blank</span><span class="p">(),</span><span class="w">
                      </span><span class="n">axis.title.x</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">element_blank</span><span class="p">(),</span><span class="w">
                      </span><span class="n">panel.background</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">element_blank</span><span class="p">(),</span><span class="w">
                      </span><span class="n">panel.border</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">element_blank</span><span class="p">(),</span><span class="w">
                      </span><span class="n">panel.grid.major</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">element_blank</span><span class="p">(),</span><span class="w">
                      </span><span class="n">panel.grid.minor</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">element_blank</span><span class="p">(),</span><span class="w">
                      </span><span class="n">plot.background</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">element_blank</span><span class="p">())</span><span class="w">

</span><span class="n">animation</span><span class="o">::</span><span class="n">ani.options</span><span class="p">(</span><span class="n">interval</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">0.025</span><span class="p">)</span><span class="w">
</span><span class="n">gganimate</span><span class="o">::</span><span class="n">gganimate</span><span class="p">(</span><span class="n">clock</span><span class="p">,</span><span class="w"> </span><span class="s2">"clock.gif"</span><span class="p">)</span><span class="w">
</span>

I ended up with a very useful visualization as you can see… at least, I have no trouble finding out when wine o’clock is!

To leave a comment for the author, please follow the link and comment on their blog: Maëlle.

R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

Never miss an update!
Subscribe to R-bloggers to receive
e-mails with the latest R posts.
(You will not see this message again.)

Click here to close (This popup will not appear again)