Forest plot columns with R Plotly Annotations

Viewed 297

Typo in code has been fixed so that it should now be reproducible

I am new to posting on StackOverflow so please let me know should my question or example not be clear enough and I will add more information as needed.

I am trying to develop a forest plot in R using plotly. For this, I need to be able to position the text along the y axis as if it were a formatted table (column content should be left-aligned for text, right-aligned for numbers, see here for an example). My initial solution was to have one, long, formatted string per y axis tick (using print formatting). This works, but only for monospaced font.

So now I am trying to use annotations instead of y axis labels. The difficulty lies in placing each annotation/column correctly outside the plotting area to created the desired formatting. I first wanted to find the widest string in a column and to calculate the normalized coordinates accordingly, but I am not experienced in this so although I could get the annotations to show up as left-aligned columns, my conversions were wrong and the spaces between the columns were large. Here is what I used to try and figure out the coordinates. If you can point me towards other functions for this or know how I can work with these coordinates, this would definitely be my preferred solution. Note that the number of columns to be plotted to the left/right of the plot will be selected dynamically by the user, and so the plot's margins also need to be able to adjust. And I believe those have to be provided in pixels, so this brings along another conversion, from normalized coordinates to pixels...

  longestMpg = max(strwidth(mtcars$mpg, unit = 'in'))
  coord = grconvertX(longestMpg, from = 'inches', to = 'ndc') #normalized device coordinates
  # coord = grconvertX(longestNames, from = 'inches', to = 'npc') # normalized plot coordinates
  # coord = grconvertX(longestNames, from = 'inches', to = 'nfc') # normalized figure coordinates

So now I have moved on to placing each column/annotation into a separate plot at x = 0 and to trying to combine them into one subplot at the end (not a very elegant workaround...). The problem here is that the text shows up left-aligned for each plot separately (I am not trying to mix left-aligned and right-aligned text at this point), but as soon as I put both plots into one subplot, the text in the second plot is center-aligned. Here is a very simple example:

library(plotly)

# Plot only mtcar$disp
aPlot = plotly_empty(mtcars, type = "scatter", mode = "markers") %>%
  config(
    displayModeBar = FALSE
  )

for (i in 1:nrow(mtcars)) {
  aPlot = aPlot %>% add_annotations(x = 0,
                                    y = i,
                                    text = mtcars$disp[i],
                                    xref = 'paper',
                                    yref = 'y',
                                    showarrow = F) %>%
    layout(yxaxis = list(showline = T), yaxis = list(showline = T))

}

# Plot only mtcar rownames
bPlot = plotly_empty(mtcars, type = "scatter", mode = "markers") %>%
  config(
    displayModeBar = FALSE
  )
for (i in 1:nrow(mtcars)) {
  bPlot = bPlot %>% add_annotations(x = 0,
                                    y = i,
                                    text = rownames(mtcars)[i],
                                    xref = 'paper',
                                    yref = 'y',
                                    showarrow = F) %>%
    layout(yxaxis = list(showline = T), yaxis = list(showline = T))

}

# Subplot
subplot(aPlot, bPlot, shareX = T, shareY = F)

Maybe there is an easier, more elegant way to achieve what I am looking for and I am happy to learn something new so please don't hesitate to share your ideas. Grateful for any help!

0 Answers
Related