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')
Related
I am using Plotly to plot a scatterplot of GWAS data and want to highlight a certain point a different colour to the rest of the data. I have tried multiple times but unable to find away around this in Plotly. Any advice would be great please.
input data looks like this:
fig <- fig %>% add_trace(data=data_1, x = ~BP, y = ~log, name = "data", mode = "markers", type = "scatter",
y = c(117300000, 117900000), marker = list(size = 8, color = '#d62728'),
x = c(117558703), y = c(19.75696195), marker = list(color = 'blue',size = 8), type = "scatter")
fig
One of the easiest ways is to create a variable to identify that specific point. I created sample data here and assigned a colour variable equal to 1 for the point I want in another color.
df = tibble(bp = round(rnorm(10,5,2),2),
log = round(rnorm(10,6,1.5),2))
df$colour <- as.factor(ifelse(df$bp == 4.41,1 ,0))
fig <- plot_ly(data = df, x = ~bp, y = ~log, group_by = ~colour,marker = list(color = factor(df$colour,labels=c("red","purple")))) %>%
add_trace(data = df, x = ~bp, y = ~log, mode = 'markers', type = 'scatter')
fig
Link to plot produced by this code
One option to achieve your desired result would be to add an indicator variable to your data to indicate which points you want to highlight. This variable could then be mapped on the color attribute. The colors could then be set via the colors attribute.
Using a minimal reproducible example base on mtcars:
library(plotly)
data_1 <- mtcars
data_1$highlight <- row.names(data_1) %in% c("Honda Civic", "Porsche 914-2")
plot_ly() %>%
add_trace(
data = data_1, x = ~hp, y = ~mpg, color = ~highlight,
mode = "markers", type = "scatter",
marker = list(size = 8), colors = c("#d62728", "blue")
)
I must be having trouble with less than a one liner,
but have a look at the snippet below: I cannot the legend option to enter the text that I want in the legend as the name of the species (say, "foo1", "foo2", "foo3").
Notice that I do not want to change the original (iris in this case) dataset.
Any suggestion?
library(tidyverse)
library(plotly)
plot_ly(iris, x = ~Sepal.Length,
y = ~Sepal.Width,
type = 'scatter', color = ~Species,
symbol = ~Species,
mode = 'markers') %>%
layout(legend=list(title=list(text='My title')))
Plotly considers legend names to be associated with each trace rather than with the legend itself. So redefining names has to occur on each trace. If you don't want to modify the original dataset, you'd have to filter it by Species and add the trace with the new name one at a time, with something like this:
library(tidyverse)
library(plotly)
plot_ly(iris %>% filter(Species == "setosa"),
x = ~Sepal.Length,
y = ~Sepal.Width,
type = 'scatter',
color = ~Species,
symbol = ~Species,
mode = 'markers',
name = "foo 1") %>%
add_trace(data = iris %>% filter(Species == "versicolor"),
x = ~Sepal.Length,
y = ~Sepal.Width,
type = 'scatter',
color = ~Species,
symbol = ~Species,
mode = 'markers',
name = "foo 2") %>%
add_trace(data = iris %>% filter(Species == "virginica"),
x = ~Sepal.Length,
y = ~Sepal.Width,
type = 'scatter',
color = ~Species,
symbol = ~Species,
mode = 'markers',
name = "foo 3") %>%
layout(legend=list(title=list(text='My title')))
In a more complex case, it may be best to indeed modify the dataset itself or use a loop. A similar question about a more complex case is here: Manipulating legend text in R plotly and the reference documentation on plotly legend names is here: https://plotly.com/r/legend/#legend-names
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')
This code makes a simple 3d scatter plot of the Fisher iris dataset, with an additional categorical variable added:
library(plotly)
roots <- factor(round(runif(n = dim(iris)[2],min = -.499,max = 2.499)))
my_iris <- cbind(data.frame(roots), iris)
plot_ly() %>%
add_trace(data = my_iris, type = 'scatter3d', mode = "markers",
x = ~Sepal.Length,
y = ~Petal.Length,
z = ~Sepal.Width,
color = ~Species,
colors = c("red","blue","green")
)
By looking at this help page: https://plot.ly/r/marker-style/
I was able to figure out that you can add an outline to the points like this:
plot_ly() %>%
add_trace(data = my_iris, type = 'scatter3d', mode = "markers",
x = ~Sepal.Length,
y = ~Petal.Length,
z = ~Sepal.Width,
color = ~Species,
colors = c("#00FA9A34","#B22222dd","#00BFFFee"),
marker = list(
line = list(
color = "#aabbffdd",
width = 2
)
)
)
Looking at this site https://plot.ly/r/reference/#scatter3d made the idea that lines are a property of scatter3d markers that in turn have the properties color and width make sense.
Now I attempt to map colors to the outlines based on my new roots variable,
plot_ly() %>%
add_trace(data = my_iris, type = 'scatter3d', mode = "markers",
x = ~Sepal.Length,
y = ~Petal.Length,
z = ~Sepal.Width,
color = ~Species,
colors = c("#00FA9A34","#B22222dd","#00BFFF66"),
marker = list(
line = list(
color = ~roots,
colors = c("#000000ff","#f00f3355","#dd22ccbb"),
width = 2
)
)
)
and it doesn't quite work: The first hex+alpha value I use should map to completely opaque black, but that is not one of the colors I get, and I would expect to see legend entries that describe the output.
So my question is: is there a way to do this aesthetic mapping? Perhaps instead of using add_trace I should use add_markers? Is there a way to do this in 2d scatters in Plotly R? Also would appreciate hints on how to learn Plotly for R properly as the documentation page I linked to above is a bit opaque and there seem to be fewer great resources to learn plotly than there are for ggplot2.
it seems to me that plotly doesn't allow to specifying the colors of markers outline.
For the labels you can change the hover text.
Or use annotations:
https://plotly.com/r/text-and-annotations/
Maybe this doesn't solve your problem but I hope that be useful someway.
# Yours data
library(dplyr)
library(plotly)
roots <- as.character(round(runif(n = dim(iris)[2],min = -.499,max = 2.499)))
my_iris <- cbind(data.frame(roots), iris)
# Changing plot
my_iris %>%
plot_ly(type = 'scatter3d', mode = "markers") %>%
add_trace(x = ~Sepal.Length,
y = ~Petal.Length,
z = ~Sepal.Width,
color = ~Species,
colors = c("#00FA9A34","#B22222dd","#00BFFF66"),
marker = list(
line = list(
color = ~roots,
colors = c("#000000","#E35F13","#E3138B"),
width = 6
)
),
hoverinfo = 'text',
text = ~paste('</br> Species: ', Species,
'</br> Petal Length: ', Petal.Length,
'</br> Petal Width: ', Petal.Width,
'</br> Roots: ',roots)
)
The Output:
I was able to find a solution that I still think is inadequate: Set the variable that you are using to color the marker outlines to the colors you want to use themselves:
library(plotly)
roots <- round(runif(n = dim(iris)[1],min = -.499,max = 2.499))
roots_colors <- vector(mode="character", length=length(roots))
#setting the value of roots colors to be the colors we want
roots_colors[roots == 0] <- "#000000ff"
roots_colors[roots == 1] <- "#ff0000ff"
roots_colors[roots == 2] <- "#0000ffff"
my_iris <- cbind(data.frame(roots_colors), iris)
plot_ly() %>%
add_trace(data = my_iris, type = 'scatter3d', mode = "markers",
x = ~Sepal.Length,
y = ~Petal.Length,
z = ~Sepal.Width,
color = ~Species,
colors = c("#00FA9A34","#B22222dd","#00BFFF66"),
marker = list(
line = list(
color = ~roots_colors,
width = 2
)
)
)
We now have the appropriate colors that we want, but no legend describing them. Now I want to know how to make the legend reflect these colors.
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...