Change scale on X axis in ggplot in R - r

I am using ggplot (Line graph) and trying to plot my data by week, however when I am plotting the data R automatically shows the weeks by 10, 15, ....
I want o show all the weeks number on my X Axis, e.g. 10,11,12,...

ggplot(...) + geom_line(...) + scale_x_continuous(n.breaks = 30)
You can modify the n.breaks parameter to your liking.

It seems your "weeks" axis is numeric (just the number) rather than a date. To change where the tick marks are indicated for your axis, you can use the breaks= argument of scale_*_continuous() for the numeric scale. Here's an example where you can see how to do this:
df <- data.frame(x=1:20, y=rnorm(20))
p <- ggplot(df, aes(x,y)) + geom_point()
p
By default, the x axis is separated into major breaks of 5. If you wanted breaks every 1, you supply a vector to the breaks= argument:
p + scale_x_continuous(breaks=seq(0,20,by=1))
You can even do odd things, like specify breaks individually if you want:
p + scale_x_continuous(breaks=c(0,5,10,11,12,18,20))

Related

Is there a way to change a continuous axis' labels to be strings in ggplot?

I am creating a line chart in ggplot2 with a continuous y-axis but I would like to change the labels to strings to represent bounds, is this possible? For example, I want all values V<10 = A, 10>V<20 = B, and V>20 = C.
Y<-c(5,15,12,8,12,13,19,24)
Day<-c(1,2,3,4,5,6,7,8)
data <- data.frame(Y, Day)
ggplot(data= data, aes(x=Day, y=Y, group=1))+geom_line()+geom_point()
The label of 10 would be replaced by A, 20 by B and so on.
Hope this is a little clearer, thank you.
You can use scale_y_continuous and relabel the scale using the labels= argument. The key here is to also use breaks= which map back to the original numeric scale and then I'm also using limits= to ensure that we can see the whole alphabet.
ggplot(data= data, aes(x=Day, y=Y, group=1))+geom_line()+geom_point() +
scale_y_continuous(labels=LETTERS, breaks=1:26, limits=c(1,26))

How to format x-axis tick label in sqrt(x) format?

I'm studying the example of coord_trans() of ggplot2:
library(ggplot2)
library(scales)
set.seed(4747)
df <- data.frame(a = abs(rnorm(26)),letters)
plot <- ggplot(df,aes(a,letters)) + geom_point()
plot + coord_trans(x = "log10")
plot + coord_trans(x = "sqrt")
I modified the code plot + coord_trans(x = "log10") as following and get what I expected:
plot + scale_x_log10(breaks=trans_breaks("log10", function(x) 10^x),
labels=trans_format("log10", math_format(10^.x)))
I modified the code plot + coord_trans(x = "sqrt") as following and get a strange x-axis:
plot + scale_x_sqrt(breaks=trans_breaks("sqrt", function(x) sqrt(x)),
labels=trans_format("sqrt", math_format(.x^0.5)))
How could I fix the problem?
I get why you said it was a strange / terrible axis. The documentation for trans_breaks even warns you about this in its first line:
These often do not produce very attractive breaks.
To make it less unattractive, I would use round(,2) so my axis labels only have 2 decimal points instead of the default 8 or 9 - cluttering up the axis. Then I would set a sensible range, say in your case 0 to 5 (c(0,5)).
Finally, you can specify the number of ticks for your axis using n in the trans_breaks call.
So putting it together, here's how you can format your x-axis and its tick label in the scale_x_sqrt(x) format:
plot <- ggplot(df,aes(a,letters)) + geom_point()
plot + scale_x_sqrt(breaks=trans_breaks("sqrt", function(x) round(sqrt(x),2), n=5)(c(0, 5)))
Produces this:
The c(0,5) is passed to pretty(), a lesser-known Base R's function. From the documentation, pretty does the following:
Compute a sequence of about n+1 equally spaced "round" values which cover the range of the values in x.
pretty(c(0,5)) simply produces [1] 0 1 2 3 4 5 in our case.
You can even fine-tune your axis by changing the parameters. Here the code uses 3 decimal points (round(x,3)) and we asked for 3 number of ticks n=3:
plot <- ggplot(df,aes(a,letters)) + geom_point()
plot + scale_x_sqrt(breaks=trans_breaks("sqrt", function(x) round(sqrt(x),3), n=3)(c(0, 5)))
Produces this:
EDIT based on OP's additional comments:
To get round integer values, floor() or round(x,0) works, so the following code:
plot <- ggplot(df,aes(a,letters)) + geom_point()
plot + scale_x_sqrt(breaks=trans_breaks("sqrt", function(x) round(sqrt(x),0), n=5)(c(0, 5)))
Produces this:

