How to adjust figure settings in plotmatrix? - r

Can I adjust the point size, alpha, font, and axis ticks in a plotmatrix?
Here is an example:
library(ggplot2)
plotmatrix(iris)
How can I:
make the points twice as big
set alpha = 0.5
have no more than 5 ticks on each axis
set font to 1/2 size?
I have fiddled with the mapping = aes() argument to plotmatrix as well as opts() and adding layers such as + geom_point(alpha = 0.5, size = 14), but none of these seem to do anything. I have hacked a bit of a fix to the size by writing to a large pdf (pdf(file = "foo.pdf", height = 10, width = 10)), but this provides only a limited amount of control.

Pretty much all of the ggplot2 scatterplot matrix options are still fairly new and can be a bit experimental.
But the facilities in GGally do allows you to construct this kind of plot manually, though:
custom_iris <- ggpairs(iris,upper = "blank",lower = "blank",
title = "Custom Example")
p1 <- ggplot(iris,aes(x = Sepal.Length,y = Sepal.Width)) +
geom_point(size = 1,alpha = 0.3)
p2 <- ggplot(iris,aes(x = Sepal.Width,y = Sepal.Length)) +
geom_point()
custom_iris <- putPlot(custom_iris,p1,2,1)
custom_iris <- putPlot(custom_iris,p2,3,2)
custom_iris
I did that simply by directly following the last example in ?ggpairs.

Related

R: Change number of ticks in ggplot2 with ggthemes::extended_range_breaks()

