Created
December 20, 2016 19:39
-
-
Save D3f0/35011bc1e3788011583c54da2b0f4681 to your computer and use it in GitHub Desktop.
Plot metl schema XML using Matplotlib to produce a PNG
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python2 | |
''' | |
Plots a MELT xml schema with matplotlib | |
''' | |
from __future__ import print_function | |
from lxml import etree | |
import sys | |
from datetime import datetime, timedelta | |
from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas | |
from matplotlib.figure import Figure | |
# JS like object access for dicts | |
try: | |
from bunch import Bunch | |
except ImportError: | |
print("please install bunch to run this command") | |
sys.exit(1) | |
# Easy argparse alternative | |
try: | |
import click | |
except ImportError: | |
print("please install click to run this command") | |
sys.exit(1) | |
def _dbg(e): | |
'''Display etree to stdout''' | |
print(etree.tostring(e, pretty_print=True)) | |
def seconds(secs): | |
'''Time delta in seconds. Accepts strings''' | |
if isinstance(secs, basestring): | |
secs = float(secs) | |
return timedelta(seconds=secs) | |
def get_musix_xy(music_prod, base_time=None): | |
points = [] | |
# Go through music | |
for flt in music_prod.xpath('./filter'): | |
gain = flt.find('./property[@name="gain"]') | |
end = flt.find('./property[@name="end"]') | |
in_ = float(flt.attrib['in']) | |
out = float(flt.attrib['out']) | |
start = (base_time + seconds(in_), float(gain.text)) | |
end = (base_time + seconds(out), float(end.text)) | |
points.append(start) | |
points.append(end) | |
# Sort | |
points.sort(cmp=lambda a, b: cmp(a[0], b[0])) | |
x = [e[0] for e in points] | |
y = [e[1] for e in points] | |
return x, y | |
def plot_schema(xml_schema): | |
"""Converts schema into plot""" | |
music_prod = xml_schema.xpath('//producer[contains(@id,"music")]')[0] | |
fig = Figure() | |
ax = fig.add_subplot(111) | |
# We need a datetime to do timedelta cacls | |
base_time = datetime(1970, 1, 1) | |
# Draw palylist | |
max_out_time = base_time | |
for i, plst in enumerate(xml_schema.xpath('//playlist')): | |
data = Bunch(plst.attrib) # Adds Id, autoclose | |
try: | |
data.update(plst.find('blank').attrib) # Adds length | |
except AttributeError: | |
data.update({'length': 0}) | |
data.update(plst.find('entry').attrib) # Adds in and out | |
if 'music' in data.id: # lousy comparision | |
offsetd_time = base_time + seconds(data.length) | |
music_prod = xml_schema.xpath('//producer[@id="%s"]' % data.producer)[0] | |
x, y = get_musix_xy(music_prod, base_time=offsetd_time) | |
ax.plot_date(x, y, '-', label='audio volume') | |
else: | |
in_time = base_time + seconds(data.length) + seconds(data['in']) # In resvd | |
out_time = base_time + seconds(data.length) + seconds(data.out) | |
x = [in_time - seconds(-0.01), in_time, out_time, out_time + seconds(0.01)] | |
y = [0, 1, 1, 0] | |
ax.plot_date(x, y, '-', label=data.id) | |
if out_time > max_out_time: | |
max_out_time = out_time | |
# The following two lines could be improved if there's no space left for | |
# lables | |
ax.axis([base_time, max_out_time, 0, 1.1 + 2]) | |
ax.legend() | |
fig.autofmt_xdate() | |
#import ipdb; ipdb.set_trace() | |
canvas = FigureCanvas(fig) | |
return canvas | |
@click.command() | |
@click.argument('paths', nargs=-1) | |
@click.argument('dst', nargs=1, default='-') | |
def main(paths, dst): | |
print(dst) | |
if not paths and dst: | |
paths = [dst, ] | |
dst = 'output.png' | |
for p in paths: | |
click.echo("Processing {}".format(p), file=sys.stderr) | |
with open(p) as fp: | |
xml = etree.fromstring(fp.read()) | |
canvas = plot_schema(xml) | |
click.echo("Writing output to {}".format(dst), file=sys.stderr) | |
canvas.print_png(dst) | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment