Skip to content

Commit 139fc74

Browse files
authored
Merge pull request #56 from CEGRcode/python_scripts
Added python scripts for creating plots on the command line
2 parents e50cffb + 703d445 commit 139fc74

11 files changed

Lines changed: 1344 additions & 6 deletions

File tree

.gitignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,9 @@
1+
js/*
2+
13
**/.DS_Store
4+
5+
!.gitignore
6+
!python
7+
python/sample_composites/composite_average.out
8+
/python/sample_composites
9+
/python/__pycache__

js/parse_composite.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,5 @@ let parse_multiple_composite = function(text, prefix) {
160160
if (save_comp) {
161161
composites[id] = {xmin: xmin, xmax: xmax, sense: sense, anti: anti}
162162
};
163-
164163
return composites
165164
}

js/widgets/main_plot.js

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -171,8 +171,8 @@ $(function() {
171171
d3.select("#main-plot-div").on("mousemove", function(e) {
172172
$("#main-plot").main_plot("move_tooltip", e)
173173
});
174-
main_plot.on("mouseleave", function() {
175-
// $("#main-plot").main_plot("hide_tooltip")
174+
d3.select("#main-plot-div").on("mouseleave", function() {
175+
$("#main-plot").main_plot("hide_tooltip")
176176
});
177177

178178
this.enable_tooltip = true;
@@ -737,8 +737,10 @@ $(function() {
737737
if (color_trace) {
738738
this._elements.composite_group.selectAll(".composite .color-line-top")
739739
.style("display", null);
740-
this._elements.composite_group.selectAll(".composite .color-line-bottom")
741-
.style("display", null);
740+
if (!this.combined){
741+
this._elements.composite_group.selectAll(".composite .color-line-bottom")
742+
.style("display", null);
743+
}
742744
this._elements.composite_group.selectAll(".composite .white-line")
743745
.style("display", "none");
744746
this._elements.composite_group.selectAll(".composite .black-line")
@@ -820,12 +822,13 @@ $(function() {
820822
.style("left", ev.clientX - (w - 80) / 1.4)
821823
} else {
822824
this._elements.tooltip.style("display", "none")
825+
d3.selectAll("#composite-plot-tooltip").remove();
823826
}
824827
}
825828
},
826829

827830
hide_tooltip: function() {
828-
this._elements.tooltip.style("display", "none")
831+
d3.selectAll("#composite-plot-tooltip").remove();
829832
},
830833

831834
download_as_svg: function() {

python/composite.py

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import csv
2+
import xml.dom.minidom as dom
3+
import argparse
4+
import math
5+
import parseComposite
6+
7+
# Objected to store bare-bones composite data, can be used with plot_composite function
8+
class SimpleComposite:
9+
def __init__(self, xmin=None, xmax=None, sense=[], anti=[], id=""):
10+
self.xmin = xmin
11+
self.xmax = xmax
12+
self.sense = sense
13+
self.anti = anti
14+
self.id = id
15+
16+
# Object to store composite data with options for plotting, similar to a settings row
17+
class Composite:
18+
def __init__(self, scale=1, color=None, secondary_color=None, i=None, opacity=None, smoothing=None, bp_shift=None, hide_sense=False, hide_anti=False, baseline=0, name=None, sense=None, anti=None, xmin=None, xmax=None):
19+
# Sets default values
20+
self.scale = scale if scale is not None else 1
21+
self.color = color if color is not None else "#0000FF"
22+
self.secondary_color = secondary_color if secondary_color is not None else color
23+
self.baseline = baseline if baseline is not None else 0
24+
self.xmin = xmin if xmin is not None else 0
25+
self.xmax = xmax if xmax is not None else 0
26+
self.sense = sense if sense is not None else []
27+
self.anti = anti if anti is not None else []
28+
# Don't assign defaults to opacity, smoothing, and bp_shift so plot can apply plot defaults
29+
self.opacity = opacity
30+
self.smoothing = smoothing
31+
self.bp_shift = bp_shift
32+
self.hide_anti = hide_anti
33+
self.hide_sense = hide_sense
34+
self.individual_files = {}
35+
self.files_loaded = len(self.individual_files)
36+
self.name = name
37+
# Adds a simple composite to the 'row'
38+
def load_simple_composite(self,composite: SimpleComposite):
39+
# If no files, initialize sense and anti arrays; otherwise, pad sense and anti arrays to new xdomain
40+
self.xmin = min(composite.xmin, self.xmin)
41+
self.xmax = max(composite.xmax, self.xmax)
42+
if len(self.individual_files) == 0:
43+
self.sense = [0] * (composite.xmax - composite.xmin + 1)
44+
self.anti = [0] * (composite.xmax - composite.xmin + 1)
45+
else:
46+
xmin = min([int(self.individual_files[c].xmin) for c in self.individual_files])
47+
xmax = max([int(self.individual_files[c].xmax) for c in self.individual_files])
48+
prefix = [0] * (xmin - self.xmin)
49+
suffix = [0] * (self.xmax - xmax)
50+
self.sense = prefix + self.sense + suffix
51+
self.anti = prefix + self.anti + suffix
52+
# Update sense and anti arrays
53+
j = composite.xmin - self.xmin
54+
while j <= composite.xmax - composite.xmin:
55+
idx = composite.xmin - self.xmin + j
56+
self.sense[idx] += composite.sense[j]
57+
self.anti[idx] += composite.anti[j]
58+
j += 1
59+
self.individual_files[composite.id] = composite
60+
# Loads dictionary from parse_multiple_composites
61+
def load_composite_dict(self,composite_dict: dict):
62+
for key in composite_dict:
63+
composite = composite_dict[key]
64+
# If no files, initialize sense and anti arrays; otherwise, pad sense and anti arrays to new xdomain
65+
self.xmin = min(composite.xmin, self.xmin)
66+
self.xmax = max(composite.xmax, self.xmax)
67+
if len(self.individual_files) == 0:
68+
self.sense = [0] * (composite.xmax - composite.xmin + 1)
69+
self.anti = [0] * (composite.xmax - composite.xmin + 1)
70+
else:
71+
xmin = min([c.xmin for c in self.individual_files])
72+
xmax = max([c.xmax for c in self.individual_files])
73+
prefix = [0] * (xmin - self.xmin)
74+
suffix = [0] * (self.xmax - xmax)
75+
self.sense = prefix + self.sense + suffix
76+
self.anti = prefix + self.anti + suffix
77+
# Update sense and anti arrays
78+
j = composite.xmin - self.xmin
79+
while j <= composite.xmax - composite.xmin:
80+
idx = composite.xmin - self.xmin + j
81+
self.sense[idx] += composite.sense[j]
82+
self.anti[idx] += composite.anti[j]
83+
j += 1
84+
self.individual_files[composite.id] = composite
85+
86+
def __str__(self):
87+
return str(self.individual_files)

python/out.svg

Lines changed: 123 additions & 0 deletions
Loading

python/parseComposite.py

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
import csv
2+
import xml.dom.minidom as dom
3+
import argparse
4+
import math
5+
import composite
6+
import os
7+
8+
# Returns a simple composite from a single file
9+
def parse_simple(file):
10+
fileArr = open(file, "r").read().split("\n")
11+
xmin = None
12+
xmax = None
13+
sense = []
14+
anti = []
15+
xmin_curr = 0
16+
xmax_curr = 0
17+
offset = 0
18+
for line in fileArr:
19+
# Skip empty
20+
if len(line.strip()) == 0 :
21+
continue
22+
# Separate fields
23+
fields = line.split("\t")
24+
if not fields[0].strip() or fields[0] == "NAME":
25+
xmin_curr = int(float(fields[1]))
26+
xmax_curr = int(float(fields[-1]))
27+
# If the x domain starts at 0 shift it to the left
28+
if xmin_curr == 0:
29+
xmin_curr -= math.floor(xmax_curr / 2)
30+
xmax_curr -= math.floor(xmax_curr / 2)
31+
# If the x domain is not defined yet, define it
32+
if xmin == None or xmax == None:
33+
xmin = xmin_curr
34+
xmax = xmax_curr
35+
# Redefine min and max if necessary
36+
xmax = max(xmax_curr, xmax)
37+
xmin = min(xmin_curr, xmin)
38+
sense = [0] * (xmax - xmin + 1)
39+
anti = [0] * (xmax - xmin + 1)
40+
# Add the values to sense and anti arrays
41+
if "sense" in fields[0].lower():
42+
i = 1
43+
while i < len(fields):
44+
sense[offset + i - 1] += float(fields[i])
45+
i += 1
46+
elif "anti" in fields[0].lower():
47+
i = 1
48+
while i < len(fields):
49+
anti[offset + i - 1] += float(fields[i])
50+
i += 1
51+
# If the first field is not empty or "NAME" and does not contain "sense" or "anti" parse as combined or midpoint data
52+
elif not (fields[0] == "" or fields[0] == "NAME"):
53+
i = 1
54+
while i < len(fields):
55+
sense[offset + i - 1] += float(fields[i]) / 2
56+
anti[offset + i - 1] += float(fields[i]) / 2
57+
return composite.SimpleComposite(xmin, xmax, sense, anti, os.path.basename(file).split('_')[0])
58+
59+
# Returns list of prefixes from multi-composite file, mimics the plotter method
60+
def get_prefixes_from_multiple_composites(file):
61+
lines = open(file, "r").read().split("\n")
62+
names_list = []
63+
i = 0
64+
while i < len(lines):
65+
line = lines[i]
66+
# Skip empty
67+
if line.strip() == "":
68+
i += 1
69+
continue
70+
# Get the first field
71+
col0 = line.split("\t")[0]
72+
if col0 == "" or col0[0] == "NAME":
73+
# Get the names of the composites for lines immediately following the xdomain
74+
i += 1
75+
names_list.append(lines[i].split("\t")[0])
76+
i += 1
77+
# Take the first name and split it by "_"
78+
split_name = names_list[0].split("_")
79+
idx = None
80+
# Iterate over each possible prefix-suffix split
81+
for i in range(1, len(split_name) - 1):
82+
prefix = "_".join(split_name[:i])
83+
suffix = "_".join(split_name[i:])
84+
n_prefix = sum(1 for n in names_list if n.startswith(prefix))
85+
n_suffix = sum(1 for n in names_list if n.endswith(suffix))
86+
if n_prefix * n_suffix == len(names_list):
87+
if n_suffix == len(names_list):
88+
idx = i if idx is None else idx
89+
break
90+
idx = i
91+
suffix = "_".join(split_name[idx:])
92+
# Get the prefixes by removing the suffix from the names
93+
return [n[:-len(suffix)] for n in names_list if n.endswith(suffix)]
94+
95+
# Returns dictionary with composite from multi-composite file, mimics the plotter method
96+
def parse_multiple_composite(file, prefix):
97+
lines = open(file, "r").read().split("\n")
98+
composites = {}
99+
xmin = None
100+
xmax = None
101+
sense = []
102+
anti = []
103+
i = 0
104+
id = 0
105+
save_comp = False
106+
while i < len(lines):
107+
line = lines[i]
108+
# Skip empty
109+
if line.strip() == "":
110+
i += 1
111+
continue
112+
# Get the first field
113+
fields = line.split("\t")
114+
col0 = fields[0]
115+
if not col0.strip() or col0 == "NAME":
116+
# If the x domain is defined, save the composite
117+
if save_comp:
118+
composites[id] = composite.SimpleComposite(xmin, xmax, sense, anti, id)
119+
save_comp = False
120+
# Get the nex x domain
121+
fields = [field for field in fields if field.strip()]
122+
xmin = int(float(fields[0]))
123+
xmax = int(float(fields[-1]))
124+
# If the x domain starts at 0 shift it to the left
125+
if xmin == 0:
126+
xmin -= math.floor(xmax / 2)
127+
xmin -= math.floor(xmax / 2)
128+
elif col0.startswith(prefix):
129+
id = col0[len(prefix):].split("_")[0]
130+
save_comp = True
131+
# Add the values to sense and anti arrays
132+
fields = [field for field in fields if field.strip()]
133+
if "sense" in fields[0].lower():
134+
sense = [float(val) for val in fields[1:]]
135+
elif "anti" in fields[0].lower():
136+
anti = [float(val) for val in fields[1:]]
137+
else:
138+
sense = [float(val) / 2 for val in fields[1:]]
139+
anti = [float(val) / 2 for val in fields[1:]]
140+
i += 1
141+
# Save the last composite
142+
if save_comp:
143+
composites[id] = composite.SimpleComposite(xmin, xmax, sense, anti, id)
144+
return composites

0 commit comments

Comments
 (0)