Drawing labels on contour lines

3,247 views
Skip to first unread message

fgg

unread,
Jul 11, 2013, 11:32:42 AM7/11/13
to ggp...@googlegroups.com
Hi there,

Is there a way to draw labels on contour lines when using geom_contour() or a similar ggplot2 function? Here's an example:

library(reshape2) #for melt
volcano3d <- melt(volcano)
names(volcano3d) <- c("x", "y", "z")
ggplot(volcano3d, aes(x, y, z = z)) +
geom_contour()

... and here's what I'm looking for:

contour(volcano)


Thanks! 

Rebecca Clark

unread,
Sep 20, 2013, 12:29:14 PM9/20/13
to ggp...@googlegroups.com
Hello,

I have the same question, and it looks like this original question never received any replies.  I've found some information on using 'directlabels' to append labels, but they don't look quite as nice for my purposes as the options from contour(), which offers 3 methods, 'simple', 'edge', and 'flattest' (the default), and incorporates the labels right into the contours (introducing a break in the contour for the label).  Here's what I found for ggplot2 via StackOverflow:

http://stackoverflow.com/questions/13627735/stat-contour-with-data-labels-on-lines

Cheers,
Rebecca Clark

Ista Zahn

unread,
Sep 20, 2013, 1:33:48 PM9/20/13
to Rebecca Clark, ggplot2
Another approach, which is even uglier but does not depend on
direct.labels is something like

library(ggplot2)
library(reshape2)

volcano3d <- melt(volcano)
names(volcano3d) <- c("x", "y", "z")

p <- ggplot(volcano3d, aes(x, y, z = z)) +
geom_contour()

tmp <- ggplot_build(p)$data[[1]]

p + geom_text(aes(label=level, z=NULL), data=subset(tmp, x==50))

Best,
Ista
> --
> --
> You received this message because you are subscribed to the ggplot2 mailing
> list.
> Please provide a reproducible example:
> https://github.com/hadley/devtools/wiki/Reproducibility
>
> To post: email ggp...@googlegroups.com
> To unsubscribe: email ggplot2+u...@googlegroups.com
> More options: http://groups.google.com/group/ggplot2
>
> ---
> You received this message because you are subscribed to the Google Groups
> "ggplot2" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to ggplot2+u...@googlegroups.com.
> For more options, visit https://groups.google.com/groups/opt_out.

Rebecca Clark

unread,
Sep 20, 2013, 2:28:54 PM9/20/13
to ggplot2
Good point, Ista.  It does seem to me that a method depending on geom_text would be more straightforward in the long run.  I'm stuck on the problem of figuring out how contour() is calculating/assigning 'flattest' - knowing that should allow me to place geom_text() labels pleasingly, I'd think.  For a bit more backstory on what I'm working with: http://stackoverflow.com/questions/18881546/creating-a-trellised-faceted-thin-plate-spline-response-surface

Cheers,
Rebecca Clark

Rebecca Clark

unread,
Feb 22, 2014, 11:45:46 PM2/22/14
to ggplot2
Hi all,

I'm resurrecting this thread to point to a mostly-completed update to an older question, in the hopes that someone here might be up for the challenge of helping finish the (hopefully now simpler) job.  One part should be pretty easy, the other part probably involves digging through the plot3d code some more.

The backstory: I have to create a lot of faceted contour plots, and want to apply labels to the contour lines that resemble the labels from contour() in base.  I'm almost there, but (1) right now all of the labels are appearing in both facets, and (2) I haven't gotten to the step of erasing segments and rotating/fitting text. I'll include the full reproducible example at the end here, and here is a link to the stackoverflow answer I have so far:

http://stackoverflow.com/a/21941774/2464894

Thanks,
Rebecca Clark


library(fields)
library(ggplot2)
library(reshape)

sumframe<-structure(list(Morph = c("LW", "LW", "LW", "LW", "LW", "LW", "LW", "LW", "LW", "LW", "LW", "LW", "LW", "SW", "SW", "SW", "SW", "SW", "SW", "SW", "SW", "SW", "SW", "SW", "SW", "SW"), xvalue = c(4, 8, 9, 9.75, 13, 14, 16.25, 17.25, 18, 23, 27, 28, 28.75, 4, 8, 9, 9.75, 13, 14, 16.25, 17.25, 18, 23, 27, 28, 28.75), yvalue = c(17, 34, 12, 21.75, 29, 7, 36.25, 14.25, 24, 19, 36, 14, 23.75, 17, 34, 12, 21.75, 29, 7, 36.25, 14.25, 24, 19, 36, 14, 23.75), zvalue = c(126.852666666667, 182.843333333333, 147.883333333333, 214.686666666667, 234.511333333333, 198.345333333333, 280.9275, 246.425, 245.165, 247.611764705882, 266.068, 276.744, 283.325, 167.889, 229.044, 218.447777777778, 207.393, 278.278, 203.167, 250.495, 329.54, 282.463, 299.825, 286.942, 372.103, 307.068)), .Names = c("Morph", "xvalue", "yvalue", "zvalue"), row.names = c(NA, -26L), class = "data.frame")

# Subdivide, calculate surfaces, recombine for ggplot.  There may be a workaround with rsm() too.
sumframeLW<-subset(sumframe, Morph=="LW")
sumframeSW<-subset(sumframe, Morph="SW")

surf.teLW<-Tps(cbind(sumframeLW$xvalue, sumframeLW$yvalue), sumframeLW$zvalue, lambda=0.01)
surf.te.outLW<-predict.surface(surf.teLW)

surf.teSW<-Tps(cbind(sumframeSW$xvalue, sumframeSW$yvalue), sumframeSW$zvalue, lambda=0.01)
surf.te.outSW<-predict.surface(surf.teSW)

sumframe$Morph<-as.numeric(as.factor(sumframe$Morph))

LWsurfm<-melt(surf.te.outLW)
LWsurfm<-rename(LWsurfm, c("value"="z", "X1"="x", "X2"="y"))
LWsurfms<-na.omit(LWsurfm)
LWsurfms[,"Morph"]<-c("LW")

SWsurfm<-melt(surf.te.outSW)
SWsurfm<-rename(SWsurfm, c("value"="z", "X1"="x", "X2"="y"))
SWsurfms<-na.omit(SWsurfm)
SWsurfms[,"Morph"]<-c("SW")

LWSWsurf<-rbind(LWsurfms, SWsurfms)
# Note that I've lost my units - things have been rescaled to be between 0 and 80.

LWSWc<-ggplot(LWSWsurf, aes(x,y,z=z))+facet_wrap(~Morph)+geom_contour(colour="black", size=0.6)
# This is used to create a data frame:
tmp3<-ggplot_build(LWSWc)$data[[1]]

flattenb <- function (tmp3){
    counts = length(tmp3$group)
    xdiffs = diff(tmp3$x)
    ydiffs = diff(tmp3$y)
    avgGradient = ydiffs/xdiffs
    squareSum = avgGradient * avgGradient
    variance = (squareSum - (avgGradient * avgGradient) / counts / counts)
    data.frame(variance = c(9999999, variance) #99999 pads this so the length is same as original and the first values are not selected
    )
}

tmp3<-cbind(tmp3, ddply(tmp3, 'group', flattenb))
tmp3l<-ddply(tmp3, 'group', subset, variance==min(variance))

LWSWpp<-ggplot(LWSWsurf, aes(x,y,z=z))+facet_wrap(~Morph)
LWSWpp<-LWSWpp+geom_tile(aes(fill=z))+stat_contour(aes(x,y,z=z, colour=..level..), colour="black", size=0.6)
LWSWpp<-LWSWpp+scale_fill_gradientn(colours=tim.colors(128))
LWSWpp<-LWSWpp+geom_text(data=tmp3l, aes(z=NULL, label=level))
LWSWpp

Brandon Hurr

unread,
Feb 23, 2014, 2:59:18 AM2/23/14
to Rebecca Clark, ggplot2
It's due to the date being used in this line:
LWSWpp<-LWSWpp+geom_text(data=tmp3l, aes(z=NULL, label=level))

In your tmp3l dataframe you need a column called morph that has values LW or SW so that it knows which label to put it which facet. I did this manually with this:

tmp3l$Morph<-rep(c("LW", "SW"), 8)

ggplot(LWSWsurf, aes(x,y,z=z))+
geom_tile(aes(fill=z))+
stat_contour(aes(x,y,z=z, colour=..level..), colour="black", size=0.6)+
scale_fill_gradientn(colours=tim.colors(128))+
geom_text(data=tmp3l, aes(z=NULL, label=level))+
facet_wrap(~Morph)

However... it doesn't quite work and I'm not sure why. There are definitely fewer labels, but a few of them are repeated and that should not happen. Inline image 1

Rebecca Clark

unread,
Feb 26, 2014, 11:36:18 AM2/26/14
to ggplot2
Brandon and Dennis,

Thank you both for the feedback.  I'm making good progress on this fussy task overall, but it's a project I keep having to back-burner.  When I finally have a full function put together, I'll share an update (maybe sometime in the next couple of months, ha).

Brandon: your suggestion worked - the 'tmp3l' data frame was organized with all of the LW first, then all of the SW, so I just had to reorganize the order: c(rep("LW", times=8), rep("SW", times=8)).  Thank you!

I would also note that I've tested out a lot of the alternate methods in lattice, including wireframe(), levelplot(), and cloud() [noted here in case these help anyone else].  Aesthetically, they aren't quite as nice for my purposes yet, or I don't understand how to tweak them properly.

Cheers,
Rebecca Clark


Reply all
Reply to author
Forward
0 new messages