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")
Related
I am trying to figure out how to iterate through columns in a data table in R to graph in plotly. Not sure how to do this. Below is the code:
library(data.table)
library(plotly)
library(dplyr)
month_date = c("2019-01-01", "2019-01-02", "2019-01-03")
num_cars = c(100,201,168)
num_planes = c(10,15,17)
master = data.frame(month_date, num_cars, num_planes)
names(master)[2:3] %>%
lapply(function(z){
plot_ly(master,
x = ~month_date,
y = z,
type = 'scatter',
mode = 'lines')
})
Appreciate the help.
A WORKAROUND
I can get this to work below but I don't love using the index. If anyone has something more elegant, would be good:
2:3 %>%
lapply(function(z){
print(z)
plot_ly(master,
x = ~month_date,
y = ~master[,z],
type = 'scatter',
mode = 'lines')
})
Here is an option with for loop
plst <- vector('list', length(master)-1)
names(plst) <- names(master)[-1]
for(nm in names(plst)) {
plst[[nm]] <- plot_ly(master, x = ~ month_date, y = get(nm),
type = 'scatter', mode = 'lines')
}
-check the plots
plst$num_cars
plst$num_planes
Or using the OP's code, just change the 'z' with get(z)
names(master)[2:3] %>%
lapply(function(z){
plot_ly(master,
x = ~month_date,
y = get(z), # // or it can be master[[z]]
type = 'scatter',
mode = 'lines')
})
You can consider using subplot to combine plots after getting the data in long format.
library(plotly)
library(dplyr)
master %>%
tidyr::pivot_longer(cols = -month_date) %>%
group_by(name) %>%
group_map(~ plot_ly(data=., x = ~month_date,
y = ~value, type = "scatter", mode="lines")) %>%
subplot(nrows = 1, shareX = TRUE, shareY=FALSE)
The hover name that appears outside the hover box on my plotly plot is getting cutoff because of the long names. I have found solutions for plotly.js and plotly.py but not R. I have been able to remove that name from the hover or move it into the box with the value, but need a solution that keeps it in place while allowing the entire name to be visible.
# sample data
Value <- rnorm(100, mean = 5)
Time <- c(1:100)
Site <- "Really long name for Site 1"
datTemp <- data.frame(Time, Value, Site)
Value <- rnorm(100, mean = 5)
Time <- c(1:100)
Site <- "Really long name for Site 2"
datTemp2 <- data.frame(Time, Value, Site)
Value <- rnorm(100, mean = 5)
Time <- c(1:100)
Site <- "Really long name for Site 3"
datTemp3 <- data.frame(Time, Value, Site)
figTemp<-datTemp%>%
plot_ly(x = ~Time, y = ~Value, type = "scatter", mode = "lines", line = list(width = 0.75), name = ~Site[1])%>%
layout(xaxis = list(title = "Date"), yaxis = list(title = "Temperature (C)"), legend = list(x = 0, y = 1.05, orientation = "h"))
figTemp<-figTemp%>%
add_trace(data = datTemp2, y = ~Value, type = "scatter", mode = "lines", name = ~Site[1])%>%
add_trace(data = datTemp3, y = ~Value, type = "scatter", mode = "lines", name = ~Site[1])
Add hovertemplate = paste('(%{x}, %{y})') to your call to plot_ly. Worked. Try this:
library(tidyverse)
library(plotly)
# sample data
Value <- rnorm(100, mean = 5)
Time <- c(1:100)
Site <- "Really long name for Site 1"
datTemp <- data.frame(Time, Value, Site)
Value <- rnorm(100, mean = 5)
Time <- c(1:100)
Site <- "Really long name for Site 2"
datTemp2 <- data.frame(Time, Value, Site)
Value <- rnorm(100, mean = 5)
Time <- c(1:100)
Site <- "Really long name for Site 3"
datTemp3 <- data.frame(Time, Value, Site)
figTemp<-datTemp%>%
plot_ly(x = ~Time, y = ~Value, type = "scatter", mode = "lines", line = list(width = 0.75), name = ~Site[1],
hovertemplate = paste('(%{x}, %{y})')) %>%
layout(xaxis = list(title = "Date"), yaxis = list(title = "Temperature (C)"), legend = list(x = 0, y = 1.05, orientation = "h"))
figTemp<-figTemp%>%
add_trace(data = datTemp2, y = ~Value, type = "scatter", mode = "lines", name = ~Site[1]) %>%
add_trace(data = datTemp3, y = ~Value, type = "scatter", mode = "lines", name = ~Site[1])
figTemp
Created on 2020-03-18 by the reprex package (v0.3.0)
I am using plotly package in R-Shiny to plot bar chart. The problem is that the percent sign is not shown in the .
The legend should be generated by using the following piece of code:
data1<- data[,list('MW (%)'=sum(as.numeric(Markw))/mw.g),by=Best]
data2<- data[,list('EL (%)'=sum(as.numeric(`EL absolut`))/EL.g),by=Best]
data3<- data[,list('VaR (%)'=sum(`VaR absolut`)/Var.g),by=Best]
.
.
.
I did not find any option to show (%) in the legend. I tried even the Unicode Character of %, however without success.
Any idea what could be the solution?
The whole code is really big and dose not really help to find the solution if one dose not know already the answer. Everyone can construct a minimal example in which one column is named: 'MW (%)'
However, the part of plot in server.R
output$plot <- renderPlotly({
d.plot<-data.frame(dataset())
# make traces:
x<- d.plot[,1]
y1<- d.plot[,2]*100
y2<- d.plot[,3]*100
y3<- d.plot[,4]*100
#make the plot data frame:
pl.d<- data.frame(x,y1,y2,y3)
#define the margin
m <- list(
b = 200
#autoexpand = TRUE
)
#plot
plot_ly(pl.d, x = ~x, y = ~y1, type = 'bar', name = colnames(d.plot)[2], marker = list(color = "#26478A"),
height=800) %>%
add_trace(y = ~y2, name = colnames(d.plot)[3], marker = list(color = "#FF6600")) %>%
add_trace(y = ~y3, name = colnames(d.plot)[4], marker = list(color = "#7E182F")) %>%
layout("title" = colnames(d.plot)[1],
xaxis = list(title = "", tickangle = 65,tickfont = list(family= "Arial",size = 14),
margin = m
),
yaxis = list(title = "",ticksuffix = "%"),
barmode = 'group'
#margin = m
)
})
You will need to check what is passed to the name arguement of plot_ly and add_trace:
library(plotly)
Animals <- c("giraffes", "orangutans", "monkeys")
SF_Zoo <- c(20, 14, 23)
LA_Zoo <- c(12, 18, 29)
data <- data.frame(Animals, SF_Zoo, LA_Zoo)
p <- plot_ly(data, x = ~Animals, y = ~SF_Zoo, type = 'bar', name = 'MW (%)') %>%
add_trace(y = ~LA_Zoo, name = 'EL (%)') %>%
layout(yaxis = list(title = 'Count'), barmode = 'group')
p
example source
Edit:
With the above example I wanted to point out, that this hasn't got to do anything with plotly.
The reason for the behaviour you describe is that the data.frame() function by default uses the make.names() function to check for syntactically valid names.
You can disable this option by setting check.names=FALSE in your call to data.frame().
Please see the following:
df1 <- data.frame('MW (%)' = 1:10)
print(names(df1))
# [1] "MW...."
df2 <- data.frame('MW (%)' = 1:10, check.names=FALSE)
print(names(df2))
# [1] "MW (%)"
I hope this helped to clarify.
actually I did not change the code really. Because of the answer above, I recognized the problem lies on
d.plot<-data.frame(dataset())
I changed just for instance
name = colnames(d.plot)[2]
into
name = colnames(dataset())[2],
where dataset() is a data.table.
In other words,data.frame replacing by data.table
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'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)
)