Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Displaying duration in timeline labels #59

Closed
JesseVent opened this issue Aug 15, 2018 · 12 comments
Closed

Displaying duration in timeline labels #59

JesseVent opened this issue Aug 15, 2018 · 12 comments

Comments

@JesseVent
Copy link

JesseVent commented Aug 15, 2018

I've recently started using the timevis package to visualise average process durations in some shiny dashboards. The issue I am having is due to measuring 'average' duration between steps in the process.

I want the timeline to display the results of duration using a measure of days instead, as the actual dates I end up with are often irrelevant and get questioned on it frequently by the dashboard consumers.

I have two questions:

  • Is there a way I can change the labels rendered in timevis to display a different range (i.e. Days 1:90) or is it restricted purely to dates (2018-01-01:2018-04-01)?

  • Is there a better way or alternative for me to achieve the below using timevis?

I did create a function realign dates to beginning of the year, so I could reformat the date using scales::date_format("%j") which converts the day of the year as decimal number (001–366). I tried feeding the output of this into timevis and got very odd results, see below for examples and an example of the concept in ggplot.

I went through the timevis.js examples and documentation and couldn't find an answer, I'm pretty much stumped as implementing what i'm trying to do using R.

What I expect to be rendered

library(tidyverse)

# Generate timeline with unformatted dates ----------------------------------------------

df_unformatted <- data.frame(stringsAsFactors=FALSE,
  id        = 1:7,
  group     = c("customer", "customer", "customer", "initiate", "staff", "staff", "staff"),
  className = c("customer", "customer", "customer", "initiate", "staff", "staff", "staff"),
  content   = c("Provide documents", "Answer survey", "Prove identity", "Submit application",
                "Verify documents", "Verify survey", "Verify identity"),
  start     = lubridate::dmy(c("16/4/18", "12/1/18", "1/1/18", "3/4/18", "4/8/18", "16/3/18", "30/5/18")),
  end       = lubridate::dmy(c("15/5/18", "30/1/18", "13/1/18", "5/5/18", "19/9/18", "7/4/18", "6/8/18"))
)
timevis::timevis(df_unformatted)

screen shot 2018-08-15 at 10 24 18 pm

What actually renders

# Generate timeline with formatted dates ------------------------------------------------

df_formatted          <- df_unformatted
df_formatted$start    <- scales::date_format("%j")(df_formatted$start)
df_formatted$end      <- scales::date_format("%j")(df_formatted$end)
timevis::timevis(df_formatted)

screen shot 2018-08-15 at 10 25 31 pm

Concept in ggplot2

# Generate concept in ggplot ------------------------------------------------------------

time <- tibble::tibble(
    start   = df_unformatted$start,
    end     = df_unformatted$end,
    group   = df_unformatted$group,
    content = df_unformatted$content
  )
tasks <- time %>%
  mutate(start = ymd(start), end = ymd(end)) %>%
  gather(date.type, task.date, -c(group, content)) %>%
  arrange(date.type, task.date) %>%
  mutate(task = factor(content, levels = rev(unique(content)), ordered = TRUE))

ggplot(tasks, aes(x = content, y = task.date, colour = group)) +
  geom_line(size = 6) +
  guides(colour = guide_legend(title = NULL)) +
  labs(x = NULL, y = "Duration (Days)") +
  coord_flip() +
  scale_y_date(date_breaks = "4 weeks", labels = scales::date_format("%j")) +
  ggthemes::theme_few(base_size = 12, base_family = "")

screen shot 2018-08-15 at 10 26 51 pm

@daattali
Copy link
Owner

Hi @JesseVent , these questions don't seem like "bugs" or issues with the package. They seem like questions about the underlying visualization library. You'll need to see if what you want to do is possible with the visjs timeline library http://visjs.org/docs/timeline/ , as this package is essentially a binding to that library.

@JesseVent
Copy link
Author

Thanks for the quick response, yeah I was more curious if you or any of the community has come across a similar scenario.

I'm not sure why the output is rendering like the below though - or why it doesn't appear to accept values based on vis.js documentation.

Name Type Required Description
end Date or number or string or Moment no The end date of the item. The end date is optional, and can be left null. If end date is provided, the item is displayed as a range. If not, the item is displayed as a box.
start Date or number or string or Moment yes The start date of the item, for example new Date(2010,9,23).

timevis shiny output

