Saturday, October 18, 2008

More on docpictures and (almost) minimal example of web server with inline svg

After playing some more with the idea of embedding pictures in docstrings, I've settled on using dynamically created svg images instead of png images. The basic idea (which I'll write about in more details later) is to have something like

.. docpictures:: some_type
highly readable description

and have the docpicture module parse the "highly readable description" based on the syntax defined in some_type. Note that I chose this notation to be compatible with reStructuredText directives. The "highly readable description" will depend on the context. For example, the mathematically inclined will be able to read this:

.. docpictures:: equation
e^{i\pi} = -1

while the following might be easy to understand by programmers:

..docpicture:: uml_sequence
User --> Browser: clicks on a link
Browser -> Crunchy: requests file
Crunchy --> Browser: Authentication Request
Browser --> Crunchy: Authentication Response
note over Crunchy: Retrieves and processes file
Crunchy -> Browser: Sends processed file
Browser --> User: Displays file
In this last example using the syntax of this site which generates the following picture:



(Btw, the picture above is generated automatically each time this page is loaded - so it depends on the availability of the server. I have used a static version of this picture in the documentation for Crunchy.)

Using svg to do graphics is fairly easy. Using svg as embedded objects in an html document requires a bit of searching on the internet. Creating such documents and displaying dynamically requires even more searching (or perhaps more careful reading...). The thing important to remember is to serve the document as "application/xhtml+xml" instead of the usual "text/html". I thought it would be useful to share an almost minimal working example (tested only on Firefox) and perhaps save some time for others that would like to do the same. Feel free to adapt it as you like.

svg_test = """<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:svg="http://www.w3.org/2000/svg">
<head></head>
<body>
<h1>SVG embedded inline in XHTML</h1>
<svg:svg width="300px" height="200px">
<svg:circle cx="150px" cy="100px" r="50px" fill="%s"
stroke="#000000" stroke-width="5px"/>
</svg:svg>
</body>
</html>
"""


import BaseHTTPServer
import webbrowser

colors = ["#330000", "#660000", "#990000", "#cc0000", "#ff0000"]
index = 0
class WebRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
def do_GET(self):
global index
self.send_response(200)
self.send_header('Content-type', 'application/xhtml+xml')
self.end_headers()
self.wfile.write(svg_test% colors[index % 5])
index += 1

port = 8000
server = BaseHTTPServer.HTTPServer(('',port), WebRequestHandler)
webbrowser.open("http://127.0.0.1:%s"%port)
server.serve_forever()

And, if you know how to suppress the output of the webserver, feel free to leave a comment.

6 comments:

André said...

About the last sentence of my post, after re-reading the documentation carefully, I found out that all that is needed is to define something like

def log_message(self, *args):
''' will suppress the usual output'''
return

as a method of the request handler.

Doug Napoleone said...

I had been working on something to do the equations in rst, but it required some nasty hacks backing off to LaTeX to do the real work. I never really liked it. SVG does seem like the better way to go.

Paddy3118 said...

It might be good to support a subset of the dot language but maybe making things simpler on the auto-layout side?
(http://www.graphviz.org/)

- Paddy.

André said...

@paddy: Good idea. Ideally, one would do a Python port of WebDot.

Jon Schull said...

For embedding in html (and other things) it would also be good to consider this pidgeon-dot (based on python-like indentation)

http://tinyurl.com/6qrouc

André said...

@jon schull:
This does look like a very neat approach, and complements an earlier suggestion. The only downside is the external dependency on GraphViz. I'm trying (at least for now) to design things based on Python-only modules - preferably with no dependency outside of the standard library.