aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar nagilooh <ficsorattila96@gmail.com>2023-07-27 12:12:26 +0200
committerLibravatar nagilooh <ficsorattila96@gmail.com>2023-08-02 12:09:18 +0200
commit68aa56964c736c2fc4fa4dcdae1af4d4db94bf7d (patch)
tree03df01874a94ffef67499fa84d278262f3b850b5
parentAdd new test files (diff)
downloadrefinery-68aa56964c736c2fc4fa4dcdae1af4d4db94bf7d.tar.gz
refinery-68aa56964c736c2fc4fa4dcdae1af4d4db94bf7d.tar.zst
refinery-68aa56964c736c2fc4fa4dcdae1af4d4db94bf7d.zip
Add visualization using DOT language
-rw-r--r--subprojects/visualization/src/main/java/tools/refinery/visualization/ModelVisualizerAdapter.java11
-rw-r--r--subprojects/visualization/src/main/java/tools/refinery/visualization/internal/FileFormat.java21
-rw-r--r--subprojects/visualization/src/main/java/tools/refinery/visualization/internal/ModelVisualizerAdapterImpl.java113
3 files changed, 132 insertions, 13 deletions
diff --git a/subprojects/visualization/src/main/java/tools/refinery/visualization/ModelVisualizerAdapter.java b/subprojects/visualization/src/main/java/tools/refinery/visualization/ModelVisualizerAdapter.java
index ae23e3bc..42f01242 100644
--- a/subprojects/visualization/src/main/java/tools/refinery/visualization/ModelVisualizerAdapter.java
+++ b/subprojects/visualization/src/main/java/tools/refinery/visualization/ModelVisualizerAdapter.java
@@ -3,6 +3,7 @@ package tools.refinery.visualization;
3import guru.nidi.graphviz.engine.Format; 3import guru.nidi.graphviz.engine.Format;
4import guru.nidi.graphviz.model.MutableGraph; 4import guru.nidi.graphviz.model.MutableGraph;
5import tools.refinery.store.adapter.ModelAdapter; 5import tools.refinery.store.adapter.ModelAdapter;
6import tools.refinery.visualization.internal.FileFormat;
6import tools.refinery.visualization.internal.ModelVisualizerBuilderImpl; 7import tools.refinery.visualization.internal.ModelVisualizerBuilderImpl;
7 8
8public interface ModelVisualizerAdapter extends ModelAdapter { 9public interface ModelVisualizerAdapter extends ModelAdapter {
@@ -16,7 +17,17 @@ public interface ModelVisualizerAdapter extends ModelAdapter {
16 17
17 public MutableGraph createVisualizationForModelState(Long version); 18 public MutableGraph createVisualizationForModelState(Long version);
18 19
20 public String createDotForCurrentModelState();
21
22 public String createDotForModelState(Long version);
23
19 public boolean saveVisualization(MutableGraph graph, String path); 24 public boolean saveVisualization(MutableGraph graph, String path);
20 25
21 public boolean saveVisualization(MutableGraph graph, Format format, String path); 26 public boolean saveVisualization(MutableGraph graph, Format format, String path);
27
28 public boolean saveDot(String dot, String filePath);
29
30 public boolean renderDot(String dot, String filePath);
31
32 public boolean renderDot(String dot, FileFormat format, String filePath);
22} 33}
diff --git a/subprojects/visualization/src/main/java/tools/refinery/visualization/internal/FileFormat.java b/subprojects/visualization/src/main/java/tools/refinery/visualization/internal/FileFormat.java
new file mode 100644
index 00000000..43d6eb3f
--- /dev/null
+++ b/subprojects/visualization/src/main/java/tools/refinery/visualization/internal/FileFormat.java
@@ -0,0 +1,21 @@
1package tools.refinery.visualization.internal;
2
3public enum FileFormat {
4 BMP("bmp"),
5 DOT("dot"),
6 JPEG("jpg"),
7 PDF("pdf"),
8 PLAIN("plain"),
9 PNG("png"),
10 SVG("svg");
11
12 private final String format;
13
14 FileFormat(String format) {
15 this.format = format;
16 }
17
18 public String getFormat() {
19 return format;
20 }
21}
diff --git a/subprojects/visualization/src/main/java/tools/refinery/visualization/internal/ModelVisualizerAdapterImpl.java b/subprojects/visualization/src/main/java/tools/refinery/visualization/internal/ModelVisualizerAdapterImpl.java
index 475ae416..7456d913 100644
--- a/subprojects/visualization/src/main/java/tools/refinery/visualization/internal/ModelVisualizerAdapterImpl.java
+++ b/subprojects/visualization/src/main/java/tools/refinery/visualization/internal/ModelVisualizerAdapterImpl.java
@@ -1,24 +1,51 @@
1package tools.refinery.visualization.internal; 1package tools.refinery.visualization.internal;
2 2
3import guru.nidi.graphviz.attribute.GraphAttr;
3import guru.nidi.graphviz.attribute.Label; 4import guru.nidi.graphviz.attribute.Label;
4import guru.nidi.graphviz.engine.Format; 5import guru.nidi.graphviz.engine.Format;
5import guru.nidi.graphviz.engine.Graphviz; 6import guru.nidi.graphviz.engine.Graphviz;
6import guru.nidi.graphviz.model.MutableGraph; 7import guru.nidi.graphviz.model.MutableGraph;
8import tools.refinery.store.model.Interpretation;
7import tools.refinery.store.model.Model; 9import tools.refinery.store.model.Model;
10import tools.refinery.store.representation.AnySymbol;
11import tools.refinery.store.representation.TruthValue;
8import tools.refinery.visualization.ModelVisualizerAdapter; 12import tools.refinery.visualization.ModelVisualizerAdapter;
9import tools.refinery.visualization.ModelVisualizerStoreAdapter; 13import tools.refinery.visualization.ModelVisualizerStoreAdapter;
10 14
11import java.io.File; 15import java.io.*;
12import java.io.IOException; 16import java.util.HashMap;
17import java.util.Map;
13 18
14import static guru.nidi.graphviz.model.Factory.*; 19import static guru.nidi.graphviz.model.Factory.*;
15 20
16public class ModelVisualizerAdapterImpl implements ModelVisualizerAdapter { 21public class ModelVisualizerAdapterImpl implements ModelVisualizerAdapter {
17 private final Model model; 22 private final Model model;
18 private final ModelVisualizerStoreAdapter storeAdapter; 23 private final ModelVisualizerStoreAdapter storeAdapter;
24 private final Map<AnySymbol, Interpretation<?>> interpretations;
19 public ModelVisualizerAdapterImpl(Model model, ModelVisualizerStoreAdapter storeAdapter) { 25 public ModelVisualizerAdapterImpl(Model model, ModelVisualizerStoreAdapter storeAdapter) {
20 this.model = model; 26 this.model = model;
21 this.storeAdapter = storeAdapter; 27 this.storeAdapter = storeAdapter;
28 this.interpretations = new HashMap<>();
29 for (var symbol : storeAdapter.getStore().getSymbols()) {
30 var arity = symbol.arity();
31 if (arity < 1 || arity > 2) {
32 continue;
33 }
34 var interpretation = model.getInterpretation(symbol);
35 var valueType = symbol.valueType();
36 Interpretation<?> castInterpretation;
37 if (valueType == Boolean.class) {
38 castInterpretation = (Interpretation<Boolean>) interpretation;
39 }
40 // TODO: support TruthValue
41// else if (valueType == TruthValue.class) {
42// castInterpretation = (Interpretation<TruthValue>) interpretation;
43// }
44 else {
45 continue;
46 }
47 interpretations.put(symbol, castInterpretation);
48 }
22 } 49 }
23 50
24 @Override 51 @Override
@@ -33,19 +60,10 @@ public class ModelVisualizerAdapterImpl implements ModelVisualizerAdapter {
33 60
34 @Override 61 @Override
35 public MutableGraph createVisualizationForCurrentModelState() { 62 public MutableGraph createVisualizationForCurrentModelState() {
36 var interpretations = model.getInterpretations(); 63 var graph = mutGraph("model").setDirected(true).graphAttrs().add(GraphAttr.dpi(100));
37 MutableGraph graph = mutGraph("model").setDirected(true);
38 for (var entry : interpretations.entrySet()) { 64 for (var entry : interpretations.entrySet()) {
39 var key = entry.getKey(); 65 var key = entry.getKey();
40 var arity = key.arity(); 66 var arity = key.arity();
41 if (arity < 1 || arity > 2) {
42 continue;
43 }
44 var valueType = key.valueType();
45 // TODO: support TruthValue
46 if (valueType != Boolean.class) {
47 continue;
48 }
49 var cursor = entry.getValue().getAll(); 67 var cursor = entry.getValue().getAll();
50 while (cursor.move()) { 68 while (cursor.move()) {
51 if (arity == 1) { 69 if (arity == 1) {
@@ -65,7 +83,41 @@ public class ModelVisualizerAdapterImpl implements ModelVisualizerAdapter {
65 public MutableGraph createVisualizationForModelState(Long version) { 83 public MutableGraph createVisualizationForModelState(Long version) {
66 var currentVersion = model.getState(); 84 var currentVersion = model.getState();
67 model.restore(version); 85 model.restore(version);
68 MutableGraph graph = createVisualizationForCurrentModelState(); 86 var graph = createVisualizationForCurrentModelState();
87 model.restore(currentVersion);
88 return graph;
89 }
90
91 @Override
92 public String createDotForCurrentModelState() {
93 var sb = new StringBuilder();
94 sb.append("digraph model {\n");
95 for (var entry : interpretations.entrySet()) {
96 var key = entry.getKey();
97 var arity = key.arity();
98 var cursor = entry.getValue().getAll();
99 while (cursor.move()) {
100 if (arity == 1) {
101 var id = cursor.getKey().get(0);
102 sb.append("\t").append(id).append(" [label=\"").append(key.name()).append(": ").append(id)
103 .append("\"]\n");
104 } else {
105 var from = cursor.getKey().get(0);
106 var to = cursor.getKey().get(1);
107 sb.append("\t").append(from).append(" -> ").append(to).append(" [label=\"").append(key.name())
108 .append("\"]\n");
109 }
110 }
111 }
112 sb.append("}");
113 return sb.toString();
114 }
115
116 @Override
117 public String createDotForModelState(Long version) {
118 var currentVersion = model.getState();
119 model.restore(version);
120 var graph = createDotForCurrentModelState();
69 model.restore(currentVersion); 121 model.restore(currentVersion);
70 return graph; 122 return graph;
71 } 123 }
@@ -85,4 +137,39 @@ public class ModelVisualizerAdapterImpl implements ModelVisualizerAdapter {
85 return false; 137 return false;
86 } 138 }
87 } 139 }
140
141 @Override
142 public boolean saveDot(String dot, String filePath) {
143 File file = new File(filePath);
144 file.getParentFile().mkdirs();
145
146 try (FileWriter writer = new FileWriter(file)) {
147 writer.write(dot);
148 } catch (Exception e) {
149 e.printStackTrace();
150 return false;
151 }
152 return true;
153 }
154
155 @Override
156 public boolean renderDot(String dot, String filePath) {
157 return renderDot(dot, FileFormat.SVG, filePath);
158 }
159
160 @Override
161 public boolean renderDot(String dot, FileFormat format, String filePath) {
162 try {
163 Process process = new ProcessBuilder("dot", "-T" + format.getFormat(), "-o", filePath).start();
164
165 OutputStream osToProcess = process.getOutputStream();
166 PrintWriter pwToProcess = new PrintWriter(osToProcess);
167 pwToProcess.write(dot);
168 pwToProcess.close();
169 } catch (IOException e) {
170 e.printStackTrace();
171 return false;
172 }
173 return true;
174 }
88} 175}