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
Related
I have a stack of raster's and suppose to find the mean of it. I have done it. Now, I want to add polygon on the mean of raster image that I got. Then, I wants to save and make it colorful by using ggplot2 code. But I don't understand how to and where add polygon in ggplot2.
fs <- list.files(path="directory.tiff", pattern =
"tif$", full.names = TRUE)
s<- raster::stack(fs)
pg <- readOGR("parks.shp")
se1 <- calc(s, fun = mean)
plot(se1)
plot(pg, add= T )
They give me this attached below picture, Parks overlay on the mean of raster's. Its fine till now.
But when I used ggplot to change its color scheme. They gave me desired pattern what I want, but the problem is parks polygons doesn't overlay on the final picture (attached below after code what I get). So can anyone tell me where I need to change the code in ggplot to get park shp overlay on the picture 2.
conti_col_pal <- pnw_palette("Bay",10,type="continuous")
binary.cols <- c("1" = conti_col_pal[10], "0" = "white")
cv.df <- as.data.frame(rasterToPoints(se1))
##above I give the comand of se1 when I add pg here instead it give me error.
p_cv <- ggplot() +
coord_fixed() +
geom_raster(data = xy_FONDO, aes(lon, lat, fill = r)) +
scale_fill_gradient(low = "gray56", high = "gray56", na.value = NA, guide = FALSE) +
new_scale("fill") +
geom_raster(data = cv.df, aes(x, y, fill = layer))+
scale_fill_gradientn(colours = conti_col_pal,
breaks = seq(-1, 7, 2), limits = c(0, 10))+
annotate(geom = "text", x = lonmin+2, y = latmax-2, vjust = 1, hjust = 0,
label = "",
color = "black", angle = 0, size=4)+
scale_x_continuous(limits = c(lonmin, lonmax), expand = c(0, 0)) +
scale_y_continuous(limits = c(latmin, latmax), expand = c(0, 0))+
theme_bw(base_family="")+
theme(
plot.margin = margin(0, 0, 0, 0, "cm"),
#panel.background = element_rect(fill = col_pal_binary[1], colour = col_pal_binary[1], size
= 0.5, linetype = "solid"),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
axis.title.x=element_blank(),
axis.title.y=element_blank(),
axis.text.x=element_blank(),
axis.text.y=element_blank(),
axis.ticks.x=element_blank(),
axis.ticks.y=element_blank(),
legend.background = element_rect(fill=NA, size=0.3, linetype="solid", color=NA),
legend.position = c(0.8, 0.35),
legend.title= element_blank(),
legend.text = element_text(colour = "black", size = 12, angle = 0),
legend.direction = "vertical", ##vertical; horizontal
legend.title.align=0.5)+
guides(fill = guide_colorbar(## label.position = "bottom",
## title.position = "left",
label.vjust=0,
# draw border around the legend
frame.colour = "black",
barwidth = 1.5,
barheight = 8))
tiff(filename = "bay.tiff", res = 600,
width = 4080, height = 3200, compression = "lzw")
grid.arrange(p_cv,
ncol = 1)
dev.off()
After defining the raster "d.f" do same for pg but use function fortify to do and similarly after "geom_raster" do "geom_polygon" to introduce the polygon in ggplot.
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.
I am making a sort of population pyramid using ggplot (plotrix doesn't allow me to do fancy labels etc), then I start with a geom_bar with labels and later I flip the coordinates. Sadly, labels almost cannot being seeing. I would like to move those labels near to the "y- axis" in the middle, that now is showing the age groups.
Data is here: d <- data.frame(age.grp2 = c("1-10", "11-20", "21-30", "31-40", "41-50", "1-10", "11-20", "21-30", "31-40", "41-50"),
sex = c("Female","Female","Female","Female","Female","Male","Male","Male","Male","Male" ),
n.enroll = c(288,500,400,300,200,300,460,300,200,300),
proportion = c(17.1,29.6,23.7,17.8,11.8,51,47.9,42.9,40,60),
proportion2 = c(-17.1,-29.6,-23.7,-17.8,-11.8,51,47.9,42.9,40,60)) My code is this one: ggplot(d, aes(x = age.grp2, y = proportion2, fill = sex)) +
geom_bar(position = position_dodge(width=1), stat='identity') +
geom_label(aes(label = paste(n.enroll," (",proportion,"%)", sep=""), group = factor(sex)),
fill="white", colour = "black",
position= position_dodge(width=1),
size = 3) +
scale_fill_manual(values=c("#BFD5E3", "grey")) +
facet_share(~sex, dir = "h", scales = "free", reverse_num = TRUE) +
coord_flip() +
theme(panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
#panel.border = element_blank(),
panel.background = element_blank(),
legend.position = "none",
#axis.line.x = element_line(color = "black"),
axis.ticks.y = element_blank(),
axis.text.x = element_text(colour = "black", size = 8, face = "bold", angle=0, hjust=0.5),
axis.text.y = element_text(colour = "black", size = 8, face = "bold"),
axis.title.x = element_text(size = 14, face="bold", margin = margin(t = 30, r = 20, b = 10, l = 20)),
plot.margin = unit(c(1,1,1,1),"cm")) +
labs(y = "Enrollment percentage within sex",x="") I am attaching also the plot, where we can see in females the label in the age group 11-20 is cut. I would like to have all labels near to the age group labels, within each bar: female labels moved to the right and male labels move it to the left. Also, I would like to have each x-axis extended to 100% or at least in same range, in females goes up to 30% and in males goes up to 60%. Thanks for all the comments
Here's a minimal solution using the base ggplot package, without most of your formatting. The key part is to add a conditional y = ... into the geom_label(aes()) section:
d %>%
mutate(
label = str_c(n.enroll, " (", proportion, "%)"),
label_loc = if_else(sex == "Female", -9.5, 3),
proportion_for_chart = if_else(sex == "Female", -proportion, proportion)
) %>%
ggplot(aes(x = age.grp2, y = proportion_for_chart, fill = sex)) +
geom_col(show.legend = FALSE) +
geom_label(aes(y = label_loc, label = label), size = 3, fill = "white", hjust = 0) +
coord_flip() +
facet_wrap(~ sex, scales = "free") +
theme(
axis.title = element_blank()
)
Whenever possible, I try to reshape data and use geom_col rather than try to get lucky with geom_bar. You should be able to play around with different hard-coded values of y in the geom_label call to fix the proper location for your labels based on your formatting and image size/scale.
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
}