/
plots.wsgi
159 lines (145 loc) · 5.43 KB
/
plots.wsgi
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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
import traceback
import StringIO
import psycopg2
import matplotlib
# import error forces us to import cbook here; see
import matplotlib.cbook
matplotlib.use('Agg')
# https://groups.google.com/forum/?fromgroups=#!topic/modwsgi/97bnQk9ojtY
import matplotlib.backends.backend_agg
# in pixels, floating point for calculations
image_width = 600.0
image_height = 400.0
# in pixels
bottom_whitespace = 50
min_max_text_y = 40
val_text_y = 20
# plot_params[qa_type][parameter] -> dictionary of parameters
# parameter dictionary keys are:
# title: the plot title
# xlabel: the X-axis label
# bins: the number of bins in the histogram
# trim_f: a tuple (f_low, f_high) giving the fraction of values to
# exclude from the plot (to exclude outliers)
plot_params = {'basic_structural': {'snr': {'title': 'SNR',
'xlabel': 'SNR',
'bins': 50,
'trim_f': (0.01, 0.05)}},
'birn_fmri': {'snr': {'title': 'SNR',
'xlabel': 'SNR',
'bins': 50,
'trim_f': (0, 0)},
'sfnr': {'title': 'SFNR',
'xlabel': 'SFNR',
'bins': 50,
'trim_f': (0, 0)}}}
# query_params[qa_type][parameter] -> (table, column) to query
query_params = {'basic_structural': {'snr': ('incf_basicstructuralqadata',
'snr')},
'birn_fmri': {'snr': ('incf_maskeddetrendeddata',
'meansnrroimiddleslice'),
'sfnr': ('incf_maskeddetrendeddata',
'meansfnrroimiddleslice')}}
uncaught_exception_data = """An error occurred while generating this plot. Please report this incident
to xnat-admin@incf.org.
"""
class WSGIError(Exception):
"""base class for WSGI script errors"""
class ClientError(WSGIError):
def __init__(self, message):
WSGIError.__init__(self)
self.status = '400 Bad Request'
self.message = message
return
def application(environ, start_response):
try:
data = generate_png(environ)
status = '200 OK'
content_type = 'image/png'
except WSGIError, exc:
data = '%s\n' % exc.message
status = exc.status
content_type = 'text/plain'
except:
environ['wsgi.errors'].write(traceback.format_exc())
status = '500 Internal Server Error'
data = uncaught_exception_data
content_type = 'text/plain'
response_headers = [('Content-type', content_type),
('Content-Length', str(len(data)))]
start_response(status, response_headers)
return [data]
def generate_png(environ):
db_password = open('/home/ch/.xnat_db_pw').read().rstrip('\n')
uri_parts = environ['REQUEST_URI'].split('/')
try:
(empty, parts, qa_type, parameter, value) = uri_parts
value = float(value)
(table, column) = query_params[qa_type][parameter]
query = 'SELECT %s FROM %s' % (column, table)
params = plot_params[qa_type][parameter]
except ValueError:
# unpack tuple of wrong size or bad float
raise ClientError('malformed request URL')
except KeyError:
raise ClientError('unknown QA type or parameter')
db = psycopg2.connect(host='localhost',
user='xnat',
database='xnat',
password=db_password)
try:
c = db.cursor()
c.execute(query)
vals = [ row[0] for row in c ]
c.close()
finally:
db.close()
vals.sort()
min_val = min(vals)
max_val = max(vals)
i = 0
while i < len(vals):
if value < vals[i]:
break
i += 1
pct = float(i)/len(vals)
# trim top and bottom
n_bottom = int(params['trim_f'][0] * len(vals))
n_top = int(params['trim_f'][1] * len(vals))
if n_top == 0:
plot_vals = vals[n_bottom:]
else:
plot_vals = vals[n_bottom:-n_top]
fig = matplotlib.figure.Figure()
fig.set_facecolor('w')
fig.set_size_inches(image_width / fig.get_dpi(),
image_height / fig.get_dpi())
fig.suptitle(params['title'])
bottom_f = bottom_whitespace / image_height
h_f = 1.0 - bottom_f - 0.2
ax = fig.add_axes([0.1, 0.1+bottom_f, 0.8, h_f],
xlabel=params['xlabel'],
ylabel='Count')
min_max_text = 'min = %.1f, max = %.1f' % (min_val, max_val)
min_max_text_y_f = min_max_text_y / image_height
fig.text(0.5,
min_max_text_y_f,
min_max_text,
horizontalalignment='center',
verticalalignment='center')
val_text = 'value = %.1f, percentile = %d' % (value, int(100*pct))
val_text_y_f = val_text_y / image_height
fig.text(0.5,
val_text_y_f,
val_text,
horizontalalignment='center',
verticalalignment='center')
ax.hist(plot_vals, bins=params['bins'])
ax.axvline(value, color='k')
canvas = matplotlib.backends.backend_agg.FigureCanvasAgg(fig)
so = StringIO.StringIO()
canvas.print_png(so)
data = so.getvalue()
so.close()
return data
# eof