How to create geom_boxplot with large amount of continuous x-variables

I have a data frame which contains x-axis numeric bins and continuous y-axis data across multiple categories. Initially, I created a boxplot by making the x-axis bins "factors", and doing a boxplot of the melted data. Reproducible data:
x <- seq(1,10,by=1)
y1 <- rnorm(10, mean=3)
y2 <- rnorm(10, mean=10)
y3<- rnorm(10, mean=1)
y4<- rnorm(10, mean=8)
y5<- rnorm(10, mean=12)
df <- data.frame(x,y1,y2,y3,y4,y5)
df.m <- melt(df, id="x")
My code to create the x-axis data as a factor:
df.m$x <- as.factor(df.m$x)
My ggplot:
ggplot(df.m, aes(x=x, y=value))+
geom_boxplot(notch=FALSE, outlier.shape=NA, fill="red", alpha=0.1)+
theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1))
The resulting plot:
:
The problem is that I cannot use x-axis numeric spacing because the x-axis is categorized as a factor, which has equal spacing. I want to be able to use something like scale_x_continuous to manipulate the axis breaks and spacing to, say, an interval of 2, rather than a boxplot every 1, but when I try to plot the data with the x-axis "as.numeric", I just get one boxplot of all of the data:
Any suggestions for a way to get this continuous-looking boxplot curve (the first image) while still being able to control the numeric properties of the x-axis? Thanks!
Here is a way using the original data you posted on Google - which actually was much more helpful, IMO.
ggplot(df, aes(x=CH, y=value,group=CH))+
geom_boxplot(notch=FALSE, outlier.shape=NA, fill="red", alpha=0.2)+
scale_x_log10()
So, as #BenBolker said before he deleted his answer(??), you should leave the x-variable (CH) as numeric, and set group=CH in the call to aes(...).
With your real data there is another problem though. Your CH is more or less logarithmically spaced, so there are about as many points < 1 as there are between 1 - 10, etc. ggplot wants to make the boxes all the same size, so with a linear x-axis the box width is smaller than the line width, and you don't see the boxes at all. Changing the x-axis to a logarithmic scale fixes that, more or less.
Don't make x a factor. You need to aesthetically map a group that is a factor determining which box the value is associated with, luckily, after melting, this is what you variable column is:
ggplot(df.m, aes(x = x, y = value, group = variable)) +
geom_boxplot()
As x is still numeric, you can give it whatever values you want within a specific variable level and the boxplot will show up at that spot. Or you could transform the x axis, etc.

R - Time series data with ggplot2

I have a time series dataset in which the x-axis is a list of events in reverse chronological order such that an observation will have an x value that looks like "n-1" or "n-2" all the way down to 1.
I'd like to make a line graph using ggplot that creates a smooth, continuous line that connects all of the points, but it seems when I try to input my data, the x-axis is extremely wonky.
The code I am currently using is
library(ggplot2)
theoretical = data.frame(PA = c("n-1", "n-2", "n-3"),
predictive_value = c(100, 99, 98));
p = ggplot(data=theoretical, aes(x=PA, y=predictive_value)) + geom_line();
p = p + scale_x_discrete(labels=paste("n-", 1:3, sep=""));
The fitted line and grid partitions that would normally appear using ggplot are replaced by no line and wayyy too many partitions.
When you use geom_line() with a factor on at least one axis, you need to specify a group aesthetic, in this case a constant.
p = ggplot(data=theoretical, aes(x=PA, y=predictive_value, group = 1)) + geom_line()
p = p + scale_x_discrete(labels=paste("n-", 1:3, sep=""))
p
If you want to get rid of the minor grid lines you can add
theme(panel.grid.minor = element_blank())
to your graph.
Note that it can be a little risky, scale-wise, to use factors on one axis like this. It may work better to use a typical continuous scale, and just relabel the points 1, 2, and 3 with "n-1", "n-2", and "n-3".

