I honestly don't know why this is being so hard.
I'm creating a simple scatter plot. The x axis is a continuous variable, and at every tick in x I need to plot four points with error bars. I'm using position dodge and everything works fine.
Each point has a different color, size and shape as governed by three further variables: color and shape are governed by factors, size by a continuous variable.
By default, the four points reflect the order of the levels in the color variable (red always left, then green, then blue) but I would like them to reflect the order of the size variable (the continuous one), smallest left and largest right. How do I specify that size should be prioritised when ordering points in position dodge? I tried using reverse ordering but then the points are ordered first according to the shape legend.
I could change the mapping between variable and aesthetics (all variables are fundamentally continuous and could be used with size) but I think it'd be useful to know how to specify the order in which multiple variables should be considered when dodging points.
The question is somewhat unclear unfortunately. You don't show "a simple scatter plot". You are showing some statistics (mean with error band??) for specific x values - although this is seemingly continuous, this looks as if you have categorised it beforehand - resulting in some summary statistics which you are plotting.
Also, it is not easy (impossible) to fully help you without knowing what you have done until now to come to where you are.
I have tried to reproduce a similar looking plot with mtcars.
Dodging is only possible by one group (but one group can contain more than one variable). To specify how to group, add group = ... to your aesthetics.
Like so:
library(tidyverse)
ggplot(filter(mtcars, carb %in% 1:4)) +
geom_point(aes(carb, mpg, size= gear, group = gear, shape = as.character(vs), color = as.factor(cyl)),
position = position_dodge(width = .5))
This is now dodged by gear, which is also used as size aesthetic.
Related
I am currently trying to plot some data with dots and lines. My dataframe has an own column (FarbDots) in which I specify my wanted colours. When I try to plot the data, geom_point takes the colours in the wanted order, while geom_lines() creates a total mess (see image).
I was not able to recreate the same effect in a sample data set. Any idea on how to get my colours in order while still specifying them within the geom_line()/ geom_point()?
This is the code I used for plotting: (with b specifying the dataset, x, y, and groups)
b +
geom_line(colour=Data_Biol_long$FarbDots)+
geom_point(colour=Data_Biol_long$FarbDots)+
scale_y_log10()+
facet_grid(Analysis~., scale='free')
dots and lines should receive colour from same vector?!
Context: when you have "many" categories it can become hard to distinguish them in a bar plot. I found the plot below dealing with this situation quite nicely by linking the legend with categories in the plot.
Question: is it possible to do something similar with ggplot2?
With ggplot2 it is straighforward to get this:
But I really do not know were to start to acheive the result shown in the 1st plot.
Here is some code to sort it out:
library(ggplot2)
ggplot(data = mtcars, aes(x = vs, y = disp, fill = factor(carb))) +
geom_bar(stat = "identity")
Expected output (not as nice as the one presented above but it shows the idea)
There is no proper legend on the axes in any of the plots, but my guess is that the desired chart is based on relative frequencies, while your plot seems to show absolute frequencies, though I'm not sure about that.
Assuming that you want to produce a stacked bar chart giving the (relative) number of observations of a categorial variable in two groups, there are two ways to get the two stacked bars to be of the same height:
There need to be the exact same amount of observations in both of
them. Then you can use absolute frequencies.
The absolute frequencies need to be transformed to relative frequencies (or percent) by dividing them by the total number of observations in each group.
You can calculate the relative frequencies yourself and use them as the y-values.
Or refer to this post, as it seems to describe exactly what you want using ggplot2.
I come to encounter a problem that using two different data with the help of second axis function as described in this previous post how-to-use-facets-with-a-dual-y-axis-ggplot.
I am trying to use geom_point and geom_bar but the since the geom_bar data range is different it is not seen on the graph.
Here is what I have tried;
point_data=data.frame(gr=seq(1,10),point_y=rnorm(10,0.25,0.1))
bar_data=data.frame(gr=seq(1,10),bar_y=rnorm(10,5,1))
library(ggplot2)
sec_axis_plot <- ggplot(point_data, aes(y=point_y, x=gr,col="red")) + #Enc vs Wafer
geom_point(size=5.5,alpha=1,stat='identity')+
geom_bar(data=bar_data,aes(x = gr, y = bar_y, fill = gr),stat = "identity") +
scale_y_continuous(sec.axis = sec_axis(trans=~ .*15,
name = 'bar_y',breaks=seq(0,10,0.5)),breaks=seq(0.10,0.5,0.05),limits = c(0.1,0.5),expand=c(0,0))+
facet_wrap(~gr, strip.position = 'bottom',nrow=1)+
theme_bw()
as it can be seen that bar_data is removed. Is is possible to plot them together in this context ??
thx
You're running into problems here because the transformation of the second axis is only used to create the second axis -- it has no impact on the data. Your bar_data is still being plotted on the original axis, which only goes up to 0.5 because of your limits. This prevents the bars from appearing.
In order to make the data show up in the same range, you have to normalize the bar data so that it falls in the same range as the point data. Then, the axis transformation has to undo this normalization so that you get the appropriate tick labels. Like so:
# Normalizer to bring bar data into point data range. This makes
# highest bar equal to highest point. You can use a different
# normalization if you want (e.g., this could be the constant 15
# like you had in your example, though that's fragile if the data
# changes).
normalizer <- max(bar_data$bar_y) / max(point_data$point_y)
sec_axis_plot <- ggplot(point_data,
aes(y=point_y, x=gr)) +
# Plot the bars first so they're on the bottom. Use geom_col,
# which creates bars with specified height as y.
geom_col(data=bar_data,
aes(x = gr,
y = bar_y / normalizer)) + # NORMALIZE Y !!!
# stat="identity" and alpha=1 are defaults for geom_point
geom_point(size=5.5) +
# Create second axis. Notice that the transformation undoes
# the normalization we did for bar_y in geom_col.
scale_y_continuous(sec.axis = sec_axis(trans= ~.*normalizer,
name = 'bar_y')) +
theme_bw()
This gives you the following plot:
I removed some of your bells and whistles to make the axis-specific stuff more clear, but you should be able to add it back in no problem. A couple of notes though:
Remember that the second axis is created by a 1-1 transformation of the primary axis, so make sure they cover the same limits under the transformation. If you have bars that should go to zero, the primary axis should include the untransformed analogue of zero.
Make sure that the data normalization and the axis transformation undo each other so that your axis lines up with the values you're plotting.
Here is an example of the code I'm working with
x<-as.factor(rep(c("tree_mean","tree_qmean","tree_skew"),3))
factor<-c(rep("mfn2_burned_99",3),rep("mfna_burned_5_7",3),rep("mfna_burned_5_7_10_12",3)))
y<-c(0.336457409,-0.347422910,-0.318945621,1.494109367, 0.003578698,-0.019985780,-0.484171146, 0.611589217,-0.322292664)
dat<-as.data.frame(cbind(x,factor,y))
head(dat)
x factor y
tree_mean mfn2_burned_99 -0.3364574
tree_qmean mfn2_burned_99 -0.3474229
tree_skew mfn2_burned_99 -0.3189456
tree_mean mfna_burned_5_7 -0.8269814
tree_qmean mfna_burned_5_7 -0.8088810
tree_skew mfna_burned_5_7 -2.5429226
tree_mean mfna_burned_5_7_10_12 -0.8601206
tree_qmean mfna_burned_5_7_10_12 -0.8474920
tree_skew mfna_burned_5_7_10_12 -2.9854178
I am trying to plot how much x deviates from 0, and facet it by each factor, as so:
ggplot(dat) +
geom_point(aes(x=x,y=y),shape=1,size=3)+
geom_linerange(aes(x=x,ymin=0,ymax=y))+
geom_hline(yintercept=0)+
facet_grid(factor~.)
This works fine when I have three factors (ignore the *: I had a significance column which I have since removed.
Example below:
However, I have 8 factors in total, and faceting obscures the plot such that the distance from zero for each x value gets very distorted.
Example below
So, my question is this: what would be a better way of coding/rendering this plot given my large number of x values and factors using faceting or color coding by factor in ggplot??
I would be very open to color-coding each distance for x by factor rather than faceting, but I have been beating my head against the wall trying to figure out how to even do that in ggplot (very new to ggplot), so I can't yet say if it would make the figure much more interpretable.
One option as you note is to color your point and/or linerange by a factor. You can then use position_dodge to move the points slightly on the x axis.
For example:
ggplot(dat, aes(color = factor)) +
geom_point(aes(x=x,y=y),shape=1,size=3, position = position_dodge(width = 0.5)+
geom_linerange(aes(x=x,ymin=0,ymax=y), position = position_dodge(width =0.5))+
geom_hline(yintercept=0)
I think this would still be difficult with many factors, but with 8 it might suit your purposes.
What is the difference (if any) between geom_bar and geom_histogram in ggplot? They seem to produce the same plot and take the same parameters.
Bar charts provide a visual presentation of categorical data. Examples:
The number of people with red, black and brown hair
Look at the geom_bar help file. The examples are all counts.
Wikipedia page
Histograms are used to plot density of interval (usually numeric) data. Examples,
Distributions of age and height
geom_hist help file. The examples are distribution of movie ratings.
ggplot2
After a bit more investigating, I think in ggplot2 there is no difference between geom_bar and geom_histogram. From the docs:
geom_histogram(mapping = NULL, data = NULL, stat = "bin",
position = "stack", ...)
geom_bar(mapping = NULL, data = NULL, stat = "bin",
position = "stack", ...)
I realise that in the geom_histogram docs it states:
geom_histogram is an alias for geom_bar plus stat_bin
but to be honest, I'm not really sure what this means, since my understanding of ggplot2 is that both stat_bin and geom_bar are layers (with a slightly different emphasis).
The default behavior is the same from both geom_bar and geom_histogram. This is because (and as #csgillespie mentioned), there is an implied stat_bin when you call geom_histogarm (understandable), and it is also the default statistics transformation applied to geom_bar (arguable behavior IMO). That's why you need to specify stat='identity' when you want the to plot the data as is.
The stat='bin' or stat_bin() is a statistical transformation that ggplot does for you. It provides you as output the variables surrounded with two dots (the ..count.. and ..density... If you don't specify stat='bin' you won't get those variables.
geom_bar() is for both x and y-values are categorical data -- so there are spaces between two bars as x-values are factor with distinct levels.
geom_histogram() is for one continuous data and one categorical data. Usually we put the continuous data to the x-axis (so the bars are touching each other as they are continuous) and categorical data to the y-axis.
There is another plot we can use to show the above situation (1 categorical 1 continuous) -- geom_boxplot(). Usually we use y-axis to represent the continuous data as it's going to be a vertical box-and-whisker.