Zoltr for Project Owners

Welcome to the zoltr vignette for project owners and forecasters. You should read this if you are interested in creating and managing your own zoltardata.com projects using this package to access them via the Zoltar API. Building on the Getting Started vignette, this one covers deleting and uploading forecasts. Note that before starting you should:

  • Create an account on zoltardata.com.
  • Create a ‘sandbox’ project with one timezero for testing.
  • Create a model in that project.
  • Edit your .Renviron file:
    • USERNAME and PASSWORD: should match your account settings
    • PROJECT_NAME and MODEL_NAME: should match your project and model
    • TIMEZERO_DATE: should match your project
    • FORECAST_CSV_FILE: the path of a forecast data file in the format documented in Zoltar documentation

Connect to the host and authenticate

To access your project, you’ll first need to authenticate via the zoltar_authenticate() function. Pass it the username and password for your account. Notes:

  • Be careful to store and use your username and password so that they’re not accessible to others. A good practice is to put them them in your .Renviron file and then use Sys.getenv() to retrieve them, as outlined in Use Environment variables and as done below.
  • The Zoltar service uses a “token”-based scheme for authentication. These tokens have a five minute expiration for security, which requires re-authentication after that period of time. The zoltr library takes care of re-authenticating as needed by passing your username and password back to the server to get another token. Note that the connection object returned by the new_connection function stores a token internally, so be careful if saving that object into a file.
  • Below you will see the host shown as - this is a temporary one that was used to generate this documentation.
conn <- new_connection()
zoltar_authenticate(conn, Sys.getenv("USERNAME"), Sys.getenv("PASSWORD"))

Get the sandbox project and model work with and then list its forecasts (if any)

Get the ID of the project named by PROJECT_NAME and then get the ID of that project’s model named MODEL_NAME. From the model ID, call the forecasts() function to get a data.frame of that model’s forecasts.

the_projects <- projects(conn)
project_id <- the_projects[the_projects$name == Sys.getenv("PROJECT_NAME"), 'id']  # integer(0) if not found, which is an invalid project ID
the_models <- models(conn, project_id)
model_id <- the_models[the_models$name == Sys.getenv("MODEL_NAME"), 'id']  # integer(0) if not found
the_forecasts <- forecasts(conn, model_id)
#> 'data.frame':    1 obs. of  4 variables:
#>  $ id               : int 208
#>  $ url              : chr ""
#>  $ timezero_date    : Date, format: "2017-01-17"
#>  $ data_version_date: Date, format: NA

Delete the model’s existing forecast for TIMEZERO_DATE, if any, first printing its info

Get the forecast for the timezero date specified by TIMEZERO_DATE and then call delete_forecast(), if one was found.

timezero_date_str <- Sys.getenv("TIMEZERO_DATE")
timezero_date <- as.Date(timezero_date_str, format = "%Y%m%d")  # YYYYMMDD
existing_forecast_id <- the_forecasts[the_forecasts$timezero_date == timezero_date, 'id']

the_forecast_info <- forecast_info(conn, existing_forecast_id)  # `Not Found (HTTP 404)` this if forecast doesn't exist 
#> List of 6
#>  $ id            : int 208
#>  $ url           : chr ""
#>  $ forecast_model: chr ""
#>  $ csv_filename  : chr "EW1-KoTsarima-2017-01-17-small.csv"
#>  $ time_zero     :List of 2
#>   ..$ timezero_date    : chr "20170117"
#>   ..$ data_version_date: NULL
#>  $ forecast_data : chr ""

delete_forecast(conn, the_forecast_info$id)

Upload a forecast

Now let’s upload the forecast data file FORECAST_CSV_FILE for TIMEZERO_DATE via the upload_forecast() function.

Keep in mind that Zoltar queues long operations like forecast uploading, which keeps the site responsive, but makes the Zoltar API a little more complicated. Rather than having the upload_forecast() function block until the upload is done, you instead get a quick response in the form of an UploadFileJob ID that you can pass to the upload_info() function to check its status to find out when the upload is done (or failed). (This is called polling the host to ask the status.) Here we poll every second using a helper function.

busy_poll_upload_file_job <- function(upload_file_job_id) {
    cat(paste0("polling for status change. upload_file_job: ", upload_file_job_id, "\n"))
    while (TRUE) {
        status <- upload_info(conn, upload_file_job_id)$status
        cat(paste0(status, "\n"))
        if (status == "FAILED") {
            cat(paste0("x failed\n"))
        if (status == "SUCCESS") {
forecast_csv_file <- Sys.getenv("FORECAST_CSV_FILE")
upload_file_job_id <- upload_forecast(conn, model_id, timezero_date_str, forecast_csv_file)
#> polling for status change. upload_file_job: 188

And here’s the upload’s final information:

the_upload_info <- upload_info(conn, upload_file_job_id)
#> List of 10
#>  $ id             : int 188
#>  $ url            : chr ""
#>  $ status         : chr "SUCCESS"
#>  $ user           : chr ""
#>  $ created_at     : Date[1:1], format: "2019-05-30"
#>  $ updated_at     : Date[1:1], format: "2019-05-30"
#>  $ failure_message: chr ""
#>  $ filename       : chr "EW1-KoTsarima-2017-01-17-small.csv"
#>  $ input_json     :List of 2
#>   ..$ forecast_model_pk: int 1
#>   ..$ timezero_pk      : int 2
#>  $ output_json    :List of 1
#>   ..$ forecast_pk: int 209

Look at the model’s forecast list to see the new forecast

Finally, let’s again examine the model’s forecasts and notice the new one is there.

the_forecasts <- forecasts(conn, model_id)
#> 'data.frame':    1 obs. of  4 variables:
#>  $ id               : int 209
#>  $ url              : chr ""
#>  $ timezero_date    : Date, format: "2017-01-17"
#>  $ data_version_date: Date, format: NA