Skipole WSGI generator.

Topics:

Introduction Getting Started Your Code skiadmin start_call submit_data end_call Exceptions PageData SectionData skicall Serving wsgi Code Examples

Development at GitHub:

github.com/bernie-skipole/skipole

Using Gnuplot to serve an inline svg chart

Ensure your server has gnuplot installed.

Create a directory, and move to it, then create a skipole project "myproj", note the trailing space dot, for current directory.

python -m skilift myproj .

which creates the file myproj.py in your current directory.

Run the project and use skiadmin to add a paras.TagUnEscaped widget with name 'gnuptest' on the template page 4001.

This example creates random time data, and uses python random and datetime modules. Edit the start of your myproj.py file to include the imports:


import subprocess, random

from datetime import date, timedelta, datetime

And edit the end_call function as shown here:


def end_call(page_ident, page_type, skicall):
    """This function is called prior to returning a page,
       it can also be used to return an optional session cookie string."""

    # The following code could have been set in a submit_data function called by a responder,
    # but in this simple case it is set here when the returned page is the template page
    # with ident number 4001
    if page_ident[1] == 4001:
        # this template page contains the TagUnEscaped widget which holds the inline svg figure created here
        dataset = []
        # create a dataset of values against hourly time points
        # with a graph starting at now minus 2 days and 30 minutes
        # and with the end range at today, 23:59
        now = datetime.now()
        start_time = (now - timedelta(days=2, minutes=30)).strftime("%Y-%m-%d %H:%M")
        end_time = date.today().strftime("%Y-%m-%d 23:59")
        d = now - timedelta(days=2, hours=1)
        delta = timedelta(hours=1)
        while d <= now:
            d += delta
            x = d.strftime("%Y-%m-%d %H:%M")
            # y values are a random normal distribution, mean 100, sd 5
            y = random.normalvariate(100,5)
            dataset.append((x, y))
            # so a point in the dataset is a tuple which looks like ("year-month-day hour:minute", yvalue)
        result = timeline(start_time, end_time, *dataset).decode("utf-8")
        # The result string contains the code however,the beginning of
        # the string contains xml information before the svg tag which we want to remove:
        figdata = '<svg' + result.split('<svg')[1]

        # so figdata can now be set into a TagUnEscaped widget called gnuptest
        # this widget has been set in the template page with a 'div' tag - which will now
        # contain all the figdata code

        pd = PageData()
        pd['gnuptest', 'content'] = figdata
        skicall.update(pd)



def timeline(start_time, end_time, *dataset):
    "Create an SVG line chart, return svg code as a bytes string"
    # data to plot
    datastring = "\n".join(f"{x} {y}" for x,y in dataset)
    # commands to plot the points
    commands = ['set title "timeline.svg"',
                'set key off',
                'set xdata time',
                'set timefmt "%Y-%m-%d %H:%M"',
                'set yrange [50:150]',
                f'set xrange ["{start_time}":"{end_time}"]',
                'set format x "%d %b\n%H:%M"',
                'plot "-" using 1:3  with lines'
               ]
    return svgplot(commands, datastring)


def svgplot(commands, datastring):
    "Call gnuplot with commands, and datastring returns svg bytes"
    commandstring = "set terminal svg;" + ";".join(commands)
    args = ["gnuplot", "-e", commandstring]
    result = subprocess.check_output(args, input=datastring.encode("utf-8"), timeout=2)
    return result

 

The code string produced in variable figdata is inserted into the 'gnuptest' widget, which serves the code without escapes, and hence the chart will be shown on the page.