---
title: "vistime - Pretty Timelines"
author: "Sandro Raabe"
date: "`r Sys.Date()`"
output: 
  rmarkdown::html_vignette:
    toc: true
vignette: >
  %\VignetteIndexEntry{vistime - Pretty Timelines}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r setup, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
library(vistime)
library(highcharter)
hc_vistime <- function(...) hc_size(vistime::hc_vistime(...), width=700, height=150)
```

[![Buy Me A Coffee](https://i.imgur.com/xI5UtRm.png)](https://www.buymeacoffee.com/shosaco)

A library for creating time-based charts, like Gantt or timelines. Possible outputs include `ggplot`s, `plotly` graphs, `Highchart`s or `data.frame`s. Results can be used in the RStudio viewer pane, in R Markdown documents or in Shiny apps. In the interactive outputs created by `Plotly.js` and `Highcharts.js` you can interact with the plot using mouse hover or zoom. Timelines and their components can afterwards be manipulated using `ggplot::theme()`, `plotly_build` or `hc_*`functions (for `gg-vistime`, `vistime` or `hc_vistime`, respectively). When choosing the `data.frame` output, you can use your own plotting engine for visualizing the graph.

If you find vistime useful, please consider supporting its development: <a href="https://www.buymeacoffee.com/shosaco" target="_blank"><img src="https://i.imgur.com/kN1GxnC.png" alt="Buy Me A Coffee"></a>

**Feedback welcome:** sa.ra.online@posteo.de  


## 1. Main functionality

This package `vistime` provides three main functions: 

### 1) `vistime()` to produce interactive `Plotly` charts:

```{r vistime_basic_ex, warning=FALSE, fig.height=1, out.width="100%"}
library(vistime)
timeline_data <- data.frame(event = c("Event 1", "Event 2"), start = c("2020-06-06", "2020-10-01"), end = c("2020-10-01", "2020-12-31"), group = "My Events")
vistime(timeline_data)
```

### 2) `hc_vistime()` to produce interactive `Highcharts` charts:

```{r hc_vistime_basic_ex, warning=FALSE}
timeline_data <- data.frame(event = c("Event 1", "Event 2"), start = c("2020-06-06", "2020-10-01"), end = c("2020-10-01", "2020-12-31"), group = "My Events")
hc_vistime(timeline_data)
```

### 3) `gg_vistime()` to produce static `ggplot` output:

```{r gg_vistime_basic_ex, warning=FALSE, fig.width=4, fig.height=1.5}
timeline_data <- data.frame(event = c("Event 1", "Event 2"), start = c("2020-06-06", "2020-10-01"), end = c("2020-10-01", "2020-12-31"), group = "My Events")
gg_vistime(timeline_data)
```


### 3)  `vistime_data()`, for pure `data.frame` output that you can use with the plotting engine of your choice: 

```{r vistime_data_basic_ex, eval=F}
timeline_data <- data.frame(event = c("Event 1", "Event 2"), start = c("2020-06-06", "2020-10-01"), end = c("2020-10-01", "2020-12-31"), group = "My Events")
vistime_data(timeline_data)

#>     event      start        end     group                                      tooltip      col subplot   y
#> 1 Event 1 2020-06-06 2020-10-01 My Events  from <b>2020-06-06</b> to <b>2020-10-01</b>  #8DD3C7       1   1
#> 2 Event 2 2020-10-01 2020-12-31 My Events  from <b>2020-10-01</b> to <b>2020-12-31</b>  #FFFFB3       1   1
```

You want to use this for the intelligent y-axis assignment depending on overlapping of events (this can be disabled with `optimize_y = FALSE`).


## 2. Installation

To install the package from CRAN (v1.0.0), type the following in your R console:

```{r eval=FALSE}
install.packages("vistime")
```

## 3. Usage and default arguments

The simplest way to create a timeline is by providing a data frame with `event` and `start` columns. If your columns are named otherwise, you need to tell the function. You can also tweak the y positions, linewidth, title, label visibility and number of lines in the background.

```{r eval = FALSE}
vistime(data, col.event = "event", col.start = "start", col.end = "end", col.group = "group", col.color = "color", 
              col.fontcolor = "fontcolor", col.tooltip = "tooltip", optimize_y = TRUE, linewidth = NULL, 
              title = NULL, show_labels = TRUE, background_lines = NULL)

hc_vistime(data, col.event = "event", col.start = "start", col.end = "end", col.group = "group", col.color = "color", 
           optimize_y = TRUE, title = NULL, show_labels = TRUE)
           
gg_vistime(data, col.event = "event", col.start = "start", col.end = "end", col.group = "group", col.color = "color", 
           col.fontcolor = "fontcolor", optimize_y = TRUE, linewidth = NULL, 
           title = NULL, show_labels = TRUE, background_lines = NULL)

vistime_data(data, col.event = "event", col.start = "start", col.end = "end", col.group = "group", col.color = "color", 
             col.fontcolor = "fontcolor", col.tooltip = "tooltip", optimize_y = TRUE)
```



## 4. Arguments

parameter | optional? | data type | explanation 
--------- |----------- | -------- | ----------- 
data | mandatory | data.frame | data.frame that contains the data to be visualized
col.event | optional | character | the column name in data that contains event names. Default: *event*
col.start | optional | character | the column name in data that contains start dates. Default: *start*
col.end | optional | character | the column name in data that contains end dates. Default: *end*
col.group | optional | character | the column name in data to be used for grouping. Default: *group*
col.color | optional | character | the column name in data that contains colors for events. Default: *color*, if not present, colors are chosen via RColorBrewer.
col.fontcolor | optional | character | the column name in data that contains the font color for event labels. Default: *fontcolor*, if not present, color will be black.
col.tooltip | optional | character | the column name in data that contains the mouseover tooltips for the events. Default: *tooltip*, if not present, then tooltips are build from event name and date. [Basic HTML](https://help.plot.ly/adding-HTML-and-links-to-charts/#step-2-the-essentials) is allowed.
optimize_y | optional | logical | distribute events on y-axis by smart heuristic (default) or use order of input data.
linewidth | optional | numeric | override the calculated linewidth for events. Default: heuristic value.
title | optional | character | the title to be shown on top of the timeline. Default: empty.
show_labels | optional | logical | choose whether or not event labels shall be visible. Default: `TRUE`.
background_lines | optional | integer | the number of vertical lines to draw in the background to demonstrate structure. Default: 10.


## 5. Value

* `vistime` returns an object of class `plotly` and `htmlwidget`
* `hc_vistime` returns an object of class `highchart` and `htmlwidget`
* `gg_vistime` returns an object of class `gg` and `ggplot`
* `vistime_data` returns an object of class `data.frame`


## 6. Examples  

### Ex. 1: Presidents
```{r presidents example, fig.height=3, out.width="100%"}
pres <- data.frame(Position = rep(c("President", "Vice"), each = 3),
                   Name = c("Washington", rep(c("Adams", "Jefferson"), 2), "Burr"),
                   start = c("1789-03-29", "1797-02-03", "1801-02-03"),
                   end = c("1797-02-03", "1801-02-03", "1809-02-03"),
                   color = c('#cbb69d', '#603913', '#c69c6e'),
                   fontcolor = c("black", "white", "black"))
                  
