Boxplot next to a scatterplot in R with plotly - r

I created a scatter plot with plotly in R. Now I want to plot a boxplot with different data next to the scatter plot. I want to use plotly for this.
The result should look like this. Can someone help me please, I have no idea how to do that.
My code so far is
plot_ly(ds, x = ~x, y = ~y , mode = "markers", name = "Clusters", opacity = point.opacity,
text = ds$id,
hoverinfo = "text",
marker = list(symbol = point.symbol, color = ~color, size = point.size,
line = list(color = "#262626", width = point.linewidth, opacity = point.lineopacity)),
showlegend = F)

Here is an example on how to make a scatter with marginal box plots with plotly:
library(plotly)
data(iris)
create, three plots for the data: one for the scatter, two for the appropriate box plots, and one additional empty plot. Use the subplot function to arrange them:
subplot(
plot_ly(data = iris, x = ~Petal.Length, type = 'box'),
plotly_empty(),
plot_ly(data = iris, x = ~Petal.Length, y = ~Petal.Width, type = 'scatter',
mode = 'markers'),
plot_ly(data = iris, y = ~Petal.Width, type = 'box'),
nrows = 2, heights = c(.2, .8), widths = c(.8,.2), margin = 0,
shareX = TRUE, shareY = TRUE) %>%
layout(showlegend = F)

Related

Color code forest plot points and error bars by range

I have a data.frame of regression coefficients with the associated p-values:
library(dplyr)
set.seed(1)
effects.df <- data.frame(contrast = paste0("C",1:5), effect = rnorm(5), stringsAsFactors = F) %>%
dplyr::mutate(effect.error = abs(effect)/sqrt(5)) %>%
dplyr::mutate(p.value = pnorm(effect/effect.error)) %>%
dplyr::arrange(p.value)
effects.df$contrast <- factor(effects.df$contrast,levels = effects.df$contrast)
Which I want to display as a forest plot (X-axis are the effect size and Y-axis are the 'contrast's), where the points and their associated error bars (effect.error) are color coded by 1-p.value, using R's plotly.
Here's what I'm trying:
library(plotly)
effects.plot <- plot_ly(x = effects.df$effect, y = effects.df$contrast, type = 'scatter', mode = "markers", marker = list(size = 8, colorbar = "Hot", color = 1-effects.df$p.value)) %>%
layout(xaxis=list(title = "Effect size",zerolinewidth = 2, zerolinecolor = plotly::toRGB('black'), showgrid = F), yaxis = list(showgrid = F)) %>%
add_trace(error_x = list(array = effects.df$effect.error, width = 5),marker = list(size = 8,colorbar = "Hot", color = 1-effects.df$p.value))
It's close because it's color-coding the points how I want them to but not the error bars.
Any idea how to:
Color the error bars similar to the points?
Get the color-bar to show?
I'm not sure that it will allow you to color the error bars separately without some (a lot) of creativity. If you created separate traces for each color, you might be able to force it to comply.
There are many ways you could show the color bar. Here's one way:
(effects.plot <- plot_ly(data = effects.df,
x = ~effect,
y = ~contrast,
error_x = list(array = ~effect.error,
width = 5,
color = "black"),
type = 'scatter',
mode = "markers",
marker = list(colorscale = "Hot",
colorbar = list(size = 8),
color = 1 - effects.df$p.value)) %>%
layout(xaxis=list(title = "Effect size",
zerolinewidth = 2,
zerolinecolor = plotly::toRGB('black'),
showgrid = F),
yaxis = list(showgrid = F)) # set the joined color axis
)
By the way, I noticed that the colors you have are gray and red, not black and white, as shown in my image. You're getting a different color scale than you were expecting.
You can see what I mean by plotting this a different way:
(effects.plot <- plot_ly(data = effects.df,
x = ~effect,
y = ~contrast,
error_x = list(array = ~effect.error,
width = 5,
color = "black"),
type = 'scatter',
mode = "markers",
marker = list(coloraxis = "coloraxis",
color = 1 - effects.df$p.value)) %>%
layout(xaxis=list(title = "Effect size",
zerolinewidth = 2,
zerolinecolor = plotly::toRGB('black'),
showgrid = F),
yaxis = list(showgrid = F),
coloraxis = list(colorbar = "Hot", size = 8))
)
This plot is not using the "Hot" color scale. That scale is shown in the first image.
The easiest way to solve this is to use ggplot2 and then to convert it to a plotly object:
Libraries and data:
library(dplyr)
library(plotly)
library(ggplot2)
set.seed(1)
effects.df <- data.frame(contrast = paste0("C",1:5), effect = rnorm(5), stringsAsFactors = F) %>%
dplyr::mutate(effect.error = abs(effect)/sqrt(5)) %>%
dplyr::mutate(p.value = pnorm(effect/effect.error)) %>%
dplyr::arrange(p.value)
Here I also add a horizontal dashed y-line to mark the p-value = 0.05 cutoff:
effects.df$contrast <- factor(effects.df$contrast,levels=effects.df$contrast)
y.intercept <- min(which(effects.df$p.value > 0.05))-0.5
pp <- ggplot(effects.df)+geom_vline(xintercept=0,color="black")+geom_point(aes(y=contrast,x=effect,color=p.value))+
geom_errorbarh(aes(y=contrast,xmin=effect-effect.error,xmax=effect+effect.error,x=effect,color=p.value,height=0.1))+
scale_color_continuous(low="darkred",high="gray")+theme_minimal()+xlab("Effect Size")+
geom_hline(yintercept=y.intercept,linetype="dashed",color="black",size=0.25)
Which gives:
And the plotly object:
ggplotly(pp)

