I am trying to visualize my ggtree and I seem to be stuck on the last final step; repositioning the tree labels from horizontal to verticle so that they do not overlap. If I change the geom = "text" on the geom_tiplab function, I get what I want but my labels are no longer coloured. Datasets here and here
Here is the code for reproducibility; Please help
p1 <- ape::read.tree("Tert_aln.fasta_processed.fa.raxml.support")
temp1 = read.csv("Tert_Final_Mapping_File.csv", sep=";")
mycolors = c(brewer.pal(name="Set1", n = 9), brewer.pal(name="Paired", n = 12), brewer.pal(name="Dark2", n = 8))
p2 <- ggtree(p1, layout='circular') %<+% temp1 +
geom_tippoint(
mapping = aes(color = phylum), # tip color by phyla.
size = 2,
show.legend = FALSE) +
scale_color_manual(values = mycolors) +
geom_tiplab( # adds name of phyla to tip of its branch
aes(fill = phylum),
color = 'black',
offset = 2,
size = 3,
geom = "label",
align = TRUE,
face = "bold",
label.size = 0
label.padding = unit(0.15, "lines"), # amount of padding around the labels
linetype = "solid") +
ggtitle("Phylogenetic tree of Tert")+ # title of your graph
theme(
axis.title.x = element_blank(), # removes x-axis title
axis.title.y = element_blank(), # removes y-axis title
legend.title = element_text( # defines font size and format of the legend title
face = "bold",
size = 12),
legend.text=element_text( # defines font size and format of the legend text
face = "bold",
size = 10),
plot.title = element_text( # defines font size and format of the plot title
size = 12,
face = "bold"),
legend.position = "bottom", # defines placement of the legend
legend.box = "vertical", # defines placement of the legend
legend.margin = margin())
pdf("ggplot_Tert1.pdf", width = 20, height = 22)
p2
dev.off()
I noticed you wrote you wanted colored labels, but you have fill, which isn't doing anything here. You declared color = 'black', as well.
Sorry if I miss the mark! I am applying my best guess as to what you wanted to see.
There are four things I did to make this happen:
In geom_tiplab(), I changed fill = phylum to color = phylum.
In geom_tiplab(), I commented out color = 'black'.
In geom_tiplab(), I commented out label.size = 0.
In geom_tiplab(), I changed geom = "label" to geom = "text".
Is this what you wanted? (You will have to adjust the plotted limits to get all of the text into the visual.) This is geom = "text". When you use labels, it automatically rotates the values to show horizontally.
Related
I have a dataframe where I have colored points from one location black and from another location white. In ggplot, the white points show properly; they have a black margin with a white fill. However, in the legend, the white point no longer has a black margin. How can I get the white point in the legend to have a black margin?
Example code:
library(ggplot2)
set.seed(321)
dat <- data.frame(matrix(ncol = 3, nrow = 6))
x <- c("Location","Month", "Value")
colnames(dat) <- x
dat$Location <- c("North","North","North","South","South","South")
dat$Month <- rep(c(1,2,3),2)
dat$Value <- rnorm(6,20,5)
cols <- c("South" = "black", "North" = "white")
ggplot(data = dat, aes(x = Month, y = Value, group = Location)) +
geom_point(aes(color = Location, fill = Location), size = 3) +
geom_point(size = 3, shape = 21, color = "black") +
scale_color_manual(values = cols) +
theme_bw() +
theme(panel.grid = element_blank(),
text = element_text(size = 16),
axis.text.x = element_text(size = 14, color = "black"),
axis.text.y = element_text(size = 14, color = "black"),
legend.title = element_blank(),
legend.text = element_text(size = 16, color = "black"),
legend.position = c(0.1,0.1),
legend.key = element_blank(),
legend.background = element_blank())
I could add another point onto the plot with something like geom_point(aes(x=1.1,y=16),size = 3.8, shape = 21, color = 'black') + but this is sloppy and does not play well when reformatting figure height or width.
If you use one of the filled-in shapes like shape = 21, you can separately control the border (with color, black by default) and the fill (with fill). So to get a combination of solid black points and white points with black margin, you can use one geom layer and should get the appropriate legend:
...
geom_point(aes(fill = Location), shape = 21, size = 3) +
scale_fill_manual(values = cols) +
...
[Here with legend moved to 0.8,0.8:]
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))
I have a treemap that I've made using ggplot and treemapify. It's fine, but the legend is weirdly squashed - the labels are right up to the edges of the keys/symbols/icons. This doesn't happen with other plots so maybe it is a treemapify issue?
When I've searched for answers, most are about changing spacing between labels, for e.g., but that is not what I'm trying to do. I've found this one answer to what seems to be my question. And I guess I could add spaces to the labels! But it feels like there must be a better solution, especially because the labels are my column names and don't need spaces elsewhere, because for some reason the legend spacing is only an issue with this plot.
I've also tried theme(legend.text.align = 0.2), for e.g., but that clearly isn't right because it's about alignment, not margins or padding.
library(ggplot2)
library(treemapify)
tree_data <- as.data.frame(matrix(0, ncol = 0, nrow = 12))
tree_data$colour <- as.character(c("Red", "Red", "Blue", "Green"))
tree_data$shade <- as.character(c("Ruby", "Merlot", "Ink", "Olive",
"Garnet", "Wine", "Royal", "Emerald",
"Brick", "Berry", "Navy", "Apple"))
tree_data$freq <- sample(100, size = nrow(tree_data), replace = TRUE)
treeMapPlot <- ggplot(tree_data, aes(area = freq, fill = colour, label = shade,
subgroup = colour)) +
geom_treemap(color = "gray20") +
geom_treemap_subgroup_border() +
geom_treemap_text(colour = "white", place = "topleft", reflow = T, padding.x = grid::unit(1.5, "mm"),
padding.y = grid::unit(2, "mm"), size = 20) +
theme(plot.title = element_text(hjust = 0.5, size = 16),
legend.title = element_blank())
treeMapPlot
(Apologies for the colour mismatching!)
You can manually add a margin between the legend symbols and the text by specifying legend.spacing.x within theme. How about this:
treeMapPlot <- ggplot(tree_data, aes(area = freq, fill = colour, label = shade,
subgroup = colour)) +
geom_treemap(color = "gray20") +
geom_treemap_subgroup_border() +
geom_treemap_text(colour = "white", place = "topleft", reflow = T, padding.x = grid::unit(1.5, "mm"),
padding.y = grid::unit(2, "mm"), size = 20) +
theme(plot.title = element_text(hjust = 0.5, size = 16),
legend.title = element_blank(),
legend.spacing.x = unit(0.2, 'cm'))
treeMapPlot
This is a follow-up on https://stackoverflow.com/questions/32275113
The problem is to tweak the legend elements to increase the space between legend keys without simultaneously extending the legend keys themselves. The solution is likely to be in tweaking the correct legend theme option.
Desired result: more vertical space between the legend key text labels, but without stretching the legend key lines.
d <- data.frame(x = mtcars$mpg, y = 0.10)
vlines <- rbind(aggregate(d[1], d[2], mean),
aggregate(d[1], d[2], median))
vlines$stat <- rep(c("mean", "median"), each = nrow(vlines)/2)
library("ggplot2")
ggplot(data = d, aes(x = x, y = ..density..)) +
geom_histogram(fill = "lightblue", color = "black") +
geom_vline(data = vlines, mapping = aes(xintercept = x, colour = stat),
show.legend = TRUE) +
theme(legend.direction = "vertical",
legend.position = "right",
# legend.key = element_rect(size = 2),
legend.key.size = unit(3, "cm"),
# legend.key.width = unit(2, "cm"),
# legend.key.height = unit(1, "cm")
)
Increasing legend.key.size, as suggested in answers to the linked question (see above), has the undesired side effect of increasing the vertical lines as well.
Edit Based on PoGibas's clever workaround, here's a screenshot of the desired result, included here to make sure the purpose is clear:
Following PoGibas, I used: shape = 73, legend.key.height = unit(2, "cm") and size = 6 inside the color guide.
One solution is to replace lines with points (requires additional geom layer):
Create plot with invisible points (size = 0 and rectangle shape shape = 15).
p <- ggplot(d, aes(x, ..density..)) +
geom_histogram(fill = "lightblue", color = "black") +
geom_vline(data = vlines, mapping = aes(xintercept = x, colour = stat)) +
geom_point(data = vlines, aes(0, 0, colour = stat), size = 0, shape = 15)
Add legend theme to:
Mask background color in legend (legend.key = element_rect(fill = "white"))
Create large legend (legend.key.height = unit(3, "cm"))
Remove lines (linetype = 0) and make large points (size = 5)
Code:
p +
theme(legend.direction = "vertical",
legend.position = "right",
legend.key = element_rect(fill = "white"),
legend.key.height = unit(3, "cm")) +
guides(color = guide_legend(override.aes = list(linetype = 0, size = 5)))
PS.:
This is not a perfect solution as there's a gap between legend label and boxes.
If you want lines instead of rectangles use shape = 73
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
}