# timevis output
id    group className            content                    start                      end
1  1 customer  customer  Provide documents 0105-12-31T14:45:40.000Z 0134-12-31T14:45:40.000Z
2  2 customer  customer      Answer survey 2001-11-30T13:30:00.000Z                     NULL
3  3 customer  customer     Prove identity 2000-12-31T13:30:00.000Z                     NULL
4  4 initiate  initiate Submit application 1992-12-31T13:30:00.000Z 0124-12-31T14:45:40.000Z
5  5    staff     staff   Verify documents 0215-12-31T14:45:40.000Z 0261-12-31T14:45:40.000Z
6  6    staff     staff      Verify survey 1974-12-31T13:30:00.000Z 1996-12-31T13:30:00.000Z
7  7    staff     staff    Verify identity 0149-12-31T14:45:40.000Z 0217-12-31T14:45:40.000Z

timevis object

timeline <- timevis::timevis(df_formatted)
str(timeline)



# df_formatted 
A tibble: 7 x 6
     id group    className content            start   end
  <int> <chr>    <chr>     <chr>              <dbl> <dbl>
1     1 customer customer  Provide documents    106   135
2     2 customer customer  Answer survey         12    30
3     3 customer customer  Prove identity         1    13
4     4 initiate initiate  Submit application    93   125
5     5 staff    staff     Verify documents     216   262
6     6 staff    staff     Verify survey         75    97
7     7 staff    staff     Verify identity      150   218

List of 8
 $ x            :List of 8
  ..$ items     :List of 7
  .. ..$ :List of 6
  .. .. ..$ id       : chr "1"
  .. .. ..$ group    : chr "customer"
  .. .. ..$ className: chr "customer"
  .. .. ..$ content  : chr "Provide documents"
  .. .. ..$ start    : chr "106"
  .. .. ..$ end      : chr "135"
  .. ..$ :List of 6
  .. .. ..$ id       : chr "2"
  .. .. ..$ group    : chr "customer"
  .. .. ..$ className: chr "customer"
  .. .. ..$ content  : chr "Answer survey"
  .. .. ..$ start    : chr " 12"
  .. .. ..$ end      : chr " 30"
  .. ..$ :List of 6
  .. .. ..$ id       : chr "3"
  .. .. ..$ group    : chr "customer"
  .. .. ..$ className: chr "customer"
  .. .. ..$ content  : chr "Prove identity"
  .. .. ..$ start    : chr "  1"
  .. .. ..$ end      : chr " 13"
  .. ..$ :List of 6
  .. .. ..$ id       : chr "4"
  .. .. ..$ group    : chr "initiate"
  .. .. ..$ className: chr "initiate"
  .. .. ..$ content  : chr "Submit application"
  .. .. ..$ start    : chr " 93"
  .. .. ..$ end      : chr "125"
  .. ..$ :List of 6
  .. .. ..$ id       : chr "5"
  .. .. ..$ group    : chr "staff"
  .. .. ..$ className: chr "staff"
  .. .. ..$ content  : chr "Verify documents"
  .. .. ..$ start    : chr "216"
  .. .. ..$ end      : chr "262"
  .. ..$ :List of 6
  .. .. ..$ id       : chr "6"
  .. .. ..$ group    : chr "staff"
  .. .. ..$ className: chr "staff"
  .. .. ..$ content  : chr "Verify survey"
  .. .. ..$ start    : chr " 75"
  .. .. ..$ end      : chr " 97"
  .. ..$ :List of 6
  .. .. ..$ id       : chr "7"
  .. .. ..$ group    : chr "staff"
  .. .. ..$ className: chr "staff"
  .. .. ..$ content  : chr "Verify identity"
  .. .. ..$ start    : chr "150"
  .. .. ..$ end      : chr "218"
  ..$ groups    : NULL
  ..$ showZoom  : logi TRUE
  ..$ zoomFactor: num 0.5
  ..$ fit       : logi TRUE
  ..$ options   : list()
  ..$ height    : NULL
  ..$ api       : list()
 $ width        : NULL
 $ height       : NULL
 $ sizingPolicy :List of 6
  ..$ defaultWidth : NULL
  ..$ defaultHeight: NULL
  ..$ padding      : NULL
  ..$ viewer       :List of 6
  .. ..$ defaultWidth : NULL
  .. ..$ defaultHeight: NULL
  .. ..$ padding      : NULL
  .. ..$ fill         : logi TRUE
  .. ..$ suppress     : logi FALSE
  .. ..$ paneHeight   : NULL
  ..$ browser      :List of 5
  .. ..$ defaultWidth : NULL
  .. ..$ defaultHeight: NULL
  .. ..$ padding      : NULL
  .. ..$ fill         : logi FALSE
  .. ..$ external     : logi FALSE
  ..$ knitr        :List of 3
  .. ..$ defaultWidth : NULL
  .. ..$ defaultHeight: NULL
  .. ..$ figure       : logi TRUE
 $ dependencies :List of 2
  ..$ :List of 10
  .. ..$ name      : chr "jquery"
  .. ..$ version   : chr "1.11.3"
  .. ..$ src       :List of 1
  .. .. ..$ file: chr "/Library/Frameworks/R.framework/Versions/3.5/Resources/library/rmarkdown/rmd/h/jquery-1.11.3"
  .. ..$ meta      : NULL
  .. ..$ script    : chr "jquery.min.js"
  .. ..$ stylesheet: NULL
  .. ..$ head      : NULL
  .. ..$ attachment: NULL
  .. ..$ package   : NULL
  .. ..$ all_files : logi TRUE
  .. ..- attr(*, "class")= chr "html_dependency"
  ..$ :List of 10
  .. ..$ name      : chr "bootstrap"
  .. ..$ version   : chr "3.3.5"
  .. ..$ src       :List of 1
  .. .. ..$ file: chr "/Library/Frameworks/R.framework/Versions/3.5/Resources/library/rmarkdown/rmd/h/bootstrap-3.3.5"
  .. ..$ meta      :List of 1
  .. .. ..$ viewport: chr "width=device-width, initial-scale=1"
  .. ..$ script    : chr [1:3] "js/bootstrap.min.js" "shim/html5shiv.min.js" "shim/respond.min.js"
  .. ..$ stylesheet: chr "css/bootstrap.min.css"
  .. ..$ head      : NULL
  .. ..$ attachment: NULL
  .. ..$ package   : NULL
  .. ..$ all_files : logi TRUE
  .. ..- attr(*, "class")= chr "html_dependency"
 $ elementId    : NULL
 $ preRenderHook: NULL
 $ jsHooks      : list()
 - attr(*, "class")= chr [1:2] "timevis" "htmlwidget"
 - attr(*, "package")= chr "timevis"

@JesseVent
Copy link
Author

Actually looks like 10 days ago someone added a solution almende/vis#92 (comment) by using the following

options = {
    format: {
      minorLabels: function(date,scale,step) {
        // must have a space otherwise it will get mad.
        return new Date(date).getTime() + "";
      },
      majorLabels: function(date,scale,step) {
        // must have a space otherwise it will get mad.
        return new Date(date).getTime() + "";
      }
    },
    timeAxis:{scale:'millisecond'}
}

@daattali
Copy link
Owner

daattali commented Aug 15, 2018 via email

@Pindar777
Copy link

@JesseVent
If these options are really working, could you please show, how to implement.
I tried this in vain:

timevis(df_formatted, options = list( timeAxis = htmlwidgets::JS('{scale:"millisecond", step: 10}'), format = htmlwidgets::JS(' minorLabels: function(date,scale,step) { return new Date(date).getTime() + ""; }, majorLabels: function(date,scale,step) { return new Date(date).getTime() + ""; } }')))

@daattali
Copy link
Owner

@Pindar777 if you can show a working example with the javascript library, I can try to see how to make it work in timevis

@Pindar777
Copy link

@daattali I'm using (time)vis via RStudio only.
When reading this issue I tried to run the solution provided for the javascript library almende/vis#92
At the moment I have no clue how to combine this into a working example with that javasript library. Hence, I cannot confirm, if the proposed solution is really working.
However, modifying the GNU R example from above after consulting the help files (using htmlwidgets::JS inside the options-list) changed the output but without showing the days as timeline lables.

@daattali
Copy link
Owner

You can use this HTML code as a starter code to get the javascript library to work and experiment with it

<!DOCTYPE HTML>
<html>
<head>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/vis/4.16.1/vis.min.js"></script>
  <link href="https://cdnjs.cloudflare.com/ajax/libs/vis/4.16.1/vis.min.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="visualization"></div>
<script type="text/javascript">
  var container = document.getElementById('visualization');
  var items = [
    {id: 1, content: 'item 1', start: '2013-04-19'}
  ]
  var timeline = new vis.Timeline(container, items, {});
</script>
</body>
</html>

@Pindar777
Copy link

@daattali Thanks. I'm gonna try it and check back.

@Pindar777
Copy link

@daattali Well, altough trying hard to use the "format" option, is is just ignored by vis.js and the padding zeros show up as if not using the extra code.

@JesseVent
Copy link
Author

I couldn’t end up getting it to work the way i intended it and ended up going a different route for displaying average times using the processanimateR package and then used timevis for drilling through to actual times. Issue was more with me trying to use timevis for duration in days from day zero which doesn’t look like it supports in vis.js

Combination worked quite well shinyapps.io/loan-process

@Pindar777
Copy link

@JesseVent Thanks. This package is new to me. Good example!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants