[resent, plus small addition; I do not understand why gmail sent a weird charset.] Dear R wizards: I would love to write a general function that matches the slope of a plotted line in an xy-plot at a particular x,y location. something like x<- (1:10)^2; y<- 40:50; plot( x,y, type="l", xlim=c(0,90) ) srt.at5 = text.at.current.plot.with.slope( x, y, 5); text( x[5],y[5], pos=3, srt=srt.at.5); to do this, I first need to compute the function slope around x[5], which is an easy task. alas, the harder task is that I need to scale this by the plot aspect ratio and the axes. How can a function read this from the current plot? (Has someone written such a function, perhaps more embellished, to save me the debugging effort?) Or, is there an alternative to srt, which slopes the text relative to the existing scale? *** come to think of it, what I would really like is the ability of text to 'snake' itself along the line itself. I doubt that this is easily possible, but I just wanted to ask. help appreciated. sincerely, /ivo welch
srt --- slope text with function?
5 messages · ivo welch, Duncan Murdoch
On 2/4/2006 3:50 PM, ivo welch wrote:
[resent, plus small addition; I do not understand why gmail sent a weird charset.] Dear R wizards: I would love to write a general function that matches the slope of a plotted line in an xy-plot at a particular x,y location. something like x<- (1:10)^2; y<- 40:50; plot( x,y, type="l", xlim=c(0,90) ) srt.at5 = text.at.current.plot.with.slope( x, y, 5); text( x[5],y[5], pos=3, srt=srt.at.5); to do this, I first need to compute the function slope around x[5], which is an easy task. alas, the harder task is that I need to scale this by the plot aspect ratio and the axes. How can a function read this from the current plot?
I haven't done this, but you can presumably work it out from the conversions implied by the "fig", "fin", "plt", and/or "usr" values.
(Has someone written such a function, perhaps more embellished, to save me the debugging effort?) Or, is there an alternative to srt, which slopes the text relative to the existing scale? *** come to think of it, what I would really like is the ability of text to 'snake' itself along the line itself. I doubt that this is easily possible, but I just wanted to ask.
Using strsplit and strwidth you should be able to do it, but it will probably look quite ugly. Duncan Murdoch
Thank you, Duncan. This led me to the info I needed. Here is a
simple utility function that does what I needed---maybe it will come
in helpful for others.
################################################################
#### native.slope computes a suitable srt from a function around
#### a point on a function. This is useful until text() gets
#### an srt parameter that is relative to the coordinate system.
#### (Ideally, R would be able to slope along a function.)
################################################################
native.slope <- function( x, y, where.i,
xlim = par()$xaxp, ylim= par()$yaxp,
asp.ratio = (par()$fin)[1]/(par()$fin)[2] ) {
if (where.i<=1) { return(0); }
if (where.i>=length(y)) { return(0); }
if (length(x)!=length(y)) {
stop("native.slope: Sorry, but x and y must have equal dimensions,
not ", length(x), " and ", length(y), "\n"); }
# native slope in a 1:1 coordinate system
d= ( (y[where.i-1]-y[where.i+1])/(x[where.i-1]-x[where.i+1]) );
if (is.na(d)) return(0); # we do not know how to handle an undefined
spot at a function!
d.m= (ylim[2]-ylim[1])/(xlim[2]-xlim[1]); # now adjust by the axis scale
if (is.na(d)) stop("native.slope: internal error, I do not have
sensible axis dimensions (", xlim, ylim, ")\n");
if (is.na(asp.ratio)) stop("native.slope: internal error, I do not
have a reasonable drawing aspect ratio");
net.slope= d/asp.ratio/d.m;
return(slope = atan(net.slope)/pi*180.0 )
}
# some test code
x<- seq(-10,20,by=0.1)
y<- x*x;
plot( x, y, type="l" );
display= ((1:length(y))%%40 == 0)
for (i in 1:(length(y))) {
if (display[i]) {
points(x[i],y[i], pch=19);
srt= native.slope( x, y, i );
text( x[i], y[i], paste(i,"=",x[i],"=",srt), srt=srt, cex=0.9 );
}
}
On 2/4/06, Duncan Murdoch <murdoch at stats.uwo.ca> wrote:
On 2/4/2006 3:50 PM, ivo welch wrote:
[resent, plus small addition; I do not understand why gmail sent a weird charset.] Dear R wizards: I would love to write a general function that matches the slope of a plotted line in an xy-plot at a particular x,y location. something like x<- (1:10)^2; y<- 40:50; plot( x,y, type="l", xlim=c(0,90) ) srt.at5 = text.at.current.plot.with.slope( x, y, 5); text( x[5],y[5], pos=3, srt=srt.at.5); to do this, I first need to compute the function slope around x[5], which is an easy task. alas, the harder task is that I need to scale this by the plot aspect ratio and the axes. How can a function read this from the current plot?
I haven't done this, but you can presumably work it out from the conversions implied by the "fig", "fin", "plt", and/or "usr" values.
(Has someone written such a function, perhaps more embellished, to save me the debugging effort?) Or, is there an alternative to srt, which slopes the text relative to the existing scale? *** come to think of it, what I would really like is the ability of text to 'snake' itself along the line itself. I doubt that this is easily possible, but I just wanted to ask.
Using strsplit and strwidth you should be able to do it, but it will probably look quite ugly. Duncan Murdoch
Some more experimentation reveals that I need to also adjust for the
plot dimensions. (And there are other issues I probably do not know
yet and totally misprogrammed...just trying to be helpful.)
native.slope <- function( x, y, where.i,
xlim = par()$xaxp, ylim= par()$yaxp,
asp.ratio = (par()$fin)[1]/(par()$fin)[2],
debug =0) {
if (where.i<=1) { return(0); }
if (where.i>=length(y)) { return(0); }
if (length(x)!=length(y)) {
stop("native.slope: Sorry, but x and y must have equal dimensions,
not ", length(x), " and ", length(y), "\n"); }
# native slope in a 1:1 coordinate system
d= ( (y[where.i-1]-y[where.i+1])/(x[where.i-1]-x[where.i+1]) );
if (is.na(d)) return(0); # we do not know how to handle an undefined
spot at a function!
d.m= (ylim[2]-ylim[1])/(xlim[2]-xlim[1]); # now adjust by the axis scale
if (is.na(d)) stop("native.slope: internal error, I do not have
sensible axis dimensions (", xlim, ylim, ")\n");
if (is.na(asp.ratio)) stop("native.slope: internal error, I do not
have a reasonable drawing aspect ratio");
## alas, we also need to take into account the plot region:
pq= par()$plt; plt.distort= (pq[2]-pq[1])/(pq[4]-pq[3]);
net.slope= d/asp.ratio/d.m / plt.distort;
slope = atan(net.slope)/pi*180.0;
if (debug) {
cat("xlim=", par()$xaxp, "\n");
cat("ylim=", par()$yaxp, "\n\n");
cat("native.slope: d=", d, " (",y[where.i-1],y[where.i+1],
x[where.i-1], x[where.i+1],")",
"d.m=",d.m, " (", ylim[2],ylim[1],xlim[2],xlim[1], ")",
"asp.ratio=", (par()$fin)[1], ":", (par()$fin)[2], "==>", net.slope,
"=", slope, "deg\n");
}
return( slope = slope );
}
On 2/4/06, ivo welch <ivowel at gmail.com> wrote:
Thank you, Duncan. This led me to the info I needed. Here is a
simple utility function that does what I needed---maybe it will come
in helpful for others.
################################################################
#### native.slope computes a suitable srt from a function around
#### a point on a function. This is useful until text() gets
#### an srt parameter that is relative to the coordinate system.
#### (Ideally, R would be able to slope along a function.)
################################################################
[old function deleted]
# some test code
x<- seq(-10,20,by=0.1)
y<- x*x;
plot( x, y, type="l" );
display= ((1:length(y))%%40 == 0)
for (i in 1:(length(y))) {
if (display[i]) {
points(x[i],y[i], pch=19);
srt= native.slope( x, y, i );
text( x[i], y[i], paste(i,"=",x[i],"=",srt), srt=srt, cex=0.9 );
}
}
On 2/4/06, Duncan Murdoch <murdoch at stats.uwo.ca> wrote:
On 2/4/2006 3:50 PM, ivo welch wrote:
[resent, plus small addition; I do not understand why gmail sent a weird charset.] Dear R wizards: I would love to write a general function that matches the slope of a plotted line in an xy-plot at a particular x,y location. something like x<- (1:10)^2; y<- 40:50; plot( x,y, type="l", xlim=c(0,90) ) srt.at5 = text.at.current.plot.with.slope( x, y, 5); text( x[5],y[5], pos=3, srt=srt.at.5); to do this, I first need to compute the function slope around x[5], which is an easy task. alas, the harder task is that I need to scale this by the plot aspect ratio and the axes. How can a function read this from the current plot?
I haven't done this, but you can presumably work it out from the conversions implied by the "fig", "fin", "plt", and/or "usr" values.
(Has someone written such a function, perhaps more embellished, to save me the debugging effort?) Or, is there an alternative to srt, which slopes the text relative to the existing scale? *** come to think of it, what I would really like is the ability of text to 'snake' itself along the line itself. I doubt that this is easily possible, but I just wanted to ask.
Using strsplit and strwidth you should be able to do it, but it will probably look quite ugly. Duncan Murdoch
I don't think it's got the slope exactly right - you'll see this if you
go to a really extreme aspect ratio by changing the shape of a window to
be long and thin before you call your code. To fix this:
- use "usr" rather than "xaxp" and "yaxp" to get the limits of the
plot region in user coordinates; those two refer to the ticks, not the
whole plot region as "usr" does.
- "fin" is the whole figure region, not just the plot region; you need
to use "plt" to modify it to find the plot region within it. So I think
the aspect ratio should really be done as
pars <- par("fin", "plt")
asp.ratio <- (diff(pars$plt)[1]*pars$fin[1]) /
(diff(pars$plt)[3]*pars$fin[2])
Some other suggestions:
- split the function into two: one that determines a slope from the
data, and one that converts a slope to an angle suitable for "srt". (I
think the latter would have pretty wide use; the former is pretty
specialized for data the way you're using it).
- use the fact that defaults in a function call can be local variables
in the function, so that you only need one call to par() instead of 4.
(The 4 calls probably take a negigible amount of time, but it just looks
wasteful to make them.)
Duncan Murdoch
On 2/4/2006 5:19 PM, ivo welch wrote:
Thank you, Duncan. This led me to the info I needed. Here is a
simple utility function that does what I needed---maybe it will come
in helpful for others.
################################################################
#### native.slope computes a suitable srt from a function around
#### a point on a function. This is useful until text() gets
#### an srt parameter that is relative to the coordinate system.
#### (Ideally, R would be able to slope along a function.)
################################################################
native.slope <- function( x, y, where.i,
xlim = par()$xaxp, ylim= par()$yaxp,
asp.ratio = (par()$fin)[1]/(par()$fin)[2] ) {
if (where.i<=1) { return(0); }
if (where.i>=length(y)) { return(0); }
if (length(x)!=length(y)) {
stop("native.slope: Sorry, but x and y must have equal dimensions,
not ", length(x), " and ", length(y), "\n"); }
# native slope in a 1:1 coordinate system
d= ( (y[where.i-1]-y[where.i+1])/(x[where.i-1]-x[where.i+1]) );
if (is.na(d)) return(0); # we do not know how to handle an undefined
spot at a function!
d.m= (ylim[2]-ylim[1])/(xlim[2]-xlim[1]); # now adjust by the axis scale
if (is.na(d)) stop("native.slope: internal error, I do not have
sensible axis dimensions (", xlim, ylim, ")\n");
if (is.na(asp.ratio)) stop("native.slope: internal error, I do not
have a reasonable drawing aspect ratio");
net.slope= d/asp.ratio/d.m;
return(slope = atan(net.slope)/pi*180.0 )
}
# some test code
x<- seq(-10,20,by=0.1)
y<- x*x;
plot( x, y, type="l" );
display= ((1:length(y))%%40 == 0)
for (i in 1:(length(y))) {
if (display[i]) {
points(x[i],y[i], pch=19);
srt= native.slope( x, y, i );
text( x[i], y[i], paste(i,"=",x[i],"=",srt), srt=srt, cex=0.9 );
}
}
On 2/4/06, Duncan Murdoch <murdoch at stats.uwo.ca> wrote:
On 2/4/2006 3:50 PM, ivo welch wrote:
[resent, plus small addition; I do not understand why gmail sent a weird charset.] Dear R wizards: I would love to write a general function that matches the slope of a plotted line in an xy-plot at a particular x,y location. something like x<- (1:10)^2; y<- 40:50; plot( x,y, type="l", xlim=c(0,90) ) srt.at5 = text.at.current.plot.with.slope( x, y, 5); text( x[5],y[5], pos=3, srt=srt.at.5); to do this, I first need to compute the function slope around x[5], which is an easy task. alas, the harder task is that I need to scale this by the plot aspect ratio and the axes. How can a function read this from the current plot?
I haven't done this, but you can presumably work it out from the conversions implied by the "fig", "fin", "plt", and/or "usr" values.
(Has someone written such a function, perhaps more embellished, to save me the debugging effort?) Or, is there an alternative to srt, which slopes the text relative to the existing scale? *** come to think of it, what I would really like is the ability of text to 'snake' itself along the line itself. I doubt that this is easily possible, but I just wanted to ask.
Using strsplit and strwidth you should be able to do it, but it will probably look quite ugly. Duncan Murdoch