Varying axis labels formatter per facet in ggplot/R - r

I have a dataframe capturing several measures over time that I would like to visualize a 3x1 facet. However, each measure contains different units/scales that would benefit from custom transformations and labeling schemes.
So, my question is: If the units and scales are different across different facets, how can I specify a custom formatter or transformation (i.e., log10) to a particular axis within a facet?
For example, let's say I have the data:
df = data.frame(dollars=10^rlnorm(50,0,1), counts=rpois(50, 100))
melted.df = melt(df, measure.var=c("dollars", "counts"))
How would one go upon setting up a 2x1 facet showing dollars and counts over the index with labels=dollars and scale_y_continuous(trans = "log10", ...) for the df$dollars data?
Thank you!

As you discovered, there isn't an easy solution to this, but it comes up a lot. Since this sort of thing is asked so often, I find it helpful to explain why this is hard, and suggest a potential solution.
My experience has been that people coming to ggplot2 or lattice graphics fundamentally misunderstand the purpose of faceting (or trellising, in lattice). This feature was developed with a very specific idea in mind: the visualization of data across multiple groups that share a common scale. It comes from something called the principle of small multiples, espoused by Tufte and others.
Placing panels next to each other with very different scales is something that visual design experts will tend to avoid, because it can be at best misleading. (I'm not scolding you here, just explaining the rationale...)
But of course, once you have this great tool out in the open, you never know how folks are going to use it. So it gets stretched: the requests come in for the ability to allows the scales to vary by panel, and to set various aspects of the plot separately for each panel. And so faceting in ggplot2 has been expanded well beyond its original intent.
One consequence of this is that some things are difficult to implement simply due to the original design intent of the feature. This is likely one such instance.
Ok, enough explanation. Here's my solution.
The trick here is to recognize that you aren't plotting graphs that share a scale. To me, that means you shouldn't even be thinking of using faceting at all. Instead, make each plot separately, and arrange them together in one plot:
library(gridExtra)
p1 <- ggplot(subset(melted.df,variable == 'dollars'),
aes(x = value)) +
facet_wrap(~variable) +
geom_density() +
scale_x_log10(labels = dollar_format())
p2 <- ggplot(subset(melted.df,variable == 'counts'),
aes(x = value)) +
facet_wrap(~variable) +
geom_density()
grid.arrange(p1,p2)
I've just guessed at what geom_* you wanted to use, and I'm sure this isn't really what you wanted to plot, but at least it illustrates the principle.

Related

Remembering steps in R [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed last year.
Improve this question
I am a beginner in R and it might appear irrelevant. But can anyone tell me how to remember syntax? like arguments of ggplot or tidyverse or any other package.
There are a few ways to do that. You can start writing the function and press TAB, it will appear in a pop up. You can also check the cheatsheet, here are some
examples: https://www.rstudio.com/resources/cheatsheets/
Or you can check the help topic by writing the function with a ? in it's start, for example: ?ggplot
OP, your question does not relate to coding per se - no problem to solve via issues with code - so it's not really supposed to be on SO. With that being said, it is a viable question and very daunting to approach using ggplot2 to create plots when you really don't have the background for doing so. Consequently, I think you still deserve a good answer, so here are some principles to help out a new user.
Know where to get information
The biggest help to offer is to practice. You will become more familiar with usage, but even "the pros" forget the argument syntax and what stuff does. In this case, the following is helpful:
Use RStudio. The base R terminal is fully capable; however, RStudio brings a ton of conveniences that make programming in R so much easier. Tooltips are an important part of how I create and use functions in R. If you start typing out a function, you'll be presented with a short list of arguments:
What's more, you can start typing an argument and you'll get a description from the help directly within RStudio:
Check the help for functions. This one should be obvious, but I am constantly checking the help for functions on CRAN. This is easily done in RStudio by typing ? before the function. So, if I need to know the arguments and syntax for geom_point(), I'll type ?geom_point into the console and you'll get the documentation directly within RStudio.
Online Resources. A quick search online can give you a lot of information (maybe even this answer). There are a lot of other resources: here too. Including here, here, here, and here.
Become familiar with the Principles of plotting in ggplot2
Knowing where to get information is helpful, but sometimes you feel so lost that you don't even know what information you actually are looking to get. This is the crux of many of the questions here on SO related to ggplot2, which is: "how can I change my axes?", "How do I change colors in the plot?", or "How can I get a legend to show x, y, or z?". Sometimes you can google, but often it's not even clear what you are looking to find.
This is where a fundamental understanding of how to create a plot in ggplot2 becomes useful. I'll go through how I always approach plotting in ggplot2 and hopefully this will help you out a bit.
Step 1 - prepare data
Making your data prepared to plot is exceptionally useful, and sometimes difficult to do. It's a bit beyond what I intend to communicate here, but a mandatory piece of reading would be regarding Tidy Data Principles.
Step 2 - Think about Mapping
Mapping is often overlooked in the process, but in short, this is how the columns of your dataset relate to the plot. It's easy to say "this column will be my x axis" and "this column will be my y axis", but you should also be clear on if the values of other columns will relate to color, fill, size, shape, etc etc... Thinking this way, it will soon be quite obvious why you would want to get Step 1 correct above, because only Tidy data will be able to be used directly in mapping without issue.
Step 3 - The Fundamental ggplot() call
The first step in plotting will be your first call to ggplot(). Here you need to assign data - example via df %>% ggplot(...) or ggplot(data=df, ...). This is also typically where you would setup at least your x and y axes via mapping. You can just stop here (x and y axes), or you can specify the other aesthetics in the mapping here too. Ultimately, this alone plotted "sets up" the plot. If we just plot the result of that, you get the following:
p <- ggplot(mtcars, aes(disp, mpg))
p
Step 4 - Add your geoms
A "geom" (short for "geometry") describes the shapes and "things" on your plot that will be positioned on the x and y axes. You can add any number, but in this example, we'll add points. If all you want to do is plot the observations at the x and y axes, you just need to add geom_point() and that should be enough:
p + geom_point()
Step 5 - Adding Legends
Note we don't have a legend yet. This is because there are no aesthetics mapped other than x and y. ggplot2 creates legends automatically when you specify in the mapping (via aes()) a characteristic way of differentiating the way we draw a geom. In other words, we can describe color= within aes() and that will initiate the creation of a legend. You can do the same with other aesthetics too.
p + geom_point(aes(color=cyl))
This creates a legend type depending on the type of data mapped. So, a colorbar legend is created here because the column mtcars$cyl is numeric. If we use a non-numeric column, you get a discrete legend:
p + geom_point(aes(color=rownames(mtcars)))
There's advanced stuff too... but not covered here.
Step 6 - Adjusting the Scales
All we do when you specify mapping (i.e. aes(color = ...),) is how the data is mapped to that aesthetic. This does not specify the actual color to be used. If you don't specify, the default coloring or sizing is used, but sometimes you want to change that. You can do that via scale_*_() functions... of which there are many depending on your application. For information on color scales, you can see this answer here... but suffice it to say this is quite a complicated part of the plotting stuff that depends greatly on what you want to do. Many of the scale_() functions are structured similarly, so you can probably get an idea of what you can do with that answer and see. Here's an example of how we can adjust the color with one of these functions:
p + geom_point(aes(color=cyl)) +
scale_color_gradient(low="red", high="green")
Step 7 - Adjusting Labels
Here I usually add the plot labels and axis labels. You can conviently use ylab(), or xlab() or ggtitle() to assign axis labels and the title, or just define them all together with labs(y = ..., x = ..., title = ...). You can also use this time to format and arrange things associated with legends and scales (tick marks and whatnot) via guides(...) (for legends) or the scale_x_*() and scale_y_*() functions (for tick marks on axes).
Step 8 - Theme Elements
Finally, you can change the overall look with various ggplot themes. An account of default themes is given here, but you can extend that with the ggtheme package to get more. You might want to just change a few specific elements of size, color, linetype, etc on the plot. You can address these specific elements via theme(). A helpful list of theme elements is given here.
So, putting it all together you have:
# initial call
ggplot(mtcars, aes(disp, mpg)) +
# geoms
geom_point(aes(color=cyl), size=3) +
# define the color scale
scale_color_viridis_c() +
# define labels and ticks and stuff
# axis
scale_x_continuous(breaks = seq(0, 600, by=50)) +
# legend ticks
guides(color=guide_colorbar(ticks.colour = "black", ticks.linewidth = 3)) +
# Labels
labs(x="Disp", y="Miles per gallon (mpg)", color = "# of \ncylinders", title="Ugly Plot 1.0") +
# theme and theme elements
theme_bw() +
theme(
panel.background = element_rect(fill="gray90"),
panel.grid.major = element_line(color="gray20", linetype=2, size=0.2),
panel.grid.minor = element_line(color="gray70", linetype=2, size=0.1),
axis.text = element_text(size=12, face = "bold"),
axis.text.x = element_text(angle=30, hjust=1)
)
It's a lot of steps, but I break it down like that basically every time. When plot code gets large, I break up the chunks much in that manner above to help clear my mind on how to create the plot.

Problems with Creating Bar Plot In R

Image of Problematic Barplot
Hello everyone, this is my first time posting on Stack Exchange and I will start off by saying that I am a beginner at coding, (like, really a beginner).
I am having issues creating a barplot for one of my classes. (I have attached an image of this problematic barplot in this post).
As you will be able to see, there are two problems with it:
(1) The legend practically blocks out the whole fourth plot
and
(2) I just can't get there to be one color per leaf shape, (there are multiple leaf shapes represented by one color, in other words. I have 13 leaf shapes, I would like 13 different colors, one per shape).
Lastly, here is the code I used to generate the plot:
barplot(shape_biome_table,beside=T,legend.text = T,col=c(1:13),
main="Leaf Shapes By Biome Type",
xlab="Leaf Shape",ylab="Frequency",las=1,
args.legend=list(x="topright"))
If someone can please help me in figuring out what needs to be done to solve these two issues I would be very appreciative. And, as I mentioned previously, I am not very well versed in coding jargon, so please try to make your explanation as easy as possible to understand.
Thank you very much!
R's native plotting support is a bit cumbersome. Perhaps the first thing is to try ggplot2. I've tried to make a guess at what your data looks like.
library(tidyverse)
library(ggplot2)
shape_biome_table <- tribble(
~leaf.shape, ~biome,
"Acicular", "Hawaiian Natives",
"Acicular", "Hawaiian Natives",
"Acuminate", "Hawaiian Natives",
"Aristate", "Mediterranean" )
ggplot(shape_biome_table, aes(x = leaf.shape, fill = leaf.shape)) +
geom_bar() +
facet_grid(. ~ biome)

Unwanted bold-face while putting multiple ggplot charts in the same file

I don't know if you have seen some unwanted bold-face font like picture below:
As you see the third line is bold-faced, while the others are not. This happens to me when I try to use ggplot() with lapply() or specially mclapply(), to make the same chart template based on different data, and put all the results as different charts in a single PDF file.
One solution is to avoid using lapply(x, f) when f() is a function that returns a ggplot() plot, but I have to do so for combining charts (i.e. as input for grid.arrange()) in some situation.
Sorry not able to provide you reproducible example, I tried really hard but was not successful because the size of code and data is too big with several nested functions and when I reduced complexity to make a reproducible example, the problem did not happen.
I asked the question because I guessed maybe someone has faced the same experience and know how to solve it.
My intuition is that it's not actually being printed in bold, but rather double-printed for some reason, which then looks bold. This would explain why it doesn't come up with a simpler example. Especially given your mention of nested functions and probably other complicated structures where it's easy to get an off-by-one or similar error, I would try doing something where you can see exactly what's being plotted -- perhaps by examining the length() of the return value from apply().
Changing the order of elements of the vector, so that the order of the elements in the key is different, may also help. If you consistently get the bold-face on the last element, that also tells you a little bit more about where something is going wrong.
As #Dinre also mentioned, it could also be related to your plotting device. You can try out changing your plotting device. I have my doubts about this though, seeing as it's not a consistent problem. You could also try changing the position of the key, which depending on your plotting device and settings, may move you in or out of a compression block, thus changing which artifacts crop up.
Reproducible example and a solution may be as follows:
library(ggplot2)
d <- data.frame(x=1:10, y=1:10)
ggplot(data = d, aes(x=x, y=y)) +
geom_point() +
geom_text(aes(3,7,label = 'some text 10 times')) +
geom_text(data = data.frame(x=1,y=1),
aes(7,3, label = 'some text one time'))
When we try to add a label by geom_text() manually inserting x and y do not shorten the data. Then same label happen to be printed as many times as the number of rows our data has. Data length may be forced to 1 by replacing data within geom_text().

Indicating the statistically significant difference in bar graph USING R

This is a repeat of a question originally asked here: Indicating the statistically significant difference in bar graph but asked for R instead of python.
My question is very simple. I want to produce barplots in R, using ggplot2 if possible, with an indication of significant difference between the different bars, e.g. produce something like this. I have had a search around but can't find another question asking exactly the same thing.
I know that this is an old question and the answer by Didzis Elferts already provides one solution for the problem. But I recently created a ggplot-extension that simplifies the whole process of adding significance bars: ggsignif
Instead of tediously adding the geom_path and annotate to your plot you just add a single layer geom_signif:
library(ggplot2)
library(ggsignif)
ggplot(iris, aes(x=Species, y=Sepal.Length)) +
geom_boxplot() +
geom_signif(comparisons = list(c("versicolor", "virginica")),
map_signif_level=TRUE)
Full documentation of the package is available at CRAN.
You can use geom_path() and annotate() to get similar result. For this example you have to determine suitable position yourself. In geom_path() four numbers are provided to get those small ticks for connecting lines.
df<-data.frame(group=c("A","B","C","D"),numb=c(12,24,36,48))
g<-ggplot(df,aes(group,numb))+geom_bar(stat="identity")
g+geom_path(x=c(1,1,2,2),y=c(25,26,26,25))+
geom_path(x=c(2,2,3,3),y=c(37,38,38,37))+
geom_path(x=c(3,3,4,4),y=c(49,50,50,49))+
annotate("text",x=1.5,y=27,label="p=0.012")+
annotate("text",x=2.5,y=39,label="p<0.0001")+
annotate("text",x=3.5,y=51,label="p<0.0001")
I used the suggested method from above, but I found the annotate function easier for making lines than the geom_path function. Just use "segment" instead of "text". You have to break things up by segment and define starting and ending x and y values for each line segment.
example for making 3 lines segments:
annotate("segment", x=c(1,1,2),xend=c(1,2,2), y= c(125,130,130), yend=c(130,130,125))

displaying stat_summary accurately on violin plots

I just started using ggplot2 on R and have a violin plot question.
I have a data set that can be accessed here: data.
The data comes from a study of making estimations. The variables of interest are the question.no (questions), condition, estimate.no (tr.est1 or tr.est2) and estimate.
The code below makes the plot look almost the way I want it to look at least for one question, yet the median dots generated by stat_summary() are displayed in between the "violins."
v.data<-read.csv("data.csv")
# loop through each question number
d_ply(v.data, c("question.no"), function(d.plot){
q.no <- v.data$question.no
plot.q <- ggplot(d.plot,aes(condition, estimate, fill=estimate.no)) +
geom_violin() +
stat_summary(fun.y="median", geom="point") +
scale_y_continuous('Change Scores') +
scale_x_discrete("Conditions")
ggsave(filename=paste(q.no,".png",sep=""))
})
My Question: How can I make the median dots display correctly on the "violins" rather than in between them?
I searched the previous questions asked on ggplot2 on this site and looked at the ggplot2 documentation as well as other R forums but have not been able to find anything relevant.
I would appreciate any comments and suggestions as to how I can fix it. Also, if the questions I ask are already answered somewhere else, I would appreciate the links to the threads,too. Many thanks in advance.
stat_summary is limited to the variable that determines your x-axis. One way to convey the information you want would be to replace condition in your call to aes with interaction(condition, estimate.no).
Plotluck is a library based on ggplot2 that aims at automating the choice of plot type based on characteristics of 1-3 variables. For your data set, the command plotluck(v.data, condition, estimate, question.no) generates the following plot:
Note that the library chose to scale y logarithmically. You can override this behavior with plotluck(v.data,condition,estimate,question.no,opts=plotluck.options(trans.log.thresh=1E20)) but it doesn't display well, and the median points look like they are all on the zero line.

Resources