Plotting multiple categorical variables in R Plotly - r

I am attempting to make a graph comparing max, min, and mean temperatures from 2 different locations (2 unique locations: turnbull and finley) in R's Plotly package. I have been able to build scatter plots for each location independently, but cannot figure out how to plot both sites on the same graph. Here is a link to the data set (referenced as temp_c in the code): https://docs.google.com/spreadsheets/d/1A1HkOVjifYRp62fkMO2Xe8_STzo2rfq4UXfso9kjxfw/edit#gid=0
Here is my code for one of the locations - I would like to plot both locations on one graph:
fig_fin_1 <- plot_ly(temp_c[temp_c$location=="finley",], x = ~date, y = ~max_temp_c,
type = 'scatter', mode = 'lines',
line = list(color = 'transparent'),
showlegend = FALSE, name = 'Finley Max')
fig_fin_1 <- fig_fin_1 %>% add_trace(y = ~min_temp_c, split = c("finley"), type = 'scatter', mode = 'lines',
fill = 'tonexty', fillcolor='rgba(0,100,80,0.2)',
line = list(color = 'transparent'),
showlegend = FALSE,
name = 'Finley Min')
fig_fin_1 <- fig_fin_1 %>% add_trace(x = ~date, y = ~ave_temp_c, split = c("finley"), type = 'scatter', mode = 'lines', split = c("finley"),
line = list(color='green'),
name = 'Finley Mean')
fig_fin_1 <- fig_fin_1 %>% layout(title = "Historical Average, Min and Max Temperatures for Finley NWR",
paper_bgcolor='rgb(255,255,255)', plot_bgcolor='rgb(229,229,229)',
xaxis = list(title = "Date",
gridcolor = 'rgb(255,255,255)',
showgrid = TRUE,
showline = FALSE,
showticklabels = TRUE,
tickcolor = 'rgb(127,127,127)',
ticks = 'outside',
zeroline = FALSE),
yaxis = list(title = "Temperature (degrees C)",
gridcolor = 'rgb(255,255,255)',
showgrid = TRUE,
showline = FALSE,
showticklabels = TRUE,
tickcolor = 'rgb(127,127,127)',
ticks = 'outside',
zeroline = FALSE))
fig_fin_1
I've tried adding all the traces from each graph into one graph - I'm not sure how to retain the 2 unique colors representing the locations colors when I do this, and I get a strange 3rd line. I've also tried making a new data frame for each location and temperature treatment/measurement (i.e. turnbull_min_c), but that didn't work - here's my attempt at making graph representing both locations:
Any help would be much appreciated!