assume the following MWE:
library(ggplot2)
library(ggthemes)
set.seed(100)
df <- data.frame(x = rnorm(50), y = rnorm(50))
ggplot(df, aes(x,y)) +
geom_point() +
theme_tufte() +
geom_rangeframe() +
scale_x_continuous(breaks = extended_range_breaks()(df$x),
labels = scales::number_format(accuracy = 0.1))+
scale_y_continuous(breaks = extended_range_breaks()(df$y),
labels = scales::number_format(accuracy = 0.1))
From my point of view the number of ticks on the y-axis is not enough, the space between 1.0 and 2.9 is too large and I would like to have another tick at 2.0. Anyone an idea how to do that when working with extended_range_breaks or do I have to switch to manually setting the ticks?
I tried scale_y_continuous(n.breaks = 7) and scale_y_continuous(breaks = extended_range_breaks(n = 7)(df$y) but both don't have an effect.
Not a perfect answer, but at least a work-around for now: change the weights applied to the four optimization components. The parameters are set to w = c(0.25, 0.2, 0.5, 0.05) for simplicity, coverage, density, and legibility. If we set coverage for example to 2 (for the y-axis), the graph changes to the following:
The actual desired goal to simly add (-2,2) was yet not possible with this tweak.

ggplot: place image in corner of panel

I'm trying to find a way to insert an image into the corner of a ggplot panel, without specifying the coordinates manually each time.
In this instance, I'm attempting to place a graphic in the top right.
library(magick)
library(ggplot2)
library(datasets)
homer <- magick::image_read("http://icons.iconarchive.com/icons/jonathan-rey/simpsons/128/Homer-Simpson-04-Happy-icon.png")
g <- ggplot(mpg, aes(class)) +
geom_bar() +
labs(
title = "Count of Auto by Class",
subtitle = "Text to Create More Space")
g + annotation_custom(rasterGrob(homer, interpolate = TRUE),
xmax = Inf, ymax = Inf) +
coord_cartesian(clip = "off")
I have found some examples that come close to solving this:
Inserting an image to ggplot outside the chart area
Corner Labels in ggplot2
But neither quite get there. Specifying the exact location at which to place the image seems to require quite a bit of trial-and-error on each plot created, especially when x is categorical.
I would also like to maintain the size of my original image; the code I've used above seems to stretch it across the plot.
Thanks in advance...much appreciated.
try this
library(grid)
a <- rasterGrob(homer, interpolate = TRUE,
width=unit(1,'cm'),
x = unit(1,"npc"), y = unit(1,"npc"),
hjust = 1, vjust=1)
g + annotation_custom(grob = a)

Secondary / Dual axis - ggplot

I am opening this question for three reasons : First, to re-open the dual-axis discussion with ggplot. Second, to ask if there is a non-torturing generic approach to do that. And finally to ask for your help with respect to a work-around.
I realize that there are multiple discussions and questions on how to add a secondary axis to a ggplot. Those usually end up in one of two conclusions:
It's bad, don't do it: Hadley Wickham answered the same question here, concluding that it is not possible. He had a very good argument that "using separate y scales (not y-scales that are transformations of each other) are fundamentally flawed".
If you insist, over-complicate your life and use grids : for example here and here
However, here are some situations that I often face, in which the visualization would greatly benefit from dual-axis. I abstracted the concepts below.
The plot is wide, hence duplicating the y-axis on the right side would help (or x-axis on the top) would ease interpretation. (We've all stumbled across one of those plots where we need to use a ruler on the screen, because the axis is too far)
I need to add a new axis that is a transformation to the original axes (eg: percentages, quantiles, .. ). (I am currently facing a problem with that. Reproducible example below)
And finally, adding Grouping/Meta information: I stumble across that when using categorical data with multiple-level, (e.g.: Categories = {1,2,x,y,z}, which are "meta-divided" into letters and numerics.) Even though color-coding the meta-levels and adding a legend or even facetting solve the issue, things get a little bit simpler with a secondary axis, where the user won't need to match the color of the bars to that of the legend.
General question: Given the new extensibility features ggplot 2.0.0, is there a more-robust no-torture way to have dual-axis without using grids?
And one final comment: I absolutely agree that the wrong use of dual-axis can be dangerously misleading... But, isn't that the case for information visualization and data science in general?
Work-around question:
Currently, I need to have a percentage-axis (2nd case). I used annotate and geom_hline as a workaround. However, I can't move the text outside the main plot. hjust also didn't seem to work with me.
Reproducible example:
library(ggplot2)
# Random values generation - with some manipulation :
maxVal = 500
value = sample(1:maxVal, size = 100, replace = T)
value[value < 400] = value[value < 400] * 0.2
value[value > 400] = value[value > 400] * 0.9
# Data Frame prepartion :
labels = paste0(sample(letters[1:3], replace = T, size = length(value)), as.character(1:length(value)))
df = data.frame(sample = factor(labels, levels = labels), value = sort(value, decreasing = T))
# Plotting : Adding Percentages/Quantiles as lines
ggplot(data = df, aes(x = sample, y = value)) +
geom_bar(stat = "identity", fill = "grey90", aes(y = maxVal )) +
geom_bar(stat = "identity", fill = "#00bbd4") +
geom_hline(yintercept = c(0, maxVal)) + # Min and max values
geom_hline(yintercept = c(maxVal*0.25, maxVal*0.5, maxVal*0.75), alpha = 0.2) + # Marking the 25%, 50% and 75% values
annotate(geom = "text", x = rep(100,3), y = c(maxVal*0.25, maxVal*0.5, maxVal*0.75),
label = c("25%", "50%", "75%"), vjust = 0, hjust = 0.2) +
theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
theme(panel.background = element_blank()) +
theme(plot.background = element_blank()) +
theme(plot.margin = unit(rep(2,4), units = "lines"))
In response to #1
We've all stumbled across one of those plots where we need to use a ruler on the screen, because the axis is too far
cowplot.
# Assign your original plot to some variable, `gpv` <- ggplot( ... )
ggdraw(switch_axis_position(gpv, axis="y", keep="y"))

How to smartly place text labels beside points of different sizes in ggplot2?

I am trying to make a labeled bubble plot with ggplot2 in R. Here is the simplified scenario:
I have a data frame with 4 variables: 3 quantitative variables, x, y, and z, and another variable that labels the points, lab.
I want to make a scatter plot, where the position is determined by x and y, and the size of the points is determined by z. I then want to place text labels beside the points (say, to the right of the point) without overlapping the text on top of the point.
If the points did not vary in size, I could try to simply modify the aesthetic of the geom_text layer by adding a scaling constant (e.g. aes(x=x+1, y=y+1)). However, even in this simple case, I am having a problem with positioning the text correctly because the points do not scale with the output dimensions of the plot. In other words, the size of the points remains constant in a 500x500 plot and a 1000x1000 plot - they do not scale up with the dimensions of the outputted plot.
Therefore, I think I have to scale the position of the label by the size (e.g. dimensions) of the output plot, or I have to get the radius of the points from ggplot somehow and shift my text labels. Is there a way to do this in ggplot2?
Here is some code:
# Stupid data
df <- data.frame(x=c(1,2,3),
y=c(1,2,3),
z=c(1,2,1),
lab=c("a","b","c"), stringsAsFactors=FALSE)
# Plot with bad label placement
ggplot(aes(x=x, y=y), data=df) +
geom_point(aes(size=z)) +
geom_text(aes(label=lab),
colour="red") +
scale_size_continuous(range=c(5, 50), guide="none")
EDIT: I should mention, I tried hjust and vjust inside of geom_text, but it does not produce the desired effect.
# Trying hjust and vjust, but it doesn't look nice
ggplot(aes(x=x, y=y), data=df) +
geom_point(aes(size=z)) +
geom_text(aes(label=lab), hjust=0, vjust=0.5,
colour="red") +
scale_size_continuous(range=c(5, 50), guide="none")
EDIT: I managed to get something that works for now, thanks to Henrik and shujaa. I will leave the question open just in case someone shares a more general solution.
Just a blurb of what I am using this for: I am plotting a map, and indicating the amount of precipitation at certain stations with a point that is sized proportionally to the amount of precipitation observed. I wanted to add a station label beside each point in an aesthetically pleasing manner. I will be making more of these plots for different regions, and my output plot may have a different resolution or scale (e.g. due to different projections) for each plot, so a general solution is desired. I might try my hand at creating a custom position_jitter, like baptiste suggested, if I have time during the weekend.
It appears that position_*** don't have access to the scales used by other layers, so it's a no go. You could make a clone of GeomText that shifts the labels according to the size mapped,
but it's a lot of effort for a very kludgy and fragile solution,
geom_shiftedtext <- function (mapping = NULL, data = NULL, stat = "identity",
position = "identity",
parse = FALSE, ...) {
GeomShiftedtext$new(mapping = mapping, data = data, stat = stat, position = position,
parse = parse, ...)
}
require(proto)
GeomShiftedtext <- proto(ggplot2:::GeomText, {
objname <- "shiftedtext"
draw <- function(., data, scales, coordinates, ..., parse = FALSE, na.rm = FALSE) {
data <- remove_missing(data, na.rm,
c("x", "y", "label"), name = "geom_shiftedtext")
lab <- data$label
if (parse) {
lab <- parse(text = lab)
}
with(coord_transform(coordinates, data, scales),
textGrob(lab, unit(x, "native") + unit(0.375* size, "mm"),
unit(y, "native"),
hjust=hjust, vjust=vjust, rot=angle,
gp = gpar(col = alpha(colour, alpha),
fontfamily = family, fontface = fontface, lineheight = lineheight))
)
}
})
df <- data.frame(x=c(1,2,3),
y=c(1,2,3),
z=c(1.2,2,1),
lab=c("a","b","c"), stringsAsFactors=FALSE)
ggplot(aes(x=x, y=y), data=df) +
geom_point(aes(size=z), shape=1) +
geom_shiftedtext(aes(label=lab, size=z),
hjust=0, colour="red") +
scale_size_continuous(range=c(5, 100), guide="none")
This isn't a very general solution, because you'll need to tweak it every time, but you should be able to add to the x value for the text some value that's linear depending on z.
I had luck with
ggplot(aes(x=x, y=y), data=df) +
geom_point(aes(size=z)) +
geom_text(aes(label=lab, x = x + .06 + .14 * (z - min(z))),
colour="red") +
scale_size_continuous(range=c(5, 50), guide="none")
but, as the font size depends on your window size, you would need to decide on your output size and tweak accordingly. I started with x = x + .05 + 0 * (z-min(z)) and calibrated the intercept based on the smallest point, then when I was happy with that I adjusted the linear term for the biggest point.
Another alternative. Looks OK with your test data, but you need to check how general it is.
dodge <- abs(scale(df$z))/4
ggplot(data = df, aes(x = x, y = y)) +
geom_point(aes(size = z)) +
geom_text(aes(x = x + dodge), label = df$lab, colour = "red") +
scale_size_continuous(range = c(5, 50), guide = "none")
Update
Just tried position_jitter, but the width argument only takes one value, so right now I am not sure how useful that function would be. But I would be happy to find that I am wrong. Example with another small data set:
df3 <- mtcars[1:10, ]
ggplot(data = df3, aes(x = wt, y = mpg)) +
geom_point(aes(size = qsec), alpha = 0.1) +
geom_text(label = df3$carb, position = position_jitter(width = 0.1, height = 0)) +
scale_size_continuous(range = c(5, 50), guide = "none")

cex equivalent in ggplot2

In my work, I frequently display scatterplots using text labels. That's meant a plot() command, followed by text(). I used cex to adjust to font size to what I wanted it very quickly.
I created a text scatterplot very quickly using qplot. But I can't adjust the size fast. Here's a silly code example:
data(state)
qplot(Income, Population,
data=as.data.frame(state.x77),
geom=c("smooth", "text"), method="lm",
label=state.abb)
Whereas in the old days I'd do:
plot(xlim=range(Income), ylim=range(Population),
data=state.x77, type="n")
text(Income, Population, state.abb,
data=state.x77, cex=.5)
If I wanted the text size halved from what I saw at the defaults (oh, and I'd have to do a linear regression manually and add abline() to get the regression line -- nice to do it all in one via ggplot2).
I know I can add a size adjustment with size, but it's not a relative size adjustment like I'm used to. Hadley tweeted me to say that size is measured in mm, which isn't fully intuitive to me. Since I often adjust the size of the plot, either in R or in LaTeX, an absolute scale isn't as useful to me.
I must be missing something really simple. What is it?
I think you are tyring to adjust the size of the text itself, not the x-axis, right?
Here's an approach using the ggplot() command.
ggplot(data = as.data.frame(state.x77), aes(x = Income, y = Population)) +
geom_smooth(method = "lm", se = FALSE) +
geom_text(aes(label = state.abb), size = 2.5)
qp <- qplot(Income, Population,data=as.data.frame(state.x77),
geom=c("smooth","text"),
method="lm",
label=state.abb)
qp + opts(axis.text.x = theme_text(size = 5))
I think Chase is probably right about wanting points as "labels":
qp <- qplot(Income, Population,data=as.data.frame(state.x77),
geom="smooth",method="lm",label=state.abb)
qp + geom_text(aes(label = state.abb), size = 2.5)
If "text" is given in the geom argument to qplot the default size is used and then gets overwritten (or underwritten as it were in this case). Give Chase the check. (Edit: should make size 2.5)
Edit2: Took digging but I found the way to get ggplot2 to cough up some of its defaults:
https://github.com/hadley/ggplot2/blob/master/R/geom-text.r
GeomText$new()$geom$default_aes
proto method (instantiated with ): function (.)
aes(colour = "black", size = 5, angle = 0, hjust = 0.5, vjust = 0.5,
alpha = 1)
There's got to be a better way....
qp <- qplot(Income, Population,data=as.data.frame(state.x77),
geom="smooth",method="lm",label=state.abb)
qp + geom_text(aes(label = state.abb, cex = 1.2))
Add cex inside aes will get what you want, as quoted from:
aes creates a list of unevaluated expressions. This function also performs partial name matching, converts color to colour, and old style R names to ggplot names (eg. pch to shape, cex to size)
http://docs.ggplot2.org/current/aes.html

Resources