Using ggplotly with ggplot - r

I have a script using ggplotly to produce a couple of interactive charts. I then try to produce addition charts that are not interactive using ggplot. They refuse to plot even if I introduce Sys.sleep() pauses.
Is there a reason why one cannot mix the interactive Javescript ggplotly plots with non-interactive ggplot plots in the same script? I cannot find anything answers regarding this question.
Update: Here is a mini-version of the code I am using. Actually, it doesn't work in RStudio. The second plot appears to write on top of the first one. Whatever plot is created last appears to overwrite the previous plot. If I remove the call to 'ggplotly' and just print the ggplot construction, all is well. It has something to do with the call to ggplotly.Conversely, if I use ggplotly for both charts, all is well. Seems they don't mix.
library("ggplot2")
library("plotly")
test_data <- data.frame(A = c(1,5,7,4,2),
B = c(3,3,6,8,4),
C = c(6,2,9,4,5))
my_dates <- as.Date(c("2010-01-01", "2010-02-01",
"2010-03-01", "2010- 4-01",
"2010-05-01"))
xts_data <- xts(test_data, order.by = my_dates)
p <- autoplot(xts_data, facets = NULL) +
guides(color = guide_legend(override.aes = list(size = 2))) +
geom_line(size = 1)
print(ggplotly(p))
new_df <- data.frame(P = c(70, 70, 70),
Category = c("A", "B", "C"),
Value = c(5, 15, 10))
p <- ggplot(data = new_df, aes(
x = Category, y = Value)) +
geom_bar(position = position_dodge(), stat = "identity")
print(p)

The "problem" I was having is the ggplot chart is displayed in the Plot pane and the ggplotly charts are displayed in the Viewer pane. Problem solved.

Related

getting colour scale gradient to work with ggplot converted to ggplotly

I'm not able to correctly draw a colour aesthetic line in plotly, using a ggplot object. What am I missing?
library(ggplot2)
library(plotly)
df <- data.frame(val = as.numeric(LakeHuron), idx = 1:length(LakeHuron))
p <- ggplot(df, aes(x = idx, y = val, colour = val)) + geom_line()
p <- p + scale_color_gradient2(low="red", mid = "gold", high="green", midpoint = mean(df$val))
p
p2 <- ggplotly(p)
p2
p prints the correct expected output.
When I print the plotly object p2, I dont get the line points joining correctly?
The problem is when i add the colour aesthetic I think.
Versions:
plotly 4.9, ggplot2 3.1.1
This is due to a limitation / difference in how plotly works vs. ggplot. Looks like there's an open issue here updated August 2018 suggesting it's not possible within the same structure ggplot uses -- a single series in plotly can't currently have varying color. ("We don't allow per-segment coloring on line traces")
But fear not! We could construct the plot a little differently using geom_segment to specify each part of the line as a separate segment. This structure is a separate object for each segment and will convert over to plotly fine:
df <- data.frame(val = as.numeric(LakeHuron), idx = 1:length(LakeHuron))
p_seg <- ggplot(df, aes(x = idx, y = val,
xend = lead(idx), yend = lead(val),
colour = val)) +
geom_segment()
p_seg <- p_seg + scale_color_gradient2(low="red", mid = "gold", high="green", midpoint = mean(df$val))
p_seg
p2 <- ggplotly(p_seg)

Vertically combing multiple bar plots

