How to plot with a specific distance between each line

I'm actually trying to build a drawing, but it puts and shows all the columns (rows) on top of each other, so it is not representative. I am trying to make simulated data and show you how I earned it, and also show you what I want.

I don’t know how to make an example like below, but here is what I do

set.seed(1) M <- matrix(rnorm(20),20,5) x <- as.matrix(sort(runif(20, 5.0, 7.5))) df <- as.data.frame(cbind(x,M)) 

After creating the data frame, I will build all the columns compared to the first, melting it and using ggplot

 require(ggplot2) require(reshape) dff <- melt(df , id.vars = 'V1') b <- ggplot(dff, aes(V1,value)) + geom_line(aes(colour = variable)) 

I want to have a specific distance between each line (in this case we have 6) something like below. in one dimension it is V1, in another dimension it is the number of columns. I don't care about the function, I just want a photo

+8
r
source share
3 answers

This solution uses rgl and creates this graph:

enter image description here

It uses this function, which takes 3 arguments:

  • df : a data.frame exactly the same as your "M" above
  • x : a numeric vector (or a 1-col data.frame`) for the x axis
  • cols : (optionnal) a vector of colors to repeat. If absent, a black line is drawn

Here is the function:

 nik_plot <- function(df, x, cols){ require(rgl) # if a data.frame is if (is.data.frame(x) && ncol(x)==1) x <- as.numeric(x[, 1]) # prepare a vector of colors if (missing(cols)) cols <- rep_len("#000000", nrow(df)) else cols <- rep_len(cols, nrow(df)) # initialize an empty 3D plot plot3d(NA, xlim=range(x), ylim=c(1, ncol(df)-1), zlim=range(df), xlab="Mass/Charge (M/Z)", ylab="Time", zlab="Ion Spectra", box=FALSE) # draw lines, silently silence_please <- sapply(1:ncol(df), function(i) lines3d(x=x, y=i, z=df[, i], col=cols[i])) } 

Note that you can remove require(rgl) from the function and library(rgl) somewhere in the script, for example, at the beginning.

If you do not have rgl , then install.packages("rgl") .

Black lines by default can cause a moire effect, but a repeating color palette is worse. It may be brain dependent. One color will also avoid artificial measurement (and strong).

Example below:

 # black lines nik_plot(M, x) # as in the image above nik_plot(M, x, "grey40") # an unreadable rainbow nik_plot(M, x, rainbow(12)) 

The 3D window can be moved with the mouse.

Do you need something else?


EDIT

You can build your second plot using the function below. The range of your data is so large, and I think the whole idea of ​​shifting up and up on each line prevents the presence of the Y axis with a reliable scale. Here I normalized all signals (0 <= signal <= 1). In addition, the gap parameter can be used for this. We could disable two behaviors, but I think it’s nice. Try different gap values ​​and see examples below.

  • df : a data.frame exactly the same as your "M" above
  • x : a numeric vector (or a 1-col data.frame`) for the x axis
  • cols : (optionnal) a vector of colors to repeat. If absent, a black line is drawn
  • gap : gap coefficient between individual lines
  • more_gap_each : every n lines get a bigger gap ...
  • more_gap_relative : ... and there will be a gap x more_gap_relative wide

