I am trying to plot a heat map with ggplot2 and I would like to resize the colorbar and increase the font.
Here is the relevant part of the code:
g <- ggplot(data=melt.m)
g2 <- g+geom_rect(aes(xmin=colInd-1, xmax=colInd,
ymin=rowInd-1, ymax=rowInd, fill=value))
g2 <- g2+scale_x_continuous('beta', breaks=c(1, ceiling(cols/2), rows)-0.5,
labels=c(1,ceiling(cols/2), rows))
g2 <- g2+scale_y_continuous('alpha', breaks=c(1, ceiling(rows/2), rows)-0.5,
labels=c(1, ceiling(rows/2), rows))
g2 <- g2+opts(panel.grid.minor=theme_line(colour=NA),
panel.grid.major=theme_line(colour=NA),
panel.background=theme_rect(fill=NA, colour=NA),
axis.text.x=theme_text(size=30),
axis.text.y=theme_text(size=30, angle=90),
axis.title.x=theme_text(size=30),
axis.title.y=theme_text(size=30, angle=90), title = title)
heatscale <- c(low='ghostwhite', high='steelblue')
g2 <- g2+scale_fill_gradient("", heatscale[1], heatscale[2], bias = 10)
It works fine, the problem is that the color legend on the right side is too small. Is there a way to make the color legend bigger and increase the font size of the legend?
Thanks,
kz
We don't have your melt.m data, so the code you give is not reproducible. Using the diamonds dataset that comes with ggplot2 as an example, though:
ggplot(diamonds, aes(x=table, y=price)) +
geom_bin2d() +
scale_fill_gradient("", 'ghostwhite', 'steelblue', bias=10) +
opts(legend.key.width=unit(1, "in"),
legend.text = theme_text(size=30))
legend.key.width and legend.text are what you are looking for. I have used exaggerated sizes to make it more obvious.
For more details on the options available, see https://github.com/hadley/ggplot2/wiki/+opts%28%29-List
I tried this and found that R or ggplot2 have changed in the last four years. It yielded the error:
Error: 'opts' is deprecated. Use 'theme' instead. (Defunct; last used in version 0.9.1)
Was able to get it to work with the following instead:
p + theme(legend.text = element_text(size=30),legend.key.size = unit(1, "in"))
Initially tried just changing the text size but had to change the key size with it or it becomes unreadable. Also, unit needs a library explicitly loaded with library(grid)
Related
I use R for most of my data analysis. Until now I used to export the results as a CSV and visualized them using Macs Numbers.
The reason: The Graphs are embeded in documents and there is a rather large border on the right side reserved for annotations (tufte handout style). Between the acutal text and the annotations column there is white space. The plot of the graphs needs to fit the width of text while the legend should be placed in the annotation column.
I would prefer to also create the plots within R for a better workflow and higher efficiency. Is it possible to create such a layout using plotting with R?
Here is an example of what I would like to achieve:
And here is some R Code as a starter:
library(tidyverse)
data <- midwest %>%
head(5) %>%
select(2,23:25) %>%
pivot_longer(cols=2:4,names_to="Variable", values_to="Percent") %>%
mutate(Variable=factor(Variable, levels=c("percbelowpoverty","percchildbelowpovert","percadultpoverty"),ordered=TRUE))
ggplot(data=data, mapping=aes(x=county, y=Percent, fill=Variable)) +
geom_col(position=position_dodge(width=0.85),width=0.8) +
labs(x="County") +
theme(text=element_text(size=9),
panel.background = element_rect(fill="white"),
panel.grid = element_line(color = "black",linetype="solid",size= 0.3),
panel.grid.minor = element_blank(),
panel.grid.major.x=element_blank(),
axis.line.x=element_line(color="black"),
axis.ticks= element_blank(),
legend.position = "right",
legend.title = element_blank(),
legend.box.spacing = unit(1.5,"cm") ) +
scale_y_continuous(breaks= seq(from=0, to=50,by=5),
limits=c(0,51),
expand=c(0,0)) +
scale_fill_manual(values = c("#CF232B","#942192","#000000"))
I know how to set a custom font, just left it out for easier saving.
Using ggsave
ggsave("Graph_with_R.jpeg",plot=last_plot(),device="jpeg",dpi=300, width=18, height=9, units="cm")
I get this:
This might resample the result aimed for in the actual case, but the layout and sizes do not fit exact. Also recognize the different text sizes between axis titles, legend and tick marks on y-axes. In addition I assume the legend width depends on the actual labels and is not fixed.
Update
Following the suggestion of tjebo I posted a follow-up question.
Can it be done? Yes. Is it convenient? No.
If you're working in ggplot2 you can translate the plot to a gtable, a sort of intermediate between the plot specifications and the actual drawing. This gtable, you can then manipulate, but is messy to work with.
First, we need to figure out where the relevant bits of our plot are in the gtable.
library(ggplot2)
library(gtable)
library(grid)
plt <- ggplot(mtcars, aes(factor(cyl), fill = factor(vs))) +
geom_bar(position = position_dodge2(preserve = "single"))
# Making gtable
gt <- ggplotGrob(plt)
gtable_show_layout(gt)
Then, we can make a new gtable with prespecified dimensions and place the bits of our old gtable into it.
# Making a new gtable
new <- gtable(widths = unit(c(12.5, 1.5, 4), "cm"),
heights = unit(9, "cm"))
# Adding main panel and axes in first cell
new <- gtable_add_grob(
new,
gt[7:9, 3:5], # If you see the layout above as a matrix, the main bits are in these rows/cols
t = 1, l = 1
)
# Finding the legend
legend <- gt$grobs[gt$layout$name == "guide-box"][[1]]
legend <- legend$grobs[legend$layout$name == "guides"][[1]]
# Adding legend in third cell
new <- gtable_add_grob(
new, legend, t = 1, l = 3
)
# Saving as raster
ragg::agg_png("test.png", width = 18, height = 9, units = "cm", res = 300)
grid.newpage(); grid.draw(new)
dev.off()
#> png
#> 2
Created on 2021-04-02 by the reprex package (v1.0.0)
The created figure should match the dimensions you're looking for.
Another option is to draw the three components as separate plots and stitch them together in the desired ratio.
The below comes quite close to the desired ratio, but not exactly. I guess you'd need to fiddle around with the values given the exact saving dimensions. In the example I used figure dimensions of 7x3.5 inches (which is similar to 18x9cm), and have added the black borders just to demonstrate the component limits.
library(tidyverse)
library(patchwork)
data <- midwest %>%
head(5) %>%
select(2,23:25) %>%
pivot_longer(cols=2:4,names_to="Variable", values_to="Percent") %>%
mutate(Variable=factor(Variable, levels=c("percbelowpoverty","percchildbelowpovert","percadultpoverty"),ordered=TRUE))
p1 <-
ggplot(data=data, mapping=aes(x=county, y=Percent, fill=Variable)) +
geom_col() +
scale_fill_manual(values = c("#CF232B","#942192","#000000"))
p_legend <- cowplot::get_legend(p1)
p_main <- p1 <-
ggplot(data=data, mapping=aes(x=county, y=Percent, fill=Variable)) +
geom_col(show.legend = FALSE) +
scale_fill_manual(values = c("#CF232B","#942192","#000000"))
p_main + plot_spacer() + p_legend +
plot_layout(widths = c(12.5, 1.5, 4)) &
theme(plot.margin = margin(),
plot.background = element_rect(colour = "black"))
Created on 2021-04-02 by the reprex package (v1.0.0)
update
My solution is only semi-satisfactory as pointed out by the OP. The problem is that one cannot (to my knowledge) define the position of the grob in the third panel.
Other ideas for workarounds:
One could determine the space needed for text (but this seems not so easy) and then to size the device accordingly
Create a fake legend - however, this requires the tiles / text to be aligned to the left with no margin, and this can very quickly become very hacky.
In short, I think teunbrand's solution is probably the most straight forward one.
Update 2
The problem with the left alignment should be fixed with Stefan's suggestion in this thread
I have a two-part waffle plot with a lot of little squares, and a legend that contains two squares. I would like to make the sizes of all of these squares to be the same.
There was an issue opened on GitHub about this, and the repo owner said that since waffle() returns a ggplot2 object, we can use guide() to do this.
I tried searching on documentation to do this and came up with
library(waffle)
phrase_count = 17345/10000
all_count = (22784085 - phrase_count)/10000
my_waffle = waffle(c("All"=all_count, "Phrases"=phrase_count),
rows=43,
size=0.6,
colors=c("#969696", "pink", "white"),
flip=TRUE)
my_waffle + guides(colour=guide_legend(override.aes = list(size=0.6)))
but this doesn't affect the size of the legend. I've seen people use color, colour, or shape, but none of these arguments work for me.
How do I get the size of squares in the legend to be the same as the size of the squares in the plot itself?
Try setting theme() for your legend key as the waffle object is from ggplot2 nature as mentioned in comments by #Waldi:
#Code
my_waffle <- my_waffle + theme(legend.key.size = unit(3, "mm"))
Output:
Or maybe this:
#Code 2
my_waffle + theme(legend.key.height = unit(0.2, "cm"),
legend.key.width = unit(0.3, "cm"))
Output:
I've only very recently started learning R. Now what I'm trying to do is to integrate two legends for the same plot. In other words, I want the default size legend to change color depending on it's size.
I have been Googling several solutions that apparently all don't seem to work, but again, I'm new to R so maybe I'm just doing something wrong.
My code:
ggplot(Caschool, aes(x=testscr, y=avginc), colour="green") +
geom_point(aes(size=enrltot, color=enrltot)) +
geom_smooth(colour="blue") +
labs(x="Test Score", y="Average Income", title="California Test Score Data", color="Number of Students\nPer District") +
theme(
panel.grid.minor = element_blank(),
panel.grid.major=element_line(colour="grey", size=0.4),
panel.background=element_rect(fill="beige"),
axis.line=element_line(size = 1.2, colour = "black"),
plot.title = element_text(size = rel(2))) +
scale_color_continuous(limits=c(0, 30000), breaks=seq(0,30000, by=2500)) +
guides(color= guide_legend(), size=guide_legend())
Apparently, I'm not allowed to post pictures, or I would have shown what this looks like so far.
ggplot2 can indeed combine size and colour legends into one, however, this only works, if they are compatible: they need to have exactly the same breaks, otherwise they can not be combined.
Let me make an example: Assume, you have values between 0 and 10 that you want to map on size and colour. You tell ggplo2 to use small points for values below 5 and large points for larger value. It will then plot a legend with a small and a large point, as expected. Now, you also want to add colour and you require points below 3 to be green and points above to be blue. ggplot2 will also draw a legend for this, but it is impossible to combine the two legends. The small point would have to be both, green and blue. The problem can be solved by using the same breaks for colour and size.
In your example, you manually change the breaks of the colour scale, but not those of the size scale. This results in incompatible legends that can not be combined.
I can not demonstrate this using your date, because I don't have it. So I will create an example with mtcars. The variant with incompatible legends is constructed as follows:
p <- ggplot(mtcars, aes(x=mpg, y=drat)) +
geom_point(aes(size=gear, color=gear)) +
scale_color_continuous(limits=c(2, 5), breaks=seq(2, 5, by=0.5)) +
guides(color= guide_legend(), size=guide_legend())
which gives the following plot:
If I now add the same breaks for size,
p + scale_size_continuous(limits=c(2, 5), breaks=seq(2, 5, by=0.5))
I get a plot with only one legend:
For your code, this means that you should add the following to your plot:
+ scale_size_continuous(limits=c(0, 30000), breaks=seq(0,30000, by=2500))
A little side remark: What do you intend by using colour = "green" in your call to ggplot? I don't see that this has any effect at all, because you set the colour again in both geoms that you use later. Maybe a relic from an older variant of the plot?
I have a really simple question, which I am struggling to find the answer to. I hoped someone here might be able to help me.
An example dataframe is presented below:
a <- c(1:10)
b <- c(10:1)
df <- data.frame(a,b)
library(ggplot2)
g = ggplot(data=df) + geom_point(aes(x=a, y=b)) +
xlab("x axis")
g
I just want to learn how I change the text size of the axes titles and the axes labels.
You can change axis text and label size with arguments axis.text= and axis.title= in function theme(). If you need, for example, change only x axis title size, then use axis.title.x=.
g+theme(axis.text=element_text(size=12),
axis.title=element_text(size=14,face="bold"))
There is good examples about setting of different theme() parameters in ggplot2 page.
I think a better way to do this is to change the base_size argument. It will increase the text sizes consistently.
g + theme_grey(base_size = 22)
As seen here.
If you are creating many graphs, you could be tired of typing for each graph the lines of code controlling for the size of the titles and texts. What I typically do is creating an object (of class "theme" "gg") that defines the desired theme characteristics. You can do that at the beginning of your code.
My_Theme = theme(
axis.title.x = element_text(size = 16),
axis.text.x = element_text(size = 14),
axis.title.y = element_text(size = 16))
Next, all you will have to do is adding My_Theme to your graphs.
g + My_Theme
if you have another graph, g1, just write:
g1 + My_Theme
and so on.
To change the size of (almost) all text elements, in one place, and synchronously, rel() is quite efficient:
g+theme(text = element_text(size=rel(3.5))
You might want to tweak the number a bit, to get the optimum result. It sets both the horizontal and vertical axis labels and titles, and other text elements, on the same scale. One exception is faceted grids' titles which must be manually set to the same value, for example if both x and y facets are used in a graph:
theme(text = element_text(size=rel(3.5)),
strip.text.x = element_text(size=rel(3.5)),
strip.text.y = element_text(size=rel(3.5)))
I'd like to remove the labels for the facets completely to create a sort of sparkline effect, as for the audience the labels are irrelevant, the best I can come up with is:
library(MASS)
library(ggplot2)
qplot(week,y,data=bacteria,group=ID, geom=c('point','line'), xlab='', ylab='') +
facet_wrap(~ID) +
theme(strip.text.x = element_text(size=0))
So can I get rid of the (now blank) strip.background completely to allow more space for the "sparklines"?
Or alternatively is there a better way to get this "sparkline" effect for a large number of binary valued time-series like this?
For ggplot v2.1.0 or higher, use element_blank() to remove unwanted elements:
library(MASS) # To get the data
library(ggplot2)
qplot(
week,
y,
data = bacteria,
group = ID,
geom = c('point', 'line'),
xlab = '',
ylab = ''
) +
facet_wrap(~ ID) +
theme(
strip.background = element_blank(),
strip.text.x = element_blank()
)
In this case, the element you're trying to remove is called strip.
Alternative using ggplot grob layout
In older versions of ggplot (before v2.1.0), the strip text occupies rows in the gtable layout.
element_blank removes the text and the background, but it does not remove the space that the row occupied.
This code removes those rows from the layout:
library(ggplot2)
library(grid)
p <- qplot(
week,
y,
data = bacteria,
group = ID,
geom = c('point', 'line'),
xlab = '',
ylab = ''
) +
facet_wrap(~ ID)
# Get the ggplot grob
gt <- ggplotGrob(p)
# Locate the tops of the plot panels
panels <- grep("panel", gt$layout$name)
top <- unique(gt$layout$t[panels])
# Remove the rows immediately above the plot panel
gt = gt[-(top-1), ]
# Draw it
grid.newpage()
grid.draw(gt)
I'm using ggplot2 version 1 and the commands required have changed.
Instead of
ggplot() ... +
opts(strip.background = theme_blank(), strip.text.x = theme_blank())
you now use
ggplot() ... +
theme(strip.background = element_blank(), strip.text = element_blank())
For more detail see http://docs.ggplot2.org/current/theme.html
Sandy's updated answer seems good but, possibly has been rendered obsolete by updates to ggplot? From what I can tell the following code (a simplified version of Sandy's original answer) reproduces Sean's original graph without any extra space:
library(ggplot2)
library(grid)
qplot(week,y,data=bacteria,group=ID, geom=c('point','line'), xlab='', ylab='') +
facet_wrap(~ID) +
theme(strip.text.x = element_blank())
I am using ggplot 2.0.0.
As near as I can tell, Sandy's answer is correct but I think it's worth mentioning that there seems to be a small difference the width of a plot with no facets and the width of a plot with the facets removed.
It isn't obvious unless you're looking for it but, if you stack plots using the viewport layouts that Wickham recommends in his book, the difference becomes apparent.