Plotly stacked bar chart add_trace loop issue - r

I am building a stacked bar chart in plotly and whenever I run my loop for add_trace, there is an issue as data of the previous trace seems to dissapear while names remain.
p = plot_ly( x = rownames(dist_data), y = as.numeric(dist_data[,1]), type = 'bar', name = colnames(dist_data)[1])%>%
layout(legend = list(x = 0.1, y = 0.9))
for ( j in 2:length(colnames(dist_data)))
{
p = add_trace(p, y = ~as.numeric(dist_data[,j]), type = 'bar',name = colnames(dist_data)[j]) %>%
layout( barmode = 'stack')
}
p
I am wondering whether there is something wrong in the loop.
When trying manually for adding trace1, works fine. When adding trace 2 (j=3), trace1's values become automatically equal to trace2's value.
UPD: When using dplyr, I have issues with some other parts of my code.
Is there a solution without it?
Thank you for the help,

You are overwriting p at each loop iteration. Try:
p = p %>% add_trace(y = ~as.numeric(dist_data[,j]), type = 'bar',name = colnames(dist_data)[j]) %>%
layout( barmode = 'stack')
2nd Edit:
not sure why this is happening. It works if you reshape to a long format dataframe which is better practice than using a for loop:
mtcars %>%
mutate(id = rownames(.)) %>%
gather(key = "variable",value = "value",-id) %>%
plot_ly(x = ~id, y=~value, type="bar", color=~variable) %>%
layout(barmode = "stack")
Edit:
dist_data=mtcars
p = plot_ly( x = rownames(dist_data),
y = as.numeric(dist_data[,1]),
type = 'bar', name = colnames(dist_data)[1]) %>%
layout(legend = list(x = 0.1, y = 0.9))
for ( j in 2:length(colnames(dist_data))){
p = add_trace(p, y = ~as.numeric(dist_data[,j]),
type = 'bar',name = colnames(dist_data)[j]) %>%
layout( barmode = 'stack')
}
p

Related

R plotly simple boxplot highlighting the most recent value

I probably have a simple question but I can't find a way to achieve what I need. I have a simple boxplot as the following:
end_dt <- as.Date("2021-02-12")
start_dt <- end_dt - (nrow(iris) - 1)
dim(iris)
dates <- seq.Date(start_dt, end_dt, by="1 day")
df <- iris
df$LAST_VAL <- "N"
df[3, 'LAST_VAL'] <- "Y"
df1 <- df[,c("Sepal.Length","LAST_VAL")]
df1$DES <- 'Sepal.Length'
colnames(df1) <- c("VALUES","LAST_VAL","DES")
df2 <- df[,c("Sepal.Width","LAST_VAL")]
df2$DES <- 'Sepal.Width'
colnames(df2) <- c("VALUES","LAST_VAL","DES")
df <- rbind(df1, df2)
fig <- plot_ly(df, y = ~VALUES, color = ~DES, type = "box") %>% layout(showlegend = FALSE)
What I would like to do now is a add a red marker to each box plot just for the value corresponding to LAST_VAL = "Y". This would allow me to see given the distribution of each plot, to see where the most recent value is located.
I tried to use the info on https://plotly.com/r/box-plots/ but I can't figure out how to do this.
Thanks
The following solution ended up to be a bit too long codewise. However, it should give you what you asked for. I think the boxplots should be added afterwards, like:
fig <- plot_ly(df[df$LAST_VAL=="Y",],
x=~DES, y = ~VALUES, color = ~DES, type = "scatter", colors='red') %>%
layout(showlegend = FALSE) %>%
add_boxplot(data = df[df$DES=="Sepal.Length",], x = ~DES, y = ~VALUES,
showlegend = F, color = ~DES,
boxpoints = F, fillcolor = 'white', line = list(color = c('blue'))) %>%
add_boxplot(data = df[df$DES=="Sepal.Width",], x = ~DES, y = ~VALUES,
showlegend = F, color = ~DES,
boxpoints = F, fillcolor = 'white', line = list(color = c('green')))

R plotly histogram hover text

