Reputation: 214
I am trying to create an isoline plot with ggplot2. I successfully filled the tiles of the geom_tile() function in groups using the cut() function for breaks. Using this approach, the breaks will be interpreted as strings though, not as values, giving me trouble in the order the guide is set up. This way, e.g. a value of 20 will be interpreted as a bigger number than 180, resulting in fatally misleading colors in the plot, such as this purposely ugly one:
To create this ugly image, I used the following code:
plot.isoline <- function(data, dbr=20, n_interp=200){
library(akima)
library(ggplot2)
library(fields)
data <- read.table(file = "http://s000.tinyupload.com/download.php?file_id=90687695741432763217&t=9068769574143276321730276", header = T)
dint <- interp(x = data$x, y = data$y, z = data$z,
xo = seq(min(data$x), max(data$x), length = n_interp),
yo = seq(min(data$y), max(data$y), length = n_interp))
dat_interp <- data.frame(expand.grid(x=dint$x,y=dint$y), z=c(dint$z))
br <- seq(floor(min(dat_interp$z)/dbr)*dbr, ceiling(max(dat_interp$z)/dbr)*dbr, dbr)
breaks <- cut(dat_interp$z, breaks = br)
breaks <- gsub(","," - ",breaks,fixed=TRUE)
dat_interp$breaks <- sapply(breaks, function(x){strsplit(x, "[( ]")[[1]][[2]]})
ret <- ggplot(dat_interp) +
aes(x=x, y=y, z=z) +
geom_tile(aes(fill=breaks)) +
scale_fill_manual("TEMP", values=tim.colors(length(br)), guide = guide_legend(reverse=TRUE)) +
stat_contour(breaks=br) +
scale_x_continuous(expand=c(0,0)) +
scale_y_continuous(expand=c(0,0))
return(ret)
}
I already tried setting the break strings to values the following way:
dat_interp$breaks <- as.numeric(sapply(breaks, function(x){strsplit(x, "[( ]")[[1]][[2]]}))
This approach only leads to an error "Error: Continuous value supplied to discrete scale". I am sure there has to be a way to order the scale in a numeric way, and I'd be really glad if someone could help me out on this one.
Upvotes: 1
Views: 591
Reputation: 214
With the helpful input of @krlmlr I managed to solve the problem. As he said, the crucial part was to just edit the levels(). For anyone interested, this is the important part:
breaks <- cut(dat_interp$z, breaks = br)
levels(breaks) <- gsub(","," - ", levels(breaks),fixed=TRUE)
dat_interp$breaks <- breaks
levels(dat_interp$breaks) <- as.numeric(sapply(levels(breaks), function(x){strsplit(x, "[( ]")[[1]][[2]]}))
This way I get the following result, properly sorted:
And the full code:
plot.isoline <- function(data, dbr=20, n_interp=200){
library(akima)
library(ggplot2)
library(fields)
data <- read.table(file = "http://s000.tinyupload.com/download.php?file_id=90687695741432763217&t=9068769574143276321730276", header = T)
dint <- interp(x = data$x, y = data$y, z = data$z,
xo = seq(min(data$x), max(data$x), length = n_interp),
yo = seq(min(data$y), max(data$y), length = n_interp))
dat_interp <- data.frame(expand.grid(x=dint$x,y=dint$y), z=c(dint$z))
br <- seq(floor(min(dat_interp$z)/dbr)*dbr, ceiling(max(dat_interp$z)/dbr)*dbr, dbr)
breaks <- cut(dat_interp$z, breaks = br)
levels(breaks) <- gsub(","," - ", levels(breaks),fixed=TRUE)
dat_interp$breaks <- breaks
levels(dat_interp$breaks) <- as.numeric(sapply(levels(breaks), function(x){strsplit(x, "[( ]")[[1]][[2]]}))
ret <- ggplot(dat_interp) +
aes(x=x, y=y, z=z) +
geom_tile(aes(fill=breaks)) +
scale_fill_manual("TEMP", values=tim.colors(length(br)), guide = guide_legend(reverse=TRUE)) +
stat_contour(breaks=br) +
scale_x_continuous(expand=c(0,0)) +
scale_y_continuous(expand=c(0,0))
return(ret)
}
Upvotes: 1
Reputation: 25484
ggplot2
will sort character
values as strings, and factor
values by their level. In your code,
breaks <- gsub(","," - ",breaks,fixed=TRUE)
converts the factor returned by cut
to a character. Try omitting it.
If you need to change the display, use something like
levels(breaks) <- gsub(",", " - ", levels(breaks), fixed=TRUE)
Upvotes: 1