Create a filled area line plot with annotated scatters using plotly

I want to create a filled area plot with line and scatters like in the screenshot attached but I do not know how could add scatters for every year of x-axis and also annotate its value. My code is:
library(plotly)
data <- t(USPersonalExpenditure)
data <- data.frame("year"=rownames(data), data)
fig <- plot_ly(data, x = ~year, y = ~Food.and.Tobacco, name = 'Food and Tobacco', type = 'scatter', mode = 'line', stackgroup = 'one', fillcolor = '#F5FF8D')
fig
The mode lines+markers+text allows you to define a line plot with markers and add some text.
I changed the type of year from factor to numeric, because I had to expand the xaxis for readabilty of the annotations.
library(plotly)
data <- t(USPersonalExpenditure)
data <- data.frame("year" = as.numeric(rownames(data)), data)
plot_ly(data,
x = ~year,
y = ~Food.and.Tobacco,
text = ~Food.and.Tobacco) %>%
add_trace(
type = 'scatter',
mode = 'lines+markers+text',
fill = 'tozeroy',
fillcolor = '#F5FF8D',
marker = list(color = 'black'),
line = list(color = 'black'),
textposition = "top center",
hovertemplate = paste0("<b>%{x}</b>
Cummulative Food and Tobacco: %{y}
<extra></extra>"),
hoveron = 'points') %>%
layout(xaxis = list(
range= list(min(data$year) - 1, max(data$year) + 1)))

Plotly R setting the title of a continuous color legend

I'm trying to plot a 3D scatter using Plotly and R. Other than x, y and z I also would like to set the color of each point depending on a fourth variable.
I manage to set the plot correctly (the use of name = ~res is to show the value of res while hovering), but I am not able to change the name of the colorbar.
This is a mock code of what I've done:
library(tidyverse)
library(plotly)
a = seq(1,10,1)
b = seq(100,1000,100)
c = seq(1,4.9,0.4)
data = tibble(a,b,c)
data <- data %>% mutate(res = a+b+c)
layout_details <- list(xaxis = list(title = 'a [-]'),
yaxis = list(title = 'b [-]'),
zaxis = list(title = 'c [-]'),
coloraxis=list(colorbar=list(title=list(text='Here are the results'))))
p = plot_ly(data, x = ~a, y = ~b, z = ~c, color = ~res, type = 'scatter3d',
mode = 'markers', name = ~res, showlegend = FALSE, scene = 'scene1')
p <- p %>% layout(scene1 = layout_details)
p
I've noticed that a quite similar question was asked (R plotly to legend title value ignored for continuous color scatter plot), but without any answers.
Does anyone know how to solve this?
Thanks
You can define your colorbar inside the marker argument.
The name argument is interfering with the colorbar therefore I moved res from the name argument to the hovertemplate and the customdata.
Code
p = plot_ly(data, x = ~a, y = ~b, z = ~c,
name = "",
scene = 'scene1',
type = 'scatter3d',
mode = 'markers',
customdata = as.list(data$res),
hovertemplate = paste('x: %{x}',
'y: %{y}',
'z: %{z}',
'name: %{customdata}',
sep = "\n"),
marker = list(color = ~res,
colorbar = list(title = "Here are the results"),
colorscale='Viridis',
showscale = TRUE))
p <- p %>% layout(scene1 = layout_details)
p
Plot

Plot multiple legends in R-plotly

I have 5 continuous variables that I'd like to graph together in R plotly.
I wrote the following code and got the plot to run as expected, but I cannot figure out how to deal with the legends. As is, the color legend appears, but the size legend does not.
I would like to plot both legends and control their locations within the plot. Suggestions from a similar post Adding color and bubble size legend in R plotly do not solve the problem.
Here's the code and sample data:
x<-sample(30)
y<-sample(30)
z<-sample(30)
c<-sample(30)
s<-sample(30)
fig <- plot_ly (x = x, y = y, z = z, color = c,
colors = c("#440154FF", "#1F968BFF", "#FDE725FF"), size = s,
marker = list(symbol = 'circle', sizemode = 'diameter'), sizes = c(1, 30))
fig <- fig %>% add_markers()
fig <- fig %>% layout(scene = list(xaxis = list (title = 'X'),
yaxis = list(title = 'Y'),
zaxis = list(title = 'Z'),
annotations = list(x = 1.05, y =1.02,
text = 'Gradient title',
xref = 'paper', yref = 'paper',
showarrow=FALSE, showlegend=TRUE)))
fig
It's been a while since this question was asked, but I have an answer. Initially, I tried to make the legend a subplot, but the legend from the 3D markers is offset from the plot-as-a-legend of bubble sizes. To fix that issue, I created an image of the bubbles and added it to the original plot as an image.
Using the information from fig in your original code, I created another figure (the bubbles and sizes).
figB <- plot_ly(x = 1, y = seq(30, 5, by = -5),
size = seq(30, 5, by = -5),
sizes = c(1, 30),
type = "scatter",
mode = "markers",
color = seq(30, 5, by = -5),
colors = c("#440154FF", "#1F968BFF", "#FDE725FF"),
marker = list(sizeref = 0.1,
sizemode = "area"),
height = 275, width = 100) %>%
layout(
xaxis = list(zeroline = F, showline = F, showticklabels = F, showgrid = F),
yaxis = list(showgrid = F, side = "right")) %>% # numbers on right (as fig legend)
hide_colorbar()
figB
I used three different libraries for this next part: htmlwidgets, webshot, and magick.
# create temp files
tmp <- tempfile(fileext = ".html") # plotly to html
tmp2 <- tempfile(fileext = ".png") # html to png
# create html
htmlwidgets::saveWidget(figB, tmp, background = "transparent")
# create png
webshot::webshot(tmp, tmp2, zoom = 2, vwidth = 150, vheight = 275) # to get great res
# make the png an object
itsBack <- magick::image_read(tmp2)
# check the amount of white space
magick::image_border(itsBack, "gray") # not too much white space; good res
unlink(tmp) # remove tempfile connection
unlink(tmp2)
For this last step, I copied the code from your original figure. The image needs to be added to layout. I removed code that didn't impact the figure, as well.
# set up placement of image below the initial legend
imgr = list(
source = raster2uri(as.raster(itsBack)),
xref = "paper",
yref = "paper",
y = .5, # paper domain is 0 to 1, this puts the top in the middle
x = .95, # almost all the way right
sizex = .45, # scale image down (0-1)
sizey = .45, # scale image down (0-1)
opacity = 1,
layer = "above")
# Rebuild fig without the initial legend - then add imgr to the legend
fig <- plot_ly (x = x, y = y, z = z, color = c,
colors = c("#440154FF", "#1F968BFF", "#FDE725FF"),
size = s,
marker = list(symbol = 'circle',
sizemode = 'diameter'),
sizes = c(1, 30))
fig <- fig %>% layout(
scene = list(xaxis = list(title = 'X'),
yaxis = list(title = 'Y'),
zaxis = list(title = 'Z')),
images = imgr) # adding bubbles here
fig
Depending on what you're doing with the graph, the placement and scaling may need to be adjusted. While plotly objects scale dynamically, the png won't be nearly as dynamic-friendly. The image is scaled down to 45% of its original size, so you have a lot of room to grow, but you may have to adjust those parameters (sizex and sizey). If you rescale your viewer window, you may also need to refresh the view. (Use the refresh icon in the Viewer pane.)

Remove continuous legend from plotly

I have a basic scatterplot that I've made in plotly (in R). I'm using a continuous input to color the data points which plotly converts into a gradient. However, the removelegend option doesn't remove a continuous legend the way it removes a discrete legend. Consider the example below.
data = mtcars
data$vs = as.character(data$vs)
plotly::plot_ly(
data = data,
x = ~disp,
y = ~mpg,
color = ~vs,
mode = "markers",
type = "scatter"
) %>%
layout(showlegend = FALSE)
plotly::plot_ly(
data = data,
x = ~disp,
y = ~mpg,
color = ~hp,
mode = "markers",
type = "scatter"
) %>%
layout(showlegend = FALSE)
Is there a way to remove the continuous legend?
The issue arises because in the continuous case plotly doesn't call it a legend, it's a color bar. The easiest way to remove it is to pipe in hide_colorbar()
plotly::plot_ly(
data = data,
x = ~disp,
y = ~mpg,
color = ~hp,
mode = "markers",
type = "scatter"
) %>%
hide_colorbar()

Resources