Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Use graphviz with pure java

License

NotificationsYou must be signed in to change notification settings

nidi3/graphviz-java

Repository files navigation

Build StatuscodecovLicenseMaven Central

Use graphviz with pure java. Create graphviz models using java code and convert them into nice graphics.

How it works

To execute the graphviz layout engine, one of these options is used:

  • If the machine has graphviz installed and adot command is available, spawn a new process runningdot.
  • Use thisjavascript version of graphviz and execute it on the V8 javascript engine.This is done with the bundledJ2V8 library.
  • Alternatively, the javascript can be executed on Java's own Nashorn or GraalVM engine (preferring Graal if both are available).

The method(s) to be used can be configured with theGraphviz.useEngine() method.

Prerequisites

This project heavily uses classes fromjava.awt. Therefore,it does not work on android.

Maven

This project is available via Maven:

<dependency>    <groupId>guru.nidi</groupId>    <artifactId>graphviz-java</artifactId>    <version>0.18.1</version></dependency>

graphviz-java contains all needed dependencies including one toJ2V8 for the current platform (Linux, Mac OS X, Windows).This should be ok for most use cases.

gradle does not support this way of defining a dependency. Gradle users have to manually add a dependency to J2V8,e.g.com.eclipsesource.j2v8:j2v8_linux_x86_64:4.6.0

Instead ofgraphviz-java there are two alternative dependencies that can be used:

  • graphviz-java-all-j2v8 additionally contains dependencies toallJ2V8 platforms.So the same application can run on Linux, Mac OS X and Windows.
  • graphviz-java-min-deps contains only dependencies that are absolutely necessary.All other dependencies are marked asoptional and must added manually. See thepom.xml for details.

Instead ofJ2V8, one can also use the JDK javascript engine Nashorn.If Nashorn is too slow or on JDK version 15 or newer (where Nashorn has been removed),the graaljavascript engine is a third option.It needs this additional dependency:

<dependency>    <groupId>org.graalvm.js</groupId>    <artifactId>js</artifactId>    <version>20.0.0</version></dependency>

Logging

Graphviz-java uses theSLF4J facade to log.Users must therefore provide a logging implementation likeLOGBack

<dependency>    <groupId>ch.qos.logback</groupId>    <artifactId>logback-classic</artifactId>    <version>1.2.3</version></dependency>

orLog4j

<dependency>    <groupId>org.apache.logging.log4j</groupId>    <artifactId>log4j-core</artifactId>    <version>2.13.0</version></dependency><dependency>    <groupId>org.apache.logging.log4j</groupId>    <artifactId>log4j-slf4j-impl</artifactId>    <version>2.13.0</version></dependency>

API

The API is separated into a mutable and immutable part.The basic usage is as follows (assumingimport static guru.nidi.graphviz.model.Factory.*).

Immutable

Graphg =graph("example1").directed()        .graphAttr().with(Rank.dir(LEFT_TO_RIGHT))        .nodeAttr().with(Font.name("arial"))        .linkAttr().with("class","link-class")        .with(node("a").with(Color.RED).link(node("b")),node("b").link(to(node("c")).with(attr("weight",5),Style.DASHED)                )        );Graphviz.fromGraph(g).height(100).render(Format.PNG).toFile(newFile("example/ex1.png"));

  • Global attributes are set using thegraphAttr,linkAttr andnodeAttr methods.
  • Nodes are styled using thewith method.
  • To style edges, use the static methodto which returns aLink that also has awith method.
  • Thewith method accepts predefined attributes likeStyle,Arrow orShapeas well as everything defined in theGraphviz referencee.g.with("weight", 5) or even arbitrary custom attributes.
  • Custom attribute classes can be defined by extendingSingleAttributes orMapAttributes.

Attention:Node a = node("a"); a.with(Color.RED); Is not working as it might be expected.All "mutating" methods likewith on nodes, links and graphs create new objects and leave the original object unchanged.So in the example above, variablea contains a node that is NOT red.If you want a red node, doa = a.with(Color.RED) or use the mutable API.

Mutable

MutableGraphg =mutGraph("example1").setDirected(true).add(mutNode("a").add(Color.RED).addLink(mutNode("b")));Graphviz.fromGraph(g).width(200).render(Format.PNG).toFile(newFile("example/ex1m.png"));

The mutable API provides similar functions as the immutable one with slightly different syntax:

  • mutGraph instead ofgraph,mutNode instead ofnode
  • use setters:setDirected instead ofdirected
  • add instead ofwidth

Imperative

There is a third possibility to use the API, based on the mutable version.Its form is closer to the way dot files are written.In the lambda of theMutableGraph.use method, all referenced nodes, links and graphs are automatically added to the parent graph,without explicitly calling theadd method.

MutableGraphg =mutGraph("example1").setDirected(true).use((gr,ctx) -> {mutNode("b");nodeAttrs().add(Color.RED);mutNode("a").addLink(mutNode("b"));});Graphviz.fromGraph(g).width(200).render(Format.PNG).toFile(newFile("example/ex1i.png"));

This corresponds to the followingdot file:

digraphexample1 {    bnode[color=red]    a-> b}

Kotlin DSL

Kotlin DSL is still experimental. Things can change and any feedback is very welcome.

<dependency>    <groupId>guru.nidi</groupId>    <artifactId>graphviz-kotlin</artifactId>    <version>0.18.1</version></dependency>

The kotlin DSL based on the imperative API. It defines that following elements:

  • edge,node,graph variables to define global attributes.
  • -,/,[] operators on MutableNode which link, define ports, set attributes.
  • -,/,[] operators on String so that strings can be used directly to define nodes.
  • -,[] operators on Link which allow to chain links and set attributes.

To enable the functions, useimport guru.nidi.graphviz.*

graph(directed=true) {    edge["color" eq"red",Arrow.TEE]    node[Color.GREEN]    graph[Rank.dir(LEFT_TO_RIGHT)]"a"-"b"-"c"    ("c"[Color.RED]-"d"[Color.BLUE])[Arrow.VEE]"d"/NORTH-"e"/SOUTH}.toGraphviz().render(PNG).toFile(File("example/ex1.png"))

Parsing

Dot files can be parsed and thus manipulated. Given this filecolor.dot:

graph {    { rank=same; white}    { rank=same; cyan; yellow; pink}    { rank=same; red; green; blue}    { rank=same; black}    white -- cyan -- blue    white -- yellow -- green    white -- pink -- red    cyan -- green -- black    yellow -- red -- black    pink -- blue -- black}

Then running this program:

try (InputStreamdot =getClass().getResourceAsStream("/color.dot")) {MutableGraphg =newParser().read(dot);Graphviz.fromGraph(g).width(700).render(Format.PNG).toFile(newFile("example/ex4-1.png"));g.graphAttrs()            .add(Color.WHITE.gradient(Color.rgb("888888")).background().angle(90))            .nodeAttrs().add(Color.WHITE.fill())            .nodes().forEach(node ->node.add(Color.named(node.name().toString()),Style.lineWidth(4),Style.FILLED));Graphviz.fromGraph(g).width(700).render(Format.PNG).toFile(newFile("example/ex4-2.png"));}

results in this graphics:

Examples

Complex example

Nodemain =node("main").with(Label.html("<b>main</b><br/>start"),Color.rgb("1020d0").font()),init =node(Label.markdown("**_init_**")),execute =node("execute"),compare =node("compare").with(Shape.RECTANGLE,Style.FILLED,Color.hsv(.7,.3,1.0)),mkString =node("mkString").with(Label.lines(LEFT,"make","a","multi-line")),printf =node("printf");Graphg =graph("example2").directed().with(main.link(to(node("parse").link(execute)).with(LinkAttr.weight(8)),to(init).with(Style.DOTTED),node("cleanup"),to(printf).with(Style.BOLD,Label.of("100 times"),Color.RED)),execute.link(graph().with(mkString,printf),to(compare).with(Color.RED)),init.link(mkString));Graphviz.fromGraph(g).width(900).render(Format.PNG).toFile(newFile("example/ex2.png"));

Example with records

importstaticguru.nidi.graphviz.attribute.Records.*;importstaticguru.nidi.graphviz.model.Compass.*;
Nodenode0 =node("node0").with(Records.of(rec("f0",""),rec("f1",""),rec("f2",""),rec("f3",""),rec("f4",""))),node1 =node("node1").with(Records.of(turn(rec("n4"),rec("v","719"),rec("")))),node2 =node("node2").with(Records.of(turn(rec("a1"),rec("805"),rec("p","")))),node3 =node("node3").with(Records.of(turn(rec("i9"),rec("718"),rec("")))),node4 =node("node4").with(Records.of(turn(rec("e5"),rec("989"),rec("p","")))),node5 =node("node5").with(Records.of(turn(rec("t2"),rec("v","959"),rec("")))),node6 =node("node6").with(Records.of(turn(rec("o1"),rec("794"),rec("")))),node7 =node("node7").with(Records.of(turn(rec("s7"),rec("659"),rec(""))));Graphg =graph("example3").directed()        .graphAttr().with(Rank.dir(LEFT_TO_RIGHT))        .with(node0.link(between(port("f0"),node1.port("v",SOUTH)),between(port("f1"),node2.port(WEST)),between(port("f2"),node3.port(WEST)),between(port("f3"),node4.port(WEST)),between(port("f4"),node5.port("v",NORTH))),node2.link(between(port("p"),node6.port(NORTH_WEST))),node4.link(between(port("p"),node7.port(SOUTH_WEST))));Graphviz.fromGraph(g).width(900).render(Format.PNG).toFile(newFile("example/ex3.png"));

Images

Images can be included in graphviz in two ways.

One possibility is using the <img> tag inside a HTML label:

Graphviz.useEngine(newGraphvizCmdLineEngine());Graphvizg =Graphviz.fromGraph(graph()        .with(node(Label.html("<table border='0'><tr><td><img src='graphviz.png' /></td></tr></table>"))));g.basedir(newFile("example")).render(Format.PNG).toFile(newFile("example/ex7.png"));

