stacked bar chart in ggplot when converted to plotly doesnt render right - r

update: adding a minimum reproducible code for the data.
im trying to convert a ggplot to plotly chart in shiny. The problem is that in ggplot, the stacked bar chart (with stat =identity) stacks up nicely without any spaces in between, whereas when i convert to plotly, there are these spaces in between each item.
I am not producing the entire code for shiny, as it is difficult to follow. However here are the images and a much simplified code (not the shiny version)
t<- 1:50
GIB_Rating = rep(c('2','3','4+','5','5-','7','8','6','6+','5'),5)
t1<-data.frame(t,GIB_Rating)
CapitalChargeType = c('Credit_risk_Capital','NameConcentration','SectorConcentration')
t2<- expand.grid(t=t, CapitalChargeType=CapitalChargeType)
t3<-left_join(t2,t1)
New = rnorm(150, mean=100,sd=250)
t3<- data.frame(t3,New)
t3<- ggplot(t3, aes(x=GIB_Rating, y=New, fill=CapitalChargeType)) + geom_bar(stat='identity')
t3
this produces this image some what like this, which is exactly what I want.
However as it is not interactive, I want a plotly image, which shows the total of capital charge type when cursor hovers over. so, I use the code below
t4<-ggplotly(t3)
t4
the plotly plot now produced has white lines (for each individual item) in between each color class (Capitalchargetype), which i want to avoid, also the tooltip also produces individual items rather than the sum of each CapitalChargeType

The issue is in the way plotly handles stacked bars of factors. Each factor gets wrapped in a border which is white by default. There's a very easy workaround: Just add color = CapitalChargeType to the ggplot object.
library(tidyverse)
df <- data_frame(
t = 1:50,
GIB_Rating = rep(c('2','3','4+','5','5-','7','8','6','6+','5'),5)
)
df <- df %>%
expand(t, CapitalChargeType =
c('Credit_risk_Capital','NameConcentration','SectorConcentration')) %>%
left_join(df) %>%
mutate(New = rnorm(150, mean=100,sd=250))
g <- ggplot(df, aes(x = GIB_Rating, y = New, fill = CapitalChargeType, color = CapitalChargeType)) +
geom_bar(stat='identity')
plotly::ggplotly(g)

Related

Select data and name when pointing it chart with ggplotly

I did everything in ggplot, and it was everything working well. Now I need it to show data when I point a datapoint. In this example, the model (to identify point), and the disp and wt ( data in axis).
For this I added the shape (same shape, I do not actually want different shapes) to model data. and asked ggplot not to show shape in legend. Then I convert to plotly. I succeeded in showing the data when I point the circles, but now I am having problems with the legend showing colors and shapes separated with a comma...
I did not wanted to make it again from scrach in plotly as I have no experience in plotly, and this is part of a much larger shiny project, where the chart adjust automatically the axis scales and adds trend lines the the chart among other things (I did not include for simplicity) that I do not know how to do it in plotly.
Many thanks in advance. I have tried a million ways for a couple of days now, and did not succeed.
# choose mtcars data and add rowname as column as I want to link it to shapes in ggplot
data1 <- mtcars
data1$model <- rownames(mtcars)
# I turn cyl data to character as when charting it showed (Error: Continuous value supplied to discrete scale)
data1$cyl <- as.character(data1$cyl)
# linking colors with cylinders and shapes with models
ccolor <- c("#E57373","purple","green")
cylin <- c(6,4,8)
# I actually do not want shapes to be different, only want to show data of model when I point the data point.
models <- data1$model
sshapes <- rep(16,length(models))
# I am going to chart, do not want legend to show shape
graff <- ggplot(data1,aes(x=disp, y=wt,shape=model,col=cyl)) +
geom_point(size = 1) +
ylab ("eje y") + xlab('eje x') +
scale_color_manual(values= ccolor, breaks= cylin)+
scale_shape_manual(values = sshapes, breaks = models)+
guides(shape='none') # do not want shapes to show in legend
graff
chart is fine, but when converting to ggplotly, I am having trouble with the legend
# chart is fine, but when converting to ggplotly, I am having trouble with the legend
graffPP <- ggplotly(graff)
graffPP
legend is not the same as it was in ggplot
I succeeded in showing the model and data from axis when I point a datapoint in the chart... but now I am having problems with the legend....
To the best of my knowledge there is no easy out-of-the box solution to achieve your desired result.
Using pure plotly you could achieve your result by assigning legendgroups which TBMK is not available using ggplotly. However, you could assign the legend groups manually by manipulating the plotly object returned by ggplotly.
Adapting my answer on this post to your case you could achieve your desired result like so:
library(plotly)
p <- ggplot(data1, aes(x = disp, y = wt, shape = model, col = cyl)) +
geom_point(size = 1) +
ylab("eje y") +
xlab("eje x") +
scale_color_manual(values = ccolor, breaks = cylin) +
scale_shape_manual(values = sshapes, breaks = models) +
guides(shape = "none")
gp <- ggplotly(p = p)
# Get the names of the legend entries
df <- data.frame(id = seq_along(gp$x$data), legend_entries = unlist(lapply(gp$x$data, `[[`, "name")))
# Extract the group identifier, i.e. the number of cylinders from the legend entries
df$legend_group <- gsub("^\\((\\d+).*?\\)", "\\1", df$legend_entries)
# Add an indicator for the first entry per group
df$is_first <- !duplicated(df$legend_group)
for (i in df$id) {
# Is the layer the first entry of the group?
is_first <- df$is_first[[i]]
# Assign the group identifier to the name and legendgroup arguments
gp$x$data[[i]]$name <- df$legend_group[[i]]
gp$x$data[[i]]$legendgroup <- gp$x$data[[i]]$name
# Show the legend only for the first layer of the group
if (!is_first) gp$x$data[[i]]$showlegend <- FALSE
}
gp

