-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathd4_server.py
129 lines (100 loc) · 4.02 KB
/
d4_server.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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# Python 3 server example
from http.server import BaseHTTPRequestHandler, HTTPServer
from urllib.parse import urlparse;
import pyBigWig
import json
import ctypes
import math
hostName = "localhost"
serverPort = 8888
# /Users/jrobinso/igv-team%20Dropbox/Data/Juicebox/CTCF_Untreated.bw
class BigwigServer(BaseHTTPRequestHandler):
def do_GET(self):
# Initial assumptions, until proven otherwise
start = 0
values = None
nvalues = 0
# Parse file path and query parameters
parsed = urlparse(self.path)
query = parsed.query
filepath = parsed.path.replace("%20", " ");
if query is not None and len(query) > 0:
query_components = dict(qc.split("=") for qc in query.split("&"))
if "class" in query_components and query_components["class"] == "header":
self.do_headerquery(filepath)
elif "chr" in query_components:
self.do_dataquery(filepath, query_components)
else:
self.do_nullresponse(query)
else:
self.do_nullresponse(None)
# Return some meta information about the file. Currently jsut returns chromosome names as a json array
# This is needed to support IGV chr name aliasing
def do_headerquery(self, filepath):
bw = pyBigWig.open(filepath)
chrom_dict = bw.chroms();
chrom_names = list(chrom_dict.keys())
self.send_response(200)
self.send_header("Content-type", "application/json")
self.end_headers()
self.wfile.write(bytes(json.dumps(chrom_names), "utf-8"))
self.wfile.flush();
def do_dataquery(self, filepath, query_components):
chr = query_components["chr"]
start = max(0, int(query_components["start"]))
end = max(0, int(query_components["end"]))
try:
# Open bigwig file and retrieve values
bw = pyBigWig.open(filepath)
chrom_dict = bw.chroms();
if chr in chrom_dict:
maxpos = chrom_dict[chr]
end = min(end, maxpos)
# Should we use summary stats (zoomLevel) or raw values?
n = end - start
if n > 1000:
stepsize = math.ceil(n / 1000)
nbins = math.floor(n / stepsize)
end = start + nbins*stepsize
values = bw.stats(chr, start, end, nBins=nbins)
else:
end = min(end, maxpos)
values = bw.values(chr, start, end)
stepsize = 1
nvalues = len(values)
self.send_response(200)
self.send_header("Content-type", "application/octect-stream")
self.end_headers()
self.wfile.write(start.to_bytes(4, 'little'))
self.wfile.write(stepsize.to_bytes(4, 'little'))
self.wfile.write(nvalues.to_bytes(4, 'little'))
# Return values in binary format.
buf = (ctypes.c_float * nvalues)()
buf[:] = values
self.wfile.write(buf)
self.wfile.flush()
else:
self.do_nullresponse()
except Exception as e:
# TODO -- send error code and message ?
self.do_nullresponse()
def do_nullresponse(self):
zero = 0
self.send_response(200)
self.send_header("Content-type", "application/octect-stream")
self.end_headers()
self.wfile.write(zero.to_bytes(4, 'little'))
self.wfile.write(zero.to_bytes(4, 'little'))
self.wfile.write(zero.to_bytes(4, 'little'))
def do_HEAD(self):
self.send_response(200)
self.end_headers()
if __name__ == "__main__":
webServer = HTTPServer((hostName, serverPort), BigwigServer)
print("Server started http://%s:%s" % (hostName, serverPort))
try:
webServer.serve_forever()
except KeyboardInterrupt:
pass
webServer.server_close()
print("Server stopped.")