Here is the function:

 nik_plot2D <- function(df, x, cols, gap=10, more_gap_each=1, more_gap_relative=0){ if (is.data.frame(x) && ncol(x)==1) x <- as.numeric(x[, 1]) # we normalize ( 0 <= signal <= 1) df <- df-min(df) df <- (df/max(df)) # we prepare a vector of colors if (missing(cols)) cols <- rep_len("#00000055", nrow(df)) else cols <- rep_len(cols, nrow(df)) # we prepare gap handling. there is probably more elegant gaps <- 1 for (i in 2:ncol(df)) gaps[i] <- gaps[i - 1] + 1/gap + ifelse((i %% more_gap_each) == 0, (1/gap)*more_gap_relative, 0) # we initialize the plot plot(NA, xlim=range(x), ylim=c(min(df), 1+max(gaps)), xlab="Time", ylab="", axes=FALSE, mar=rep(0, 4)) axis(1) # finally, the lines silent <- lapply(1:ncol(df), function(i) lines(x, df[, i] + gaps[i], col=cols[i])) } 

We can use it with (default):

 nik_plot2D(M, x) # gap=10 

And you get this plot:

enter image description here

or

 nik_plot2D(M, x, 50) 

enter image description here

or, with flowers:

 nik_plot2D(M, x, gap=20, cols=1:3) nik_plot2D(M, x, gap=20, cols=rep(1:3, each=5)) 

or, still with flowers, but with big gaps:

 nik_plot2D(M, x, gap=20, cols=terrain.colors(10), more_gap_each = 1, more_gap_relative = 0) # no gap by default nik_plot2D(M, x, gap=20, cols=terrain.colors(10), more_gap_each = 10, more_gap_relative = 4) # large gaps every 10 lines nik_plot2D(M, x, gap=20, cols=terrain.colors(10), more_gap_each = 5, more_gap_relative = 2) # small gaps every 5 lines 

enter image description here

+8
source share

As others have pointed out, your data has very large peaks, and it's unclear if you want to overlap some curves,

enter image description here

 m <- read.table("~/Downloads/M.txt", head=T) fudge <- 0.05 shifty <- function(m, fudge=1){ shifts <- fudge * max(abs(apply(m, 2, diff))) * seq(0, ncol(m)-1) m + matrix(shifts, nrow=nrow(m), ncol=ncol(m), byrow=TRUE) } par(mfrow=c(1,2), mar=c(0,0,1,0)) cols <- colorRampPalette(blues9[4:9])(ncol(m)) matplot(shifty(m), t="l", lty=1, bty="n", yaxt="n", xaxt="n", ylab="", col=cols) title("no overlap") matplot(shifty(m, 0.05), t="l", lty=1, bty="n", yaxt="n", xaxt="n", ylab="", col=cols) title("some overlap") 

Alternatively, you can use some outlier / peak detection scheme to filter them before calculating the offset between the curves,

 library(outliers) shifty2 <- function(m, outliers = 10){ tmp <- m for(ii in seq_len(outliers)) tmp <- rm.outlier(tmp, median = TRUE) shifts <- max(abs(apply(tmp, 2, diff))) * seq(0, ncol(m)-1) m + matrix(shifts, nrow=nrow(m), ncol=ncol(m), byrow=TRUE) } matplot(shifty2(m), t="l", lty=1, bty="n", yaxt="n", xaxt="n", ylab="", col=cols) 

enter image description here

(there are probably good algorithms to decide which points to remove, but I don't know them)

+5
source share

For 3D building, I prefer the rgl package. This should be close to your desired solution.
The color of each scan changes every third.

 library(rgl) M<-read.table("M.txt", sep="\t", header = TRUE, colClasses = "numeric") x<-read.table("x.txt", sep="\t", header = TRUE) n<-ncol(M) M[M<1]<-1 plot3d(x='', xlim=range(x$Time), ylim=c(1, n), zlim=(range(M)), box=FALSE) sapply(seq(1,n), function(t){lines3d(x$Time, y=t*10, z=(M[,t])/10000, col=t/3+1)}) title3d(xlab="scan", ylab="time", zlab="intensity") title3d(main ="Extracted Spectra Subset") axes3d() #axis3d(edge="x") #axis3d(edge="y") #axis3d(edge="z") 

Whether there are huge differences in the size of the data points, I needed to scale some factors to make a readable graph. The intensity ranges from 0 to almost 1,000,000, which distorts the graph. An attempt to normalize by taking ln, but the graph became unreadable.

0
source share

All Articles