Create a secondary y axis for lines graph with ggvis R - r

This is what i have so far with the ggvis package in R.
mtcars %>% ggvis(x = ~disp) %>%
layer_lines(y = ~wt, stroke := "red") %>%
layer_lines(y = ~mpg) %>%
add_axis("y", orient = "left", title = "Weight (lb/1000)") %>%
add_axis("y", orient = "right", title= "Miles/(US) gallon") %>%
add_axis("x", title = "Displacement (cu.in.)")
I cannot get the left Y axis to represent the wt scale data.
This outputs:

I assume you want the left y axis (i.e. wt) divided by 1000:
library(dplyr) #you need this library
mtcars %>% mutate(wt_scaled=wt/1000) %>% ggvis(x = ~disp) %>% #use mutate from dplyr to add scaled wt
layer_lines(y = ~wt_scaled, stroke := "red") %>% #use new column
add_axis("y", orient = "left", title = "Weight (lb/1000)" ,title_offset = 50) %>% #fix left axis label
scale_numeric("y", domain = c(0, 0.006), nice = FALSE) %>% #align the ticks as good as possible
add_axis("y", 'ympg' , orient = "right", title= "Miles/(US) gallon" , grid=F ) %>% #remove right y axis grid and name axis
layer_lines( prop('y' , ~mpg, scale='ympg') ) %>% #use scale to show layer_lines which axis it should use
add_axis("x", title = "Displacement (cu.in.)" )
and I think this is what you want:
EDIT:
If you just wanted to plot wt on the left y axis (it is not very clear) then do mutate(wt_scaled=wt/1) (or remove mutate) and change domain to domain = c(1.5, 5.5)

Related

How to adjust legend title position in ggplotly in r? [duplicate]

In the following example how can i add a title to the legend in plot_ly for R ?
mtcars %>% plot_ly(x = ~disp, y = ~mpg, color = ~factor(cyl), size = ~wt) %>% add_markers(
hoverinfo = "text",
text = ~paste("Displacement = ", disp, "\nMiles Per Gallon = ", mpg) ) %>% layout(title ="Custom Hover Text")
thanks
This functionality has since been included within the layout function in the legend option. There's a sub-option called title within which you can supply a list that includes the text.
mtcars %>%
plot_ly(x = ~disp, y = ~mpg, color = ~factor(cyl), size = ~wt) %>%
add_markers(hoverinfo = "text",
text = ~paste("Displacement = ", disp, "\nMiles Per Gallon = ", mpg) ) %>%
layout(title = "Custom Hover Text",
legend = list(title = list(text = "<b>Cylinders</b>"))) # TITLE HERE
The only way I know is to use an annotation and add it to the plot. Like this:
legendtitle <- list(yref='paper',xref="paper",y=1.05,x=1.1, text="Cylinders",showarrow=F)
mtcars %>% plot_ly(x = ~disp, y = ~mpg, color = ~factor(cyl), size = ~wt) %>%
add_markers( hoverinfo = "text",
text = ~paste("Displacement=",disp, "\nMiles Per Gallon = ", mpg)) %>%
layout(title ="Custom Hover Text", annotations=legendtitle )
Yielding:
It is a bit tricky to place the legend title though, not sure if this placement would always work.
Another way would be to use ggplot and ggplotly of course, and let ggplot figure it out.

How to remove duplicate legend entries w/ plotly subplots()

