There is my data frame
Days,Observed,Simulated
0,0,424.8933328
1,1070,1116.781453
2,2360,2278.166227
3,3882,3854.781359
4,5712,5682.090936
5,7508,7565.230044
6,9126,9343.991798
7,10600,10919.17995
8,11893,12249.07067
9,13047,13332.93044
10,14022,14193.53941
11,14852,14863.84784
12,15480,15378.56415
13,16042,15769.6773
14,16362,16064.57556
15,16582,16285.66038
16,16766,16450.70955
17,16854,16573.54275
18,16854,16664.74816
And this is my code, hope I didn't miss out some information
dt <- read.csv('data.csv')
days <- dt$Days
Observed <- dt$Observed
Simulated <- dt$Simulated
require(ggplot2)
R <- ggplot(dt, aes(x = days))+geom_line(y=Simulated, color="red", size=0.5)+
geom_point(y=Observed, color="midnightblue", size=1.75)
a <- geom_line(aes(y = Simulated, col='Simulated'))
n <- geom_point(aes(y = Observed, fill = "Observed"), col='blue')
c <- ggtitle("2.5kg of Placenta & 0.5kg of seed")
h <- labs(x = 'Time(Days)', y = "Cumulative Biogas Yield(ml)",
colour = NULL, fill = "Legend")
o <- theme(plot.title = element_text(hjust = 0.1))+
theme( plot.title = element_text(colour = "midnightblue"),
axis.title.x = element_text(colour = "black", size = 14),
axis.title.y = element_text(colour = "black", size = 14),
legend.title = element_text(colour = "black", size = 14),
legend.text = element_text(colour = "black", size = 12.5),
axis.text.x = element_text(colour = "black", size = 14),
axis.text.y = element_text(colour = "black", size = 14))
d <- scale_color_manual(values = 'red')
s <- scale_fill_manual(values = 'midnightblue')
Myplot <- R+a+n+c+h+o+d+s
Myplot
The result I get have a big gap between the variables and needs to be removed
What I want is as follows:
I have edited the graph on the painter to get what i want but its tiresome work I would like to have the code that can easy the process for me. Thanks in advance.
You can adjust the spacing between the two legends using a combination of two theme elements: legend.spacing and legend.margin. I played around a bit with these and this combination seems to work well:
Myplot + theme(
legend.spacing = unit(0,'pt'),
legend.margin = margin(t=0,b=0,unit='pt')
)
side note
Also, just wanted to note that when you want to squish together two legends, but have one title, it is better to do it like you have (where one of the legend titles is set to NULL rather than an empty character "". NULL effectively removes the legend title as an element and makes spacing easier, whereas "" still carries the spacing of the title, even if nothing is represented. If you replace NULL with "" in your code, you'll see this... so good job with that :).
Are you just looking for theme(legend.margin)?
Myplot + theme(legend.margin = margin(0, 0, -10, 0))
Related
Hello I am ploting a graph which will have the legend,width of legend items not same can any one help me to resolve my problem
data file
< https://drive.google.com/file/d/1EKhRwup3vUC3KVFOOh4XtKERIr8FQj3x/view?usp=sharing>
code I have used
df=read.table("test.txt",sep='\t', header=TRUE)
df = data.frame(df)
nCol <- 15
myCol <- viridis(n = nCol)
myCol
ggplot(df, aes(log(data1), log(data2),color=data3),cex=1.9)+
geom_point() +
scale_colour_stepsn(colours = c(myCol),breaks = seq(0,100,by=10))+
theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank(),
panel.background = element_blank(), axis.line = element_line(colour = "black"))+
theme(text = element_text(size = 12, face="bold"),
legend.text = element_text(size = 7, face="bold"), legend.position="top",
legend.key.size = unit(10, "mm"),
legend.key.width=unit(10, "mm"))
at the end of legend 90-100 width is high compare to others
There are a couple of asides before addressing your main concern:
You can simplify your code by using scale_color_binned(type = "viridis"), which gives the same result as creating a vector of
viridis colors and interpolating them as you are doing, with the added advantage that you don't need to load the viridis library.
You can use log scales on the x and y axis without having to transform your
data, by using scale_x_log10() and scale_y_log10()
You can simplify your theme call by first calling theme_classic(), which gets rid of the need to specify all those element_blank() components.
For the specific problem that you encountered though, the reason for the appearance is that breaks are for the "internal" breaks of the binned scale. The outer edges of your scale are not breaks, but limits. By default, limits are not shown on binned scales, but you can turn them on using show.limits = TRUE after setting the limits to the desired value of c(0, 100)
So your above code can be rewritten as:
df <- read.table("test.txt", sep = "\t", header = TRUE)
ggplot(df, aes(log(data1), log(data2), color = data3), cex = 1.9) +
geom_point() +
scale_colour_binned(type = "viridis",
breaks = 1:9 * 10,
limits = c(0, 100),
show.limits = TRUE,
labels = function(x) round(x)) +
theme_classic() +
theme(text = element_text(size = 12, face = "bold"),
legend.text = element_text(size = 7, face = "bold"),
legend.position = "top",
legend.key.size = unit(10, "mm"))
For a rather long report, I am trying to unify a number of bar-plots. The plots in general look like this:
The goal is that all the vertical axis start at the same position (e.g. 2 cm from the left plot-boarder), no matter how long the labels in front of the axis are.
The data that goes into the plot is generated as follows:
vector_bar <- as.character(c("Bar1","Bar1","Bar1","Bar1",
"Bar2","Bar2","Bar2","Bar2",
"thatincrediblylonglabel",
"thatincrediblylonglabel",
"thatincrediblylonglabel",
"thatincrediblylonglabel"))
vector_position <- as.numeric(c(1,1,1,1,2,2,2,2,3,3,3,3))
vector_bar_section <- c("section1","section2","section3","section4","section1","section2","section3","section4","section1","section2","section3","section4")
vector_percent <- as.numeric(c(1,0,0,0,0,1,0,0,0,0,1,0))
vector_yposition <- as.numeric(c(1.05, 1.15, 1.25, 1.35,1.05, 1.15, 1.25, 1.35,1.05, 1.15, 1.25, 1.35))
df <- data.frame(cbind(vector_bar,vector_position,vector_bar_section,vector_percent,vector_yposition))
#Formating
df$vector_percent <- as.numeric(as.character(df$vector_percent))
df$vector_yposition <- as.numeric(as.character(df$vector_yposition))
df$vector_bar <- as.character(df$vector_bar)
Now the ggplot-code:
ggplot(df, aes(x = vector_bar, y = vector_percent, fill = factor(vector_bar_section, levels = rev(c("section1", "section2", "section3", "section4"))))) +
geom_label(data = df, aes(x = vector_bar, y = vector_yposition, label = vector_percent),
colour = "white", fontface = "bold", size = 7.75, show.legend = FALSE) +
geom_bar(stat = "identity", data = subset(df), width = 0.65, colour = "white", lwd = 1.3) +
coord_flip() +
ggtitle("") +
theme(plot.title = element_text(size = 40, face = "bold"),
legend.title = element_text(size = 19),
legend.text = element_text(size = 19, color = "#587992"),
legend.key.size = unit(1.4, "line"),
legend.key.width = unit(3.4, "line"),
axis.text.x = element_text(size = 19, color = "#587992"),
axis.text.y = element_text(size = 19, color = "#587992"),
axis.ticks.y = element_blank(),
axis.ticks.x = element_blank(),
axis.title.y = element_blank(),
legend.position = "top",
legend.direction = "horizontal",
panel.border = element_blank(),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
plot.background = element_rect(fill = "white"),
panel.background = element_rect(fill = "white"),
plot.margin = unit(c(0,0,0,Autoplotmargin(df$vector_bar)), units = "in")) +
scale_y_continuous(labels = percent_format(), position = "top",breaks = seq(0,1,0.2)) +
scale_fill_manual("", values = c("section1"= "#FF0000",
"section2" = "#595959",
"section3" = "#A6A6A6",
"section4" = "#0D0D0D"), guide = guide_legend(reverse = TRUE, nrow = 1)) +
scale_x_discrete(limits = c(unique(df$vector_bar)), labels = addline_format(rev(c(unique(df$vector_bar))))) +
geom_segment(aes(x = 0.5, xend = length(unique(df$vector_bar)) + 0.5, y = 0, yend = 0),color="#587992", size = 1.5) +
geom_segment(aes(x = length(unique(df$vector_bar)) + 0.5, xend = length(unique(df$vector_bar)) + 0.5, y = 1, yend = 0),color = "#587992", size = 1.5) +
labs(y = "", x = "")
with:
addline_format <- function(x,...){
gsub('\\s ','\n',x)
}
Now the interesting part is the function "Autoplotmargin" which I have defined as follows:
Autoplotmargin <- function(x) {
y <- as.numeric(Marginkonstante)-as.numeric(unit(strwidth(strsplit(x[which.max(nchar(x))], " ", "[")[[1]][1],7.75, units = "in"), units= "in"))
y
}
whereas:
Marginkonstante <- unit(c(20), units = "in")
The idea behind this function is, that I first search for the longest label in df$vector_bar and measure it's length in inch:
as.numeric(unit(strwidth(strsplit(x[which.max(nchar(x))], " ", "[")[[1]][1],7.75, units = "in"), units= "in"))
Ignore the "strsplit"-section. It is needed because I have line breaks inside the labels and I split the string so that only the characters before the first line break are considered.
So this basically gives me the length of the longest label. I now set the Marginkonstante to a value, 20 in the example.
Now the idea is that the Autoplotmargin is defined as those 20 inches I set up, subtracted the length of the longest string. Amongst multiple plots this should set up the margin in a way that the vertical axis is positioned at the same place in every plot.
Problem is, that this does not happen. The tendency is right tough: for longer labels, the function Autoplotmargin gives me lower values, for shorter labels, it gives me higher values. But the axis are far away from being in the same position for all plots.
What is wrong in my way of thinking?
Important side-notes:
I do set fig.width in the rmarkdown chunk options, so that all figures are the same width.
I know there is a solution to this problem by using grid and/or grob functions (see here for example). I have looked into that, but can not use these solutions for a number of reasons (not explaining that in detail here, too long).
Thank you for your assistance in advance!
Best,
Fabian
Problem solved!
As it looks like, my way of thinking was all correct and I just had to change one thing to make it work. In the Autoplotmargin-Function, you choose in which Font-Size you want the string to be measured. In my case, I started with 7.75:
Autoplotmargin <- function(x) {
y <- as.numeric(Marginkonstante)-as.numeric(unit(strwidth(strsplit(x[which.max(nchar(x))], " ", "[")[[1]][1],7.75, units = "in"), units= "in"))
y
}
Now after playing around with that 7.75 value (in my case decreasing it), all works fine!
In my plot's I get an almost perfect result with 1.3:
Autoplotmargin <- function(x) {
y <- as.numeric(Marginkonstante)-as.numeric(unit(strwidth(strsplit(x[which.max(nchar(x))], " ", "[")[[1]][1],1.3, units = "in"), units= "in"))
y
}
This question already has answers here:
ggplot2 - jitter and position dodge together
(2 answers)
Closed 6 years ago.
I have a data which can be divaded via two seperators. One is year and second is a field characteristics.
box<-as.data.frame(1:36)
box$year <- c(1996,1996,1996,1996,1996,1996,1996,1996,1996,
1997,1997,1997,1997,1997,1997,1997,1997,1997,
1996,1996,1996,1996,1996,1996,1996,1996,1996,
1997,1997,1997,1997,1997,1997,1997,1997,1997)
box$year <- as.character(box$year)
box$case <- c(6.40,6.75,6.11,6.33,5.50,5.40,5.83,4.57,5.80,
6.00,6.11,6.40,7.00,NA,5.44,6.00, NA,6.00,
6.00,6.20,6.40,6.64,6.33,6.60,7.14,6.89,7.10,
6.73,6.27,6.64,6.41,6.42,6.17,6.05,5.89,5.82)
box$code <- c("L","L","L","L","L","L","L","L","L","L","L","L",
"L","L","L","L","L","L","M","M","M","M","M","M",
"M","M","M","M","M","M","M","M","M","M","M","M")
colour <- factor(box$code, labels = c("#F8766D", "#00BFC4"))
In boxplots, I want to display points over them, to see how data is distributed. That is easily done with one single boxplot for every year:
ggplot(box, aes(x = year, y = case, fill = "#F8766D")) +
geom_boxplot(alpha = 0.80) +
geom_point(colour = colour, size = 5) +
theme(text = element_text(size = 18),
axis.title.x = element_blank(),
axis.title.y = element_blank(),
panel.grid.minor.x = element_blank(),
panel.grid.major.x = element_blank(),
legend.position = "none")
But it become more complicated as I add fill parameter in them:
ggplot(box, aes(x = year, y = case, fill = code)) +
geom_boxplot(alpha = 0.80) +
geom_point(colour = colour, size = 5) +
theme(text = element_text(size = 18),
axis.title.x = element_blank(),
axis.title.y = element_blank(),
panel.grid.minor.x = element_blank(),
panel.grid.major.x = element_blank(),
legend.position = "none")
And now the question: How to move these points to boxplot axes, where they belong? As blue points to blue boxplot and red to red one.
Like Henrik said, use position_jitterdodge() and shape = 21. You can clean up your code a bit too:
No need to define box, then fill it piece by piece
You can let ggplot hash out the colors if you wish and skip constructing the colors factor. If you want to change the defaults, look into scale_fill_manual and scale_color_manual.
box <- data.frame(year = c(1996,1996,1996,1996,1996,1996,1996,1996,1996,
1997,1997,1997,1997,1997,1997,1997,1997,1997,
1996,1996,1996,1996,1996,1996,1996,1996,1996,
1997,1997,1997,1997,1997,1997,1997,1997,1997),
case = c(6.40,6.75,6.11,6.33,5.50,5.40,5.83,4.57,5.80,
6.00,6.11,6.40,7.00,NA,5.44,6.00, NA,6.00,
6.00,6.20,6.40,6.64,6.33,6.60,7.14,6.89,7.10,
6.73,6.27,6.64,6.41,6.42,6.17,6.05,5.89,5.82),
code = c("L","L","L","L","L","L","L","L","L","L","L","L",
"L","L","L","L","L","L","M","M","M","M","M","M",
"M","M","M","M","M","M","M","M","M","M","M","M"))
ggplot(box, aes(x = factor(year), y = case, fill = code)) +
geom_boxplot(alpha = 0.80) +
geom_point(aes(fill = code), size = 5, shape = 21, position = position_jitterdodge()) +
theme(text = element_text(size = 18),
axis.title.x = element_blank(),
axis.title.y = element_blank(),
panel.grid.minor.x = element_blank(),
panel.grid.major.x = element_blank(),
legend.position = "none")
I see you've already accepted #JakeKaupp's nice answer, but I thought I would throw in a different option, using geom_dotplot. The data you are visualizing is rather small, so why not forego the boxplot?
ggplot(box, aes(x = factor(year), y = case, fill = code))+
geom_dotplot(binaxis = 'y', stackdir = 'center',
position = position_dodge())
I posted my original question yesterday which got solved perfectly here
Original post
I made a few addition to my code
library(lubridate)
library(ggplot2)
library(grid)
### Set up dummy data.
dayVec <- seq(ymd('2016-01-01'), ymd('2016-01-10'), by = '1 day')
dayCount <- length(dayVec)
dayValVec1 <- c(0,-0.22,0.15,0.3,0.4,0.10,0.17,0.22,0.50,0.89)
dayValVec2 <- c(0,0.2,-0.17,0.6,0.16,0.41,0.55,0.80,0.90,1.00)
dayValVec3 <- dayValVec2
dayDF <- data.frame(Date = rep(dayVec, 3),
DataType = factor(c(rep('A', dayCount), rep('B', dayCount), rep('C', dayCount))),
Value = c(dayValVec1, dayValVec2, dayValVec3))
ggplot(dayDF, aes(Date, Value, colour = DataType)) +
theme_bw() +
ggtitle("Cumulative Returns \n") +
scale_color_manual("",values = c("#033563", "#E1E2D2", "#4C633C"),
labels = c("Portfolio ", "Index ", "In-Sample ")) +
geom_rect(aes(xmin = ymd('2016-01-01'),
xmax = ymd('2016-01-06'),
ymin = -Inf,
ymax = Inf
), fill = "#E1E2D2", alpha = 0.03, colour = "#E1E2D2") +
geom_line(size = 2) +
scale_x_datetime(labels = date_format('%b-%d'),
breaks = date_breaks('1 day'),
expand = c(0,0)) +
scale_y_continuous( expand = c(0,0), labels = percent) +
theme(axis.text.x = element_text(angle = 90),
axis.title.x = element_blank(),
axis.title.y = element_blank(),
panel.grid.minor = element_blank(),
panel.grid.major.x = element_blank(),
axis.line = element_line(size = 1),
axis.ticks = element_line(size = 1),
axis.text = element_text(size = 20, colour = "#033563"),
axis.title.x = element_text(hjust = 2),
plot.title = element_text(size = 40, face = "bold", colour = "#033563"),
legend.position = 'bottom',
legend.text = element_text(colour = "#033563", size = 20),
legend.key = element_blank()
)
which produces this output
The only thing that I still cannot get working is the position of the x axis. I want the x axis to be at y = 0 but still keep the x axis labels under the chart, exactly as in the excel version of it. I know the data sets are not the same but I didn't have the original data at hand so I produced some dummy data. Hope this was worth a new question, thanks.
> grid.ls(grid.force())
GRID.gTableParent.12660
background.1-5-7-1
spacer.4-3-4-3
panel.3-4-3-4
grill.gTree.12619
panel.background.rect.12613
panel.grid.minor.y.zeroGrob.12614
panel.grid.minor.x.zeroGrob.12615
panel.grid.major.y.polyline.12617
panel.grid.major.x.zeroGrob.12618
geom_rect.rect.12607
GRID.polyline.12608
panel.border.rect.12610
axis-l.3-3-3-3
axis.line.y.polyline.12631
axis
axis-b.4-4-4-4
axis.line.x.polyline.12624
axis
xlab.5-4-5-4
ylab.3-2-3-2
guide-box.6-4-6-4
title.2-4-2-4
> grid.gget("axis.1-1-1-1", grep=T)
NULL
ggplot2 doesn't make this easy. Below is one-way to approach this interactively. Basically, you just grab the relevant part of the plot (the axis line and ticks) and reposition them.
If p is your plot
p
grid.force()
# grab the relevant parts - have a look at grid.ls()
tck <- grid.gget("axis.1-1-1-1", grep=T)[[2]] # tick marks
ax <- grid.gget("axis.line.x", grep=T) # x-axis line
# add them to the plot, this time suppressing the x-axis at its default position
p + lapply(list(ax, tck), annotation_custom, ymax=0) +
theme(axis.line.x=element_blank(),
axis.ticks.x=element_blank())
Which produces
A quick note: the more recent versions of ggplot2 have the design decision to not show the axis. Also changes to axis.line are not automatically passed down to the x and y axis. Therefore, I tweaked your theme to define axis.line.x and axis.line.y separately.
That siad, perhaps its easier (and more robust??) to use geom_hline as suggested in the comments, and geom_segment for the ticks.
I have created a notched boxplot of some data in R using the ggplot2 package. I have a problem that the x-axis element text makes the labels of my groups overlap, which I do not want.
I also do not want to rotate the labels. Preferably, I would like each label to be written horizontally but continued on a 'separate' line. So that the two words of the (e.g.) label Carboniferous Lst. appears as two words with the second word 'Limestone' written horizontally below Carboniferous. I cannot reduce font size, as it will then be too difficult to read.
Does anyone know whether there is a command in R's ggplot that takes care of this?
Many, many thanks
Damiano
PS: My current code is:
box <- ggplot(AquiProps, aes(Geology, logTRANS))
box + geom_boxplot(notch = TRUE)
+ labs(x = "", y = "Mean log Transmissivity(m2/d)")
+ theme(axis.title = element_text(face = "bold", size = "12", color = "black"),
axis.text = element_text(size = 10, face = "bold", color = "black"),
axis.title.y = element_text(vjust = 1),
axis.title.x = element_text(vjust = 0.005))
I imagine I need to change something in the axis.title.x=element_text command?!?!
Like this?
# create example
set.seed(1)
names <- paste("Carboniferous Species:",1:8)
df <- data.frame(names=rep(names,each=100),values=rnorm(800))
library(ggplot2)
ggplot(df,aes(x=names,y=values))+
geom_boxplot(notch=TRUE)+
scale_x_discrete(labels=gsub("(Carboniferous)","\\1\n",unique(df$names)))+
theme(axis.title = element_text(face = "bold", size = "12", color = "black"),
axis.text = element_text(size = 10, face = "bold", color = "black"),
axis.title.y = element_text(vjust = 1),
axis.title.x = element_text(vjust = 0.005))
The code above inserts line breaks into the axis labels using scale_x_discrete(labels=...).
You could also insert the line breaks directly into your data, using e.g.:
df$names <- gsub("(Carboniferous)","\\1\n",df$names)
Then your code as written would generate the same plot above.
It's an old question but since ggplot 3.3.0, it's easy solve.
You can use the argument guide = guide_axis(n.dodge = 2) insidescale_x_discrete.
library(tidyverse)
set.seed(1)
names <- paste("Carboniferous Species:",1:8)
df <- data.frame(names=rep(names,each=100),values=rnorm(800))
ggplot(df,aes(x=names,y=values))+
geom_boxplot(notch=TRUE)+
scale_x_discrete(guide = guide_axis(n.dodge = 2)) +
theme(axis.title = element_text(face = "bold",
size = "12",
color = "black"),
axis.text = element_text(size = 10,
face = "bold",
color = "black"),
axis.title.y = element_text(vjust = 1),
axis.title.x = element_text(vjust = 0.005))
Result: