Adjust plots of geographic assignments

16 views
Skip to first unread message

Theresa Schabacker

unread,
Dec 20, 2022, 9:35:43 AM12/20/22
to IsoriX
Hi Alex, hi all!

Thanks for letting me join the group.
I am currently working on a noctule bat data set where we have been using stable hydrogen isotope ratios of bat fur to infere about the spatial origins/migratory strategies of the noctule bats we sampled.
Thanks to the wonderful Chapter 9 (Courtiol et al. 2018) of the "Tracking Animal Migration with Stable Isotopes"-book, I was able to run the isotope analysis using IsoriX. Now I am working on the plots depiciting the geographic assignments of single individuals to be presented in the publication and would like to modify them a bit from the default figure that the following line of code produces (example taken from Alex' publicaton mentioned above):

plot(AssignedBats, who51:14,
                                  sources5list(draw5FALSE),
                                  calibs5list(draw5FALSE))


I was wondering if adjustments to the default appeareance of the plots can be made, and if yes, how.

Specifically I am interested in the following things:
  • increase font size of all characters (labels, axis, titles)
  • add/change (sub)titles: instead of depiciting the batID (Nnoc_xx) I would like to have subtitels stating the migratory strategy (migrant/local)

I have tried several ways of modifying the code but was unable to make any changes to the appearance whatsoever, just as if something was masking it.

I would be very grateful if you could help me out here and appreciate any insight you could provide.

Thanks so much in advance and a happy pre-christmas time to everyone!

Best regards,
Theresa

Alexandre Courtiol

unread,
Dec 20, 2022, 10:55:19 AM12/20/22
to IsoriX
Hi Theresa,
and Welcome to the IsoriX user group,

I will use an example from the package since not everyone has access to the book.
Let us start by creating similar data to those you want to plot:

library(IsoriX)
GNIPDataDEagg <- prepsources(data = GNIPDataDE)
GermanFit <- isofit(data = GNIPDataDEagg, mean_model_fix = list(elev = TRUE, lat_abs = TRUE))
GermanScape <- isoscape(raster = ElevRasterDE, isofit = GermanFit)
CalibAlien <- calibfit(data = CalibDataAlien, isofit = GermanFit)
AssignmentDry <- isofind(data = AssignDataAlien, isoscape = GermanScape, calibfit = CalibAlien)

Before plotting we may want to determine who is likely to be a migrant and who is not.
This could be done as follows:

pv <- sapply(seq_len(nrow(AssignDataAlien)), \(i) extract(AssignmentDry$sample$pv[[i]], cbind(AssignDataAlien$long[i], AssignDataAlien$lat[i])))
migratory_status <- ifelse(pv < 0.05, "status = migrant", "Status = local")

So basically at each position each alien has been found, we extract the pv from the assignment raster and then label the migratory status as "migrant" if pv < 0.05 and label it as "local" otherwise.

Ok now, the default plot showing assignment plots for the first 2 individuals would be obtained as follow:
my_plot <- plot(AssignmentDry, who = 1:2, sources = list(draw = FALSE), calibs = list(draw = FALSE))

Note that I stored the output of the plot as an object called "my_plot", because as we/you want to modify this default plot we will need to reuse it.

To now change the size of the text on the plot, you can simply do that:
update(my_plot, par.settings = list(fontsize = list(text = 20)))

What this does is that it updates the information stored in the plot, which will make the plot being rendered differently.
Technically the information behind a plot are stored as a large list.
Here we updated the element called "par.settings" which is itself a list with an element "fontsize", which is itself a list with the element "text" we want to change.
It is not very intuitive but powerful if you manage to guess what the parameter you want to change is called.

To now which graphical parameters can be changed you can try:
names(lattice::trellis.par.get("par.settings"))

Unfortunately, I fear that the help files describing each items are spread-out across many help files when existing at all.
This is not IsoriX's fault, but that of package IsoriX builds on (lattice).
I was able to guess what to change was called "fontsize", tried and it worked so I got lucky, but sometimes you need a little trial or error (or to google, which I tend not to do).
I guess that deep down to the names used stem from those used in the package "grid" which most graphic packages ultimately rely on.

To update the name on top of the sub-plots, it is the same idea:
update(my_plot, strip = lattice::strip.custom(factor.levels = migratory_status))

Here to guess, I had to look a little as how rasterVis (the package using lattice to plot rasters) works.
But I could also have guessed based on the name.
Note that I used the vector "migratory_status" defined above, but you can of course directly give a vector of character instead.

I think that everything in a lattice plot can be changed using update(), which is quite elegant once you know what the thing you want to change are called.
To get the full view of all that can be changed, just look at the data behind the plot:
str(my_plot)

Of course you can change several things at once, so the answer to your question would be:
update(my_plot,
       strip = lattice::strip.custom(factor.levels = migratory_status),
       par.settings = list(fontsize = list(text = 20)))

You can alternatively use update() one change at the time and store the result of the update() call into a new object which you reuse:
my_plot2 <- update(my_plot, strip = lattice::strip.custom(factor.levels = migratory_status))
my_plot3 <- update(my_plot, par.settings = list(fontsize = list(text = 20)))

Let me know if that works for you and/or if there is still something hard to grasp... Lattice is not easy (but it is powerful).

++

Alex

Theresa Schabacker

unread,
Dec 22, 2022, 4:30:41 AM12/22/22
to iso...@googlegroups.com
Hi Alex,

this is wonderful! Thank you so much for the detailed description and explanations, it truly broadened my R-horizon and it is super interesting to see how powerful lattice can be when you know which buttons to press ;)

I was able to adjust the font size and change the subtitles, so cool!
Now it's almost entirely perfect. One additional thing I was wondering was whether it's possible to adjust the direction of the alignment of the single maps? Sometimes the plots were aligned horizontally (i.e., tha maps next to eachother, like now) and sometimes vertically (i.e., maps ontop of eachother, what I'd prefer as the single assignments are a bit bigger then) but I couldn't figure out what changed this.

I tried looking at the graphical parameters that can be changed by using your suggested line of code:
names(lattice::trellis.par.get("par.settings"))
but unfortunately, that gives me just one answer: NULL

then I used
str(myplot)
to see what parameters there are. This worked fine and my guess was that the clip element might modify the alignment. I found out that it is again a list that contains two components (strip & panel) that both can be set to either "on" or "off". I tried all possible combinations but it's rather messing up the plot then aligning it as I want it to.
Seems like my guessing skills are not quite as elaborate as yours, who would've thought... ;)
If you have another moment to look into this, I would appreciate it very much - but it's not a pressing issue.

Thanks again for taking the time to help me solve this issue and merry christmas to everyone!

All the best,
Theresa


--
You received this message because you are subscribed to the Google Groups "IsoriX" group.
To unsubscribe from this group and stop receiving emails from it, send an email to isorix+un...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/isorix/f48c268d-e0ea-4829-a739-05a9adae5f10n%40googlegroups.com.

Alexandre Courtiol

unread,
Dec 22, 2022, 3:09:33 PM12/22/22
to IsoriX
Hi Theresa,

To adjust the number of rows and columns in a so-called "multipanel display" (I just discovered the name), you can use this (using the example from the other day):

update(my_plot, layout = c(col = 1, row = 2))

You actually don't need to write "col =" and "row =", as the function will only read this as c(1, 2), but since it does not hurt the function to name what's what, I've preferred  writing that so it appears clearer to everyone.
I figured that out by looking at the help page for ?lattice::xyplot.
That is the help page I was looking for: it does contain some explanation about most of the arguments you can fine tune for plots created with lattice!

Happy holidays to you all.
PS: I will myself be on holidays from Dec 28th till Jan 15th.

Alex
Reply all
Reply to author
Forward
0 new messages