How can I remove the duplicates in my legend when using plotly's subplots()?
Here is my MWE:
library(plotly)
library(ggplot2)
library(tidyr)
mpg %>%
group_by(class) %>%
do(p = plot_ly(., x = ~cyl, y = ~displ, color = ~trans, type = 'bar')) %>%
subplot(nrows = 2, shareX = TRUE, titleX = TRUE) %>%
layout(barmode = 'stack')
plotly does not have facet like ggplot2 so it will add legend for each subplot or you can turn it off for some of them.
Here we do not have a layer with all the ~class entries nor two plots with no intersection in class which their combination also covers all of them. In that case, we could set showlegend to TRUE for those specific plot(s) and set it to FALSE for the rest and also set the legendgroup to trans so we get a unique but also complete legend.
As I said, here we do not have that special case. So What I can think of are two possibilities:
Adding the whole data (duplicating whole dataframe) and assigning class of All to them. Then plotting that along with original data but keep the legend only for class == All.
Using ggplot::facet_wrap and then ggplotly to make a plotly object. However, this would cause some issues with x-axis (compare ggplot object to plotly ones).
library(plotly)
library(ggplot2)
library(dplyr)
ly_plot <- . %>%
plot_ly(x = ~cyl, y = ~displ, color = ~trans,
type = 'bar', showlegend = ~all(legendC)) %>%
add_annotations(
text = ~unique(class),
x = 0.5,
y = 1,
yref = "paper",
xref = "paper",
xanchor = "middle",
yanchor = "top",
showarrow = FALSE,
font = list(size = 15))
mpg %>%
mutate(class= "_All_") %>%
rbind(.,mpg) %>%
mutate(legendC = (class == "_All_")) %>%
group_by(class) %>%
do(p = ly_plot(.)) %>%
subplot(nrows = 2, shareX = TRUE, titleX = TRUE) %>%
layout(barmode = 'stack')
#> Warning in RColorBrewer::brewer.pal(N, "Set2"): n too large,
#> allowed maximum for palette Set2 is 8
#> Returning the palette you asked for with that many colors
p <- ggplot(data = mpg, aes(x=cyl, y=displ, fill=trans))+
geom_bar(stat="identity") +
facet_wrap(~class)
p
ggplotly(p) #seems for this we should also set "colour = trans"
Another workaround using the tidyverse. The following steps are added to the original MWE:
Convert the trans column to a factor.
Use tidyr's complete to fill (non-NA) dummy values for the missing factor levels in each class group.
Follow M-M's suggestion setting showlegend to TRUE for a single group and legendgroup to trans to link the legend entries between subplots.
library(plotly)
library(tidyverse)
mpg %>%
mutate_at("trans", as.factor) %>%
group_by(class) %>%
group_map(.f = ~{
## fill missing levels w/ displ = 0, cyl = first available value
complete(.x, trans, fill = list(displ = 0, cyl = head(.x$cyl, 1))) %>%
plot_ly(x = ~cyl, y = ~displ, color = ~trans, colors = "Paired", type = "bar",
showlegend = (.y == "2seater"), legendgroup = ~trans) %>%
layout(yaxis = list(title = as.character(.y)), barmode = "stack")
}) %>%
subplot(nrows = 2, shareX = TRUE, titleY = TRUE)

Separate symbol and color in plotly legend

I want to achieve the same result as this ggplot code with plotly:
mtcars %>% add_rownames('car') %>%
ggplot(aes(x = mpg,
y = disp,
color = as.factor(gear),
shape = as.factor(cyl))) +
geom_point()
which results in:
My plotly code is:
library(dplyr)
mtcars %>% add_rownames('car') %>%
plot_ly(x = ~mpg,
y = ~disp,
text = ~car,
color = ~as.factor(gear),
symbol = ~as.factor(cyl),
mode = 'markers')
which enumerates all possible combinations of colors and shapes in the legend.
Is there a way to have a similar legend to the ggplot?
UPDATE: To overcome some of the issues mentioned for my previous solution (see below) and to increase the usability of the legend, one can simply add the column name to the legend description and then assign the legendgroups to each category.
mtcars %>% rownames_to_column('car') %>%
plot_ly() %>%
#Plot symbols for cyl
add_trace(type = "scatter",
x = ~mpg,
y = ~disp,
text = ~car,
symbol = ~paste0(cyl," cyl."),
mode = 'markers',
marker = list(color = "grey", size = 15)) %>%
#Overlay color for gears
add_trace(type = "scatter",
x = ~mpg,
y = ~disp,
text = ~car,
color = ~paste0(gear, " gears"),
mode = 'markers')
This is the previous solution, which is visually closer to the ggplot2 equivalent:
Based on the answer of dww in this thread, we can manually create the groups for cylinders and gears. Subsequently, with the answer of Artem Sokolov this thread, we can add the legend titles as annotations.
mtcars %>% rownames_to_column('car') %>%
plot_ly() %>%
#Plot symbols for cyl
add_trace(type = "scatter",
x = ~mpg,
y = ~disp,
text = ~car,
symbol = ~as.factor(cyl),
mode = 'markers',
legendgroup="cyl",
marker = list(color = "grey", size = 15)) %>%
#Overlay color for gears
add_trace(type = "scatter",
x = ~mpg,
y = ~disp,
text = ~car,
color = ~as.factor(gear),
mode = 'markers',
legendgroup="gear") %>%
#Add Legend Titles (manual)
add_annotations( text="Cylinders:", xref="paper", yref="paper",
x=1.02, xanchor="left",
y=0.9, yanchor="bottom", # Same y as legend below
legendtitle=TRUE, showarrow=FALSE ) %>%
add_annotations( text="Gears:", xref="paper", yref="paper",
x=1.02, xanchor="left",
y=0.7, yanchor="bottom", # Y depends on the height of the plot
legendtitle=TRUE, showarrow=FALSE ) %>%
#Increase distance between groups in Legend
layout(legend=list(tracegroupgap =30, y=0.9, yanchor="top"))
Unsolved issues:
Groups have to be created manually
Groups are just overlayed (color over shape). This means that only the whole group can be dis-/activated in the legend (e.g., it is not possible to only show only the entries with 4 cylinders)
The position of the second legend title (annotation) depends on the height of the plot!

