-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathBudgetSummaryChart.py
112 lines (81 loc) · 3.57 KB
/
BudgetSummaryChart.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
global model
global Data
y = Data.p1 or '1'
sql = model.SqlContent('BudgetSummary').replace('@p1', y)
d = model.SqlListDynamicData(sql)
def formatMoney(num):
if num < 0:
return "-${:-0,.0f}".format(num)
else:
return "${:-0,.0f}".format(num)
chart = ""
labelPositions = [[]]
def determineLine(x):
margin = 85
line = 1
while True:
c = False
if len(labelPositions) <= line:
labelPositions.append([])
for lp in labelPositions[line]:
if lp is None:
continue
if lp > x-margin and lp < x+margin:
line += 1
c = True
continue
if c:
continue
labelPositions[line].append(x)
return line
def getMarkedLabel(x, y, label1, label2, textColor="#000", lineStyle="stroke:#999;stroke-width:1", extendTop=False):
line = determineLine(x)
yBase = y + 10 # top of bar
y += line * 50 + 10 # top of the indicator (for line 1, bottom of the bar).
yTop = yBase - (10 if extendTop else 0)
r = "<line x1=\"{0}\" y1=\"{2}\" x2=\"{0}\" y2=\"{3}\" style=\"{1}\" />".format(x, lineStyle, yTop, yBase+50)
r += "<line x1=\"{0}\" y1=\"{2}\" x2=\"{0}\" y2=\"{3}\" style=\"{1}\" />".format(x, lineStyle, y, y+10)
r += "<text x=\"{0}\" y=\"{1}\" fill=\"{2}\" style=\"text-anchor: middle\" font-family=\"Lato, sans-serif\">".format(x, y+25, textColor)
r += "<tspan x=\"{0}\" dy=\"0\">{1}</tspan>".format(x, label1)
r += "<tspan x=\"{0}\" dy=\"15\">{1}</tspan>".format(x, label2)
r += "</text>"
return r
# determine scaling
maxBudget = 1
for f in d:
if f['Budget FY'] is not None and f['Budget FY'] > maxBudget:
maxBudget = f['Budget FY']
if f["Giving YTD"] is not None and f["Giving YTD"] > maxBudget:
maxBudget = f["Giving YTD"]
yCum = 0
for f in d:
givingPos = 100 + (500 * f["Giving YTD"] / maxBudget)
budgetPos = 100 + (500 * f["Budget YTD"] / maxBudget) if f["Budget YTD"] is not None else None
prevPos = 100 + (500 * f["Giving PYTD"] / maxBudget) if f["Giving PYTD"] is not None else None
barWidth = (500 * f["Budget FY"] / maxBudget) if f["Budget FY"] is not None else None
chart += "<!-- {} -->".format(f['Fund'])
# fund label
# chart += "<text x=\"{0}\" y=\"{1}\" fill=\"#000\">".format(3, yCum+35)
# chart += "<tspan x=\"{0}\" dy=\"0\">{1}</tspan>".format(3, f['Fund'])
# chart += "</text>"
# base bar
if barWidth is not None:
chart += """<rect width="{0}" height="50" x="100" y="{1}" style="fill:#ccc;" />""".format(barWidth, yCum+10)
# giving bar
chart += """<rect width="{0}" height="50" x="100" y="{1}" style="fill:#49917b;" />""".format(givingPos-100, yCum+10)
chart += getMarkedLabel(givingPos, yCum, "Giving YTD", formatMoney(f["Giving YTD"]))
if f["Budget YTD"] is not None and f["Budget FY"] is not None and f["Budget YTD"] / f["Budget FY"] < 11.2/12:
chart += getMarkedLabel(budgetPos, yCum, "Budget YTD", formatMoney(f["Budget YTD"]), "#000", "stroke:#000;stroke-width:3", True)
if f["Budget FY"] is not None:
chart += getMarkedLabel(barWidth+100, yCum, "Budget FY", formatMoney(f["Budget FY"]))
chart += getMarkedLabel(prevPos, yCum, "Giving Last Year", formatMoney(f["Giving PYTD"]), "#999")
height = len(labelPositions) * 50 + 10
yCum += height
labelPositions = [None]
break
print("""<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg viewBox="0 0 700 {0}" xmlns="http://www.w3.org/2000/svg">
""".format(yCum))
print(chart)
print("</svg>")
#