Reputation: 479
Let me start by saying I have tried the methods outlined in Color coding error bars in a plotly scatter plot, but I have not been able to get them to work. From what I can tell there were changes in how coloraxes are treated in plotly version 4, which might be why this no longer solves the problem.
I want to make a simple scatterplot of two variables with error bars for each variable. I would like the color of the points and their error bars to follow a scale determined by a third variable. I have been unable to make the error bar colors match the markers. Below are a couple simple methods I tried and their results.
set.seed(1)
x.data <- rnorm(20, 0, 1)
y.data <- rnorm(20, 2, 1)
x.err <- runif(20, 0.2, 0.8)
y.err <- runif(20, 0.2, 0.8)
z.data <- runif(20, 1.7, 2.8)
p <- plot_ly() %>%
add_markers(x=x.data, y=y.data,
error_x=list(array=x.err, color=z.data),
error_y=list(array=y.err, color=z.data),
marker=list(color=z.data, colorscale='Viridis',
colorbar=list(title='Z', limits=range(z.data)))) %>%
layout(xaxis=list(title='X'), yaxis=list(title='Y'))
z.norm <- (z.data - min(z.data))/(max(z.data)-min(z.data))
mycramp<-colorRamp(c("darkblue","yellow"))
mycolors<-rgb(mycramp(z.norm), maxColorValue = 255)
p <- plot_ly() %>%
add_markers(x=x.data, y=y.data,
error_x=list(array=x.err, color=mycolors),
error_y=list(array=y.err, color=mycolors),
marker=list(color=mycolors,
colorbar=list(title='Z', limits=range(z.data)))) %>%
layout(xaxis=list(title='X'), yaxis=list(title='Y'))
Upvotes: 7
Views: 1797
Reputation: 3195
The documentation on r
plotly
can be a bit lacking. I think this is what you're looking for though. You want to use the name
argument. Both color
and name
have to be included. We have to define the name
argument's levels manually. We can set color
to factor as well but then we lose the color ramp. colors
let's us change the color palette using RColorBrewer
palettes.
plot_ly() %>%
add_markers(x = x.data,
y = y.data,
showlegend = F, # must hide legend here or it shows up twice
name = factor(z.data, levels = z.data, labels = z.data), # this is missing
color = z.data,
colors = "Set1",
error_x = list(array = x.err),
error_y = list(array = y.err))
Upvotes: 8
Reputation: 27772
I had to install the latest dev-versions of ggplot2
and plotly
to get this to work (not sure which one did the trick, I just installed both from source). But the solution seems pretty straightforward after that.
#get the latest ggplot2 and plotly from github
# devtools::install_github("tidyverse/ggplot2")
# devtools::install_github("ropensci/plotly")
#first, create a static ggplot2 charts
p1 <-
ggplot( df, aes( x = x.data, y = y.data, color = z.data ) ) +
#plot points
geom_point( ) +
#plot horizontal errorbars
geom_errorbarh( aes( xmin = x.data - x.err, xmax = x.data + x.err ),
height = 0.1 ) +
geom_errorbar( aes( ymin = y.data - y.err, ymax = y.data + y.err ),
width = 0.1 ) +
#set color scale
scale_color_gradient2( low = "purple4", mid = "darkcyan", high = "yellow",
midpoint = min(df$z.data) + ( max(df$z.data) - min(df$z.data) ) / 2 )
#and then plot the chart as plotly
ggplotly(p1)
Upvotes: 3
Reputation: 2031
This is quite a terrible solution, but it might generate some ideas. Basically it involves creating a vector with the colours that each point/error-bar will have and adding each point to the plot separately.
# create the base plot
# if you uncomment the marker line it will also show the colourbar on the side
# but the formatting is messed up, haven't figured out yet how to solve that
p <- plot_ly(
type='scatter',
mode='markers'
# , marker=list(colorscale='Viridis', colorbar=list(title='Z', limits=range(z.data)))
)
# create a vector of colours per point
z <- (z.data - min(z.data)) / (max(z.data) - min(z.data))
z <- viridis::viridis(1001)[round(z * 1e3) + 1]
# add each point separately
for (i in seq_along(x.err)){
p <- p %>% add_markers(
x=x.data[i],
y=y.data[i],
error_x=list(array=x.err[i], color=z[i]),
error_y=list(array=y.err[i], color=z[i]),
marker=list(color=z[i]),
showlegend=F
)
}
p %>% layout(xaxis=list(title='X'), yaxis=list(title='Y'))
Upvotes: 2