R/dw_edit_chart.R

Defines functions dw_edit_chart

Documented in dw_edit_chart

#' Edits a existing Datawrapper chart
#'
#' \lifecycle{maturing}
#' Modifies an existing Datawrapper chart.
#'
#' @section Chart Types:
#'
#' - `d3-bars` : Bar Chart
#' - `d3-bars-split` : Split Bars
#' - `d3-bars-stacked` : Stacked Bars
#' - `d3-bars-bullet` : Bullet Bars
#' - `d3-dot-plot` : Dot Plot
#' - `d3-range-plot` : Range Plot
#' - `d3-arrow-plot` : Arrow Plot
#' - `column-chart` : Column Chart
#' - `grouped-column-chart` : Grouped Column Chart
#' - `stacked-column-chart` : Stacked Column Chart
#' - `d3-area` : Area Chart
#' - `d3-lines` : Line Chart
#' - `d3-pies` : Pie Chart
#' - `d3-donuts` : Donut Chart
#' - `d3-multiple-pies` : Multiple Pies
#' - `d3-multiple-donuts` : Multiple Donuts
#' - `d3-scatter-plot` : Scatter Plot
#' - `election-donut-chart` : Election Donut
#' - `tables` : Table
#' - `d3-maps-choropleth` : Choropleth Map
#' - `d3-maps-symbols` : Symbol Map
#' - `locator-map` : Locator Map
#'
#' @section Chart Properties:
#'
#' Datawrapper defines the properties of a chart in the following structure.
#'
#' Note: Not all possibilities are displayed, as different chart-types offer different design features.
#'
#' You can find more on this structure in the \href{https://developer.datawrapper.de/docs/chart-properties}{API-Guide}.
#'
#'```
#'  {
#' "id": "6Ba3L",
#' "type": "d3-scatter-plot",
#' "title": "A grat chart",
#' ...
#'
#' "metadata": {
#'
#'   "data": {
#'     "transpose": false,
#'     ...
#'   },
#'
#'   "publish": {
#'     "embed-codes": {
#'       "embed-method-iframe": "<iframe title=\"\" aria-label=\"Scatter Plot\" src=\"//datawrapper.dwcdn.net/6Ba3L/1/\" scrolling=\"no\" frameborder=\"0\" style=\"border: none;\" width=\"600\" height=\"294\"></iframe>",
#'       ...
#'     },
#'     "embed-width": 600,
#'     "chart-height": 33.859375,
#'     ...
#'   }
#' },
#'
#' "annotate": {
#'   "notes": "Updates from 2018 are excluded."
#' },
#'
#' "describe": {
#'   "intro": "",
#'   "byline": "",
#'   ...
#' },
#'
#' "visualize": {
#'   "size": "fixed",
#'   "rules": false,
#'   "shape": "fixed",
#'   ...
#' },
#'
#' "json_error": null
#' },
#'
#' "language": "en-US",
#' "externalData": null,
#' ...
#' },
#' "url": "/v3/charts/6Ba3L"
#' }
#' ```
#'
#' @md
#' @param chart_id Required. A Datawrapper-chart-id as character string, usually a five character combination of digits and letters, e.g. "aBcDe". Or a \strong{dw_chart}-object.
#' @param api_key Required. A Datawrapper-API-key as character string. Defaults to "environment" - tries to automatically retrieve the key that's stored in the .Reviron-file by \code{\link{datawrapper_auth}}.
#' @param title Optional. Adds a title to the plot.
#' @param intro Optional. Adds an intro below the title.
#' @param annotate Optional. Adds a annotation below the plot.
#' @param byline Optional. Adds the name of the chart's creator.
#' @param type Optional. Changes the type of the chart. See \href{https://developer.datawrapper.de/docs/chart-types}{the documentation} for the different types or the Chart Type section below.
#' @param source_name Optional. Adds a source name to the plot.
#' @param source_url Optional. Adds a URL to the source name (displayed only, if source name specified). Include http(s):// before URL.
#' @param folderId Optional. Moves the chart to the specified folder (by folder-id, which can be found using \code{\link{dw_list_folders}}).
#' @param axes Optional. A list which specifies the axes.
#' @param data Optional. A list. Add separate arguments for the data. See \href{https://developer.datawrapper.de/docs/chart-properties}{the documentation} for details.
#' @param visualize Optional. A list. Add separate arguments for the visualization. See \href{https://developer.datawrapper.de/docs/chart-properties}{the documentation} for details.
#' @param describe Optional. A list. Add separate arguments for the description. See \href{https://developer.datawrapper.de/docs/chart-properties}{the documentation} for details.
#' @param publish Optional. A list. Add separate arguments for publication. See \href{https://developer.datawrapper.de/docs/chart-properties}{the documentation} for details.
#' @param ... Optional. Will be added as a list to the top-level of the call-body. Use with caution, as it may overwrite some values defined earlier.
#'
#' @return A terminal message: "Chart xyz succesfully updated." - or an error message.
#' @author Benedict Witzenberger
#' @note This function builds a body for a API-call to the Datawrapper-API.
#' @note Check their \href{https://developer.datawrapper.de/docs}{reference guide} or \href{https://developer.datawrapper.de/reference}{API-documentation}.
#' @examples
#'
#' \dontrun{
#' dw_edit_chart("aBcDE") # uses the preset key in the .Renviron-file, no changes
#' }
#'
#' \dontrun{
#' dw_edit_chart(chart_id = "a1B2Cd", api_key = "1234ABCD") # uses the specified key, no changes
#' }
#'
#' \dontrun{
#' dw_edit_chart(chart_id = "a1B2Cd", title = "I'm a title",
#' intro = "Data showing daily results")
#' # changes title and intro
#' }
#'
#' \dontrun{
#' dw_edit_chart(chart_id = "a1B2Cd", title = "I'm a title",
#' data = list("transpose" = "true"))
#' # transpose data
#' }
#'
#' @rdname dw_edit_chart
#' @export
dw_edit_chart <- function(chart_id, api_key = "environment", title = NULL, intro = NULL, annotate = NULL, byline = NULL,
                          type = NULL, source_name = NULL, source_url = NULL, folderId = NULL, axes = list(), data = list(), visualize = list(),
                          describe = list(), publish = list(), ...) {

  if (api_key == "environment") {
    api_key <- dw_get_api_key()
  }

  chart_id <- dw_check_chart_id(chart_id)

  # create empty body for API-call
  call_body <- list(metadata = list())

  # change only specified parts of existing data
  if (!is.null(title)) {call_body <- rlist::list.append(call_body, title = title)}
  if (!is.null(type)) {call_body <- rlist::list.append(call_body, type = type)}
  if (!is.null(folderId)) {call_body <- rlist::list.append(call_body, folderId = folderId)}

  if (!is.null(intro)) {call_body$metadata$describe$intro <- intro}
  if (!is.null(annotate)) {call_body$metadata$annotate$notes <- annotate}

  if (!is.null(byline)) {call_body$metadata$describe$byline <- byline}
  if (!is.null(source_name)) {call_body$metadata$describe$`source-name` <- source_name}
  if (!is.null(source_url)) {

    if (grepl("^http", source_url) == FALSE) {  # include simple test, if url is starting with http(s)
      source_url <- paste0("http://", source_url)
    }

    call_body$metadata$describe$`source-url` <- source_url
  }

  # work in additional arguments, if specified
  if (length(data) > 0) {
    if (!is.list(call_body$metadata$data)) {
      call_body$metadata$data <- list()
    }
    call_body$metadata$data <- utils::modifyList(call_body$metadata$data, data)
  }

  if (length(visualize) > 0) {
    if (!is.list(call_body$metadata$visualize)) {
      call_body$metadata$visualize <- list()
    }

    call_body$metadata$visualize <- utils::modifyList(call_body$metadata$visualize, visualize)
  }

  if (length(describe) > 0) {
    if (!is.list(call_body$metadata$describe)) {
      call_body$metadata$describe <- list()
    }

    call_body$metadata$describe <- utils::modifyList(call_body$metadata$describe, describe)
  }

  if (length(publish) > 0) {
    if (!is.list(call_body$metadata$publish)) {
      call_body$metadata$publish <- list()
    }

    call_body$metadata$publish <- utils::modifyList(call_body$metadata$publish, publish)
  }

  if (length(axes) > 0) {
    if (!is.list(call_body$metadata$axes)) {
      call_body$metadata$axes <- list()
    }
    call_body$metadata$axes <- utils::modifyList(call_body$metadata$axes, axes)
  }

  additional_arguments <- list(...)

  if (length(additional_arguments) > 0) {
    call_body <- append(call_body, additional_arguments)
  }

  # send call to API
  # upload modified data
  # solution for API v1:
  # url_upload <- paste0("https://api.datawrapper.de/charts/", chart_id)
  #
  # r <- dw_call_api("PUT", url_upload, httr::add_headers(Authorization = paste("Bearer", api_key, sep = " ")),
  #                       body = call_body, encode = "json", .DATAWRAPPR_UA)

  url_upload <- paste0("https://api.datawrapper.de/v3/charts/", chart_id)
  parsed <- dw_call_api("PATCH", url_upload, httr::add_headers(Authorization = paste("Bearer", api_key, sep = " ")),
                   body = call_body, encode = "json", .DATAWRAPPR_UA)

  chart_id_response <- parsed["id"][[1]] #for v3: parsed["id"][[1]], for v1: parsed[["data"]][[1]][["id"]]

  try(if (chart_id != chart_id_response) stop(paste0("The chart_ids between call (",  chart_id ,") and response (",  chart_id_response ,") do not match. Try again and check API.")))

  if (chart_id == chart_id_response) {

    message(paste0("Chart ", chart_id_response, " succesfully updated.", "\n"))

  } else {
    stop(paste0("There has been an error in the upload process."), immediate. = TRUE)
  }

  httr::handle_reset(url_upload)

}
munichrocker/DatawRappr documentation built on March 20, 2024, 6:08 a.m.