Combining static and animated plotly objects using subplot - r

Given the following data.frame
data <- structure(list(
a = c(3.022210021321, 3.31806778755904, 3.34379454984061, 3.47242836124846, 3.55604033866356, 1.11199792191451, 1.24063173332236, 1.31781202016707, 1.30494863902628, 1.3692655447302, 1.07983946906255, 1.2084732804704, 1.40142399758216, 1.60723809583472, 1.64582823925707),
b = c(2.64027979608152, 2.79483009168741, 2.90522315997732, 3.08185206924119, 2.86106593266136, 0.653204566863006, 0.697361794178973, 0.67528318052099, 0.653204566863006, 0.697361794178973, 2.06623584097395, 2.28702197755379, 2.48572950047564, 2.72859425071346, 2.77275147802942),
c = c(2L, 2L, 2L, 2L, 2L, 3L, 3L, 3L, 3L, 3L, 1L, 1L, 1L, 1L, 1L),
d = c(1.16264425026133, 1.16264425026133, 1.16264425026133, 1.16264425026133, 1.16264425026133, 1.48373054411498, 1.48373054411498, 1.48373054411498, 1.48373054411498, 1.48373054411498, 3.35362520562369, 3.35362520562369, 3.35362520562369, 3.35362520562369, 3.35362520562369),
e = c(2015L, 2016L, 2017L, 2018L, 2019L, 2015L, 2016L, 2017L, 2018L, 2019L, 2015L, 2016L, 2017L, 2018L, 2019L),
f = c("X", "X", "X", "X", "X", "Y", "Y", "Y", "Y", "Y", "Z", "Z", "Z", "Z", "Z"),
h = structure(c(2L, 2L, 2L, 2L, 2L, 3L, 3L, 3L, 3L, 3L, 1L, 1L, 1L, 1L, 1L), .Label = c("low", "mid", "high"), class = c("ordered", "factor"))),
row.names = c(NA, -15L),
class = "data.frame")
and the following code snippet
library(plotly)
p <- data %>% plot_ly(
x = ~a,
y = ~b,
size = ~c,
sizes = c(100, 850),
color = ~d,
colors = "YlOrRd",
alpha = 0.365,
frame = ~e,
text = ~paste0("Info: ", f),
hoverinfo = "text",
type = 'scatter',
mode = 'markers') %>%
add_text(textfont = list(size = 10, color = "black"), textposition = "top", text=~f, showlegend = F)
legend.plot <- plot_ly() %>%
add_markers(x = 1,
y = seq_len(length(unique(data$c))),
size = sort(unique(data$c)),
showlegend = F,
color = I("black"),
marker = list(sizeref=0.1, sizemode="area")) %>%
layout(
annotations = list(
list(x = 1.2,
y = 0.4,
text = "Size by: c",
showarrow = F,
xref='paper',
yref='paper')),
xaxis = list(
zeroline=F,
showline=F,
showticklabels=F,
showgrid=F),
yaxis=list(
side = "right",
range = c(0,10),
showgrid=F,
zeroline=F,
tickmode = "array",
tickvals = seq_len(length(unique(data$c))),
ticktext = c("low","mid","high")))
subplot(p, legend.plot, widths = c(0.85, 0.15), titleX=TRUE, titleY=TRUE) %>%
config(displayModeBar = F) %>%
colorbar(title = "Color by: d", x = 0.9, y = 1)
I manage to almost get a plotly plot that I want (ignoring the warnings along the way for now).
I am, however, unable to figure out, how to make the legend for size to stay during the animation. It appears in the initial stage, before the play button is hit, but as soon as I press play, it goes away.
So the static plot data points are disappearing from the subplot when I run the animation. Any hints?

