I am trying to connect the stacked bars with lines.
Expectation :
However I am unable to draw the lines between the bars. Have tried with the following script however it is not adding the line.
Using add_trace instead of 'add_lines' is not working.
df = data.frame(Aria = 20:25, Acqua = 21:26, Fuoco = 22:27,
Terra = 23:28, Cielo = 24:29,
Labels = c( 'Antonio', 'Maria', 'Giovanni',
'Sergio', 'Giorgio', 'Michele' ) )
evo_bar_plot_variant = function(plot_data, var_x, x_name = 'X axis',
y_name = 'Y axis', ... ){
df = data.frame(plot_data)
df = na.omit(df)
var = quos(...)
names_vars = names( var )
y_vars = names_vars[ startsWith( names_vars, 'var_y' ) ]
y_var_names = sapply(1:length(y_vars), function(j){
quo_name(var[[y_vars[j]]] )})
row_sum = df %>%
select( y_var_names ) %>%
rowSums()
xenc = enquo( var_x )
cols = colorRampPalette(c("white", "#4C68A2"))( length( y_vars ) )
#... Plot parameters .....
font_size = list( size = 12, family = 'Lato' )
gray_axis = '#dadada'
p = plot_ly(data = df, x = xenc, y = var[[ y_vars[1] ]],
name = quo_name( var[[ y_vars[1] ]] ),
type = 'bar', marker = list( color = cols[1],
line = list( color = '#E1E1E1', width = 0.8 ) ),
hoverlabel = list( font = font_size ) ) %>%
layout(title = list( text = 'Bar', x = 0 ), barmode = 'stack',
yaxis = list( title = y_name, showgrid = F,
zerolinecolor = gray_axis,
titlefont = font_size, side = 'right' ),
xaxis = list(title = x_name, linecolor = gray_axis,
zerolinecolor = gray_axis,
tickfont = font_size, titlefont = font_size),
legend = list(font = font_size, orientation= 'h',
font = font_size, x = 1 , y = 1.2,
xanchor = "left", yanchor = 'top' ))
if( length( y_vars ) >= 2 ){
for( i in 2:length( y_vars ) ){
p = p %>%
add_trace(y = var[[ y_vars[i] ]],
name = quo_name( var[[ y_vars[i] ]] ),
marker = list(color = cols[i],
line = list(color = '#E1E1E1', width = 0.8)),
hoverlabel = list(font = font_size))
}
}
p = p %>%
add_annotations(xref = 'x', yref = 'y',
y = ( row_sum ) + 5, x = xenc,
text = paste( row_sum ),
font = font_size, showarrow = F )
p
}
evo_bar_plot_variant( df, var_x = Labels, var_y1 = Aria, var_y2 = Acqua, var_y3 = Fuoco, var_y4 = Terra,
var_y5 = Cielo )
Getting output like this :
Sorry, I dropped a few lines of your example, as it isn't really minimal. Furthermore, I switched from dplyr to data.table as I'm more familar with it and melting the table makes thing much easier.
However, I hope the following is still helpful to you:
library(plotly)
library(data.table)
DF = data.frame(
Aria = 20:25,
Acqua = 21:26,
Fuoco = 22:27,
Terra = 23:28,
Cielo = 24:29,
Labels = c('Antonio', 'Maria', 'Giovanni',
'Sergio', 'Giorgio', 'Michele')
)
setDT(DF)
DT <- melt.data.table(DF, id.vars = "Labels")
DT[, c("label_group", "cumsum_by_label") := .(.GRP, cumsum(value)), by = Labels]
lineDT <- rbindlist(list(DT[, .(
label_group = label_group - 0.4,
cumsum_by_label = cumsum_by_label,
variable = variable
)],
DT[, .(
label_group = label_group + 0.4,
cumsum_by_label = cumsum_by_label,
variable = variable
)]))
p <- plot_ly(
DT,
x = ~ label_group,
y = ~ value,
color = ~ variable,
type = "bar",
colors = ~ colorRampPalette(c("white", "#4C68A2"))(length(unique(variable)) + 1)[-1],
legendgroup = ~ variable,
showlegend = TRUE
) %>%
layout(
title = list(text = 'Bar', x = 0),
barmode = 'stack',
legend = list(itemclick = FALSE, itemdoubleclick = FALSE)
) %>%
layout(
xaxis = list(
title = "X axis",
ticktext = ~ Labels,
tickvals = ~ label_group,
tickmode = "array"
),
yaxis = list(title = "")
) %>%
add_annotations(
text = ~ value,
xref = 'x',
yref = 'y',
y = ~ cumsum_by_label - value / 2,
x = ~ label_group,
showarrow = FALSE
) %>%
add_annotations(
data = DT[, .(maxval = max(cumsum_by_label),
label_group = unique(label_group)), by = Labels],
inherit = FALSE,
text = ~ maxval,
xref = 'x',
yref = 'y',
y = ~ maxval,
x = ~ label_group,
showarrow = FALSE,
yshift = 20
) %>%
add_lines(
data = lineDT,
inherit = FALSE,
x = ~ c(label_group),
y = ~ cumsum_by_label,
color = ~ variable,
legendgroup = ~ variable,
showlegend = FALSE,
hoverinfo = "none"
)
p
Related
I'm trying to reproduce in R Plotly a 2 categorical variables violin plot that works just fine in ggplot2. But when I set the widths of the individual violins to be the same, using scalemode = "width", as described in the reference (https://plotly.com/r/reference/violin/), it simply wont work. Instead, it shows the widths (violin maximum) proportional to the counts in each category.
Here is an example:
# Paths:
path_data = "data/"
path_lib = "renv/library/R-4.1/x86_64-pc-linux-gnu/"
# Packages:
require(dplyr, lib = path_lib)
require(readr, lib = path_lib)
require(RColorBrewer, lib = path_lib)
require(plotly, lib = path_lib)
# Dataset:
df = readr::read_csv(paste0(path_data, "nasa_exoplanets.csv")) %>%
as.data.frame()
attr(df, "spec") = NULL
df_varnames = readr::read_csv(paste0(path_data, "nasa_exoplanets_var_names.csv")) %>%
as.data.frame()
attr(df_varnames, "spec") = NULL
# Variables:
cat_var1 = "st_metratio"
cat_var2 = "disc_locale"
cat_var_name1 = (df_varnames %>%
dplyr::filter(var == cat_var1))$var_name
cat_var_name2 = (df_varnames %>%
dplyr::filter(var == cat_var2))$var_name
num_var = "sy_dist"
num_var_name = (df_varnames %>%
dplyr::filter(var == num_var))$var_name
# Adapt the data:
df_plot = df %>%
dplyr::select(cat_var1,
cat_var2,
num_var)
# Deal with NA:
df_plot[which(is.na(df_plot[, cat_var1])), cat_var1] = "NA"
df_plot[which(is.na(df_plot[, cat_var2])), cat_var2] = "NA"
df_plot = df_plot[which(!is.na(df_plot[, num_var])), ]
# Levels order:
sorted_levels1 = sort(unique(df_plot[, cat_var1]))
df_plot[, cat_var1] = factor(x = df_plot[, cat_var1],
levels = sorted_levels1)
sorted_levels2 = sort(unique(df_plot[, cat_var2]))
df_plot[, cat_var2] = factor(x = df_plot[, cat_var2],
levels = sorted_levels2)
# Plot:
my_palette = colorRampPalette(c("#111539", "#97A1D9"))
n_levels2 = length(unique(df_plot[, cat_var2]))
p = plot_ly(
data = df_plot,
type = "violin",
x = ~eval(parse(text = cat_var1)),
y = ~eval(parse(text = num_var)),
color = ~eval(parse(text = cat_var2)),
colors = my_palette(n_levels2),
spanmode = "hard",
alpha = 1,
box = list(visible = FALSE),
meanline = list(visible = FALSE),
points = FALSE,
scalemode = "width" ### this doesn't work ###
) %>%
layout(
xaxis = list(
title = paste0("<b>", cat_var_name1, "</b>"),
titlefont = list(size = 20),
tickfont = list(size = 18),
categoryorder = "array"
),
yaxis = list(
title = paste0("<b>", num_var_name, "</b>"),
titlefont = list(size = 20),
tickfont = list(size = 18),
type = "log"
),
margin = list(
l = 10,
r = 10,
t = 10,
b = 10
),
legend = list(
title = list(
text = paste0("<br><b>", cat_var_name2, "</b>"),
font = list(size = 18)
)
),
hoverlabel = list(font = list(size = 16)),
showlegend = TRUE,
violinmode = "group"
)
p
data file: https://github.com/rafael747cardoso/Data_Visualization_Gallery/blob/main/data/nasa_exoplanets.csv
How it should be, plotted in ggplot2:
How it is with R Plotly:
I am trying to add custom button to update the y axis, here is a small example that is similar.
When I click on “frq” or “count” the correct bar chart appears, but the values are wrong (its take only one value for each city and put it in all gender categories bars)
library(plotly)
library(dplyr)
library(tidyr)
Occupation = c("Tel Aviv", "Paris", "Amsterdam", "Kyoto")
Gender = c("F", "M", "[missing]")
df <- crossing(Occupation, Gender) %>%
mutate(n = row_number()) %>%
group_by(.data[["Occupation"]]) %>%
mutate(frq = round(100 * (n / sum(n)), 1))
chart_type <- list(
type = "buttons",
direction = "right",
xanchor = 'center',
yanchor = "top",
pad = list('r' = 0, 't' = 10, 'b' = 10),
x = 0.1,
y = 1.20,
buttons = list(
list(
method = "update",
args = list(list(y = list(df$n))),
label = "count"
),
list(
method = "update",
args = list(list(y = list(df$frq))),
label = "frq"
)
)
)
df %>%
plot_ly(
x = ~ Occupation,
y = ~ n,
color = ~ Gender,
text = ~ n,
textposition = 'auto',
type = "bar"
) %>%
layout(updatemenus = list(chart_type))
Another version:
chart_type <- list(
type = "buttons",
direction = "right",
xanchor = 'center',
yanchor = "top",
pad = list('r'= 0, 't'= 10, 'b' = 10),
x = 0.1,
y = 1.20,
buttons = list(
list(method = "update",
args = list(list(visible = c(TRUE, FALSE)
)),
label = "count"),
list(method = "update",
args = list(list(visible = c(FALSE, TRUE)
)),
label = "frq")
))
df %>%
plot_ly(mode = 'markers',type = "bar") %>%
add_trace(x = ~Occupation, y = ~n, color = ~Gender,
text=~n, textposition = 'auto', visible = FALSE,
colorbar = list()) %>%
add_trace(x = ~Occupation, y = ~frq, color = ~Gender,
text=~frq, textposition = 'auto', visible = TRUE,
colorbar = list()) %>%
layout(updatemenus = list(chart_type))
After the click:
The labels within bubbles are appearing with size proportional to size argument. However I want to keep the labels in constant sizes.
Which argument should I use to keep them at constant size ?
Code that I am using is provided below.
df = data.frame( x = c( 3, 2, 2, 4, 6, 8 ), y = c( 3, 2, 3, 4, 6, 7 ), size = c( 20, 20, 20, 30, 40, 40 ), labels = letters[1:6] )
evo_bubble <- function(plot_data ,x_var, y_var, z_var, t_var) {
# Trasform data into dataframe and quos
df <- data.frame(plot_data)
xenc <- enquo(x_var)
yenc <- enquo(y_var)
zenc <- enquo(z_var)
tenc <- enquo(t_var)
df <- df %>% mutate( bubble_size = !!zenc*50 ) # Modify the denominator if you want to change the dimension of the bubble
# Set parameters for the plot
bubble_pal <- c("white", "#AECEE8" )
gray_axis <- '#dadada'
font_size <- list(size = 12, family = 'Lato')
width <- 0.5
legend_name <- Hmisc::capitalize( quo_name(zenc) ) # WATCH OUT! it works only with the package with Hmisc
decimal <- ',.2f'
sep <- ','
#x_name <- capitalize(quo_name(xenc))
y_name <- Hmisc::capitalize(quo_name(yenc))
p <- plot_ly(df, x = xenc, y = yenc, name = '', text = tenc, type = "scatter", mode = 'markers+text',
hoverlabel = list(font = font_size), size = zenc, color = zenc, hoverinfo = "text+y", colors= bubble_pal,
marker = list(size = df$bubble_size, line = list(color = gray_axis)) ) %>% hide_colorbar()
p <- p %>% layout(xaxis = list(zeroline = F,
title = '',
linecolor = gray_axis,
titlefont = font_size,
tickfont = font_size,
rangemode='tozero',
gridcolor = gray_axis,
gridwidth = width,
hoverformat = decimal,
mirror = "ticks",
tickmode = 'array',
tickcolor = gray_axis,
linewidth = width,
showgrid = F ),
yaxis = list(title = y_name,
zerolinecolor = gray_axis,
linecolor = gray_axis,
mirror = "ticks",
hoverformat = '.2f',
linewidth = width,
tickcolor = gray_axis,
tickformat = '.2f',
titlefont = font_size,
tickfont = font_size,
showgrid = FALSE) ) %>%
config(displayModeBar = F)
return(p)
}
evo_bubble( df, x, y, size, labels )
Expected image :
Obtained image :
Please ignore the colors in plot.
You can use add_text to get the desired result:
library(plotly)
library(dplyr)
DF = data.frame( x = c( 3, 2, 2, 4, 6, 8 ), y = c( 3, 2, 3, 4, 6, 7 ), size = c( 20, 20, 20, 30, 40, 40 ), labels = letters[1:6] )
evo_bubble <- function(plot_data, x_var, y_var, z_var, t_var) {
# browser()
# Trasform data into dataframe and quos
DF <- data.frame(plot_data)
xenc <- enquo(x_var)
yenc <- enquo(y_var)
zenc <- enquo(z_var)
tenc <- enquo(t_var)
DF <- DF %>% mutate( bubble_size = !!zenc*50 ) # Modify the denominator if you want to change the dimension of the bubble
# Set parameters for the plot
bubble_pal <- c("white", "#AECEE8" )
gray_axis <- '#dadada'
font_size <- list(size = 12, family = 'Lato')
width <- 0.5
legend_name <- Hmisc::capitalize( quo_name(zenc) ) # WATCH OUT! it works only with the package with Hmisc
decimal <- ',.2f'
sep <- ','
#x_name <- capitalize(quo_name(xenc))
y_name <- Hmisc::capitalize(quo_name(yenc))
p <- plot_ly(DF, x = xenc, y = yenc, name = '', type = "scatter", mode = 'markers',
hoverlabel = list(font = font_size), size = zenc, color = zenc, hoverinfo = "text+y", colors= bubble_pal,
marker = list(size = DF$bubble_size, line = list(color = gray_axis))) %>%
add_text(text = tenc, textfont = font_size, textposition = "middle center") %>% hide_colorbar()
p <- p %>% layout(xaxis = list(zeroline = F,
title = '',
linecolor = gray_axis,
titlefont = font_size,
tickfont = font_size,
rangemode='tozero',
gridcolor = gray_axis,
gridwidth = width,
hoverformat = decimal,
mirror = "ticks",
tickmode = 'array',
tickcolor = gray_axis,
linewidth = width,
showgrid = F ),
yaxis = list(title = y_name,
zerolinecolor = gray_axis,
linecolor = gray_axis,
mirror = "ticks",
hoverformat = '.2f',
linewidth = width,
tickcolor = gray_axis,
tickformat = '.2f',
titlefont = font_size,
tickfont = font_size,
showgrid = FALSE) ) %>%
config(displayModeBar = F)
return(p)
}
evo_bubble( DF, x, y, size, labels )
I am trying to plot waterfall chart with the following code. The only issue I am facing currently is the data marker which is not at the correct place. I want the data marker to be just below the end of each bar.
source('./r_files/flatten_HTML.r')
library("plotly")
dataset <- data.frame(Category = c("Akash Jain","Ankit Jain","Pankaj Jain","Nitin Pandey","Gopal Pandit","Ramnath Agarwal"),
TH = c(-62,-71,-1010,44,-44,200))
#dataset <- data.frame(Category = Values$Category, TH = Values$TH)
#dataset <- as.data.frame(cbind(Values$Category,Values$TH))
dataset$Category = dataset$Category
dataset$TH = dataset$TH
dataset$SortedCategoryLabel <- sapply(dataset$Category, function(x) gsub(" ", " <br> ", x))
dataset$SortedCategory <- factor(dataset$SortedCategoryLabel, levels = dataset$SortedCategoryLabel)
dataset$id <- seq_along(dataset$TH)
dataset$type <- ifelse(dataset$TH > 0, "in", "out")
dataset$type <- factor(dataset$type, levels = c("out", "in"))
dataset$end <- cumsum(dataset$TH)
dataset$start <- c(0, head(dataset$end, -1))
Hover_Text <- paste(dataset$Category, "= ", dataset$TH, "<br>")
dataset$colors <- ifelse(dataset$type =="out","red","green")
g <- plot_ly(dataset, x = ~SortedCategory, y = ~start, type = 'bar', marker = list(color = 'rgba(1,1,1, 0.0)'), hoverinfo = 'text') %>%
add_trace(y = dataset$TH , marker = list(color = ~colors), hoverinfo = "text", text = Hover_Text ) %>%
layout(title = '',
xaxis = list(title = ""),
yaxis = list(title = ""),
barmode = 'stack',
margin = list(l = 50, r = 30, b = 50, t = 20),
showlegend = FALSE) %>%
add_annotations(text = dataset$TH,
x = dataset$SortedCategoryLabel,
y = dataset$end,
xref = "dataset$SortedCategoryLabel",
yref = "dataset$end",
font = list(family = 'Arial',
size = 14,
color = "black"),
showarrow = FALSE)
g
Attached the screenshot of the waterfall chart.
So for the first bar, I need the data marker to be just below the end of red bar. Currently it is overlapping with the bar. And similarly for others.
Any help would be really appreciated.
Regards,
Akash
You should specify valign and height inside add_annotations:
vert.align <- c("bottom","top")[as.numeric(dataset$TH>0)+1]
g <- plot_ly(dataset, x = ~SortedCategory, y = ~start, type = 'bar',
marker = list(color = 'rgba(1,1,1, 0.0)'), hoverinfo = 'text') %>%
add_trace(y = dataset$TH , marker = list(color = ~colors), hoverinfo = "text",
text = Hover_Text ) %>%
layout(title = '',
xaxis = list(title = ""),
yaxis = list(title = ""),
barmode = 'stack',
margin = list(l = 50, r = 30, b = 50, t = 20),
showlegend = FALSE) %>%
add_annotations(text = dataset$TH,
x = dataset$SortedCategoryLabel,
y = dataset$end,
xref = "x",
yref = "y",
valign=vert.align, height=40,
font = list(family = 'Arial',
size = 14,
color = "black"),
showarrow = FALSE)
g
In Plotly for Python, we have this beautiful multiple y-axis example:
here is the link for the code.
I tried to do the same with Plotly in R using this code:
library(plotly)
x <- 1:4
y1 <- c(1,2,3,4)
y2 <- c(4,3,2,1)
y3 <- c(1,4,1,4)
y4 <- c(4,1,4,1)
test <- data.frame(x, y1, y2, y3, y4)
plot_ly(data = test, x = ~x, y = ~y1
,type = "scatter", mode = "lines", width = 800, color = I("red")
,name = "name01") %>%
add_trace(x = ~x, y = ~y2, yaxis = "y2", color = I("blue"), name = "name02") %>%
add_trace(x = ~x, y = ~y3, yaxis = "y3", color = I("purple"), name = "name03") %>%
add_trace(x = ~x, y = ~y4, yaxis = "y4", color = I("green"), name = "name04") %>%
layout(
yaxis = list(
showline = FALSE, side = "left"
,title = "Label 1"
,color = "red"
)
,yaxis2 = list(
showline = FALSE
,overlaying = "y"
,title = "Label 2", anchor = "free"
,color = "blue"
)
,yaxis3 = list(
showline = FALSE, side = "right", overlaying = "y"
,title = "Label 3"
,color = "purple"
)
,yaxis4 = list(
showline = FALSE, side = "right", overlaying = "y", position = 1
,title = "Label 4", anchor = "free"
,color = "green"
)
,xaxis = list(
showline = FALSE, zeroline = FALSE, dtick = 1, title = ""
)
,showlegend = FALSE
,margin = list(
pad = 30, b = 90, l = 150, r = 90
)
,legend = list(orientation = "h")
)
But I get these overlapping labels:
How can I fix it to get a non overlapping chart?
Try tuning the padding (pad) value for margin argument of layout().
Best I found for your other parameters is with pad = 49