Search code examples
rimageplotlyyaxis

Is it possible to put logos on the y-axis


I have a very simple plotly graph for which I would like to put the company logos instead (or both) of their names on the Y axis

library(plotly)

plot_ly(
  y = c("company_1", "company_2", "company_3", "company_4", "company_5"),
  x = c(20, 14, 23, 6, 28),
  name = "companies",
  type = "bar"
)

For example, we can imagine that the companies are Facebook, Twitter, Apple, Microsoft and Tesla I have images (logo) in png format.

Is there a way to do this?


Solution

  • This isn't something you'll be able to do strictly in R. However, if you use the function onRender from htmlwidgets, you can do it.

    I added margin so the images would fit. However, the plot is exactly as you provided it. Make sure that if/when you make changes you respect the whitespace shown here. HTML and Javascript won't understand if the attributes are smashed together.

    The first code & plot uses an image that is on the web. The next code & plot uses a local file. That way you can use whichever method applies in your situation.

    Images via Hyperlink

    plot_ly(
      y = c("company_1", "company_2", "company_3", "company_4", "company_5"),
      x = c(20, 14, 23, 6, 28),
      name = "companies",
      type = "bar") %>% 
      layout(margin = list(l = 120, r = 20, t = 20, b = 50)) %>% 
      htmlwidgets::onRender("function(){
        gimme = document.querySelectorAll('g.ytick');   /* get the text positions on y-axis */
        imTag1 = '<image width=\"100\" height=\"100\" ' /* pre-build the HTML */
        imTag2 = ' href=\"https://www.rstudio.com/wp-content/uploads/2018/10/RStudio-Logo-Flat.png\" />'
        for(i = 0; i < gimme.length; i++) {
          zz = gimme[i].firstChild.getAttribute('transform'); /* get position on page*/
          yy = gimme[i].firstChild.getAttribute('y');
          yy = yy * -10;
          img = imTag1 + 'x=\"10\" y=\"' + yy + '\" transform=\"' + zz + '\"' + imTag2;
          gimme[i].innerHTML = img;    /* replace the text tag */
        } 
      }")
    

    enter image description here

    Images via Local File

    The image I used here is from https://www.hiclipart.com/free-transparent-background-png-clipart-qzdon/download

    In MY files it's saved at ./_images/orangeIcon.png (where '.' represents the current working directory).

    Because this file is a png, I need to make something better for web portability, so I used base64 encoding using the package base64enc.

    img <- base64enc::dataURI(file = "./_images/orangeIcon.png")
    

    I'm going to assign this to customdata in the call for plotly. If you had five images, you can make a list of the 5 encoded images. if you list one, plotly will replicate it. (That's what it did here.)

    plot_ly(
      y = c("company_1", "company_2", "company_3", "company_4", "company_5"),
      x = c(20, 14, 23, 6, 28),
      name = "companies", customdata = img,       # <---- custom data!!
      type = "bar") %>% 
      layout(margin = list(l = 120, r = 20, t = 20, b = 50)) %>% 
      htmlwidgets::onRender("function(el, x){      /* changed here, as well */
            gimme = document.querySelectorAll('g.ytick');   /* get the text positions on y-axis */
            imgs = x.data[0].customdata;           /* collect the images */
            imTag1 = '<image width=\"100\" height=\"100\" href=\"' /* pre-build the HTML */
            imTag2 = ' \" />'
            for(i = 0; i < gimme.length; i++) {
              zz = gimme[i].firstChild.getAttribute('transform'); /* get position on page*/
              yy = gimme[i].firstChild.getAttribute('y');
              yy = yy * -10;
              img = imTag1 + imgs[i] + '\" x=\"10\" y=\"' + yy + '\" transform=\"' + zz + '\"' + imTag2;
              gimme[i].innerHTML = img;    /* replace the text tag */
            } 
          }") # note the differences in imgTag1 and imgTag2 
              #             to accommodate the new info for href
    

    enter image description here