I'm trying to add legends with arbitrary text in a ggvis plot using data from different dataframes. I have tried using add_legend() but I have not idea about what parameters to use. Using plot() is very simple using the legend() function but it has been very hard to find a way to do it using ggvis()
Here is a simple example of what I have using plot():
df1 = data.frame(x = sample(1:10), y = sample(1:10))
df2 = data.frame(x = 1:10, y = 1:10)
df3 = data.frame(x = 1:10, y = sqrt(1:10))
plot(df1)
lines(df2$x, df2$y, col = "red")
lines(df3$x, df3$y, col = "green")
legend("topleft", c("Data 2","Data 3"), lty = 1, col = c("red","green"))
Now, using ggvis() I can plot the points and the lines from different datasets but I can not find a way to put the legends using add_legend(), Here is the code using ggvis():
df1 %>% ggvis(x=~x,y=~y) %>% layer_points() %>%
layer_paths(x=~x,y=~y,data = df2, stroke := "red") %>%
layer_paths(x=~x,y=~y,data = df3, stroke := "green")
I will really appreciate any help.
Thank you.
Edited:
This a sample code using only one data frame and plot()
df = data.frame(x = sample(1:10), y = sample(1:10), x2 = 1:10, y2 = 1:10, y3 = sqrt(1:10) )
plot(df[,c("x","y")])
lines(df$x2, df$y2, col = "red")
lines(df$x2, df$y3, col = "green")
legend("topleft", c("Data 2","Data 3"), lty = 1, col = c("red","green"))
So, what I came up with, is the following, which works:
#add an id column for df2 and df3 and then rbind
df2$id <- 1
df3$id <- 2
df4 <- rbind(df2,df3)
#turn id into a factor
df4$id <- factor(df4$id)
#then plot df4 using the stroke=~id argument
#then plot the legend
#and finally add df1 with a separate data
df4 %>% ggvis(x=~x,y=~y,stroke=~id) %>% layer_lines() %>%
add_legend('stroke', orient="left") %>%
layer_points(x=~x,y=~y,data = df1,stroke:='black')
And it works:
If you would like to move the legend to a position inside the plot then you need to try this:
df4 %>% ggvis(x=~x,y=~y,stroke=~id) %>% layer_lines() %>%
#make sure you use add relative scales
add_relative_scales() %>%
#values for x and y need to be between 0 and 1
#e.g for the x-axis 0 is the at far-most left point and 1 at the far-right
add_legend("stroke", title = "Cylinders",
properties = legend_props(
legend = list(
x = scaled_value("x_rel", 0.1),
y = scaled_value("y_rel", 1)
))) %>%
layer_points(x=~x,y=~y,data = df1,stroke:='black')
And the output:
Related
Maybe is a silly task, but I couldn't figure out how to do it.
I just want to plot the cell values in the heat map using plotly
library(RColorBrewer)
library(plotly)
data <- matrix(data=20, nrow = 10, ncol = 10)
data<- as.data.frame(data)
colnames(data) <- letters[1:10]
rownames(data) <- LETTERS[1:10]
pal <- colorRampPalette(brewer.pal(9, "YlOrRd"))(29)
pal[1] <-c("#FFFFFF")
plot_ly(x = colnames(data), y = rownames(data), z = data, type = "heatmap", colors = pal, height=700, width=700, xgap=10, ygap=10, showscale=TRUE)
When I try add_annotation or setting layout pad etc, it prints the values on the diagonal of the matrix...
Thank you in advance.
Using the following code I generate the plot below.
I added the text using add_annotations on a reshaped dataframe.
library(RColorBrewer)
library(plotly)
library(tidyverse)
library(reshape2)
data <- matrix(data=rnorm(100), nrow = 10, ncol = 10)
x <- letters[1:10]
y <- LETTERS[1:10]
df = data.frame(data)
colnames(df) = x
rownames(df) = y
df = df %>%
rownames_to_column("y") %>%
melt(id.vars = "y") %>%
mutate(value = paste0(round(value*100,2),"%"))
pal <- colorRampPalette(brewer.pal(9, "YlOrRd"))(29)
pal[1] <-c("#FFFFFF")
plot_ly(
z = data,
x = x,
y = y,
text = data,
type = "heatmap",
hoverinfo='none',
colors = pal) %>%
add_annotations(
data = df,
x = ~variable,
y = ~y,
text = ~value,
xref = 'x',
yref = 'y',
showarrow = FALSE,
font=list(color='black'))
I am trying to plot two series at different scales on same plot with dygraph lib in r.
dygraph(data.frame(x = 1:10, y = runif(10),y2=runif(10)*100)) %>%
dyAxis("y", valueRange = c(0, 1.5)) %>%
dyAxis(runif(10)*100,name="y2", valueRange = c(0, 100)) %>%
dyEvent(2, label = "test") %>%
dyAnnotation(5, text = "A")
however, The plot does not fit the data with larger scale, I cannot figure out how to align the two axises. I suspect the option independentTicks in dyAxis() function does the trick but I cannot find how to use it in the documentation. Please help out with this. Best
One way could be:
We pass the named vector of the column with higher values to dySeries function:
See here https://rstudio.github.io/dygraphs/gallery-axis-options.html
library(dygraphs)
library(dplyr)
df = data.frame(x = 1:10, y = runif(10),y2=runif(10)*100)
y2 <- df %>%
pull(y2)
names(y2) <- df$x
dygraph(df) %>%
dySeries("y2", axis = 'y2')
I have grouped data which I want to plot as a group of box plots using R's plotly package, and control the width of the boxes and/or the space between theme.
Here are the data:
set.seed(1)
df <- data.frame(type = c(rep("t1", 1000), rep("t2", 1000), rep("t3", 1000), rep("t4", 1000), rep("t5", 1000), rep("t6", 1000)),
age = rep(c(rep("y", 500),rep("o", 500)), 6),
value = rep(c(runif(500, 5, 10), runif(500, 7.5, 12.5)), 6),
stringsAsFactors = F)
df$age <- factor(df$age, levels = c("y", "o"), ordered = T)
Following plotly's tutorial this is how I'm plotting it:
library(plotly)
library(dplyr)
plot_ly(x = df$type, y = df$value, name = df$age, color = df$type, type = 'box',showlegend = F) %>%
layout(yaxis=list(title="Diversity"),boxmode='group')
Which gives:
Where the boxes come out too narrow and the space both between boxes of the same type as well as the space between the different types are big.
Any idea how to change the box widths and/or the spaces?
According to this post, in python the boxgap and boxgroupgap control these aspects.
Analogous to the python version, layout parameters as being documented here can be changed as arguments of the function layout:
plot_ly(x = df$type, y = df$value, name = df$age, color = df$type,
type = "box", showlegend = F) %>%
layout(yaxis = list(title = "Diversity"),
boxmode = "group", boxgap = 0, boxgroupgap = 0
)
One alternative is to use a continuous x-axis. Here with ggplotly instead:
# convert factors to numbers
df$itype <- as.numeric (factor (df$type))
sc <- scale (unique (as.numeric (factor (df$age))))
df$iage <- sc[as.numeric (factor (df$age))] * .3
# plot
gg <-
ggplot (df, aes (x=itype+iage, y=value, color=type, group=itype+iage)) +
geom_boxplot() +
scale_x_continuous(labels = levels (factor (df$type)), breaks = 1:length (levels (factor (df$type)))) +
labs (x="", y="Diversity")
ggplotly (gg) %>%
layout(boxgroupgap = 0, boxgap=0)
plot
I probably have a simple question but I can't find a way to achieve what I need. I have a simple boxplot as the following:
end_dt <- as.Date("2021-02-12")
start_dt <- end_dt - (nrow(iris) - 1)
dim(iris)
dates <- seq.Date(start_dt, end_dt, by="1 day")
df <- iris
df$LAST_VAL <- "N"
df[3, 'LAST_VAL'] <- "Y"
df1 <- df[,c("Sepal.Length","LAST_VAL")]
df1$DES <- 'Sepal.Length'
colnames(df1) <- c("VALUES","LAST_VAL","DES")
df2 <- df[,c("Sepal.Width","LAST_VAL")]
df2$DES <- 'Sepal.Width'
colnames(df2) <- c("VALUES","LAST_VAL","DES")
df <- rbind(df1, df2)
fig <- plot_ly(df, y = ~VALUES, color = ~DES, type = "box") %>% layout(showlegend = FALSE)
What I would like to do now is a add a red marker to each box plot just for the value corresponding to LAST_VAL = "Y". This would allow me to see given the distribution of each plot, to see where the most recent value is located.
I tried to use the info on https://plotly.com/r/box-plots/ but I can't figure out how to do this.
Thanks
The following solution ended up to be a bit too long codewise. However, it should give you what you asked for. I think the boxplots should be added afterwards, like:
fig <- plot_ly(df[df$LAST_VAL=="Y",],
x=~DES, y = ~VALUES, color = ~DES, type = "scatter", colors='red') %>%
layout(showlegend = FALSE) %>%
add_boxplot(data = df[df$DES=="Sepal.Length",], x = ~DES, y = ~VALUES,
showlegend = F, color = ~DES,
boxpoints = F, fillcolor = 'white', line = list(color = c('blue'))) %>%
add_boxplot(data = df[df$DES=="Sepal.Width",], x = ~DES, y = ~VALUES,
showlegend = F, color = ~DES,
boxpoints = F, fillcolor = 'white', line = list(color = c('green')))
I am plotting the grouped boxplot with jittering with the following function:
plot_boxplot <- function(dat) {
# taking one of each joine_group to be able to plot it
allx <- dat %>%
mutate(y = median(y, na.rm = TRUE)) %>%
group_by(joined_group) %>%
sample_n(1) %>%
ungroup()
p <- dat %>%
plotly::plot_ly() %>%
# plotting all the groups 1:20
plotly::add_trace(data = allx,
x = ~as.numeric(joined_group),
y = ~y,
type = "box",
hoverinfo = "none",
boxpoints = FALSE,
color = NULL,
opacity = 0,
showlegend = FALSE) %>%
# plotting the boxes
plotly::add_trace(data = dat,
x = ~as.numeric(joined_group),
y = ~y,
color = ~group1,
type = "box",
hoverinfo = "none",
boxpoints = FALSE,
showlegend = FALSE) %>%
# adding ticktext
layout(xaxis = list(tickvals = 1:20,
ticktext = rep(levels(dat$group1), each = 4)))
p <- p %>%
# adding jittering
add_markers(data = dat,
x = ~jitter(as.numeric(joined_group), amount = 0.2),
y = ~y,
color = ~group1,
showlegend = FALSE)
p
}
The problem is that when some of the levels have NA as y variable the width of the jittered boxes changes. Here is an example:
library(plotly)
library(dplyr)
set.seed(123)
dat <- data.frame(group1 = factor(sample(letters[1:5], 100, replace = TRUE)),
group2 = factor(sample(LETTERS[21:24], 100, replace = TRUE)),
y = runif(100)) %>%
dplyr::mutate(joined_group = factor(
paste0(group1, "-", group2)
))
# do the plot with all the levels
p1 <- plot_boxplot(dat)
# now the group1 e is having NAs as y values
dat$y[dat$group1 == "e"] <- NA
# create the plot with missing data
p2 <- plot_boxplot(dat)
# creating the subplot to see that the width has changed:
subplot(p1, p2, nrows = 2)
The problem is that the width of boxes in both plots is different:
I've realised that the boxes have the same size without jittering so I know that the jittering is "messing" with the width but I don't know how to fix that.
Does anyone know how to make the width in both jittered plots exactly the same?
I see two separate plot shifts:
due to jittering
due to NAs
First can be solved by declaring new jitter function with fixed seed
fixed_jitter <- function (x, factor = 1, amount = NULL) {
set.seed(42)
jitter(x, factor, amount)
}
and using it instead of jitter in add_markers call.
Second problem can be solved by assigning -1 instead of NA and setting
yaxis = list(range = c(0, ~max(1.1 * y)))
as a second parameter to layout.