Flip ggplot y-axis for bar graph? - r

I am trying to create a bar graph that plots rank, where lower values are better. I want larger bars to correspond to smaller values, so the "best" groups in the data receive more visual weight.
Reprex:
dat = data.frame("Group" = c(rep("Best",50),
rep("Middle",50),
rep("Worst",50)
),
"Rank" = c(rnorm(n = 50, mean = 1.5, sd = 0.5),
rnorm(n = 50, mean = 2.5, sd = 0.5),
rnorm(n = 50, mean = 3.5, sd = 0.5)
)
)
tibdat = as_tibble(dat) %>%
group_by(Group) %>%
summarise(Mean_Rank = mean(Rank,na.rm=T))
# creates simple rightside up bar graph
ggplot(data = tibdat, mapping = aes(Group, Mean_Rank, fill = Group)) +
geom_col() +
scale_y_continuous(breaks = c(1:4), limits = c(1,4), oob = scales::squish)
# my attempt below, simply reversing the breaks and limits
ggplot(data = tibdat, mapping = aes(Group, Mean_Rank, fill = Group)) +
geom_col() +
scale_y_continuous(breaks = c(4:1), limits = c(4,1), oob = scales::squish)
The graphing code at the end does succeed in flipping the axis, but the data disappears (the bars are not plotted).
Note that I do not want the graphs to originate from the top, which scale_y_reverse can achieve. I want the bars to originate from the bottom, at the y = 4 line (or below).
How is this achieved?
Edit: Added image below to show the original bar graph that works but is wrong.

I just transformed the labels. I don't know if that's what you searched.
ggplot(data = tibdat, mapping = aes(Group, Mean_Rank, fill = Group)) +
geom_col() +
scale_y_continuous(breaks = c(1:4), limits = c(1,4), oob = scales::squish, labels = function(x) 5 - x)
With another trick in the aes argument I think you can arrive to the wanted result. Maybe someone better than me knows a clean way to do it.
ggplot(data = tibdat, mapping = aes(Group, 5 - Mean_Rank, fill = Group)) +
geom_col() +
scale_y_continuous(breaks = c(1:4), limits = c(1,4), oob = scales::squish, labels = function(x) 5 - x)
And here is the result :

Related

R ggplot2 : geom_jitter and fill, problem to have the dots on the right boxplot

Here's my R code
ggplot(dat = Table, aes(x = Group, y = value, fill = Type)) +
geom_boxplot(alpha=0.08)+
geom_jitter()+
scale_fill_brewer(palette="Spectral")+
theme_minimal()
Like you can see the dots are in the middle of the boxplots. What can I add in geom_jitter to have each point in the righ boxplot and not in the middle like this ? I also tried geom_point, it gave the same result !
Thanks to the help now It works, but I wanted to add a line to connect the dots and I got this.. can someone tell how to really connect the dots with lines
I think if you group by interaction(Group, Type) and use position_jitterdodge() you should get what you're looking for.
ggplot(mtcars, aes(as.character(am), mpg, color = as.character(vs),
group = interaction(as.character(vs), as.character(am)))) +
geom_boxplot() +
geom_jitter(position = position_jitterdodge()) # same output with geom_point()
Edit - here's an example with manual jittering applied to data where the each subject appears once in each Group.
I looked for a built-in way to do this, and this answer comes close, but I couldn't get it to work in terms of using position_jitterdodge with position defined by the groups of Group/Type, but line grouping defined by id alone and not by Group/Type. Both aesthetics (position adjustment and series identification) rely on the same group parameter, but they each need a different value for it.
Table = data.frame(id = 1:4,
value = rnorm(8),
Group = rep(c("a","b"), each = 4),
Type = c("1", "2"))
library(dplyr)
Table %>%
mutate(x = as.numeric(as.factor(Group)) +
0.2 * scale(as.numeric(as.factor(Type))) +
rnorm(n(), sd = 0.06)) %>%
ggplot(aes(x = Group, y = value, fill = Type, group = interaction(Group, Type))) +
geom_boxplot(alpha=0.2)+
geom_point(aes(x = x)) +
geom_line(aes(x = x, group = id), alpha = 0.1) +
scale_fill_brewer(palette="Spectral")+
theme_minimal()
Best to use position_dodge instead if you want them to line up:
library(ggplot2)
Table <- tibble::tibble(
Group = rep(c("A", "B"), each = 20),
Type = factor(rep(c(1:2, 1:2), each = 10)),
value = rnorm(40, mean = 10)
)
ggplot(dat = Table, aes(x = Group, y = value, fill = Type)) +
geom_boxplot(alpha=0.08)+
geom_point(position = position_dodge(width = 0.75))+
scale_fill_brewer(palette="Spectral")+
theme_minimal()
To add a line, make sure group = ID goes in both the geom_point and geom_line calls:
library(ggplot2)
Table <- tibble::tibble(
Group = rep(c("A", "B"), each = 20),
Type = factor(rep(c(1:2, 1:2), each = 10)),
ID = factor(rep(1:20, times = 2)),
value = rnorm(40, mean = 10)
)
ggplot(dat = Table, aes(x = Group, y = value, fill = Type)) +
geom_boxplot(alpha = 0.08) +
geom_point(aes(group = ID), position = position_dodge(width = 0.75))+
geom_line(aes(group = ID), position = position_dodge(width = 0.75), colour = "grey")+
scale_fill_brewer(palette = "Spectral") +
theme_minimal()