Change locale in Plotly for R (thousand separator and decimal character)

I'd like to adjust the tick labels in a plotly chart so that they would display a comma as a decimal separator and a point as a thousand separator.
library(plotly)
library(ggplot2)
library(dplyr)
diamonds %>%
mutate(cut = as.character(cut)) %>%
count(cut, clarity) %>%
plot_ly(x = ~cut, y = ~n, color = ~clarity) %>%
layout(yaxis = list(tickformat = ",.1f"))
my local is already set to "LC_COLLATE=German_Austria.1252;LC_CTYPE=German_Austria.1252;LC_MONETARY=German_Austria.1252;LC_NUMERIC=C;LC_TIME=C"
This is an ugly answer but you can set up your object:
d2 <- diamonds %>%
mutate(cut = as.character(cut)) %>%
count(cut, clarity)
and then create the axis labels from there:
ticklabels <- seq(from=0, to=round(max(d2$n), digits = -3), by=1000)
To create a custom axis label:
plot_ly(d2, x = ~cut, y = ~n, color = ~clarity) %>%
layout(yaxis = list(tickvals = ticklabels, ticktext = paste(ticklabels/1000, ".000", ",00", sep="") ))

ggvis add_legend for 'strokeDash' or 'strokeWidth'

I want to group data on two variables and distinguish them in a ggvis plot via 'stroke' and 'strokeDash'. If I want to add legends to a ggvis plot, I can do so for the 'stroke' property:
library(ggvis)
mtcars %>%
ggvis(~wt, ~mpg, stroke = ~factor(cyl), strokeDash = ~factor(vs)) %>%
layer_lines() %>%
add_legend('stroke', title = 'Number of cylinders')
However, if try to add a legend for 'strokeDash', the plot does not get rendered:
mtcars %>%
ggvis(~wt, ~mpg, stroke = ~factor(cyl), strokeDash = ~factor(vs)) %>%
layer_lines() %>%
add_legend('stroke', title = 'Number of cylinders') %>%
add_legend('strokeDash', title = 'V/S')
Same applies, if I try it with 'strokeWidth' instead of 'strokeDash':
# works
mtcars %>%
ggvis(~wt, ~mpg, stroke = ~factor(cyl), strokeWidth = ~factor(vs)) %>%
layer_lines() %>%
scale_nominal('strokeWidth', range = c(1,5)) %>%
add_legend('stroke', title = 'Number of cylinders')
# does not work
mtcars %>%
ggvis(~wt, ~mpg, stroke = ~factor(cyl), strokeWidth = ~factor(vs)) %>%
layer_lines() %>%
scale_nominal('strokeWidth', range = c(1,5)) %>%
add_legend('stroke', title = 'Number of cylinders')%>%
add_legend('strokeWidth', title = 'V/S')
Does anyone know, why for 'stroke' it works and for the others it does not? Any solutions?
Thanks,
Fabian

Resources