How to plot stacked point histograms?

What's the ggplot2 equivalent of "dotplot" histograms? With stacked points instead of bars? Similar to this solution in R:
Plot Histogram with Points Instead of Bars
Is it possible to do this in ggplot2? Ideally with the points shown as stacks and a faint line showing the smoothed line "fit" to these points (which would make a histogram shape.)
ggplot2 does dotplots Link to the manual.
Here is an example:
library(ggplot2)
set.seed(789); x <- data.frame(y = sample(1:20, 100, replace = TRUE))
ggplot(x, aes(y)) + geom_dotplot()
In order to make it behave like a simple dotplot, we should do this:
ggplot(x, aes(y)) + geom_dotplot(binwidth=1, method='histodot')
You should get this:
To address the density issue, you'll have to add another term, ylim(), so that your plot call will have the form ggplot() + geom_dotplot() + ylim()
More specifically, you'll write ylim(0, A), where A will be the number of stacked dots necessary to count 1.00 density. In the example above, the best you can do is see that 7.5 dots reach the 0.50 density mark. From there, you can infer that 15 dots will reach 1.00.
So your new call looks like this:
ggplot(x, aes(y)) + geom_dotplot(binwidth=1, method='histodot') + ylim(0, 15)
Which will give you this:
Usually, this kind of eyeball estimate will work for dotplots, but of course you can try other values to fine-tune your scale.
Notice how changing the ylim values doesn't affect how the data is displayed, it just changes the labels in the y-axis.
As #joran pointed out, we can use geom_dotplot
require(ggplot2)
ggplot(mtcars, aes(x = mpg)) + geom_dotplot()
Edit: (moved useful comments into the post):
The label "count" it's misleading because this is actually a density estimate may be you could suggest we changed this label to "density" by default. The ggplot implementation of dotplot follow the original one of Leland Wilkinson, so if you want to understand clearly how it works take a look at this paper.
An easy transformation to make the y axis actually be counts, i.e. "number of observations". From the help page it is written that:
When binning along the x axis and stacking along the y axis, the numbers on y axis are not meaningful, due to technical limitations of ggplot2. You can hide the y axis, as in one of the examples, or manually scale it to match the number of dots.
So you can use this code to hide y axis:
ggplot(mtcars, aes(x = mpg)) +
geom_dotplot(binwidth = 1.5) +
scale_y_continuous(name = "", breaks = NULL)
I introduce an exact approach using #Waldir Leoncio's latter method.
library(ggplot2); library(grid)
set.seed(789)
x <- data.frame(y = sample(1:20, 100, replace = TRUE))
g <- ggplot(x, aes(y)) + geom_dotplot(binwidth=0.8)
g # output to read parameter
### calculation of width and height of panel
grid.ls(view=TRUE, grob=FALSE)
real_width <- convertWidth(unit(1,'npc'), 'inch', TRUE)
real_height <- convertHeight(unit(1,'npc'), 'inch', TRUE)
### calculation of other values
width_coordinate_range <- diff(ggplot_build(g)$panel$ranges[[1]]$x.range)
real_binwidth <- real_width / width_coordinate_range * 0.8 # 0.8 is the argument binwidth
num_balls <- real_height / 1.1 / real_binwidth # the number of stacked balls. 1.1 is expanding value.
# num_balls is the value of A
g + ylim(0, num_balls)
Apologies : I don't have enough reputation to 'comment'.
I like cuttlefish44's "exact approach", but to make it work (with ggplot2 [2.2.1]) I had to change the following line from :
### calculation of other values
width_coordinate_range <- diff(ggplot_build(g)$panel$ranges[[1]]$x.range)
to
### calculation of other values
width_coordinate_range <- diff(ggplot_build(g)$layout$panel_ranges[[1]]$x.range)

Resources