I made several plots with this lines of code:
dataset_numeric = dplyr::select_if(dataset, is.numeric)
par(mfrow=c(3,3))
for(i in 1:9) {
boxplot(dataset_numeric[,i], main=names(dataset_numeric)[i])
}
And output from this plot is pic below :
So I want to do same but now with library(Plotly) so can anybody help me how to do that ?
The following uses packages tidyr and ggplot2. First, the data are converted to a long table with pivot_longer, and then piped to ggplot. One issue to note in the example with one box only is that an explicit x aesthetic is needed, otherwise only the first box may be shown.
library("dplyr")
library("plotly")
library("ggplot2")
library("tidyr")
dataset <- as.data.frame(matrix(rnorm(99), ncol=9))
p <- pivot_longer(dataset, cols=everything()) %>%
ggplot(aes(x=0, y = value)) +
geom_boxplot() + facet_wrap( ~ name)
ggplotly(p)
Edit: a first had still an issue, that could be solved by adding x=0.
I you want to use plotly and put all variables in the same graph, you can use add_trace() in a for loop to do what you want.
library(plotly)
dataset_numeric = dplyr::select_if(iris, is.numeric)
fig <- plot_ly(data = dataset_numeric, type = "box")
for (i in 1:ncol(dataset_numeric)) {
fig <- fig %>% add_trace(y = dataset_numeric[,i])
}
fig
If you want to have separate plot for each variable, you can use subplot()
all_plot <- list()
for (i in 1:ncol(dataset_numeric)) {
fig <- plot_ly(data = dataset_numeric, type = "box") %>%
add_trace(y = dataset_numeric[,i])
all_plot <- append(all_plot, list(fig))
}
plt <- subplot(all_plot)
plt
Related
I'm using the svars package to generate some IRF plots. The plots are rendered using ggplot2, however I need some help with changing some of the aesthetics.
Is there any way I can change the fill and alpha of the shaded confidence bands, as well as the color of the solid line? I know in ggplot2 you can pass fill and alpha arguments to geom_ribbon (and col to geom_line), just unsure of how to do the same within the plot function of this package's source code.
# Load Dataset and packages
library(tidyverse)
library(svars)
data(USA)
# Create SVAR Model
var.model <- vars::VAR(USA, lag.max = 10, ic = "AIC" )
svar.model <- id.chol(var.model)
# Wild Bootstrap
cores <- parallel::detectCores() - 1
boot.svar <- wild.boot(svar.model, n.ahead = 30, nboot = 500, nc = cores)
# Plot the IRFs
plot(boot.svar)
I'm also looking at the command for a historical decomposition plot (see below). Is there any way I could omit the first two facets and plot only the bottom three lines on the same facet?
hist.decomp <- hd(svar.model, series = 1)
plot(hist.decomp)
Your first desired result is easily achieved by resetting the aes_params after calling plot. For your second goal. There is probably an approach to manipulate the ggplot object. Instead my approach below constructs the plot from scratch. Basically I copy and pasted the data wrangling code from vars:::plot.hd and filtered the prepared dataset for the desired series:
# Plot the IRFs
p <- plot(boot.svar)
p$layers[[1]]$aes_params$fill <- "pink"
p$layers[[1]]$aes_params$alpha <- .5
p$layers[[2]]$aes_params$colour <- "green"
p
# Helper to convert to long dataframe. Source: svars:::plot.hd
hd2PlotData <- function(x) {
PlotData <- as.data.frame(x$hidec)
if (inherits(x$hidec, "ts")) {
tsStructure = attr(x$hidec, which = "tsp")
PlotData$Index <- seq(from = tsStructure[1], to = tsStructure[2],
by = 1/tsStructure[3])
PlotData$Index <- as.Date(yearmon(PlotData$Index))
}
else {
PlotData$Index <- 1:nrow(PlotData)
PlotData$V1 <- NULL
}
dat <- reshape2::melt(PlotData, id = "Index")
dat
}
hist.decomp <- hd(svar.model, series = 1)
dat <- hd2PlotData(hist.decomp)
dat %>%
filter(grepl("^Cum", variable)) %>%
ggplot(aes(x = Index, y = value, color = variable)) +
geom_line() +
xlab("Time") +
theme_bw()
EDIT One approach to change the facet labels is via a custom labeller function. For a different approach which changes the facet labels via the data see here:
myvec <- LETTERS[1:9]
mylabel <- function(labels, multi_line = TRUE) {
data.frame(variable = labels)
}
p + facet_wrap(~variable, labeller = my_labeller(my_labels))
I would like to add trace of a median line on my box plot.
like this
Here are my plots so far:
library(plotly)
p <- plot_ly(y = ~rnorm(50), type = "box") %>%
add_trace(y = ~rnorm(50, 1))
p
Just start out with a scatter plot using plot_ly(..., type='scatter', mode='lines', ...), and follow up with one add_boxplot(...' inherit=FALSE, ...) per box plot. Here's how you do it for an entire data.frame:
Complete code with sample data:
library(dplyr)
library(plotly)
# data
df <- data.frame(iris) %>% select(-c('Species'))
medians <- apply(df,2,median)
# create common x-axis values for median line and boxplots
xVals <- seq(0, length(medians)-1, by=1)
# plotly median line setup
p <- plot_ly(x = xVals, y=medians, type='scatter', mode='lines', name='medians')
# add a trace per box plot
i <- 0
for(col in names(df)){
p <- p %>% add_boxplot(y = df[[col]], inherit = FALSE, name = col)
i <- i + 1
}
# manage layout
p <- p %>% layout(xaxis = list(range = c(min(xVals)-1, max(xVals)+1)))
p
Another option is to use ggplot2 and convert it into plotly
library(ggplot2)
library(dplyr)
library(tidyr)
library(plotly)
p = iris %>% pivot_longer(-Species) %>%
ggplot(aes(x=name,y=value,col=name)) +
geom_boxplot() + stat_summary(inherit.aes = FALSE,
aes(x=name,y=value,group=1),fun.y=median,geom="line")
ggplotly(p)
A brief explanation of the code, I use pivot_longer from tidyr to cast the data frame into long format, and first made the boxplot with the column names as x variable and color.
The stat_summary part, I specified again the same x and y variables again, and omitted the colour this time, adding group=1, this tells stat_summary to consider the whole data frame as one group, and to summarize all the y values per x-group, and draw a line through it.
I have data I'd like to plot the distribution density of. The data are from three groups, where for each there are three states, each with a probability, and these probabilities sum to 1.
I'm trying to use R's plotly to plot, for each group, the density of the probabilities, color coded by state, and add some text annotation to each such group plot. Finally I'm trying to combine all of these group plots using plotly::subplot.
Here's the code to generate the data and a list of group plots:
library(dplyr)
library(reshape2)
library(plotly)
set.seed(1)
plot.list <- lapply(1:3,function(g){
if(g == 1){
show.legend <- T
} else{
show.legend <- F
}
df <- data.frame(id=LETTERS,t(sapply(1:length(LETTERS),function(x){
probs <- runif(3,0,1)
return(probs/sum(probs))
}))) %>% dplyr::rename(S1=X1,S2=X2,S3=X3) %>%
reshape2::melt() %>% dplyr::rename(state=variable,probability=value)
df$state <- factor(df$state,levels=c("S1","S2","S3"))
density.df <- do.call(rbind,lapply(levels(df$state),function(s){
dens <- density(dplyr::filter(df,state == s)$probability)
return(data.frame(x=dens$x,y=dens$y,state=s,stringsAsFactors=F))
}))
density.df$state <- factor(density.df$state,levels=levels(df$state))
dens.plot <- plot_ly(x=~density.df$x,y=~density.df$y,type='scatter',mode='lines',color=~density.df$state,showlegend=show.legend) %>%
layout(xaxis=list(title="Probability",zeroline=F),yaxis=list(title="Count",zeroline=F)) %>%
add_annotations(x=0.75,y="top",text=paste0("text: ",g))
if(show.legend) dens.plot <- dens.plot %>% add_annotations(text="State",xref="paper",yref="paper",x=1.02,xanchor="left",y=1.02,yanchor="top",legendtitle=T,showarrow=F)
return(dens.plot)
})
Note that I'm only adding the legend to the first group so it appears only once in the final grouped plot (there's probably a more elegant way of achieving that).
And here's the plotly::subplot command I'm using:
subplot(plot.list,nrows=3,shareX=T,shareY=T,titleX=T,titleY=T)
Which gives:
As you can see the text annotation is stuck at "top" of the first plot rather than at the top of each individual plot.
Any idea how do I get each annotation to be located at the top of its corresponding sub-plot?
Preamble. For reasons that are not entirely obvious to me (but relating to how values for annotations are scaled when running subplot), annotations seem to go awry with vertically stacked subplots. To see this, run the MWE at https://plot.ly/r/text-and-annotations/#subplot-annotations, but change
subplot(p1, p2, titleX = TRUE, titleY = TRUE)
to
subplot(p1, p2, titleX = TRUE, titleY = TRUE, nrows = 2)
In the vertically stacked version, the annotations are not where we would expect them to be. To achieve your desired outcome would require some post-processing of the subplot output. Now, on to your main question.
First, in add_annotations, add xref and yref arguments that correspond to each subplot. In each element of plot.list, I also add an additional element y_anno to keep track of where we would like the annotation to go (at the maximum value of the densities in each subplot).
plot.list <- lapply(1:3,function(g){
if(g == 1){
show.legend <- T
} else{
show.legend <- F
}
df <- data.frame(id=LETTERS,t(sapply(1:length(LETTERS),function(x){
probs <- runif(3,0,1)
return(probs/sum(probs))
}))) %>% dplyr::rename(S1=X1,S2=X2,S3=X3) %>%
reshape2::melt() %>% dplyr::rename(state=variable,probability=value)
df$state <- factor(df$state,levels=c("S1","S2","S3"))
density.df <- do.call(rbind,lapply(levels(df$state),function(s){
dens <- density(dplyr::filter(df,state == s)$probability)
return(data.frame(x=dens$x,y=dens$y,state=s,stringsAsFactors=F))
}))
density.df$state <- factor(density.df$state,levels=levels(df$state))
dens.plot <- plot_ly(x=~density.df$x,
y=~density.df$y,
type='scatter',
mode='lines',
color=~density.df$state,
showlegend=show.legend) %>%
layout(xaxis=list(title="Probability",zeroline=F),yaxis=list(title="Count",zeroline=F)) %>%
add_annotations(x = 0.75,
y = max(density.df$y),
text = paste0("text: ", g),
xref = paste0("x", g), # add this
yref = paste0("y", g), # add this
ax = 0,
ay = 0)
if(show.legend) dens.plot <- dens.plot %>% add_annotations(text="State",xref="paper",yref="paper",x=1.02,xanchor="left",y=1.02,yanchor="top",legendtitle=T,showarrow=F)
dens.plot$y_anno <- max(density.df$y) # add this
return(dens.plot)
})
Now if we run subplot(plot.list,nrows=3,shareX=T,shareY=T,titleX=T,titleY=T), the text will be in each subplot, but not at the top (due to the phenomenon I described in the preamble). To fix this, we can post-process the subplot output:
p <- subplot(plot.list, nrows = 3,shareX = T,shareY = T,titleX = T,titleY = T)
for (i in seq_along(plot.list)) {
for (j in seq_along(p$x$layout$annotations)) {
if (p$x$layout$annotations[[j]]$yref == paste0("y", i))
p$x$layout$annotations[[j]]$y <- plot.list[[i]]$y_anno
}
}
Now p gives us
which is close to what we want.
I found an example to add lines to a plot_ly plot by using the add_trace command. How can I add a list of lines to plot without using add_trace multiple times?
I tried a for loop to add the traces but this doesn't work as expected.
my_lines <- list(
list(x=1:10, y=2:11, color='red'),
list(x=1:10, y=0:9, color='blue'),
list(x=1:10, y=3:12, color='green')
)
p <- plot_ly()
p
for(line in my_lines) { p <- add_trace(p, y=line[['y']], x=line[['x']],
marker=list(color=line[['color']]))
}
p
But this for example works as expected.
p <- plot_ly()
p <- add_trace(p, y=my_lines[[1]][['y']], x=my_lines[[1]][['x']],
marker=list(color=my_lines[[1]][['color']]))
p <- add_trace(p, y=my_lines[[2]][['y']], x=my_lines[[2]][['x']],
marker=list(color=my_lines[[2]][['color']]))
p <- add_trace(p, y=my_lines[[3]][['y']], x=my_lines[[3]][['x']],
marker=list(color=my_lines[[3]][['color']]))
p
I believe with the release of plotly 4.0 calling any of the add_* family of functions forces evaluation so there is no need to call evaluate = T anymore
So, something like this should work fine:
devtools::install_github("ropensci/plotly")
library(plotly)
p <- plot_ly()
for(i in 1:5){
p <- add_trace(p, x = 1:10, y = rnorm(10), mode = "lines")
}
p
You need to set evaluate = TRUE to force evalutation / avoid lazy evaluation
p <- plot_ly()
p
for(line in my_lines) { p <- add_trace(p, y=line[['y']], x=line[['x']],
marker=list(color=line[['color']]),
evaluate = TRUE)
}
p
You can transform your inputs into a long-form data frame first, then plot using the split argument.
library(plotly)
library(reshape2)
my_lines = data.frame(x = 1:10, red = 2:11, blue = 0:9, green = 3:12)
my_lines_long = reshape2::melt(my_lines, id.vars = "x")
fig = plotly::plot_ly(my_lines_long, x = ~x, y = ~value, split = ~variable,
marker=list(color=~variable))
fig
The two separate charts created from data.frame work correctly when created using the R plotly package.
However,
I am not sure how to combine them into one (presumably with the add_trace function)
df <- data.frame(season=c("2000","2000","2001","2001"), game=c(1,2,1,2),value=c(1:4))
plot_ly(df, x = game, y = value, mode = "markers", color = season)
plot_ly(subset(df,season=="2001"), x = game, y = value, mode = "line")
Thanks in advance
The answer given by #LukeSingham does not work anymore with plotly 4.5.2.
You have to start with an "empty" plot_ly() and then to add the traces:
df1 <- data.frame(season=c("2000","2000","2001","2001"), game=c(1,2,1,2), value=c(1:4))
df2 <- subset(df, season=="2001")
plot_ly() %>%
add_trace(data=df1, x = ~game, y = ~value, type="scatter", mode="markers") %>%
add_trace(data=df2, x = ~game, y = ~value, type="scatter", mode = "lines")
here is a way to do what you want, but with ggplot2 :-) You can change the background, line, points color as you want.
library(ggplot2)
library(plotly)
df_s <- df[c(3:4), ]
p <- ggplot(data=df, aes(x = game, y = value, color = season)) +
geom_point(size = 4) +
geom_line(data=df_s, aes(x = game, y = value, color = season))
(gg <- ggplotly(p))
There are two main ways you can do this with plotly, make a ggplot and convert to a plotly object as #MLavoie suggests OR as you suspected by using add_trace on an existing plotly object (see below).
library(plotly)
#data
df <- data.frame(season=c("2000","2000","2001","2001"), game=c(1,2,1,2),value=c(1:4))
#Initial scatter plot
p <- plot_ly(df, x = game, y = value, mode = "markers", color = season)
#subset of data
df1 <- subset(df,season=="2001")
#add line
p %>% add_trace(x = df1$game, y = df1$value, mode = "line")