Aligning groups of points and of boxplots in ggplotly

I am trying to interactively show both points and boxplots of the same data in a ggplotly situation.
"dodged" positioning does the job in ggplot, but when passing to plotly positioning goes off--how do I get boxes and points to line up? (Essentially throwing points on top of this question. I also realize that an answer to this question would likely also be an answer to my question, though there may be more answers for my issue.)
What I want is for both layers to show up together, even when a group is missing at a location (either centered or in the group location), for examply like so:
What I get with interactivity so far is this:
library(plotly)
mtcars_boxplot <- mtcars %>%
mutate(cyl=as.factor(cyl)) %>%
mutate(vs=as.factor(vs)) %>%
ggplot(aes(y=mpg, x=cyl)) +
geom_boxplot(aes(color=vs), position=position_dodge())+
geom_point(aes(color=vs), position=position_jitterdodge(), size = 0.5)
mtcars_boxplot %>%
ggplotly() %>%
layout(boxmode='group')
You can see that for cyl=8, the points are centered, but the box shows up in its group's location.
My question is: how do I get an interactive version of the first image, or something similar (preferably using ggplotly)?
I found a way to do this--not with ggplot, but pure plotly:
mtcars_boxplot <- mtcars %>%
mutate(cyl=as.factor(cyl)) %>%
mutate(vs=as.factor(vs)) %>%
plot_ly(type="box",
x = ~cyl,
y = ~mpg,
color = ~vs,
alignmentgroup = ~MOTART,
boxpoints = "all",
pointpos = 0,
jitter = 1) %>%
layout(boxmode='group')
If there is a ggplotly-answer, I would still love to know that one. (This actually ends up aligning more nicely, but is also more work when working in ggplot otherwise.)

Is there a transition function to keep old bars and add on new ones? Transition_reveal just moves the singular bar

Trying to make it so that I can add the bars on one by one for a bar chart in R. I know that there is a function called transition_layers, but haven't been able to make it work for the life of me. In the reproducible example below I have the bar moving over the years, but what I want is a new bar added one by one over the years and for each older bar to stay.
Libraries:
library(magrittr)
library(broom)
library(purrr)
library(gganimate)
library(gifski)
library(ggthemes)
library(png)
library(jpeg)
library(ggimage)
library(grid)
Cost <- c(1, 2, 4)
Year <- c(2016, 2017, 2018)
example <- data.frame(Year, Cost)
example_bar <-ggplot(data = example, mapping = aes(Year))+
geom_bar(aes(weight = Cost))+
theme_stata()+
transition_reveal(Year)
You need to explicitly tell gganimate that each column in the x-axis is in a different group by setting group=Year inside geom_col (I changed geom_bar to geom_col because I think it is more intuitive, but it is basically the same thing). Otherwise, gganimate will treat all of them as the same group and the column will slide through the x-axis. This has happened to me before with other types of animations. Explicitly setting the group parameter is generally a good idea.
ggplot(data = example)+
geom_col(aes(x=Year, y = Cost, group=Year)) +
transition_reveal(Year)
anim_save(filename = 'gif1.gif', anim1, nframes=30, fps=10, end_pause=5)
However, I could not set transition times and configure how new columns appear using transition_reveal. The animation looks strange and each column stays there a long time before the other one. I could make it a little better using animate/anim_save...
So another solution is to change the data frame by keeping "past" rows, create a new column with current year, and work with transition_states
library(dplyr)
df.2 <- plyr::ldply(.data= example$Year,
.fun = {function(x){
example %>% dplyr::filter(Year <= x) %>%
dplyr::mutate(frame=x)}})
# add row with data for dummy empty frame
df.2 <- rbind(data.frame(Year=2016, Cost=0, frame=2015), df.2)
anim2 <- ggplot(data = df.2) +
geom_col(aes(x=Year, y = Cost, group=Year)) +
transition_states(frame, transition_length = 2, state_length = 1, wrap=FALSE) +
enter_fade() + enter_grow()
anim_save(filename = 'gif2.gif', anim2)

Plot multicolor vertical lines by using ggplot to show average time taken for each type as facet. Each type will have different vertical lines

I want to plot a chart in R where it will show me vertical lines for each type in facet.
df is the dataframe with person X takes time in minutes to reach from A to B and so on.
I have tried below code but not able to get the result.
df<-data.frame(type =c("X","Y","Z"), "A_to_B"= c(20,56,57), "B_to_C"= c(10,35,50), "C_to_D"= c(53,20,58))
ggplot(df, aes(x = 1,y = df$type)) + geom_line() + facet_grid(type~.)
I have attached image from excel which is desired output but I need only vertical lines where there are joins instead of entire horizontal bar.
I would not use facets in your case, because there are only 3 variables.
So, to get a similar plot in R using ggplot2, you first need to reformat the dataframe using gather() from the tidyverse package. Then it's in long or tidy format.
To my knowledge, there is no geom that does what you want in standard ggplot2, so some fiddling is necessary.
However, it's possible to produce the plot using geom_segment() and cumsum():
library(tidyverse)
# First reformat and calculate cummulative sums by type.
# This works because factor names begins with A,B,C
# and are thus ordered correctly.
df <- df %>%
gather(-type, key = "route", value = "time") %>%
group_by(type) %>%
mutate(cummulative_time = cumsum(time))
segment_length <- 0.2
df %>%
mutate(route = fct_rev(route)) %>%
ggplot(aes(color = route)) +
geom_segment(aes(x = as.numeric(type) + segment_length, xend = as.numeric(type) - segment_length, y = cummulative_time, yend = cummulative_time)) +
scale_x_discrete(limits=c("1","2","3"), labels=c("Z", "Y","X"))+
coord_flip() +
ylim(0,max(df$cummulative_time)) +
labs(x = "type")
EDIT
This solutions works because it assigns values to X,Y,Z in scale_x_discrete. Be careful to assign the correct labels! Also compare this answer.

Plotly.r & ggplot2: when clicking the legend in a plot made via ggplotly, it fails to update ranges and bar positions after cases are withdrawn

(Based on the "Add Lines" example found here: https://plot.ly/ggplot2/geom_histogram/. It is also similar to this Q, which has no satisfactory anwser for me, since I need to use the ggplot features, like being able to use log scale in the x-axis)
In a normal plot_ly plot, when some legend element is clicked, the plot is modified taking away all the cases matching that legend group. The following example illustrates this behaviour:
library(plotly)
gg_color_hue <- function(n) {
hues = seq(15, 375, length = n + 1)
hcl(h = hues, l = 65, c = 100)[1:n]
}
set.seed(0)
df1 <- data.frame(
cond = factor(rep(c("A", "B"), each=200)),
rating = c(rnorm(200), rnorm(200, mean=.9))
)
plot_ly(df1,
x = ~rating,
color = ~cond,
colors = gg_color_hue(2)) %>%
add_histogram() %>%
layout(barmode = "stack")
The figures show the interactive plot before and after clicking on the groups of the legend:
Figure 1: Histogram made using plot_ly, as it is plotted initially.
Figure 2: Histogram made using plot_ly, with only the B cases (after the A in the legend was clicked). Note how both axis adjusted to the new range of values.
Figure 3: Histogram made using plot_ly, with only the A cases (B was clicked). Again, both axis adjusted to the new range of values.
However, this does not happen when the plot is created via ggplot + ggplotly. Here is an example (please, do not mind the change in labels and colors or in the shape of the histograms, since those are not the focus of this Q and I don't believe are relevant):
p <- ggplot(data = df1) +
aes(x = rating, fill = cond) +
geom_histogram(bins = 13)
ggplotly(p)
Figure 4: Histogram made using ggplot and ggplotly.
Figure 5: Histogram made using ggplot and ggplotly, now with only the B cases (A was clicked). Note that the axis remain unchanged this time.
Figure 6: Histogram made using ggplot and ggplotly, now with only the A cases (B was clicked). Clearly the most ridiculous plot of them all, since the bars simply remain in their original spot, which is not helpfull at all for a histogram.
As I said, this is not a very desirable behaviour and I do not know if there's something I can do to correct it. If someone knows what can I do about this, I'll be very thankful.

Resources