1

I am trying to create a plot with multiple linear lines using ggplot2 in R, where each line represents a response of a separate individual to a change in the environment on the x-axis. I can make this plot no problem using the script provided below, however, I want the length of each line for each individual to represent the range of data each individual was sampled under (some lines will obviously be longer than others).

This link (http://www.intechopen.com/source/html/18476/media/image4.jpeg) will show you how I sort of want to final graph to look like, except I only need 1 frame (not 9), and the lines will vary in length. Also, the data on my x-axis is continuous, not discrete.

It seems that I may need to use geom_linerange, but adjusting ymin and ymax doesn't seem to make sense, since I am actually trying to limit the range over the x-axis.

Any help is greatly appreciated!

This code will produce the plot from the data below.

p <- qplot(dBLevel,LowFreq, group=Male,data=test,geom="line")

Data subset ('Upper' and 'Lower' represent the range of the environmental variable (dBLevel) each 'Male' was sampled under. 'LowFreq' is the response variable to 'dBLevel'.)

test <- structure(list(Male = c(69L, 69L, 69L, 69L, 69L, 113L, 113L, 
113L, 113L, 113L, 126L, 126L, 126L, 126L, 126L, 143L, 143L, 143L, 
143L, 143L, 155L, 155L, 155L, 155L, 155L, 178L, 178L, 178L, 178L, 
178L, 186L, 186L, 186L, 186L, 186L, 193L, 193L, 193L, 193L, 193L
), dBLevel = c(-20L, -10L, 0L, 10L, 20L, -20L, -10L, 0L, 10L, 
20L, -20L, -10L, 0L, 10L, 20L, -20L, -10L, 0L, 10L, 20L, -20L, 
-10L, 0L, 10L, 20L, -20L, -10L, 0L, 10L, 20L, -20L, -10L, 0L, 
10L, 20L, -20L, -10L, 0L, 10L, 20L), LowFreq = c(3093.5, 3142.7, 
3191.9, 3241.2, 3290.4, 3017.7, 3218.1, 3418.6, 3619, 3819.4, 
2986.1, 3251.1, 3516.2, 3781.2, 4046.3, 2776.5, 2793.1, 2809.8, 
2826.4, 2843.1, 3207.8, 3306.2, 3404.5, 3502.8, 3601.2, 2813.1, 
2834.5, 2855.9, 2877.2, 2898.6, 4468.3, 4461.2, 4454.2, 4447.1, 
4440.1, 2498.5, 2596.9, 2695.4, 2793.8, 2892.3), Upper = c(3.7, 
3.7, 3.7, 3.7, 3.7, 12.23, 12.23, 12.23, 12.23, 12.23, -3.96, 
-3.96, -3.96, -3.96, -3.96, -3.22, -3.22, -3.22, -3.22, -3.22, 
-11.34, -11.34, -11.34, -11.34, -11.34, 15.34, 15.34, 15.34, 
15.34, 15.34, -6.75, -6.75, -6.75, -6.75, -6.75, -0.67, -0.67, 
-0.67, -0.67, -0.67), Lower = c(-2.71, -2.71, -2.71, -2.71, -2.71, 
-1.31, -1.31, -1.31, -1.31, -1.31, -16.17, -16.17, -16.17, -16.17, 
-16.17, -15.28, -15.28, -15.28, -15.28, -15.28, -15.79, -15.79, 
-15.79, -15.79, -15.79, -3.79, -3.79, -3.79, -3.79, -3.79, -20.19, 
-20.19, -20.19, -20.19, -20.19, -8.24, -8.24, -8.24, -8.24, -8.24
)), .Names = c("Male", "dBLevel", "LowFreq", "Upper", "Lower"
), row.names = c(NA, 40L), class = "data.frame")
bdemarest
  • 14,397
  • 3
  • 53
  • 56
Gavia_immer
  • 67
  • 1
  • 10
  • It's going to be really hard to help you without a reproducible example (i.e. we'd need the data frame `dbLevel`). – joran Apr 03 '14 at 16:19
  • You just need the data from column dBLevel? Or the data from the actual data frame 'lowfreqblups'? Either way, do you need the whole data frame or just a subset of two individuals? – Gavia_immer Apr 03 '14 at 17:12
  • It is much easier to help if you provide a **minimal, self contained example**. Please check these links for general ideas, and how to do it in R: [**here**](http://stackoverflow.com/help/mcve), [**here**](http://www.sscce.org/), and [**here**](http://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example/5963610#5963610). – Henrik Apr 03 '14 at 20:01
  • I have edited the post to include the minimal code to produce the plot that I currently can make, along with including the raw data for the plot. I apologize for not reading some guidelines beforehand and producing a post that was virutally useless. Thank you for the input! – Gavia_immer Apr 03 '14 at 21:12
  • I'm still trying to work out what you mean by "I want the length of each line for each individual to represent the range of data each individual was sampled under". For example, Male #69 was measured five times. Do you mean that -20 is really equal to -2.71 (and 20 equal to 3.70)? If, so how do the other dBLevel values map onto the interval (-2.71, 3.70)? – bdemarest Apr 04 '14 at 00:07
  • Each 'Male' has 5 'LowFreq' measurements, one for each 'dBLevel': -20, -10, 0, 10, and 20. These 5 measurements combine to form the line for each male that runs from -20 to 20 on the x-axis. However, if possible, I would like to cut the line short based on the 'Upper' and 'Lower' range values for each male. For instance, for male 69, instead of his line running from -20 to 20, it would run from -2.71 to 3.7, but would still have the same slope and intercept at 'dBLevel' 0 as if it did run from -20 to 20. I hope this helps. – Gavia_immer Apr 05 '14 at 01:47

1 Answers1

0

Here is a possible solution that plots a line for each Male, where the slope and intercept are determined by the original data, but the x-range is determined by values of Lower and Upper for that Male.

I have used linear regression lm() to get the line coefficients, and predict() to get y-values for each Lower and Upper value. These values are placed into a data.frame called line_dat.

male_vec = unique(test$Male)

predict_list = list()

for (i in seq(length(male_vec))) {
    male = male_vec[i]
    subdat = test[test$Male == male, ]
    x = subdat[, "dBLevel"]
    y = subdat[, "LowFreq"]
    model = lm(y ~ x)
    new_x = data.frame(x=c(subdat[1, "Lower"], subdat[1, "Upper"]))
    new_y = predict(model, new_x)
    predict_list[[i]] = data.frame(Male=male, dBLevel=new_x$x, LowFreq=new_y)
}

line_dat = do.call(rbind, predict_list)
line_dat
#    Male dBLevel  LowFreq
# 1    69   -2.71 3178.599
# 2    69    3.70 3210.155
# 11  113   -1.31 3392.304
# 21  113   12.23 3663.686
# 12  126  -16.17 3087.594
# 22  126   -3.96 3411.220
# 13  143  -15.28 2784.339
# 23  143   -3.22 2804.419
# 14  155  -15.79 3249.221
# 24  155  -11.34 3292.982
# 15  178   -3.79 2847.761
# 25  178   15.34 2888.642
# 16  186  -20.19 4468.414
# 26  186   -6.75 4458.939
# 17  193   -8.24 2614.257
# 27  193   -0.67 2688.784

library(ggplot2)

p = ggplot(data=line_dat, aes(x=dBLevel, y=LowFreq, group=Male)) +
    geom_line(size=1.0)

ggsave("lines.png", plot=p, height=4, width=6, dpi=150)

enter image description here

bdemarest
  • 14,397
  • 3
  • 53
  • 56
  • I think what you have done is excellent! This is exactly what I was picturing. I will have to take some time to sit down and understand your script as I am not familiar with some of it. Thank you! – Gavia_immer Apr 08 '14 at 22:10