[BioC] fontsize in Rgraphviz
Mark W Kimpel
mwkimpel at gmail.com
Fri Feb 1 07:11:28 CET 2008
Florian,
Here is a potential way to get some more plotting symbols into
Rgraphviz, most of these based on those available in Graphviz. I have a
vested interest in getting more symbols as I am already using fill-color
to denote fold change direction and p value and size to indicate fold
change magnitude. I'd like to denote up to 5 or 6 different KEGG
pathways in one graph. Anyways, here goes:
The relevant section of your code is found in renderGraph.R:
## deal with different shapes
possible.shapes <-
c("circle", "ellipse", "box", "rectangle", "plaintext")
shape <-
possible.shapes[pmatch(shape,
possible.shapes,
duplicates.ok = TRUE)]
## shape == circle
i <- shape == "circle"
if (any(i, na.rm=TRUE))
{
symbols(nodeX[i], nodeY[i], circles = rad[i],
fg = col[i], bg = fill[i],
inches = FALSE, add = TRUE)
}
##############################################################
I have come up with the following self-contained code-snippet which
follows to demonstrate a way to draw other shapes with user-specified
radii. If you and others think this is an okay way to go, then I will
work on a patch for renderGraph.R. I also believe that the workhorse
function polygon.vertex.calc.func could be modified to calculate
ellipses so that box, rectangle, circle, and ellipse could all use this
as a generic and users could specify height and width instead of radii
to customize the other shapes below.
Let me know what you think. Mark
#calculates vertices of a regular polygon centered on origin using
radius and number of vertices. First vertex is on y axis
# unless 'shift' is specified in degrees, positive (up) or negative (down)
polygon.vertex.calc.func <- function(no.vert, radius, shift.deg){
x <- y <- rep(0, no.vert)
shift.rad <- (shift.deg * 2 * pi)/360
for (i in 1:no.vert){
x[i] <- radius * (cos((((2 * pi)/no.vert) * (i - 1)) + (shift.rad)))
y[i] <- radius * (sin((((2 * pi)/no.vert) * (i - 1)) + (shift.rad)))
}
vertex.list <- list(x = x,y = y)
}
############################################################################
triangle.func <- function(radius = 1){
vertex.list <- polygon.vertex.calc.func(no.vert = 3, radius,
shift.deg = 90)
vertex.list
}
############################################################################
inverted.triangle.func <- function(radius = 1){
vertex.list <- polygon.vertex.calc.func(no.vert = 3, radius,
shift.deg = 270)
vertex.list
}
############################################################################
pentagon.func <- function(radius = 1){
vertex.list <- polygon.vertex.calc.func(no.vert = 5, radius,
shift.deg = 18)
vertex.list
}
############################################################################
octagon.func <- function(radius = 1){
vertex.list <- polygon.vertex.calc.func(no.vert = 8, radius,
shift.deg = 0)
vertex.list
}
############################################################################
house.func <- function(radius = 1){
vertex.list <- pentagon.func(radius)
vertex.list$x[4] <- vertex.list$x[3]
vertex.list$x[5] <- vertex.list$x[1]
vertex.list
}
############################################################################
inverted.house.func <- function(radius = 1){
vertex.list <- pentagon.func(radius)
vertex.list$x[4] <- vertex.list$x[3]
vertex.list$x[5] <- vertex.list$x[1]
vertex.list$x <- -1 * vertex.list$x
vertex.list$y <- -1 * vertex.list$y
vertex.list
}
########################################
op <- par()
par(mfrow=c(2,4))
###########################################
plot(c(-2,2), c(-2,2), type="n")
vertex.list <- triangle.func(radius = 1)
polygon(x = vertex.list$x, y = vertex.list$y)
###########################################
plot(c(-2,2), c(-2,2), type="n")
vertex.list <- inverted.triangle.func(radius = 1)
polygon(x = vertex.list$x, y = vertex.list$y)
###########################################
plot(c(-2,2), c(-2,2), type="n")
vertex.list <- inverted.triangle.func(radius = 1)
polygon(x = vertex.list$x, y = vertex.list$y)
vertex.list <- triangle.func(radius = 1)
polygon(x = vertex.list$x, y = vertex.list$y)
###########################################
plot(c(-2,2), c(-2,2), type="n")
vertex.list <- pentagon.func(radius = 1)
polygon(x = vertex.list$x, y = vertex.list$y)
###########################################
plot(c(-2,2), c(-2,2), type="n")
vertex.list <- octagon.func(radius = 1)
polygon(x = vertex.list$x, y = vertex.list$y)
###########################################
plot(c(-2,2), c(-2,2), type="n")
vertex.list <- octagon.func(radius = 1)
polygon(x = vertex.list$x, y = vertex.list$y)
vertex.list <- octagon.func(radius = 0.75)
polygon(x = vertex.list$x, y = vertex.list$y)
###########################################
plot(c(-2,2), c(-2,2), type="n")
vertex.list <- house.func(radius = 1)
polygon(x = vertex.list$x, y = vertex.list$y)
###########################################
plot(c(-2,2), c(-2,2), type="n")
vertex.list <- inv.house.func(radius = 1)
polygon(x = vertex.list$x, y = vertex.list$y)
###########################################
###########################################
###########################################
###########################################
###########################################
par(op)
Mark W. Kimpel MD ** Neuroinformatics ** Dept. of Psychiatry
Indiana University School of Medicine
15032 Hunter Court, Westfield, IN 46074
(317) 490-5129 Work, & Mobile & VoiceMail
(317) 204-4202 Home (no voice mail please)
mwkimpel<at>gmail<dot>com
******************************************************************
Florian Hahne wrote:
> Hi Mark,
> to get you all the way, take a look at this:
>
> require(Rgraphviz)
> # Generate random graph
> set.seed(123)
> nodeNames <- letters[1:10]
> M <- 1:4
> g1 <- randomGraph(nodeNames, M, .2)
>
> nAttrs <- list()
>
> #node width
> nAttrs$width <- rep(3, length(nodeNames))
> names(nAttrs$width)<-nodeNames
>
> #node height
> nAttrs$height <- rep(3, length(nodeNames))
> names(nAttrs$height)<-nodeNames
>
> #font size
> fontsize <- rep(c(1, 2), (length(nodeNames)/2))
> names(fontsize)<-nodeNames
>
> #layout and render
> x <- layoutGraph(g1, nodeAttr=nAttrs)
> nodeRenderInfo(x) <- list(cex=fontsize)
> renderGraph(x, graph.pars=list(nodes=list(fill="black",
> textCol="white")))
>
> I didn't set the node shape at all, because the default for dot is to
> use "ellipse", and since you fix your node widths and node heights to
> the same size, this boils down to a circle. I also set the fill and text
> color as attributes in the graph.pars argument to renderGraph, but
> Deepayan's suggestion works, too. The only difference is, that the
> latter permanently assigns the colors to the graph object x, while the
> former takes effect only for the current rendering operation.
>
> nodeRenderInfo(x) <- list(cex=fontsize, fill="black", textCol="white")
> renderGraph(x)
>
> fillcolor is ignored in your example because in the new rendering API
> this parameter is called fill (we tried to stay closer to R's base
> graphic parameter names, and thinking of that now, maybe we should
> rename textCol to font.col or something similar). I just uploaded a much
> more detailed vignette and some bug fixes, and these changes should be
> available soon in Rgraphviz version 1.17.12. If you know how to access
> the svn repository you can get this update immediately. In the Vignette
> there are also tables of the available parameters for nodes, edges and
> the whole graph and I will update the documentation accordingly ASAP.
>
> Everything that affects the graph layout can still be passed on to
> Graphviz as nodeAttrs, edgeAttrs or attrs arguments. For instance, the
> following would change the node shapes:
>
> nAttrs$shape <- c("circle", "rect", rep(c("ellipse", "box"), 4))
> names(nAttrs$shape )<- nodeNames
> x <- layoutGraph(g1, nodeAttr=nAttrs)
> renderGraph(x)
> Again, since widths and heights of the nodes are constant, there's no
> difference between ellipse and circle (box and rect are synonyms,
> anyways). You can see the difference here:
>
> nAttrs$width <- rep(6, length(nodeNames))
> names(nAttrs$width)<-nodeNames
> x <- layoutGraph(g1, nodeAttr=nAttrs)
> renderGraph(x)
>
> Another Graphviz parameter that I find quite useful is fixedsize. If
> this is set to TRUE (the default) all nodes will be forced to have the
> same size unless manually changed. For FALSE, the node sizes will be
> computed from the labels, so longer labels will create larger nodes. As
> far as I remeber, this has to be given to the attrs argument, something
> like this:
>
> attrs <- list(node=list(fixedsize=FALSE))
> x <- layoutGraph(g1, nodeAttr=nAttrs, attrs=attrs)
>
> I'm affaid I can't really point you to the C code for the Graphviz
> interaction (we tried to stay clear of that, it's so easy to break
> things there...), but agopen is the workhorse in Rgraphviz to talk to
> the Graphviz library. Starting there and working your way though the
> code should quickly get you to the interesting C calls. Once you've
> figured out a way to access the different shapes in Graphviz and how to
> get the coordinates back into R, it is straightforward to render them.
> Everything that is stored in the Ragraph object (the return value of
> agopen) can be accessed by our rendering API.
>
> Cheers,
> Florian
>
>
>
>
>
> Mark W Kimpel schrieb:
>> Deepayan,
>>
>> We are making progress. I just updated Rgraphviz-devel. Simply
>> adjusting the way adjusting my parameters to "layoutGraph" as you
>> suggested fixed the font size problem! I did not have to add it at the
>> nodeRenderInfo stage. Attached is a postscript file documenting the
>> results, which would look prettier if I had bothered to adjust the
>> size of the output.
>>
>> Unfortunately, now nAttrs$fillcolor is being ignored, even if it is
>> added as an argument to noRenderInfo.
>>
>> Also, I would very much like to use many of the other shapes available
>> via graphviz. If I was willing to do some of the coding (I know some
>> C), would you point me in the right direction so that I might provide
>> a patch with more shapes?
>>
>> Thanks,
>> Mark
>>
>>
>> Mark W. Kimpel MD ** Neuroinformatics ** Dept. of Psychiatry
>> Indiana University School of Medicine
>>
>> 15032 Hunter Court, Westfield, IN 46074
>>
>> (317) 490-5129 Work, & Mobile & VoiceMail
>> (317) 204-4202 Home (no voice mail please)
>>
>> mwkimpel<at>gmail<dot>com
>>
>> ******************************************************************
>>
>>
>> Deepayan Sarkar wrote:
>>> On 1/30/08, Mark W Kimpel <mwkimpel at gmail.com> wrote:
>>>> Sorry for the complex prior example, I shouldn't write emails late at
>>>> night. Below is a self-contained, reproducible example.
>>>>
>>>> I've made some progress and can get the following script to flow
>>>> without
>>>> error messages. The fontsize, however, is not varying as I believe it
>>>> should and when I substitute "ellipse" for circle the width and height
>>>> parameters do not appropriately effect the shape.
>>>
>>> There are certain attributes which need to be supplied at the layout
>>> step, especially shape, width, and height, as without these the edges
>>> (which need to start from node boundaries) will not be placed
>>> properly. So, you need to supply nAttrs to layoutGraph as
>>>
>>> x <- layoutGraph(g1, nodeAttrs = nAttrs)
>>>
>>> Of course, it's not clear from the documentation that you can do this!
>>>
>>>> I also do not understand where I can specify "neato" vs. "dot" for the
>>>> rendering layout.
>>>
>>> Same goes for this; you can do
>>>
>>> x <- layoutGraph(g1, nodeAttrs = nAttrs, layoutType = "neato")
>>>
>>> The trick is to notice that the default layout function in
>>> 'layoutGraph' is 'layoutGraphviz', which is unexported, but you can
>>> get it's argument list by
>>>
>>>> args(Rgraphviz:::layoutGraphviz)
>>> function (x, layoutType = "dot", name = "graph", recipEdges =
>>> "combined",
>>> nodeAttrs = list(), edgeAttrs = list(), ...)
>>>
>>>
>>> Unfortunately, the fontsize doesn't seem to be retained in the result
>>> of layoutGraph, and I'm not sure yet if that's a bug in our wrapper or
>>> a limitation of the graphviz interface. We will look into it.
>>>
>>>> Also, where to specify a title.
>>>
>>> Generally speaking, our new model is that once the layout is done, you
>>> should be able to modify other attributes before rendering. These
>>> attributes are divided into three types: those for nodes, those for
>>> edges, and those for the whole graph, and these can be accessed and
>>> modified using nodeRenderInfo(), edgeRenderInfo(), and
>>> graphRenderInfo(), respectively.
>>>
>>> So, to come back to your problem, once you have the layout done, you
>>> can modify the fontsize and title as follows:
>>>
>>> nodeRenderInfo(x) <- list(fontsize = nAttrs$fontsize * 5)
>>> graphRenderInfo(x) <- list(main = "Main title")
>>>
>>> and then finally render it with
>>>
>>> renderGraph(x)
>>>
>>> Obviously there are many warts still to be worked out.
>>>
>>> -Deepayan
>>>
>>>> Thanks, mark
>>>>
>>>>
>>>> ####################
>>>> require(Rgraphviz)
>>>> # Generate random graph
>>>> set.seed(123)
>>>> nodeNames <- letters[1:10]
>>>> M <- 1:4
>>>> g1 <- randomGraph(nodeNames, M, .2)
>>>>
>>>> nAttrs <- list()
>>>>
>>>> #node shapes
>>>> nAttrs$shape <- rep("circle", length(nodeNames))
>>>> names(nAttrs$shape )<- nodeNames
>>>>
>>>> #node width
>>>> nAttrs$width <- rep(3, length(nodeNames))
>>>> names(nAttrs$width)<-nodeNames
>>>>
>>>> #node height
>>>> nAttrs$height <- rep(3, length(nodeNames))
>>>> names(nAttrs$height)<-nodeNames
>>>>
>>>> #node colors
>>>> nAttrs$fillcolor <-rep("black", length(nodeNames))
>>>> names(nAttrs$fillcolor) <- nodeNames
>>>>
>>>> #font color
>>>> nAttrs$fontcolor <- rep("white", length(nodeNames))
>>>> names(nAttrs$fontcolor)<-nodeNames
>>>>
>>>> #font size
>>>> nAttrs$fontsize <- rep(c(1, 2), (length(nodeNames)/2))
>>>> names(nAttrs$fontsize)<-nodeNames
>>>>
>>>> postscript(file="my.test.graph.ps", paper="special",width=4, height=5)
>>>> #set up graphics device
>>>> x <- layoutGraph(g1)
>>>> nodeRenderInfo(x) = nAttrs
>>>> renderGraph(x)
>>>> dev.off()## close the graphics device
>>>>
>>>>
>>>>
>>>> Mark W. Kimpel MD ** Neuroinformatics ** Dept. of Psychiatry
>>>> Indiana University School of Medicine
>>>>
>>>> 15032 Hunter Court, Westfield, IN 46074
>>>>
>>>> (317) 490-5129 Work, & Mobile & VoiceMail
>>>> (317) 204-4202 Home (no voice mail please)
>>>>
>>>> mwkimpel<at>gmail<dot>com
>>>
>> ------------------------------------------------------------------------
>>
>> _______________________________________________
>> Bioconductor mailing list
>> Bioconductor at stat.math.ethz.ch
>> https://stat.ethz.ch/mailman/listinfo/bioconductor
>> Search the archives:
>> http://news.gmane.org/gmane.science.biology.informatics.conductor
>
>
More information about the Bioconductor
mailing list