I am trying to customize a plot of a graph learned with bnlearn
using RGraphviz
. When I have undirected edges, RGraphviz
turns them into directed edges to both directions when I try to customize the appearance of the graph.
A reproducible example could be:
set.seed(1)
x1 = rnorm(50, 0, 1)
x2 = rnorm(50, 0, 1)
x3 = x2 + rnorm(50, 0, 1)
x4 = -2*x1 + x3 + rnorm(50, 0, 1)
graph = data.frame(x1, x2, x3, x4)
library(bnlearn)
library(Rgraphviz)
res = gs(graph)
options(repr.plot.width=3, repr.plot.height=3)
g1 <- graphviz.plot(res)
Graph not customized:
So far so good. But if I try to customize it:
plot(g1, attrs = list(node = list(fontsize=4, fillcolor = "lightgreen")))
Customized graph
The undirected edge is transformed.
I get this problem even if I just use plot(g1). The issue is that this (saving g1 and then using plot) seems to change the appearance of the graphs.
You can change some of the attributes using the highlight
argument of graphviz.plot
, however, it doesn't seem to allow the label size to be altered. You could set this globally, but there is a loss of control doing it this way.
par(cex=0.05)
graphviz.plot(res, highlight =
list(nodes=nodes(res), fill="lightgreen", col="black"))
As shown in your question, you can get a bit more control, using the attrs
argument for the plot method for the graphNEL object, but again there is the problem of direction.
g <- bnlearn::as.graphNEL(res) # use this to avoid printing of graphviz.plot
plot(g, attrs=list(node = list(fillcolor = "lightgreen", fontsize=4)))
Also try to set the graph plot parameters globally using graph.par
, however, when I try this, the fontsize changes but the colours don't render
graph.par(list(nodes=list(fill="lightgreen", fontsize=10)))
renderGraph( Rgraphviz::layoutGraph(bnlearn::as.graphNEL(res)))
So you can alter the nodes returned by graphviz.plot
using the function nodeRenderInfo
:
g1 <- graphviz.plot(res)
graph::nodeRenderInfo(g1) <- list(fill="lightgreen", fontsize=8)
Rgraphviz::renderGraph(g1)
This does however, plot the network when assigning graphviz.plot
. So as an alternative you can change the graphNEL
object (returned by graphviz.plot
). By default, a graphNEL
object is either all directed or all undirected, however you can tweak the edges manually. This is what graphviz.plot
does. By looking at the code of bnlearn:::graphviz.backend
, it identifies undirected edges, and the renders them using graph::edgeRenderInfo(graph.plot)
. You can use similar methods to do what you want - use the function nodeRenderInfo
to update node attributes.
So all together:
# this sets all edges to directed
g <- Rgraphviz::layoutGraph(bnlearn::as.graphNEL(res))
# set undirected edges
u <- names(which(graph::edgeRenderInfo(g)[["direction"]] == "both"))
graph::edgeRenderInfo(g)[["arrowhead"]][u] = "none"
graph::edgeRenderInfo(g)[["arrowtail"]][u] = "none"
# update node attributes: fill colour and label fontsize
graph::nodeRenderInfo(g) <- list(fill="lightgreen", fontsize=8)
# render
Rgraphviz::renderGraph(g)