#!/usr/bin/python
import json
import collections
import os
import xml.dom.minidom
def FlattenDict(data, prefix = ''):
if isinstance(data, list):
#if prefix == '':
# print("prefix required for lists")
# return data
output = {}
for i in range(0,len(data)):
output.update(FlattenDict(data[i], prefix + '[' + str(i) + ']'))
return output
if isinstance(data, dict):
if not prefix == '':
prefix = prefix + '.'
output = {}
for k in data.keys():
output.update(FlattenDict(data[k], prefix + k))
return output
if prefix == '':
return data
return { prefix : data }
# Convert a python dict to a 2D table / matrix of values, still as a dict
def DictToTable(data):
rowKeys = data.keys()
columnKeys = set()
flattenedData = {}
for k in rowKeys:
flattenedData[k] = FlattenDict(data[k])
colKeys = flattenedData[k].keys()
for c in colKeys:
columnKeys.add(c)
return { "rows" : sorted(rowKeys),
"columns" : sorted(list(columnKeys)),
"data" : flattenedData }
def DictToHtmlTable(data):
table = DictToTable(data)
items = ['<table>', '<tr><th></th>']
for col in table["columns"]:
items.append('<th>%s</th>' % col)
items.append('</tr>')
for row in table["rows"]:
items.append('<tr><th>%s</th>' % row)
for col in table["columns"]:
val = ''
if col in data[row]:
val = data[row][col]
items.append('<td>%s</td>' % val)
items.append('</tr>')
items.append('</table>')
return '\n'.join(items)
def TableToCSV(table):
lines = []
line = '## row-name'
for col in table["columns"]:
line = line + ' , ' + col
lines.append(line)
for row in table["rows"]:
line = row
for col in table["columns"]:
val = ''
if col in table["data"][row]:
val = table["data"][row][col]
line = line + ' , ' + str(val)
lines.append(line)
return '\n'.join(lines)
def DictToCSVTable(data):
return TableToCSV(DictToTable(data))
def TableToXmlWorksheet(table, name='Worksheet1'):
columnCount = len(table["columns"])
maxColWidth = 2
for col in table["columns"]:
maxColWidth = max(maxColWidth, len(col))
maxRowWidth = 2
for row in table["rows"]:
maxRowWidth = max(maxRowWidth, len(row))
lines = []
lines.append('<ss:Worksheet ss:Name="' + name + '">')
lines.append('<Table ss:StyleID="table">')
# Width needs to be as wide as widest row name
lines.append('<Column ss:Width="50.0"/>')
lines.append('<Column ss:Width="' + str(maxRowWidth*8) + '.0"/>')
for col in table["columns"]:
lines.append('<Column ss:Width="20.0"/>')
lines.append('<Column ss:Width="50.0"/>')
lines.append('<Row ss:Height="50.0">')
lines.append('<Cell ss:MergeAcross="' + str(columnCount+2) + '" ss:StyleID="Heading"> <Data ss:Type="String">' + name + '</Data> </Cell>')
lines.append('</Row>')
# Height needs to be as high as widest column name
lines.append('<Row ss:Height="' + str(maxColWidth*6) + '.0"><Cell ss:StyleID="Blank"/><Cell ss:StyleID="ColumnHeader"/>')
for col in table["columns"]:
lines.append('<Cell ss:StyleID="ColumnHeader"> <Data ss:Type="String">' + col + '</Data> </Cell>')
lines.append('<Cell ss:StyleID="Blank"/></Row>')
alt = 0
for row in table["rows"]:
lines.append('<Row ss:AutoFitHeight="0" ss:Height="13.0">')
lines.append('<Cell ss:StyleID="Left"/>')
lines.append('<Cell ss:StyleID="Row' + str(alt) + '"> <Data ss:Type="String">' + str(row) + '</Data> </Cell>')
for col in table["columns"]:
val = ''
if col in table["data"][row]:
val = table["data"][row][col]
lines.append('<Cell ss:StyleID="Value' + str(alt) + '"> <Data ss:Type="String">' + str(val) + '</Data> </Cell>')
lines.append('<Cell ss:StyleID="Right"/>')
lines.append('</Row>')
alt = 1 - alt
lines.append('<Row ss:Height="50.0"><Cell ss:StyleID="Blank"/>')
lines.append('<Cell ss:MergeAcross="' + str(columnCount) + '" ss:StyleID="Bottom"> </Cell>')
lines.append('<Cell ss:StyleID="Blank"/></Row>')
lines.append('</Table>')
lines.append('<x:WorksheetOptions/>')
lines.append('</ss:Worksheet>')
return '\n'.join(lines)
def ConvertToExcelFile(data):
lines = [ '<?xml version="1.0" ?>',
'<?mso-application progid="Excel.Sheet"?>',
'<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"',
'xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet">',
'<Styles>', '<Style ss:ID="Default" ss:Name="Default"/>',
'<Style ss:ID="Heading"><Alignment ss:Vertical="Center" ss:Horizontal="Center"/>',
'<Interior ss:Color="#dddddd" ss:Pattern="Solid"/>',
'<Font ss:Bold="1" ss:Size="16"/></Style>',
'<Style ss:ID="ColumnHeader"> <Alignment ss:Horizontal="Left" ss:Rotate="45"/><Borders>',
'<Border ss:Color="#000000" ss:LineStyle="Continuous" ss:Position="Bottom" ss:Weight="1"/>',
'</Borders><Interior ss:Color="#dddddd" ss:Pattern="Solid"/></Style>',
'<Style ss:ID="Left"><Borders>',
'<Border ss:Color="#000000" ss:LineStyle="Continuous" ss:Position="Right" ss:Weight="1"/>',
'</Borders><Interior ss:Color="#dddddd" ss:Pattern="Solid"/></Style>',
'<Style ss:ID="Right"><Borders>',
'<Border ss:Color="#000000" ss:LineStyle="Continuous" ss:Position="Left" ss:Weight="1"/>',
'</Borders><Interior ss:Color="#dddddd" ss:Pattern="Solid"/></Style>',
'<Style ss:ID="Bottom"><Borders>',
'<Border ss:Color="#000000" ss:LineStyle="Continuous" ss:Position="Top" ss:Weight="1"/>',
'</Borders><Interior ss:Color="#dddddd" ss:Pattern="Solid"/></Style>',
'<Style ss:ID="Blank"><Interior ss:Color="#dddddd" ss:Pattern="Solid"/></Style>',
'<Style ss:ID="Row0"><Interior ss:Color="#dddddd" ss:Pattern="Solid"/></Style>',
'<Style ss:ID="Row1"><Interior ss:Color="#eeeeee" ss:Pattern="Solid"/></Style>',
'<Style ss:ID="Value0"><Borders><Border ss:Color="#000000" ss:LineStyle="Continuous" ss:Position="Left" ss:Weight="1"/>',
'</Borders><Interior ss:Color="#ddddee" ss:Pattern="Solid"/></Style>',
'<Style ss:ID="Value1"><Borders><Border ss:Color="#000000" ss:LineStyle="Continuous" ss:Position="Left" ss:Weight="1"/>',
'</Borders><Interior ss:Color="#eeeeff" ss:Pattern="Solid"/></Style>',
'<Style ss:ID="table"> <Font ss:Size="10" ss:VerticalAlign="Subscript"/> </Style>',
'</Styles>' ]
for worksheet in sorted(data.keys()):
lines.append(TableToXmlWorksheet(DictToTable(data[worksheet]), worksheet))
lines.append('</Workbook>')
return '\n'.join(lines)
def PrettyPrintJson(data):
return json.dumps(data, indent=4, sort_keys=True)
def PrettyPrintXmlString(string):
xmlVal = xml.dom.minidom.parseString(string)
return xmlVal.toprettyxml()
def PrettyPrintXmlFile(filename):
xmlVal = xml.dom.minidom.parse(filename)
return xmlVal.toprettyxml()
# Outputs these files: <name>.csv <name>.pg and <name>.png
# the PNG output is the image of the graph
def GraphData(name, data, x_label='', y_label='', title=''):
table = DictToTable(data)
csvData = TableToCSV(table)
with open(name + ".csv", "w") as csvFile:
csvFile.write(csvData)
lines = [ '#!/usr/bin/gnuplot', 'reset', 'set terminal png size 1200,800',
'set style data lines', 'set datafile separator ","',
'set xlabel "' + x_label + '"', 'set ylabel "' + y_label + '"',
'set title "' + title + '"', 'set output "' + name + '.png"',
#set xdata time
#set timefmt "%Y-%m-%dT%H:%M:%S"
#set format x "%d/%m"
]
columns = table["columns"]
cols = []
for i in range(len(columns)):
cols.append('"' + name + '.csv" using 1:'
+ str(i+2) + ' with lines t "' + columns[i] + '"')
cols[0] = 'plot ' + cols[0]
lines.append(','.join(cols))
commands = '\n'.join(lines)
with open(name + ".pg", "w") as pgFile:
pgFile.write(commands)
print(commands)
os.system("gnuplot " + name + ".pg")
return '\n'.join(lines)
###########################
# Tests
###########################
def FlattenDictTest(data, expected):
ordered = json.dumps(collections.OrderedDict(sorted(FlattenDict(data).items())))
comparison = json.dumps(collections.OrderedDict(sorted(expected.items())))
if ordered != comparison:
print("FAIL: ")
print(" " + ordered)
print(" != " + comparison)
else:
print("PASS")
def FlattenDictTests():
FlattenDictTest({ "a" : { "b" : 1, "c" : 2 } },
{ "a.b" : 1, "a.c" : 2 })
FlattenDictTest({ "a" : { "b" : 1, "c" : { "d" : 2, "e" : 3 } } },
{ "a.b" : 1, "a.c.d" : 2, "a.c.e" : 3 })
FlattenDictTest({ "a" : { "b" : 1, "c" : [ 2, 3 ] } },
{ "a.b" : 1, "a.c[0]" : 2, "a.c[1]" : 3 })
FlattenDictTest({ "a" : [ 1, 2, 3 ] },
{ "a[0]" : 1, "a[1]" : 2, "a[2]" : 3 })
FlattenDictTest([ 1, 2, 3 ],
{ "[0]" : 1, "[1]" : 2, "[2]" : 3})
def UnitTests():
FlattenDictTests()
print(json.dumps(DictToTable({
"a" : { "m_a" : 1, "m_b" : 2 },
"b" : { "m_b" : 1, "m_c" : 2 },
"c" : { "m_a" : 1, "m_c" : 2 },
"d" : { "m_d" : 1, "m_b" : 2 },
"e" : { "m_c" : 1 },
"f" : { }
})))
print(DictToHtmlTable({
"a" : { "m_a" : 1, "m_b" : 2 },
"b" : { "m_b" : 1, "m_c" : 2 },
"c" : { "m_a" : 1, "m_c" : 2 },
"d" : { "m_d" : 1, "m_b" : 2 },
"e" : { "m_c" : 1 },
"f" : { }
}))
print(DictToCSVTable({
"a" : { "m_a" : 1, "m_b" : 2 },
"b" : { "m_b" : 1, "m_c" : 2 },
"c" : { "m_a" : 1, "m_c" : 2 },
"d" : { "m_d" : 1, "m_b" : 2 },
"e" : { "m_c" : 1 },
"f" : { }
}))
graphData = {
"0" : { "AA" : 0, "BB" : 3 },
"1" : { "AA" : 1, "BB" : 1 },
"2" : { "CC" : 2, "BB" : 2 },
"3" : { "CC" : 3, "BB" : 0 },
}
# GraphData('blah', graphData, x_label="X", y_label="Y", title="Title")
GraphData('generated', graphData)
print(PrettyPrintJson(graphData))
print(PrettyPrintXmlString("<xml> <title> blah </title> </xml>"))
excelStr = ConvertToExcelFile({
"Worksheet A" : { "uidA" : { "m_a.x" : 1, "m_a.y" : 2, "m_a.z" : 3 },
"uidB" : { "m_a.x" : 4, "m_a.y" : 5, "m_a.z" : 6 },
"uidC" : { "m_a.x" : 7, "m_a.y" : 8, "m_a.z" : 9 } },
"Worksheet B" : { "uidA" : { "m_a.x" : 10, "m_a.y" : 11, "m_a.z" : 12 },
"uidB" : { "m_a.x" : 13, "m_a.y" : 14, "m_a.z" : 15 },
"uidC" : { "m_a.x" : 16, "m_a.y" : 17, "m_a.z" : 18 } },
"Worksheet C" : { }
})
with open("generated.xml", "w") as xlsFile:
xlsFile.write(excelStr)
UnitTests()