I have horizontal dots plot replotted via ggplotly
df <- data.frame (origin = c("A","B","C","D","E","F","G","H","I","J"),
Percentage = c(23,16,32,71,3,60,15,21,44,60),
rate = c(10,12,20,200,-25,12,13,90,-105,23),
change = c(10,12,-5,12,6,8,0.5,-2,5,-2)
library(ggplot2)
plt <- ggplot(df, aes(x = rate, y = factor(origin, rev(origin)))) +
geom_hline(aes(yintercept = origin), color = 'gray') +
geom_vline(xintercept = 0, linetype = 2, color = 'gray') +
geom_point(aes(color = 'Rate'), size = 10) +
geom_text(aes(label = rate), color = 'white') +
geom_point(aes(x = change, color = 'Change'), size = 10) +
geom_text(aes(label = change, x = change)) +
theme_minimal(base_size = 16) +
scale_x_continuous(labels = ~paste0(.x, '%'), name = NULL) +
scale_color_manual(values = c('#aac7c4', '#5f9299')) +
theme(panel.grid = element_blank(),
axis.text.y = element_text(color = 'gray50')) +
labs(color = NULL, y = NULL)
ggplotly(plt)
The only issue is that when I hide one of the dot from the figure, texts are still appeared (see below), so is there way to tackle this issue and hide text with circle by clicking on legend?
P.S
(setting text colour in white color = 'white' is not option for me)
You can use the fill aesthetic for the points (as long as they are shape = 21) and use the color aesthetic for the text. As long as these have the same labels for aesthetic mapping, the interactivity for both points and text will be linked.
One minor annoyance is that this changes the plotly legend labels, even though they are correct in the ggplot version. This requires a little direct manipulation of the plotly object itself:
plt <- ggplot(df, aes(x = rate, y = factor(origin, rev(origin)))) +
geom_segment(aes(x = -100, xend = 200,
y = origin, yend = origin), color = 'gray') +
geom_vline(xintercept = 0, linetype = 2, color = 'gray') +
geom_point(aes(fill = 'Rate'), shape = 21, size = 10, color = NA) +
geom_text(aes(label = rate, color = 'Rate')) +
geom_point(aes(x = change, fill = 'Change'),
color = NA, shape = 21, size = 10) +
geom_text(aes(label = change, x = change, color = "Change")) +
theme_minimal(base_size = 16) +
scale_x_continuous(labels = ~paste0(.x, '%'), name = NULL) +
scale_fill_manual(values = c('#aac7c4', '#5f9299')) +
scale_color_manual(values = c("black", "white")) +
theme(panel.grid = element_blank(),
axis.text.y = element_text(color = 'gray50')) +
labs(color = NULL, y = NULL, fill = NULL)
p <- ggplotly(plt)
p$x$data[[3]]$name <- p$x$data[[3]]$legendgroup <-
p$x$data[[4]]$name <- p$x$data[[4]]$legendgroup <- "Rate"
p$x$data[[5]]$name <- p$x$data[[5]]$legendgroup <-
p$x$data[[6]]$name <- p$x$data[[6]]$legendgroup <- "Change"
p
This gives us the following plot:
Now clicking on Rate we get:
And clicking on Change we get
Related
i have run the following code yet what is inside the "theme" function doesn't work (it does not change the legend title nor the axis title). Could anyone help fix this problem ?
ggplot() +
geom_line(aes(x = df$année,
y = df$nb_amb,
color = df$Type_amb,
group = 1)) +
geom_line(aes(x = df$année,
y = df$nb_hosp,
color = df$type_hosp,
group = 1)) +
geom_line(aes(x = df$année,
y = df$nb_ext,
color = df$type_ext,
group = 1)) +
theme(axis.title.y = element_text("trip"),
axis.title.x = element_text("year"),
legend.title = element_text("alpha"))
Putting the comments together, your code would look something like this:
ggplot(PGS_evol_type) +
geom_line(aes(x = année, y = nb_amb, color = type_amb, group = 1)) +
geom_line(aes(x = année, y = nb_hosp, color = type_hosp, group = 1)) +
geom_line(aes(x = année, y = nb_ext, color = type_ext, group = 1)) +
labs(y = "nombre de séjour", x = "année", color = "type de séjour") +
# Theme is used for changing the look of objects, for example
theme(
axis.title.x = element_text(face = "bold", size = "14"),
axis.title.y = element_text(face = "italic", size = "12")
)
I am plotting a smooth to my data using geom_smooth and using geom_ribbon to plot shaded confidence intervals for this smooth. No matter what I try I cannot get a single legend that represents both the smooth and the ribbon correctly, i.e I am wanting a single legend that has the correct colours and labels for both the smooth and the ribbon. I have tried using + guides(fill = FALSE), guides(colour = FALSE), I also read that giving both colour and fill the same label inside labs() should produce a single unified legend.
Any help would be much appreciated.
Note that I have also tried to reset the legend labels and colours using scale_colour_manual()
The below code produces the below figure. Note that there are two curves here that are essentially overlapping. The relabelling and setting couours has worked for the geom_smooth legend but not the geom_ribbon legend and I still have two legends showing which is not what I want.
ggplot(pred.dat, aes(x = age.x, y = fit, colour = tagged)) +
geom_smooth(size = 1.2) +
geom_ribbon(aes(ymin = lci, ymax = uci, fill = tagged), alpha = 0.2, colour = NA) +
theme_classic() +
labs(x = "Age (days since hatch)", y = "Body mass (g)", colour = "", fill = "") +
scale_colour_manual(labels = c("Untagged", "Tagged"), values = c("#3399FF", "#FF0033")) +
theme(axis.title.x = element_text(face = "bold", size = 14),
axis.title.y = element_text(face = "bold", size = 14),
axis.text.x = element_text(size = 12),
axis.text.y = element_text(size = 12),
legend.text = element_text(size = 12))
The problem is that you provide new labels for the color-aesthetic but not for the fill-aesthetic. Consequently ggplot shows two legends because the labels are different.
You can either also provide the same labels for the fill-aesthetic (code option #1 below) or you can set the labels for the levels of your grouping variable ("tagged") before calling ggplot (code option #2).
library(ggplot2)
#make some data
x = seq(0,2*pi, by = 0.01)
pred.dat <- data.frame(x = c(x,x),
y = c(sin(x), cos(x)) + rnorm(length(x) * 2, 0, 1),
tag = rep(0:1, each = length(x)))
pred.dat$lci <- c(sin(x), cos(x)) - 0.4
pred.dat$uci <- c(sin(x), cos(x)) + 0.4
#option 1: set labels within ggplot call
pred.dat$tagged <- as.factor(pred.dat$tag)
ggplot(pred.dat, aes(x = x, y = y, color = tagged, fill = tagged)) +
geom_smooth(size = 1.2) +
geom_ribbon(aes(ymin = lci, ymax = uci), alpha = 0.2, color = NA) +
scale_color_manual(labels = c("untagged", "tagged"), values = c("#F8766D", "#00BFC4")) +
scale_fill_manual(labels = c("untagged", "tagged"), values = c("#F8766D", "#00BFC4")) +
theme_classic() + theme(legend.title = element_blank())
#option 2: set labels before ggplot call
pred.dat$tagged <- factor(pred.dat$tag, levels = 0:1, labels = c("untagged", "tagged"))
ggplot(pred.dat, aes(x = x, y = y, color = tagged, fill = tagged)) +
geom_smooth(size = 1.2) +
geom_ribbon(aes(ymin = lci, ymax = uci), alpha = 0.2, color = NA) +
theme_classic() + theme(legend.title = element_blank())
I am trying to make a combo chart using ggplot2. However i want to add a text box sort outside my plot body. I am unable to place it at the desired location
I have used grid pack to create grob and include that in annotation in the ggplot code. Additionally i have also put the same text in geom_text. How do i ensure the text comes say below the legend. Following is my code
m <- ggplot() +
geom_area(data= (ly_vol_ntwk %>%
mutate(Wk_end_d = as.factor(Wk_end_d))%>%
filter(!is.na(value_new))),
aes(x = Wk_end_d, y = value_new ,group = variable,fill=variable))+
geom_bar(data = (fcst_act_vol_ntwk %>%
mutate(Wk_end_d = as.factor(Wk_end_d))%>%
filter(!is.na(value_new))),
aes(x = Wk_end_d, y = value_new, group = variable, fill = variable),
stat = "identity",position = "dodge", width =0.5)+
geom_line(data = (var_vol_ntwk %>%
mutate(Wk_end_d = as.factor(Wk_end_d))%>%
filter(!is.na(value_new))),
aes(x = Wk_end_d, y = value_new,
group = variable, fill= variable), size = 0.8)+
scale_y_continuous(sec.axis = sec_axis(trans = ~./100000,
name = "Variance", breaks = waiver(),
labels=function(x) paste0(x,"%")))+
theme_set(theme_bw())+
theme(axis.text.x = element_text(angle=65, vjust=0.5,face = "plain"),
text = element_text(size=9), legend.position = "bottom", legend.title = element_blank())+
labs(title= "Inbound - Network", x= "Week end date", y = " ")+
scale_fill_manual(values = c("#C5E0B4","#7030A0", "#D9D9D9","#ED7D31","black"))+
geom_text(label = "LW Variance",
aes(x = 19, y = -1960000),
check_overlap = TRUE) #annotation_custom(grob = textGrob("LW Variance"), xmin = 18, xmax = 18, ymin = -1030000, ymax = -1030000)+ coord_cartesian(clip = 'off')
I need to get the text box with a border outside the area of the ggplot. Can you please help me?
You can place text below plot area with labs(caption = "text"), but you can't place captions on top of the plot. However, you could use subtitles labs(subtitle = "text") to produce a similar visual of captions on the top.
To further control the aspect of both options use theme(plot.caption = element_text(...), plot.subtitle = element_text(...)). Type ?element_text in your console to get all the options for text formatting.
For example:
library(ggplot2)
df <- data.frame(x = rnorm(50), y = rnorm(50))
ggplot(df, aes(x, y)) +
geom_point() +
labs(subtitle = "Your text here", caption = "Your text here") +
theme(plot.caption = element_text(colour = "red", hjust = 0, angle = 15),
plot.subtitle = element_text(size = 18, face = "bold", hjust = 0.8))
If you want it below your current legend, you can always add a dummy legend and put your text as its name. An example:
ggplot(mtcars, aes(mpg, wt, color = gear,fill = "a")) +
geom_point() +
scale_fill_discrete(name = "Your custom caption\ngoes here", labels = "") +
theme(legend.key = element_rect(fill = "white")) +
guides(color = guide_legend(order = 1),
fill = guide_legend(order = 2, override.aes = list(linetype = 0, shape=NA))) # setting the order parameter in guide_legend will help place it below your existing legend(s)
I would like to change the colour of one of my ggrepel labels to black. I have tried to override the inheritance by specifying ...geom_text_repel(...colour='black') but that doesn't seem to work.
My attempt at a fix to the problem is in the second geom_text_repel function (below).
N.B. If there is a way to control the colour of individual geom_text_repel elements, rather than having to call the function twice, I would prefer that.
library("tidyverse")
library("ggthemes")
library("ggrepel")
df1 <- gather(economics, variable_name, observation, -date) %>%
rename(period = date) %>%
filter(variable_name == 'psavert')
df2 <- gather(economics, variable_name, observation, -date) %>%
rename(period = date) %>%
filter(variable_name == 'uempmed')
ggplot(df1, aes(x = period, y = observation, colour = variable_name)) +
geom_line() +
geom_line(data = df2, colour = 'black', size = .8) +
geom_text_repel(
data = subset(df1, period == max(as.Date(period, "%Y-%m-%d"))),
aes(label = variable_name),
size = 3,
nudge_x = 45,
segment.color = 'grey80'
) +
geom_text_repel(
data = subset(df2, period == max(as.Date(period, "%Y-%m-%d"))),
aes(label = variable_name, colour = 'black'), #How do I set the colour of the label text to black?
size = 3,
nudge_x = 45,
segment.color = 'grey80'
) +
scale_y_continuous(labels = scales::comma) +
theme_minimal(base_size = 16) +
scale_color_tableau() +
scale_fill_tableau() +
theme(legend.position = 'none') +
labs(x="", y="", title = "Economic Data") +
scale_x_date(limits = c(min(df1$period), max(df1$period) + 1200))
Do the same thing you did in your geom_line() layer. You want to set a color, not a mapping. Make colour = 'black' an argument to geom_text_repel(), not aes().
ggplot(df1, aes(x = period, y = observation, colour = variable_name)) +
geom_line() +
geom_line(data = df2, colour = 'black', size = .8) + # just like this layer
geom_text_repel(
data = subset(df1, period == max(as.Date(period, "%Y-%m-%d"))),
aes(label = variable_name),
size = 3,
nudge_x = 45,
segment.color = 'grey80'
) +
geom_text_repel(
data = subset(df2, period == max(as.Date(period, "%Y-%m-%d"))),
aes(label = variable_name) # don't assign it here,
size = 3,
nudge_x = 45,
segment.color = 'grey80',
colour = "black" # assign it here
) +
scale_y_continuous(labels = scales::comma) +
theme_minimal(base_size = 16) +
scale_color_tableau() +
scale_fill_tableau() +
theme(legend.position = 'none') +
labs(x="", y="", title = "Economic Data") +
scale_x_date(limits = c(min(df1$period), max(df1$period) + 1200))
Note that now the first line AND text are now both set manually to "black", so the automatic variable assignment will start over with next line (and text). If you want to set that manually to a different color, you can use the same strategy (set it as an argument to the geom, not as an argument to aes
I wanted to comment on the following doubt.
Using this code:
Plot<-data.frame(Age=c(0,0,0,0,0),Density=c(0,0,0,0,0),Sensitivity=c(0,0,0,0,0),inf=c(0,0,0,0,0),sup=c(0,0,0,0,0),tde=c(0,0,0,0,0))
Plot[1,]<-c(1,1,0.857,0.793,0.904,0.00209834)
Plot[2,]<-c(1,2,0.771 ,0.74,0.799,0.00348286)
Plot[3,]<-c(1,3,0.763 ,0.717,0.804,0.00577784)
Plot[4,]<-c(1,4,0.724 ,0.653,0.785,0.00504161)
Plot[5,]<-c(2,1,0.906,0.866,0.934,0.00365742)
Plot[6,]<-c(2,2,0.785 ,0.754,0.813,0.00440399)
Plot[7,]<-c(2,3,0.660,0.593,0.722,0.00542849)
Plot[8,]<-c(2,4,0.544,0.425,0.658,0.00433052)
names(Plot)<-c("Age","Mammographyc density","Sensitivity","inf","sup","tde")
Plot$Age<-c("50-59","50-59","50-59","50-59","60-69","60-69","60-69","60-69")
Plot$Density<-c("Almost entirely fat","Scattered fibroglandular density","Heterogeneously dense","Extremely dense","Almost entirely fat","Scattered fibroglandular density","Heterogeneously dense","Extremely dense")
levels(Plot$Age)<-c("50-59","60-69")
levels(Plot$Density)<-c("Almost entirely fat","Scattered fibroglandular density","Heterogeneously dense","Extremely dense")
pd <- position_dodge(0.2) #
Plot$Density <- reorder(Plot$Density, 1-Plot$Sensitivity)
ggplot(Plot, aes(x = Density, y = 100*Sensitivity, colour=Age)) +
geom_errorbar(aes(ymin = 100*inf, ymax = 100*sup), width = .1, position = pd) +
geom_line(position = pd, aes(group = Age), linetype = c("dashed")) +
geom_point(position = pd, size = 4)+
scale_y_continuous(expand = c(0, 0),name = 'Sensitivity (%)',sec.axis = sec_axis(~./5, name = 'Breast cancer detection rate (per 1000 mammograms)', breaks = c(0,5,10,15,20),
labels = c('0‰',"5‰", '10‰', '15‰', '20‰')), limits = c(0,100)) +
geom_line(position = pd, aes(x = Density, y = tde * 5000, colour = Age, group = Age), linetype = c("dashed"), data = Plot) +
geom_point(shape=18,aes(x = Density, y = tde * 5000, colour = Age, group = Age), position = pd, size = 4) +
theme_light() +
scale_color_manual(name="Age (years)",values = c("50-59"= "grey55", "60-69" = "grey15")) +
theme(legend.position="bottom") + guides(colour = guide_legend(), size = guide_legend(),
shape = guide_legend())
I have made the following graph,
in which the axis on the left is the scale of the circles and the axis on the right is the scale of the diamonds. The fact is that I would like to have a legend approximately like this:
But it is impossible for me, I have tried suggestions of other threads like scale_shape and different commands in guides but I have not got success. I just want to make clear the difference in what shape and color represent.
Would someone know how to help me?
Best regards,
What you should do is a panel plot to avoid the confusion of double axes:
library(dplyr)
library(tidyr)
Plot %>%
gather(measure, Result, Sensitivity, tde) %>%
ggplot(aes(x = Density, y = Result, colour=Age)) +
geom_errorbar(aes(ymin = inf, ymax = sup), width = .1, position = pd,
data = . %>% filter(measure == "Sensitivity")) +
geom_line(aes(group = Age), position = pd, linetype = "dashed") +
geom_point(position = pd, size = 4)+
# scale_y_continuous(expand = c(0, 0), limits = c(0, 1)) +
scale_y_continuous(labels = scales::percent) +
facet_wrap(~measure, ncol = 1, scales = "free_y") +
theme_light() +
scale_color_manual(name="Age (years)",values = c("50-59"= "grey55", "60-69" = "grey15")) +
theme(legend.position="bottom")
But to do what you asked, you problem is that you have only 1 non-positional aesthetic mapped so you cannot get more than one legend. To force a second legend, you need to add a second mapping. It can be a dummy mapping that has no effect, as below we map alpha but then manually scale both levels to 100%. This solution is not advisable because, as you have done in your example of a desired legend, it is easy to mix up the mappings and have your viz tell a lie by mislabeling which points are sensitivity and which are detection rate.
ggplot(Plot, aes(x = Density, y = 100*Sensitivity, colour=Age, alpha = Age)) +
geom_errorbar(aes(ymin = 100*inf, ymax = 100*sup), width = .1, position = pd) +
geom_line(position = pd, aes(group = Age), linetype = c("dashed")) +
geom_point(position = pd, size = 4)+
scale_y_continuous(expand = c(0, 0),name = 'Sensitivity (%)',sec.axis = sec_axis(~./5, name = 'Breast cancer detection rate (per 1000 mammograms)', breaks = c(0,5,10,15,20),
labels = c('0‰',"5‰", '10‰', '15‰', '20‰')), limits = c(0,100)) +
geom_line(position = pd, aes(x = Density, y = tde * 5000, colour = Age, group = Age), linetype = c("dashed"), data = Plot) +
geom_point(shape=18,aes(x = Density, y = tde * 5000, colour = Age, group = Age), position = pd, size = 4) +
theme_light() +
scale_color_manual(name="Age (years)",values = c("50-59"= "grey55", "60-69" = "grey15")) +
scale_alpha_manual(values = c(1, 1)) +
guides(alpha = guide_legend("Sensitivity"),
color = guide_legend("Detection Rate", override.aes = list(shape = 18))) +
theme(legend.position="bottom")