I'm asking myself how to solve the following problem the most elegant. My data encompasses of some actual values and some proposed values. Right now I have data that looks like the reproducible example below:
library(plotly)
library(dplyr)
test_dt <- data.frame(Age=1:5, Key=c("Actuals", "Actuals", "Actuals", "Other", "Other") , Value=rnorm(5))
plot_ly(data = (test_dt %>% group_by(., Key) %>% arrange(desc(Age))),
x = ~Age,
y = ~Value,
type = 'scatter',
mode = 'lines',
color = ~Key,
linetype = ~Key
) %>% layout(
yaxis = list(
title = "SD"),
margin = list(top=100, b=50)
)
The output of this code looks like this:
how plot a dashed line where i drew the red arrow?
My solution so far is that I access the last value of my actuals and insert this value as a new row for my "other" line. But I don't think that's very elegant and sometimes, if no other values exist which can happen in my data depending on the inputs then I have a legend plotted for my "other" line without actually having one.
act_age_max <- filter(test_dt, Key=="Actuals") %>% .[["Age"]] %>% max
propval_names <- filter(test_dt, Key!="Actuals") %>% .[["Key"]]
last_actual <- filter(test_dt, Age==act_age_max, Key=="Actuals") %>% .[["Value"]]
acts_year <- filter(test_dt, Age==act_age_max, Key=="Actuals") %>% .[["Year"]]
append_dt <- data.frame(Age=act_age_max, Key=propval_names, Value=last_actual)
plot_data <- rbind(test_dt, append_dt)
plot_ly(data = (plot_data %>% group_by(., Key) %>% arrange(desc(Age))),
x = ~Age,
y = ~Value,
type = 'scatter',
mode = 'lines',
color = ~Key,
linetype = ~Key
) %>% layout(
yaxis = list(
title = "SD"),
margin = list(top=100, b=50)
)
Related
I posted this in the plotly community forum but got absolutely no activity! Hope you can help here:
I have map time-series data, some countries don’t have data and plotly does not plot them at all. I can have them outlined and they look different but it appears nowhere that the data is missing there (i.e. I want a legend entry). How can I achieve this? Here is a reprex:
library(plotly)
library(dplyr)
data = read.csv('https://github.com/lc5415/COVID19/raw/master/data.csv')
l <- list(color = toRGB("grey"), width = 0.5)
g <- list(
scope = 'world',
countrycolor = toRGB('grey'),
showframe = T,
showcoastlines = TRUE,
projection = list(type = 'natural earth')
)
map.time = data %>%
plot_geo() %>%
add_trace(z = ~Confirmed, color = ~Confirmed, frame = ~Date, colors = 'Blues',
text = ~Country, locations = ~Alpha.3.code, marker = list(line = l)) %>%
colorbar(title = 'Confirmed') %>%
layout(
title = 'Number of confirmed cases over time',
geo = g
) %>%
animation_opts(redraw = F) %>%
animation_slider(
currentvalue = list(
prefix = paste0("Days from ",
format(StartDate, "%B %dnd"),": "))) %>%
plotly_build()
map.time
Note that the countries with missing data (e.g. Russia) have as many data points as all other countries, the issue is not that they do not appear in the dtaframe passed to plotly.
The obvious way to handle this is to create a separate labels column for the tooltip that reads "No data" for NA values (with the actual value otherwise), then make your actual NA values 0. This will give a uniform appearance to all the countries but correctly tells you when a country has no data.
map.time = data %>%
mutate_if(is.numeric, function(x) {x[is.na(x)] <- -1; x}) %>%
plot_geo() %>%
add_trace(z = ~Confirmed, color = ~Confirmed, frame = ~Date, colors = 'Blues',
text = ~Country, locations = ~Alpha.3.code,
marker = list(line = l)) %>%
colorbar(title = 'Confirmed') %>%
layout(
title = 'Number of confirmed cases over time',
geo = g
) %>%
animation_opts(redraw = F) %>%
animation_slider(
currentvalue = list(
prefix = paste0("Days from ",
format(StartDate, "%B %dnd"),": "))) %>%
plotly_build()
Which gives:
I want to know how to mirror 2 kinds of bars(positive number and negative number) in vertical like the picture below:
So far I can only make them mirror but standing side by side like:
Data:
library(plotly)
time <- c("2018-10","2018-11","2018-12")
add <- c(20,15,20)
delete <- c(-5,-10,-2)
total <- c(60,65,83)
df <- data.frame(time,add,delete,total)
plot_ly(df) %>%
add_trace(x = ~time, y = ~add, type = 'bar', name = 'add',
marker = list(color = '#33adff'),
hovertemplate = paste('add: %{y}',
'<br>time: %{x}<br>')) %>%
add_trace(x = ~time, y = ~delete, type = 'bar', name = 'delete',
marker = list(color = '#ff6666'),
hovertemplate = paste('delete: %{y}',
'<br>time: %{x}<br>'))
The problem can be solved using barmode="overlay".
You need to set the df dataset in long data format.
library(plotly)
time <- c("2018-10","2018-11","2018-12")
add <- c(20,15,20)
delete <- c(-5,-10,-2)
total <- c(60,65,83)
n <- length(time)
df <- data.frame(time=rep(time,2), y=c(add, delete), grp=rep(c("Add","Delete"),each=n))
plot_ly(df) %>%
add_trace(x = ~time, y = ~y, color=~grp, text=~grp, type = 'bar',
marker = list(color = c(rep('#33adff',n), rep('#ff6666',n))),
hovertemplate = paste('%{text}: %{y}', '<br>time: %{x}<br>')) %>%
layout(barmode="overlay")
How can I create a grouped bar chart in plotly that has a dropdown (or something else), so a viewer can select the grouping variable?
Working example:
library(dplyr)
library(plotly)
library(reshape2)
iris$Sepal.L <- iris$Sepal.Length %>%
cut(breaks = c(4,5,7,8),
labels = c("Length.a","Length.b","Length.c"))
iris$Sepal.W <- iris$Sepal.Width %>%
cut(breaks = c(1,3,5),
labels = c("Width.a","Width.b"))
# Get percentages
data1 <- table(iris$Species, iris$Sepal.L) %>%
prop.table(margin = 1)
data2 <- table(iris$Species, iris$Sepal.W) %>%
prop.table(margin = 1)
# Convert to df
data1 <- data.frame(Var1=row.names(data1), cbind(data1))
row.names(data1) <- NULL
data2 <- data.frame(Var1=row.names(data2), cbind(data2))
row.names(data2) <- NULL
plot_ly(
data = data1,
name = "Length.a",
x = ~Var1, y = ~Length.a,
type = "bar") %>%
add_trace(y=~Length.b, name = "Length.b") %>%
add_trace(y=~Length.c, name = "Length.c")
plot_ly(
data = data2,
name = "Width.a",
x = ~Var1, y = ~Width.a,
type = "bar") %>%
add_trace(y=~Width.b, name = "Width.b")
For example if I would like to select between viewing a plot with table(iris$Species, iris$Sepal.Length) and a plot with table(iris$Species, iris$Sepal.Width)
Bonus:
If it's easy; being able to interactively select the x variable as well would be cool, but not necessary.
You can find a solution here.
The idea is to plot your bar charts (with data1 and data2) all together and to make visible only one at a time.
items <- list(
list(label="Var1",
args=list(list(visible=c(T,T,T,F,F)))),
list(label="Var2",
args=list(list(visible=c(F,F,F,T,T))))
)
plot_ly(data=data1) %>%
add_bars(name = "Length.a",
x = ~Var1, y = ~Length.a, visible=T) %>%
add_bars(name = "Length.b",
x = ~Var1, y = ~Length.b, visible=T) %>%
add_bars(name = "Length.c",
x = ~Var1, y = ~Length.c, visible=T) %>%
add_bars(name = "Width.a",
x = ~Var1, y = ~Width.a, visible=F, data=data2, marker=list(color="#377EB8")) %>%
add_bars(name = "Width.b",
x = ~Var1, y = ~Width.b, visible=F, data=data2, marker=list(color="#FF7F00")) %>%
layout(
title = "Bar chart with drop down menu",
xaxis = list(title="x"),
yaxis = list(title = "y"),
showlegend = T,
updatemenus = list(
list(y = 0.9,
buttons = items)
))
I create a plot in the following manner:
## generate test data
getTestData <- function(seed_val=711, noise=1.0) {
set.seed(seed_val)
d <- seq(as.Date('2017/01/01'), as.Date('2017/01/08'), "days")
first_name <- rep("Jane", 8)
first_name <- append(first_name, rep("Fred", 8))
first_name <- append(first_name, rep("Sally", 8))
y1_vals <- seq(1, 3*8, 1)
y2_vals <- rnorm(3*8, mean=y1_vals, sd=noise)
dat <- data.frame(date=d, f_name=first_name, y1=y1_vals, y2=y2_vals,
stringsAsFactors = FALSE)
return(dat)
}
dat <- getTestData()
library(dplyr)
library(plotly)
p1 <- plot_ly(dat, x=~date, y=~y1, color=~f_name,
type = 'scatter', mode = "lines+markers") %>%
layout(yaxis = list(title = "some important y value")) %>%
add_trace(y=~y2, name='actual', showlegend=FALSE,
type='scatter', mode='lines',
line=list(width = 2, dash = 'dash'), color=~f_name)
Plotly orders the legend alphabetically by the f_name grouping, but I want this order to be: Jane, Fred, Sally which is the original order in the data frame
The accepted answer given here:
Plotly R order legend entries
in the section commented as #Set sort argument to FALSE and now orders like the data frame is very close to what I need, but this solution is for a pie chart. I need to reorder my legend in a scatterplot which doesn't appear to have a sort parameter available to set (like the pie chart does).
Is this what you want?
dat$f_name <- factor(dat$f_name, levels = c("Jane", "Fred", "Sally"))
plot_ly(dat, x=~date, y=~y1, color=~f_name,
type = 'scatter', mode = "lines+markers") %>%
layout(yaxis = list(title = "some important y value")) %>%
add_trace(y=~y2, name='actual', showlegend=FALSE,
type='scatter', mode='lines',
line=list(width = 2, dash = 'dash'), color=~f_name)
To add something to previous answer, you can also choose colors for names. Note I added Peter to show that if whenever it appears Peter (not this case), its color would be gray (I needed to choose colors in shiny and I needed them to be the same, whether they appeared or not, or in casi they appear)
dat$f_name <- factor(dat$f_name, levels = c("Jane", "Fred", "Sally", "Peter"))
ccolors <- c('black', 'blue','red', 'gray')
plot_ly(dat, x=~date, y=~y1, color=~f_name, colors=ccolors,
type = 'scatter', mode = "lines+markers") %>%
layout(yaxis = list(title = "some important y value")) %>%
add_trace(y=~y2, name='actual', showlegend=FALSE,
type='scatter', mode='lines',
line=list(width = 2, dash = 'dash'), color=~f_name)
I'd like to plot a large scatterplot using the highcharter package, but only allow mouse over on a few outliers. Is there a way to enable mouseTracking on one series but not the other?
df <- data.frame( x = rnorm(1000), y = rnorm(1000) )
df$sig <- ifelse( abs(df$x) > 2, "signif", "not")
library(highcharter)
hc <- highchart() %>%
hc_add_series_df(df, type = "scatter", group=sig)
Right now I can only disable mouse over on all points, but the hc_plotOptions says something about using a series array?
hc_plotOptions(hc, scatter = list( enableMouseTracking= FALSE ))
There are a lot of way to do what you want.
I think the simplest is use:
hchart(df, "scatter", hcaes(x, y, group = sig), enableMouseTracking = c(FALSE, TRUE))
(Note this is the development version of highcharter.)
Which is same as:
highchart() %>%
hc_add_series(data = df %>% filter(sig == "not"), type = "scatter", enableMouseTracking = FALSE) %>%
hc_add_series(data = df %>% filter(sig == "signif"), type = "scatter", enableMouseTracking = TRUE)
Or
highchart() %>%
hc_add_series(data = list_parse(df %>% filter(sig == "not")), type = "scatter", enableMouseTracking = FALSE) %>%
hc_add_series(data = list_parse(df %>% filter(sig == "signif")), type = "scatter", enableMouseTracking = TRUE)