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")
)
How do I get the text size for dr5 and dr3 for the shorter bars? If the text is longer than the bar span, I would like the text to overflow past the end of the bar.
I tried using uniformtext in layout, but that shrunk all text to the smallest font being used. How do I change all font to the biggest size being used?
library(plotly)
# Test long text and short bars
xValues <- c("loooooooooooooooooonnnnnngg","lonnnnnnnnnnggggggg",
"dr3","dr4","dr5")
yValues <- c(0.5,1,2,0.22,10)
bar <- plot_ly(x = yValues,
y = xValues) %>%
add_trace(
type = 'bar',
orientation = 'h',
text = xValues,
textangle = 360,
textposition = "inside",
insidetextanchor = "start",
showlegend = F) %>%
layout(
yaxis = list(zeroline = FALSE,showline = FALSE,showticklabels = FALSE),
uniformtext = list(mode = "show")
)
bar
This can be achieved by adding the labels via add_text like so:
BTW: I put the vectors inside a df. Seems more natural to me.
library(plotly)
# Test long text and short bars
xValues <- c("loooooooooooooooooonnnnnngg","lonnnnnnnnnnggggggg",
"dr3","dr4","dr5")
yValues <- c(0.5,1,2,0.22,10)
df <- data.frame(
x = xValues,
y = yValues
)
bar <- plot_ly(df, x = ~y, y = ~x, text = ~x) %>%
add_trace(
type = 'bar',
orientation = 'h',
showlegend = F) %>%
add_text(x = 0.1, textposition = "middleright") %>%
layout(yaxis = list(zeroline = FALSE,showline = FALSE, showticklabels = FALSE))
bar
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 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)))))
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')