Because viz.jsdoes not support <img> tags,this works only when using the command line engine.

The other possibility is theimage attribute of a node:

Graphvizg =Graphviz.fromGraph(graph()        .with(node(" ").with(Size.std().margin(.8,.7),Image.of("graphviz.png"))));g.basedir(newFile("example")).render(Format.PNG).toFile(newFile("example/ex8.png"));

This works with all engines.

In both cases, thebasedir() method can be used to define where relative paths are looked up.

Configuration

The size of the resulting image, the rendering engine and the output format can be configured:

Graphviz.useEngine(newGraphvizCmdLineEngine());// Rasterizer.builtIn() works only with CmdLineEngineGraphg =graph("example5").directed().with(node("abc").link(node("xyz")));Graphvizviz =Graphviz.fromGraph(g);viz.width(200).render(Format.SVG).toFile(newFile("example/ex5.svg"));viz.width(200).rasterize(Rasterizer.BATIK).toFile(newFile("example/ex5b.png"));viz.width(200).rasterize(Rasterizer.SALAMANDER).toFile(newFile("example/ex5s.png"));viz.width(200).rasterize(Rasterizer.builtIn("pdf")).toFile(newFile("example/ex5p"));Stringdot =viz.render(Format.DOT).toString();Stringjson =viz.engine(Engine.NEATO).render(Format.JSON).toString();BufferedImageimage =viz.render(Format.PNG).toImage();

To rasterize with batik, provide this library on the classpath:

<dependency>    <groupId>org.apache.xmlgraphics</groupId>    <artifactId>batik-rasterizer</artifactId>    <version>1.13</version></dependency>

Processors

Processors can be registered to further customize what goes in and out of the graphviz engine.

  • Pre processors change the dot file that is fed into the graphviz engine.
  • Post processor change the result of the graphviz engine (image, svg,...).
Graphgraph =graph().with(node("bad word").link("good word"));Graphvizg =Graphviz.fromGraph(graph)        .preProcessor((source,options,processOptions) ->source.replace("bad word","unicorn"))        .postProcessor((result,options,processOptions) ->result.mapString(svg ->SvgElementFinder.use(svg,finder -> {finder.findNode("unicorn").setAttribute("class","pink");                        })));g.render(Format.PNG).toFile(newFile("example/ex9.png"));

Javadoc

To use graphviz inside javadoc comments, add this topom.xml:

<build>  <plugins>    <plugin>      <artifactId>maven-javadoc-plugin</artifactId>      <version>3.1.0</version>      <configuration>        <taglet>guru.nidi.graphviz.taglet.GraphvizTaglet</taglet>        <tagletArtifact>          <groupId>guru.nidi</groupId>          <artifactId>graphviz-taglet</artifactId>          <version>0.18.1</version>        </tagletArtifact>      </configuration>    </plugin>  </plugins></build>

To use this with JDK 9 or later, replacegraphviz-tagletwithgraphviz-taglet9.

The usage inside javadoc is then as follows:

/** * Support graphviz inside javadoc. * <p> * {@graphviz * graph test { a -- b } * } * </p> * So easy. */publicclassGraphvizTagletimplementsTaglet {}

Sketchy

To change the appearance of the graph into something more sketchy / hand drawn, theRoughifyer processor can be used.First, add the rough module to the dependencies:

<dependency>    <groupId>guru.nidi</groupId>    <artifactId>graphviz-rough</artifactId>    <version>0.18.1</version></dependency>

Then, apply theRoughifyer to the graph:

finalGraphg =graph("ex1").directed().with(graph().cluster()                .nodeAttr().with(Style.FILLED,Color.WHITE)                .graphAttr().with(Style.FILLED,Color.LIGHTGREY,Label.of("process #1"))                .with(node("a0").link(node("a1").link(node("a2")))),graph("x").cluster()                .nodeAttr().with(Style.FILLED)                .graphAttr().with(Color.BLUE,Label.of("process #2"))                .with(node("b0").link(node("b1").link(node("b2")))),node("start").with(Shape.M_DIAMOND).link("a0","b0"),node("a0").with(Style.FILLED,Color.RED.gradient(Color.BLUE)).link("b1"),node("b1").link("a2"),node("a2").link("end"),node("b2").link("end"),node("end").with(Shape.M_SQUARE));Graphviz.fromGraph(g)        .processor(newRoughifyer()                .bowing(2)                .curveStepCount(6)                .roughness(1)                .fillStyle(FillStyle.hachure().width(2).gap(5).angle(0))                .font("*serif","Comic Sans MS"))        .render(Format.PNG)        .toFile(newFile("example/ex1-rough.png"));

About

Use graphviz with pure java

Topics

Resources

License

Code of conduct

Stars

Watchers

Forks

Sponsor this project

 

Packages

No packages published

Languages


[8]ページ先頭

©2009-2025 Movatter.jp