ggplot facet grid y axis some values are not visible how adjust grid

ggplot2 i am trying plot the scatter plot but and merging with facet grid some values are looking incomplete near y axis points how to fix this anyone help me.
dummy <- data.frame(Value = c(rnorm(100, mean = 35, sd = 2),
rnorm(100, mean = 47, sd = 2),
rnorm(100, mean = 28, sd = 1)),
Method = c(rep("base", times = 100),
rep("new", times = 100),
rep("edge", times = 100)),
Subject = rep(paste0("M", seq_len(100)), times = 3))
library("ggplot2")
ggplot(dummy, aes(y=Value, x=Subject)) +
geom_point(aes(shape=Method),size = 2.5) +
facet_wrap(~ Method)
Although using the expand parameter would be the textbook answer, the sanest way to do this with the given data is to make Subject a numeric variable instead of a factor. If you don't do this, your x axis labels will be hopelessly overlapped, and your underlying panel grid will look weird.
Compare Subject as numeric:
ggplot(dummy, aes(y = Value, x = as.numeric(gsub("M", "", Subject)))) +
geom_point(aes(shape=Method),size = 2.5) +
facet_wrap(~ Method) +
labs(x = "Subject")
Versus as a character with expand:
ggplot(dummy, aes(y = Value, x = Subject)) +
geom_point(aes(shape = Method),size = 2.5) +
facet_wrap(~ Method) +
scale_x_discrete(expand = c(0.1, 0.1))
I think it's pretty clear that the numeric version is easier to read.
You can increase the margin of the X axis with ggplot2::scale_x_discrete(), just experiment with the "add = 5" until you have what you need
library("ggplot2")
ggplot2::ggplot(dummy, aes(y=Value, x=Subject)) +
ggplot2::geom_point(aes(shape=Method),size = 2.5) +
ggplot2::scale_x_discrete(expand = expand_scale(add = 5)) +
ggplot2::facet_grid(~ Method, scales = "free")

How to correct the position of labels on piechart in ggplot. Also tell me how produce 3D piechart

One of the value in my dataset is zero, I think because of that I am not able to adjust labels correctly in my pie chart.
#Providing you all a sample dataset
Averages <- data.frame(Parameters = c("Cars","Motorbike","Bicycle","Airplane","Ships"), Values = c(15.00,2.81,50.84,51.86,0.00))
mycols <- c("#0073C2FF", "#EFC000FF", "#868686FF", "#CD534CFF","#FF9999")
duty_cycle_pie <- Averages %>% ggplot(aes(x = "", y = Values, fill = Parameters)) +
geom_bar(width = 1, stat = "identity", color = "white") +
coord_polar("y", start = 0)+
geom_text(aes(y = cumsum(Values) - 0.7*Values,label = round(Values*100/sum(Values),2)), color = "white")+
scale_fill_manual(values = mycols)
Labels are not placed in the correct way. Please tell me how can get 3D piechart.
Welcome to stackoverflow. I am happy to help, however, I must note that piecharts are highly debatable and 3D piecharts are considered bad practice.
https://www.darkhorseanalytics.com/blog/salvaging-the-pie
https://en.wikipedia.org/wiki/Misleading_graph#3D_Pie_chart_slice_perspective
Additionally, if the names of your variables reflect your actual dataset (Averages), a piechart would not be appropriate as the pieces do not seem to be describing parts of a whole. Ex: avg value of Bicycle is 50.84 and avg value of Airplane is 51.86. Having these result in 43% and 42% is confusing; a barchart would be easier to follow.
Nonetheless, the answer to your question about placement can be solved with position_stack().
library(tidyverse)
Averages <-
data.frame(
Parameters = c("Cars","Motorbike","Bicycle","Airplane","Ships"),
Values = c(15.00,2.81,50.84,51.86,0.00)
) %>%
mutate(
# this will ensure the slices go biggest to smallest (a best practice)
Parameters = fct_reorder(Parameters, Values),
label = round(Values/sum(Values) * 100, 2)
)
mycols <- c("#0073C2FF", "#EFC000FF", "#868686FF", "#CD534CFF","#FF9999")
Averages %>%
ggplot(aes(x = "", y = Values, fill = Parameters)) +
geom_bar(width = 1, stat = "identity", color = "white") +
coord_polar("y", start = 0) +
geom_text(
aes(y = Values, label = label),
color = "black",
position = position_stack(vjust = 0.5)
) +
scale_fill_manual(values = mycols)
To move the pieces towards the outside of the pie, you can look into ggrepel
https://stackoverflow.com/a/44438500/4650934
For my earlier point, I might try something like this instead of a piechart:
ggplot(Averages, aes(Parameters, Values)) +
geom_col(aes(y = 100), fill = "grey70") +
geom_col(fill = "navyblue") +
coord_flip()

