diff options
author | nagilooh <ficsorattila96@gmail.com> | 2023-07-27 12:12:26 +0200 |
---|---|---|
committer | nagilooh <ficsorattila96@gmail.com> | 2023-08-02 12:09:18 +0200 |
commit | 68aa56964c736c2fc4fa4dcdae1af4d4db94bf7d (patch) | |
tree | 03df01874a94ffef67499fa84d278262f3b850b5 /subprojects/visualization/src/main/java/tools | |
parent | Add new test files (diff) | |
download | refinery-68aa56964c736c2fc4fa4dcdae1af4d4db94bf7d.tar.gz refinery-68aa56964c736c2fc4fa4dcdae1af4d4db94bf7d.tar.zst refinery-68aa56964c736c2fc4fa4dcdae1af4d4db94bf7d.zip |
Add visualization using DOT language
Diffstat (limited to 'subprojects/visualization/src/main/java/tools')
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; | |||
3 | import guru.nidi.graphviz.engine.Format; | 3 | import guru.nidi.graphviz.engine.Format; |
4 | import guru.nidi.graphviz.model.MutableGraph; | 4 | import guru.nidi.graphviz.model.MutableGraph; |
5 | import tools.refinery.store.adapter.ModelAdapter; | 5 | import tools.refinery.store.adapter.ModelAdapter; |
6 | import tools.refinery.visualization.internal.FileFormat; | ||
6 | import tools.refinery.visualization.internal.ModelVisualizerBuilderImpl; | 7 | import tools.refinery.visualization.internal.ModelVisualizerBuilderImpl; |
7 | 8 | ||
8 | public interface ModelVisualizerAdapter extends ModelAdapter { | 9 | public 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 @@ | |||
1 | package tools.refinery.visualization.internal; | ||
2 | |||
3 | public 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 @@ | |||
1 | package tools.refinery.visualization.internal; | 1 | package tools.refinery.visualization.internal; |
2 | 2 | ||
3 | import guru.nidi.graphviz.attribute.GraphAttr; | ||
3 | import guru.nidi.graphviz.attribute.Label; | 4 | import guru.nidi.graphviz.attribute.Label; |
4 | import guru.nidi.graphviz.engine.Format; | 5 | import guru.nidi.graphviz.engine.Format; |
5 | import guru.nidi.graphviz.engine.Graphviz; | 6 | import guru.nidi.graphviz.engine.Graphviz; |
6 | import guru.nidi.graphviz.model.MutableGraph; | 7 | import guru.nidi.graphviz.model.MutableGraph; |
8 | import tools.refinery.store.model.Interpretation; | ||
7 | import tools.refinery.store.model.Model; | 9 | import tools.refinery.store.model.Model; |
10 | import tools.refinery.store.representation.AnySymbol; | ||
11 | import tools.refinery.store.representation.TruthValue; | ||
8 | import tools.refinery.visualization.ModelVisualizerAdapter; | 12 | import tools.refinery.visualization.ModelVisualizerAdapter; |
9 | import tools.refinery.visualization.ModelVisualizerStoreAdapter; | 13 | import tools.refinery.visualization.ModelVisualizerStoreAdapter; |
10 | 14 | ||
11 | import java.io.File; | 15 | import java.io.*; |
12 | import java.io.IOException; | 16 | import java.util.HashMap; |
17 | import java.util.Map; | ||
13 | 18 | ||
14 | import static guru.nidi.graphviz.model.Factory.*; | 19 | import static guru.nidi.graphviz.model.Factory.*; |
15 | 20 | ||
16 | public class ModelVisualizerAdapterImpl implements ModelVisualizerAdapter { | 21 | public 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 | } |