'R Plotly Bar Chart - Add horizontal line markers
I want to draw a bar chart with two bars side by side for each category (LETTERS
) and add a horizontal line to each bar (y_ref
as red lines & z_ref
as green lines). It should look like this:
I tried it with add_trace (and add_lines, add_segment, etc) but can't find the correct way to make it work. Here's one of the reprex's I tried so far.
df <- tibble(x = LETTERS[1:5], y = runif(5), z = runif(5), y_ref = runif(5), z_ref = runif(5))
plot_ly(
df,
x = ~x,
y = ~y,
type = "bar",
name = "a"
) %>% add_trace(
y = ~z,
name = "b"
) %>% layout(
legend = list(
orientation = "h"
)
) %>% add_trace(
y = ~y_ref,
type = 'scatter',
mode = 'lines',
marker = list(
line = list(
width = 2,
color = "red"
)
)
) %>% add_trace(
y = ~z_ref,
type = 'scatter',
mode = 'lines',
marker = list(
line = list(
width = 2,
color = "green"
)
)
)
Edit: I need a solution for n
bars.
Solution 1:[1]
You have to use shapes
for line segments in Plotly. Additionally, because the x-axis is discrete, the x
for the shapes will need to be in paper
space.
When working in paper space, you use the plot domain
to figure out the values for x
. Plotly has a default domain
set to [0, 1] for both x
and y
axes.
There is a gap between bars; that has to be accounted for as well. I used three functions to create the line segments, using all of this information.
Lastly, I used a seed
for repeatability.
Libraries, seed, and base plot
library(tidyverse)
library(plotly)
set.seed(8)
df <- tibble(x = LETTERS[1:5], y = runif(5), z = runif(5),
y_ref = runif(5), z_ref = runif(5))
p = plot_ly(df, x = ~x, y = ~y,
type = "bar", name = "a") %>%
add_trace(y = ~z, name = "b")
Create the segments
# standard shape elements, call for color
details <- function(col){
list(type = 'line',
line = list(color = col),
xref = "paper", yref = "y")
}
# green lines for orange bars
segs = lapply(1:nrow(df),
function(k){
x1 <- (k + k)/10 - .02 # if the domain is [0, 1]
x0 <- x1 - .08
y0 <- y1 <- df[k, ]$z_ref
line = list("x0" = x0, "x1" = x1,
"y0" = y0, "y1" = y1)
deets = details("green")
c(deets, line)
})
# green lines for blue bars
segs2 = lapply(1:nrow(df),
function(j){
x1 <- (j + j - 1)/10 # if the domain is [0, 1]
x0 <- x1 - .08
y0 <- y1 <- df[j, ]$y_ref
line = list("x0" = x0, "x1" = x1,
"y0" = y0, "y1" = y1)
deets = details("red")
c(deets, line)
})
segs = append(segs, segs2)
Put it together
p %>% layout(legend = list(orientation = "h"),
shapes = segs)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Kat |