Exhausting all arguments on qgraph
Let's use it all!
By Gabriel R. R. in network psychometrics tutorials qgraph
August 21, 2021
TL;DR: I try to use all
qgraph::qgraph()
’s arguments and fail miserably. Truth is, there’s just so many options, and most arguments didn’t apply to the data analysis I designed. Nevertheless, it was a great exercise and I learned A LOT more about qgraph.
Preparing the data
We’ll use all arguments on qgraph on this blog post. Well, we’ll either do that or die trying… Let’s again use the 25 item Big-Five questionnaire from the psych package. This time we’ll also load the items so we can create a pretty neat viz.
load_libraries <- function(){
if (!require("dplyr"))
install.packages("dplyr"); library(dplyr)
if (!require("psych"))
install.packages("psych"); library(psych)
if(!require("qgraph"))
install.packages("qgraph"); library(qgraph)
}
load_libraries()
# Data
df <- bfi[,1:25]
# Hyperparameters
# Group:
traits <- rep(c('Agreeableness',
'Conscientiousness',
'Extraversion',
'Neuroticism',
'Openness'),
each = 5)
# Nodes:
items <- c(
"Am indifferent to the feelings of others.",
"Inquire about others' well-being.",
"Know how to comfort others.",
"Love children.",
"Make people feel at ease.",
"Am exacting in my work.",
"Continue until everything is perfect.",
"Do things according to a plan.",
"Do things in a half-way manner.",
"Waste my time.",
"Don't talk a lot.",
"Find it difficult to approach others.",
"Know how to captivate people.",
"Make friends easily.",
"Take charge.",
"Get angry easily.",
"Get irritated easily.",
"Have frequent mood swings.",
"Often feel blue.",
"Panic easily.",
"Am full of ideas.",
"Avoid difficult reading material.",
"Carry the conversation to a higher level.",
"Spend time reflecting on things.",
"Will not probe deeply into a subject.")
# Neuroticism columns:
neuroticism <- c('N1', 'N2', 'N3', 'N4', 'N5')
Let’s create the biggest function ever created
Say we’re interested in Neuroticism. We want to look at its relationship with the other personality dimensions, its connections and its place in the network. In our function, we’ll make the neuroticism nodes bigger. And well… this is the only major change we’ll make. The rest of the arguments will remain practically the default ones. Oh!, another fancy thing we’ll do is plot the items and its dimensions in the graph.
network <-
qgraph(
input = cor_auto(df),
#' *Important additional arguments* (p. 29)
layout = 'spring', # 'circle', 'groups', 'circular'
groups = traits, # list or vector
minimum = 0, # min value to be plotted
#' *maximum* =, max value to scale edge widths, default is absmax pcor(x,y)
cut = 0, # value to initiate the scaling of edge widths
details = F, # if T, min/max/cut is printed under the graph
threshold = 0, # edges with abs value below this are REMOVED from estimation
palette = 'colorblind', # 'rainbow', 'pastel', 'gray', 'R', 'ggplot2'
theme = 'colorblind', # 'classic', 'gray', 'Hollywood', 'Borkulo', 'gimme',
# 'TeamFortress', 'Reddit', 'Leuven', 'Fried'
#' *Additional options for correlation/covariance matrices* (p. 30)
graph = 'glasso', # 'cor', 'pcor'
threshold = 'none', # remove edges based on significance testing; 'sig',
# 'holm', 'hochberg', 'hommel', 'bonferroni', 'BH', 'BY', 'fdr', 'locfdr'
sampleSize = nrow(df), # sample size, when graph="glasso" or minimum="sig"
tuning = 0.5, # gamma argument
lambda.min.ratio = 0.01, # min lambda value for glasso estimation
gamma = 0.5, # just an alias for tuning, overwrites tuning
refit = F, # should the optimal graph be refitted without LASSO?
countDiagonal = F, # count diagonal in EBIC comp? generally F
alpha = 0.05, # sig value for not showing edges if minimum = 'sig'
bonf = F, # should a bonferroni correction be used if minimum = 'sig'?
FDRcutoff = 0.9, # False-Discovery Rate cutoff if *threshold* = 'fdr'
#' *Output arguments* (pp. 30-31)
#mar = c(3, 3, 3, 3), # margins' vector c(bottom, left, top, rigth)
#' *filetype* = 'R', can also be 'pdf', 'svg', 'tex', 'jpg', 'png', 'tiff'
#' *filename* = 'graph', name of the file WITHOUT extension
width = 7 * 1.4, # width of figure
height = 7, # height of figure
normalize = T, # graph's normalized to look the same for all sizes
DoNotPlot = F, # useful to save plot without plotting
plot = T, # should a new plot be made? if F, adds graph to existing plot
rescale = T, # should layout be rescaled? best used with plot = F
standAlone = F, # make output standalone LaTeX file if filetype = 'tex'
#' *Graphical arguments*
# Nodes (pp. 31-32)
#color = rainbow(length(groups)), # vector with a color for each node
vsize = ifelse(colnames(df) == neuroticism, 7.5, 6),
# indicates node size, can be a vector with size for each node
# default = 8*exp(-nNodes/80)+1
#' *vsize2* = ..., node vertical size if shape = 'rectangle'
node.width = 1, # scalar on value of vsize
node.height = 1, # scalar on value of vsize2
borders = T, # should borders be plotted?
border.color = 'black', # color vector indicating colors of borders
border.width = 0.5, # controls width of the border
shape = 'circle', # 'square', 'triangle', 'diamond', 'ellipse', 'heart'
#' *polygonList* = ..., list containing named lists for each element to
#' include polygons
vTrans = 255, # transparency of nodes, between 0 and 255 (no transparency)
#' *subplots* = ..., list with as elements R expressions or NULL for
#' each node. If an R expression, evaluated to create plot for the node.
#' *subpars* = ..., list of graphical parameters to use in subplots
#' *subplotbg* = ..., background to be used in subplots
images = NA, # indicate file location of PNG of JPEG img to use as nodes
noPar = F, # don't run the par function
#' *pastel* = F, # should default colors be chosen from pastel colors?
#' *rainbowStart* = ..., number from 0 to 1 indicating offset of rainbow
usePCH = F, # nodes drawn using polygons or base R plotting symbols?
node.resolution = 100, # resolution of nodes if usePCH = F
# title = "Big-Five Inventory Psychometric Network", string graph title
# title.cex = 0.5, size of title
#' *preExpression* = ..., parsable string containing R code to be evaluated
#' after opening a plot and before drawing the graph
#' *postExpression* = ..., parsable string containing R code to be evaluated
#' just before closing the device
diag = F, # should diagonal also be plotted? Can also be 'col'
# Node labels (pp. 32-33)
#labels = T, # should labels be plotted?
label.cex = 0.7, # scalar on label size
label.color = 'black', # string on label colors
label.prop = 0.9, # proportion of the width of the node that the label scales
label.norm = "OOO", # normalize width of label size in nodes
label.scale = T, # should labels be scaled to fit the node?
label.scale.equal = T, # should labels have same font size?
#' *label.font* = ..., # integer specifying the label font of nodes
#' *label.fill.vertical* = ..., scalar indicating max prop to fill a node
#' *label.fill.horizontal* = ..., scalar indicating max prop to fill a node
node.label.offset = c(0.5,0.5), # where should label be centered, (x, y)
node.label.position = NULL, # set specific positions of node labels
# Edges (pp. 33-34)
#' *esize* = ..., size of largest edge
#' *edge.width* = ..., size of largest edge
#' *edge.color* = ..., size of largest edge
# posCol = c("#009900", "darkgreen"), color of positive edges
negCol = c("#BF0000","red"), # color of negative edges
unCol = "#808080", # default edge color of unweighted graphs
probCol = "blue", # color of probability nodes
negDashed = T, # should negative edges be dashed?
probabilityEdges = F, # do edges indicate probabilities?
colFactor = 1, # exponentially transforms color int. of relative strength 1
trans = T, # should edges fade to white?
fade = T, # should edges fade?
loopRotation = NA, # vector for each node assigning rotation in radians
loop = 1, # if diag = T, scales the size of the loop
lty = 1, # line type, see 'par'
#' *edgeConnectPoints* = ..., specifies the point for each edge to which it
#' connects to a node, in radians
# Edge curvature (pp. 34-35)
# curve = NA, # single value, a vector list, weight matrix or NA (default)
curveAll = T, # logical indicating if all edges should be curved
curveDefault = 0.5, # default is 1
curveShape = -1, # shape of the curve, as used in xspline
curveScale = T, # should curve scale with distance between nodes?
curveScaleNodeCorrection = T, # discable node correction in curveScale
curvePivot = F, # can be logical or numeric, this can be used to make
# straight edges as curves with knicks in them.
curvePivotShape = 0.25, # shape of edge pivot, default is 0.25
parallelEdge = F, # draw parallel straight edges rather than curved ones?
parallelAngle = NA, # distance in radians an edge is shifted
parallelAngleDefault = pi/6, # angle of the edge furthest from the center
# Edge labels (p. 35)
edge.labels = F, # if T, numeric is plotted. if F, nothing is.
edge.label.cex = 1, # single number or number per edge
edge.label.bg = T, # plot a white background behind number
edge.label.margin = 0, # margin of the background bow around the edge label
edge.label.position = 0.5, # vector between 0 and 1, 0.5 is middle
#' *edge.label.font* = ..., numeric specifying the label font of edges
#' *edge.label.color* = ..., character vector indicating color of edge label
# Layout (p. 35)
repulsion = 1, # setting to lower values will cause nodes to repulse each
# other less. This is useful if few unconnected nodes cause the giant
# component to visually be clustered too much in the same place.
#' *layout.par* = ..., list of arguments passed to
#' qgraph.layout.fruchtermanreingold()
layoutRound = T, # should weights be rounded before computing layouts?
#' *layout.control* = ..., scalar on the size of the circles created
aspect = F, # should the original aspect ratio be maintained if rescaled?
rotation = 0, # rotate the circles created with the circular layout;
# contains the rotation in radian for each group of nodes
# Legend (p. 35-36)
legend = T, # should a legend be plotted?
legend.cex = 0.27, # scalar of the legend
legend.mode = 'style2', # default is 'style1', different way to show legend
GLratio = 2.5, # relative size of graph compared to the layout
layoutScale = c(1, 1), # vector with a scalar for respectively the x and y
# coordinates of the layout. Setting this to c(2, 2) makes plot twice as
# big. This can be used with layoutOffset to determine the graph's placement.
layoutOffset = c(0,0), # vector with the offset to the x and coordinates of
# the center of the graph
nodeNames = items, # names for each node to plot in legend
# Background (p. 36)
bg = F, # should node colors cast a light in the background?
# can also be a color...
bgcontrol = 6, # the higher, the less light each node gives if bg = T
bgres = 100, # (default) square root of the number of pixels used in bg = T
# Generical graphical arguments (p. 36)
#' *pty* = ..., see 'par'
gray = F, # should the graph be plotted in grayscale colors?
font = 2, # integer specifying default font for node and edge labels
# Arguments for directed graphs (p. 36)
directed = F, # are edges directed? can be logical vector/matrix
arrows = F, # should arrows be plotted? can be a number
arrowAngle = pi/8, # (default for unweighted) and pi/4 for weighted
#' *azise* = ..., size of the arrowhead
open = F, # should arrowheads be open?
bidirectional = F, # should directional edges between nodes have two edges?
# Arguments for graphs based on significance values (p. 37)
mode = "strength", # defines mode used for coloring edges, can be "sig" too
alpha = 0.05, # if minimum = "sig" , sig level for not showing edges
#' *sigScale* = ..., fybctuib ysed ti scake tge edges if mode = "sig"
bonf = F, # should bonferronni correction be applied?
# Arguments for plotting scores on nodes (p. 37)
#' *scores* = ..., vector used to plot scores of an individual on the test
#' *scores.range* = ..., vector of length two indicating the range of scores
# Arguments for manually defining graphs (p. 37)
#' *mode* = ..., mode can also be used to make the weights matrix correspond
#' directly with the width of the edges
edge.color = NA, # argument used to overwrite the colors, can be a single
# value or vector/matrix with a color for each edge
# Arguments for knots (tying together edges) (p. 37)
#' *knots* = ..., argument used to tie edges together in their center,
#' useful for indicating interaction effects. Can be a list where each
#' element is a vector containing the edge numbers that should be knotted.
#' *knot.size* = 1, size of the knots
#' *knot.color* = NA, color of the knots
#' *knot.borders* = F, should a border be plotted around the knot?
#' *knot.border.color* = 'black', color of the know borders
#' *knot.border.width* = 1, width of the knot borders
# Arguments for bars (p. 38)
#' *means* = ..., vector with means for every node or NA, will plot a
#' vertical bar at the location of the mean between meanRange values
#' *SDs* = ..., vector with SDs for every node or NA, will plot an error bar
#' of 2 times this value around the means location
#' *meanRange* = ..., range of the means argument
#' *bars* = ..., a list with for each node or vector with values between 0-1
#' indicating where bars should be placed inside the node
#' *barSide* = ..., integer for each node indicating at which side the bars
#' should be drawn. 1, 2, 3 or 4: bottom, left, top or right respectively.
#' *barColor* = ..., vector with for each node indicating color of bars
#' *barLength* = 0.5, vector indicating relative length of bars for each
#' node compared to the node size
#' *barsAtSide* = F, should bars be drawn at the side of a node?
# Arguments for pies (p. 38)
#' *pie* = ..., vector with values between 0-1 for each node or just one
#' value for all nodes. This will make the border of nodes a pie chart.
#' *pieBorder* = 0.15, size of the pie chart in the border, between 0-1
#' *pieColor* = ..., colors of the pie plot parts, can be a vector with a
#' value for each node or list with multiple values if there are more parts
#' *pieColor2* = 'white', final color of the pie chart
#' *pieStart* = ..., vector with values between 0-1 for each node or just
#' one value for all nodes indicating the starting point of the pie chart.
#' *pieDarken* = ..., vector with values between 0-1 for each node or just
#' one value for all nodes indicating how much darker the pie border is
#' *piePastel* = F, pastel colors to fill pie chart parts when >= 2 blocks?
#' *pieCImid* = ..., vector with values between 0-1 for each node or just
#' one value for all nodes indicating center point of confidence region
#' *pieCIlower* = ..., vector with values between 0-1 for each node or just
#' one value for all nodes indicating lower point of confidence region
#' *pieCIupper* = ..., vector with values between 0-1 for each node or just
#' one value for all nodes indicating upper point of confidence region
#' *pieCIpointcex* = 0.01, vector with values between 0-1 for each node or
#' just one value for all nodes indicating size of the point estimate
#' *pieCIpointcex* = 'black', vector with values between 0-1 for each node
#' or just one value for all nodes indicating color of the point estimate
# Additional arguments (p. 39)
edgelist = F, # is input an edgelist?
weighted = T, # is input weighted?
nNodes = 25 # number of nodes, only specified if edgelist = T
# XKCD = T, if T, graph is plotted in XKCD style based on
#' http://stackoverflow.com/a/12680841/567015
)
There we go! A personalyzed network graph.
Making the same graph with a smaller function
If you read the function, you probably noticed that a lot of values used on the arguments were default. To facilitate my future work, I’ll now create the same graph without the spare arguments from before.
network <-
qgraph(
input = cor_auto(df),
#' *Important additional arguments* (p. 29)
layout = 'spring', # 'circle', 'groups', 'circular'
groups = traits, # list or vector
minimum = 0, # min value to be plotted
#' *maximum* =, max value to scale edge widths, default is absmax pcor(x,y)
cut = 0, # value to initiate the scaling of edge widths
palette = 'colorblind', # 'rainbow', 'pastel', 'gray', 'R', 'ggplot2'
theme = 'colorblind', # 'classic', 'gray', 'Hollywood', 'Borkulo', 'gimme',
# 'TeamFortress', 'Reddit', 'Leuven', 'Fried'
#' *Additional options for correlation/covariance matrices* (p. 30)
graph = 'glasso', # 'cor', 'pcor'
sampleSize = nrow(df), # sample size, when graph="glasso" or minimum="sig"
#' *Output arguments* (pp. 30-31)
width = 7 * 1.4, # width of figure
height = 7, # height of figure
#' *Graphical arguments*
# Nodes (pp. 31-32)
vsize = ifelse(colnames(df) == neuroticism, 7.5, 6),
# indicates node size, can be a vector with size for each node
# default = 8*exp(-nNodes/80)+1
border.width = 0.5, # controls width of the border
# Node labels (pp. 32-33)
label.cex = 0.7, # scalar on label size
label.color = 'black', # string on label colors
label.prop = 0.9, # proportion of the width of the node that the label scales
# Edges (pp. 33-34)
negDashed = T, # should negative edges be dashed?
# Edge curvature (pp. 34-35)
# curve = NA, # single value, a vector list, weight matrix or NA (default)
curveAll = T, # logical indicating if all edges should be curved
curveDefault = 0.5, # default is 1
# Legend (p. 35-36)
legend.cex = 0.27, # scalar of the legend
legend.mode = 'style2', # default is 'style1', different way to show legend
nodeNames = items, # names for each node to plot in legend
# Generical graphical arguments (p. 36)
font = 2 # integer specifying default font for node and edge labels
)
Estimate network with a “cool” background
One cool thing I found out during this is the bg = T
argument.
Basically, this argument lets the light shine through the node
and onto the background. It’s quite interesting. It’s probably
more useful if we have a bunch of nodes and various groupings.
But, for now, let’s see what we can get with this…
network <-
qgraph(
input = cor_auto(df),
#' *Important additional arguments* (p. 29)
layout = 'spring', # 'circle', 'groups', 'circular'
groups = traits, # list or vector
minimum = 0, # min value to be plotted
#' *maximum* =, max value to scale edge widths, default is absmax pcor(x,y)
cut = 0, # value to initiate the scaling of edge widths
palette = 'colorblind', # 'rainbow', 'pastel', 'gray', 'R', 'ggplot2'
theme = 'colorblind', # 'classic', 'gray', 'Hollywood', 'Borkulo', 'gimme',
# 'TeamFortress', 'Reddit', 'Leuven', 'Fried'
#' *Additional options for correlation/covariance matrices* (p. 30)
graph = 'glasso', # 'cor', 'pcor'
sampleSize = nrow(df), # sample size, when graph="glasso" or minimum="sig"
#' *Output arguments* (pp. 30-31)
width = 7 * 1.4, # width of figure
height = 7, # height of figure
#' *Graphical arguments*
# Nodes (pp. 31-32)
vsize = ifelse(colnames(df) == neuroticism, 7.5, 6),
# indicates node size, can be a vector with size for each node
# default = 8*exp(-nNodes/80)+1
border.width = 0.5, # controls width of the border
# Node labels (pp. 32-33)
label.cex = 0.7, # scalar on label size
label.color = 'black', # string on label colors
label.prop = 0.9, # proportion of the width of the node that the label scales
# Edges (pp. 33-34)
negDashed = T, # should negative edges be dashed?
# Edge curvature (pp. 34-35)
# curve = NA, # single value, a vector list, weight matrix or NA (default)
curveAll = T, # logical indicating if all edges should be curved
curveDefault = 0.5, # default is 1
# Legend (p. 35-36)
legend = F,
# Generical graphical arguments (p. 36)
font = 2, # integer specifying default font for node and edge labels
# Background (p. 36)
bg = T, # should node colors cast a light in the background?
# can also be a color...
bgcontrol = 3 # the higher, the less light each node gives, default is 6
)
That’s it for now!
References
Costantini, G., Epskamp, S., Borsboom, D., Perugini, M., Mõttus, R., Waldorp, L. J., & Cramer, A. O. J. (2015). State of the aRt personality research: A tutorial on network analysis of personality data in R. Journal of Research in Personality, 54, 13–29. https://doi.org/10.1016/j.jrp.2014.07.003
Epskamp, S., Cramer, A. O. J, Waldorp, L. J., Schmittmann, V. D., Borsboom, D. (2012). qgraph: Network visualizations of relationships in psychometric data. Journal of Statistical Software, 48(4), 1–18. https://doi.org/10.18637/jss.v048.i04
- Posted on:
- August 21, 2021
- Length:
- 17 minute read, 3523 words
- Categories:
- network psychometrics tutorials qgraph
- See Also: