In [1]:
import sys
sys.path.insert(0, '..')

from branca.element import *

Element

This is the base brick of branca. You can create an Element in providing a template string:


In [2]:
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.


In [3]:
print(e._name, e._id)
print(e.get_name())


Element a1d0f648f7444f96b526931944247fd6
element_a1d0f648f7444f96b526931944247fd6

You can render an Element using the method render:


In [4]:
e.render()


Out[4]:
'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:


In [5]:
e = Element("Hello {{kwargs['you']}}, my name is `{{this.get_name()}}`.")
e.render(you='World')


Out[5]:
'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.


In [6]:
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.


In [7]:
print(parent.render(), child.render())


This is the parent. This is the child.

But you can use the tree structure in the template.


In [8]:
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()


Out[8]:
'<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:


In [9]:
parent = Element("<parent>{% for child in this._children.values() %}{{child.render()}}{% endfor %}</parent>")
Element('<child1/>').add_to(parent, name='child_1')
parent._children


Out[9]:
OrderedDict([('child_1', <branca.element.Element at 0x7f758f2db6a0>)])

That way, it's possible to overwrite a child in specifying the same name:


In [10]:
Element('<child1_overwritten/>').add_to(parent, name='child_1')
parent.render()


Out[10]:
'<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.

Figure

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.

In [11]:
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:


In [12]:
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:


In [13]:
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:


In [14]:
f


Out[14]:

If this rendering is too large for you, you can force it's width and height:


In [15]:
f.width = 300
f.height = 200
f


Out[15]:

Note that you can also define a Figure's size in a matplotlib way:


In [16]:
Figure(figsize=(5,5))


Out[16]:

MacroElement

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.


In [17]:
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:


In [18]:
js_link = JavascriptLink('https://example.com/javascript.js')
js_link.render()


Out[18]:
'<script src="https://example.com/javascript.js"></script>'

In [19]:
css_link = CssLink('https://example.com/style.css')
css_link.render()


Out[19]:
'<link rel="stylesheet" href="https://example.com/style.css" />'

Html

An Html element enables you to create custom div to put in the body of your page.


In [26]:
html = Html('Hello world')
html.render()


Out[26]:
'<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.


In [25]:
Html('<b>Hello world</b>').render()


Out[25]:
'<div id="html_18a1f0cf2e61444d8a396ad5cb77f864" style="width: 100.0%; height: 100.0%;">&lt;b&gt;Hello world&lt;/b&gt;</div>'

For this, you have to set script=True and it will work:


In [28]:
Html('<b>Hello world</b>', script=True).render()


Out[28]:
'<div id="html_9cf0c436b7f0462ea59479bc9175e72a" style="width: 100.0%; height: 100.0%;"><b>Hello world</b></div>'

IFrame

If you need to embed a full webpage (with separate javascript environment), you can use IFrame.


In [21]:
iframe = IFrame('Hello World')
iframe.render()


Out[21]:
'<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:


In [22]:
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


Out[22]:

Div

At last, you have the Div element that behaves almost like Html with a few differences:

  • The style is put in the header, while Html's style is embedded inline.
  • Div inherits from MacroElement so that:
    • It cannot be rendered unless it's embedded in a Figure.
    • It is a useful object toinherit from when you create new classes.

In [29]:
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>