I would like to make a predefined layout that I can use for my plot functions that I have created so as not to repeat myself everytime I make a plot. For example, I tried to do sth like the following which doesn't work and gives an error:
custom_layout <- function(){
plotly::layout(
xaxis = list(title = ""),
yaxis = list(title = ""),
title = list(text = title, y = 0.98)
)
}
plot_bar <- function(title, dt, x, y, fill){
plot_ly(dt, x = ~x, y = ~y, type = "bar",
color = ~ fill, split = ~ fill) %>%
custom_layout()}
plot_line <- function(title, dt, x, y, fill){
plot_ly(dt, x = ~x, y = ~y, type="scatter",
split = ~fill, mode="lines+markers") %>%
custom_layout()}
I call these 2 plotting functions multiple times in my code. I have also other predefined plotting functions like plot_line and plot_bar and I use the same layout for them as well but now manually adding the layout like in the following:
plot_bar <- function(title, dt, x, y, fill){
plot_ly(dt, x = ~x, y = ~y, type = "bar",
color = ~ fill, split = ~ fill) %>%
layout(
xaxis = list(title = ""),
yaxis = list(title = ""),
title = list(text = title, y = 0.98)
Ideally, I would like to define it like in the first scenario with a predefined layout that I could use later for every plotting function which is not working for me. Is there a way to do it with native plotly and not ggplot2?
You need to make the custom_layout() function take p as its first argument (just like layout() does).
library(tibble)
dt <- tibble(x=1:4, y=3:6, fill=1:4)
custom_layout <- function(p, title){
plotly::layout(p,
xaxis = list(title = ""),
yaxis = list(title = ""),
title = list(text = title, y = 0.98)
)
}
plot_bar <- function(title, dt, x, y, fill){
plot_ly(dt, x = ~x, y = ~y, type = "bar",
color = ~ fill, split = ~ fill) %>%
custom_layout(title=title)}
plot_bar(title="myplot", dt, "x", "y", "fill")
Related
I want to prepare a subplot where each facet is a separate dual y-axis plot of one variable against the others. So I make a base plot p and add secondary y-axis variable in a loop:
library(rlang)
library(plotly)
library(tibble)
dual_axis_lines <- function(data, x, y_left, ..., facets = FALSE, axes = NULL){
x <- rlang::enquo(x)
y_left <- rlang::enquo(y_left)
y_right <- rlang::enquos(...)
y_left_axparms <- list(
title = FALSE,
tickfont = list(color = "#1f77b4"),
side = "left")
y_right_axparms <- list(
title = FALSE,
overlaying = "y",
side = "right",
zeroline = FALSE)
p <- plotly::plot_ly(data , x = x) %>%
plotly::add_trace(y = y_left, name = quo_name(y_left),
yaxis = "y1", type = 'scatter', mode = 'lines',
line = list(color = "#1f77b4"))
p_facets <- list()
for(v in y_right){
p_facets[[quo_name(v)]] <- p %>%
plotly::add_trace(y = v, name = quo_name(v),
yaxis = "y2", type = 'scatter', mode = 'lines') %>%
plotly::layout(yaxis = y_left_axparms,
yaxis2 = y_right_axparms)
}
p <- subplot(p_facets, nrows = length(y_right), shareX = TRUE)
return(p)
}
mtcars %>%
rowid_to_column() %>%
dual_axis_lines(rowid, mpg, cyl, disp, hp, facets = TRUE)
However, the resulting plots have all the secondary y-axis variables cluttered in the first facet.
The issue seems to be absent when I return p_facets lists that goes into subplot as each plot looks like below:
How can I fix this issue?
Okay, I followed the ideas given in this github issue about your bug.
library(rlang)
library(plotly)
library(tibble)
dual_axis_lines <- function(data, x, y_left, ..., facets = FALSE, axes = NULL){
x <- rlang::enquo(x)
y_left <- rlang::enquo(y_left)
y_right <- rlang::enquos(...)
## I removed some things here for simplicity, and because we want overlaying to vary between subplots.
y_left_axparms <- list(
tickfont = list(color = "#1f77b4"),
side = "left")
y_right_axparms <- list(
side = "right")
p <- plotly::plot_ly(data , x = x) %>%
plotly::add_trace(y = y_left, name = quo_name(y_left),
yaxis = "y", type = 'scatter', mode = 'lines',
line = list(color = "#1f77b4"))
p_facets <- list()
## I needed to change the for loop so that i can have which plot index we are working with
for(v in 1:length(y_right)){
p_facets[[quo_name(y_right[[v]])]] <- p %>%
plotly::add_trace(y = y_right[[v]], x = x, name = quo_name(y_right[[v]]),
yaxis = "y2", type = 'scatter', mode = 'lines') %>%
plotly::layout(yaxis = y_left_axparms,
## here is where you can assign each extra line to a particular subplot.
## you want overlaying to be: "y", "y3", "y5"... for each subplot
yaxis2 = append(y_right_axparms, c(overlaying = paste0(
"y", c("", as.character(seq(3,100,by = 2)))[v]))))
}
p <- subplot(p_facets, nrows = length(y_right), shareX = TRUE)
return(p)
}
mtcars %>%
rowid_to_column() %>%
dual_axis_lines(rowid, mpg, cyl, disp, hp, facets = TRUE)
Axis text the same color as the lines.
For this you would need two things. You would need to give a palette to your function outside of your for-loop:
color_palette <- colorRampPalette(RColorBrewer::brewer.pal(10,"Spectral"))(length(y_right))
If you don't like the color palette, you'd change it!
I've cleaned up the for-loop so it's easier to look at. This is what it would now look like now so that lines and axis text share the same color:
for(v in 1:length(y_right)){
## here is where you can assign each extra line to a particular subplot.
## you want overlaying to be: "y", "y3", "y5"... for each subplot
overlaying_location = paste0("y", c("", as.character(seq(3,100,by = 2)))[v])
trace_name = quo_name(y_right[[v]])
trace_value = y_right[[v]]
trace_color = color_palette[v]
p_facets[[trace_name]] <- p %>%
plotly::add_trace(y = trace_value,
x = x,
name = trace_name,
yaxis = "y2",
type = 'scatter',
mode = 'lines',
line = list(color = trace_color)) %>%
plotly::layout(yaxis = y_left_axparms,
## We can build the yaxis2 right here.
yaxis2 = eval(
parse(
text = "list(side = 'right',
overlaying = overlaying_location,
tickfont = list(color = trace_color))")
)
)
}
I want to rename labels in a heatmap. for example:
instead of the label says "x:", I want the label to say "Hour:"
instead of the label says "y:", I want the label to say "Day:"
Library(plotly)
p <- plot_ly(z = volcano, colors = colorRamp(c("red", "green")), type = "heatmap")
furthermore, it would be useful, for example if we use a transformation of data in order to intensify contrast, still the html interactive label show real data.
Example
What about
library(plotly)
dat <- expand.grid(x = 1:nrow(volcano), y = 1:ncol(volcano))
dat$z <- c(volcano)
plot_ly(height = 500) %>%
layout(autosize = FALSE,
xaxis=list(title = "Hour", titlefont = list(size=20)),
yaxis=list(title = "Day", titlefont = list(size=20))) %>%
add_trace(data = dat, x = ~x, y = ~y, z = ~z, type = "heatmap",
hoverinfo = 'text',
text = ~paste("Hour:", dat$x,
"<br> Day:", dat$y,
"<br> z:", dat$z))
I have written below snippet of code to plot dual-axis charts using plotly in R.
Code:
## Date creation
dtMasterWithtotals <- data.table("Period_Month" = c('7/1/2017', '9/1/2017'), A = c(171, 448), B = c(0, 655), C = c(476, 812))
## Vectors to select categories for primary and secondary axis
vecPrimaryAxis <- c("A", "B")
vecSecondaryAxis <- c("C")
## X-axis properties
ax <- list(
type = "category",
categoryorder = "array",
categoryarray = dtMasterWithtotals[order(as.Date(dtMasterWithtotals[, Period_Month])),],
showgrid = TRUE,
showline = TRUE,
autorange = TRUE,
showticklabels = TRUE,
ticks = "outside",
tickangle = 0
)
## arrange columns in an order – TBD
## The plot function below assumes that the data will be in format, Period_Month, A, B,C.
## Plot function
plot <- plot_ly(dtMasterWithtotals, x = ~Period_Month, y = dtMasterWithtotals[[2]], type = "scatter", mode = 'lines', name = names(dtMasterWithtotals)[2])
if(length(vecPrimaryAxis) > 1){
t <- (3 + length(vecPrimaryAxis) - 2)
for (i in 3:t){
plot <- add_trace(plot, x = ~Period_Month, y = dtMasterWithtotals[[i]], type = "scatter", mode = "lines", name = names(dtMasterWithtotals)[i]) %>%
layout(xaxis = ax)
}
}
if(length(vecSecondaryAxis) > 0){
p <- 2 + length(vecPrimaryAxis)
q <- p + length(vecSecondaryAxis) - 1
for (j in (p:q)){
plot <- add_trace(plot, x = ~Period_Month, y = dtMasterWithtotals[[j]], type = "scatter", mode = "lines", yaxis = "y2", name = names(dtMasterWithtotals)[j]) %>%
layout(yaxis2 = list(overlaying = "y", side = "right"), xaxis = ax)
}
}
When trying to plot A and B on primary y-axis and C on secondary y-axis, the last trace (in this case C) overlaps the second trace (in this case B), resulting in two traces instead of three. However, on hover the new trace shows the correct value labels, but comes up incorrectly (at the wrong position) in the visualization.
Let me know if you require any other detail.
Thanks.
If I understand correctly what you want, in fact, there is no problem with your code. You just need to set manually your y and y2 axis. To make it easier to visualize I simply reversed the y2 axis. If you try this:
plot_ly() %>%
add_lines(data=dtMasterWithtotals, x = ~Period_Month, y = ~A, name = "A") %>%
add_lines(data=dtMasterWithtotals, x = ~Period_Month, y = ~B, name = "B") %>%
add_lines(data=dtMasterWithtotals, x = ~Period_Month, y = ~C, name = "C", yaxis = "y2") %>%
layout(xaxis = ax, yaxis2 = list(overlaying = "y", side = "right", autorange="reversed"))
It will give you this:
As you can see, all three lines are visible and all three displayed the right values.
I have build a surface chart with plotly and I am trying to have hoverinfo based on my own text. Curiously it is not working anymore.
library(plotly)
x <- rnorm(10)
y <- rnorm(10)
z <- outer(y, x)
p <- plot_ly(x = ~x, y = ~y, z = ~z, type = "surface",
text = ~paste0("My X = ", x, "\n My Y = ", y, "\n My Z = ", z),
hoverinfo = "text") %>% layout(dragmode = "turntable")
print(p)
Although
p <- plot_ly(x = ~x, y = ~y, z = ~z, type = "surface") %>% layout(dragmode = "turntable")
works well.
I have also tried to substitute \n by <br /> with no effect.
I am using R 3.4.0 and plotly 4.7.0 on macOS Sierra.
Any suggestions?
Plotly's labeling seems finicky with custom labels using the ~paste() syntax because it is trying to build a new data structure with your inputs (three vectors and one matrix), but if you pass in custom labels as a matrix with the same dimensions it will work.
custom_txt <- paste0("My X = ", rep(x, times = 10),
"</br> My Y = ", rep(y, each = 10), # correct break syntax
"</br> My Z = ", z) %>%
matrix(10,10) # dim must match plotly's under-the-hood? matrix
plot_ly(x = ~x, y = ~y, z = ~z, type = "surface",
text = custom_txt,
hoverinfo = "text") %>%
layout(dragmode = "turntable")
I'm learning R. With the help of Maximilian Peters' answer, I wrote a custom function to make a bunch of plotly scatterplots. I want to label the x and y axis titles with the column names from those variables.
Here is the code:
library(plotly)
my_plot <- function(x, y, ...) {
plot_ly(y = y, x = x, ...) %>%
add_markers() %>%
layout(xaxis = list(title = deparse(substitute(x))),
yaxis = list(title = deparse(substitute(y))))
}
my_plot(y = mtcars$mpg, x = mtcars$disp)
This sets the xaxis title to "x", but I want it to be "disp".
I also tried this code:
my_plot <- function(data, x, y, ...) {
plot_ly(y = data[[y]], x = data[[x]], ...) %>%
add_markers() %>%
layout(xaxis = list(title = deparse(substitute(data[[x]]))),
yaxis = list(title = deparse(substitute(data[[y]]))))
}
my_plot(data = mtcars, y = 'mpg', x = 'disp')
This sets the xaxis title to "data[[x]]".
Oops, I posted too quick. The solution was simple.
my_plot <- function(data, x, y, ...) {
plot_ly(y = data[[y]], x = data[[x]], ...) %>%
add_markers() %>%
layout(xaxis = list(title = x),
yaxis = list(title = y))
}
my_plot(data = mtcars, y = 'mpg', x = 'disp')