I am trying to combine a stacked bar and a simple grouped bar on one X axis in R-plotly. Here is a reproducible sample of code I am using:
library(data.table)
library(magrittr)
library(plotly)
DT <- data.frame("year" = c(2019, 2020, 2021),
"example_var1" = c(12872100, 69436460, 8129560),
"example_var2" = c(25589160, 19671712, 19648085),
"example_var3" = c(15889160, 27671712, 19648085))
setDT(DT)
DT <- melt(DT, id.vars = "year")
DT[, ratio := paste0(round(value / sum(value) * 100, digits = 0), "%"), by = year]
# I would like to select 'example_var1' and 'example_var2 ' only for this part
my_plot <-
plot_ly(
DT,
x = ~ year,
y = ~ value, # select 'example_var1' and 'example_var2'
type = "bar",
name = ~ variable,
text = ~ ratio,
textposition = 'auto'
) %>%
layout (barmode = "stack")
# I would like to select 'example_var3' only for this part
my_plot <- my_plot %>%
add_trace(
x = ~ year,
y = ~ value, # select 'example_var2'
type = "bar",
name = ~ variable,
text = ~ ratio,
textposition = 'auto'
) %>%
layout (barmode = "group")
I don't know how to plot a serie of a stacked bar and a group bar in one plot using the same X axis.
I can't find a way to determine that variables "example_var1" and "example_var2" should plotted together on a stacked bar and variable "example_var3" should be plotted separately as a group bar.
Below a plot that I would like to get:
I am not aware of a straightforward solution for this (read more here:
Combination of grouped and stacked bar chart ). But we can find a workaround by editing the data and modifying the axis. See below;
DT1 <- DT[variable =="example_var3", year := year + 0.4][]
my_plot <-
plot_ly(
DT1,
x = ~ year,
y = ~ value,
type = "bar",
name = ~ variable,
text = ~ ratio,
textposition = 'auto'
) %>%
layout (barmode = "stack",
xaxis = list(
ticktext = list(2019, 2020, 2021),
tickvals = lapply(list(2019, 2020, 2021), `+`, 0.2),
tickmode = "array"
))
Related
I have grouped data which I want to plot as a group of box plots using R's plotly package, and control the width of the boxes and/or the space between theme.
Here are the data:
set.seed(1)
df <- data.frame(type = c(rep("t1", 1000), rep("t2", 1000), rep("t3", 1000), rep("t4", 1000), rep("t5", 1000), rep("t6", 1000)),
age = rep(c(rep("y", 500),rep("o", 500)), 6),
value = rep(c(runif(500, 5, 10), runif(500, 7.5, 12.5)), 6),
stringsAsFactors = F)
df$age <- factor(df$age, levels = c("y", "o"), ordered = T)
Following plotly's tutorial this is how I'm plotting it:
library(plotly)
library(dplyr)
plot_ly(x = df$type, y = df$value, name = df$age, color = df$type, type = 'box',showlegend = F) %>%
layout(yaxis=list(title="Diversity"),boxmode='group')
Which gives:
Where the boxes come out too narrow and the space both between boxes of the same type as well as the space between the different types are big.
Any idea how to change the box widths and/or the spaces?
According to this post, in python the boxgap and boxgroupgap control these aspects.
Analogous to the python version, layout parameters as being documented here can be changed as arguments of the function layout:
plot_ly(x = df$type, y = df$value, name = df$age, color = df$type,
type = "box", showlegend = F) %>%
layout(yaxis = list(title = "Diversity"),
boxmode = "group", boxgap = 0, boxgroupgap = 0
)
One alternative is to use a continuous x-axis. Here with ggplotly instead:
# convert factors to numbers
df$itype <- as.numeric (factor (df$type))
sc <- scale (unique (as.numeric (factor (df$age))))
df$iage <- sc[as.numeric (factor (df$age))] * .3
# plot
gg <-
ggplot (df, aes (x=itype+iage, y=value, color=type, group=itype+iage)) +
geom_boxplot() +
scale_x_continuous(labels = levels (factor (df$type)), breaks = 1:length (levels (factor (df$type)))) +
labs (x="", y="Diversity")
ggplotly (gg) %>%
layout(boxgroupgap = 0, boxgap=0)
plot
I'm having trouble specifying the order of the legend in a plotly R plot. This is similar to this unresolved post.
These made-up data are grouped by the group variable with two levels, "A" and "B". There are two aesthetic properties separating these groups:
"A" is red with a solid line;
"B" is blue with a dashed line.
The desired output is a legend with the blue dotted line, corresponding to the "B" group, at the top.
library(plotly)
library(dplyr)
set.seed(1)
dat <- tibble(
year = rep(2010:2019, 2),
group = factor(rep(c("A", "B"), each = 10), levels = c("B", "A")),
value = c(
rnorm(10, 10, 2),
rnorm(10, 14, 2)
),
colour = rep(c("red", "blue"), each = 10),
linetype = factor(rep(c("solid", "dot"), each = 10), levels = c("solid", "dot"))
)
If we ignore linetype for now, the legend is correct in that it has "B" above "A" (based on the factor levels for group variable).
dat %>%
plot_ly(
type = "scatter",
mode = "lines+markers",
x = ~ year,
y = ~ value,
color = ~ I(colour),
name = ~ group
)
However, when we add linetype in, the legend order is reverted to the default (with "A" above "B"):
dat %>%
plot_ly(
type = "scatter",
mode = "lines+markers",
x = ~ year,
y = ~ value,
color = ~ I(colour),
linetype = ~ I(linetype),
name = ~ group
)
Changing the factor levels of linetype doesn't fix the legend, it just breaks the mapping from linetype to the data:
dat %>%
mutate(linetype = factor(linetype, levels = c("dot", "solid"))) %>%
plot_ly(
type = "scatter",
mode = "lines+markers",
x = ~ year,
y = ~ value,
color = ~ I(colour),
linetype = ~ I(linetype),
name = ~ group
)
R version 4.0.3
plotly version 4.9.2.1
Thanks for reading and any suggestions.
I struggled with this myself today, and came across your post in the process.
I found that plotly.js side introduced a legendrank feature around April 2021, but this doesnt seem to be reflected in the R Plotly documentation, though I tested and it is a working feature that came into plotly version 4.10.0
dat %>%
plot_ly(
type = "scatter",
mode = "lines+markers",
x = ~ year,
y = ~ value,
color = ~ I(colour),
linetype = ~ I(linetype),
name = ~ group,
legendrank = ~ as.integer(group)
)
I have measurements from several groups which I would like to plot as violin plots:
set.seed(1)
df <- data.frame(val = c(runif(100,1,5),runif(100,1,5),rep(0,100)),
group = c(rep("A",100),rep("B",100),rep("C",100)))
Using R's ggplot2:
library(ggplot2)
ggplot(data = df, aes(x = group, y = val, color = group)) + geom_violin()
I get:
But when I try to get the equivalent with R's plotly using:
library(plotly)
plot_ly(x = df$group, y = df$val, split = df$group, type = 'violin', box = list(visible = F), points = F, showlegend = T, color = df$group)
I get:
Where group "C" gets an inflated/artificial violin.
Any idea how to deal with this and not by using ggplotly?
I did not find a way to fix the behaviour of plotly (probably worth making a bug report for this). A workaround would be to filter your data to only draw violin plots on groups whose range is greater than zero. If you also need to show where the other groups are, you can use a boxplot for these.
To demonstrate, I use library(data.table) for the filtering stage. You could use dplyr or base versions of the same procedure if you prefer:
setDT(df)[, toplot := diff(range(val)) > 0, group]
Now we can plot the groups using different trace styles depending on whether they should have violins or not
plot_ly() %>%
add_trace(data = df[(toplot)], x = ~group, y = ~val, split = ~group,
type = 'violin', box = list(visible = F), points = F) %>%
add_boxplot(data = df[(!toplot)], x = ~group, y = ~val, split = ~group)
I am making a pie-chart in plotly in R.
I want my labels to be on the chart, so I use textposition = "inside", and for the very small slices those values are not visible.
I am trying to find a way to exclude those labels.
Ideally, I would like to like to not print any lables on my plot that are below 10%.
Setting textposition = "auto" doesn't work well, since there are a lot of small slices, and it makes the graph look very messy.
Is there a way to do it?
For example these piecharts from plotly website (https://plot.ly/r/pie-charts/)
library(plotly)
library(dplyr)
cut <- diamonds %>%
group_by(cut) %>%
summarize(count = n())
color <- diamonds %>%
group_by(color) %>%
summarize(count = n())
clarity <- diamonds %>%
group_by(clarity) %>%
summarize(count = n())
plot_ly(cut, labels = cut, values = count, type = "pie", domain = list(x = c(0, 0.4), y = c(0.4, 1)),
name = "Cut", showlegend = F) %>%
add_trace(data = color, labels = color, values = count, type = "pie", domain = list(x = c(0.6, 1), y = c(0.4, 1)),
name = "Color", showlegend = F) %>%
add_trace(data = clarity, labels = clarity, values = count, type = "pie", domain = list(x = c(0.25, 0.75), y = c(0, 0.6)),
name = "Clarity", showlegend = F) %>%
layout(title = "Pie Charts with Subplots")
In the plot for Clarity 1.37% are outside of the plot, while I would like them not to show at all.
You'll have to specify sector labels manually like so:
# Sample data
df <- data.frame(category = LETTERS[1:10],
value = sample(1:50, size = 10))
# Create sector labels
pct <- round(df$value/sum(df$value),2)
pct[pct<0.1] <- 0 # Anything less than 10% should be blank
pct <- paste0(pct*100, "%")
pct[grep("0%", pct)] <- ""
# Install devtools
install.packages("devtools")
# Install latest version of plotly from github
devtools::install_github("ropensci/plotly")
# Plot
library(plotly)
plot_ly(df,
labels = ~category, # Note formula since plotly 4.0
values = ~value, # Note formula since plotly 4.0
type = "pie",
text = pct, # Manually specify sector labels
textposition = "inside",
textinfo = "text" # Ensure plotly only shows our labels and nothing else
)
Check out https://plot.ly/r/reference/#pie for more information...
How can I a draw a linechart with rcharts using nvd3 and a categorical xaxis? What I'm trying to do would look with ggplot2 like this:
library(ggplot2)
dat <- data.frame(expand.grid(group = letters[1:3], x = letters[4:6]), y = rnorm(9))
ggplot(dat, aes(x = x, y = y, group = group, color = group)) + geom_line()
I tried:
library(rCharts)
nPlot(y ~ x, group = 'group', data = dat, type = 'lineChart')
I know that I could change x to a numeric variable, but then the xaxis labels would not be correctly written.
is this what you are after?
foo <- hPlot(x = "x", y = "y", groups = "group", data = dat, type = "line")
foo