import sys
sys.path.insert(0, '..')
from branca.element import *
This is the base brick of branca
. You can create an Element
in providing a template string:
e = Element("This is fancy text")
Each element has an attribute _name
and a unique _id
. You also have a method get_name
to get a unique string representation of the element.
print(e._name, e._id)
print(e.get_name())
Element a1d0f648f7444f96b526931944247fd6 element_a1d0f648f7444f96b526931944247fd6
You can render an Element
using the method render
:
e.render()
'This is fancy text'
In the template, you can use keyword this
for accessing the object itself ; and the keyword kwargs
for accessing any keyword argument provided in the render
method:
e = Element("Hello {{kwargs['you']}}, my name is `{{this.get_name()}}`.")
e.render(you='World')
'Hello World, my name is `element_6f17661abddb45c7bf2aa794cadd327d`.'
Well, this is not really cool for now. What makes elements useful lies in the fact that you can create trees out of them. To do so, you can either use the method add_child
or the method add_to
.
child = Element('This is the child.')
parent = Element('This is the parent.').add_child(child)
parent = Element('This is the parent.')
child = Element('This is the child.').add_to(parent)
Now in the example above, embedding the one in the other does not change anything.
print(parent.render(), child.render())
This is the parent. This is the child.
But you can use the tree structure in the template.
parent = Element("<parent>{% for child in this._children.values() %}{{child.render()}}{% endfor %}</parent>")
Element('<child1/>').add_to(parent)
Element('<child2/>').add_to(parent)
parent.render()
'<parent><child1/><child2/></parent>'
As you can see, the child of an element are referenced in the _children
attibute in the form of an OrderedDict
. You can choose the key of each child in specifying a name
in the add_child
(or add_to
) method:
parent = Element("<parent>{% for child in this._children.values() %}{{child.render()}}{% endfor %}</parent>")
Element('<child1/>').add_to(parent, name='child_1')
parent._children
OrderedDict([('child_1', <branca.element.Element at 0x7f758f2db6a0>)])
That way, it's possible to overwrite a child in specifying the same name:
Element('<child1_overwritten/>').add_to(parent, name='child_1')
parent.render()
'<parent><child1_overwritten/></parent>'
I hope you start to find it useful.
In fact, the real interest of Element
lies in the classes that inherit from it. The most important one is Figure
described in the next section.
A Figure
represents an HTML document. It's composed of 3 parts (attributes):
header
: corresponds to the <head>
part of the HTML document,html
: corresponds to the <body>
part,script
: corresponds to a <script>
section that will be appended after the <body>
section.f = Figure()
print(f.render())
<!DOCTYPE html> <head> <meta http-equiv="content-type" content="text/html; charset=UTF-8" /> </head> <body> </body> <script> </script>
You can for example create a beatiful cyan "hello-world" webpage in doing:
f.header.add_child(Element("<style>body {background-color: #00ffff}</style>"))
f.html.add_child(Element("<h1>Hello world</h1>"))
print(f.render())
<!DOCTYPE html> <head> <meta http-equiv="content-type" content="text/html; charset=UTF-8" /> <style>body {background-color: #00ffff}</style> </head> <body> <h1>Hello world</h1> </body> <script> </script>
You can simply save the content of the Figure
to a file, thanks to the save
method:
f.save('foo.html')
print(open('foo.html').read())
<!DOCTYPE html> <head> <meta http-equiv="content-type" content="text/html; charset=UTF-8" /> <style>body {background-color: #00ffff}</style> </head> <body> <h1>Hello world</h1> </body> <script> </script>
If you want to visualize it in the notebook, you can let Figure._repr_html_
method do it's job in typing:
f
If this rendering is too large for you, you can force it's width and height:
f.width = 300
f.height = 200
f
Note that you can also define a Figure
's size in a matplotlib way:
Figure(figsize=(5,5))
It happens you need to create elements that have multiple effects on a Figure. For this, you can use MacroElement
whose template contains macros ; each macro writes something into the parent Figure's header, body and script.
macro = MacroElement()
macro._template = Template(
'{% macro header(this, kwargs) %}'
'This is header of {{this.get_name()}}'
'{% endmacro %}'
'{% macro html(this, kwargs) %}'
'This is html of {{this.get_name()}}'
'{% endmacro %}'
'{% macro script(this, kwargs) %}'
'This is script of {{this.get_name()}}'
'{% endmacro %}'
)
print(Figure().add_child(macro).render())
<!DOCTYPE html> <head> <meta http-equiv="content-type" content="text/html; charset=UTF-8" /> This is header of macro_element_ea36a310ab8a4212a8c7ca754a4140fc </head> <body> This is html of macro_element_ea36a310ab8a4212a8c7ca754a4140fc </body> <script> This is script of macro_element_ea36a310ab8a4212a8c7ca754a4140fc </script>
To embed javascript and css links in the header, you can use these class:
js_link = JavascriptLink('https://example.com/javascript.js')
js_link.render()
'<script src="https://example.com/javascript.js"></script>'
css_link = CssLink('https://example.com/style.css')
css_link.render()
'<link rel="stylesheet" href="https://example.com/style.css" />'
An Html
element enables you to create custom div to put in the body of your page.
html = Html('Hello world')
html.render()
'<div id="html_cec7064e3ecc492ca40ac8c6f63ce839" style="width: 100.0%; height: 100.0%;">Hello world</div>'
It's designed to render the text as you gave it, so it won't work directly it you want to embed HTML code inside the div.
Html('<b>Hello world</b>').render()
'<div id="html_18a1f0cf2e61444d8a396ad5cb77f864" style="width: 100.0%; height: 100.0%;"><b>Hello world</b></div>'
For this, you have to set script=True
and it will work:
Html('<b>Hello world</b>', script=True).render()
'<div id="html_9cf0c436b7f0462ea59479bc9175e72a" style="width: 100.0%; height: 100.0%;"><b>Hello world</b></div>'
If you need to embed a full webpage (with separate javascript environment), you can use IFrame
.
iframe = IFrame('Hello World')
iframe.render()
'<div style="width:100%;"><div style="position:relative;width:100%;height:0;padding-bottom:60%;"><iframe src="data:text/html;base64,CiAgICBIZWxsbyBXb3JsZA==" style="position:absolute;width:100%;height:100%;left:0;top:0;"></iframe></div></div>'
As you can see, it will embed the full content of the iframe in a base64 string so that the ouput looks like:
f = Figure(height=180)
f.html.add_child(Element("Before the frame"))
f.html.add_child(IFrame('In the frame', height='100px'))
f.html.add_child(Element("After the frame"))
f
At last, you have the Div
element that behaves almost like Html
with a few differences:
Html
's style is embedded inline.Div
inherits from MacroElement
so that:Figure
.div = Div()
div.html.add_child(Element('Hello world'))
print(Figure().add_child(div).render())
<!DOCTYPE html> <head> <meta http-equiv="content-type" content="text/html; charset=UTF-8" /> <style> #div_e72aae6984604f7093a46452870bbebd { position : relative; width : 100.0%; height: 100.0%; left: 0.0%; top: 0.0%; </style> </head> <body> <div id="div_e72aae6984604f7093a46452870bbebd">Hello world</div> </body> <script> </script>