This question already has answers here:
Horizontal/Vertical Line in plotly
(4 answers)
Closed 2 years ago.
I would like to add a vertical line on a special date to my plot. I am using the plot_ly() function from the plotly package in R.
p <- plot_ly(dt.allDataFvsS, x = dt.allDataFvsS$date, y = dt.allDataFvsS$meanDifference, mode = 'lines',
type = "scatter", line = list(color = " #007d3c")) %>%
layout(title = "Average Price Difference Forward vs. Spot", xaxis = list(title = "Date"),
yaxis = list(title = "EUR / MWh"))
The date has the following form: e.g. "2018-10-01" ("Y-M-D")
My plot looks like this:
PLOT
So, my question is how do I get a black vertical line at date "2018-10-01" ?
Is it also possible to have vertical lines at the beginning of each year? Or of every quarter (Jan - Apr - Jul - Oct) of each year?
I would be very happy if someone could help me? Unfortunately, after a day of browsing the internet, I couldn't find anything that worked.
As no data is provided to reproduce your issue, I would suggest next approach using add_trace() function where you define the coordinates for the line:
p <- plot_ly(dt.allDataFvsS, x = dt.allDataFvsS$date, y = dt.allDataFvsS$meanDifference, mode = 'lines',
type = "scatter", line = list(color = " #007d3c")) %>%
add_trace(x =as.Date("2018-10-01"),type = 'scatter', mode = 'lines',
line = list(color = 'black'),name = '') %>%
layout(title = "Average Price Difference Forward vs. Spot", xaxis = list(title = "Date"),
yaxis = list(title = "EUR / MWh"))
Let me know if that works!
Here is another approach based on shapes rather than adding another trace (you can see the difference when zooming out + there is no legend item for the vertical line):
library(plotly)
dates <- seq(from = as.Date("2018-08-01"), to = as.Date("2018-12-31"), by = 1)
dt.allDataFvsS <- data.frame(date = dates, meanDifference = sin(seq_along(dates)*0.1))
vline <- function(x = 0, color = "red") {
list(
type = "line",
y0 = 0,
y1 = 1,
yref = "paper",
x0 = x,
x1 = x,
line = list(color = color)
)
}
p <- plot_ly(dt.allDataFvsS, x = dt.allDataFvsS$date, y = dt.allDataFvsS$meanDifference, mode = 'lines',
type = "scatter", line = list(color = " #007d3c")) %>%
layout(title = "Average Price Difference Forward vs. Spot", xaxis = list(title = "Date"),
yaxis = list(title = "EUR / MWh"))
p %>% layout(shapes = list(vline(as.Date("2018-10-01"))))
Based on this answer.
Related
I wish to add scatterplots to an existing 3D scatterplot in R using plot_ly.
I am generating data from Normal distribution of length 219. Then I want to plot and add scatter plots corresponding to the indices 80, 150 and 195 of the variables on the same graph with a different color (red in my case).
I used the following codes -
library(plotly)
index <- c(80, 150, 195)
set.seed(4991)
data1 <- rnorm(219,9,1.5)
data2 <- rnorm(219,2,1)
timeline <- 1:length(data1)
plot_ly(x=data1, y=data2, z=timeline, type="scatter3d", mode="markers")%>%
layout(scene = list(xaxis = list(title = 'cases per day'),
yaxis = list(title = 'deaths per day'),
zaxis = list(title = 'observation #')))%>%
add_trace(x=data1[index],y=data2[index],z=timeline[index], type="scatter3d", mode = "markers", marker = list(size = 5, color = "red", symbol = 104))
Snapshot of the output looks like this -
However if I use the color=timeline option in the plot_ly section,
plot_ly(x=data1, y=data2, z=timeline, type="scatter3d", mode="markers",color=timeline)%>%
layout(scene = list(xaxis = list(title = 'cases per day'),
yaxis = list(title = 'deaths per day'),
zaxis = list(title = 'observation #')))%>%
add_trace(x=data1[index],y=data2[index],z=timeline[index], type="scatter3d", mode = "markers", marker = list(size = 5, color = "red", symbol = 104))
I get the following error
Error:
! Tibble columns must have compatible sizes.
• Size 3: Columns `x`, `y`, and `z`.
• Size 219: Column `color`.
ℹ Only values of size one are recycled.
Run `rlang::last_error()` to see where the error occurred.
I want to plot the 3D scatterplot with color=timeline option and then add the scatterplot in red.
Any help is appreciated.
The variable timeline is all unique values, which doesn't align with your desire to have the three values colored. What you need is a grouping variable (i.e., yes or no, a or b, etc.)
I made a control.
timeline1 <- rep("A", length(data1))
timeline1[index] <- "B"
summary(timeline1 %>% as.factor())
# A B
# 216 3
Then I made my graph. One trace- with specific colors designated. I used Plotly's blue to keep it consistent with your question.
# '#1f77b4' is the Plotly blue (muted blue)
plot_ly(x = data1, y = data2, z = timeline, type = "scatter3d", mode = "markers",
color = timeline1, colors = setNames(c('#1f77b4', "red"), nm = c("A", "B"))) %>%
layout(scene = list(xaxis = list(title = 'cases per day'),
yaxis = list(title = 'deaths per day'),
zaxis = list(title = 'observation #')))
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)
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
I am trying to reproduce this Gantt chart with the plotly in R ( the chart I want). I have a dataframe with 6 columns and I want to have text on the y axis and months with years on x axis. Based on my dataframe I have the following :
one=c('bla','bla','bla',
'bla','bla','bla','bla','bla','bla','bla',
'bla','bla')
two=c('09/25/2017','10/02/2017','11/15/2017','11/29/2017','01/01/2018','01/01/2018','04/01/2018','07/01/2018','09/01/2018','09/01/2018',
'08/01/2020','09/01/2020')
three=c(1102,55,46,214,181,181,122,62,700,700,31,30)
four=c('bla','bla','bla',
'bla','bla','bla','bla',
'bla','bla','bla'
,'bla','bla')
five=c('A','B','C','D','E','F','G','H','E','I','J','E')
df=data.frame(one,two,three,four,five)
df$two =as.Date(df$two,"%m/%d/%Y")
client = "my example"
# Choose colors based on number of resources
cols <- RColorBrewer::brewer.pal(length(unique(df$five)), name = "Set3")
df$color <- factor(df$five, labels = cols)
# Initialize empty plot
p <- plot_ly()
# Each task is a separate trace
# Each trace is essentially a thick line plot
# x-axis ticks are dates and handled automatically
for(i in 1:(nrow(df))){
p <- add_trace(p,
x = c(df$two[i], df$two[i] + df$three[i]), # x0, x1
y = c(i, i), # y0, y1
mode = "lines",
line = list(color = df$color[i], width = 20),
showlegend = F,
hoverinfo = "text",
# Create custom hover text
text = paste("Task: ", df$one[i], "<br>",
"Duration: ", df$three[i], "days<br>",
"Resource: ", df$five[i]),
evaluate = T # needed to avoid lazy loading
)
}
# Add information to plot and make the chart more presentable
p <- layout(p,
# Axis options:
# 1. Remove gridlines
# 2. Customize y-axis tick labels and show task names instead of numbers
xaxis = list(showgrid = F, tickfont = list(color = "#e6e6e6")),
yaxis = list(showgrid = F, tickfont = list(color = "#e6e6e6"),
tickmode = "array", tickvals = 1:nrow(df), ticktext = unique(df$one),
domain = c(0, 0.9)),
# Annotations
annotations = list(
# Add total duration and total resources used
# x and y coordinates are based on a domain of [0,1] and not
# actual x-axis and y-axis values
list(xref = "paper", yref = "paper",
x = 0.80, y = 0.1,
text = paste0("Total Duration: ", sum(df$three), " days<br>",
"Total Resources: ", length(unique(df$five)), "<br>"),
font = list(color = "#ffff66", size = 12),
ax = 0, ay = 0,
align = "left"),
# Add client name and title on top
list(xref = "paper", yref = "paper",
x = 0.1, y = 1, xanchor = "left",
text = paste0("Gantt Chart: ", client),
font = list(color = "#f2f2f2", size = 20, family = "Times New Roman"),
ax = 0, ay = 0,
align = "left")
),
plot_bgcolor = "#333333", # Chart area color
paper_bgcolor = "#333333") # Axis area color
p
the first column (one) is a text
So my questions are:
How can I get the text from tasks (column one) on my y axis (instead of numbers)?
How can I get all the months on x axis?
Thank you.
Answer for question 1:
The reason your current code doesn't do what you would like is because of this:
ticktext = unique(df$one)
Since df$one contains 12 identical values, there is only 1 unique value, and hence not 12 as you would need. To fix this, you can either just use ticktext = df$one or make sure that your labels in df$one are unique (as is the case in the example you linked to). For example, changing df$one to bla1,bla2, ..., bla12 would work for your current example.
And question 2:
To specify the tick interval on your x-axis, you can use the dtick argument. In your case, this would result in the following addition to your line of code for the x-axis:
xaxis = list(showgrid = F, tickfont = list(color = "#e6e6e6"),
dtick = "M1")
where the M is to specify that you want intervals in months, and the 1 specifies that you want the interval to be 1 month (shocking!). FYI, this will automatically change the direction of the tick labels to vertical, if you would like to adapt this, you can use the tickangle argument.
I'm trying to overlay a line chart and bar chart in plotly (with a vertical line designating an important date) and I'm encountering this issue where the two zero lines are offset instead of on the same line. I've tried messing around with the overlaying = 'y' option within layout and tried changing the order of the three trace components but nothing seems to help. Any ideas how to fix? Below is my code with dummy data:
(Also, bonus points if you can fix my legend-overlapping-y2axis issue)
date <- seq(as.Date("2015/6/1"), by = "month", length.out = 19)
wires_mnth <- c(rep(0,8),100000,750000,1200000,2500000,3100000,5500000,7500000,8000000,9900000,11300000,11000000)
wires_cnt <- c(rep(0,8),100,200,250,325,475,600,750,800,1000,1150,1200)
data <- data.frame(date, wires_mnth)
plot_ly(data) %>%
add_trace(x = ~date, y = ~wires_cnt, type = 'bar', name = 'Wires Count',
yaxis = 'y2', opacity = .5) %>%
add_trace(x = ~date, y = ~wires_mnth, type = 'scatter', mode = 'lines', name
= 'Monthly Wires') %>%
add_trace(x = c(2016,2016), y = c(0, 12000000), type = 'scatter', mode =
"lines", name = 'Sanctions Removed') %>%
layout(title = 'Monthly Aggregate Wire Transfers to Iran',
xaxis = list(title = ''),
yaxis = list(side = 'left', title = 'Wire Amounts (USD)', showgrid =
FALSE, zeroline = FALSE),
yaxis2 = list(side = 'right', overlaying = 'y', title = 'Wires Count',
showgrid = FALSE, zeroline = FALSE)
)
You could add rangemode='nonnegative' to your layout or specify the range manually via range=list(0, max(wires_mnth).
For your bonus question, you can set the x-position of the legend, e.g.
legend = list(x = 1.2)