Plotting Images Using echarts4r library for R

In this post, an overview will be provided of how to add images to a chart using the echarts4r package
Published

March 11, 2023

Introduction

An example of a body weight chart with images

Charts4r is a powerful R package that offers a variety of graphing options for data visualization. This blog post focuses on creating a line chart with images overlaid on data points. The weight records by date will be used as the data source for this tutorial. To insert images into the chart, we will need to provide the paths from where they can be obtained. If the chart is being hosted online, the images must be accessible to all users. Otherwise, local paths can be used if the chart is being created locally.

Setup

###---Libraries
  library(echarts4r)  #Charting
  library(dplyr)      #Data Transformation
Warning: package 'dplyr' was built under R version 4.1.3

Attaching package: 'dplyr'
The following objects are masked from 'package:stats':

    filter, lag
The following objects are masked from 'package:base':

    intersect, setdiff, setequal, union
  library(tidyr)      #Data Transformation (pivoting)
  library(lubridate)  #Date formats

Attaching package: 'lubridate'
The following objects are masked from 'package:base':

    date, intersect, setdiff, union
  library(imputeTS)   #NA Handeling
Warning: package 'imputeTS' was built under R version 4.1.2
Registered S3 method overwritten by 'quantmod':
  method            from
  as.zoo.data.frame zoo 
###---Folder where images are stored
IMG_Folder <- './images/echarts4r-demo/No-BG'
IMG_Folder_Website <- paste0('image://https://www.patrickboyce.com/r-projects/', gsub('\\./', '', IMG_Folder), '/')

###---Load Data
  Body_Weight_Records <- read.csv('./data/wlp/weight-by-date.csv')
  
  Body_Weight_Records <- Body_Weight_Records %>%
    mutate(Date = mdy(Date))
  
  Photo_Records <- tibble(File_Name = list.files(IMG_Folder)) %>%
    mutate(Week = as.Date(substr(File_Name, 1, 10)),
           Echart_Path = paste0(IMG_Folder_Website, File_Name))

###---Example of data
head(Body_Weight_Records) %>%
       knitr::kable()
Date Weight
2012-12-01 280
2012-12-08 278
2012-12-15 276
2012-12-22 274
2012-12-29 272
2013-01-05 270

Data Preparation

Data will be aggregated by week, then, if an image exists for that week, it’s added.

###---Aggregates the data by week
Body_Weight_By_Week <- Body_Weight_Records %>%
  group_by(Week = floor_date(Date, unit = 'week')) %>%
  summarise(`Body Weight` = mean(Weight))

###---Creates a sequence of all weeks from the start to the end of the body weight by week
All_Weeks <- tibble('Week' = seq.Date(min(Body_Weight_By_Week$Week), max(Body_Weight_By_Week$Week), by = 'weeks'))

###---Imputes the weight values for any weeks for which the data was missing
Body_Weight_By_Week <- All_Weeks %>%
  left_join(Body_Weight_By_Week, by = 'Week') %>%
  na_ma(k = 2, weighting = 'simple') 

###---Adds the assosciated image path to each week if there is one
Body_Weight_By_Week <- Body_Weight_By_Week %>%
  left_join(Photo_Records, by = 'Week') %>%
  #If no image is avaialble, passing "None" will stop echarts4r from plotting it
  mutate(Echart_Path = if_else(is.na(Echart_Path), 'none', Echart_Path)) %>% 
  mutate(`Body Weight` = round(`Body Weight`, 1))

###---Final data
Body_Weight_By_Week %>%
  slice_head(n=5) %>%
  knitr::kable()
Week Body Weight File_Name Echart_Path
2012-11-25 280 2012-11-25-removebg-preview.webp image://https://www.patrickboyce.com/r-projects/images/echarts4r-demo/No-BG/2012-11-25-removebg-preview.webp
2012-12-02 278 NA none
2012-12-09 276 NA none
2012-12-16 274 NA none
2012-12-23 272 NA none

Plotting The Data

Body_Weight_By_Week %>% 
    e_charts(Week) %>% 
  e_line(`Body Weight`, #Adds a line for the weekly weight
         legend = FALSE,
         showSymbol = FALSE) %>%
    e_pictorial( #Adds a picture when there is one available
        `Body Weight`, symbol = Echart_Path, 
        symbolRepeat = FALSE,
        symbolSize = c(68,102),
        symbolPosition = 'end',
        symbolOffset = c(0,-100),
        color = '#ffff0000',
        hoverAnimation = TRUE,
        legend = FALSE
    ) %>%
  e_theme('vintage') %>%
  e_title(text = 'Body Weight',
          subtext = '280 LB (Start) > 179 LB (Lowest) > 205 LB (Current)',
          x = 'center') %>%
  e_tooltip(formatter = htmlwidgets::JS("
                                    function(params){
                                    return('Weight: ' +
parseFloat((params.value[1] * 10) / 10).toFixed(1) + '<br>' + params.value[0]) 
                                    }
                                    ")) 

Additional Information

For additional information about the charts you can make using the echarts4r package, visit https://echarts4r.john-coene.com/