How to modify and add an extra legend in a ggplot2 figure

I have data that looks like this:
example.df <- as.data.frame(matrix( c("height","fruit",0.2,0.4,0.7,
"height","veggies",0.3,0.6,0.8,
"height","exercise",0.1,0.2,0.5,
"bmi","fruit",0.2,0.4,0.6,
"bmi","veggies",0.1,0.5,0.7,
"bmi","exercise",0.4,0.7,0.8,
"IQ","fruit",0.4,0.5,0.6,
"IQ","veggies",0.3,0.5,0.7,
"IQ","exercise",0.1,0.4,0.6),
nrow=9, ncol=5, byrow = TRUE))
colnames(example.df) <- c("phenotype","predictor","corr1","corr2","corr3")
So basically three different correlations between 3x3 variables. I want to visualize the increase in correlations as follows:
ggplot(example.df, aes(x=phenotype, y=corr1, yend=corr3, colour = predictor)) +
geom_linerange(aes(x = phenotype,
ymin = corr1, ymax = corr3,
colour = predictor),
position = position_dodge(width = 0.5))+
geom_point(size = 3,
aes(x = phenotype, y = corr1, colour = predictor),
position = position_dodge(width = 0.5), shape=4)+
geom_point(size = 3,
aes(x = phenotype, y = corr2, colour = predictor),
position = position_dodge(width = 0.5), shape=18)+
geom_point(size = 3,
aes(x = phenotype, y = corr3, colour = predictor),
position = position_dodge(width = 0.5))+
labs(x=NULL, y=NULL,
title="Stackoverflow Example Plot")+
scale_colour_manual(name="", values=c("#4682B4", "#698B69", "#FF6347"))+
theme_minimal()
This gives me the following plot:
Problems:
Tthere is something wrong with the way the geom_point shapes are dodged with BMI and IQ. They should be all with on the line with the same colour, like with height.
How do I get an extra legend that can show what the circle, cross, and square represent? (i.e., the three different correlations shown on the line: cross = correlation 1, square = correlation 2, circle = correlation 3).
The legend now shows a line, circle, cross through each other, while just a line for the predictors (exercise, fruit, veggies) would suffice..
Sorry for the multiple issues, but adding the extra legend (problem #2) is the most important one, and I would be already very satisfied if that could be solved, the rest is bonus! :)
See if the following works for you? The main idea is to convert the data frame from wide to long format for the geom_point layer, and map correlation as a shape aesthetic:
example.df %>%
ggplot(aes(x = phenotype, color = predictor, group = predictor)) +
geom_linerange(aes(ymin = corr1, ymax = corr3),
position = position_dodge(width = 0.5)) +
geom_point(data = . %>% tidyr::gather(corr, value, -phenotype, -predictor),
aes(y = value, shape = corr),
size = 3,
position = position_dodge(width = 0.5)) +
scale_color_manual(values = c("#4682B4", "#698B69", "#FF6347")) +
scale_shape_manual(values = c(4, 18, 16),
labels = paste("correlation", 1:3)) +
labs(x = NULL, y = NULL, color = "", shape = "") +
theme_minimal()
Note: The colour legend is based on both geom_linerange and geom_point, hence the legend keys include both a line and a point shape. While it's possible to get rid of the second one, it does take some more convoluted code, and I don't think the plot would be much improved as a result...

Manipulating Y axis limits does not work (ggplot2 percent bar plot)

Following the nice example here:
Create stacked barplot where each stack is scaled to sum to 100%
I generated a barplot for my data in which the results are presented as percent.
My data frame is:
small_df = data.frame(type = c('A','A','B','B'),
result = c('good','bad','good','bad'),
num_cases = c(21,72,87,2))
And my attempt to draw looks like so:
library(scales)
library(ggplot2)
ggplot(small_df,aes(x = type, y = num_cases, fill = result)) +
geom_bar(position = "fill",stat = "identity") +
scale_y_continuous(labels = percent, breaks = seq(0,1.1,by=0.1))
This all works fine and produces the a figure like so:
However, I want to make the limits of the y axis to be 0-110% (I will later want to add a label on top so I need the space). Changing the line to:
scale_y_continuous(labels = percent, breaks = seq(0,1.1,by=0.1), limits = c(0,1.1))
fails with the following error:
Error: missing value where TRUE/FALSE needed
Any idea how to solve this?
Many thanks!!!
You can change the out of bounds option via oob or use coord_cartesian to set the limits. See info here
ggplot(small_df, aes(x = type, y = num_cases, fill = result)) +
geom_bar(position = "fill", stat = "identity") +
scale_y_continuous(labels = percent, breaks = seq(0, 1.1, by=0.1),
oob = rescale_none, limits = c(0, 1.1))
ggplot(small_df, aes(x = type, y = num_cases, fill = result)) +
geom_bar(position = "fill", stat = "identity") +
scale_y_continuous(labels = percent, breaks = seq(0, 1.1, by=0.1)) +
coord_cartesian(ylim = c(0, 1.1))

Resources