From dd2d8a1517f3f198fe005ebf91a4f8e912609c1b Mon Sep 17 00:00:00 2001 From: nagilooh Date: Tue, 25 Jul 2023 17:17:17 +0200 Subject: Add visualization adapter Uses Graphviz to create a visualization of the models and can save them to disk as an image or various textual representations --- .../java/tools/refinery/store/model/Model.java | 4 + .../refinery/store/model/internal/ModelImpl.java | 4 + subprojects/visualization/build.gradle.kts | 14 ++++ .../visualization/ModelVisualizerAdapter.java | 22 ++++++ .../visualization/ModelVisualizerBuilder.java | 6 ++ .../visualization/ModelVisualizerStoreAdapter.java | 7 ++ .../internal/ModelVisualizeStoreAdapterImpl.java | 24 ++++++ .../internal/ModelVisualizerAdapterImpl.java | 88 ++++++++++++++++++++++ .../internal/ModelVisualizerBuilderImpl.java | 14 ++++ 9 files changed, 183 insertions(+) create mode 100644 subprojects/visualization/build.gradle.kts create mode 100644 subprojects/visualization/src/main/java/tools/refinery/visualization/ModelVisualizerAdapter.java create mode 100644 subprojects/visualization/src/main/java/tools/refinery/visualization/ModelVisualizerBuilder.java create mode 100644 subprojects/visualization/src/main/java/tools/refinery/visualization/ModelVisualizerStoreAdapter.java create mode 100644 subprojects/visualization/src/main/java/tools/refinery/visualization/internal/ModelVisualizeStoreAdapterImpl.java create mode 100644 subprojects/visualization/src/main/java/tools/refinery/visualization/internal/ModelVisualizerAdapterImpl.java create mode 100644 subprojects/visualization/src/main/java/tools/refinery/visualization/internal/ModelVisualizerBuilderImpl.java (limited to 'subprojects') diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/Model.java b/subprojects/store/src/main/java/tools/refinery/store/model/Model.java index d58d91c3..703a0720 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/model/Model.java +++ b/subprojects/store/src/main/java/tools/refinery/store/model/Model.java @@ -7,9 +7,11 @@ package tools.refinery.store.model; import tools.refinery.store.adapter.ModelAdapter; import tools.refinery.store.map.Versioned; +import tools.refinery.store.model.internal.VersionedInterpretation; import tools.refinery.store.representation.AnySymbol; import tools.refinery.store.representation.Symbol; +import java.util.Map; import java.util.Optional; public interface Model extends Versioned { @@ -27,6 +29,8 @@ public interface Model extends Versioned { Interpretation getInterpretation(Symbol symbol); + public Map> getInterpretations(); + ModelDiffCursor getDiffCursor(long to); Optional tryGetAdapter(Class adapterType); diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelImpl.java b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelImpl.java index c5475a1a..bf6987d6 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelImpl.java +++ b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelImpl.java @@ -187,4 +187,8 @@ public class ModelImpl implements Model { public void removeListener(ModelListener listener) { listeners.remove(listener); } + + public Map> getInterpretations() { + return interpretations; + } } diff --git a/subprojects/visualization/build.gradle.kts b/subprojects/visualization/build.gradle.kts new file mode 100644 index 00000000..97b1688a --- /dev/null +++ b/subprojects/visualization/build.gradle.kts @@ -0,0 +1,14 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + +plugins { + id("tools.refinery.gradle.java-library") +} + +dependencies { + implementation ("guru.nidi:graphviz-java:0.18.1") + api(project(":refinery-store-query")) +} diff --git a/subprojects/visualization/src/main/java/tools/refinery/visualization/ModelVisualizerAdapter.java b/subprojects/visualization/src/main/java/tools/refinery/visualization/ModelVisualizerAdapter.java new file mode 100644 index 00000000..ae23e3bc --- /dev/null +++ b/subprojects/visualization/src/main/java/tools/refinery/visualization/ModelVisualizerAdapter.java @@ -0,0 +1,22 @@ +package tools.refinery.visualization; + +import guru.nidi.graphviz.engine.Format; +import guru.nidi.graphviz.model.MutableGraph; +import tools.refinery.store.adapter.ModelAdapter; +import tools.refinery.visualization.internal.ModelVisualizerBuilderImpl; + +public interface ModelVisualizerAdapter extends ModelAdapter { + + ModelVisualizerStoreAdapter getStoreAdapter(); + static ModelVisualizerBuilder builder() { + return new ModelVisualizerBuilderImpl(); + } + + public MutableGraph createVisualizationForCurrentModelState(); + + public MutableGraph createVisualizationForModelState(Long version); + + public boolean saveVisualization(MutableGraph graph, String path); + + public boolean saveVisualization(MutableGraph graph, Format format, String path); +} diff --git a/subprojects/visualization/src/main/java/tools/refinery/visualization/ModelVisualizerBuilder.java b/subprojects/visualization/src/main/java/tools/refinery/visualization/ModelVisualizerBuilder.java new file mode 100644 index 00000000..9c1bd0e0 --- /dev/null +++ b/subprojects/visualization/src/main/java/tools/refinery/visualization/ModelVisualizerBuilder.java @@ -0,0 +1,6 @@ +package tools.refinery.visualization; + +import tools.refinery.store.adapter.ModelAdapterBuilder; + +public interface ModelVisualizerBuilder extends ModelAdapterBuilder { +} diff --git a/subprojects/visualization/src/main/java/tools/refinery/visualization/ModelVisualizerStoreAdapter.java b/subprojects/visualization/src/main/java/tools/refinery/visualization/ModelVisualizerStoreAdapter.java new file mode 100644 index 00000000..764de6d4 --- /dev/null +++ b/subprojects/visualization/src/main/java/tools/refinery/visualization/ModelVisualizerStoreAdapter.java @@ -0,0 +1,7 @@ +package tools.refinery.visualization; + +import tools.refinery.store.adapter.ModelStoreAdapter; +import tools.refinery.store.query.ModelQueryStoreAdapter; + +public interface ModelVisualizerStoreAdapter extends ModelStoreAdapter { +} diff --git a/subprojects/visualization/src/main/java/tools/refinery/visualization/internal/ModelVisualizeStoreAdapterImpl.java b/subprojects/visualization/src/main/java/tools/refinery/visualization/internal/ModelVisualizeStoreAdapterImpl.java new file mode 100644 index 00000000..6e158c28 --- /dev/null +++ b/subprojects/visualization/src/main/java/tools/refinery/visualization/internal/ModelVisualizeStoreAdapterImpl.java @@ -0,0 +1,24 @@ +package tools.refinery.visualization.internal; + +import tools.refinery.store.adapter.ModelAdapter; +import tools.refinery.store.model.Model; +import tools.refinery.store.model.ModelStore; +import tools.refinery.visualization.ModelVisualizerStoreAdapter; + +public class ModelVisualizeStoreAdapterImpl implements ModelVisualizerStoreAdapter { + private final ModelStore store; + + public ModelVisualizeStoreAdapterImpl(ModelStore store) { + this.store = store; + } + + @Override + public ModelStore getStore() { + return store; + } + + @Override + public ModelAdapter createModelAdapter(Model model) { + return new ModelVisualizerAdapterImpl(model, this); + } +} 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 new file mode 100644 index 00000000..475ae416 --- /dev/null +++ b/subprojects/visualization/src/main/java/tools/refinery/visualization/internal/ModelVisualizerAdapterImpl.java @@ -0,0 +1,88 @@ +package tools.refinery.visualization.internal; + +import guru.nidi.graphviz.attribute.Label; +import guru.nidi.graphviz.engine.Format; +import guru.nidi.graphviz.engine.Graphviz; +import guru.nidi.graphviz.model.MutableGraph; +import tools.refinery.store.model.Model; +import tools.refinery.visualization.ModelVisualizerAdapter; +import tools.refinery.visualization.ModelVisualizerStoreAdapter; + +import java.io.File; +import java.io.IOException; + +import static guru.nidi.graphviz.model.Factory.*; + +public class ModelVisualizerAdapterImpl implements ModelVisualizerAdapter { + private final Model model; + private final ModelVisualizerStoreAdapter storeAdapter; + public ModelVisualizerAdapterImpl(Model model, ModelVisualizerStoreAdapter storeAdapter) { + this.model = model; + this.storeAdapter = storeAdapter; + } + + @Override + public Model getModel() { + return model; + } + + @Override + public ModelVisualizerStoreAdapter getStoreAdapter() { + return storeAdapter; + } + + @Override + public MutableGraph createVisualizationForCurrentModelState() { + var interpretations = model.getInterpretations(); + MutableGraph graph = mutGraph("model").setDirected(true); + for (var entry : interpretations.entrySet()) { + var key = entry.getKey(); + var arity = key.arity(); + if (arity < 1 || arity > 2) { + continue; + } + var valueType = key.valueType(); + // TODO: support TruthValue + if (valueType != Boolean.class) { + continue; + } + var cursor = entry.getValue().getAll(); + while (cursor.move()) { + if (arity == 1) { + var id = cursor.getKey().get(0); + graph.add(mutNode(String.valueOf(id)).add("label", key.name() + ": " + id)); + } else { + var from = cursor.getKey().get(0); + var to = cursor.getKey().get(1); + graph.add(mutNode(String.valueOf(from)).addLink(to(mutNode(String.valueOf(to))).with(Label.of(key.name())))); + } + } + } + return graph; + } + + @Override + public MutableGraph createVisualizationForModelState(Long version) { + var currentVersion = model.getState(); + model.restore(version); + MutableGraph graph = createVisualizationForCurrentModelState(); + model.restore(currentVersion); + return graph; + } + + @Override + public boolean saveVisualization(MutableGraph graph, String path) { + return saveVisualization(graph, Format.PNG, path); + } + + @Override + public boolean saveVisualization(MutableGraph graph, Format format, String path) { + try { + Graphviz.fromGraph(graph).render(format).toFile(new File(path)); + return true; + } catch (IOException e) { + e.printStackTrace(); + return false; + } + } +} diff --git a/subprojects/visualization/src/main/java/tools/refinery/visualization/internal/ModelVisualizerBuilderImpl.java b/subprojects/visualization/src/main/java/tools/refinery/visualization/internal/ModelVisualizerBuilderImpl.java new file mode 100644 index 00000000..4148c24a --- /dev/null +++ b/subprojects/visualization/src/main/java/tools/refinery/visualization/internal/ModelVisualizerBuilderImpl.java @@ -0,0 +1,14 @@ +package tools.refinery.visualization.internal; + +import tools.refinery.store.adapter.AbstractModelAdapterBuilder; +import tools.refinery.store.model.ModelStore; +import tools.refinery.visualization.ModelVisualizerBuilder; + +public class ModelVisualizerBuilderImpl + extends AbstractModelAdapterBuilder + implements ModelVisualizerBuilder { + @Override + protected ModelVisualizeStoreAdapterImpl doBuild(ModelStore store) { + return new ModelVisualizeStoreAdapterImpl(store); + } +} -- cgit v1.2.3-70-g09d2