I would like to visualize how functions in my own R package depend on each other. For this purpose I use the foodweb() function from the mvbutils package.
I can get the right functional dependencies out without a problem but the plot looks a bit messy, with lines crossing each other and function names not aligned vertically or horizontally.
Is there a way to control the layout of the plot similar to the way this works in the igraph package?
Example
dirPath <- "~/dev/stackoverflow/46910042"
setwd(dirPath)
## Download example Package
urlPackage <- "https://github.com/kbroman/qtlcharts/archive/master.zip"
download.file(urlPackage, destfile = "master.zip")
unzip("./master.zip", exdir = dirPath, overwrite = TRUE)
## Install or load mcbutils
if (!require(mvbutils)) install.packages("mvbutils")
thefiles = list.files(path = "./qtlcharts-master/R/", full.names = TRUE)
thefiles
## Now we load all the package files into memory, so we can have
## foodweb generate a map of the package functions.
sapply(thefiles, source)
## Generate plot
par(mar = rep(0.1, 4))
foodweb(border = TRUE, boxcolor = "pink", lwd = 1.5, cex = 0.8)
Plot Output:
Michael,
One option is to look behind the curtains of foodweb. The mvbutils::foodweb function returns an object of (S3) class foodweb. This has three components:
funmat a matrix of 0s and 1s showing what (row) calls what (column). The dimnames are the function names.
x shows the x-axis location of the centre of each function’s name in the display, in par("usr") units
level shows the y-axis location of the centre of each function’s name in the display, in par("usr") units.
thus one approach we can take is to call foodweb but tell it not to create a plot rather return a foodweb object. This then allows us to manipulate the data directory or via graphics::plot() externally of the defaults provided by the mvbutils::foodweb() function.
Why? Well, to do what you suggest my sense is three options exist:
You can either play with mvbutils::foodweb() parameters.
Work with data structure returned with another plotting package.
Use graphics::par() and graphics::plot to manipulate the plot size and attributes of the foodweb structure returned.
It would be great to know your preference. Excluding, that my sense was to provide a base example:
Plot Package Example
In the case of using graphics::plot, you need to go look at how you manipulate graphics:par. par() allows you to set or query graphical parameters. For example, if we want to clean up the function plot you might choose to modify the grahics::par() fin parameter to increase the figure region dimensions, (width, height), in inches. A simple example but my sense it helps map out and demonstrate the options available to you.
## Generate plot
if (!require(qtlcharts)) install.packages("qtlcharts")
## Here we specify `asNamespace` to get the package internals
fw <- foodweb( where = asNamespace( "qtlcharts"),
plotting = FALSE,
)
#Display foodweb structure
str(fw)
# Expand plot figure region dimensions...
par(fin = c(9.9,7))
# Plot fw strucuture
plot(fw,
border = TRUE,
expand.xbox = 1,
boxcolor = "pink", lwd = 1.5, cex = 0.8)
Plot Output example
Note that the function names are not spaced out. Note I cut the top and bottom white of plot here. In this case, you can play with the par constraints such as margin to get the plot you want.
Pruning your plot
Another option within the constraints of mvbutils::foodweb is to use the prune and rprune option to simplify your plots. These are super poweful and useful especially the regular expression version.
if (!require(qtlcharts)) install.packages("qtlcharts")
fw <- foodweb( where = asNamespace( "qtlcharts"),
plotting = FALSE)
str(fw)
par(fin = c(9.9,7))
plot(fw,
border = TRUE,
expand.xbox = 1,
boxcolor = "pink", lwd = 1.5, cex = 0.8)
fw <- foodweb( where = asNamespace( "qtlcharts"),
rprune = "convert_", ## search on `convert_` to negate use `~convert_`
plotting = FALSE)
str(fw)
par(fin = c(9.9,7))
plot(fw,
border = TRUE,
expand.xbox = 1,
boxcolor = "pink", lwd = 1.5, cex = 0.8)
Hoping the above information points you in the right direction.
T.
Because of the fact that there are many data, connections etc, the plot is squeezed in order to fit in the screen, hence it becomes messy.
What I would suggest is to save it in a PDF or PNG with big enough width and Height and then you can zoom in. This will save you a lot of time.
E.G.
## Generate plot
pdf( "mygraph.pdf", width = 50, height = 80 )
par(mar = rep(0.1, 4))
foodweb(border = TRUE, boxcolor = "pink", lwd = 1.5, cex = 0.8)
dev.off()
In addition, you can play with the plot options of foodweb.
Hope it helps.
Related
I would like to create a single figure with multiple panels, in which each panel contains a qgraph network plot.
Ideally, I would do this:
pacman::p_load(qgraph)
# Load big5 dataset:
data(big5)
data(big5groups)
# Correlations:
Q <- qgraph(cor(big5), minimum = 0.25, cut = 0.4, vsize = 1.5, groups = big5groups,
legend = TRUE, borders = FALSE)
title("Big 5 correlations", line = 2.5)
# Same graph with spring layout:
Q2 <- qgraph(Q, layout = "spring")
title("Big 5 correlations spring", line = 2.5)
cowplot::plot_grid(Q, Q2)
But this won't work, because cowplot doesn't know how to convert the qgraph objects to grobs.
I have tried converting the qgraph objects to igraph objects, which I think I should be able to further convert to grobs, perhaps using tidygraph, ggraph, GGally, ggnetwork, or similar, but some of the information I would like to convey is lost along the way, and I already have my networks plotted just the way I want using qgraph.
It seems that there has previously been an experimental as.ggraphfunction in qgraph that might have helped, but it appears that no longer exists.
My question is: Is there any way to either simply convert qgraph objects to grobs, or otherwise produce an image with several qgraph objects next to each other?
I think you can do this:
par(mfrow=c(1, 2))
qgraph(cor(big5), minimum = 0.25, cut = 0.4, vsize = 1.5, groups = big5groups, legend = TRUE, borders = FALSE)
qgraph(Q, layout = "spring")
I am plotting a SpatialPoint dataframe in R using spplot, and I would like to use a colorbar rather than a legend, to portray color values. (It's more efficient, and I want the map to "match" previous, raster data maps.) I'm sure this is possible, but can find no examples of it online. Could anyone give me a hint?
My current code is:
my.palette <- brewer.pal(n = 9, name = "Spectral")
my.palette<- rev(my.palette)
pols1 <- list("sp.lines", as(ugborder, 'SpatialLines'), col = gray(0.4), lwd = 1)
pols2 <- list("sp.polygons", as(water_ug, 'SpatialPolygons'), fill = 'skyblue1',col="transparent", first = FALSE)
spplot(ughouseszn,zcol="lzn_sg_clng",cex = .75,
key.space="right", digits=1,
par.settings = list(axis.line = list(col = 'transparent')),
xlim = bbox(ugborder)[1, ],ylim = bbox(ugborder)[2, ],
col.regions = my.palette, cuts=8,
sp.layout=list(pols1, pols2))
Where ugborder and water_ug give Uganda's borders and water, ughouseszn is a SpatialPointsDataframe, and the resulting map is here:
(As a side note, I'm hoping that adding a colorbar will lead to a more efficient use of space -- right now there's a lot of extra space at the top and bottom of Uganda's border, which is useless, and also does NOT appear when I map raster data using spplot, with the same pols1 and pols2.)
If "lzn_sg_clng" is converted to a factor, does this give you the map you desire? (rendering by the category rather than a graduated scale).
I´m recently trying to analyse my data and want to make the graphs a little nicer but I´m failing at this.
So I have a data set with 144 sites and 5 environmental variables. It´s basically about the substrate composition around an island and the fish abundance. On this island there is supposed to be a difference in the substrate composition between the north and the southside. Right now I am doing a pca and with the biplot function it works quite fine, but I would like to change the plot a bit.
I need one where the sites are just points and not numbered, arrows point to the different variable and the sites are colored according to their location (north or southside). So I tried everything i could find.
Most examples where with the dune data and suggested something like this:
library(vegan)
library(biplot)
data(dune)
mod <- rda(dune, scale = TRUE)
biplot(mod, scaling = 3, type = c("text", "points"))
So according to this I would just need to say text and points and R would label the variables and just make points for the sites. When i do this, however I get the Error:
Error in plot.default(x, type = "n", xlim = xlim, ylim = ylim, col = col[1L], :
formal argument "type" matched by multiple actual arguments
No idea how to get around this.
So next strategy I found, is to make a plot manually like this:
require("vegan")
data(dune, dune.env)
mod <- rda(dune, scale = TRUE)
scl <- 3 ## scaling == 3
colvec <- c("red2", "green4", "mediumblue")
plot(mod, type = "n", scaling = scl)
with(dune.env, points(mod, display = "sites", col = colvec[Use],
scaling = scl, pch = 21, bg = colvec[Use]))
text(mod,display="species", scaling = scl, cex = 0.8, col = "darkcyan")
with(dune.env, legend("bottomright", legend = levels(Use), bty = "n",
col = colvec, pch = 21, pt.bg = colvec))
This works fine so far as well, I get different colors and points, but now the arrows are missing. So I found that this should be corrected easy, if i just put "display="bp"" in the text line. But this doesn´t work either. Everytime I put "bp" R says:
Error in match.arg(display) :
argument "display" is missing, with no default
So I´m kind of desperate now. I looked through all the answers here and I don´t understand why display="bp" and type=c("text","points") is not working for me.
If anyone has an idea i would be super grateful.
https://www.dropbox.com/sh/y8xzq0bs6mus727/AADmasrXxUp6JTTHN5Gr9eufa?dl=0
This is the link to my dropbox folder. It contains my R-script and the csv files. The one named environmentalvariables_Kon1 also contains the data about north and southside.
So yeah...if anyone could help me. That would be awesome. I really don´t know what to do anymore.
Best regards,
Nancy
You can add arrows with arrows(). See the code for vegan:::biplot.rda to see how it works in the original function.
With your plot, add
g <- scores(mod, display = "species")
len <- 1
arrows(0, 0, len * g[, 1], len * g[, 2], length = 0.05, col = "darkcyan")
You might want to adjust the value of len to make the arrows longer
I'm still relatively inexperienced manipulating plots in R, and am in need of assistance. I ran a redundancy analysis in R using the rda() function, but now I need to simplify the figure to exclude unnecessary information. The code I'm currently using is:
abio1516<-read.csv("1516 descriptors.csv")
attach(abio1516)
bio1516<-read.csv("1516habund.csv")
attach(bio1516)
rda1516<-rda(bio1516[,2:18],abio1516[,2:6])
anova(rda1516)
RsquareAdj(rda1516)
summary(rda1516)
varpart(bio1516[,2:18],~Distance_to_source,~Depth, ~Veg._cover, ~Surface_area,data=abio1516)
plot(rda1516,bty="n",xaxt="n",yaxt="n",main="1516; P=, R^2=",
ylab="Driven by , Var explained=",xlab="Driven by , Var explained=")
The produced plot looks like this:
Please help me modify my code to: exclude the sites (sit#), all axes, and the internal dashed lines.
I'd also like to either expand the size of the field, or move the vector labels to all fit in the plotting field.
updated as per responses, working code below this point
plot(rda,bty="n",xaxt="n",yaxt="n",type="n",main="xxx",ylab="xxx",xlab="xxx
Overall best:xxx")
abline(h=0,v=0,col="white",lwd=3)
points(rda,display="species",col="blue")
points(rda,display="cn",col="black")
text(rda,display="cn",col="black")
Start by plotting the rda with type = "n" which generates an empty plot to which you can add the things you want. The dotted lines are hard coded into the plot.cca function, so you need either make your own version, or use abline to hide them (then use box to cover up the holes in the axes).
require(vegan)
data(dune, dune.env)
rda1516 <- rda(dune~., data = dune.env)
plot(rda1516, type = "n")
abline(h = 0, v = 0, col = "white", lwd = 3)
box()
points(rda1516, display = "species")
points(rda1516, display = "cn", col = "blue")
text(rda1516, display = "cn", col = "blue")
If the text labels are not in the correct position, you can use the argument pos to move them (make a vector as long as the number of arrows you have with the integers 1 - 4 to move the label down, left, up, or right. (there might be better solutions to this)
I have a grid and I want to produce a map out of this grid with some map elements (scale, north arrow, etc). I have no problem drawing the grid and the coloring I need, but the additional map elements won't show on the map. I tried putting first=TRUE to the sp.layout argument according to the sp manual, but still no success.
I reproduced the issue with the integrated meuse dataset, so you may just copy&paste that code. I use those package versions: lattice_0.20-33 and sp_1.2-0
library(sp)
library(lattice) # required for trellis.par.set():
trellis.par.set(sp.theme()) # sets color ramp to bpy.colors()
alphaChannelSupported = function() {
!is.na(match(names(dev.cur()), c("pdf")))
}
data(meuse)
coordinates(meuse)=~x+y
data(meuse.riv)
library(gstat, pos = match(paste("package", "sp", sep=":"), search()) + 1)
data(meuse.grid)
coordinates(meuse.grid) = ~x+y
gridded(meuse.grid) = TRUE
v.uk = variogram(log(zinc)~sqrt(dist), meuse)
uk.model = fit.variogram(v.uk, vgm(1, "Exp", 300, 1))
meuse[["ff"]] = factor(meuse[["ffreq"]])
meuse.grid[["ff"]] = factor(meuse.grid[["ffreq"]])
zn.uk = krige(log(zinc)~sqrt(dist), meuse, meuse.grid, model = uk.model)
zn.uk[["se"]] = sqrt(zn.uk[["var1.var"]])
meuse.sr = SpatialPolygons(list(Polygons(list(Polygon(meuse.riv)),"meuse.riv")))
rv = list("sp.polygons", meuse.sr, fill = "lightblue")
sampling = list("sp.points", meuse.riv, color = "black")
scale = list("SpatialPolygonsRescale", layout.scale.bar(),
offset = c(180500,329800), scale = 500, fill=c("transparent","black"), which = 4)
text1 = list("sp.text", c(180500,329900), "0", cex = .5, which = 4)
text2 = list("sp.text", c(181000,329900), "500 m", cex = .5, which = 4)
arrow = list("SpatialPolygonsRescale", layout.north.arrow(),
offset = c(181300,329800),
scale = 400, which = 4)
library(RColorBrewer)
library(lattice)
trellis.par.set(sp.theme())
precip.pal <- colorRampPalette(brewer.pal(7, name="Blues"))
spplot(zn.uk, "var1.pred",
sp.layout = list(rv, sampling, scale, text1, text2),
main = "log(zinc); universal kriging standard errors",
col.regions=precip.pal,
contour=TRUE,
col='black',
pretty=TRUE,
scales=list(draw = TRUE),
labels=TRUE)
And that's how it looks...all naked:
So my questions:
Where is the scale bar, north arrow, etc hiding? Did I miss something? Every example I could find on the internet looks similar to that. On my own dataset I can see the scale bar and north arrow being drawn at first, but as soon as the grid is rendered, it superimposes the additional map elements (except for the scale text, that is shown on the map - not the bar and north arrow for some reason I don't seem to comprehend).
The error message appearing on the map just shows when I try to add the sampling locations sampling = list("sp.points", meuse.riv, color = "black"). Without this entry, the map shows without error, but also without additional map elements. How can I show the sampling points on the map (e.g. in circles whose size depends on the absolute value of this sampling point)?
This bothered me for many, many hours by now and I can't find any solution to this. In Bivand et al's textbook (2013) "Applied Spatial Data Analysis with R" I could read the following entry:
The order of items in the sp.layout argument matters; in principle objects
are drawn in the order they appear. By default, when the object of spplot has
points or lines, sp.layout items are drawn before the points to allow grids
and polygons drawn as a background. For grids and polygons, sp.layout
items are drawn afterwards (so the item will not be overdrawn by the grid
and/or polygon). For grids, adding a list element first = TRUE ensures that
the item is drawn before the grid is drawn (e.g. when filled polygons are added). Transparency may help when combining layers; it is available for the
PDF device and several other devices.
Function sp.theme returns a lattice theme that can be useful for plots
made by spplot; use trellis.par.set(sp.theme()) after a device is opened
or changed to make this effective.
However, also with this additional information I wasn't able to solve this problem. Glad for any hint!
The elements you miss are being drawn in panel four, which does not exist, so are not being drawn. Try removing the which = 4.
meuse.riv in your example is a matrix, which causes the error message, but should be a SpatialPoints object, so create sampling by:
sampling = list("sp.points", SpatialPoints(meuse.riv), color = "black")
When working from examples, my advice is to choose examples as close as possible to what you need, and only change one thing at a time.