I am wondering how to give difference subtitles for the subplots using plot_ly. Any hint please. I got one title BB in this case. Thanks.
p <- subplot(
plot_ly(economics, x = date, y = uempmed)%>%layout(showlegend = FALSE, title="AA"),
plot_ly(economics, x = date, y = unemploy)%>%layout(showlegend = FALSE, title="BB"),
margin = 0.05
)
Instead of positioning "by hand" (i.e., #d-roy's answer), you can now leverage subplot()'s ability to reposition paper referenced things like annotations (as well as shapes, images, etc).
library(plotly)
library(dplyr)
my_plot <- . %>%
plot_ly(x = ~date, y = ~value) %>%
add_annotations(
text = ~unique(variable),
x = 0.5,
y = 1,
yref = "paper",
xref = "paper",
xanchor = "middle",
yanchor = "top",
showarrow = FALSE,
font = list(size = 15)
)
economics_long %>%
group_by(variable) %>%
do(p = my_plot(.)) %>%
subplot(nrows = NROW(.), shareX = TRUE)
The title attribute in layout refers to the title for the entire plotting surface, so there can only be one. However, we can use text annotations to create "titles" for your subplots, for example:
p <- subplot(
plot_ly(economics, x = date, y = uempmed)%>%layout(showlegend = FALSE),
plot_ly(economics, x = date, y = unemploy)%>%layout(showlegend = FALSE),
margin = 0.05
)
p %>% layout(annotations = list(
list(x = 0.2 , y = 1.05, text = "AA", showarrow = F, xref='paper', yref='paper'),
list(x = 0.8 , y = 1.05, text = "BB", showarrow = F, xref='paper', yref='paper'))
)
I was able to use layout(annotations()) scheme not on the subplot() but on the plot_ly objects themselves. This gives a slightly better placement for dynamic visualization. So to rework #d-roy's answer:
p <- subplot(
plot_ly(economics, x = date, y = uempmed) %>%
layout(annotations = list(x = 0.2 , y = 1.05, text = "AA", showarrow = F,
xref='paper', yref='paper'),
showlegend = FALSE),
plot_ly(economics, x = date, y = unemploy) %>%
layout(annotations = list(x = 0.2 , y = 1.05, text = "AA", showarrow = F,
xref='paper', yref='paper'),
showlegend = FALSE),showlegend = FALSE))`.
Please note that in this case coordinates of the annotations are the same for each annotation because they are referring to each subplot and not the combined plot as a whole.
Related
I'm trying to create a 2x2 subplot, with both plots in each column having the same y-axis title, like this :
i.e. one 'title' (here called annotations, cf. later) for the left column (blue+green) and one for the right column (yellow+red).
I can easily have a yaxis title for each plot but I'm stumped as to making shared ones.
I tried using annotations, like this (this is the code used to render the plot shown above) :
if (!require("plotly")) install.packages("plotly")
library(plotly)
group <- c("a", "b", "c")
values <- c(0, 5, 10)
df <- data.frame(group, values)
plot <- df %>%
plot_ly() %>%
add_trace(x = ~group, y = ~values, type = "scatter", mode = "line") %>%
layout(yaxis = list(ticks = "outside"), xaxis = list(showline = TRUE))
plot
subdf1 <- subplot(plot, plot, nrows = 1, margin = 0.06)
subdf2 <- subplot(plot, plot, nrows = 1, margin = 0.06)
subdf <- subplot(subdf1, subdf2, nrows = 2, margin = 0.06) %>%
layout(annotations = list(list(x = -0.1, y = 0.5, text = "<b>First annotation</b>", xref = "paper", yref = "paper", xanchor = "center", yanchor = "center", showarrow = FALSE, textangle = -90, font = list(color = "black", size = 16)),
list(x = 0.48, y = 0.5, text = "<b>Second annotation</b>", xref = "paper", yref = "paper", xanchor = "center", yanchor = "center", showarrow = FALSE, textangle = -90, font = list(color = "black", size = 16))))
subdf
My main gripe with this method is that when the plot is resized, the annotations (mainly the first one, in the negative range for x-axis placement) move around the x-axis.
Same plot but wider :
I used xref = "paper" as I thought it meant the whole plot area i.e. the whole white background, but in such case, my annotation wouldn't disappear (and wouldn't be in negatives, but I'm possibly not thinking about this the right way). I did try using xref = x but it won't go into negatives and instead just push the data to the right.
So all in all, two questions :
Is there a native way to have a shared axis title for subplots?
If not, is there a way to make sure that my annotations stay in the same relative place as the plots and axes when resizing the subplot?
If you aren't tied to using plotly, this can be done in a straightforward way using faceting in ggplot. It may require some rearranging of your data into tidy format but gives some serious flexibility while plotting!
library(ggplot2)
group <- c("a", "b", "c")
values <- c(0, 5, 10)
df <- data.frame(group, values)
df <- data.frame(group = rep(c('a','b','c'), 4),
values = rep(c(0,5,10), 4),
facet = rep(c('W','X','Y','Z'), each = 3))
ggplot(df, aes(x = group, y = values, colour = facet, group = 1)) +
geom_line(size = 1.1) +
geom_point(size = 2) +
facet_wrap(~facet) +
theme_bw() +
labs(x = 'Shared X axis title', y = 'Shared Y axis title', colour = 'Traces') +
theme(
strip.background = element_blank(),
strip.text.x = element_blank()
)
You could create a separate title in each layout of both subplots and combine them using titleY like this:
library(plotly)
library(dplyr)
group <- c("a", "b", "c")
values <- c(0, 5, 10)
df <- data.frame(group, values)
plot <- df %>%
plot_ly() %>%
add_trace(x = ~group, y = ~values, type = "scatter", mode = "line") %>%
layout(yaxis = list(ticks = "outside"), xaxis = list(showline = TRUE))
subdf1 <- subplot(plot, plot, nrows = 1) %>%
layout(yaxis = list(title = "First annotation"))
subdf2 <- subplot(plot, plot, nrows = 1) %>%
layout(yaxis = list(title = "Second annotation"))
subdf <- subplot(subdf1, subdf2, nrows = 2, titleY = TRUE)
subdf
Created on 2023-01-23 with reprex v2.0.2
Edit
Change margin in layout:
library(plotly)
library(dplyr)
group <- c("a", "b", "c")
values <- c(0, 5, 10)
df <- data.frame(group, values)
plot <- df %>%
plot_ly() %>%
add_trace(x = ~group, y = ~values, type = "scatter", mode = "line") %>%
layout(yaxis = list(ticks = "outside"), xaxis = list(showline = TRUE))
subdf1 <- subplot(plot, plot, nrows = 1, margin = 0.06)
subdf2 <- subplot(plot, plot, nrows = 1, margin = 0.06)
subdf <- subplot(subdf1, subdf2, nrows = 2, margin = 0.06) %>%
layout(margin = 0.01,
annotations = list(list(x = -0.1, y = 0.5, text = "<b>First annotation</b>", xref = "paper", yref = "paper", xanchor = "center", yanchor = "center", showarrow = FALSE, textangle = -90, font = list(color = "black", size = 16)),
list(x = 0.48, y = 0.5, text = "<b>Second annotation</b>", xref = "paper", yref = "paper", xanchor = "center", yanchor = "center", showarrow = FALSE, textangle = -90, font = list(color = "black", size = 16))))
subdf
Created on 2023-01-23 with reprex v2.0.2
How can I reproduce the following graph in plotly
library(dplyr)
library(ggplot2)
tibble(x =1:10, y = 1:10) %>%
ggplot(aes(x,y)) +
geom_line() +
scale_y_continuous(sec.axis = ~.*2)
I tried the following code based on this answer here
library(dplyr)
library(plotly)
tibble(x =1:10, y = 1:10) %>%
mutate(y2 = y*2) %>%
plot_ly() %>%
add_lines(x =~x, y =~y) %>%
add_lines(x= ~x, y=~y2,
yaxis = "y2", color = I("transparent"),
hoverinfo='skip', showlegend=FALSE) %>%
layout(yaxis2 = list(side = "right", overlaying = "y", showgrid = FALSE),
margin = list(r = 50))
While at first glance it appears to work, it only provides a partial solution, since if I interactively try to change the scale of the main (left) y axis on the produced graph (by dragging it up or down), the right axis does not move with the graph (because it is linked only to the second invisible graph). This of course is not acceptable as it does not allow using any of interactive features of plotly reliably which is the reason I wanted to use it to begin with instead of ggplot.
Edit: Just realized that this plotly solution does not seem to work at all in the case of non linear transformation between the axes (while ggplot handles it beautifully).
You just need to set up dtick and tick0 for plotly to have the same graph as ggplot2 one. See below;
library(plotly)
library(dplyr)
tibble(x =1:10, y = 1:10) %>%
mutate(y2 = y*2) -> df1
n0 <- 4
y0 <- max(df1$y)/n0
x0 <- max(df1$x)/n0
df1 %>%
plot_ly(data = . , x = ~x, y = ~y,
type = "scatter", mode = "lines", width = 800,
color = I("red"), name = "") %>%
add_trace(x = ~x, y = ~y2, yaxis = "y2",
color = I("red"), name = "") %>%
layout(yaxis = list(showline = FALSE, side = "left",
title = "", color = "red",
dtick = y0, tick0 = y0, fixedrange=TRUE),
yaxis2 = list(showline = FALSE, side = "right", overlaying = "y", position = 1,
title = "", anchor = "free", color = "blue",
dtick = 2*y0, tick0 = 2*y0, fixedrange=TRUE),
xaxis = list(showline = FALSE, zeroline = FALSE, title = "",
dtick = x0, tick0 = x0),
showlegend = FALSE,
margin = list(l = 50, r = 50, b = 50, t = 50, pad = 4)
)
Created on 2020-06-19 by the reprex package (v0.3.0)
I have a list of figures created with R's plotly, just as an example:
library(plotly)
library(dplyr)
set.seed(1)
data.df <- data.frame(val = c(rnorm(100,0,1),rnorm(100,1,1)), group = c(rep("A",100),rep("B",100)))
density.df <- do.call(rbind,lapply(levels(data.df$group),function(g){
dens <- density(dplyr::filter(data.df,group == g)$val)
data.frame(x = dens$x, y = dens$y, group = g)
}))
plot.list <- lapply(1:5,function(x)
plot_ly(x = density.df$x, y = density.df$y, type = 'scatter', mode = 'lines',color = density.df$group, showlegend = (x == 5)) %>%
layout(xaxis = list(title= "Value", zeroline = F), yaxis = list(title = "Density", zeroline = F))
)
Which I'd like to put together horizontally, where there will be only a single shared x-axis label and a single shared y-axis label.
I'm using:
plotly::subplot(plot.list, nrows = 1, shareX = T, shareY = T, titleX = T, titleY = T)
And getting:
Is it not possible to get a single x-axis label in a horizontal plot?
The same occurs for the y-axis label if I change the nrows argument value from 1 to 5.
You can manually add an annotation
https://community.plot.ly/t/subplots-how-to-add-master-axis-titles/13927/5
myplotly(df) %>%
add_annotations(
text = "my x title",
x = 0.5,
y = 0,
yref = "paper",
xref = "paper",
xanchor = "center",
yanchor = "bottom",
yshift = -35,
showarrow = FALSE,
font = list(size = 15)
)
I made a boxplot:
dat %>%
plot_ly(y = ~xval, color = ~get(col), type = "box",
boxpoints = "all", jitter = 0.7,
pointpos = 0, marker = list(size = 3),
source = shiny_source, key = shiny_key,
hoverinfo = 'text', text = txt)
but problem is that jittered points are not interactive and cannot be marked separately, so I came with an idea to add those points using add_markers:
dat %>%
plot_ly(y = ~xval, color = ~get(col), type = "box",
boxpoints = FALSE, jitter = 0.7,
pointpos = 0, marker = list(size = 3),
source = shiny_source, key = shiny_key,
hoverinfo = 'col', text = txt
) %>%
add_markers(x = ~get(col), y = ~varval, size = I(6))
but now points are in straight line and I'd like to add some jitter (for example by using beeswarm package). But I don't know how to get coordinates of qualitative variable IC0 on X axis. Any ideas?
I find myself in the same potential case often with plotly and ggplot2-- 3 lines of code to get 90% of what I want, and 30 lines of code to get the aesthetics just right.
One potential solution/workaround: Take advantage of R's "factors are coded with integers" paradigm, plot everything on a numeric scale, and then cover your tracks by hiding x labels and x hover values.
dat <- data.frame(xval = sample(100,1000,replace = TRUE),
group = as.factor(sample(c("a","b","c"),1000,replace = TRUE)))
dat %>%
plot_ly() %>%
add_trace(x = ~as.numeric(group),y = ~xval, color = ~group, type = "box",
hoverinfo = 'name+y') %>%
add_markers(x = ~jitter(as.numeric(group)), y = ~xval, color = ~group,
marker = list(size = 6),
hoverinfo = "text",
text = ~paste0("Group: ",group,
"<br>xval: ",xval),
showlegend = FALSE) %>%
layout(legend = list(orientation = "h",
x =0.5, xanchor = "center",
y = 1, yanchor = "bottom"
),
xaxis = list(title = "Group",
showticklabels = FALSE))
Yields the following
I'm making some figures with ggplotly() and have noticed that facet_wrap and facet_grid causes each item in the legend to be repeated by the number of facets. Is there a way to stop this?
For example:
library("ggplot2")
library("plotly")
diamonds = diamonds[diamonds$cut %in% c("Fair", "Good"),]
dia = ggplot(diamonds, aes(x = cut)) +
geom_bar(aes(stat = "identity", fill = cut)) +
facet_grid(.~color)
ggplotly(dia)
The ?plotly documentation isn't very elaborate, and none of these have legends.
Here's what comes up when I just type ggplotly if that gives any insight:
function (p = ggplot2::last_plot(), filename, fileopt, world_readable = TRUE)
{
l <- gg2list(p)
if (!missing(filename))
l$filename <- filename
if (!missing(fileopt))
l$fileopt <- fileopt
l$world_readable <- world_readable
hash_plot(p$data, l)
}
UPDATE
Issues appear fixed with Plotly 3.6.0 -- 16 May 2016
Due to the ggplotly bug for geom_bar, which distorts the data for the bars, there may not be a good way to do this. For this particular case, facet is not needed. You can use plot_ly() to build an effective plot.
Plot_ly
require(plotly)
require(dplyr)
d <- diamonds[diamonds$cut %in% c("Fair", "Good"),] %>%
count(cut, color)
plot_ly(d, x = color, y = n, type = "bar", group = cut)
Use Plotly subplot()
If this plot type is a must, you can build a facet-like plot using Plotly's subplot. It's not pretty.
d2 <- diamonds[diamonds$cut %in% c("Fair", "Good"),] %>%
count(cut, color) %>%
transform(color = factor(color, levels=rev(levels(color)))) %>%
mutate(id = as.integer(color))
p <- plot_ly(d2, x = cut, y = n, type = "bar", group = color, xaxis = paste0("x", id), marker = list(color = c("#0000FF","#FF0000"))) %>%
layout(yaxis = list(range = range(n), linewidth = 0, showticklabels = F, showgrid = T, title = ""),
xaxis = list(title = ""))
subplot(p) %>%
layout(showlegend = F,
margin = list(r = 100),
yaxis = list(showticklabels = T),
annotations = list(list(text = "Fair", showarrow = F, x = 1.1, y = 1, xref = "paper", yref = "paper"),
list(text = "Good", showarrow = F, x = 1.1, y = 0.96, xref = "paper", yref = "paper")),
shapes = list(list(type = "rect", x0 = 1.1, x1 = 1.13, y0 = 1, y1 = 0.97, line = list(width = 0), fillcolor = "#0000FF", xref = "paper", yref = "paper"),
list(type = "rect", x0 = 1.1, x1 = 1.13, y0 = 0.96, y1 = 0.93, line = list(width = 0), fillcolor = "#FF0000", xref = "paper", yref = "paper")))
You could just turn off the guide/legend in this case as you don't really need it.
library("ggplot2")
library("plotly")
diamonds = diamonds[diamonds$cut %in% c("Fair", "Good"),]
dia = ggplot(diamonds, aes(x = cut)) +
geom_bar(aes(stat = "identity", fill = cut)) +
guides(fill=FALSE) +
facet_grid(.~color)
ggplotly(dia)