diff --git a/NAMESPACE b/NAMESPACE index f48b20b..a5cc9bf 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -52,7 +52,6 @@ export( makeNodeAttrs, pieGlyph, removedEdges, - toFile, layoutGraph ) @@ -69,7 +68,8 @@ exportClasses( ) exportMethods( - graphDataDefaults, + toFile, + graphDataDefaults, "graphDataDefaults<-", graphData, "graphData<-", diff --git a/R/AllGenerics.R b/R/AllGenerics.R index e8006e1..5cb0d6c 100644 --- a/R/AllGenerics.R +++ b/R/AllGenerics.R @@ -88,6 +88,8 @@ setGeneric("to", function(object) standardGeneric("to")) setGeneric("toDot", function(graph, filename, ...) standardGeneric("toDot")) +setGeneric("toFile", function(graph, layoutType="dot", filename, fileType="dot") standardGeneric("toFile")) + ################################################################### # graph attributes ################################################################### diff --git a/R/writers.R b/R/writers.R index 1fe7524..890ef1a 100644 --- a/R/writers.R +++ b/R/writers.R @@ -1,21 +1,48 @@ -toFile <- function(graph, layoutType = "dot", filename, fileType = "dot") { - if ( !is(graph,"Ragraph") ) stop("Given graph is not of class Ragraph") - - layoutType <- .checkLayoutType(layoutType) - fileType <- .checkFileType(fileType) - filename <- path.expand(filename) - if(!is.null(graphvizCapabilities()) && - ! fileType %in% graphvizCapabilities()$deviceTypes) { - warning("Graphviz does not support 'fileType'") - return(NULL) - } - - .Call("Rgraphviz_toFile", graph, - as.character(layoutType), - as.character(filename), - as.character(fileType), - PACKAGE="Rgraphviz") -} +## function that writes out an Rgraph to a file through the graphviz rendering engines +setMethod("toFile", c("Ragraph"), + function(graph, layoutType = "dot", filename, fileType = "dot") { + if ( !is(graph,"Ragraph") ) stop("Given graph is not of class Ragraph") + + layoutType <- .checkLayoutType(layoutType) + fileType <- .checkFileType(fileType) + filename <- path.expand(filename) + if(!is.null(graphvizCapabilities()) && + ! fileType %in% graphvizCapabilities()$deviceTypes) { + warning("Graphviz does not support 'fileType'") + return(NULL) + } + + .Call("Rgraphviz_toFile", graph, + as.character(layoutType), + as.character(filename), + as.character(fileType), + PACKAGE="Rgraphviz") + }) + +## function that writes out a dot graph given as a character vector to a file +## through the graphviz rendering engine +setMethod("toFile", c("character"), + function(graph, layoutType = "dot", filename, fileType = "dot") { + layoutType <- .checkLayoutType(layoutType) + fileType <- .checkFileType(fileType) + filename <- path.expand(filename) + + if(!is.null(graphvizCapabilities()) && + ! fileType %in% graphvizCapabilities()$deviceTypes) { + warning("Graphviz does not support 'fileType'") + return(NULL) + } + + ## now collapse the graph into a character vector of length 1 + graph <- paste(graph, collapse="\n") + + res <- .Call("Rgraphviz_dotToFile", as.character(graph), + as.character(layoutType), + as.character(filename), + as.character(fileType), + PACKAGE="Rgraphviz") + return(invisible(res)) + }) setMethod("toDot", "graph", function(graph, filename, ...) { z <- agopen(graph, name = "foo", ...) diff --git a/inst/GV/softwareGraph.gv b/inst/GV/softwareGraph.gv new file mode 100644 index 0000000..cee9e5b --- /dev/null +++ b/inst/GV/softwareGraph.gv @@ -0,0 +1,287 @@ + digraph "Software Graph" { +graph [ranksep="0.75", size="7.5,7.5"]; +node []; +"past" [shape="plaintext", fontsize="16"]; +"1978" [shape="plaintext", fontsize="16"]; +"1980" [shape="plaintext", fontsize="16"]; +"1982" [shape="plaintext", fontsize="16"]; +"1983" [shape="plaintext", fontsize="16"]; +"1985" [shape="plaintext", fontsize="16"]; +"1986" [shape="plaintext", fontsize="16"]; +"1987" [shape="plaintext", fontsize="16"]; +"1988" [shape="plaintext", fontsize="16"]; +"1989" [shape="plaintext", fontsize="16"]; +"1990" [shape="plaintext", fontsize="16"]; +"future" [shape="plaintext", fontsize="16"]; +"C*" [shape="box"]; +"DAG" [shape="box"]; +"CSAS" [shape="box"]; +"CIA" [shape="box"]; +"CIA++" [shape="box"]; +"APP" [shape="box"]; +"DOT" [shape="box"]; +"DIA" [shape="box"]; +"libft" [shape="box"]; +"Software IS" [shape="ellipse"]; +"Adv. Software Technology" [shape="box"]; +"SCCS" [shape="plaintext", fontsize="16"]; +"make" [shape="plaintext", fontsize="16"]; +"Bourne sh" [shape="plaintext", fontsize="16"]; +"yacc" [shape="plaintext", fontsize="16"]; +"cron" [shape="plaintext", fontsize="16"]; +"Reiser cpp" [shape="plaintext", fontsize="16"]; +"Cshell" [shape="plaintext", fontsize="16"]; +"build" [shape="plaintext", fontsize="16"]; +"vi" [shape="plaintext", fontsize="16"]; +"emacs" [shape="plaintext", fontsize="16"]; +"RCS" [shape="plaintext", fontsize="16"]; +"" [shape="plaintext", fontsize="16"]; +"SYNED" [shape="box"]; +"IMX" [shape="box"]; +"ksh" [shape="box"]; +"IFS" [shape="box"]; +"TTU" [shape="box"]; +"nmake" [shape="box"]; +"Peggy" [shape="box"]; +"ncpp" [shape="box"]; +"" [shape="box"]; +"ksh-i" [shape="box"]; +"PG2" [shape="box"]; +"Ansi cpp" [shape="box"]; +"fdelta" [shape="box"]; +"3D File System" [shape="box"]; +"nmake 2.0" [shape="box"]; +"SBCS" [shape="box"]; +"PAX" [shape="box"]; +"ksh-88" [shape="box"]; +"PEGASUS/PML" [shape="box"]; +"backtalk" [shape="box"]; +"SHIP" [shape="box"]; +"Data Share" [shape="box"]; +"ryacc" [shape="box"]; +"Mosaic" [shape="box"]; +"CoShell" [shape="box"]; +"sfio" [shape="box"]; +"IFS-i" [shape="box"]; +"ML-X" [shape="box"]; +"kyacc" [shape="box"]; +"yeast" [shape="box"]; +"Configuration Mgt" [shape="ellipse"]; +"Architecture & Libraries" [shape="ellipse"]; +"Process" [shape="ellipse"]; +edge []; +"past" -> "1978" []; +"1978" -> "1980" []; +"1980" -> "1982" []; +"1982" -> "1983" []; +"1983" -> "1985" []; +"1985" -> "1986" []; +"1986" -> "1987" []; +"1987" -> "1988" []; +"1988" -> "1989" []; +"1989" -> "1990" []; +"1990" -> "future" []; +"C*" -> "CSAS" []; +"DAG" -> "DOT" []; +"DAG" -> "DIA" []; +"DAG" -> "Software IS" []; +"CSAS" -> "CIA" []; +"CIA" -> "CIA++" []; +"CIA" -> "DIA" []; +"CIA++" -> "Software IS" []; +"APP" -> "DIA" []; +"APP" -> "Software IS" []; +"DOT" -> "Software IS" []; +"DIA" -> "Software IS" []; +"libft" -> "Software IS" []; +"Software IS" -> "Adv. Software Technology" []; +"SCCS" -> "RCS" []; +"SCCS" -> "3D File System" []; +"SCCS" -> "nmake" []; +"make" -> "nmake" []; +"make" -> "build" []; +"Bourne sh" -> "Cshell" []; +"Bourne sh" -> "ksh" []; +"yacc" -> "ryacc" []; +"cron" -> "yeast" []; +"Reiser cpp" -> "ncpp" []; +"Cshell" -> "ksh" []; +"build" -> "nmake 2.0" []; +"vi" -> "" []; +"vi" -> "ksh" []; +"emacs" -> "ksh" []; +"RCS" -> "fdelta" []; +"RCS" -> "SBCS" []; +"" -> "" []; +"SYNED" -> "Peggy" []; +"IMX" -> "TTU" []; +"ksh" -> "nmake" []; +"ksh" -> "ksh-i" []; +"ksh" -> "ksh-88" []; +"IFS" -> "" []; +"IFS" -> "sfio" []; +"IFS" -> "IFS-i" []; +"TTU" -> "PG2" []; +"nmake" -> "ncpp" []; +"nmake" -> "3D File System" []; +"nmake" -> "nmake 2.0" []; +"nmake" -> "ksh" []; +"Peggy" -> "PEGASUS/PML" []; +"Peggy" -> "ryacc" []; +"ncpp" -> "Ansi cpp" []; +"" -> "fdelta" []; +"ksh-i" -> "ksh-88" []; +"PG2" -> "backtalk" []; +"Ansi cpp" -> "Configuration Mgt" []; +"fdelta" -> "SBCS" []; +"fdelta" -> "PAX" []; +"3D File System" -> "Configuration Mgt" []; +"nmake 2.0" -> "Configuration Mgt" []; +"nmake 2.0" -> "CoShell" []; +"SBCS" -> "Configuration Mgt" []; +"PAX" -> "SHIP" []; +"ksh-88" -> "Configuration Mgt" []; +"ksh-88" -> "Architecture & Libraries" []; +"ksh-88" -> "sfio" []; +"PEGASUS/PML" -> "ML-X" []; +"PEGASUS/PML" -> "Architecture & Libraries" []; +"backtalk" -> "Data Share" []; +"SHIP" -> "Configuration Mgt" []; +"Data Share" -> "Architecture & Libraries" []; +"ryacc" -> "kyacc" []; +"Mosaic" -> "Process" []; +"CoShell" -> "Configuration Mgt" []; +"CoShell" -> "Architecture & Libraries" []; +"sfio" -> "Architecture & Libraries" []; +"IFS-i" -> "Architecture & Libraries" []; +"ML-X" -> "Architecture & Libraries" []; +"kyacc" -> "Architecture & Libraries" []; +"yeast" -> "Process" []; +"Configuration Mgt" -> "Adv. Software Technology" []; +"Architecture & Libraries" -> "Adv. Software Technology" []; +"Process" -> "Adv. Software Technology" []; +subgraph "past" { +graph [rank="same"]; +node []; +"past" []; +"SCCS" []; +"make" []; +"Bourne sh" []; +"yacc" []; +"cron" []; +edge []; +} +subgraph "1978" { +graph [rank="same"]; +node []; +"1978" []; +"Reiser cpp" []; +"Cshell" []; +edge []; +} +subgraph "1980" { +graph [rank="same"]; +node []; +"1980" []; +"build" []; +"emacs" []; +"vi" []; +edge []; +} +subgraph "1982" { +graph [rank="same"]; +node []; +"1982" []; +"RCS" []; +"" []; +"IMX" []; +"SYNED" []; +edge []; +} +subgraph "1983" { +graph [rank="same"]; +node []; +"1983" []; +"ksh" []; +"IFS" []; +"TTU" []; +edge []; +} +subgraph "1985" { +graph [rank="same"]; +node []; +"1985" []; +"nmake" []; +"Peggy" []; +edge []; +} +subgraph "1986" { +graph [rank="same"]; +node []; +"1986" []; +"C*" []; +"ncpp" []; +"ksh-i" []; +"" []; +"PG2" []; +edge []; +} +subgraph "1987" { +graph [rank="same"]; +node []; +"1987" []; +"Ansi cpp" []; +"nmake 2.0" []; +"3D File System" []; +"fdelta" []; +"DAG" []; +"CSAS" []; +edge []; +} +subgraph "1988" { +graph [rank="same"]; +node []; +"1988" []; +"CIA" []; +"SBCS" []; +"ksh-88" []; +"PEGASUS/PML" []; +"PAX" []; +"backtalk" []; +edge []; +} +subgraph "1989" { +graph [rank="same"]; +node []; +"1989" []; +"CIA++" []; +"APP" []; +"SHIP" []; +"Data Share" []; +"ryacc" []; +"Mosaic" []; +edge []; +} +subgraph "1990" { +graph [rank="same"]; +node []; +"1990" []; +"libft" []; +"CoShell" []; +"DIA" []; +"IFS-i" []; +"kyacc" []; +"sfio" []; +"yeast" []; +"ML-X" []; +"DOT" []; +edge []; +} +subgraph "future" { +graph [rank="same"]; +node []; +"future" []; +"Adv. Software Technology" []; +edge []; +} +} diff --git a/man/toFile.Rd b/man/toFile-methods.Rd similarity index 51% rename from man/toFile.Rd rename to man/toFile-methods.Rd index f79ae76..39cac5f 100644 --- a/man/toFile.Rd +++ b/man/toFile-methods.Rd @@ -1,5 +1,9 @@ -\name{toFile} +\name{toFile-methods} +\docType{methods} \alias{toFile} +\alias{toFile-methods} +\alias{toFile,character-method} +\alias{toFile,Ragraph-method} \title{Render a graph in a file with given format} \description{Render a graph in a file with given format} @@ -9,7 +13,8 @@ toFile(graph, layoutType = "dot", filename, fileType = "dot") } \arguments{ - \item{graph}{an instance of the \code{Ragraph} class} + \item{graph}{an instance of the \code{Ragraph} class; alternatively a + character vector that represents the graph in \code{dot} format} \item{layoutType}{Which layout algorithm to use. Defaults to dot, and see \code{graphvizCapabilities()$layoutTypes} for possible values.} \item{filename}{output file name} @@ -20,6 +25,16 @@ toFile(graph, layoutType = "dot", filename, fileType = "dot") This function takes a given \code{Ragraph}, does the chosen layout, then renders the output to an external file. Users could view the output file with corresponding viewer. + +The second usage of \code{toFile} is to use a character vector that +represents a graph in \code{dot} format. By using the character format, +all \emph{graphviz} options are possible in rendering the final +graph. However, please note that \emph{graphviz} as packaged in +\emph{Rgraphviz} currently has limited support for certain features +(e.g. HTML labels are not rendered). In this case, please consider +installing \emph{graphviz} on your computer, saving the dot graph +to a file and running it through the installed version to get improved +functionality (depending on your installation). } \value{ @@ -28,7 +43,7 @@ with corresponding viewer. \references{Rgraphviz by E. Ganssner, S. North, www.graphviz.org } -\author{Li Long } +\author{Li Long , Holger Hoefling } \examples{ g1_gz <- gzfile(system.file("GXL/graphExample-01.gxl.gz", @@ -42,6 +57,11 @@ if(require(XML)) { toFile(ag, layoutType="neato", filename="g1_neato.ps", fileType="ps") toFile(ag, layoutType="twopi", filename="g1_twopi.svg", fileType="svg") } + +software.dot <- readLines(system.file("GV/softwareGraph.gv", + package="Rgraphviz")) +toFile(software.dot, layoutType="dot", filename="softwareGraph.svg", fileType="svg") } -\keyword{ models } +\keyword{methods} +\keyword{graphs} diff --git a/src/RgraphvizInit.c b/src/RgraphvizInit.c index a49ba50..d5ccbe0 100644 --- a/src/RgraphvizInit.c +++ b/src/RgraphvizInit.c @@ -12,6 +12,7 @@ static const R_CallMethodDef R_CallDef[] = { {"Rgraphviz_buildEdgeList", (DL_FUNC)&Rgraphviz_buildEdgeList, 7}, {"Rgraphviz_toFile", (DL_FUNC)&Rgraphviz_toFile, 4}, + {"Rgraphviz_dotToFile", (DL_FUNC)&Rgraphviz_dotToFile, 4}, {"Rgraphviz_getDefAttrsGraph", (DL_FUNC)&Rgraphviz_getDefAttrsGraph, 1}, {"Rgraphviz_setDefAttrsGraph", (DL_FUNC)&Rgraphviz_setDefAttrsGraph, 3}, diff --git a/src/common.h b/src/common.h index 36a147b..61b5c26 100644 --- a/src/common.h +++ b/src/common.h @@ -39,6 +39,7 @@ SEXP Rgraphviz_graphvizVersion(void); SEXP Rgraphviz_init(void); SEXP Rgraphviz_toFile(SEXP, SEXP, SEXP, SEXP); +SEXP Rgraphviz_dotToFile(SEXP, SEXP, SEXP, SEXP); SEXP Rgraphviz_agopenSimple(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); SEXP Rgraphviz_getDefAttrsGraph(SEXP); diff --git a/src/dotToFile.c b/src/dotToFile.c new file mode 100644 index 0000000..1fc8f9f --- /dev/null +++ b/src/dotToFile.c @@ -0,0 +1,18 @@ +#include "common.h" +#include "util.h" +#include + +Agraph_t* myg = NULL; + +SEXP Rgraphviz_dotToFile(SEXP graph, SEXP layoutType, SEXP filename, SEXP fileType) +{ + char * char_graph = ALLOC_CHAR(graph, 0); + myg = agmemread(char_graph); + gvLayout(gvc, myg, ALLOC_CHAR(layoutType, 0)); + gvRenderFilename(gvc, myg, ALLOC_CHAR(fileType, 0), ALLOC_CHAR(filename, 0) ); + gvFreeLayout(gvc, myg); + agclose(myg); + return(R_NilValue); + +} +