I'm trying to use to vertically group bar plots, sharing their x-axes.
I thought of using R's plotly's subplot for that but running into an issue I hope someone here may have a solution for.
Here are example data which have 28 groups where I'm creating a bar plot over 4 families in each group and then trying to vertically combine them using plotly::subplot:
set.seed(1)
df <- data.frame(group = paste0("G",unlist(lapply(1:28,function(i) rep(i,4)))),
family = paste0("F",rep(1:4,28)),
log2n = log2(as.integer(runif(4*28,0,30))+1),
stringsAsFactors = F)
Creating the list of bar plots:
library(plotly)
library(dplyr)
groups <- unique(df$group)
y.range <- c(0,max(df$log2n))
plot.list <- lapply(1:length(groups),function(g){
group.df <- dplyr::filter(df,group == groups[g])
plot_ly(x=group.df$family,y=group.df$log2n,type='bar',name=group.df$family,color=group.df$family,showlegend=(g==length(groups))) %>%
layout(yaxis=list(range=y.range))
})
If I try:
plotly::subplot(plot.list,shareX=T,nrows=length(plot.list))
I get:
So it seems like some sort of an overflow.
I gradually cut down on the number of plots in plot.list that I run subplot on and when reached 19 it seemed to stop 'overflowing':
plotly::subplot(plot.list[1:19],shareX=T,nrows=19)
Any idea if there's hope to get all 28 bar plots without overflowing?
Thanks a lot
I would generate the figure with ggplot and then convert it to plotly (or save it as a picture file) with proper size arguments.
library(plotly)
library(tidyverse)
g <- ggplot(df,
aes(x = family, y = log2n, fill = family)) +
geom_bar(stat = 'identity') +
facet_wrap(~group, ncol = 1) +
theme_minimal() +
theme(legend.position = "none")
ggsave(g, file = "temp.png", width = 4, height = 40)
ggplotly(g, width = 400, height = 4000)

ggplotly fails with geom_vline() with xintercept Date value

Trying to use ggplotly to graph time series data with a vertical line to indicate dates of interest.
Call fails with Error in Ops.Date(z[[xy]], 86400000) : * not defined for "Date" objects. I have tried unsuccessfully using both the latest CRAN and development versions of ggplot2 (as per plotly recommendation). Other SO questions (e.g., ggplotly and geom_bar when using dates - latest version of plotly (4.7.0)) do not address my concerns.
As illustrated below with plot object p - both ggplot and ggplotly work as expected. However, when a geom_vline() is added to the plot in p2, it only works correctly in ggplot, failing when calling ggplotly(p2).
library(plotly)
library(ggplot2)
library(magrittr)
set.seed(1)
df <- data.frame(date = seq(from = lubridate::ymd("2019-01-01"), by = 1, length.out = 10),
y = rnorm(10))
p <- df %>%
ggplot(aes(x = date, y = y)) +
geom_line()
p ## plots as expected
ggplotly(p) ## plots as expected
p2 <- p + geom_vline(xintercept = lubridate::ymd("2019-01-08"), linetype = "dashed")
p2 ## plots as expected
ggplotly(p2) ##fails
I just solved this using #Axeman's suggestion. In your case, you can just replace the date:
lubridate::ymd("2019-01-01")
becomes
as.numeric(lubridate::ymd("2019-01-01"))
Not pretty, but it works.
For future reference:
The pop-up window for vertical lines created via date (or POSIX*) to numeric conversions is rather blank. This is particularly valid for POSIX* applications where the exact time can often not be read off directly.
In case you need more significant pop-up content, the definition of a text aesthetic could be helpful (just ignore the 'unknown aesthetics' warning as it doesn't seem to apply). Then, simply specify what you want to see during mouse hover via the tooltip argument, ie. rule out xintercept, and you're all set.
p2 = p +
geom_vline(
aes(
xintercept = as.numeric(lubridate::ymd("2019-01-08"))
, text = "date: 2019-01-08"
)
, linetype = "dashed"
)
ggplotly(p2, tooltip = c("x", "y", "text"))

Converting ggplot graph with ggplotly function

I have got a shiny application where I use the plotly package to convert my ggplot graph into dynamics graphics.
I am at the moment facing a problem with this conversion.
Here is my data.frame :
b <- data.frame(ID_Miseq = c(rep("P1",8), rep("P2",8), rep("P3",8), rep("P4",8)),
Condition1 = c(rep("A", 8), rep("B",16), rep("C", 8)),
Taxon = c(rep(paste0("T",1:8),4)),
Percent = sample(seq(1,25,0.1),32))
When I am creating my static barplot, no problem.
library(ggplot2)
gg <- ggplot(b, aes(x = ID_Miseq, y = Percent, fill = Taxon))
gg <- gg + geom_bar(stat = "identity", position = "stack")
factors <- "~Condition1"
gg <- gg + facet_grid(factors, scales = "free", space = "free_x")
gg
But, when I am using the ggplotly function from the plotly package, one of the sample is turning into numeric scale.
library(plotly)
ggplotly(gg)
Does anyone have ever faced the same kind of issue ? Am I using the ggplotly function wrong ? I am using plotly 4.7.1
Thanks, this is now fixed in the dev version, https://github.com/ropensci/plotly/commit/a0fc9c93e3b64ef4545b3522abbdfe44dc0e81a3
Install the dev version with devtools::install_github("ropensci/plotly")

Sharing a Legend between two combined ggplots

I'm currently trying to present two time series using ggplot2, both with very different scales, using two ggplots. I've combined the two separate ggplots, one on top of the other, using grid.arrange. In order to aid visualization, I'd like to make each line a different colour, and have this legend below the combined plot.
As this may be relevant, I'm currently working in the confines of creating a shiny section of an R markdown document. Hence the renderPlot wrapper around grid.arrange.
The following is similar to the code that I currently have.
testdata = data.frame(var1 = seq(0,10,by=1), var2 = runif(11),
var3 = runif(11, min = 100, max = 500))
renderPlot({grid.arrange(
ggplot(data = testdata, aes(x = var1, y = var2))
+ geom_line(colour = "blue") + xlab(NULL),
ggplot(data = testdata, aes(x = var1, y = var3)) + geom_line(colour = "red"))})
Does anyone have any suggestions about how to create the shared legend? Thanks very much for your help.
using ggplot2 I usually use the following 2 methods to create a common legend:
Method 1 : When scales are similar
By using facet_grid or just the color parameter in combination with reshape2 package, you can easily combine multiple plots with same legend. But this is ideal in case the values in your variables have a similar magnitude order.
Using color & reshape2:
library('reshape2')
data_melt<-melt(data=testdata,value.name='Value',id.vars='var1')
ggplot(data_melt)+
geom_line(aes(x=var1,y=Value,color=variable))
Using color, facet_grid & reshape2:
library('reshape2')
data_melt<-melt(data=testdata,value.name='Value',id.vars='var1')
ggplot(data_melt)+
geom_line(aes(x=var1,y=Value,color=variable))+
facet_grid(~variable)
Method 2: When scales differ wildly
As you can see,the final plot is great!
All you need is to create a plot having your legend & pass it as an input parameter to the custom function created in the wiki here.
testdata = data.frame(var1 = seq(0,10,by=1), var2 = runif(11),
var3 = runif(11, min = 100, max = 500))
library('reshape2')
data_melt<-melt(data=testdata,value.name='Value',id.vars='var1')
p1=ggplot(data = testdata)+
geom_line(aes(x = var1, y = var2,color='blue'))
p2=ggplot(data = testdata) +
geom_line(aes(x = var1, y = var3,color='red'))
p3=ggplot(data_melt)+
geom_line(aes(x=var1,y=Value,color=variable))
grid.arrange(p1,p2,nrow=2,main='Line Plots')
g_legend<-function(a.gplot){
tmp <- ggplot_gtable(ggplot_build(a.gplot))
leg <- which(sapply(tmp$grobs, function(x) x$name) == "guide-box")
legend <- tmp$grobs[[leg]]
return(legend)}
legend <- g_legend(p3)
lwidth <- sum(legend$width)
## using grid.arrange for convenience
## could also manually push viewports
grid.arrange(arrangeGrob(p1 + theme(legend.position="none"),
p2 + theme(legend.position="none"),
main ="Variable Name",
left = "Value"),
legend,
widths=unit.c(unit(1, "npc") - lwidth, lwidth), nrow=1)

Resources