This is my code. Just a simple historgram. But what I wanted to do is to customize the hover text so that when I hover, it will display all species included in that histogram bar. Can you help me?
iris %>%
plot_ly(x=~Sepal.Length, color=~Sepal.Width, text=~Species) %>%
add_histogram()
Here's the output. But when I hover it seems the text is only displaying the first species in the table.
plotly_hist
I'm not sure whether this is possible. Probably you are demanding too much from plotly. After trying some options I think there are two ways to go if you want the different Species to show up in the tooltip:
First option is to use a stacked histogram using hovermode = "unified" like so:
library(plotly)
fig <- plot_ly()
fig <- fig %>% add_trace(data = filter(iris, Species == "setosa"),
x = ~Sepal.Length,
color = ~Species,
text = ~Species,
type='histogram',
bingroup=1, showlegend = FALSE)
fig <- fig %>% add_trace(data = filter(iris, Species == "versicolor"),
x = ~Sepal.Length,
color = ~Species,
text = ~Species,
type='histogram',
bingroup=1, showlegend = FALSE)
fig <- fig %>% add_trace(data = filter(iris, Species == "virginica"),
x = ~Sepal.Length,
color = ~Species,
text = ~Species,
type='histogram',
bingroup=1, showlegend = FALSE)
fig <- fig %>% layout(
hovermode="unified",
barmode="stack",
bargap=0.1)
fig
The second option would be to make the computations yourself, i.e. binning and summarising and to make a bar chart of the counts.
iris %>%
mutate(Sepal.Length.Cut = cut(Sepal.Length, breaks = seq(4, 8, .5), right = FALSE)) %>%
group_by(Sepal.Length.Cut, Species) %>%
summarise(n = n(), Sepal.Width = sum(Sepal.Width)) %>%
tidyr::unite("text", Species, n, sep = ": ", remove = FALSE) %>%
summarise(n = sum(n), Sepal.Width = sum(Sepal.Width) / n, text = paste(unique(text), collapse = "\n")) %>%
plot_ly(x = ~Sepal.Length.Cut, y = ~n, text = ~text) %>%
add_bars(marker = list(colorscale = "Rainbow"), hovertemplate = "%{y}<br>%{text}")
Edit A third option would be to use ggplotly(). This way it is an easy task to add annotations displayling the total numbers per bin. This way we can make use of the stats layers in ggplot2 which will do all the computations. To the best of my knowledge that couldn't be done that easily using "pure" plotly.
library(plotly)
ggplot(iris, aes(Sepal.Length, fill = Species)) +
stat_bin(breaks = seq(4, 8, .5), closed = "left") +
stat_bin(breaks = seq(4, 8, .5), closed = "left", geom = "text", mapping = aes(Sepal.Length, label = ..count..), inherit.aes = FALSE, vjust = -.5) +
theme_light()
ggplotly()

How do I split grouped bar chart in R by variable

I am trying to split the attached grouped bar chart by the variable spec. Two thoughts on best way to do this are by adding facet_grid() or if a filter can be applied to the static output? Can either be done? Any advice appreciated.
a sample is below:
period <- c('201901', '201901', '201904', '201905')
spec <- c('alpha', 'bravo','bravo', 'charlie')
c <- c(5,6,3,8)
e <- c(1,2,4,5)
df <- data.frame(period, spec, c,e)
library(tidyverse)
library(plotly)
plot_ly(df, x =~period, y = ~c, type = 'bar', name = "C 1", marker = list(color = 'lightsteelblue3'))
%>%
add_trace(y = ~e, name = "E 1", marker = list(color = 'Gray')) %>%
layout(xaxis = list(title="", tickangle = -45),
yaxis = list(title=""),
margin= list(b=100),
barmode = 'group'
)
I am not sure if you are plotting what you actually want to achieve? My suggestion is to create your plot using standard ggplot and then use ggplotly.
For this, you also need to reshape your data and make it a bit longer.
library(tidyverse)
library(plotly)
period <- c('201901', '201901', '201904', '201905')
spec <- c('alpha', 'bravo','bravo', 'charlie')
c <- c(5,6,3,8)
e <- c(1,2,4,5)
df <- data.frame(period, spec, c,e) %>%
pivot_longer(cols = c(c,e), names_to = 'var', values_to = 'val')
p <- ggplot(df, aes(period, val, fill = var)) +
geom_col(position = position_dodge()) +
facet_grid(~spec)
ggplotly(p)
It's probably easier to use facets here, but a more "interactive" option would be to use a filter transforms which gives you a drop-down menu in the top left corner of your plot.
spec.val <- unique(df$spec)
plot_ly(
df %>% pivot_longer(-c(period, spec)),
x = ~period, y = ~value, color = ~name,
type = "bar",
transforms = list(
list(
type = "filter",
target = ~spec,
operation = "=",
value = spec.val[1]))) %>%
layout(
updatemenus = list(
list(
type = "drowdown",
active = 0,
buttons = map(spec.val, ~list(
method = "restyle",
args = list("transforms[0].value", .x),
label = .x)))))

R Plotly Deselect trace by default

I am ussing R Plotly and have a line of the form:
add_trace(y = meanRank,
x = DateOnly,
data = timeSeriesDF,
name = "Daily Value",
text = hoverText,
hoverinfo = "text",
showlegend = TRUE)
It works fine. However, I want this trace to be "unselected" when the plot is shown. So a user would click it on the legend to show the line. I can't seem to find the parameter to show that.
You could add visible = "legendonly":
library(plotly)
economics %>%
transform(rate = unemploy / pop) %>%
plot_ly(x = date, y = rate) %>%
loess(rate ~ as.numeric(date), data = .) %>%
broom::augment() %>%
add_trace(y = .fitted, name = "foo", visible = "legendonly")
See the reference.
you can use the attribute 'visible = legendonly' to other add_ functions such as:
add_lines(x = as.Date(x()$ds),
y = round(y()$total),
name = 'Inventory Total',
visible = 'legendonly')

R plotly show only labels where percentage value is value is above 10

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...

Resources