R plot_ly: How display discrete & non-discrete data on same axis? - r

I am working on a stacked bar plot for the following data set, and get an error "Can't display both discrete & non-discrete data on same axis". Also, data is not plotted correctly. For each "month" on X-axis, I expect to have stacked bars by "unit" with values from "value".
library(data.table)
library(plotly)
df <- fread(
'"month","unit","value"
"2017-01","Unit 1",1064000
"2017-01","Unit 2",911487
"2017-02","Unit 1",851200
"2017-02","Unit 2",656640
"2017-03","Unit 1",834905
"2017-03","Unit 2",601920')
df %>%
plot_ly(x = ~month, y = ~value, type = 'bar', name = "month") %>%
add_trace(y = ~unit, name = "unit") %>%
layout(yaxis = list(title = 'Units by dates'), barmode = 'stack')
I will be highly appreciated if someone knows how to make workable plots here.
Thanks!

You don't have to add a trace for a simple barplot it's easier to define a color-argument.
df %>%
plot_ly(x = ~month, y = ~value, color = ~unit, type = "bar") %>%
layout(yaxis = list(title = 'Units by dates'), barmode = 'stack')

Related

Create stacked bar chart for column based on unique levels of another dataframe column with plotly

I have the dataframe below and I would like to create a stacked bar chart with plotly for every country. The differents "stacks" will be the Year values
country<-c("AFG","AFG","ALB","ALB")
Year<-c("2019","2020","2019","2020")
value<-c(4,5,6,7)
note<-data.frame(country,Year,value)
fig <- plot_ly(mote, x = ~country, y = ~value, type = 'bar')
fig <- fig %>% add_trace(y = ~)
fig <- fig %>% layout(yaxis = list(title = 'Count'), barmode = 'stack')
fig

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

Plotly stacked bar chart add_trace loop issue

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

How to set different text and hoverinfo text

I am working with the plotly package, and I cannot find a way to display different things on the chart itself and in the hoverinfo.
Here is an example of a barchart:
library(plotly)
library(dplyr)
data(iris)
df <- iris %>%
group_by(Species) %>%
summarise(n = n(),
avg = mean(Sepal.Length))
p1 <- plot_ly(data = df,
x = ~Species,
y = ~n,
type = "bar",
text = ~paste("Species :", Species,
"<br> Avg :", avg),
textposition = "auto",
hoverinfo = "text")
From this code I get this:
And I would like to display the frequency (n) value in each bar instead of the same thing as the hoverinfo.
I have been looking at this thread but the solution described is too complicated for me and I think there must be an easier way to solve this issue.
Something like this?
p1 <- plot_ly(data = df,
x = ~Species,
y = ~n,
type = "bar",
text = ~n,
textposition = "auto",
hoverinfo = "text",
hovertext = paste("Species :", df$Species,
"<br> Avg :", df$avg))

Stacked area chart using Plotly and R without ggplot

Is there any way to make a stacked bar chart only using plot_ly in R? I'm aware a possible solution is to use ggplot and then convert with ggplotly but it doesn't look as nice as other plotly charts. The Plotly site has an example, but the totals stay the same when a category is removed via clicking on the legend.
Make example data:
library(tidyverse)
library(plotly)
# Create some data
grpnames <- c("Thing_3", "Thing_2", "Thing_1")
xval <- as.factor(c(100, 101, 102, 103))
frame <- merge(grpnames, xval, all=T)
yval <- runif(12, 0, .2)
df <- tbl_df(cbind(frame, yval))
colnames(df) <- c("GroupName", "X", "Y")
df.wide <- spread(df, key = GroupName, value = Y)
The stacked bar works:
# Creates a legit stacked bar where values sum to highest point
plot_ly(df, x = ~X, y = ~Y, color = ~GroupName, type='bar') %>%
layout(barmode = 'stack')
I couldn't find an analogue to "barmode = 'stack'" for a line chart:
# Attempt with tidy data
df %>%
plot_ly(
x = ~X,
y = ~Y,
color = ~GroupName,
type='scatter',
mode = 'lines',
fill = 'tonexty',
fillcolor = ~GroupName)
And the example from the Plotly side, attempted here, doesn't add the values of Y for each value of X -- it simply overlays them.
# Attempt with wide data
df.wide %>%
plot_ly(
x = ~X,
y = ~Thing_1,
name = 'Thing 1',
type = 'scatter',
mode = 'none',
fill = 'tozeroy',
fillcolor = 'aquamarine') %>%
add_trace(
x = ~X,
y = ~Thing_2,
name = 'Thing 2',
fill = 'tonexty',
fillcolor = 'orange') %>%
add_trace(
x = ~X,
y = ~Thing_3,
name = 'Thing 3',
fill = 'tonexty',
fillcolor = 'gray')
Has anyone been able to do this successfully? Thanks!
Edit for clarification: I'm aware that it's possible to do a cumsum first and then create the chart but still appreciate the responses! I'm wondering if it's possible to do the sum within the chart so that it behaves like the stacked bars, where clicking the legend to remove a group shows the sum for the remaining groups.
You can adjust your data to use the cumulative sum of the y value for that point to calculate the stacked value, e.g.
library(plotly)
library(tidyverse)
# group, sort (to keep cumulative sum in right order), and adjust Y
df %>% group_by(X) %>% arrange(GroupName) %>% mutate(Y = cumsum(Y)) %>%
plot_ly(type = 'scatter', x = ~X, y = ~Y, color = ~GroupName,
mode = 'lines', fill = 'tonexty')
For those few that stumble across this question even after a few years (like myself):
In 2021, the second link mentioned by #kkd42 is quite useful, the solution is stackgroup='one' here.
plot_ly(df,x=~X, y=~Y, color=~GroupName,
type='scatter', mode='line',
stackgroup='one')
does the job for me.
You can calculate the heights of the stacked areas by adding together the things you want to stack. Then plot these already-stacked cumulative values. The 'reproducible' data from the original question was not reproducible, so I demonstrate with some new data here.
[note that the data used in the example on the plotly page is also converted into a cumulative table like this - https://plot.ly/r/filled-area-plots/#stacked-area-chart-with-cumulative-values]
set.seed(123)
df.wide = data.frame(
X = 100:105,
Thing_1 = cumsum(rnorm(6,10,3)),
Thing_2 = cumsum(rnorm(6,6,2)),
Thing_3 = cumsum(rnorm(6,3,1)))
df.wide$T1 = df.wide$Thing_1
df.wide$T2 = df.wide$Thing_1 + df.wide$Thing_2
df.wide$T3 = df.wide$T2 + df.wide$Thing_3
plot_ly(df.wide, fill = 'tozeroy', line = list(color = '#00000000')) %>%
add_trace(x = ~X, y = ~T3, name = 'Thing 3',
type = 'scatter', mode = 'lines', fillcolor = 'green') %>%
add_trace(x = ~X, y = ~T2, name = 'Thing 2',
type = 'scatter', mode = 'lines', fill = 'tozeroy', fillcolor = 'blue') %>%
add_trace(x = ~X, y = ~T1, name = 'Thing 1',
type = 'scatter', mode = 'lines', fill = 'tozeroy', fillcolor = 'orange')

Resources