Update
I guess I misunderstood. You want to combine the graphs, not recreate the graph you provided a picture of. I've tried various ways to make this happen. I've only found one method that works every time.
The data I originally created was so similar that you couldn't see them when they were on the same graph. I modified that data (df1 described in the original answer).
# mod so stack is more obvious
df1$min_temp <- ifelse(df1$location == unique(df1$location)[1],
df1$min_temp - 5, df1$min_temp)
df1$max_temp <- ifelse(df1$location == unique(df1$location)[1],
df1$max_temp - 5, df1$max_temp)
df1$ave_temp <- ifelse(df1$location == unique(df1$location)[1],
df1$ave_temp - 5, df1$ave_temp)
I used the same map call to create plt1 and plt2. (Although, you could remove the %>% layout and just add it at the end.)
I should point out that I reduced the opacity for the blue fill from .2 to .1 so that you could see it overlapping the green (otherwise, it was hard to tell that's what happened).
Then I extracted the trace data from each of these plots so that I could make all of the fill traces first.
plt1 <- plotly_build(plt1)
plt2 <- plotly_build(plt2)
plt1_d <- plt1$x$data # extract all trace data
plt2_d <- plt2$x$data
# restack trace data so all fill traces are first
ndata <- list(plt1_d[[1]], plt1_d[[2]], plt2_d[[1]], plt2_d[[2]],
plt1_d[[3]], plt2_d[[3]])
Now that ndata is the new lineup of traces, I replaced the data in plt1.
plt1$x$data <- ndata
If you kept the layout in the map call (or in your original plot traces you won't need to call the layout again. If you removed it up to this point, you can add it now.
plt1 %>%
# your original layout (I've changed nothing here)
layout(title = "Historical Average, Min and Max Temperatures for Finley NWR",
paper_bgcolor='rgb(255,255,255)', plot_bgcolor='rgb(229,229,229)',
xaxis = list(title = "Date", gridcolor = 'rgb(255,255,255)',
showgrid = TRUE, showline = FALSE, showticklabels = TRUE,
tickcolor = 'rgb(127,127,127)', ticks = 'outside',
zeroline = FALSE),
yaxis = list(title = "Temperature (degrees C)",
gridcolor = 'rgb(255,255,255)',
showgrid = TRUE, showline = FALSE, showticklabels = TRUE,
tickcolor = 'rgb(127,127,127)', ticks = 'outside',
zeroline = FALSE))
Original answer
I'm assuming from what little I know about your data that the field location has two unique values, and that's what you're splitting the graphs with.
You didn't include data, so I've included the data I used in this answer.
library(tidyverse)
library(plotly)
lows <- c(seq(-10, 20, length.out = 7), seq(15, -10, length.out = 5))
highs <- c(seq(0, 30, length.out = 7), seq(25, 0, length.out = 5))
set.seed(25)
df1 <- map2(1:12, rep(c(31, 30), 6),
function(j, k) {
max_temp <- rnorm(k * 2, highs[j], 1)
min_temp <- rnorm(k * 2, lows[j], 1)
m <- matrix(c(max_temp, min_temp), nrow = 2, byrow = T)
ave_temp <- colMeans(m)
data.frame(ave_temp = ave_temp, max_temp = max_temp,
min_temp = min_temp)
}) %>% bind_rows() %>%
mutate(dat = rep(seq.Date(from = today(), by = 1, length.out = 366), each = 2),
location = rep(c("A", "B"), 366)) %>%
select(dat, location, everything())
head(df1)
I used map, but lapply does the same thing. This creates 2 separate plots, one object is plt1; the other is plt2.
map(1:2,
function(i) {
df <- filter(df1, location == unique(df1$location)[i]) # filter for subplot
# the area first
p <- plot_ly(type = "scatter", mode = "lines", df, x = ~dat, showlegend = F,
y = ~min_temp, line = list(color = "transparent")) %>%
add_trace(type = "scatter", mode = "lines", df, x = ~dat,
y = ~max_temp, fill = "tonexty",
fillcolor = c('rgba(0, 100, 80, .2)', 'rgba(0, 0, 255, .2)')[i],
opacity = .2, line = list(color = "transparent")) %>%
# line only
add_trace(type = "scatter", mode = "lines", df, x = ~dat,y = ~ave_temp,
line = list(color = c('rgba(0, 100, 80, 1)',
'rgba(0, 0, 255, 1)')[i])) %>%
# your original layout (I've changed nothing here)
layout(title = "Historical Average, Min and Max Temperatures for Finley NWR",
paper_bgcolor='rgb(255,255,255)', plot_bgcolor='rgb(229,229,229)',
xaxis = list(title = "Date", gridcolor = 'rgb(255,255,255)',
showgrid = TRUE, showline = FALSE, showticklabels = TRUE,
tickcolor = 'rgb(127,127,127)', ticks = 'outside',
zeroline = FALSE),
yaxis = list(title = "Temperature (degrees C)",
gridcolor = 'rgb(255,255,255)',
showgrid = TRUE, showline = FALSE, showticklabels = TRUE,
tickcolor = 'rgb(127,127,127)', ticks = 'outside',
zeroline = FALSE))
assign(paste0("plt", i), p, envir = .GlobalEnv)
})
Now all you have to do is stack them.
subplot(plt1, plt2, nrows = 2)
The image of your desired outcome doesn't have x and y-axis labels, but you designated them in your layout. As you can see here, there are no axis labels in the subplot. There is a way to add them via Plotly, but it's much easier to do with the htmltools library.
Using this method, you may not want each graph to have a title.
plt2 <- plt2 %>% layout(title = "")
Additionally, the default height via Plotly is 400 px. The default width is 100%. Because of the height, you lose the dynamic resizing. So first, let's change that.
plt1$sizingPolicy$defaultHeight <- '100%'
plt2$sizingPolicy$defaultHeight <- '100%'
Now using htmltools, stack them.
browsable(
div(div(plt1, style = "width: 100%; height: 49%; float: left;"),
div(plt2, style = "width: 100%; height: 49%; float: left;"),
style = "width: 100vw; height: 100vh;"))

Related

Hover is not spot on in R plotly with hovermode 'x unified'

I created a graph with two traces in plotly and I use the hovermode x unified. At some point there is no data for line 2, but there is for line 1. In the hoover I only want to see the information about line 1 then, but it also shows information about the nearest point of line 2. When I zoom in the issue dissapears.
So in short, I want to disable the closest function of the hovermode. How can I do this?
Some sample data + code:
library(plotly)
# dummy data
df_data1 = data.frame(date_input = seq(as.Date('2020/01/01'), as.Date('2022/07/01'), by="week")
, value=1:131)
df_data2 = data.frame(date_input = seq(as.Date('2020/01/01'), as.Date('2022/06/01'), by="week")
, value2=3:129)
plot1 <- plot_ly()
plot1 <- plot1 %>%
add_trace(data = df_data1, x = ~date_input, y = ~value
, type = 'scatter', mode = "lines", yaxis = "y", line = list(color = '#E64B35FF', opacity = 0.8)
, showlegend = FALSE
, hovertemplate = ~paste('# Value1: %{y:.0f}<extra></extra>')) %>%
add_trace(data = df_data2, x = ~date_input, y = ~value2
, type = 'scatter', mode = "lines", yaxis = "y2", line = list(color = '#4DBBD5FF', opacity = 0.8)
, showlegend = FALSE
, hovertemplate = ~paste('# Value2: %{y:.0f}<extra></extra>'))
plot1 %>%
layout(
font = list(size = 10),
xaxis = list(title = list(text = '<b>Date<b>', font = list(size = 12))
, fixedrange = T, showgrid = FALSE, ticks = 'inside', type = 'date'
),
yaxis = list(title = list(text = '<b>Number of value1<b>', font = list(size = 12, color = '#E64B35FF'))
, fixedrange = T
, rangemode = 'tozero', showgrid = FALSE, showline = T, ticks = 'inside'),
yaxis2 = list(overlaying = 'y', side = 'right', fixedrange = T, rangemode = 'tozero', showgrid = FALSE, showline = T, ticks = 'inside'
, title = list(text = '<b>Number of value2<b>', font = list(size = 12, color = '#4DBBD5FF'))),
hovermode = "x unified"
)
As you can see the hovermode shows the value2 information still at 15 june (but it shows the closest data from 1 june.

Trouble with creating bar & pie subplot with R plotly

I've created a Plotly bar and pie chart and want to combine them to form one chart.
When I use subplot() to combine these Plotly charts, the pie & bar charts overlap.
Any advice on how to present these plots so that each is in its own row? Thank you.
Here's a picture of what I'm currently experiencing:
Reprex below:
#Pie chart example
pie_tibble <- tibble(donuts = c(49050, 66924),
group = c("Group A", "Group B"))
pie <- plot_ly(data = pie_tibble, labels = ~group, values = ~donuts, type = 'pie',
showlegend = F,
hoverinfo = "none",
marker = ~list(colors = c('#404040', '#24608B'))) %>%
layout(xaxis = list(showgrid = FALSE, zeroline = FALSE, showticklabels = FALSE),
yaxis = list(showgrid = FALSE, zeroline = FALSE, showticklabels = FALSE))
bar_tibble <- tibble(category = c("Cat 1", "Cat 1", "Cat 2", "Cat 2"),
pct_increase = c(0.17, 0.25, 0.64, 0.85),
week = c(1, 2, 1, 2))
#Bar chart example
bar <- plot_ly(data = bar_tibble, hoverinfo = "none") %>%
layout(
barmode = 'stack',
showlegend = F) %>%
add_trace(
x = ~pct_increase,
y = ~category,
type = "bar",
transforms = list(
list(
type = "aggregate",
groups = ~category,
aggregations = list(
list(
target = "x", func = "avg", enabled = T)))))
#Combine charts
subplot(bar, pie, nrows = 2)
Pie charts and plotly::subplot() are notoriously challenging - though you can get around many of the issues by specifying the domain manually. Below I have changed the pie code by specifying the domain = list(...) as so:
pie <- plot_ly(data = pie_tibble, labels = ~group, values = ~donuts, type = 'pie',
# Specify the domain here
domain = list(x = c(0.5, 0.5), # centered on x axis
y = c(0.0, 0.4)),
showlegend = F,
hoverinfo = "none",
marker = ~list(colors = c('#404040', '#24608B'))) %>%
layout(xaxis = list(showgrid = FALSE, zeroline = FALSE, showticklabels = FALSE),
yaxis = list(showgrid = FALSE, zeroline = FALSE, showticklabels = FALSE))
subplot(bar, pie, nrows = 2) now gives:
Sorry I don't have a more elegant answer, but hoping someone else might!

Showing full categorical x-axis even when there are no points to plot

I am using plotly to plot a scatter plot with line+markers. The problem is that I have a categorical x-axis and I want to fix it for full range static on all plots.
Below is the example code:
import(plotly)
x_group <- c('[8-9]','[9-10]','[10-11]','[11-12]','[12-13]','[13-14]','[14-15]','[16-17]','[17-18]','[18-19]','[19-20]')
total <- c('22','17','27','8 ','16','4 ','17','12','15','2 ','22')
example_df <- as.data.frame(list(hour_bin_grp= x_group, total = total))
m <- list(
l = 50,
r = 50,
b = 100,
t = 100,
pad = 4
)
hour_bins <- c("[0-7]","[7-8]","[8-9]","[9-10]","[10-11]", "[11-12]","[12-13]", "[13-14]", "[14-15]", "[15-16]","[16-17]", "[17-18]","[18-19]", "[19-20]", "[20-21]","[21-22]")
p <- plot_ly(example_df, x = ~hour_bin_grp, y = ~total, type = 'scatter', mode = 'markers+lines') %>%
layout(autosize = T, margin = m,
xaxis = list(
type='category',
categoryorder= 'array',
showgrid = TRUE,
autorange = FALSE,
showticklabels = TRUE,
categoryarray= unique(hour_bins)
),
yaxis = list(
showgrid = TRUE,
autorange = TRUE,
showline = TRUE,
showticklabels = TRUE,
rangemode = "tozero",
))
p
The plot seems okay, but I want to fix the range of x-axis to values of hour_bins.
I have already looked up some of the articles on the same, but it does not seem to work under my condition:
Plotly.js: Cannot show full categorical x-axis
https://community.plot.ly/t/cannot-re-arrange-x-axis-when-axis-type-is-category/1274/3
As a workaround I'd suggest using numeric ticks with character ticktext:
library(plotly)
bin_df <- data.frame(hour_bins = c("[0-7]","[7-8]","[8-9]","[9-10]","[10-11]", "[11-12]","[12-13]", "[13-14]", "[14-15]", "[15-16]","[16-17]", "[17-18]","[18-19]", "[19-20]", "[20-21]","[21-22]"))
bin_df$hour_bin_grp <- seq_len(nrow(bin_df))
example_df <- data.frame(hour_bin_grp = bin_df$hour_bin_grp[bin_df$hour_bins %in% c('[8-9]','[9-10]','[10-11]','[11-12]','[12-13]','[13-14]','[14-15]','[16-17]','[17-18]','[18-19]','[19-20]')], total = as.numeric(c('22','17','27','8','16','4','17','12','15','2','22')))
p <- plot_ly(example_df, x = ~hour_bin_grp, y = ~total, type = 'scatter', mode = 'markers+lines') %>%
layout(xaxis = list(
tickmode = "array",
tickvals = bin_df$hour_bin_grp,
ticktext = example_df$hour_bins,
range = list(min(bin_df$hour_bin_grp), max(bin_df$hour_bin_grp))
))
p

How to add pattern to pie chart R plotly

I have created a pie chart using plotly, the pie has 14 parts, I want to distinguish between them, it needs to be in grayscale I have been using grDevices for grey colors but it is hard to see the differences. I thought about adding a pattern/texture to the chart, can anyone help me with the code, please?
This is the code that I have used:
library(plotly)
library(grDevices)
grey.colors(n, start = 0.3, end = 0.9, gamma = 2.2, alpha = NULL)
A <- c(1426,329,65,62,56,52,45,43,29,24,21,14,13,146)
lbls <- c(A,B,C,D,E,F,G,H,I,J,K,L,M,N)
df= data.frame(A, lbls )
t<- list(family=“Times New Roman”, size=12,color=‘black’)
plot_ly(df, labels = ~lbls,
values = ~A, type = ‘pie’,marker = list(colors = grey.colors,
line = list(color = ‘#0f0e0e’, width = 1)),textfont=t,
textinfo = ‘percent+value’,
hoverinfo = ‘text’,
text = ~paste( A, ’ individuals’),
marker = list(colors = gcolors,
line = list(color = ‘#FFFFFF’, width = 1)))%>%
add_pie(hole=0.0)%>%
layout(xaxis = list(showgrid = FALSE, zeroline = FALSE, showticklabels = FALSE),
yaxis = list(showgrid = FALSE, zeroline = FALSE, showticklabels = FALSE))’
Thanks!

Two X-axis in Plotly for R

https://community.plot.ly/t/how-to-plot-multiple-x-axis-in-plotly-in-r/3014/3?u=him4u324
I have posted my question on Plotly community as well
I am trying to display two x-axis with common Y-axis on plotly for R. I was able to do so as well but starting point for each x-axis is separated from each other Whereas I wish them to be represented a common y-axis.
f1 <- list(
family = "Arial, sans-serif",
size = 18,
color = "grey"
)
f2 <- list(
family = "Old Standard TT, serif",
size = 14,
color = "#4477AA"
)
# bottom x-axis
ax <- list(
title = "Number of PBIs",
titlefont = f1,
anchor = "y",
side = "bottom",
showticklabels = TRUE,
tickangle = 0,
tickfont = f2
)
# top x-axis
ax2 <- list(
title = " ",
overlaying = "x",
anchor = "y",
side = "top",
titlefont = f1,
showticklabels = TRUE,
tickangle = 0,
tickfont = f2
)
# common y-axis
ay <- list(
title = "Process & Sub-Process Areas",
titlefont = f1,
showticklabels = TRUE,
tickangle = 0,
tickfont = f2
)
plot_ly(data = scrum %>%
group_by(Master.Project) %>%
summarise(Total_PBIs_Planned=sum(PBIs.Planned.in.Sprint, na.rm = TRUE),
Total_PBIs_Delivered = sum(Actual.PBI.Delivery,na.rm = TRUE)) %>% inner_join(scrum %>% count(Master.Project)), # creating the desired data frame
color = I("#149EF7")) %>%
# for bottom x-axis
add_segments(x = ~Total_PBIs_Planned, xend = ~Total_PBIs_Delivered,
y = ~Master.Project, yend = ~Master.Project, showlegend = FALSE) %>%
add_trace(x = ~Total_PBIs_Planned, y = ~Master.Project,
name = "Total_PBIs_Planned", type = 'scatter',mode = "markers",
marker = list(color = "#149EF7", size = 15,
line = list(color = '#FFFFFF', width = 1))) %>%
add_trace(x = ~Total_PBIs_Delivered, y = ~Master.Project,
name = "Total_PBIs_Delivered",type = 'scatter',mode = "markers",
marker = list(symbol ="circle-dot",color = "#F71430", size = 10,
line = list(color = '#FFFFFF', width = 1))) %>%
# for top x-axis
add_trace(x = ~n, y = ~Master.Project, xaxis = "x2",
name = "No._of_Sub_projects",type = 'bar',
marker = list(color = "#149EF7"),
opacity = 0.1,
hoverinfo = 'text',
text = ~paste(
Master.Project,
'<br> Total Sub Projects: ',n,
'<br> PBIs Planned: ',Total_PBIs_Planned,
'<br> PBIs Delivered: ',Total_PBIs_Delivered
)
) %>%
plotly::layout(
title = "Product Backlog Items - Planned Vs Delivered", titlefont = f1,
xaxis = ax,
yaxis = ay,
xaxis2 = ax2,
margin = list(l = 250)
)
You want to use rangemode = "tozero" in your axis layout.
ax <- list(
title = "Number of PBIs",
titlefont = f1,
anchor = "y",
side = "bottom",
showticklabels = TRUE,
tickangle = 0,
tickfont = f2,
rangemode = 'tozero')
Or you can specify your specific ranges using
range = c(0, 5)
See Plotly help here: https://plot.ly/r/axes/#rangemode

Resources