I know there are many many questions on here around plotting multiple lines in a graph in R, but I've been struggling with a more specific task. I would like to add multiple line segments to a graph using only the intercept and slope specified for each line. abline() would work great for this, except each line has a specific range on the X axis, and I do not want the line plotted beyond the range.
I managed to get the graph I want using plotrix, but I am hoping to publish the work, and the graph does not look up-to-par (very basic). I am somewhat familiar with ggpplot, and think that graphs generated in ggplot look much better than what I have made, especially with the various themes availible, but I cannot figure out how to do something similar using ggplot.
Code:
library(plotrix)
plot(1, type="n", xlab="PM2.5(ug/m3)", ylab="LogRR Preeclampsia ", xlim=c(0, 20), ylim=c(-1, 2.5))
ablineclip(a = 0, b = 0.3, x1=1.2, x2=3)
ablineclip(a = 0, b = 0.08, x1=8.0, x2=13.1)
ablineclip(a = 0, b = 0.5, x1=10.1, x2=18.9)
ablineclip(a = 0, b = 0.12, x1=2.6, x2=14.1)
Any help would be appreciated!
Thank you.
You can write a basic function doing a bit of algebra to calculate the start/stop points for the line segments and then feed that into ggplot. For example
to_points <- function(intercept, slope, start, stop) {
data.frame(
segment = seq_along(start),
xstart = start,
xend = stop,
ystart = intercept + slope*start,
yend = intercept + slope*stop)
}
And then use that with
library(ggplot2)
segments <- to_points(0, c(0.3, 0.08, 0.5, .12),
c(1.2, 8.0, 10.1, 2.6),
c(3, 13.1, 18.9, 14.2))
ggplot(segments) +
aes(xstart, ystart, xend=xend, yend=yend) +
geom_segment() +
coord_cartesian(xlim=c(0,20), ylim=c(-1, 2.5)) +
labs(x="PM2.5(ug/m3)", y="LogRR Preeclampsia ")
That will produce the following plot
(Note the third segment is outside the region you specified. You can drop the coord_cartesian to see all the segments.)
Related
I'm plotting a cumulative step function, and I want to suppress the behavior of the line jumping up after the last row in dataset. This happens both in base R and ggplot2.
Is there a way to do it without specifying xlim to exclude the jump upwards?
data = data.frame(V1 = c(-0.1, 0, 0, 1, 1.1), V2 = c(0, 0, 0.7, 0.3, 0.3))
base R
plot(data$V1, cumsum(data$V2), type="s")
ggplot2
ggplot(data, aes(x=V1, y=cumsum(V2))) +
geom_step()
The way the step function works seems correct to me, if you take sum(data$V2) that is 1.3 and that is where your line ends. It is also identical to tail(cumsum(data$V2), 1). However, if you insist on not drawing the last line segment, you can set the last value of data$V2 to 0. Example below:
library(ggplot2)
data = data.frame(V1 = c(-0.1, 0, 0, 1, 1.1), V2 = c(0, 0, 0.7, 0.3, 0.3))
ggplot(data, aes(x = V1, y = cumsum(c(head(V2, -1), 0)))) +
geom_step()
Note that the example doesn't generalise to multiple groups; pre-processing the data should help then.
I have got a graph like below, except without the red and blue indifference curves (level sets). I know I can use contour() but that creates long curves going from edge to edge.
Is there any way I can create such curves? They don't have to follow a function or any data in particular, I just wanna show the general picture.
You can try with contour
sig <- seq(0,0.25,by=.01)
exr <- seq(0,.20,length.out = length(sig))
# define function
Uf=function(sig,ret,ra=1)ret-0.5*(1/ra)*sig^2
u = outer(sig,exr,function(sd,mr)Uf(sd,mr,ra=0.075))
#image(sig,exr,u)
#contour(sig,exr,u)
contour(sig,exr,u, levels =c(0.04666667, 0.07500000, 0.10333333),col=3,drawlabels = F)
v = outer(sig,exr,function(sd,mr)Uf(sd,mr,ra=0.195))
contour(sig,exr,v, levels =c(0.07333333, 0.09500000, 0.11666667),add = T,col=4,drawlabels = F)
abline(a=0.03,b=0.6666667)
Edit
Uf is a classical quadratic preference function that depends on risk, return and risk aversion. See more information for example here.
outer fist make all possible combination of the supplied vectors sig and exr, then takes every pair of values and computes the utility with Uf. Try head(u) or View(u).
contour takes all values to plot with the desired levels (indifference curves).
abline adds a reference line that you actually have in your plot.
A handmade solution requiring some fiddling with the position and the curvature:
line <- data.frame(x = 0, xend = 0.2, y = 0.03, yend = 0.18)
ggplot(line, aes(x, y, xend=xend, yend=yend)) +
geom_segment() +
annotate(
"curve",
x = 0.02 - c(0, 0.005, 0.01),
y = 0.08 + c(0, 0.01, 0.02),
xend = 0.08 - c(0, 0.005, 0.01),
yend = 0.14 + c(0, 0.01, 0.02),
color = "red", curvature=0.76) +
expand_limits(y = 0)
I'm a beginner with R and looking for help with plotting.
I would like to make a distribution plot in R that looks like a histogram of continuous data bucketed into columns with x-axis labels between each column to denote the range captured in each column.
Instead of continuous data though, I only have the bucketed counts. I can create a plot with barplot, however I can't find a way to label BETWEEN the columns to denote the range captured in each bar.
I've tried barplot but cannot get the labels to fall between columns instead of being treated as column labels and falling directly beneath each column.
dat$freq = c(5,15,20,10)
dat$mid = c(-1.5,-.5,.5,1.5) #midpoint in each bucketed range
dat$perc = dat$freq/sum(dat$freq)
barplot(dat$perc, names.arg = dat$mid)
Each column is labeled with the midpoint. I would instead like the labels to be -2,-1,0,1,2 BETWEEN the columns.
Thank you!
edit: dput(dat) outputs:
list(freq = c(5, 15, 20, 10), mid = c(-1.5, -0.5, 0.5, 1.5), perc =
c(0.1, 0.3, 0.4, 0.2))
Is this what you're after?
df <- data.frame(freq = c(5, 15, 20, 10), mid = c(-1.5, -0.5, 0.5, 1.5), perc = c(0.1, 0.3, 0.4, 0.2))
I'm using the awesome and highly customisable library ggplot2 to plot this, which renders the plot as I think you want it. You can install this with install.packages('ggplot2'):
# install.packages('ggplot2')
library(ggplot2)
p <- ggplot(df)
p <- p + geom_bar(aes(mid, perc), stat='identity')
p
In the ggtern package in R, I am trying to plot two paths of different colors on the same ternery plot, and label their starting points ONLY, could someone show me how to do this, I can get the path on single plots, but not together on the same one, here is my example:
require(ggtern)
require(ggtern)
x <- data.frame(
A = c( 0, 0, 1, 0.1),
B = c( 0, 1, 0, 0.3) ,
C = c( 1, 0, 0, 0.6)
)
yy<-data.frame(
D= c(0.6, 0.2,0.8,0.33 ),
E= c(0.2, 0.8, 0.1,0.33),
F= c(0.2, 0.0, 0.1,0.33)
)
ggtern(data=x,aes(A,B,C)) +
geom_path(color="red")+
geom_point(type="l",shape=21,size=2) +
geom_text(label="", color="blue")+
theme_classic()
ggtern(data=yy,aes(D,E,F)) +
geom_path(color="blue")+
geom_point(type="l",shape=21,size=1) +
theme_classic()
Here I provide an answer to your question, also taking the opportunity to demonstrate some of the additional functionality of ggtern 2.0.1, which was published on CRAN a couple of days ago after completely re-writing the package to be compatible with ggplot2 2.0.0. A summary of the new functionality in ggtern 2.0.X can be found here:
Eric Fail is correct in saying that the best solution requires that the data to be combined into a single dataframe, and the paths either grouped or mapped to a different variable for colour, in order to distinguish between them. An alternate way is to create two(2) path layers, with a local dataframe passed to each geometry, rather than using the global dataframe passed to the ggtern constructor.
In the following solution, I have combined the data, created a 'Series' variable (subsequently mapped to colour), and then made use of the new geom_label(...) geometry that comes with the new version of ggplot2. Since some of the points lie on the perimeter (and the labels extend beyond the perimeter), I have also applied a manual clipping mask under the layers, which suppresses ggterns automatic clipping mask -- normally rendered in the foreground. I have also applied the theme_rotate(...) convenience function for the purposes of demonstration, and made use of the limit_tern(...) convenience function to extend the range of the axes beyond the standard range of [0,1]. Finally, new labels have been created for the procession arrows, which are different from the apex labels.
The above solution can be produced with the following code:
require(ggtern)
df.A <- data.frame(
A = c( 0, 0, 1, 0.1),
B = c( 0, 1, 0, 0.3) ,
C = c( 1, 0, 0, 0.6)
)
df.B <-data.frame(
A= c(0.6, 0.2,0.8,0.33 ),
B= c(0.2, 0.8, 0.1,0.33),
C= c(0.2, 0.0, 0.1,0.33)
)
df = rbind(data.frame(df.A,Series='A'),
data.frame(df.B,Series='B'))
df$Label = 1:nrow(df)
ggtern(data=df,aes(A,B,C,colour=Series)) +
theme_dark() +
theme_legend_position('topleft') +
theme_showarrows() + custom_percent('%') +
theme_rotate(60) +
geom_mask() +
geom_path(size=1) +
geom_label(aes(label=Label),show.legend = F) +
limit_tern(1.1,1.1,1.1) +
labs(title ="Example Combined Paths",
Tarrow = "Value B",
Larrow = "Value A",
Rarrow = "Value C")
I'm fairly new to R so please comment on anything you see.
I have data taken at different timepoints, under two conditions (for one timpoint) and I want to plot this as a bar plot with errorbars and with the bars at the appropriate timepoint.
I currently have this (stolen from another question on this site):
library(ggplot2)
example <- data.frame(tp = factor(c(0, "14a", "14b", 24, 48, 72)), means = c(1, 2.1, 1.9, 1.8, 1.7, 1.2), std = c(0.3, 0.4, 0.2, 0.6, 0.2, 0.3))
ggplot(example, aes(x = tp, y = means)) +
geom_bar(position = position_dodge()) +
geom_errorbar(aes(ymin=means-std, ymax=means+std))
Now my timepoints are a factor, but the fact that there is an unequal distribution of measurements across time makes the plot less nice.!
This is how I imagine the graph :
I find the ggplot2 package can give you very nice graphs, but I have a lot more difficulty understanding it than I have with other R stuff.
Before we get into R, you have to realize that even in a bar plot the x axis needs a numeric value. If you treat them as factors then the software assumes equal spacing between the bars by default. What would be the x-values for each of the bars in this case? It can be (0, 14, 14, 24, 48, 72) but then it will plot two bars at point 14 which you don't seem to want. So you have to come up with the x-values.
Joran provides an elegant solution by modifying the width of the bars at position 14. Modifying the code given by joran to make the bars fall at the right position in the x-axis, the final solution is:
library(ggplot2)
example <- data.frame(tp = factor(c(0, "14a", "14b", 24, 48, 72)), means = c(1, 2.1, 1.9, 1.8, 1.7, 1.2), std = c(0.3, 0.4, 0.2, 0.6, 0.2, 0.3))
example$tp1 <- gsub("a|b","",example$tp)
example$grp <- c('a','a','b','a','a','a')
example$tp2 <- as.numeric(example$tp1)
ggplot(example, aes(x = tp2, y = means,fill = grp)) +
geom_bar(position = "dodge",stat = "identity") +
geom_errorbar(aes(ymin=means-std, ymax=means+std),position = "dodge")