This works. The reason that your pseudo-legend disappears is that you only have it for the first frame. What I did here is adding the data for all the 5 years (that's why I have rep) and making sure that frame is included in both plots.
legend.plot <- plot_ly() %>%
add_markers(x = rep(1,15),
y = rep(seq_len(length(unique(data$c))),5),
size = rep(sort(unique(data$c)),5),
showlegend = F,
color = I("black"),
frame = ~data$e,
marker = list(sizeref=0.1, sizemode="area")) %>%
layout(
annotations = list(
list(x = 1.2,
y = 0.4,
text = "Size by: c",
showarrow = F,
xref='paper',
yref='paper')),
xaxis = list(
zeroline=F,
showline=F,
showticklabels=F,
showgrid=F),
yaxis=list(
side = "right",
range = c(0,10),
showgrid=F,
zeroline=F,
tickmode = "array",
tickvals = seq_len(length(unique(data$c))),
ticktext = c("low","mid","high")))

Related

Donut plots with same colors for same labels

I am using Plotly to plot Donut Plot. Below you can see my data
df1<-structure(list(manuf = c("AMC", "Cadillac", "Camaro", "Chrysler",
"Datsun", "Dodge", "Duster", "Ferrari", "Fiat", "Ford", "Honda",
"Hornet", "Lincoln", "Lotus", "Maserati", "Mazda", "Merc", "Pontiac",
"Porsche", "Toyota", "Valiant", "Volvo"), count = c(1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 2L, 1L, 1L, 2L, 1L, 1L, 1L, 2L, 7L, 1L, 1L,
2L, 1L, 1L)), row.names = c(NA, -22L), class = c("tbl_df", "tbl",
"data.frame"))
fig <- df1 %>% plot_ly(labels = ~manuf, values = ~count)
fig <- fig %>% add_pie(hole = 0.6)
fig <- fig %>% layout(title = "Donut charts using Plotly", showlegend = T,
xaxis = list(showgrid = FALSE, zeroline = FALSE, showticklabels = FALSE),
yaxis = list(showgrid = FALSE, zeroline = FALSE, showticklabels = FALSE))
fig
The above code produces Donut Plot, which you can see below. In this plot, Merc has the largest share of 21 % and is the blue color.
Now I want to plot the same plot but with small changes in data. Now instead of Merc in the first place is AMC with 44.6 %. Below you can see the data and code
df2<-structure(list(manuf = c("AMC", "Cadillac", "Camaro", "Chrysler",
"Datsun", "Dodge", "Duster", "Ferrari", "Fiat", "Ford", "Honda",
"Hornet", "Lincoln", "Lotus", "Maserati", "Mazda", "Merc", "Pontiac",
"Porsche", "Toyota", "Valiant", "Volvo"), count = c(25L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 2L, 1L, 1L, 2L, 1L, 1L, 1L, 2L, 7L, 1L, 1L,
2L, 1L, 1L)), row.names = c(NA, -22L), class = c("tbl_df", "tbl",
"data.frame"))
fig <- df2 %>% plot_ly(labels = ~manuf, values = ~count)
fig <- fig %>% add_pie(hole = 0.6)
fig <- fig %>% layout(title = "Donut charts using Plotly", showlegend = T,
xaxis = list(showgrid = FALSE, zeroline = FALSE, showticklabels = FALSE),
yaxis = list(showgrid = FALSE, zeroline = FALSE, showticklabels = FALSE))
fig
Now in this Donut plot, colors are different compared to the first Donut Plot. Namely Merc in the first plot is blue in color while in the second plot is orange.
So can anybody help me how to produce Donut plots with the same colors for the same names.
I used the library shades, but any color palette creator would work. Since every row of the data is equivalent to a pie element, you need the same number of colors as you have rows (22). You can simply add the colors to the data frame.
library(plotly)
library(shades)
# since the data frame has all unique manuf
df1$colr <- gradient("viridis", steps = 22)
By the way, you can check your colors before designation:
swatch(gradient("viridis", steps = 22))
While you have plot_ly() and add_pie() separated, you don't need to. Additionally, you can update the figure all at once (instead of updating continuously). Lastly, the following arguments showlegend = T, xaxis = list(showgrid = FALSE, zeroline = FALSE, showticklabels = FALSE), yaxis = list(showgrid = FALSE, zeroline = FALSE, showticklabels = FALSE) are all default settings. You don't need to call any of these.
df1 %>% plot_ly(labels = ~manuf, values = ~count, type = "pie",
hole = .6, marker = list(colors = ~colr)) %>%
layout(title = "Donut charts using Plotly")
And your other data and plot...
df2$colr <- gradient("viridis", steps = 22)
plot_ly(data = df2, labels = ~manuf, values = ~count, type = "pie",
marker = list(colors = ~colr), hole = .6) %>%
layout(title = "Donut charts using Plotly")

Split legend into two or multiple columns in a plot using ggnewscale::new_scale() with ggplot2 in R

after following Stefan's very helpful answer to this post, where he uses ggnewscale::new_scale(), I now am stuck with the following question:
"How to arrange the custom legends from ggnewscale into multiple vertical columns?"
like it is usually done with a command such as guides(scale_shape_manual=guide_legend(ncol=2)) in ggplot2.
Minimal reproducible example:
# fictional data in the scheme of https://stackoverflow.com/q/66804487/16642045
mutated <- list()
for(i in 1:10) {
mutated[[i]] <- data.frame(Biological.Replicate = rep(1,4),
Reagent.Conc = c(10000, 2500, 625, 156.3),
Reagent = rep(1,8),
Cell.type = rep(LETTERS[i],4),
Mean.Viable.Cells.1 = rep(runif(n = 10, min = 0, max = 1),4))
}
mutated <- do.call(rbind.data.frame, mutated)
The modified code after the answer of user "stefan" looks like this:
# from https://stackoverflow.com/a/66808609/16642045
library(ggplot2)
library(ggnewscale)
library(dplyr)
library(magrittr)
mutated <- mutated %>%
mutate(Cell.type = as.factor(Cell.type),
Reagent = factor(Reagent,
levels = c("0", "1", "2")))
mean_mutated <- mutated %>%
group_by(Reagent, Reagent.Conc, Cell.type) %>%
split(.$Cell.type)
layer_geom_scale <- function(Cell.type) {
list(geom_point(mean_mutated[[Cell.type]], mapping = aes(shape = Reagent)),
geom_line(mean_mutated[[Cell.type]], mapping = aes(group = Reagent, linetype = Reagent)),
scale_linetype_manual(name = Cell.type, values = c("solid", "dashed", "dotted"), drop=FALSE),
scale_shape_manual(name = Cell.type, values = c(15, 16, 4), labels = c("0", "1", "2"), drop=FALSE)
)
}
my_plot <-
ggplot(mapping = aes(
x = as.factor(Reagent.Conc),
y = Mean.Viable.Cells.1)) +
layer_geom_scale(unique(mutated$Cell.type)[1])
for(current_Cell.type_index in 2:length(unique(mutated$Cell.type))) {
my_plot <-
my_plot +
ggnewscale::new_scale("shape") +
ggnewscale::new_scale("linetype") +
layer_geom_scale(unique(mutated$Cell.type)[current_Cell.type_index])
}
my_plot
This results in:
Now, I want the legends to be displayed side-by-side, in two columns, and I tried this (without success):
my_plot +
guides(scale_shape_manual=guide_legend(ncol=2))
EDIT: A picture of the way I want the legends to be arranged
Is there anyone who could help me?
Thanks!
Note: This answer addresses the question before clarification was made at question edit # 4 and beyond.
Horizontal legend
Adding theme(legend.box = "horizontal") will make the legend elements appear side by side.
Multiple columns and ggnewscale
Using guides globally will result in the modification of scales after ggnewscale updates them. In this context, only the variable RKO will be updated:
layer_geom_scale <- function(cell_type, color) {
list(geom_point(mean_mutated[[cell_type]], mapping = aes(shape = Reagent), color = color),
geom_line(mean_mutated[[cell_type]], mapping = aes(group = Reagent, linetype = Reagent), color = color),
scale_linetype_manual(name = cell_type, values = c("solid", "dashed", "dotted"), drop=FALSE),
scale_shape_manual(name = cell_type, values = c(15, 16, 4), labels = c("0", "1", "2"), drop=FALSE)
)
}
my_plot <-
ggplot(mapping = aes(
x = as.factor(Reagent.Conc),
y = Mean.Viable.Cells.1)) +
layer_geom_scale("HCT", "#999999") +
ggnewscale::new_scale("linetype") +
ggnewscale::new_scale("shape") +
layer_geom_scale("RKO", "#E69F00") +
theme(legend.box = "horizontal") +
guides(shape = guide_legend(ncol = 2),
linetype = guide_legend(ncol = 2))
my_plot
To modify the same scales for all variables, the guide should be added inside the scale definitions:
layer_geom_scale <- function(cell_type, color) {
list(geom_point(mean_mutated[[cell_type]], mapping = aes(shape = Reagent), color = color),
geom_line(mean_mutated[[cell_type]], mapping = aes(group = Reagent, linetype = Reagent), color = color),
scale_linetype_manual(name = cell_type, values = c("solid", "dashed", "dotted"), drop=FALSE,
guide = guide_legend(ncol = 2)),
scale_shape_manual(name = cell_type, values = c(15, 16, 4), labels = c("0", "1", "2"), drop=FALSE,
guide = guide_legend(ncol = 2))
)
}
my_plot <-
ggplot(mapping = aes(
x = as.factor(Reagent.Conc),
y = Mean.Viable.Cells.1)) +
layer_geom_scale("HCT", "#999999") +
ggnewscale::new_scale("linetype") +
ggnewscale::new_scale("shape") +
layer_geom_scale("RKO", "#E69F00") +
theme(legend.box = "horizontal")
my_plot
Raw data
# from https://stackoverflow.com/q/66804487/16642045
mutated <- structure(list(
Biological.Replicate = c(1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L),
Reagent.Conc = c(10000, 2500, 625, 156.3,
39.1, 9.8, 2.4, 0.6,
10000, 2500, 625, 156.3,
39.1, 9.8, 2.4, 0.6,
10000, 2500, 625, 156.3,
39.1, 9.8, 2.4, 0.6),
Reagent = c(1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L,
2L, 2L, 2L, 2L,
2L, 2L, 2L, 2L,
0L, 0L, 0L, 0L,
0L, 0L, 0L, 0L),
Cell.type = c("HCT", "HCT", "HCT", "HCT",
"HCT", "HCT", "HCT", "HCT",
"HCT", "HCT", "HCT", "HCT",
"HCT", "HCT", "HCT", "HCT",
"RKO", "RKO", "RKO", "RKO",
"RKO", "RKO", "RKO", "RKO"),
Mean.Viable.Cells.1 = c(1.014923966, 1.022279854, 1.00926559, 0.936979842,
0.935565248, 0.966403395, 1.00007073, 0.978144524,
1.019673384, 0.991595836, 0.977270557, 1.007353643,
1.111928183, 0.963518289, 0.993028364, 1.027409034,
1.055452733, 0.953801253, 0.956577449, 0.792568337,
0.797052961, 0.755623576, 0.838482346, 0.836773918)),
row.names = 9:32,
class = "data.frame")
# from https://stackoverflow.com/a/66808609/16642045
library(ggplot2)
library(ggnewscale)
library(dplyr)
library(magrittr)
mutated <- mutated %>%
mutate(Cell.type = factor(Cell.type,
levels = c("HCT", "RKO")),
Reagent = factor(Reagent,
levels = c("0", "1", "2")))
mean_mutated <- mutated %>%
group_by(Reagent, Reagent.Conc, Cell.type) %>%
split(.$Cell.type)

keep line graphs after the frame ends in r ggplotly

I am trying to create an interactive plot. My lines have different frames (some end shorter). When I play the animation, the lines disappear after their frame ends. I tried to add more rows of fake data with the added frames but that didn't make a difference. I am not sure why this is happening.
Sample Data:
> dput(sample_n(Plot, 20))
structure(list(Strain = c(0.0114976650717703, 0.0283627375, 0.00173272727272728,
0.0150241, 0.0450557, 0.0113663, 3.97637e-05, 0.0434292, 0.00406928,
0.00207895693779905, 0.000215139, 0.00148572499999999, 0.0418233875,
0.000939926, 0.000255219, 0.0213334, 0.023816, 0.0145059, 0.0131467081339713,
0.0668966), Stress = c(75.9505644091148, 78.5302055162329, 48.6062116858257,
68.4024611345473, 85.2904610049016, 63.9140059100703, 1.43583171490823,
84.8256506176318, 64.1272033757161, 53.8795512181689, 14.442082799196,
64.3587637619208, 84.731707366194, 25.4200560130662, 13.8571035440045,
84.1313452985436, 85.4161843153761, 67.9158653588222, 77.7143709896995,
90.4239965485986), Instrumentation = structure(c(2L, 2L, 2L,
1L, 1L, 1L, 1L, 1L, 1L, 2L, 1L, 2L, 2L, 1L, 1L, 1L, 1L, 1L, 2L,
1L), .Label = c("DIC", "LVDT"), class = "factor"), Bar = structure(c(1L,
2L, 1L, 2L, 2L, 2L, 1L, 2L, 1L, 1L, 1L, 2L, 2L, 2L, 1L, 1L, 1L,
2L, 1L, 2L), .Label = c("Spliced", "Unspliced"), class = "factor"),
ANIM = c(0.01, 0.03, 0, 0.02, 0.05, 0.01, 0, 0.04, 0, 0,
0, 0, 0.04, 0, 0, 0.02, 0.02, 0.01, 0.01, 0.07), frame = c(0.05,
0.05, 0.04, 0.13, 0.05, 0.1, 0.01, 0.11, 0.02, 0, 0.04, 0.11,
0.09, 0.01, 0.01, 0.04, 0.06, 0.09, 0.05, 0.08)), row.names = c(NA,
-20L), class = "data.frame")
The frames are created by the function:
accumulate_by <- function(dat, var) {
var <- lazyeval::f_eval(var, dat)
lvls <- plotly:::getLevels(var)
dats <- lapply(seq_along(lvls), function(x) {
cbind(dat[var %in% lvls[seq(1, x)], ], frame = lvls[[x]])
})
dplyr::bind_rows(dats)
}
I have the following for the plot:
plot <- ggplot(Plot) + aes(x = Strain, y = Stress, colour = Instrumentation, linetype = Bar, frame = frame) +
scale_color_manual(values = c("DIC"="red", "LVDT"="blue")) + geom_line(size = 0.8) + theme_classic() +
labs(x = "Strain (in/in)", y = "Stress (ksi)") +
theme_classic() + theme(axis.text = element_text(color = "black", size = 16),
axis.line = element_line(color = "black", size = 0.2), axis.ticks.y = element_line(color = "black", size = 0.2),
axis.title.y = element_text(color = "black", size = 20, margin = margin(0,40,0,0)),
axis.title.x = element_text(color = "black", size = 20, margin = margin(35,0,0,0)),
legend.title = element_blank(), legend.text = element_text(color = "black", size = 16))
ggplotly(
p = ggplot2::last_plot(),
width = NULL,
height = NULL,
tooltip = c("Strain","Stress","Instrumentation","Bar"),
dynamicTicks = FALSE,
layerData = 1,
originalData = TRUE,) %>% animation_opts(frame = 300, transition = 0, easing = "linear", redraw = TRUE) %>%
layout(yaxis = list(title = list(text = "Stress (ksi)", standoff = 30L), spikesides = TRUE,spikethickness = 1),
xaxis = list(title = list(text = "Strain (in/in)",standoff = 30L), spikesides = TRUE,spikethickness = 1),
legend = list(orientation = "v", x = 0.7, y = 0.13)) %>% animation_slider(hide = TRUE)
Also, the redraw doesn't seem to do what I want. I want the plot to start with the complete graph (last frame and all lines) and then also end with everything completed. I only want the animation when pressing the play button.
EDITED:
The initial data is comprised of multiple dataframes. I accumulated the frames for each dataframe independently and then collected them in a single dataframe with rbind.
> dput(sample_n(Plot.Spliced_DIC, 5))
structure(list(Strain = c(0.00635239, 0.00646411, 0.00304078,
0.00104394, 0.00138191), Stress = c(64.9199586945409, 65.0674673934705,
60.7649363239015, 26.5627079525764, 39.4159208404832), Instrumentation = structure(c(1L,
1L, 1L, 1L, 1L), .Label = "DIC", class = "factor"), Bar = structure(c(1L,
1L, 1L, 1L, 1L), .Label = "Spliced", class = "factor"), ANIM = c(0.01,
0.01, 0, 0, 0)), class = "data.frame", row.names = c(NA,
-5L))
> dput(sample_n(Plot.Unspliced_DIC, 5))
structure(list(Strain = c(7.66444e-05, 0.112481, 6.7294e-05,
0.00275991, 0.0600871), Stress = c(0.00344797841982851, 92.8897366602444,
0.522824377824084, 64.3513766859271, 88.2700702030104), Instrumentation = structure(c(1L,
1L, 1L, 1L, 1L), .Label = "DIC", class = "factor"), Bar = structure(c(1L,
1L, 1L, 1L, 1L), .Label = "Unspliced", class = "factor"), ANIM = c(0,
0.11, 0, 0, 0.06)), class = "data.frame", row.names = c(NA,
-5L))
> dput(sample_n(Plot.Unspliced_LVDT, 5))
structure(list(Strain = c(0.071858225, 0.0020442, 0.01736605,
0.0259565, 0.025441275), Stress = c(90.4766041042011, 60.701740404307,
70.0774864366534, 76.21702132901, 75.9110679987475), Instrumentation = structure(c(1L,
1L, 1L, 1L, 1L), .Label = "LVDT", class = "factor"), Bar = structure(c(1L,
1L, 1L, 1L, 1L), .Label = "Unspliced", class = "factor"), ANIM = c(0.07,
0, 0.02, 0.03, 0.03)), class = "data.frame", row.names = c(NA,
-5L))
> dput(sample_n(Plot.Spliced_LVDT, 5))
structure(list(Strain = c(0.0238954832535885, 0.00040463157894736,
0.0158640956937799, 0.0224346507177033, 0.00269568421052631),
Stress = c(85.3207044456991, 14.881393139828, 79.7864191978379,
84.4980682215488, 56.6941352672259), Instrumentation = structure(c(1L,
1L, 1L, 1L, 1L), .Label = "LVDT", class = "factor"), Bar = structure(c(1L,
1L, 1L, 1L, 1L), .Label = "Spliced", class = "factor"), ANIM = c(0.02,
0, 0.02, 0.02, 0)), class = "data.frame", row.names = c(NA, -5L))
Plot.Spliced_DIC <- Plot.Spliced_DIC %>% accumulate_by(~ANIM)
Plot.Unspliced_DIC <- Plot.Unspliced_DIC %>% accumulate_by(~ANIM)
Plot.Unspliced_LVDT <- Plot.Unspliced_LVDT %>% accumulate_by(~ANIM)
Plot.Spliced_LVDT <- Plot.Spliced_LVDT %>% accumulate_by(~ANIM)
Plot <- rbind(Plot.Spliced_DIC, Plot.Unspliced_DIC, Plot.Unspliced_LVDT, Plot.Spliced_LVDT)
There are two issues regarding your above approach:
you need to call accumulate_by after using rbind
There seems to be a bug when using the tooltip argument along with an animation (traces are disappearing - I therefore commented it out)
Please check the following:
library(plotly)
library(dplyr)
accumulate_by <- function(dat, var) {
var <- lazyeval::f_eval(var, dat)
lvls <- plotly:::getLevels(var)
dats <- lapply(seq_along(lvls), function(x) {
cbind(dat[var %in% lvls[seq(1, x)], ], frame = lvls[[x]])
})
dplyr::bind_rows(dats)
}
Plot.Spliced_DIC <-
structure(list(Strain = c(0.00635239, 0.00646411, 0.00304078, 0.00104394, 0.00138191),
Stress = c(64.9199586945409, 65.0674673934705, 60.7649363239015, 26.5627079525764, 39.4159208404832),
Instrumentation = structure(c(1L, 1L, 1L, 1L, 1L), .Label = "DIC", class = "factor"),
Bar = structure(c(1L, 1L, 1L, 1L, 1L), .Label = "Spliced", class = "factor"),
ANIM = c(0.01, 0.01, 0, 0, 0)), class = "data.frame", row.names = c(NA, -5L))
Plot.Unspliced_DIC <-
structure(list(Strain = c(7.66444e-05, 0.112481, 6.7294e-05, 0.00275991, 0.0600871),
Stress = c(0.00344797841982851, 92.8897366602444, 0.522824377824084, 64.3513766859271, 88.2700702030104),
Instrumentation = structure(c(1L, 1L, 1L, 1L, 1L), .Label = "DIC", class = "factor"),
Bar = structure(c(1L, 1L, 1L, 1L, 1L), .Label = "Unspliced", class = "factor"),
ANIM = c(0, 0.11, 0, 0, 0.06)), class = "data.frame", row.names = c(NA, -5L))
Plot.Unspliced_LVDT <-
structure(list(Strain = c(0.071858225, 0.0020442, 0.01736605,0.0259565, 0.025441275),
Stress = c(90.4766041042011, 60.701740404307, 70.0774864366534, 76.21702132901, 75.9110679987475),
Instrumentation = structure(c(1L, 1L, 1L, 1L, 1L), .Label = "LVDT", class = "factor"),
Bar = structure(c(1L, 1L, 1L, 1L, 1L), .Label = "Unspliced", class = "factor"),
ANIM = c(0.07,0, 0.02, 0.03, 0.03)), class = "data.frame", row.names = c(NA, -5L))
Plot.Spliced_LVDT <-
structure(list(Strain = c(0.0238954832535885, 0.00040463157894736,
0.0158640956937799, 0.0224346507177033, 0.00269568421052631),
Stress = c(85.3207044456991, 14.881393139828, 79.7864191978379,
84.4980682215488, 56.6941352672259),
Instrumentation = structure(c(1L, 1L, 1L, 1L, 1L), .Label = "LVDT", class = "factor"),
Bar = structure(c(1L, 1L, 1L, 1L, 1L), .Label = "Spliced", class = "factor"),
ANIM = c(0.02, 0, 0.02, 0.02, 0)), class = "data.frame", row.names = c(NA, -5L))
plotData <- rbind(Plot.Spliced_DIC, Plot.Unspliced_DIC, Plot.Unspliced_LVDT, Plot.Spliced_LVDT)
plotData <- plotData %>% accumulate_by(~ANIM)
lastFrame <- with(plotData, plotData[frame == max(frame),])
lastFrame$frame <- -1
plotData <- rbind(lastFrame, plotData) # prepend last frame to show all complete traces in the beginning
plot <- ggplot(plotData) + aes(x = Strain, y = Stress, colour = Instrumentation, linetype = Bar, frame = frame) +
scale_color_manual(values = c("DIC"="red", "LVDT"="blue")) + geom_line(size = 0.8) + theme_classic() +
labs(x = "Strain (in/in)", y = "Stress (ksi)") +
theme_classic() + theme(axis.text = element_text(color = "black", size = 16),
axis.line = element_line(color = "black", size = 0.2), axis.ticks.y = element_line(color = "black", size = 0.2),
axis.title.y = element_text(color = "black", size = 20, margin = margin(0,40,0,0)),
axis.title.x = element_text(color = "black", size = 20, margin = margin(35,0,0,0)),
legend.title = element_blank(), legend.text = element_text(color = "black", size = 16))
ggplotly(
p = ggplot2::last_plot(),
width = NULL,
height = NULL,
# tooltip = c("Strain","Stress","Instrumentation","Bar"), # bug?
# tooltip = c("x","y","colour","linetype"), # bug?
dynamicTicks = FALSE,
layerData = 1,
originalData = TRUE) %>%
animation_opts(frame = 300, transition = 0, easing = "linear", redraw = TRUE) %>%
layout(yaxis = list(title = list(text = "Stress (ksi)", standoff = 30L), spikesides = TRUE,spikethickness = 1),
xaxis = list(title = list(text = "Strain (in/in)",standoff = 30L), spikesides = TRUE,spikethickness = 1),
legend = list(orientation = "v", x = 0.7, y = 0.13)) %>%
animation_slider(hide = TRUE)
By the way the approach to create cumulative animations using accumulate_by will turn slower with more data. Here you can find another approach to create a cumulative animation by filtering the data. However, the R plotly package currently doesn't allow providing custom steps for animation sliders.
Please support my FR if you are interested.

Colors not displaying correctly on a 3D scatterplot (R)

I am trying to make a couple of plots (code below) and to keep the colors consistent between the two graphs. One graph contains 8 data points and the other contains 5. Despite using almost identical code for each of the plots, the colors do not match up. Does anyone have any insight as to why the colors are not matching up between the two graphs?
Correct colors (https://plot.ly/~MKT533/3/#/):
p <-
plot_ly(
mkt533,
x = ~ onsitetrainers_x,
y = ~ lowprice_y,
z = ~ flexibleclasses_z,
color = ~ name,
colors = c(
"#AB1100",
"#00274C",
"#00B5AF",
"#00274C",
"#00274C",
"#72088E",
"#E9B000",
"#0050AC"
)
) %>%
add_markers() %>%
layout(scene = list(
xaxis = list(title = "Professional guidance",
range = c(1, 10)),
yaxis = list(title =
"Value for money", range = c(1, 10)),
zaxis = list(title =
"Time flexibility", range = c(1, 10))
))
Wrong colors (https://plot.ly/~MKT533/1/#/):
mkt533_product <- subset(mkt533, type!="Segment")
product <-
plot_ly(
mkt533_product,
x = ~ onsitetrainers_x,
y = ~ lowprice_y,
z = ~ flexibleclasses_z,
color = ~ name,
colors = c("#AB1100", "#00B5AF", "#72088E", "#E9B000", "#0050AC")
) %>%
add_markers() %>%
layout(scene = list(
xaxis = list(title = "Professional guidance", range = c(1, 10)),
yaxis = list(title = "Value for money", range =
c(1, 10)),
zaxis = list(title = "Time flexibility", range =
c(1, 10))
))
Here are the data I am using for these plots:
mkt533 <-
structure(
list(
onsitetrainers_x = c(1L, 3L, 10L, 9L, 2L, 1L,
7L, 10L),
lowprice_y = c(10L, 3L, 3L, 2L, 7L, 7L, 3L, 1L),
flexibleclasses_z = c(4L,
8L, 3L, 5L, 7L, 1L, 6L, 6L),
name = structure(
c(4L, 2L, 5L, 3L,
7L, 1L, 8L, 6L),
.Label = c(
"At-home gym",
"Busy young families",
"CrossFit",
"Fitness-conscious youth",
"Need that extra push",
"Taekwondo gym",
"YMCA",
"Yoga studio"
),
class = "factor"
),
type = structure(
c(3L,
3L, 3L, 2L, 5L, 1L, 6L, 4L),
.Label = c(
"At-home gym",
"CrossFit",
"Segment",
"Taekwondo gym",
"YMCA",
"Yoga studio"
),
class = "factor"
),
size = c(0.55, 0.3, 0.15, 0.25, 0.25, 0.25, 0.25, 0.25)
),
class = "data.frame",
row.names = c(NA,-8L)
)
And mkt533_product
structure(
list(
onsitetrainers_x = c(9L, 2L, 1L, 7L, 10L),
lowprice_y = c(2L,
7L, 7L, 3L, 1L),
flexibleclasses_z = c(5L, 7L, 1L, 6L, 6L),
name = structure(
c(3L,
7L, 1L, 8L, 6L),
.Label = c(
"At-home gym",
"Busy young families",
"CrossFit",
"Fitness-conscious youth",
"Need that extra push",
"Taekwondo gym",
"YMCA",
"Yoga studio"
),
class = "factor"
),
type = structure(
c(2L,
5L, 1L, 6L, 4L),
.Label = c(
"At-home gym",
"CrossFit",
"Segment",
"Taekwondo gym",
"YMCA",
"Yoga studio"
),
class = "factor"
),
size = c(0.25,
0.25, 0.25, 0.25, 0.25)
),
row.names = 4:8,
class = "data.frame"
)
The colors are different because you supplied different colors for each plot. More specifically because mkt533_product is a subset of mkt533 it retains the organization of each variable, even if all the contents of that variable aren't retained. So
mkt533$name
[1] Fitness-conscious youth Busy young families Need that extra push CrossFit
[5] YMCA At-home gym Yoga studio Taekwondo gym
8 Levels: At-home gym Busy young families CrossFit Fitness-conscious youth Need that extra push Taekwondo gym ... Yoga studio
and
mkt533_product$name
[1] CrossFit YMCA At-home gym Yoga studio Taekwondo gym
8 Levels: At-home gym Busy young families CrossFit Fitness-conscious youth Need that extra push Taekwondo gym ... Yoga studio
have different content, but the same 8 levels. If you supply each plot with the same colors, the same color will be mapped to the same level in each plot, which is what you want
p <-
plot_ly(
mkt533,
x = ~ onsitetrainers_x,
y = ~ lowprice_y,
z = ~ flexibleclasses_z,
color = ~ name,
colors = c(
"#AB1100",
"#00274C",
"#00B5AF",
"#00274C",
"#00274C",
"#72088E",
"#E9B000",
"#0050AC"
)
) %>%
add_markers() %>%
layout(scene = list(
xaxis = list(title = "Professional guidance", range = c(1, 10)),
yaxis = list(title = "Value for money", range =
c(1, 10)),
zaxis = list(title = "Time flexibility", range =
c(1, 10))
))
product <-
plot_ly(
mkt533_product,
x = ~ onsitetrainers_x,
y = ~ lowprice_y,
z = ~ flexibleclasses_z,
color = ~ name,
colors = c(
"#AB1100",
"#00274C",
"#00B5AF",
"#00274C",
"#00274C",
"#72088E",
"#E9B000",
"#0050AC"
)
) %>%
add_markers() %>%
layout(scene = list(
xaxis = list(title = "Professional guidance", range = c(1, 10)),
yaxis = list(title = "Value for money", range =
c(1, 10)),
zaxis = list(title = "Time flexibility", range =
c(1, 10))
))

How to add ellipses to each cluster of 3D scatter plot using updatemenus in plotly R?

I wanted to create 3D scatter plot in R plotly and add ellipses to each cluster of plot using updatemenue. (Something similar to "Relayout Button" section in https://plot.ly/r/custom-buttons/#relayout-button but for 3D one). I'm able to add ellipses using ellipse3d to plotly plot but I don't know how to make it interactive with updatemenue layout.
I wrote below code but not adding updatemenus yet. Would you please give me a help?
df<-
structure(list(C = structure(c(1L, 1L, 1L, 2L, 2L, 2L, 3L,
3L, 3L, 4L, 4L, 4L), .Label = c("h", "j", "k", "l"), class = "factor"),
R = structure(c(1L, 2L, 3L, 1L, 2L, 3L, 1L, 2L, 3L, 1L,
2L, 3L), .Label = c("a", "b", "c"), class = "factor"),
p1 = c(-58.2553800845032, -56.8446241583638, -57.4730903743034,
9.69295162882175, 23.2783600609086, 17.5961245834489, 27.1776771896781,
31.8555589999195, 31.1329423894753, 5.49176565720366, 12.9720812431292,
13.3756328645854), p2 = c(1.89343789795219, 2.96630118684064,
3.36783254906029, 22.1036613994383, 19.1821210966211, 26.161634708624,
0.00600630960161123, 6.18082767371698, 1.73282189156538,
-26.351364716711, -26.6021818789505, -30.641098117759), p3 = c(1.98930539820297,
3.3628193816464, 4.50430994627108, -16.0161352497141, -10.0505758631406,
-3.19889710494869, 8.92935203885341, 7.00720243933593, 22.7494673296249,
-11.7929746942337, -5.26783717642642, -2.21603644547113)), .Names = c("C",
"R", "p1", "p2", "p3"), class = "data.frame", row.names = c(NA,
-12L))
library(plotly)
library(corpcor)
library(rgl)
x=df$p1; y=df$p2; z=df$p3
col <- c("orange", "blue", "purple", "green")
p <- plot_ly(df, x =x, y = y, z = z,type = "scatter3d",
mode = "markers", marker = list(color = col[df$C],
showscale = FALSE)
#, text = paste(df$C, df$R)
)
groups <- df$C
levs <- levels(groups)
group.col <- c("red", "blue", "yellow", "green")
for (i in 1:length(levs)) {
group <- levs[i]
selected <- groups == group
xx <- x[selected]; yy <- y[selected]; zz <- z[selected]
co<- cov(cbind(xx,yy,zz))
S<- make.positive.definite(co)
ellips <- ellipse3d(S, centre=c(mean(xx),mean(yy),mean(zz)), level = 0.95)
p<- add_trace(p, x = ellips$vb[1,], y = ellips$vb[2,], z = ellips$vb[3,]
,type = 'scatter3d', size = 1
,opacity=0.002
#,color= group.col[i]
,showlegend = FALSE)
}
print(p)

Resources