Another example doodle - flowchart.js
Been tinkering again... here's another possible misc example - flowchart.js
import jp_proxy_widget
fcode = '''
st=>start: Start|past:>http://www.google.com[blank]
e=>end: End|future:>http://www.google.com
op1=>operation: My Operation|past
op2=>operation: Stuff|current
sub1=>subroutine: My Subroutine|invalid
cond=>condition: Yes
or No?|approved:>http://www.google.com
c2=>condition: Good idea|rejected
io=>inputoutput: catch something...|future
st->op1(right)->cond
cond(yes, right)->c2
cond(no)->sub1(left)->op1
c2(yes)->io->e
c2(no)->op2->e
'''
class FlowchartWidget(jp_proxy_widget.JSProxyWidget):
def __init__(self, *pargs, **kwargs):
super(FlowchartWidget, self).__init__(*pargs, **kwargs)
e = self.element
# Call some standard jQuery method on the widget element:
e.empty()
# This is for the controls as well as the simulator
e.width("1000") # 1181px 2362
e.height("1000") # 551px 1143
html = '<div id="fchart_canvas"></div>'
e.html(html)
self.load_js_files(["https://cdnjs.cloudflare.com/ajax/libs/raphael/2.3.0/raphael.min.js",
'https://cdnjs.cloudflare.com/ajax/libs/flowchart/1.13.0/flowchart.js'])
def charter(self, chart):
self.set_element("chartdef", chart)
self.js_init("chart = flowchart.parse(element.chartdef); chart.drawSVG('fchart_canvas');")
testEmbed = FlowchartWidget()
testEmbed.charter(fcode)
testEmbed
Nice! I put it here -- hope that's okay:
https://github.com/AaronWatters/jp_doodle/blob/master/notebooks/misc/flowcharts.ipynb
Yes, no probs...
I made a couple of tweaks, trying to make it easy to get hold of the asset that's created, eg as SVG and PNG.
import jp_proxy_widget
fcode = '''
st=>start: Start|past:>http://www.google.com[blank]
e=>end: End|future:>http://www.google.com
op1=>operation: My Operation|past
op2=>operation: Stuff|current
sub1=>subroutine: My Subroutine|invalid
cond=>condition: Yes
or No?|approved:>http://www.google.com
c2=>condition: Good idea|rejected
io=>inputoutput: catch something...|future
st->op1(right)->cond
cond(yes, right)->c2
cond(no)->sub1(left)->op1
c2(yes)->io->e
c2(no)->op2->e
'''
fcode='''
st=>start: Start
e=>end: End
op1=>operation: Generate
op2=>parallel: Evaluate
st(right)->op1(right)->op2
op2(path1, top)->op1
op2(path2, right)->e
'''
import uuid
from IPython.display import Image, SVG
import cairosvg
class FlowchartWidget(jp_proxy_widget.JSProxyWidget):
"""jp_proxy_widget to render flowchart.js diagrams."""
def __init__(self, *pargs, **kwargs):
super(FlowchartWidget, self).__init__(*pargs, **kwargs)
e = self.element
e.empty()
self.load_js_files(["https://cdnjs.cloudflare.com/ajax/libs/raphael/2.3.0/raphael.min.js",
'https://cdnjs.cloudflare.com/ajax/libs/flowchart/1.13.0/flowchart.js'])
self.uid = None
self.svg = None
def charter(self, chart, embed=False):
"""Render chart from chart description."""
self.uid = uid = uuid.uuid4()
self.element.html(f'<div id="{uid}"></div>')
self.set_element("chartdef", chart)
self.js_init(f"chart = flowchart.parse(element.chartdef); chart.drawSVG('{uid}');svg_data = document.getElementById('{uid}').innerHTML;")
self.get_value_async(self.svg_callback, "svg_data")
if embed:
return self
def svg_callback(self, svg):
"""Persist SVG state on Python side."""
self.svg = svg
def get_svg_data(self):
"""Return raw SVG data for flowchart."""
return self.svg
def get_svg(self):
"""Return SVG data of flowchart."""
return SVG(self.svg)
def get_png(self):
"""Return png of flowchart."""
return Image(cairosvg.svg2png(self.svg));
testEmbed = FlowchartWidget()
testEmbed.charter(fcode)
testEmbed
#testEmbed.get_svg_data()
#testEmbed.get_svg()
#testEmbed.get_png()
You can also display the image directly as FlowchartWidget().charter(fcode, embed=True), though there's a flicker as the Uninitialised widget message displays before it's rendered (can that be made silent somehow?)
I'm not sure if the SVG conversion should really happen on the js side? It alls feels a bit hacky to me!
PS I tried to do the same for mermaid.js but mermaid seems to be a bit less well behaved and I couldn't get it to render properly...