Related
Here is the graph that I have as a basis:
color_two_groups_type_2 <- c("dark red", "black")
pd <- position_dodge(0.4)
hedonic_price_indices %>% ggplot(aes(x=year, y=index, group=factor(sample_sizes), color=factor(sample_sizes))) +
geom_line(linetype = "dashed", position = pd) +
geom_point(size = 0.5, position = pd) +
geom_errorbar(aes(ymin = index_lower_ci, ymax = index_upper_ci), width = 0.15, size = 0.25, colour="black", position = pd) +scale_y_continuous(breaks = c(0.5,1.0,1.5,2.0,2.5), limits = c(0.125, 2.85)) +
theme(legend.position="bottom", legend.margin=margin(0,0,0,0), legend.box.margin=margin(-20,0,0,0)) +
scale_color_manual(labels = c("Alternative", "Normal"), values = color_two_groups_type_2, guide = guide_legend(reverse = TRUE)) +
labs(title = "", x = "", y = "Index value (2000 = 1)", color = "") +
scale_x_discrete(breaks = c(1985,1990,1995,2000,2005,2010,2015,2020))
Now I would like to have two different line types.
desired_linetype <- c("dotted", "solid")
color_two_groups_type_2 <- c("dark red", "black")
pd <- position_dodge(0.4)
hedonic_price_indices %>% ggplot(aes(x=year, y=index, group=factor(sample_sizes), color=factor(sample_sizes))) +
#geom_line(linetype = "dashed", position = pd) +
geom_line(aes(linetype = sample_sizes), position = pd) +
scale_linetype_manual(values = desired_linetype) +
geom_point(size = 0.5, position = pd) +
geom_errorbar(aes(ymin = index_lower_ci, ymax = index_upper_ci), width = 0.15, size = 0.25, colour="black", position = pd) +
scale_y_continuous(breaks = c(0.5,1.0,1.5,2.0,2.5), limits = c(0.125, 2.85)) + theme(legend.position="bottom", legend.margin=margin(0,0,0,0), legend.box.margin=margin(-20,0,0,0)) +
scale_color_manual(labels = c("Alternative", "Normal"), values = color_two_groups_type_2, guide = guide_legend(reverse = TRUE)) +
labs(title = "", x = "", y = "Index value (2000 = 1)", color = "") +
scale_x_discrete(breaks = c(1985,1990,1995,2000,2005,2010,2015,2020))
Unfortunately, I have got two legends by now. By adding + guides(col = "none") (e.g. at the bottom), the left part of the legend gets removed:
And alternatively, by changing scale_linetype_manual(values = desired_linetype) to scale_linetype_manual(values = desired_linetype, guide="none"), the right part of the legend is gets removed:
However, I would like to have mixed version of these two legends. I.e. a legend that shows both the line type and the color. How could I obtain this result? (and I would prefer not to have a legend title ("sample sizes"), as in my initial graph).
I would be thankful for any suggestion!
Here is some code to reproduce the graphs:
hedonic_price_indices <- structure(list(estimate = c(-0.575412358998748, -0.52549627191954, -0.48635414326085, -0.732792998304216, -0.562889873546058, -0.913572700671539, -1.13936126077503, -1.08231133221031, -1.3515171997382, -0.94983790292841 ), lower_ci = c(-0.626714841953077, -0.584959417015897, -0.542829387483941, -0.790953736050918, -0.620938372048851, -1.02481824744291, -1.26017870739697, -1.17246349249945, -1.41331442736626, -1.01254016013769), upper_ci = c(-0.524109876044418, -0.466033126823183, -0.429878899037759, -0.674632260557514, -0.504841375043265, -0.802327153900171, -1.01854381415308, -0.992159171921177, -1.28971997211013, -0.887135645719133), year = c("1984", "1985", "1986", "1987", "1988", "1984", "1985", "1986", "1987", "1988"), estimate_exp = c(-0.437527119774759, -0.408738135115574, -0.38513598119696, -0.519435103003286, -0.430439275221177, -0.598911308640654, -0.679976631974547, -0.661188486027214, -0.741152760388594, -0.613196281876959), lower_ci_exp = c(-0.465655673667104, -0.442871528710716, -0.41889823785973, -0.546587846514592, -0.462560117662101, -0.641138316492387, -0.71639666004378, -0.69039670436256, -0.756664572496545, -0.636705020910341 ), upper_ci_exp = c(-0.407917843611993, -0.372513502931199, -0.349412123229172, -0.490656308062782, -0.3963986859341, -0.551715477774212, -0.63887958407625, -0.629224741409214, -0.724652122619944, -0.588166297456909), index = c(0.562472880225241, 0.591261864884426, 0.61486401880304, 0.480564896996714, 0.569560724778823, 0.401088691359346, 0.320023368025453, 0.338811513972786, 0.258847239611406, 0.386803718123041), index_lower_ci = c(0.534344326332896, 0.557128471289284, 0.58110176214027, 0.453412153485408, 0.537439882337899, 0.358861683507613, 0.28360333995622, 0.30960329563744, 0.243335427503455, 0.363294979089659), index_upper_ci = c(0.592082156388007, 0.627486497068801, 0.650587876770828, 0.509343691937218, 0.6036013140659, 0.448284522225788, 0.36112041592375, 0.370775258590786, 0.275347877380056, 0.411833702543091), sample_sizes = c("Normal", "Normal", "Normal", "Normal", "Normal", "Alternative", "Alternative", "Alternative", "Alternative", "Alternative")), row.names = c("normal_sale_1984", "normal_sale_1985", "normal_sale_1986", "normal_sale_1987", "normal_sale_1988", "foreclosure_1984", "foreclosure_1985", "foreclosure_1986", "foreclosure_1987", "foreclosure_1988"), class = "data.frame")
To merge your legends use the same labels and guide in both scale_color and scale_linetype and the same name in labs:
library(ggplot2)
library(dplyr)
desired_linetype <- c("dotted", "solid")
color_two_groups_type_2 <- c("dark red", "black")
pd <- position_dodge(0.4)
hedonic_price_indices %>%
ggplot(aes(x = year, y = index, group = factor(sample_sizes), color = factor(sample_sizes))) +
geom_line(aes(linetype = sample_sizes), position = pd) +
geom_point(size = 0.5, position = pd) +
geom_errorbar(aes(ymin = index_lower_ci, ymax = index_upper_ci),
width = 0.15, size = 0.25, colour = "black", position = pd
) +
scale_x_discrete(breaks = c(1985, 1990, 1995, 2000, 2005, 2010, 2015, 2020)) +
scale_y_continuous(breaks = c(0.5, 1.0, 1.5, 2.0, 2.5), limits = c(0.125, 2.85)) +
scale_color_manual(
labels = c("Alternative", "Normal"),
values = color_two_groups_type_2,
guide = guide_legend(reverse = TRUE)
) +
scale_linetype_manual(
labels = c("Alternative", "Normal"),
values = desired_linetype,
guide = guide_legend(reverse = TRUE)
) +
labs(
title = "", x = "", y = "Index value (2000 = 1)",
color = "", linetype = ""
) +
theme(
legend.position = "bottom",
legend.margin = margin(0, 0, 0, 0),
legend.box.margin = margin(-20, 0, 0, 0)
)
I have this data frame :
Raw.Score = c(0,1,2,3,4,5,6,7,8)
Severity = c(-3.56553994,-2.70296933,-1.63969850,-0.81321707,-0.04629182,
0.73721320,1.61278518,2.76647043,3.94804472)
x = data.frame(Raw.Score = Raw.Score, Severity = Severity)
Raw.score are raw numbers from 0 to 8 (let's consider them as the labels of the severity numbers)
Severity are relative numbres that represent the locations of the scores in the diagram
I want to graphically present the results as in the following example using ggplot (the example includes different numbers but I want something similar)
As a fun exercise in ggplot-ing here is one approach to achieve or come close to your desired result.
Raw.Score = c(0,1,2,3,4,5,6,7,8)
Severity = c(-3.56553994,-2.70296933,-1.63969850,-0.81321707,-0.04629182,
0.73721320,1.61278518,2.76647043,3.94804472)
dat <- data.frame(Raw.Score, Severity)
library(ggplot2)
dat_tile <- data.frame(
Severity = seq(-4.1, 4.1, .05)
)
dat_axis <- data.frame(
Severity = seq(-4, 4, 2)
)
tile_height = .15
ymax <- .5
ggplot(dat, aes(y = 0, x = Severity, fill = Severity)) +
# Axis line
geom_hline(yintercept = -tile_height / 2) +
# Colorbar
geom_tile(data = dat_tile, aes(color = Severity), height = tile_height) +
# Sgements connecting top and bottom labels
geom_segment(aes(xend = Severity, yend = -ymax, y = ymax), color = "orange") +
# Axis ticks aka dots
geom_point(data = dat_axis,
y = -tile_height / 2, shape = 21, stroke = 1, fill = "white") +
# ... and labels
geom_text(data = dat_axis, aes(label = Severity),
y = -tile_height / 2 - .1, vjust = 1, fontface = "bold") +
# Bottom labels
geom_label(aes(y = -ymax, label = scales::number(Severity, accuracy = .01))) +
# Top labels
geom_point(aes(y = ymax, color = Severity), size = 8) +
geom_text(aes(y = ymax, label = Raw.Score), fontface = "bold") +
# Colorbar annotations
annotate(geom = "text", fontface = "bold", label = "MILD", color = "black", x = -3.75, y = 0) +
annotate(geom = "text", fontface = "bold", label = "SEVERE", color = "white", x = 3.75, y = 0) +
# Fixing the scales
scale_x_continuous(expand = c(0, 0)) +
scale_y_continuous(limits = c(-ymax, ymax)) +
# Color gradient
scale_fill_gradient(low = "orange", high = "red", guide = "none") +
scale_color_gradient(low = "orange", high = "red", guide = "none") +
# Get rid of all non-data ink
theme_void() +
# Add some plot margin
theme(plot.margin = rep(unit(10, "pt"), 4)) +
coord_cartesian(clip = "off")
My legend is not showing correctly when I am doing my graph in R using ggplot2. One column of my dataset is represented by a geom_bar and the two others are represented by geom_points (one shape each). The circle and the diamond shape are showing for both 2000 and 2008, the circle being in the diamong for both year. However, the graph works totally fine...
Here is a screenshot:
I have created a simplified version of my dataset:
order_var <- c(1, 4, 3, 5, 6, 2)
alt_name <- c('Agriculture', 'Mining', 'Food products',' Manufacture', 'Chemicals', 'Machinery')
y2000 <- c(20, 40, 50, 80, 30, 70)
y2008 <- c(40, 50, 80, 70, 30, 60)
y2018 <- c(10, 30, 80, 50, 40, 50)
datatest <- data.frame("order_var" = order_var, "alt_name" = alt_name, "y2000" = y2000, "y2008" = y2008, "y2018" = y2018)
And the code for my graph:
datatest %>% ggplot(aes(x = reorder(alt_name, order_var))) +
geom_bar(stat = "identity", aes(y = `y2018`, fill = "2018"), width = 0.7, col = "black") +
geom_point(aes(y = `y2008`, col = "2008"), shape = 23, fill = "white", size = 5) +
geom_point(aes(y = `y2000`, col = "2000"), shape = 19, fill = "black", size = 3) +
xlab("Industry") +
ylab("Percentage") +
theme(legend.position = "top") +
scale_fill_manual(name = '', values = c("2018" = "#4F81BD"), breaks = c("2018")) +
scale_colour_manual(name = '', values = c("2008" = "black", "2000" = "orange"))
If you know how to correct this problem, I would be very grateful!!
Thank you :)
That's a very tricky plot you are trying to make because you are in essence mapping the same aesthetics to different geoms.
The first thing you should do is to reshape your data to the long format. I also divided your dataset between 2018 (the bar), and 2000, 2008 (the points).
df2 <- datatest %>%
pivot_longer(cols = -c(order_var, alt_name)) %>%
mutate(bar = if_else(name == "y2018", 1, 0))
data_bar <- df2 %>% filter(bar == 1)
data_point <- df2 %>% filter(bar != 1)
I also find it useful to add a dodge to your points to avoid overlapping one inside the other as in the case of chemicals with position = position_dodge(width = 0.6).
The first solution gives what you want, but it is a bit of a hack, and I wouldn't recommend doing it as a general strategy. You basically add an aesthetics that you are not going to use to the bars (in this case, linetype), and then override it, as suggested in this answer.
ggplot(data_bar, aes(x = reorder(alt_name, order_var))) +
geom_bar(aes(y = value, linetype = name), fill = "#4F81BD", stat = 'identity', color = 'black') +
geom_point(data = data_point, position=position_dodge(width=0.6), aes(y = value, color = name, shape = name, size = name, fill = name)) +
scale_colour_manual(values = c("orange", "black"), labels = c("2000", "2008")) +
scale_fill_manual(values = c("orange", "white"), labels = c("2000", "2008")) +
scale_shape_manual(values = c(19, 23), labels = c("2000", "2008")) +
scale_size_manual(values = c(3, 5), labels = c("2000", "2008")) +
scale_linetype_manual(values = 1, guide = guide_legend(override.aes = list(fill = c("#4F81BD"))), labels = c("2018")) +
theme(legend.position = "top", legend.title = element_blank()) +
labs(x = "Industry", y = "Percentage")
Another solution, more general, is to avoid using the fill aesthetics for the geom_point and changing the shape to a solid one instead:
ggplot(data_bar, aes(x = reorder(alt_name, order_var))) +
geom_bar(aes(y = value, fill = name), stat = 'identity', color = "black") +
geom_point(data = data_point, position=position_dodge(width=0.6), aes(y = value, color = name, shape = name, size = name)) +
scale_fill_manual(values = c("#4F81BD"), labels = c("2018")) +
scale_colour_manual(values = c("orange", "white"), labels = c("2000", "2008")) +
scale_shape_manual(values = c(19, 18), labels = c("2000", "2008")) +
scale_size_manual(values = c(4, 6), labels = c("2000", "2008")) +
theme(legend.position = "top", legend.title = element_blank()) +
labs(x = "Industry", y = "Percentage")
I am creating a stacked bar chart below using ggplot and I convert it to interactive using ggplotly(). As you can see in the screenshot below the pop up text when I hover over a bar shows as "Name" the correct "Name" of the relative bar-in that case- DCH. I tried to replace that with a name of my choice but then the whole chart breaks down. So basically I would like to know if I can use "Name" in the background in order to display the chart but display another Name instead. The same for all of the 5 bars.
The code chunk which is related with this is:
geom_col(mapping = aes(x = Name, y = count, fill = Class), width = rep(0.9,5),
color = "black", position = position_fill(reverse = T)) +
geom_text(size = 4, position = position_fill(reverse = T, vjust = 0.50), color = "black",
mapping = aes(x = Name, y = count, group = Class, label = round(count))) +
#DATA
Name<-c("DCH","DCH","DCH","DGI","DGI","DGI","LDP","LDP","LDP","RH","RH","RH","TC","TC","TC")
Class<-c("Class1","Class2","Overlap","Class1","Class2","Overlap","Class1","Class2","Overlap","Class1","Class2","Overlap","Class1","Class2","Overlap")
count<-c(2077,1642,460,1971,5708,566,2316,810,221,2124,3601,413,2160,1097,377)
FinalDF<-data.frame(Name, Class,count)
#PLOT
ggplotly(ggplot(data = FinalDF) +
geom_col(mapping = aes(x = Name, y = count, fill = Class), width = rep(0.9,5),
color = "black", position = position_fill(reverse = T)) +
geom_text(size = 4, position = position_fill(reverse = T, vjust = 0.50), color = "black",
mapping = aes(x = Name, y = count, group = Class, label = round(count))) +
annotate('text', size = 5, x = (5+1)/2, y = -0.1, label = c('A'), angle = 90) +
coord_flip() +
scale_fill_manual(values = c('lemonchiffon', 'palegreen3', 'deepskyblue2'),breaks=c("Class1", "Overlap", "Class2"), labels = c(paste("Unique to","DB"), "Overlap", "Unique to Comparison Dataset "),
guide = guide_legend(label.position = 'left', label.hjust = 0, label.vjust = 0.5)) )
The tooltip argument might be in the right direction.
library(sf)
library(plotly)
# Create the stacked bar plot using ggplot()
stackedBarPlot<- ggplot(data = FinalDF) +
geom_col(mapping = aes(x = Name, y = count, fill = Class), width = rep(0.9,5),
color = "black", position = position_fill(reverse = T)) +
geom_text(size = 4, position = position_fill(reverse = T, vjust = 0.50), color = "black",
mapping = aes(x = Name, y = count, group = Class, label = round(count))) +
annotate('text', size = 5, x = (5+1)/2, y = -0.1, label = c('A'), angle = 90) +
coord_flip() +
scale_fill_manual(values = c('lemonchiffon', 'palegreen3', 'deepskyblue2'),breaks=c("Class1", "Overlap", "Class2"), labels = c(paste("Unique to","DB"), "Overlap", "Unique to Comparison Dataset "),
guide = guide_legend(label.position = 'left', label.hjust = 0, label.vjust = 0.5))+
geom_sf(aes(fill=Class,text=paste(Name,"DB")))
stackedBarPlot%>%
ggplotly(tooltip = "text")
Using ggplot2, I'm trying to color a specific set of bars using 2 different colors, according to their categories. In the plot below, I have columns over a certain value filled in red, but due to my method it excludes their 'partner columns' (the cols on top of them) from the coloring, when I would like them to be filled with blue.
If I change the values in scale_fill_manual() then it doesn't do anything as the 'fill' expression will give priority to coloring the 'TRUE' and 'FALSE' categories.
How can I change my code so that the bars accompanying the filled red bars will be colored blue?
My current plot:
My code:
pop %>%
group_by(age_range, sex) %>%
summarize(population = sum(population)) %>%
mutate(prop = population / sum(population)) %>%
ggplot() +
geom_col(aes(x = age_range, y = prop, color = sex,
fill = (prop >= .504 & sex == 'female' & age_range != '75 - 79'),
width = .85),
position = 'dodge') +
scale_fill_manual(values = c('Grey60', 'Grey60', 'Blue', 'Red')) +
scale_color_manual(values = c('Red', 'Blue')) +
geom_text(aes(x = age_range, y = prop, fill = sex, label = percent(prop)),
position = position_dodge(width = .9),
vjust = .358, hjust = 1.1,size = 4, color = 'White') +
scale_y_continuous(limits = c(0, 1), expand = c(0,0)) +
geom_hline(yintercept = .504, color = 'Grey', alpha = .7) +
coord_flip()
Here's one way to go about it:
# define TRUE / FALSE condition, then assign the same condition
# to the male group within the same age range
pop <- pop %>%
mutate(condition = prop >= 0.504 & sex == "female" & age_range != '75 - 79') %>%
group_by(age_range) %>%
mutate(condition = any(condition))
# define colour / fill scale for gender
sex.scale <- c("female" = "red", "male" = "blue")
ggplot(pop,
aes(x = age_range, y = prop,
color = sex, group = sex,
label = scales::percent(prop))) +
# bars with colored outlines & grey fill
geom_col(position = "dodge", fill = "grey60") +
# bars with coloured fill; only visible if condition is TRUE
geom_col(aes(fill = sex, alpha = condition),
position = "dodge") +
scale_color_manual(values = sex.scale) +
scale_fill_manual(values = sex.scale, guide = F) +
scale_alpha_manual(values = c("TRUE" = 1, "FALSE" = 0)) +
geom_text(position = position_dodge(width = .9),
vjust = .358, hjust = 1.1,
size = 4,
color = 'White') +
scale_y_continuous(limits = c(0, 1), expand = c(0,0)) +
geom_hline(yintercept = .504, color = 'Grey', alpha = .7) +
coord_flip()
sample subset data:
pop <- data.frame(
age_range = rep(c("10-14", "15-19", "20-24", "25-29"), each = 2),
sex = rep(c("male", "female"), by = 4),
prop = c(0.51, 0.49, 0.518, 0.482, 0.495, 0.505, 0.446, 0.554)
)