How to ggplot partial values with only max in whisker plot? - r

I am thinking how to present partial values in whisker plot/...
M2 has only the max.
Both measurements do not hav
Code which output in Fig. 1
library("reshape2")
library("ggplot2")
ds <- structure(list(Vars = c("M1", "M2", "M1", "M2", "M1", "M2"),
variable = structure(c(1L, 1L, 2L, 2L, 3L, 3L), .Label = c("Max",
"Ave", "Min"), class = "factor"), value = c("150",
"61", " 60", NA, " 41", NA)), row.names = c(NA, -6L), .Names = c("Vars",
"variable", "value"), class = "data.frame")
# http://stackoverflow.com/q/44100187/54964 eipi10
ds$value = as.numeric(ds$value)
# http://stackoverflow.com/a/44090815/54964
minmax <- ds[ds$variable %in% c("Min","Max"), ]
absol <- ds[ds$variable %in% c("Ave"), ]
# absol <- ds[ds$variable %in% c("Ave", "Absolute"), ]
minm <- dcast(minmax, Vars ~ variable)
absol <- merge(absol, minm, by = "Vars", all.x = T)
absol
ggplot(absol, aes(x = Vars, y = value, fill = variable)) +
geom_bar(stat = "identity") +
geom_errorbar(aes(ymin = Min, ymax = Max), width = .25)
Values at start
Max Ave Min Vars
M1 150 60 41 M1
M2 61 <NA> <NA> M2
Fig. 1 Output where no visualisations when only max value exists
The presentation of M1 is also weird in the barplot becuase no absolute values in data, designed initially in absol.
Expected output: mark maximum value in M2 presentation
OS: Debian 8.7
R: 3.4 (backports)

Add a column to absol, call it yMin, that will set the min value to the max value if the min value is missing.
absol$yMin <- ifelse(is.na(absol$Min), absol$Max, absol$Min)
Then, when plotting, have the geom_errorbar use yMin in the aesthetics.
ggplot(absol, aes(x = Vars, y = value, fill = variable)) +
geom_bar(stat = "identity") +
geom_errorbar(aes(ymin = yMin, ymax = Max), width = .25)

Related

Adding line with specific df value to each bar in ggplot

My df is organized this way for example:
OCCURED_COUNTRY_DESC | a | b | c | d | flagged | type | MedDRA_PT| **E** |
__________________________________________________________________________
UNITED STATES |403|1243|473|4077| yes | disp | Seizure |144.208|
__________________________________________________________________________
My data:
structure(list(OCCURED_COUNTRY_DESC = c("AUSTRALIA", "AUSTRIA",
"BELGIUM", "BRAZIL", "CANADA"), a = c(4L, 7L, 20L, 5L, 11L),
b = c(31, 27, 100, 51, 125), c = c(872, 869, 856, 871, 865
), d = c(5289, 5293, 5220, 5269, 5195), w = c(876, 876, 876,
876, 876), x = c(5320, 5320, 5320, 5320, 5320), y = c(35L,
34L, 120L, 56L, 136L), z = c(6161, 6162, 6076, 6140, 6060
), N = c(6196, 6196, 6196, 6196, 6196), k = c("0.5", "0.5",
"0.5", "0.5", "0.5"), SOR = c(0.80199821407511, 1.52042360060514,
1.21312776329214, 0.615857869962066, 0.539569644832803),
log = c(-0.318329070860348, 0.604473324558599, 0.278731499148795,
-0.699330656240263, -0.890118907611227), LL99 = c(-0.695969674426877,
0.382102954188229, 0.198127619344382, -1.00534117464748,
-1.03425468471322), UL99 = c(-0.0544058884186467, 0.763880731966007,
0.337239065783058, -0.482651467660248, -0.785935460582379
), flagged = c("no", "no", "no", "no", "yes"), type = c(NA,
NA, NA, NA, "under"), MedDRA_PT = c("Seizure", "Seizure",
"Seizure", "Seizure", "Seizure"), E = c(5.11098506333901,
4.43283582089552, 16.3984674329502, 8.43063199848168, 20.8132820019249
)), row.names = c(NA, -5L), class = c("tbl_df", "tbl", "data.frame"
))
I am using ggplot2 to create a bar chart using the following piece of code:
test2 %>% #using test2 as the df
ggplot(aes(a, OCCURED_COUNTRY_DESC, fill=type)) +
geom_bar(stat="identity")+
scale_fill_manual(values = c("disp" = "#FF8C00",
"under" = "#7EC0EE",
"NA"="#EEE9E9"))+
theme_classic()+
labs(title = "Seizure",
x = "Count",
y = "")
What I would like to do is to add a black line in each bar correspondent to the E value, from the dataframe, for that country. However I haven't been successful. Can someone kindly guide me on how to achieve this?
Thanks!
One option to achieve your desired result would be via a geom_segment, where you map your E column on both the x and the xend position. "Tricky" part are the y positions. However, as a categorical axis is still a numeric axis we could add a helper column to your data which contains the numeric positions of your categorical OCCURED_COUNTRY_DESC column. This helper column could then be mapped on the y and the yend aes needed by geom_segment where we also take into account the width of the bars:
library(ggplot2)
test2$OCCURED_COUNTRY_DESC_num <- as.numeric(factor(test2$OCCURED_COUNTRY_DESC))
width <- .9 # defautlt width of bars
ggplot(test2, aes(a, OCCURED_COUNTRY_DESC, fill = type)) +
geom_bar(stat = "identity") +
geom_segment(aes(x = E, xend = E,
y = OCCURED_COUNTRY_DESC_num - width / 2,
yend = OCCURED_COUNTRY_DESC_num + width / 2),
color = "black", size = 1) +
scale_fill_manual(values = c(
"disp" = "#FF8C00",
"under" = "#7EC0EE",
"NA" = "#EEE9E9"
)) +
theme_classic() +
labs(
title = "Seizure",
x = "Count",
y = ""
)