vistime(pres, col.event = "Position", col.group = "Name", title = "Presidents of the USA")      # the Plotly version
# hc_vistime(pres, col.event = "Position", col.group = "Name", title = "Presidents of the USA") # Alternative for Highcharts
# gg_vistime(pres, col.event = "Position", col.group = "Name", title = "Presidents of the USA") # Alternative for ggplot2
```


### Ex. 2: Project Planning
```{r project planning example, fig.height=5, out.width="100%"}
data <- read.csv(text="event,group,start,end,color
                       Phase 1,Project,2016-12-22,2016-12-23,#c8e6c9
                       Phase 2,Project,2016-12-23,2016-12-29,#a5d6a7
                       Phase 3,Project,2016-12-29,2017-01-06,#fb8c00
                       Phase 4,Project,2017-01-06,2017-02-02,#DD4B39
                       Room 334,Team 1,2016-12-22,2016-12-28,#DEEBF7
                       Room 335,Team 1,2016-12-28,2017-01-05,#C6DBEF
                       Room 335,Team 1,2017-01-05,2017-01-23,#9ECAE1
                       Group 1,Team 2,2016-12-22,2016-12-28,#E5F5E0
                       Group 2,Team 2,2016-12-28,2017-01-23,#C7E9C0
                       3-200,category 1,2016-12-25,2016-12-25,#1565c0
                       3-330,category 1,2016-12-25,2016-12-25,#1565c0
                       3-223,category 1,2016-12-28,2016-12-28,#1565c0
                       3-225,category 1,2016-12-28,2016-12-28,#1565c0
                       3-226,category 1,2016-12-28,2016-12-28,#1565c0
                       3-226,category 1,2017-01-19,2017-01-19,#1565c0
                       3-330,category 1,2017-01-19,2017-01-19,#1565c0
                       1-217.0,category 2,2016-12-27,2016-12-27,#90caf9
                       4-399.7,moon rising,2017-01-13,2017-01-13,#f44336
                       8-831.0,sundowner drink,2017-01-17,2017-01-17,#8d6e63
                       9-984.1,birthday party,2016-12-22,2016-12-22,#90a4ae
                       F01.9,Meetings,2016-12-26,2016-12-26,#e8a735
                       Z71,Meetings,2017-01-12,2017-01-12,#e8a735
                       B95.7,Meetings,2017-01-15,2017-01-15,#e8a735
                       T82.7,Meetings,2017-01-15,2017-01-15,#e8a735")
                           
vistime(data)		# the Plotly version
# hc_vistime(data)  # Alternative for Highcharts
# gg_vistime(data)  # Alternative for ggplot2
```


### Ex. 3: Gantt Charts

The argument `optimize_y` can be used to change the look of the timeline. `TRUE` (the default) will find a nice heuristic to save `y`-space, distributing the events:

```{r gantt_true, fig.height=1.8, out.width="100%"}
data <- read.csv(text="event,start,end
                       Phase 1,2020-12-15,2020-12-24
                       Phase 2,2020-12-23,2020-12-29
                       Phase 3,2020-12-28,2021-01-06
                       Phase 4,2021-01-06,2021-02-02")
        
vistime(data, optimize_y = TRUE, linewidth = 25)
```



`FALSE` will plot events as-is, not saving any space:

```{r gantt_false, fig.height=2.5, out.width="100%"}
vistime(data, optimize_y = FALSE, linewidth = 25)
```



## 7. Export of vistime as PDF or PNG

Once created, you can use `plotly::export()` for saving your vistime chart (the plotly version) as PDF, PNG or JPEG:

```{r eval=FALSE}
# webshot::install_phantomjs()
chart <- vistime(pres, col.event = "Position")
plotly::export(chart, file = "presidents.pdf")
```

Note that export requires the `webshot` package and additional arguments like width or height can be used (`?webshot` for the details). You can also download the plot as PNG by using the toolbar on the upper right side of the generated plot.

## 8. Usage in Shiny apps

- `vistime()` objects can be integrated into [Shiny](https://shiny.rstudio.com/) via `plotlyOutput()` and `renderPlotly()`
- `hc_vistime()` objects can be integrated into Shiny via `highchartOutput()` and `renderHighchart()`
- `gg_vistime()` objects can be integrated into Shiny via `plotOutput()` and `renderPlot()`


```{r eval=FALSE}
library(shiny)
library(plotly)
library(vistime)

pres <- data.frame(Position = rep(c("President", "Vice"), each = 3),
                   Name = c("Washington", rep(c("Adams", "Jefferson"), 2), "Burr"),
                   start = c("1789-03-29", "1797-02-03", "1801-02-03"),
                   end = c("1797-02-03", "1801-02-03", "1809-02-03"),
                   color = c('#cbb69d', '#603913', '#c69c6e'),
                   fontcolor = c("black", "white", "black"))

shinyApp(
  ui = plotlyOutput("myVistime"),
  server = function(input, output) {
    output$myVistime <- renderPlotly({
      vistime(pres, col.event = "Position", col.group = "Name")
    })
  }
)
```

## 8. Customization

### Using `ggplot2::theme()` for `gg_vistime` charts

Since every `gg_vistime` output is a `ggplot` object, you can customize and override literally everything:

```{r gg_customization, fig.height=2, message=FALSE}
library(vistime)
data <- read.csv(text="event,start,end
                       Phase 1,2020-12-15,2020-12-24
                       Phase 2,2020-12-23,2020-12-29
                       Phase 3,2020-12-28,2021-01-06
                       Phase 4,2021-01-06,2021-02-02")
        
p <- gg_vistime(data, optimize_y = T, col.group = "event", title = "ggplot customization example")

library(ggplot2)
p + ggplot2::theme(
      plot.title = element_text(hjust = 0, size=10),
      axis.text.x = element_text(size = 10, color = "violet"),
      axis.text.y = element_text(size = 10, color = "red", angle = 30),
      panel.border = element_rect(linetype = "dashed", fill=NA),
      panel.background = element_rect(fill = 'green')) +
    coord_cartesian(ylim = c(0.7, 3.5))

```


### Using `plotly::layout()` for `vistime` charts

```{r plotly_customization, fig.height=2.5, out.width="100%", message=FALSE}
library(plotly)
p2 <- vistime(data, optimize_y = T, col.group = "event", title = "Plotly customization example")
p2 %>% layout(xaxis=list(fixedrange=TRUE, tickfont=list(size=30, color="violet")), 
              yaxis=list(fixedrange=TRUE, tickfont=list(size=30, color="red"), tickangle=30,
                         mirror = FALSE, range = c(0.7, 3.5), showgrid = T),
              plot_bgcolor = "lightgreen") 
```

See `?plotly::layout` and the official [Plotly API reference](https://plotly.com/r/reference/#Layout_and_layout_style_objects) for details. 

### Using `highcharter::hc_*()` for `hc_vistime` charts

```{r hc_customization, message=FALSE}
library(highcharter)
p3 <- hc_vistime(data, optimize_y = T, col.group = "event", title = "Highcharts customization example")
p3 %>% hc_title(style = list(fontSize=30)) %>% 
       hc_yAxis(labels = list(style = list(fontSize=30, color="violet"))) %>% 
       hc_xAxis(labels = list(style = list(fontSize=30, color="red"), rotation=30)) %>% 
       hc_chart(backgroundColor = "lightgreen")%>% 
  hc_size(width=700, height=300)
```

See `?hc_xAxis`, `?hc_chart` and the official [Highcharts API reference](https://api.highcharts.com/highcharts) for details. 

### Using `plotly::plotly_build()` for `vistime` charts

The function `plotly_build()` from package `plotly` turns your plot into a list. You can then use the function `str` to explore the structure of your plot. You can even manipulate all the elements there.

The key is to first create a **simple Plotly example** yourself, turning it into a list (using `plotly_build()`) and **exploring the resulting list** regarding the naming of the relevant attributes. Then manipulate or create them in your vistime example accordingly. Below are some examples of common solutions.

#### Changing x-axis tick font size
The following example creates the presidents example and manipulates the font size of the x axis ticks:

```{r plotly_build1, fig.height=3, out.width="100%"}
pres <- data.frame(Position = rep(c("President", "Vice"), each = 3),
                   Name = c("Washington", rep(c("Adams", "Jefferson"), 2), "Burr"),
                   start = c("1789-03-29", "1797-02-03", "1801-02-03"),
                   end = c("1797-02-03", "1801-02-03", "1809-02-03"),
                   color = c('#cbb69d', '#603913', '#c69c6e'),
                   fontcolor = c("black", "white", "black"))
 
p <- vistime(pres, col.event = "Position", col.group = "Name", title = "Presidents of the USA")

# step 1: transform into a list
library(plotly)
pp <- plotly_build(p)

# step 2: change the font size
pp$x$layout$xaxis$tickfont <- list(size = 28)

pp
```

#### Changing y-axis tick font size
We need to change the font size of the y-axis:

```{r plotly_build2, fig.height=3, out.width="100%"}
pp$x$layout[["yaxis"]]$tickfont <- list(size = 28)
pp
```


#### Changing events font size
The following example creates the presidents example and manipulates the font size of the events:

```{r plotly_build3, fig.height=3, out.width="100%"}
pres <- data.frame(Position = rep(c("President", "Vice"), each = 3),
                    Name = c("Washington", rep(c("Adams", "Jefferson"), 2), "Burr"),
                    start = c("1789-03-29", "1797-02-03", "1801-02-03"),
                    end = c("1797-02-03", "1801-02-03", "1809-02-03"),
                    color = c('#cbb69d', '#603913', '#c69c6e'),
                    fontcolor = c("black", "white", "black"))
 
p <- vistime(pres, col.event = "Position", col.group = "Name", title = "Presidents of the USA", linewidth=30)

# step 1: transform into a list
library(plotly)
pp <- plotly_build(p)

# step 2: loop over pp$x$data, and change the font size of all text elements to 28
for(i in seq_along(pp$x$data)){
    if(pp$x$data[[i]]$mode == "text") pp$x$data[[i]]$textfont$size <- 28
}

#' # or, using purrr:
#' text_idx <- which(purrr::map_chr(pp$x$data, "mode") == "text")
#' for(i in text_idx) pp$x$data[[i]]$textfont$size <- 28
#' pp

pp
```


#### Changing marker size
The following example a simple example using markers and manipulates the size of the markers:

```{r plotly_build4, fig.height=2, out.width="100%"}
dat <- data.frame(event = 1:4, start = c("2019-01-01", "2019-01-10"))
 
p <- vistime(dat)

# step 1: transform into a list
library(plotly)
pp <- plotly_build(p)

# step 2: loop over pp$x$data, and change the marker size of all text elements to 50px
for(i in seq_along(pp$x$data)){
    if(pp$x$data[[i]]$mode == "markers") pp$x$data[[i]]$marker$size <- 20
}

# or, using purrr:
# marker_idx <- which(purrr::map_chr(pp$x$data, "mode") == "markers")
# for(i in marker_idx) pp$x$data[[i]]$marker$size <- 20
# pp

pp

```

