From 7f1d8f17bb6159e3d909bb3a83eacb2e69caa580 Mon Sep 17 00:00:00 2001 From: Joilnen Date: Wed, 3 Apr 2019 10:47:23 -0300 Subject: [PATCH 1/4] Added edge label support folowing this format: ae 1 2 le 1 2 "L1" --- gvanim/action.py | 12 ++++++++++++ gvanim/animation.py | 15 ++++++++++++--- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/gvanim/action.py b/gvanim/action.py index d152ec2..3a87d37 100644 --- a/gvanim/action.py +++ b/gvanim/action.py @@ -93,6 +93,17 @@ def __call__( self, steps ): steps[ -1 ].E.add( ( self.u, self.v ) ) steps[ -1 ].hE[ ( self.u, self.v ) ] = self.color +class LabelEdge( object ): + def __init__( self, u, v, label = 'label' ): + self.u = u + self.v = v + self.label_edge = label + def __call__( self, steps ): + steps[ -1 ].V.add( self.u ) + steps[ -1 ].V.add( self.v ) + steps[ -1 ].E.add( ( self.u, self.v ) ) + steps[ -1 ].lE[ ( self.u, self.v ) ] = self.label_edge + class RemoveEdge( object ): def __init__( self, u, v ): self.u = u @@ -101,5 +112,6 @@ def __call__( self, steps ): steps[ -1 ].E.discard( ( self.u, self.v ) ) try: del steps[ -1 ].hE[ ( self.u, self.v ) ] + del steps[ -1 ].lE[ ( self.u, self.v ) ] except KeyError: pass diff --git a/gvanim/animation.py b/gvanim/animation.py index 33a0748..cfdfc33 100644 --- a/gvanim/animation.py +++ b/gvanim/animation.py @@ -32,10 +32,12 @@ def __init__( self, step = None ): self.V = step.V.copy() self.E = step.E.copy() self.L = step.L.copy() + self.lE = step.lE.copy() else: self.V = set() self.E = set() self.L = dict() + self.lE = dict() self.hV = dict() self.hE = dict() @@ -49,18 +51,21 @@ def node_format( self, v ): fmt.append( 'color={}'.format( self.hV[ v ] ) ) elif v not in self.V: fmt.append( 'style=invis' ) - if fmt: return '[{}]'.format( ','.join( fmt ) ) + if fmt: + return '[{}]'.format( ','.join( fmt ) ) return '' def edge_format( self, e ): - if e in self.hE: + if e in self.lE: + return '[label={}]'.format( self.lE[ e ] ) + elif e in self.hE: return '[color={}]'.format( self.hE[ e ] ) elif e in self.E: return '' return '[style=invis]' def __repr__( self ): - return '{{ V = {}, E = {}, hV = {}, hE = {}, L = {} }}'.format( self.V, self.E, self.hV, self.hE, self.L ) + return '{{ V = {}, E = {}, hV = {}, hE = {}, L = {}, lE = {} }}'.format( self.V, self.E, self.hV, self.hE, self.L, self.lE ) class Animation( object ): @@ -91,6 +96,9 @@ def add_edge( self, u, v ): def highlight_edge( self, u, v, color = 'red' ): self._actions.append( action.HighlightEdge( u, v, color = color ) ) + def label_edge( self, u, v, label = 'label' ): + self._actions.append( action.LabelEdge( u, v, label) ) + def remove_edge( self, u, v ): self._actions.append( action.RemoveEdge( u, v ) ) @@ -104,6 +112,7 @@ def parse( self, lines ): 'rn' : self.remove_node, 'ae' : self.add_edge, 'he' : self.highlight_edge, + 'le' : self.label_edge, 're' : self.remove_edge, } for line in lines: From 36d0267bc2ef16ad3b12698b5a41da8ab1c9fb3c Mon Sep 17 00:00:00 2001 From: Joilnen Date: Wed, 3 Apr 2019 10:50:40 -0300 Subject: [PATCH 2/4] Added a example line to edge label in simple.txt --- examples/simple.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/simple.txt b/examples/simple.txt index 1fed48b..effdeeb 100644 --- a/examples/simple.txt +++ b/examples/simple.txt @@ -1,6 +1,7 @@ ae 1 2 ae 1 "a \"node\"" ae 2 "a \"node\"" +le 1 2 "Label 0" ns hn 1 ns From 1556470becf3c2a1384070a89d23fb31e0d29b39 Mon Sep 17 00:00:00 2001 From: Joilnen Date: Wed, 3 Apr 2019 10:57:18 -0300 Subject: [PATCH 3/4] Labels without space yet only --- examples/simple.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/simple.txt b/examples/simple.txt index effdeeb..7f01c75 100644 --- a/examples/simple.txt +++ b/examples/simple.txt @@ -1,7 +1,7 @@ ae 1 2 ae 1 "a \"node\"" ae 2 "a \"node\"" -le 1 2 "Label 0" +le 1 2 "L0" ns hn 1 ns From a95d2739796e07d027f34682ad7ca4bb054a0d09 Mon Sep 17 00:00:00 2001 From: Massimo Santini Date: Wed, 3 Apr 2019 20:09:27 +0200 Subject: [PATCH 4/4] Preparing to merge (an amended) pull request. * Added labels for edges, escaping for edge and node labels. * Renamed the set of node (and edge) labels for consisentcy. * PNGs are resized (using mogrify) before being merged in the animated gif. --- examples/heapsort.ipynb | 2 +- examples/simple.txt | 5 +++-- gvanim/action.py | 21 +++++++++++++++++---- gvanim/animation.py | 38 ++++++++++++++++++++++---------------- gvanim/render.py | 4 +++- tests/action.pyc | Bin 1508 -> 0 bytes 6 files changed, 46 insertions(+), 24 deletions(-) delete mode 100644 tests/action.pyc diff --git a/examples/heapsort.ipynb b/examples/heapsort.ipynb index 17c1d71..8c6c8ba 100644 --- a/examples/heapsort.ipynb +++ b/examples/heapsort.ipynb @@ -157,7 +157,7 @@ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "6f45a62e8def48d38d9720bde9ab736b", + "model_id": "0f5267abc9e3478587dd7b61d9cb0c1c", "version_major": 2, "version_minor": 0 }, diff --git a/examples/simple.txt b/examples/simple.txt index 7f01c75..649ec17 100644 --- a/examples/simple.txt +++ b/examples/simple.txt @@ -1,12 +1,13 @@ ae 1 2 ae 1 "a \"node\"" ae 2 "a \"node\"" -le 1 2 "L0" +le 1 2 "an \"edge\"" ns hn 1 ns hn 2 -ln 2 "foo bar" +ln 2 "foo \"bar\"" +ue 1 2 ns hn "a \"node\"" # this is a comment diff --git a/gvanim/action.py b/gvanim/action.py index 3a87d37..fc3eb81 100644 --- a/gvanim/action.py +++ b/gvanim/action.py @@ -42,7 +42,7 @@ def __init__( self, v, label ): self.label = label def __call__( self, steps ): steps[ -1 ].V.add( self.v ) - steps[ -1 ].L[ self.v ] = self.label + steps[ -1 ].lV[ self.v ] = self.label class UnlabelNode( object ): def __init__( self, v ): @@ -50,7 +50,7 @@ def __init__( self, v ): def __call__( self, steps ): steps[ -1 ].V.add( self.v ) try: - del steps[ -1 ].L[ self.v ] + del steps[ -1 ].lV[ self.v ] except KeyError: pass @@ -64,7 +64,7 @@ def __call__( self, steps ): except KeyError: pass try: - del steps[ -1 ].L[ self.v ] + del steps[ -1 ].lV[ self.v ] except KeyError: pass dE = set( e for e in steps[ -1 ].E if self.v in e ) @@ -94,7 +94,7 @@ def __call__( self, steps ): steps[ -1 ].hE[ ( self.u, self.v ) ] = self.color class LabelEdge( object ): - def __init__( self, u, v, label = 'label' ): + def __init__( self, u, v, label ): self.u = u self.v = v self.label_edge = label @@ -104,6 +104,19 @@ def __call__( self, steps ): steps[ -1 ].E.add( ( self.u, self.v ) ) steps[ -1 ].lE[ ( self.u, self.v ) ] = self.label_edge +class UnlabelEdge( object ): + def __init__( self, u, v ): + self.u = u + self.v = v + def __call__( self, steps ): + steps[ -1 ].V.add( self.u ) + steps[ -1 ].V.add( self.v ) + steps[ -1 ].E.add( ( self.u, self.v ) ) + try: + del steps[ -1 ].lE[ ( self.u, self.v ) ] + except KeyError: + pass + class RemoveEdge( object ): def __init__( self, u, v ): self.u = u diff --git a/gvanim/animation.py b/gvanim/animation.py index cfdfc33..cd7f089 100644 --- a/gvanim/animation.py +++ b/gvanim/animation.py @@ -31,41 +31,42 @@ def __init__( self, step = None ): if step: self.V = step.V.copy() self.E = step.E.copy() - self.L = step.L.copy() + self.lV = step.lV.copy() self.lE = step.lE.copy() else: self.V = set() self.E = set() - self.L = dict() + self.lV = dict() self.lE = dict() self.hV = dict() self.hE = dict() def node_format( self, v ): fmt = [] - try: - fmt.append( 'label="{}"'.format( self.L[ v ] ) ) - except KeyError: - pass + if v in self.lV: + fmt.append( 'label="{}"'.format( quote( str( self.lV[ v ] ) ) ) ) if v in self.hV: fmt.append( 'color={}'.format( self.hV[ v ] ) ) elif v not in self.V: fmt.append( 'style=invis' ) if fmt: - return '[{}]'.format( ','.join( fmt ) ) + return '[{}]'.format( ', '.join( fmt ) ) return '' def edge_format( self, e ): + fmt = [] if e in self.lE: - return '[label={}]'.format( self.lE[ e ] ) - elif e in self.hE: - return '[color={}]'.format( self.hE[ e ] ) - elif e in self.E: - return '' - return '[style=invis]' + fmt.append('label="{}"'.format( quote( str( self.lE[ e ] ) ) ) ) + if e in self.hE: + fmt.append('color={}'.format( self.hE[ e ] ) ) + elif e not in self.E: + fmt.append('style=invis') + if fmt: + return '[{}]'.format( ', '.join( fmt ) ) + return '' def __repr__( self ): - return '{{ V = {}, E = {}, hV = {}, hE = {}, L = {}, lE = {} }}'.format( self.V, self.E, self.hV, self.hE, self.L, self.lE ) + return '{{ V = {}, E = {}, hV = {}, hE = {}, L = {}, lE = {} }}'.format( self.V, self.E, self.hV, self.hE, self.lV, self.lE ) class Animation( object ): @@ -96,8 +97,11 @@ def add_edge( self, u, v ): def highlight_edge( self, u, v, color = 'red' ): self._actions.append( action.HighlightEdge( u, v, color = color ) ) - def label_edge( self, u, v, label = 'label' ): - self._actions.append( action.LabelEdge( u, v, label) ) + def label_edge( self, u, v, label ): + self._actions.append( action.LabelEdge( u, v, label ) ) + + def unlabel_edge( self, u, v ): + self._actions.append( action.UnlabelEdge( u, v ) ) def remove_edge( self, u, v ): self._actions.append( action.RemoveEdge( u, v ) ) @@ -113,6 +117,7 @@ def parse( self, lines ): 'ae' : self.add_edge, 'he' : self.highlight_edge, 'le' : self.label_edge, + 'ue' : self.unlabel_edge, 're' : self.remove_edge, } for line in lines: @@ -146,4 +151,5 @@ def graphs( self ): for e in E: graph.append( '"{}" -> "{}" {};'.format( quote( str( e[ 0 ] ) ), quote( str( e[ 1 ] ) ), s.edge_format( e ) ) ) graph.append( '}' ) graphs.append( '\n'.join( graph ) ) + return graphs diff --git a/gvanim/render.py b/gvanim/render.py index f8fe1b1..146339d 100644 --- a/gvanim/render.py +++ b/gvanim/render.py @@ -34,7 +34,9 @@ def render( graphs, basename, fmt = 'png', size = 320 ): _map = map return _map( _render, [ ( '{}_{:03}.{}'.format( basename, n, fmt ), fmt, size, graph ) for n, graph in enumerate( graphs ) ] ) -def gif( files, basename, delay = 100 ): +def gif( files, basename, delay = 100, size = 320 ): + for file in files: + call([ 'mogrify', '-gravity', 'center', '-background', 'white', '-extent', str(size), file ]) cmd = [ 'convert' ] for file in files: cmd.extend( ( '-delay', str( delay ), file ) ) diff --git a/tests/action.pyc b/tests/action.pyc deleted file mode 100644 index c7eb72ff1a0ffb780f35d21cb682d39dad79a013..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1508 zcmcgsO>fgc5S_K1v?+Va;A{q)C&ube9pDP!tlR;!3)KKVN6>xX86z4Hj(0B7A)?ry_~fa;FeK=T zV3y$y2Jejz$FpEt=l}4dS+CIib99JUA{-DLazd^Y#85>XB*cn(1|W+x!38r~P8Ok^ zp!xgg0+XE!_y(YOzk=E1DNU1T5C-Tx67yT0-qhzQ4YKoZG0LXibUyRi1?y~f+Rj#u zalvOKV{L;qK6}@-^G-L7b@S{^rZ_*=jP zyDRuNbw19#bw<)^W-eoj&~A$LE^Zx+?oQh;?g_^KCH|NuV#?rw3%KILUqlp8Y88C+ zxy3n<66HV&<~r#MWF`%zYPF>a(p>F5f^mu9VY_QHt+Jsiv(~HNHwJI!Q$?N90J=Hu*TZ z_PUW&-w)6{5gUq8Our4wMq8&;N?F7`D`x|V4g1(LUu&$xLvotFI(_9+f&Cug+6<(p uFVp_62#3B^C)yiEmt*YV;v>A97R*9k^hbVl50O2|8%O)%ZuDp}7QX-%%u|Q}