Commit b2a30f6e authored by Lucas Bourneuf's avatar Lucas Bourneuf

auto-generation of gifs based on models + working example

parent 5e15cd42
......@@ -10,6 +10,9 @@ run-config-test:
python -m biseau -c ./configs/concept-lattice.json -o out/concept-lattice.png $(VERBOSITY)
xdg-open out/concept-lattice.png
python -m biseau examples/path-to-gif.lp --dotfile "out/todel{}.dot" --outfile out/out.gif --gif-duration 1000 $(VERBOSITY)
t: test
python -m pytest biseau test --ignore=venv --doctest-module
......@@ -23,11 +23,13 @@ def parse_cli(args:iter=None) -> dict:
help="output file. Will be overwritten with dot data. Can be templated with '{model_number}'")
parser.add_argument('--config', '-c', type=str, default=None,
help="configuration file, specifying scripts and their options")
parser.add_argument('--gif-duration', '-gd', type=int, default=500,
help="gif duration in second")
parser.add_argument('-v', '--verbosity', action='count', default=0)
# flags
parser.add_argument('--flag-example', action='store_true',
help="Do nothing currently")
parser.add_argument('--gif', '-g', action='store_true',
help="Do not merge graphs ; build a gif with frame for each model")
return parser.parse_args(args)
......@@ -40,6 +42,18 @@ if __name__ == '__main__':
core.build_pipeline.from_configfile(args.config, verbosity=args.verbosity)
if os.path.splitext(args.outfile)[1] == '.gif' and args.gif is None:
args.gif = True # turn on the gif behavior
if args.gif:
......@@ -31,6 +31,15 @@ def single_image_from_filenames(fnames:[str], outfile:str=None, dotfile:str=None
return compile_to_single_image(final_context, outfile=outfile, dotfile=dotfile, return_image=return_image, verbosity=verbosity)
def gif_from_filenames(fnames:[str], giffile:str, dotfile_template:str=None, duration:int=1000, verbosity:int=0) -> str:
"""Make a gif, with each ASP model as an image. Save it in outfile and dotfile_template"""
pipeline = build_pipeline(fnames, verbosity)
final_context = run(pipeline, verbosity=verbosity)
first, *lasts = compile_to_images(final_context, dotfile_template=dotfile_template, return_image=True, verbosity=verbosity), save_all=True, append_images=lasts, duration=duration, loop=0)
return giffile
def build_pipeline(fnames:[str], verbosity:int=0) -> [Script]:
"Yield scripts found in given filenames"
for fname in fnames:
......@@ -117,3 +126,36 @@ def compile_to_single_image(context:str, outfile:str=None, dotfile:str=None,
if del_outfile:
return img
def compile_to_images(context:str, outfile_template:str=None, dotfile_template:str=None,
return_image:bool=True, verbosity:int=0) -> [Image]:
"""Yield pillow.Image objects, and write it to outfile if given
outfile_template -- template name for png files, or None
dotfile_template -- template name for dot files, or None
configs = asp_to_dot.visual_config_from_asp(
if outfile_template and '{}' not in outfile_template:
raise ValueError("Outfile argument is not a valid template")
if dotfile_template and '{}' not in dotfile_template:
raise ValueError("Dotfile argument is not a valid template")
dots = dot_writer.multiple_graphs_from_configs(configs)
for idx, dot in enumerate(dots, start=1):
del_outfile = False
if outfile_template is None:
with tempfile.NamedTemporaryFile(delete=False) as fd:
outfile =
del_outfile = True
outfile = outfile_template.format(idx)
dotfile = dotfile_template.format(idx) if dotfile_template else None
dot = dot_writer.dot_to_png(dot, outfile, dotfile=dotfile)
if return_image:
img =
if del_outfile:
yield img
......@@ -3,6 +3,7 @@
import itertools
import pydot
from .asp_to_dot import VisualConfig
......@@ -27,20 +28,22 @@ def _dot_from_properties(properties:dict or None, prefix:str=' ') -> str:
return ''
def multiple_graphs_from_configs(visual_configs:[VisualConfig]) -> iter:
"""Yield lines of dot describing the given VisualConfig instances.
def multiple_graphs_from_configs(visual_configs:[VisualConfig]) -> [[str]]:
"""Yield generators of lines of dot describing the given VisualConfig instances.
Produce one graph per VisualConfig.
See function counterpart, one_graph_from_configs.
for visual_config in visual_configs:
yield 'Digraph biseau_graph {\n'
yield from _from_config(visual_config)
yield '}\n\n\n'
yield itertools.chain(
['Digraph biseau_graph {\n'],
def one_graph_from_configs(visual_configs:[VisualConfig]) -> iter:
def one_graph_from_configs(visual_configs:[VisualConfig]) -> [str]:
"""Yield lines of dot describing the given VisualConfig instances.
Produce only one graph,
......@@ -53,7 +56,7 @@ def one_graph_from_configs(visual_configs:[VisualConfig]) -> iter:
yield '}'
def _from_config(visual_config:VisualConfig) -> iter:
def _from_config(visual_config:VisualConfig) -> [str]:
"""Yield lines of dot's graph describing the given VisualConfig instance.
% To use with something like:
% python -m biseau examples/path-to-gif.lp -o out/out.gif
% Graph.
start(a). target(h).
nb_link(N):- N={link(_,_)}.
% Initial state.
place(1,N) :- start(N).
% Choose a path.
1 { place(I+1,N): link(T,N) } 1 :- place(I,T) ; not target(T) ; I<Nlink ; nb_link(Nlink).
% Discards paths not terminating at target, and looping paths.
:- not place(_,T) ; target(T).
:- place(I,N) ; place(J,N) ; I!=J.
% Colorize the path.
color(N,green) :- place(_,N).
% Highlight the path: make edges red and directed.
color(A,B,red) :- link(A,B) ; place(_,A) ; place(_,B).
dot_property(A,B,arrowhead,normal) :- link(A,B) ; place(_,A) ; place(_,B).
dot_property(A,B,penwidth,5) :- link(A,B) ; place(_,A) ; place(_,B).
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment