How to scale arrows to approximately fill a plot region?

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

How to scale arrows to approximately fill a plot region?

Michael Friendly
In a variety of graphic applications, I plot some data, together with
arrows representing variables
or linear transformations of variables as vectors in the same space, as
in a biplot.

In my applications, the scale of the arrows is arbitrary -- all that
matters is relative length.
I'd like to blow them up or shrink them to fit the available space in
the plot.
The origin is typically at some mean for (x,y), but that is not
necessarily so.
There must be some general, perhaps approximate solution for this problem,
but I can't see it.

Below is a simple test case.  I found the approximate solution, scale <-
14 by trial and error.
[I'm ignoring aspect ratio, because that determines the bbox I calculate
from the plot.]


set.seed(123135251)
x <- 2 + 5* rnorm(50)
y <- 5 + 2* rnorm(50)
plot(x,y)

# get bounding box of plot region, in data coordinates
bbox <- matrix(par("usr"), 2, 2, dimnames=list(c("min", "max"),c("x", "y")))
# center vectors here
origin <- colMeans(bbox)
points(origin[1], origin[2], pch=16, cex=2)

# vectors to be displayed in this space
vectors <- cbind( runif(5), (runif(5)-.5))

# draw arrows, given origin and length in xy
Arrows <- function(xy, lenxy, length=.1, angle=10, ...) {
         arrows(xy[1], xy[2], xy[1]+lenxy[,1], xy[2]+lenxy[,2],
length=length, angle=angle, ...)
     }

## How to determine scale so that vectors ~ fill the bounding box???
scale <- 14
Arrows(origin, scale*vectors)


--
Michael Friendly     Email: friendly AT yorku DOT ca
Professor, Psychology Dept.
York University      Voice: 416 736-5115 x66249 Fax: 416 736-5814
4700 Keele Street    Web:   http://www.datavis.ca
Toronto, ONT  M3J 1P3 CANADA

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-help
PLEASE do read the posting guide http://www.R-project.org/posting-guide.html
and provide commented, minimal, self-contained, reproducible code.
Reply | Threaded
Open this post in threaded view
|

Re: How to scale arrows to approximately fill a plot region?

Uwe Ligges-3


On 07.12.2011 18:52, Michael Friendly wrote:

> In a variety of graphic applications, I plot some data, together with
> arrows representing variables
> or linear transformations of variables as vectors in the same space, as
> in a biplot.
>
> In my applications, the scale of the arrows is arbitrary -- all that
> matters is relative length.
> I'd like to blow them up or shrink them to fit the available space in
> the plot.
> The origin is typically at some mean for (x,y), but that is not
> necessarily so.
> There must be some general, perhaps approximate solution for this problem,
> but I can't see it.
>
> Below is a simple test case. I found the approximate solution, scale <-
> 14 by trial and error.
> [I'm ignoring aspect ratio, because that determines the bbox I calculate
> from the plot.]
>
>
> set.seed(123135251)
> x <- 2 + 5* rnorm(50)
> y <- 5 + 2* rnorm(50)
> plot(x,y)
>
> # get bounding box of plot region, in data coordinates
> bbox <- matrix(par("usr"), 2, 2, dimnames=list(c("min", "max"),c("x",
> "y")))
> # center vectors here
> origin <- colMeans(bbox)
> points(origin[1], origin[2], pch=16, cex=2)
>
> # vectors to be displayed in this space
> vectors <- cbind( runif(5), (runif(5)-.5))
>
> # draw arrows, given origin and length in xy
> Arrows <- function(xy, lenxy, length=.1, angle=10, ...) {
> arrows(xy[1], xy[2], xy[1]+lenxy[,1], xy[2]+lenxy[,2], length=length,
> angle=angle, ...)
> }
>
> ## How to determine scale so that vectors ~ fill the bounding box???
> scale <- 14
> Arrows(origin, scale*vectors)
>
>

Michael, you know it. Go and grab a coffee, this is school maths:

If you have a starting point and a direction as well as the plotting
region, you can simply calculate a (positive ?) scale so that an arrow
crosses the border. Now do this for all arrows and all borders and take
the minimal positive value. Should be few lines of code only.

Therefore:

scale <- c(sapply(bbox[,"x"] - origin["x"], function(i) i/vectors[,1]),
            sapply(bbox[,"y"] - origin["y"], function(i) i/vectors[,2]))
scale <- min(scale[scale > 0])


Best wishes,
Uwe

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-help
PLEASE do read the posting guide http://www.R-project.org/posting-guide.html
and provide commented, minimal, self-contained, reproducible code.
Reply | Threaded
Open this post in threaded view
|

Re: How to scale arrows to approximately fill a plot region?

Mark Difford
On Dec 07, 2011 at 10:20pm Michael Friendly asked:

> How to scale arrows to approximately fill a plot region?

Michael,

Following Uwe...If you want code that does it then look at what Daniel Chessel did in package ade4:

##
> scatter.dudi
function (x, xax = 1, yax = 2, clab.row = 0.75, clab.col = 1,
    permute = FALSE, posieig = "top", sub = NULL, ...)
{
    if (!inherits(x, "dudi"))
        stop("Object of class 'dudi' expected")
    opar <- par(mar = par("mar"))
    on.exit(par(opar))
    coolig <- x$li[, c(xax, yax)]
    coocol <- x$c1[, c(xax, yax)]
    if (permute) {
        coolig <- x$co[, c(xax, yax)]
        coocol <- x$l1[, c(xax, yax)]
    }
    s.label(coolig, clab = clab.row)
    born <- par("usr")
    k1 <- min(coocol[, 1])/born[1]
    k2 <- max(coocol[, 1])/born[2]
    k3 <- min(coocol[, 2])/born[3]
    k4 <- max(coocol[, 2])/born[4]
    k <- c(k1, k2, k3, k4)
    coocol <- 0.9 * coocol/max(k)
    s.arrow(coocol, clab = clab.col, add.p = TRUE, sub = sub,
        possub = "bottomright")
    add.scatter.eig(x$eig, x$nf, xax, yax, posi = posieig, ratio = 1/4)
}
<environment: namespace:ade4>

Regards, Mark.
Mark Difford (Ph.D.)
Research Associate
Botany Department
Nelson Mandela Metropolitan University
Port Elizabeth, South Africa
Reply | Threaded
Open this post in threaded view
|

Re: How to scale arrows to approximately fill a plot region?

Jim Lemon
In reply to this post by Michael Friendly
On 12/08/2011 04:52 AM, Michael Friendly wrote:

> In a variety of graphic applications, I plot some data, together with
> arrows representing variables
> or linear transformations of variables as vectors in the same space, as
> in a biplot.
>
> In my applications, the scale of the arrows is arbitrary -- all that
> matters is relative length.
> I'd like to blow them up or shrink them to fit the available space in
> the plot.
> The origin is typically at some mean for (x,y), but that is not
> necessarily so.
> There must be some general, perhaps approximate solution for this problem,
> but I can't see it.
>
> Below is a simple test case. I found the approximate solution, scale <-
> 14 by trial and error.
> [I'm ignoring aspect ratio, because that determines the bbox I calculate
> from the plot.]
>
>
> set.seed(123135251)
> x <- 2 + 5* rnorm(50)
> y <- 5 + 2* rnorm(50)
> plot(x,y)
>
> # get bounding box of plot region, in data coordinates
> bbox <- matrix(par("usr"), 2, 2, dimnames=list(c("min", "max"),c("x",
> "y")))
> # center vectors here
> origin <- colMeans(bbox)
> points(origin[1], origin[2], pch=16, cex=2)
>
> # vectors to be displayed in this space
> vectors <- cbind( runif(5), (runif(5)-.5))
>
> # draw arrows, given origin and length in xy
> Arrows <- function(xy, lenxy, length=.1, angle=10, ...) {
> arrows(xy[1], xy[2], xy[1]+lenxy[,1], xy[2]+lenxy[,2], length=length,
> angle=angle, ...)
> }
>
> ## How to determine scale so that vectors ~ fill the bounding box???
> scale <- 14
> Arrows(origin, scale*vectors)
>
>
Hi Michael,
Have a look at the vectorField (plotrix) function. This scales the
arrows to the unit cells in the plot, so it's trivial to change the code
in the bottom half of the function to scale to the entire plot.

Jim

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-help
PLEASE do read the posting guide http://www.R-project.org/posting-guide.html
and provide commented, minimal, self-contained, reproducible code.