- Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathplot.py
More file actions
Latest commit
174 lines (157 loc) · 10.3 KB
/
Copy pathplot.py
File metadata and controls
174 lines (157 loc) · 10.3 KB
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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
importnumpyasnp
importre
importxml.dom.minidomasdom
importargparse
importslidingWindow
classComposite:
pass
classXScale:
def__init__(self, plot):
self.domain= [plot.xmin, plot.xmax, plot.xmax-plot.xmin]
self.range= [plot.margins.get('left'), plot.width-plot.margins.get('right'), plot.width- (plot.margins.get('right') +plot.margins.get('left'))]
self.zero= (plot.width- (plot.margins.get('right') +plot.margins.get('left'))) /2+plot.margins.get('left')
defget(self, value):
return (self.range[2] /self.domain[2]) *value+self.zero
definverse(self, value):
return (value-self.zero) * (self.domain[2] /self.range[2])
classyScale:
def__init__(self, plot):
self.domain= [plot.ymin, plot.ymax, plot.ymax-plot.ymin]
self.range= [plot.margins.get('top'), plot.height-plot.margins.get('bottom'), plot.height- (plot.margins.get('top') +plot.margins.get('bottom'))]
self.zero= (plot.height- (plot.margins.get('bottom') +plot.margins.get('top'))) /2+plot.margins.get('top') ifplot.combinedisFalseelseself.range[1]
defget(self, value):
return (self.range[2] /self.domain[2]) *value+self.zero
definverse(self, value):
return (value-self.zero) * (self.domain[2] /self.range[2])
classPlot:
def__init__(self, title="Composite plot", xmin=-500, xmax=500, ymin=-1, ymax=1, xlabel="Position (bp)", ylabel="Occupancy (AU)",
opacity=1, smoothing=7, bp_shift=0, combined=False, color_trace=False, show_legend=True):
self.title=title
self.xmin=xmin
self.xmax=xmax
self.ymin=ymin
self.ymax=ymax
self.xlabel=xlabel
self.ylabel=ylabel
self.width=460
self.height=300
self.margins= {'top': 30, 'right': 170, 'bottom': 35, 'left': 40}
self.opacity=opacity
self.smoothing=smoothing
self.bp_shift=bp_shift
self.combined=combined
self.color_trace=color_trace
self.show_legend=show_legend
document=dom.Document()
self.composite_group=document.createElement("g")
self.composite_group.setAttribute("class", "composite plotted")
self.gradients_group=document.createElement("defs")
self.super_group=document.createElement("g")
self.xscale=XScale(self)
self.yscale=yScale(self)
self.num_composites=0
defplot_composite(self, xmin, xmax, sense, anti, scale=1, color=None, secondary_color=None, i=None, opacity=None, smoothing=None, bp_shift=None, hide_sense=False, hide_anti=False, baseline=0):
document=dom.Document()
# Set parameters to global values if not specified
opacity=opacityifopacityisnotNoneelseself.opacity
smoothing=smoothingifsmoothingisnotNoneelseself.smoothing
bp_shift=bp_shiftifbp_shiftisnotNoneelseself.bp_shift
if (iisNone):
i=self.num_composites
self.num_composites+=1
else:
i=i
# Set x domain as array of integers from xmin to xmax
xdomain= [i+xminforiinrange(xmax-xmin+1)]
if (self.combined):
# Calculate defined x domain after shifting
shifted_xdomain= [xforxinxdomainifx-bp_shift>=xdomain[0] andx-bp_shift<=xdomain[-1]
andx+bp_shift>=xdomain[0] andx+bp_shift<=xdomain[-1]]
shifted_sense= [sense[j] forjinrange(len(sense)) ifxdomain[j] +bp_shift>=shifted_xdomain[0]
andxdomain[j] +bp_shift<=shifted_xdomain[-1]]
shifted_anti= [anti[j] forjinrange(len(anti)) ifxdomain[j] +bp_shift>=shifted_xdomain[0]
andxdomain[j] +bp_shift<=shifted_xdomain[-1]]
# Add occupancy for sense and anti
combined_occupancy= [shifted_sense[j] +shifted_anti[j] forjinrange(len(shifted_sense))]
# Smooth occupancy with moving average
new_xdomain, smoothed_occupancy=slidingWindow.sliding_window(shifted_xdomain, combined_occupancy, smoothing).values()
# Truncate x domain to x axis limits
truncated_xdomain= [xforxinxdomainifx>=self.xminandx<=self.xmax]
# Truncate occupancy and scale by scale factor, adding baseline value
scaled_occupancy= [valueif (value:=d*scale+baseline) >0else0forj, dinenumerate(smoothed_occupancy)
ifint(new_xdomain[j]) >=self.xminandint(new_xdomain[j]) <=self.xmax]
#Create Composite Trace
document=dom.Document()
ifself.color_trace:
white_line=document.createElement("path")
composite_fill_top=document.createElement("polygon")
composite_fill_top.setAttribute("points", points:=" ".join([f"{self.xscale.get(d)},{self.yscale.get(-scaled_occupancy[j])}"forj, dinenumerate(truncated_xdomain)]) +f" {self.xscale.get(truncated_xdomain[-1])},{self.yscale.get(0)}{self.xscale.get(truncated_xdomain[0])},{self.yscale.get(0)}")
composite_fill_top.setAttribute("fill", "url(#composite-gradient-top"+str(i) +")")
self.composite_group.appendChild(composite_fill_top)
else:
# Smooth sense and anti occupancy with moving average
new_xdomain, smoothed_sense=slidingWindow.sliding_window(xdomain, sense, smoothing).values()
smoothed_anti=list(slidingWindow.sliding_window(xdomain, anti, smoothing).values())[1]
# Truncate x domain to x axis limits
truncated_sense_domain= [jforxinnew_xdomainif (j:=x+bp_shift) >=self.xminandj<=self.xmax]
truncated_anti_domain= [jforxinnew_xdomainif (j:=x-bp_shift) >=self.xminandj<=self.xmax]
# Truncate sense and anti occupancy and scale by scale factor
scaled_sense= [valueif (value:=d*scale+baseline) >0else0forj, dinenumerate(smoothed_sense)
ifint(new_xdomain[j] +bp_shift) >=self.xminandint(new_xdomain[j] +bp_shift) <=self.xmax]
scaled_anti= [valueif (value:=d*scale+baseline) >0else0forj, dinenumerate(smoothed_anti)
ifint(new_xdomain[j] -bp_shift) >=self.xminandint(new_xdomain[j] -bp_shift) <=self.xmax]
# Create sense path and gradient if not hidden
# Create top polygon
composite_fill_top=document.createElement("polygon")
composite_fill_top.setAttribute("points", pointsA:=" ".join([f"{self.xscale.get(d)},{self.yscale.get(-scaled_sense[j])}"forj, dinenumerate(truncated_sense_domain)]) +f" {self.xscale.get(truncated_sense_domain[-1])},{self.yscale.get(0)}{self.xscale.get(truncated_sense_domain[0])},{self.yscale.get(0)}")
composite_fill_top.setAttribute("fill", "url(#composite-gradient-top"+str(i) +")")
# Create bottom polygon
composite_fill_bottom=document.createElement("polygon")
composite_fill_bottom.setAttribute("points", pointsB:=" ".join([f"{self.xscale.get(d)},{self.yscale.get(scaled_anti[j])}"forj, dinenumerate(truncated_anti_domain)]) +f" {self.xscale.get(truncated_anti_domain[-1])},{self.yscale.get(0)}{self.xscale.get(truncated_anti_domain[0])},{self.yscale.get(0)}")
composite_fill_bottom.setAttribute("fill", "url(#composite-gradient-bottom"+str(i) +")")
self.composite_group.appendChild(composite_fill_top)
self.composite_group.appendChild(composite_fill_bottom)
self.generateGradients(1, i, color, secondary_color=secondary_color)
self.super_group.appendChild(self.gradients_group)
self.super_group.appendChild(self.composite_group)
returnself.super_group
defgenerateGradients(self, opacity, i, color, secondary_color=None):
# Creates DOM elements for top and bottom gradients
secondary_color=secondary_colorifsecondary_colorisnotNoneelsecolor
document=dom.Document()
composite_gradient_top=document.createElement("linearGradient")
composite_gradient_top.setAttribute("class", "composite-gradient-top")
composite_gradient_top.setAttribute("x1", "0%")
composite_gradient_top.setAttribute("x2", "0%")
composite_gradient_top.setAttribute("y1", "0%")
composite_gradient_top.setAttribute("y2", "100%")
composite_gradient_top.setAttribute("id", "composite-gradient-top"+str(i))
top_stop_one=document.createElement("stop")
top_stop_one.setAttribute("offset", "0")
top_stop_one.setAttribute("stop-color", color)
top_stop_one.setAttribute("stop-opacity", str(opacity))
top_stop_two=document.createElement("stop")
top_stop_two.setAttribute("offset", "1")
top_stop_two.setAttribute("stop-color", color)
top_stop_two.setAttribute("stop-opacity", "0")
composite_gradient_top.appendChild(top_stop_one)
composite_gradient_top.appendChild(top_stop_two)
self.gradients_group.appendChild(composite_gradient_top)
composite_gradient_bottom=document.createElement("linearGradient")
composite_gradient_bottom.setAttribute("class", "composite-gradient-bottom")
composite_gradient_bottom.setAttribute("x1", "0%")
composite_gradient_bottom.setAttribute("x2", "0%")
composite_gradient_bottom.setAttribute("y1", "100%")
composite_gradient_bottom.setAttribute("y2", "0%")
composite_gradient_bottom.setAttribute("id", "composite-gradient-bottom"+str(i))
bottom_stop_one=document.createElement("stop")
bottom_stop_one.setAttribute("offset", "0")
bottom_stop_one.setAttribute("stop-color", secondary_color)
bottom_stop_one.setAttribute("stop-opacity", str(opacity))
bottom_stop_two=document.createElement("stop")
bottom_stop_two.setAttribute("offset", "1")
bottom_stop_two.setAttribute("stop-color", secondary_color)
bottom_stop_two.setAttribute("stop-opacity", "0")
composite_gradient_bottom.appendChild(bottom_stop_one)
composite_gradient_bottom.appendChild(bottom_stop_two)
self.gradients_group.appendChild(composite_gradient_bottom)