Add character variable (weekdays) to plot

I want to add on this plot the weekday as text on top of the bars.
The only function to add text in ggplot I found, is "annotate", which does not work the way I want.
It should look like this:
Plot with weekdays
geom_text gives me this
Geom_text
My code:
ggplot(data = filter(T2G2_dayav, site %in% c("S17S", "S17N"), !is.na(distance)),
mapping = aes(as.factor(x = date_days))) +
geom_col(mapping = aes(y = T2pn_av, fill = as.factor(distance)),
position = position_dodge(width = 0.9)) +
theme_bw() + ylab("Particle Number (#/cm³), day-av") + xlab("Date") +
scale_y_continuous(limits = c(0, 30000)) +
scale_fill_discrete(name = "T2, Distance from road (m)") +
scale_color_grey(name = "Reference intrument G2") +
ggtitle("Day-averaged Particle Number (PN) per distance")
the head of my data:
distance date_days site T2pn_av T2pn_avambient T2wdir_med weekday Date G2pn_av G2pn_min G2pn_max G2ws_av G2ws_min G2ws_max G2wdir_med
<int> <dttm> <chr> <dbl> <dbl> <dbl> <chr> <dttm> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 -10 2017-07-18 S17N 28814.83 16917.831 110 Di 2017-07-18 13655.29 4621 105100 0.6781284 0 3.6 51.0
2 -10 2017-07-19 S17N 24210.95 15565.951 100 Mi 2017-07-19 10627.73 2908 67250 1.3673618 0 5.5 70.0
3 -10 2017-07-24 S17N 16143.44 7907.442 80 Mo 2017-07-24 11686.54 3582 55080 0.8178753 0 4.8 95.5
4 -10 2017-07-29 S17N 11762.56 5574.563 270 Sa 2017-07-29 12180.73 5413 45490 1.0304985 0 5.7 265.0
5 -10 2017-07-30 S17N 12138.22 6360.225 290 So 2017-07-30 10404.75 6113 23860 1.2385791 0 6.6 274.0
6 -10 2017-07-31 S17N 13815.32 9008.320 270 Mo 2017-07-31 11849.89 4595 46270 0.8554044 0 4.4 230.0
dput(head(T2G2_dayav))
structure(list(distance = c(-10L, -10L, -10L, -10L, -10L, -10L
), date_days = structure(c(1500328800, 1500415200, 1500847200,
1501279200, 1501365600, 1501452000), class = c("POSIXct", "POSIXt"
), tzone = "Europe/Berlin"), site = c("S17N", "S17N", "S17N",
"S17N", "S17N", "S17N"), T2pn_av = c(28814.8306772908, 24210.9512670565,
16143.442364532, 11762.5630630631, 12138.2247114732, 13815.3198380567
), T2pn_avambient = c(16917.8306772908, 15565.9512670565, 7907.44236453202,
5574.56306306306, 6360.22471147318, 9008.31983805668), T2wdir_med = c(110,
100, 80, 270, 290, 270), weekday = c("Di", "Mi", "Mo", "Sa",
"So", "Mo"), Date = structure(c(1500328800, 1500415200, 1500847200,
1501279200, 1501365600, 1501452000), class = c("POSIXct", "POSIXt"
), tzone = "Europe/Berlin"), G2pn_av = c(13655.2885517401, 10627.7329973352,
11686.5429216867, 12180.7308516181, 10404.7472642001, 11849.8893070109
), G2pn_min = c(4621, 2908, 3582, 5413, 6113, 4595), G2pn_max = c(105100,
67250, 55080, 45490, 23860, 46270), G2ws_av = c(0.678128438241936,
1.36736183524505, 0.817875347544022, 1.0304984658137, 1.23857912107,
0.855404388351763), G2ws_min = c(0, 0, 0, 0, 0, 0), G2ws_max = c(3.6,
5.5, 4.8, 5.7, 6.6, 4.4), G2wdir_med = c(51, 70, 95.5, 265, 274,
230)), .Names = c("distance", "date_days", "site", "T2pn_av",
"T2pn_avambient", "T2wdir_med", "weekday", "Date", "G2pn_av",
"G2pn_min", "G2pn_max", "G2ws_av", "G2ws_min", "G2ws_max", "G2wdir_med"
), row.names = c(NA, -6L), class = c("grouped_df", "tbl_df",
"tbl", "data.frame"), vars = c("distance", "date_days"), drop = TRUE, indices = list(
0L, 1L, 2L, 3L, 4L, 5L), group_sizes = c(1L, 1L, 1L, 1L,
1L, 1L), biggest_group_size = 1L, labels = structure(list(distance = c(-10L,
-10L, -10L, -10L, -10L, -10L), date_days = structure(c(1500328800,
1500415200, 1500847200, 1501279200, 1501365600, 1501452000), class = c("POSIXct",
"POSIXt"), tzone = "Europe/Berlin")), row.names = c(NA, -6L), class = "data.frame", vars = c("distance",
"date_days"), drop = TRUE, .Names = c("distance", "date_days"
)))
The idea is that you add a text on top of every bar (that's why vjust = 0, but you could also do vjust = -.5 to allow more space or vjust = 1.5 to put it in the bars, which is nice as well). The rest within the geom_text ist basically the same as in geom_col. But in general, you could put commonly used aesthetics in the first occurency within ggplot(aes(...)), as you already did with the x-value.
ggplot(data = filter(T2G2_dayav, site %in% c("S17S", "S17N"), !is.na(distance)),
mapping = aes(as.factor(x = date_days))) +
geom_col(mapping = aes(y = T2pn_av, fill = as.factor(distance)),
position = position_dodge(width = 0.9)) +
geom_text(aes(label = weekday, y = T2pn_av), vjust = -.5, # add these
position = position_dodge(width = 0.9)) + # lines
theme_bw() + ylab("Particle Number (#/cm³), day-av") + xlab("Date") +
scale_y_continuous(limits = c(0, 30000)) +
scale_fill_discrete(name = "T2, Distance from road (m)") +
scale_color_grey(name = "Reference intrument G2") +
ggtitle("Day-averaged Particle Number (PN) per distance")
The following should solve your problem with too many labels. It takes the highest label and places it in the center of the bars of that x-value. Find a plot below with additional rows added to your data:
T2G2_dayav <- rbind(T2G2_dayav %>% ungroup(), T2G2_dayav %>% ungroup() %>% mutate(distance = 5)) # add more observations for testing
T2G2_dayav <- T2G2_dayav %>% mutate(T2pn_av = ifelse(distance == 5, T2pn_av/2, T2pn_av)) # label only the highest bar
The following should work with your data:
ggplot(data = filter(T2G2_dayav, site %in% c("S17S", "S17N"), !is.na(distance)) %>%
group_by(date_days) %>% # group by days
mutate(weekday2 = ifelse(T2pn_av == max(T2pn_av), weekday, NA)), # within each day (group), only label the highest
mapping = aes(as.factor(x = date_days))) +
geom_col(mapping = aes(y = T2pn_av, fill = as.factor(distance)),
position = position_dodge(width = 0.9)) +
geom_text(aes(label = weekday2, y = T2pn_av), vjust = -.5, # add these
position = position_dodge(with = 0.9)) + # lines
theme_bw() + ylab("Particle Number (#/cm³), day-av") + xlab("Date") +
scale_y_continuous(limits = c(0, 30000)) +
scale_fill_discrete(name = "T2, Distance from road (m)") +
scale_color_grey(name = "Reference intrument G2") +
ggtitle("Day-averaged Particle Number (PN) per distance")

Create new column with percentages in data frame

I have the following dataframe:
dput(df1)
structure(list(month = c(1, 1, 2, 2, 3, 4), transaction_type = c("AAA",
"BBB", "BBB", "CCC",
"DDD", "AAA"), max_wt_per_month = c(54.9,
51.6833333333333, 52.3333333333333, 49.4666666666667, 49.85,
48.5833333333333), min_wt_per_month = c(0, 0, 0, 0, 0, 0), avg_wt_per_month = c(8.41701333107861,
7.65211141060198, 6.44184012508551, 7.74798927613941, 7.4360566888844,
7.50611319574734), prop = c(Inf, Inf, Inf, Inf, Inf, Inf)), .Names = c("month",
"transaction_type", "max_wt_per_month", "min_wt_per_month", "avg_wt_per_month",
"prop"), row.names = c(NA, -6L), class = c("grouped_df", "tbl_df",
"tbl", "data.frame"), vars = list(month), drop = TRUE, indices = list(
0:5), group_sizes = 6L, biggest_group_size = 6L, labels = structure(list(
month = 1), row.names = c(NA, -1L), class = "data.frame", vars = list(
month), drop = TRUE, .Names = "month"))
I want to create column prop that would contain the percentage of maximum waiting time with respect to each month. If I run this code, then I get Inf values in most of the rows... (especially it is evident in the real dataset):
my_fun=function(vec){
100*as.numeric(vec[3]) /
sum(with(data_merged_transactions, ifelse(month == vec[1], max_wt_per_month, 0))) }
data_merged_transactions$prop=apply(data_merged_transactions , 1 , my_fun)
I then finally need to create the filled area chart so that each area would be a percentage out of 100%:
ggplot(data_merged_transactions, aes(x=month, y=prop, fill=transaction_type)) +
geom_area(alpha=0.6 , size=1, colour="black")
Why do I get Inf if the sum is not equal to 0?
Moreover, is it possible to create filled area chart with months being factors (Jan, Feb,etc.), not numbers? I tried to substitute month id's by month names, but then I got very thin bars instead of a filled area.
Is this what you were looking for?
library(tidyverse)
df1_tidy <- df1 %>%
group_by(month) %>%
summarise(SUM = sum(max_wt_per_month)) %>%
full_join(df1) %>%
mutate(prop = max_wt_per_month / SUM)
ggplot(data = df1_tidy,
aes(x = month,
y = prop,
fill = transaction_type)) +
geom_area(alpha = 0.6,
size = 1,
colour = "black") +
scale_x_continuous(labels = c("Jan", "Feb", "Mar", "Apr"))

Single error bar for stacked graph equalling 100

I have a stacked bar graph that shows the differences in classes between skeleton and tissue. The total of the two will always be 100 and their standard errors are the same. As such, the top error bar is superfluous and adds confusion.
Is there a way to only have the standard error for the bottom group? This link shows how to get a single bar for the top of the stack but isn't quite what I need: Single error bar on stacked bar plot ggplot Thanks.
Code:
library(reshape2)
library(Rmisc)
library(ggplot2)
melt <- melt(file, id=c("TREATMENT", "Species"),
value.name="Amount", variable.name = "Class")
x1 <- summarySE(melt, measurevar = "Amount",
groupvars = c("Species", "TREATMENT", "Class"), na.rm=TRUE)
x2 <- within(x1,lit2 <- ave(Amount, Class, Species, FUN = cumsum))
p10 <- ggplot(x2, aes(y = Amount, x = Class, fill = TREATMENT)) +
geom_bar(stat = "identity", colour = "black") +
geom_errorbar(aes(ymin = lit2-se, ymax = lit2+se), size = .5, width = .25)
p10
Data:
structure(list(TREATMENT = c("SKELETON", "SKELETON", "SKELETON",
"SKELETON", "TISSUE", "TISSUE", "TISSUE", "TISSUE"), Species = c("A",
"A", "A", "A", "A", "A", "A", "A"), `1` = c(42.1958615095789,
73.6083881998577, 62.1025409404354, 21.5264243794993, 57.8041384904211,
26.3916118001423, 37.8974590595646, 78.4735756205007), `2` = c(46.9398719372755,
89.6865089817669, 55.9907366318623, 18.1145895471236, 53.0601280627245,
10.3134910182331, 44.0092633681377, 81.8854104528764), `3` = c(55.4637732254405,
75.0933095632366, 20, 18.402199079204, 44.5362267745594, 24.9066904367634,
80, 81.597800920796)), class = c("tbl_df", "tbl", "data.frame"
), row.names = c(NA, -8L), .Names = c("TREATMENT", "Species",
"1", "2", "3"))

Line plot with factor variables in R

How can I make R draw lines between two observations according with factor variables?
I have two 'time' points, early and late, coded as categorical
plotdata <- structure(list(
x = structure(1:2, .Label = c("early", "late"), class = "factor"),
y = 1:2
),
.Names = c("x", "y"), row.names = c(NA, -2L), class = "data.frame"
)
I only get kind of a bar plot:
plot(plotdata)
I also tried coding the variables as 0 and 1, but then I get a continuous axis with.
Let's say your data is
d <- structure(list(x = structure(1:2, .Label = c("early", "late"), class = "factor"),
y = 1:2), .Names = c("x", "y"), row.names = c(NA, -2L), class = "data.frame")
d
# x y
# early 1
# late 2
With base R
plot(as.numeric(d$x), d$y, type = "l", xaxt = "n")
axis(1, labels = as.character(d$x), at = as.numeric(d$x))
With ggplot2
library(ggplot2)
ggplot(d, aes(x = x, y = y)) + geom_line(aes(group = 1))

Resources