How to declare a vectors of pointers to ggplot graphs?

114 views
Skip to first unread message

Mary

unread,
Feb 3, 2013, 2:20:07 PM2/3/13
to ggp...@googlegroups.com
Is it possible to save a vector of pointers to ggplot graphs? For instance, if one has a number of graphs p1 to p30, such that:

p1 <- ggplot( )
p2 <- ggplot( )

or

p1 <- p + geom_point(....)

Is there some way to create a vector such as p[1], p[2], etc.? I'm asking this so I can refer to the subscript inside a loop like a while loop- am working on saving graphs as a moving series in saveHTML but don't want to say print(p1) print(p2), but rather want to put them inside a For loop. for ....{ print(p(i) } I'm just not sure how to declare the vector, when they are not integer, numeric, nor character, but pointers to graphs.

-Mary

Brandon Hurr

unread,
Feb 3, 2013, 2:49:52 PM2/3/13
to mlho...@avalon.net, ggp...@googlegroups.com
Do it as a list. Should work fine  
--
--
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.


Mary

unread,
Feb 3, 2013, 6:50:06 PM2/3/13
to ggp...@googlegroups.com
I'm not getting it to work as a list, for instance:

library(maps)
library(ggplot2)
ia <- map_data("county", "iowa")
mid_range <- function(x) mean(range(x))
library(plyr)
seats <- ddply(ia, .(subregion), colwise(mid_range, .(lat, long)))

p <- ggplot(ia, aes(long, lat)) +
geom_polygon(aes(group = group), fill = "lightyellow", colour = "grey60") +
geom_text(aes(label = subregion), data = seats, size = 2, angle = 45)
p

q <- list(27)
q[1] <- p

Give an error on the assignment of:

Warning message:
In q[1] <- p :
number of items to replace is not a multiple of replacement length

I'm not clear on what p is in R; if it is a pointer to a graph, wouldn't we need to declare a vector of such pointers, and how does one do so?

-Mary



--- brando...@gmail.com wrote:
> To post: email ggp...@googlegroups.com <javascript:;>
> To unsubscribe: email ggplot2+u...@googlegroups.com <javascript:;>
> 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 <javascript:;>.

Brandon Hurr

unread,
Feb 3, 2013, 7:04:21 PM2/3/13
to mlho...@avalon.net, ggp...@googlegroups.com
Try q[[1]]<-p

I know it works, but I'm not near my computer so I can't test. (Super Bowl). 

Try the assign() function too. 

Dennis Murphy

unread,
Feb 3, 2013, 7:22:53 PM2/3/13
to mlho...@avalon.net, ggp...@googlegroups.com
Hi:

I'm not quite sure in which direction you're headed, but maybe the
following toy example will help. It's not perfect, but it illustrates
the idea.

library(plyr)
library(maps)

ia <- map_data("county", "iowa")
mn <- map_data("county", "minnesota")
wi <- map_data("county", "wisconsin")
state_data <- list(ia, mn, wi)

mid_range <- function(x) mean(range(x))

# Not perfect - spits out more output than intended
plotfun <- function(DF)
{
require(plyr)
require(ggplot2)

seats <- ddply(DF, .(subregion), colwise(mid_range, .(lat, long)))

p <- ggplot(DF, aes(long, lat)) +
geom_polygon( aes(group = group),
fill = "lightyellow", color = "grey60") +
geom_text( data = seats, aes(label = subregion), size = 2, angle = 45 )

p
}

# Apply plotfun to each state's data, save in the list state_seats
state_seats <- llply(state_data, plotfun)

# apply the print() function to each ggplot object in state_seats
# (this is what needs work, as you'll find when you call it)
llply(state_seats, function(x) print(x))
## or somewhat more verbose in output,
## llply(state_seats, print)

Basic idea:

* Combine the input data sets into a list.
* Write a single function that outputs a ggplot object for an
arbitrary input data frame.
* Use a **ply family function to recursively generate the ggplot
objects from the components of the input list; save to another list
object.
* Use another **ply family function to print it.

At a basic level, there is no concept of 'pointers' in R (they exist,
but matter only when doing advanced programming). The above is more
the 'R-way' of doing things - the SAS analogue would be the BY
statement.

HTH,
Dennis

Mary

unread,
Feb 3, 2013, 10:04:03 PM2/3/13
to ggp...@googlegroups.com
Still curious, if we say,

p <- ggplot(...

Then what is p if not a pointer to a graph object? No, I'm not getting this from SAS, but my formal computer science training, such as Pascal (which was about the the time S+ was written so I see similarities). I've taught computer science classes, such as data structures courses about queues. Am not as interested in SAS-like by statements as I am in creating a vector of graphs, such as p[1], p[2], for example 50 state graphs. But the below example actually calls the code to create the graph, rather than dealing with saved graphs each referenced by a vector element.

Is it not possible to have a vector of graph objects? Once can say list(p,q,r), but I'm not sure what that graph object is if it is not a pointer.

On the other thread, will try the double brackets in the morning and let you know. I am animating with saveHTML, but would rather have my graph objects created and tested rather than to call a function to create them right in the saveHTML(), but all the examples of doing this show calling the function that actually creates graphs, not cycling through existing graphs.


-Mary

--- djm...@gmail.com wrote:

Ista Zahn

unread,
Feb 3, 2013, 11:09:00 PM2/3/13
to mlho...@avalon.net, ggp...@googlegroups.com
Hi, hope you don't mind my jumping in here.

On Sun, Feb 3, 2013 at 10:04 PM, Mary <mlho...@avalon.net> wrote:
> Still curious, if we say,
>
> p <- ggplot(...
>
> Then what is p if not a pointer to a graph object?

It _is_ a graph object


No, I'm not getting this from SAS, but my formal computer science
training, such as Pascal (which was about the the time S+ was written
so I see similarities). I've taught computer science classes, such as
data structures courses about queues. Am not as interested in
SAS-like by statements as I am in creating a vector of graphs, such as
p[1], p[2], for example 50 state graphs. But the below example
actually calls the code to create the graph, rather than dealing with
saved graphs each referenced by a vector element.
>
> Is it not possible to have a vector of graph objects?

Technically yes, because lists are vectors. But you cannot use an
atomic vector, you must use a list.

Once can say list(p,q,r), but I'm not sure what that graph object is
if it is not a pointer.

Well I suppose at some level it is: the R language definition says
"Note that in the C code underlying R, all objects are pointers to a
structure with typedef SEXPREC; the different R data types are
represented in C by SEXPTYPE, which determines how the information in
the various parts of the structure is used.". But I'm not sure what
practical importance this has to your original question.

>
> On the other thread, will try the double brackets in the morning and let you know.

Yes, double brackets are the way.

I am animating with saveHTML, but would rather have my graph objects
created and tested rather than to call a function to create them right
in the saveHTML(), but all the examples of doing this show calling the
function that actually creates graphs, not cycling through existing
graphs.

The graphs don't exist as such until they are printed. Until then they
are lists, with print methods that actually draws the graph.

Hope this helps,
Ista

Dennis Murphy

unread,
Feb 4, 2013, 4:01:15 AM2/4/13
to Ista Zahn, mlho...@avalon.net, ggp...@googlegroups.com
Hi:

On Sun, Feb 3, 2013 at 8:09 PM, Ista Zahn <ista...@gmail.com> wrote:
> Hi, hope you don't mind my jumping in here.

Not at all. I appreciate it :)
>
> On Sun, Feb 3, 2013 at 10:04 PM, Mary <mlho...@avalon.net> wrote:
>> Still curious, if we say,
>>
>> p <- ggplot(...
>>
>> Then what is p if not a pointer to a graph object?
>
> It _is_ a graph object

More specifically, saved ggplots are list objects of S3 class gg and
ggplot (which inherits from class gg). The structure of the ia object
in the initial example, associated with the Iowa map, is

str(state_seats[[1]])
List of 9
$ data :'data.frame': 991 obs. of 6 variables:
..$ long : num [1:991] -94.2 -94.2 -94.2 -94.5 -94.7 ...
..$ lat : num [1:991] 41.5 41.2 41.2 41.2 41.2 ...
..$ group : num [1:991] 1 1 1 1 1 1 1 2 2 2 ...
..$ order : int [1:991] 1 2 3 4 5 6 7 9 10 11 ...
..$ region : chr [1:991] "iowa" "iowa" "iowa" "iowa" ...
..$ subregion: chr [1:991] "adair" "adair" "adair" "adair" ...
$ layers :List of 2
..$ :Classes 'proto', 'environment' <environment: 0x0000000010eeaa08>
..$ :Classes 'proto', 'environment' <environment: 0x0000000010f72da0>
$ scales :Reference class 'Scales' [package "ggplot2"] with 1 fields
..$ scales: list()
..and 21 methods, of which 9 are possibly relevant:
.. add, clone, find, get_scales, has_scale, initialize, input, n,
.. non_position_scales
$ mapping :List of 2
..$ x: symbol long
..$ y: symbol lat
$ theme : list()
$ coordinates:List of 1
..$ limits:List of 2
.. ..$ x: NULL
.. ..$ y: NULL
..- attr(*, "class")= chr [1:2] "cartesian" "coord"
$ facet :List of 1
..$ shrink: logi TRUE
..- attr(*, "class")= chr [1:2] "null" "facet"
$ plot_env :<environment: R_GlobalEnv>
$ labels :List of 4
..$ x : chr "long"
..$ y : chr "lat"
..$ group: chr "group"
..$ label: chr "subregion"
- attr(*, "class")= chr [1:2] "gg" "ggplot"

Lists are the most general data structures in R. From this output, one
can see that there are nine components in the list object, several of
which are themselves lists. This is the actual object, not a pointer
to it.

This idea is not unusual in R: for example, any time you fit a model
to data, the returned model object is a list (or more likely, a list
of lists) with a specific class (e.g., lm, glm, loess), and there may
be methods defined for a given class to perform standard operations
such as print, plot or summary.

>
>
> No, I'm not getting this from SAS, but my formal computer science
> training, such as Pascal (which was about the the time S+ was written
> so I see similarities). I've taught computer science classes, such as
> data structures courses about queues. Am not as interested in
> SAS-like by statements as I am in creating a vector of graphs, such as
> p[1], p[2], for example 50 state graphs. But the below example
> actually calls the code to create the graph, rather than dealing with
> saved graphs each referenced by a vector element.

Exactly. This is one of several instances where the behavior of R
differs from that in more formal programming languages. It is,
however, a good idea to become very familiar with the str() function,
as it tells you the exact structure of your R object (data, model
output or function) and gives you some insight into how R manages
different types of data structures.

In R, pointers are generally associated with reference classes, which
are very recent to the language - IIRC, the R5 class debuted in R-2.14
(2011) and a new local reference class will premiere in the upcoming
R-3.0. The traditional classes (S3 and S4) both apply pass-by-value
semantics. gg and ggplot are instances of S3 classes.

>>
>> Is it not possible to have a vector of graph objects?
>
> Technically yes, because lists are vectors. But you cannot use an
> atomic vector, you must use a list.

> length(state_seats)
[1] 3
tells you that state_seats is a vector;

> class(state_seats)
[1] "list"
indicates that the object is a list;

> sapply(state_seats, class)
[,1] [,2] [,3]
[1,] "gg" "gg" "gg"
[2,] "ggplot" "ggplot" "ggplot"
tells you that each entity (i.e., list component) is an object of
class c("gg", "ggplot"). Further investigation with str() (see above)
indicates that each entity is in fact a list of lists containing
information about the various features of the object. A list object
can have arbitrarily many components and each component can have
literally any type of data structure in R.

>
> Once can say list(p,q,r), but I'm not sure what that graph object is
> if it is not a pointer.

It is a vector of gg objects, each of which is a list (of lists).
>
> Well I suppose at some level it is: the R language definition says
> "Note that in the C code underlying R, all objects are pointers to a
> structure with typedef SEXPREC; the different R data types are
> represented in C by SEXPTYPE, which determines how the information in
> the various parts of the structure is used.". But I'm not sure what
> practical importance this has to your original question.
>
>>
>> On the other thread, will try the double brackets in the morning and let you know.
>
> Yes, double brackets are the way.
>
> I am animating with saveHTML, but would rather have my graph objects
> created and tested rather than to call a function to create them right
> in the saveHTML(), but all the examples of doing this show calling the
> function that actually creates graphs, not cycling through existing
> graphs.
>
> The graphs don't exist as such until they are printed. Until then they
> are lists, with print methods that actually draws the graph.

Well stated.
>
> Hope this helps,
> Ista
>
Dennis

Mary

unread,
Feb 4, 2013, 12:09:47 PM2/4/13
to ggp...@googlegroups.com
Thanks so much to Ista and Dennis and everyone who contributed!


Now I can test out my plots such as this:

q <- list(27)

p <- ggplot(...)
q[[1]] <- p


And then in the animation I can play them back like this:

library(animation)
saveHTML(
{
for (i in 1:27)
{
print(q[[i]])
}
}
, img.name = "test", single.opts = "'utf8': false", autoplay = FALSE,
interval = 0.5, imgdir = "claimsplot_dir", htmlfile = "test.html",
ani.height = 600, ani.width = 800, title = "Test",
outdir=getwd())


-Mary

p.s. I think I also learned a lot about R in the lively discussion. I think the most important point was that when we assign a graph to a variable like p, we are saving the instructions on how to create the graph rather than the graph itself. So they are not pointers, but rather they are lists with the information needed to create the graph.

Ista Zahn

unread,
Feb 4, 2013, 12:26:28 PM2/4/13
to mlho...@avalon.net, ggp...@googlegroups.com
On Mon, Feb 4, 2013 at 12:09 PM, Mary <mlho...@avalon.net> wrote:
> Thanks so much to Ista and Dennis and everyone who contributed!

You are welcome! Just one quick clarification below.

>
>
> Now I can test out my plots such as this:
>
> q <- list(27)

The 27 is not needed, and will just be overwritten later. Just do

q <- list()

or, if you really must pre-allocate the length at 27, do

q <- vector("list", 27)

>
> p <- ggplot(...)
> q[[1]] <- p
>
>
> And then in the animation I can play them back like this:
>
> library(animation)
> saveHTML(
> {
> for (i in 1:27)
> {
> print(q[[i]])
> }
> }
> , img.name = "test", single.opts = "'utf8': false", autoplay = FALSE,
> interval = 0.5, imgdir = "claimsplot_dir", htmlfile = "test.html",
> ani.height = 600, ani.width = 800, title = "Test",
> outdir=getwd())
>
>
> -Mary
>
> p.s. I think I also learned a lot about R in the lively discussion. I think the most important point was that when we assign a graph to a variable like p, we are saving the instructions on how to create the graph rather than the graph itself. So they are not pointers, but rather they are lists with the information needed to create the graph.
>

Mary

unread,
Feb 4, 2013, 12:45:49 PM2/4/13
to ggp...@googlegroups.com
That's great! Then I don't have to know in advance how many graphs I will have in my slide show.

-Mary

--- ista...@gmail.com wrote:

From: Ista Zahn <ista...@gmail.com>
To: mlho...@avalon.net
Cc: ggp...@googlegroups.com
Subject: Re: How to declare a vectors of pointers to ggplot graphs?
Reply all
Reply to author
Forward
0 new messages