畫圖|DAG圖、狀態轉換圖、基本塊


目的

用Java或則Python畫出DAG圖、狀態轉換圖
應用場景:編譯原理等課程設計 畫自動機、狀態轉換圖、基本塊等有向圖

效果如下:

1.安裝

1.需要用到 graphviz,需要下載 http://www.graphviz.org/download/
但是上面下載太慢了,打包一個windows版的下載鏈接:https://www.yun.cn/s/31884bceaad04c3e8c630212babc0639
步驟A.下載:下載完解壓到某個文件夾就可以了。
步驟B.配置環境變量:添加剛才解壓的文件夾下的bin目錄到Path環境變量中



打開cmd,輸入dot -V 如果有顯示,就代表安裝成功、配置環境成功了。要是沒顯示就重新再來一遍。

2.畫圖

直接用安裝的graphviz里的dot工具畫一個圖試試

步驟A:新建一個txt文件

把下面的dot命令復制進去

digraph G {
  A->B
  B->C[label="a"]
  C->D[label="1"]
}

打開cmd命令行,輸入以下命令,用dot工具就可以生成狀態轉換圖。
其中D:\graph\example.txt是剛才新建的txt文件的目錄文件名
其中D:\graph\example.jpg是想要生成圖片的文件目錄文件名稱

dot D:\graph\example.txt -T jpg -o D:\graph\example.jpg

這個時候,可以猜測到之前txt文本中的命令的含義,A->B就是結點A到B連一條有向邊,B->C[label="a"]就是結點B向結點C連一條有向邊,並且邊權寫上label=a

digraph G {
  A->B
  B->C[label="a"]
  C->D[label="1"]
}

另外如果想給結點里面添加自定義的文字,也可以給結點添加lebl值,例如下圖和下面的指令所示

3.程序畫圖

可以用Java或則Python寫程序進行畫圖,Python更簡單網上有很多方法只需要導入庫,這篇文章主要來演示用Java來進行畫圖

暫時沒有Java相關的API。
所以要自己寫一個生成dot指令的,
dot指令就是下面的代碼,上文中我們寫好了代碼,在cmd下用dot命令就能生成圖了。
dot D:\graph\example.txt -T jpg -o D:\graph\example.jpg

digraph G {
  A->B
  B->C[label="a"]
  C->D[label="1"]
}

如果要用Java程序實現,我們需要完成幾個功能:
1.生成dot指令(生成邊和結點,比如生成A->B這個字符串或則生成 A[label="write some"]這個帶有文字的結點)。
2.執行cmd下生成有向圖的命令。
3.自動打開生成的圖片。

所以就寫好了個工具類來玩。原理就是實現了上面幾個功能,復制文末附件代碼到本地,可以直接用。

example使用的例子:

    public static void main(String[] args) throws IOException, InterruptedException {
        GraphUtil graphUtil = new GraphUtil(); //new一個自己寫的GraphUtil類
        graphUtil.setSourcePath("D:\\graph\\example.txt"); //設置dot指令的txt文件目錄
        graphUtil.setTargetPath("D:\\graph\\example.jpg"); //設置要生成的圖片的目錄路徑

        graphUtil.link("A","B"); //A結點向B結點 連一條有向邊  實際上就是字符串拼接,dot指令加上 A->B 這個字符串
        graphUtil.link("B","C"); //B結點向C結點 連一條有向邊 實際上就是字符串拼接,dot指令加上 B->C 這個字符串
        graphUtil.link("C","D"); //C結點向D結點 連一條有向邊
        graphUtil.link("B","D","a"); //B結點向D結點 連一條有向邊

        graphUtil.node("A","start"); //在A結點里面寫文字
        GraphUtil.saveCodeToFile(graphUtil.getSourcePath(),graphUtil.getCode()); //保存dot指令到example.txt文件,graphUtil.getCode()獲取了dot指令的內容
        GraphUtil.genAndOpenGraph(graphUtil.getSourcePath(),graphUtil.getTargetPath()); //生成圖片 並自動打開圖片文件
    }

效果:

執行完上面Main函數的代碼,看到在指定的目錄下生成了txt指令文件,和jpg狀態轉換圖。


附:GraphUtil類(在本地新建一個命名 名稱為GraphUtil的class類,然后把下面代碼拷貝進去就可以了)


import java.awt.*;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

public class GraphUtil {

    private String code = "digraph G {" + "\r\n";
    private String sourcePath;
    private String targetPath;

    public void setTargetPath(String targetPath) {
        this.targetPath = targetPath;
    }

    //節點A到節點B畫一條有向邊
    public void link(String dotA, String dotB){
        String linkCode = dotA + " -> " + dotB + "\r\n";
        this.code += linkCode;
    }

    //節點A到節點B畫一條有向邊,邊權寫上label
    public void link(String dotA,String dotB,String label){
        String linkCode = dotA + " -> " + dotB + "[label=" + label + "]" + "\r\n";
        this.code += linkCode;
    }

    public void node(String dot,String label){
        String nodeCode = dot + "[label=\"" + label + "\"]" + "\r\n";
        this.code += nodeCode;
    }

    //打開已經生成的DAG圖片
    public static void openFile(String filePath) {
        try {
            File file = new File(filePath);
            Desktop.getDesktop().open(file);
        } catch (IOException | NullPointerException e) {
            System.err.println(e);
        }
    }

    //使用dot的命令 用dot指令文件 生成DAG圖片
    public static void genGraph(String sourcePath,String targetPath) throws IOException, InterruptedException {
        Runtime run = Runtime.getRuntime();
        run.exec("dot "+sourcePath+" -T jpg -o "+targetPath);
        Thread.sleep(1000);
    }

    //整合上面兩個方法的功能: 生成圖片后自動打開
    public static void genAndOpenGraph(String sourcePath,String targetPath) throws InterruptedException, IOException {
        genGraph(sourcePath,targetPath);
        Thread.sleep(1000);
        openFile(targetPath);
    }

    //保存dot指令到文件  后續利用這個指令文件 就可以用dot命令生成圖了
    public static void saveCodeToFile(String filePath, String content) {
        FileWriter fwriter = null;
        try {
            // true表示不覆蓋原來的內容,而是加到文件的后面。若要覆蓋原來的內容,直接省略這個參數就好
            fwriter = new FileWriter(filePath, false);
            fwriter.write(content);
        } catch (IOException ex) {
            ex.printStackTrace();
        } finally {
            try {
                fwriter.flush();
                fwriter.close();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    }

    //一些setter和getter方法
    public String getCode() {
        return code + "\n}";
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getSourcePath() {
        return sourcePath;
    }

    public void setSourcePath(String sourcePath) {
        this.sourcePath = sourcePath;
    }

    public String getTargetPath() {
        return targetPath;
    }

}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM