I work with Plotly and I want to put four charts in the same picture. Below you can see data
library(dplyr)
library(plotly)
df<-data.frame(
Years = rep(2010:2020,len=22),
Tax = rep(c("PIT","CIT","VAT"),22),
Revenues = rep(c(200,400,100),22)
)
df$Pct<-prop.table(df$Revenues)
RevenueCompositionPCT <- plot_ly(df, x = ~Years, y = ~Pct,
type = 'bar',
marker = list(color = ~Revenues), name = ~Tax) %>%
layout(title = "AA",
yaxis = list(title = 'Percentage %'), barmode = 'stack')
RevenueCompositionPCT <- RevenueCompositionPCT %>% layout(legend = list(orientation = 'h'))
RevenueCompositionPCT
Now I want to put four charts with separate titles and also titles on the y-axis on the same pictures. I tried with the code below but is not work properly.
p<-subplot(
style(RevenueCompositionPCT, showlegend = FALSE,title=TRUE,titleY = TRUE),
style(RevenueCompositionPCT, showlegend = FALSE,title=TRUE,titleY = TRUE),
style(RevenueCompositionPCT, showlegend = FALSE,title=TRUE,titleY = TRUE),
style(RevenueCompositionPCT, showlegend = TRUE,title=TRUE,titleX = TRUE, ),
nrows =2,margin = 0.05)
p
So can anybody help me how to solve this problem?
I think it's easier with the combineWidgets function of the manipulateWidget package:
library(manipulateWidget)
combineWidgets(p1, p2, p3, p4, nrow = 2)
where p1, p2, p3, p4 are your plotly plots.
Related
This question already has an answer here:
Add jitter to box plot using markers in plotly
(1 answer)
Closed 9 days ago.
I would like to obtain exactly the same result as the one presented here in the best answer of this post: Add jitter to box plot using markers in plotly, but without the boxplot itself keeping only the jitter points.
Is there a way to achieve this?
thank you for your answers.
Remove the add_trace. Using the literal code from that answer,
library(plotly)
set.seed(42)
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))
We see:
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 am given a plotly object containing n subplots and I want to add a rangeslider to it. I do so using the code
p<- layout(p, xaxis = list(rangeslider = list(type = "date")))
However, I need to retain the ability to rescale the y axis on all the subplots. I know I can do so by again changing the layout in the following way:
p<- layout(p,
yaxis = list(fixedrange = F),
yaxis2 = list(fixedrange = F),
yaxis3 = list(fixedrange = F),
...)
However, since the number of plots changes, I need a programmatic way of doing that. Note that the plotly object is generated using ggplotly, and as such I don't have access to the individual subplots to pass the layout options there.
I tried passing a list to layout, but it doesn't seem to produce the right result:
layoutlist <- list(yaxis = list(fixedrange = F), yaxis2 = list(fixedrange = F), yaxis3 = list(fixedrange = F), ...)
p<- layout(p, layoutlist)
does not return an error but also doesn't apply the layout options properly.
I also tried using unquoting (!!) to solve the issue but I couldn't get it to work.
Here is some sample code for replication:
(This part can't change)
subplots_list <- list()
for(i in 1:5){
subplots_list[[i]] <- plot_ly()
}
p<- subplot(subplots_list, nrows = 5, shareX = T)
Expected result
p<- p %>% layout(xaxis = list(rangeslider = list(type = "date")))
p<- p %>% layout(
yaxis = list(fixedrange = F),
yaxis2 = list(fixedrange = F),
yaxis3 = list(fixedrange = F),
yaxis4 = list(fixedrange = F),
yaxis5 = list(fixedrange = F)
)
Thanks in advance for your help.
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)
I created a graph through R's Plotly library.
The graph has 2 y-axis's and everything looks fine, except that the y-axis's are misaligned.
How do I "realign" it?
Python answer here
Had the same issue, add rangemode = "tozero" to your overlaying axis
plot_ly(data = dat,
x = x,
y = y,
type = "bar",
name = "Y") %>%
add_trace(data = par,
x = x,
y = Z,
name = "Z",
yaxis = "y2") %>%
layout(yaxis2 = list(overlaying = "y",
side = "right",
rangemode = "tozero"))
In the layout function, you can set axis ranges manually. You can use this to align them. Often, the scale of your two traces will be very different, though.
plot_ly(...) %>%
add_trace(..., yaxis = "y2") %>%
layout(
yaxis = list(
range = c(-2, 2)
),
yaxis2 = list(
range = c(-2, 2)
)
)
You can actually align primary and secondary y axes at any value (not just at 0) and for any plotting function by calculating new y axis limits. Here's a link to some code for a function that can handle any scenario: https://github.com/davidblakneymoore/A-Function-for-Aligning-Values-on-Primary-and-Secondary-Y-Axes-on-Plots-in-R.
This answer in python took JohnCoene's answer one step further:
https://community.plotly.com/t/align-multiple-y-axis-to-one-value-in-plotly/44500/2
The parameters scaleratio can be seen in further detail in the Plotly manual.
By constraining the left and right y-axes to one another you can adjust the scale at which they increase.
plot_ly(data = dat,
x = x,
y = y,
type = "bar",
name = "Y") %>%
add_trace(data = par,
x = x,
y = Z,
name = "Z",
yaxis = "y2") %>%
layout(yaxis = list(scaleanchor = 'y2',
scaleratio = 1, # Or perhaps 0.5 or 2, dep on your figure
constraintoward = 'bottom',
rangemode = "tozero"),
yaxis2 = list(scaleanchor = 'y',
scaleratio = 1, # Or perhaps 0.5 or 2, dep on your figure
overlaying = "y",
constraintoward = 'bottom'
side = "right",
rangemode = "tozero"))