comparison jbrowse2.py @ 19:bde6b1d09f7d draft

planemo upload for repository https://github.com/usegalaxy-eu/temporary-tools/tree/master/jbrowse2 commit 1290bf486bc55c02fecd0327de10a28655a18e81-dirty
author fubar
date Tue, 30 Jan 2024 06:05:03 +0000
parents 4c201a3d4755
children 39b717d934a8
comparison
equal deleted inserted replaced
18:2e6c48910819 19:bde6b1d09f7d
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # change to accumulating all configuration for config.json based on the default from the clone 2 # change to accumulating all configuration for config.json based on the default from the clone
3 import argparse 3 import argparse
4 import binascii 4 import binascii
5 import datetime 5 import datetime
6 import hashlib
7 import json 6 import json
8 import logging 7 import logging
9 import os 8 import os
10 import re 9 import re
11 import shutil 10 import shutil
21 JB2VER = "v2.10.1" 20 JB2VER = "v2.10.1"
22 # version pinned for cloning 21 # version pinned for cloning
23 22
24 TODAY = datetime.datetime.now().strftime("%Y-%m-%d") 23 TODAY = datetime.datetime.now().strftime("%Y-%m-%d")
25 GALAXY_INFRASTRUCTURE_URL = None 24 GALAXY_INFRASTRUCTURE_URL = None
26 JB2REL = "v2.10.0" 25 JB2REL = "v2.10.1"
27 # version pinned for cloning 26 # version pinned for cloning
28 27
29 mapped_chars = { 28 mapped_chars = {
30 ">": "__gt__", 29 ">": "__gt__",
31 "<": "__lt__", 30 "<": "__lt__",
230 bc_pivot = float(bc_pivot) 229 bc_pivot = float(bc_pivot)
231 trackConfig["bicolor_pivot"] = bc_pivot 230 trackConfig["bicolor_pivot"] = bc_pivot
232 elif "scaling" in track: 231 elif "scaling" in track:
233 if track["scaling"]["method"] == "ignore": 232 if track["scaling"]["method"] == "ignore":
234 if track["scaling"]["scheme"]["color"] != "__auto__": 233 if track["scaling"]["scheme"]["color"] != "__auto__":
235 trackConfig["style"]["color"] = track["scaling"]["scheme"]["color"] 234 trackConfig["style"]["color"] = track["scaling"]["scheme"][
235 "color"
236 ]
236 else: 237 else:
237 trackConfig["style"]["color"] = self.hex_from_rgb( 238 trackConfig["style"]["color"] = self.hex_from_rgb(
238 *self._get_colours() 239 *self._get_colours()
239 ) 240 )
240 else: 241 else:
257 "red": red, 258 "red": red,
258 "green": green, 259 "green": green,
259 "blue": blue, 260 "blue": blue,
260 } 261 }
261 ) 262 )
262 trackConfig["style"]["color"] = color_function.replace("\n", "") 263 trackConfig["style"]["color"] = color_function.replace(
264 "\n", ""
265 )
263 elif trackFormat == "gene_calls": 266 elif trackFormat == "gene_calls":
264 # Default values, based on GFF3 spec 267 # Default values, based on GFF3 spec
265 min_val = 0 268 min_val = 0
266 max_val = 1000 269 max_val = 1000
267 # Get min/max and build a scoring function since JBrowse doesn't 270 # Get min/max and build a scoring function since JBrowse doesn't
268 if scales["type"] == "automatic" or scales["type"] == "__auto__": 271 if (
272 scales["type"] == "automatic"
273 or scales["type"] == "__auto__"
274 ):
269 min_val, max_val = self.min_max_gff(gff3) 275 min_val, max_val = self.min_max_gff(gff3)
270 else: 276 else:
271 min_val = scales.get("min", 0) 277 min_val = scales.get("min", 0)
272 max_val = scales.get("max", 1000) 278 max_val = scales.get("max", 1000)
273 279
274 if scheme["color"] == "__auto__": 280 if scheme["color"] == "__auto__":
275 user_color = "undefined" 281 user_color = "undefined"
276 auto_color = "'%s'" % self.hex_from_rgb(*self._get_colours()) 282 auto_color = "'%s'" % self.hex_from_rgb(
283 *self._get_colours()
284 )
277 elif scheme["color"].startswith("#"): 285 elif scheme["color"].startswith("#"):
278 user_color = "'%s'" % self.hex_from_rgb( 286 user_color = "'%s'" % self.hex_from_rgb(
279 *self.rgb_from_hex(scheme["color"][1:]) 287 *self.rgb_from_hex(scheme["color"][1:])
280 ) 288 )
281 auto_color = "undefined" 289 auto_color = "undefined"
282 else: 290 else:
283 user_color = "undefined" 291 user_color = "undefined"
284 auto_color = "'%s'" % self.hex_from_rgb(*self._get_colours()) 292 auto_color = "'%s'" % self.hex_from_rgb(
293 *self._get_colours()
294 )
285 295
286 color_function = self.COLOR_FUNCTION_TEMPLATE_QUAL.format( 296 color_function = self.COLOR_FUNCTION_TEMPLATE_QUAL.format(
287 **{ 297 **{
288 "opacity": self.OPACITY_MATH[algo].format( 298 "opacity": self.OPACITY_MATH[algo].format(
289 **{"max": max_val, "min": min_val} 299 **{"max": max_val, "min": min_val}
291 "user_spec_color": user_color, 301 "user_spec_color": user_color,
292 "auto_gen_color": auto_color, 302 "auto_gen_color": auto_color,
293 } 303 }
294 ) 304 )
295 305
296 trackConfig["style"]["color"] = color_function.replace("\n", "") 306 trackConfig["style"]["color"] = color_function.replace(
307 "\n", ""
308 )
297 return trackConfig 309 return trackConfig
298 310
299 311
300 def etree_to_dict(t): 312 def etree_to_dict(t):
301 if t is None: 313 if t is None:
334 return {} 346 return {}
335 347
336 for (key, value) in node.findall("dataset")[0].attrib.items(): 348 for (key, value) in node.findall("dataset")[0].attrib.items():
337 metadata["dataset_%s" % key] = value 349 metadata["dataset_%s" % key] = value
338 350
339 for (key, value) in node.findall("history")[0].attrib.items(): 351 if node.findall("history"):
340 metadata["history_%s" % key] = value 352 for (key, value) in node.findall("history")[0].attrib.items():
341 353 metadata["history_%s" % key] = value
342 for (key, value) in node.findall("metadata")[0].attrib.items(): 354
343 metadata["metadata_%s" % key] = value 355 if node.findall("metadata"):
344 356 for (key, value) in node.findall("metadata")[0].attrib.items():
345 for (key, value) in node.findall("tool")[0].attrib.items(): 357 metadata["metadata_%s" % key] = value
346 metadata["tool_%s" % key] = value 358 # Additional Mappings applied:
347 359 metadata[
348 # Additional Mappings applied: 360 "dataset_edam_format"
349 metadata[ 361 ] = '<a target="_blank" href="http://edamontology.org/{0}">{1}</a>'.format(
350 "dataset_edam_format" 362 metadata["dataset_edam_format"], metadata["dataset_file_ext"]
351 ] = '<a target="_blank" href="http://edamontology.org/{0}">{1}</a>'.format( 363 )
352 metadata["dataset_edam_format"], metadata["dataset_file_ext"] 364 metadata["history_user_email"] = '<a href="mailto:{0}">{0}</a>'.format(
353 ) 365 metadata["history_user_email"]
354 metadata["history_user_email"] = '<a href="mailto:{0}">{0}</a>'.format( 366 )
355 metadata["history_user_email"] 367 metadata["hist_name"] = metadata["history_display_name"]
356 ) 368 metadata[
357 metadata["hist_name"] = metadata["history_display_name"] 369 "history_display_name"
358 metadata[ 370 ] = '<a target="_blank" href="{galaxy}/history/view/{encoded_hist_id}">{hist_name}</a>'.format(
359 "history_display_name" 371 galaxy=GALAXY_INFRASTRUCTURE_URL,
360 ] = '<a target="_blank" href="{galaxy}/history/view/{encoded_hist_id}">{hist_name}</a>'.format( 372 encoded_hist_id=metadata["history_id"],
361 galaxy=GALAXY_INFRASTRUCTURE_URL, 373 hist_name=metadata["history_display_name"],
362 encoded_hist_id=metadata["history_id"], 374 )
363 hist_name=metadata["history_display_name"], 375 if node.findall("tool"):
364 ) 376 for (key, value) in node.findall("tool")[0].attrib.items():
365 metadata[ 377 metadata["tool_%s" % key] = value
366 "tool_tool" 378 metadata[
367 ] = '<a target="_blank" href="{galaxy}/datasets/{encoded_id}/show_params">{tool_id}</a>'.format( 379 "tool_tool"
368 galaxy=GALAXY_INFRASTRUCTURE_URL, 380 ] = '<a target="_blank" href="{galaxy}/datasets/{encoded_id}/show_params">{tool_id}{tool_version}</a>'.format(
369 encoded_id=metadata["dataset_id"], 381 galaxy=GALAXY_INFRASTRUCTURE_URL,
370 tool_id=metadata["tool_tool_id"], 382 encoded_id=metadata.get("dataset_id", ""),
371 # tool_version=metadata['tool_tool_version'], 383 tool_id=metadata.get("tool_tool_id", ""),
372 ) 384 tool_version=metadata.get("tool_tool_version",""),
385 )
373 return metadata 386 return metadata
374 387
375 388
376 class JbrowseConnector(object): 389 class JbrowseConnector(object):
377 def __init__(self, outdir, genomes): 390 def __init__(self, outdir, genomes):
387 self.config_json_file = os.path.join(outdir, "config.json") 400 self.config_json_file = os.path.join(outdir, "config.json")
388 self.clone_jbrowse() 401 self.clone_jbrowse()
389 402
390 def subprocess_check_call(self, command, output=None): 403 def subprocess_check_call(self, command, output=None):
391 if output: 404 if output:
392 log.debug("cd %s && %s > %s", self.outdir, " ".join(command), output) 405 log.debug(
406 "cd %s && %s > %s", self.outdir, " ".join(command), output
407 )
393 subprocess.check_call(command, cwd=self.outdir, stdout=output) 408 subprocess.check_call(command, cwd=self.outdir, stdout=output)
394 else: 409 else:
395 log.debug("cd %s && %s", self.outdir, " ".join(command)) 410 log.debug("cd %s && %s", self.outdir, " ".join(command))
396 subprocess.check_call(command, cwd=self.outdir) 411 subprocess.check_call(command, cwd=self.outdir)
397 412
466 self.config_json["assemblies"] += assemblies 481 self.config_json["assemblies"] += assemblies
467 else: 482 else:
468 self.config_json["assemblies"] = assemblies 483 self.config_json["assemblies"] = assemblies
469 484
470 def make_assembly(self, fapath, gname): 485 def make_assembly(self, fapath, gname):
471 hashData = [ 486
472 fapath, 487 faname = gname + ".fa.gz"
473 gname,
474 ]
475 hashData = "|".join(hashData).encode("utf-8")
476 ghash = hashlib.md5(hashData).hexdigest()
477 faname = ghash + ".fa.gz"
478 fadest = os.path.join(self.outdir, faname) 488 fadest = os.path.join(self.outdir, faname)
479 cmd = "bgzip -i -c %s -I %s.gzi > %s && samtools faidx %s" % ( 489 cmd = "bgzip -i -c %s -I %s.gzi > %s && samtools faidx %s" % (
480 fapath, 490 fapath,
481 fadest, 491 fadest,
482 fadest, 492 fadest,
493 }, 503 },
494 "gziLocation": { 504 "gziLocation": {
495 "uri": faname + ".gzi", 505 "uri": faname + ".gzi",
496 }, 506 },
497 } 507 }
508 self.genome_sequence_adapter = adapter
498 trackDict = { 509 trackDict = {
499 "name": gname, 510 "name": gname,
500 "sequence": { 511 "sequence": {
501 "type": "ReferenceSequenceTrack", 512 "type": "ReferenceSequenceTrack",
502 "trackId": gname, 513 "trackId": gname,
602 """ 613 """
603 mafPlugin = { 614 mafPlugin = {
604 "plugins": [ 615 "plugins": [
605 { 616 {
606 "name": "MafViewer", 617 "name": "MafViewer",
607 "url": "https://unpkg.com/browse/jbrowse-plugin-mafviewer@1.0.6/dist/jbrowse-plugin-mafviewer.umd.production.min.js", 618 "url": "https://unpkg.com/jbrowse-plugin-mafviewer/dist/jbrowse-plugin-mafviewer.umd.production.min.js"
608 } 619 }
609 ] 620 ]
610 } 621 }
611 tId = trackData["label"] 622 tId = trackData["label"]
612 fname = "%s.bed" % tId 623 fname = "%s.bed" % tId
621 dest, 632 dest,
622 ] 633 ]
623 self.subprocess_check_call(cmd) 634 self.subprocess_check_call(cmd)
624 # Construct samples list 635 # Construct samples list
625 # We could get this from galaxy metadata, not sure how easily. 636 # We could get this from galaxy metadata, not sure how easily.
626 ps = subprocess.Popen(["grep", "^s [^ ]*", "-o", data], stdout=subprocess.PIPE) 637 ps = subprocess.Popen(
638 ["grep", "^s [^ ]*", "-o", data], stdout=subprocess.PIPE
639 )
627 output = subprocess.check_output(("sort", "-u"), stdin=ps.stdout) 640 output = subprocess.check_output(("sort", "-u"), stdin=ps.stdout)
628 ps.wait() 641 ps.wait()
629 outp = output.decode("ascii") 642 outp = output.decode("ascii")
630 soutp = outp.split("\n") 643 soutp = outp.split("\n")
631 samp = [x.split("s ")[1] for x in soutp if x.startswith("s ")] 644 samp = [x.split("s ")[1] for x in soutp if x.startswith("s ")]
781 fname = "%s.bam" % trackData["label"] 794 fname = "%s.bam" % trackData["label"]
782 dest = "%s/%s" % (self.outdir, fname) 795 dest = "%s/%s" % (self.outdir, fname)
783 url = fname 796 url = fname
784 self.subprocess_check_call(["cp", data, dest]) 797 self.subprocess_check_call(["cp", data, dest])
785 bloc = {"uri": url} 798 bloc = {"uri": url}
786 if bam_index is not None and os.path.exists(os.path.realpath(bam_index)): 799 if bam_index is not None and os.path.exists(
800 os.path.realpath(bam_index)
801 ):
787 # bai most probably made by galaxy and stored in galaxy dirs, need to copy it to dest 802 # bai most probably made by galaxy and stored in galaxy dirs, need to copy it to dest
788 self.subprocess_check_call( 803 self.subprocess_check_call(
789 ["cp", os.path.realpath(bam_index), dest + ".bai"] 804 ["cp", os.path.realpath(bam_index), dest + ".bai"]
790 ) 805 )
791 else: 806 else:
792 # Can happen in exotic condition 807 # Can happen in exotic condition
793 # e.g. if bam imported as symlink with datatype=unsorted.bam, then datatype changed to bam 808 # e.g. if bam imported as symlink with datatype=unsorted.bam, then datatype changed to bam
794 # => no index generated by galaxy, but there might be one next to the symlink target 809 # => no index generated by galaxy, but there might be one next to the symlink target
795 # this trick allows to skip the bam sorting made by galaxy if already done outside 810 # this trick allows to skip the bam sorting made by galaxy if already done outside
796 if os.path.exists(os.path.realpath(data) + ".bai"): 811 if os.path.exists(os.path.realpath(data) + ".bai"):
797 self.symlink_or_copy(os.path.realpath(data) + ".bai", dest + ".bai") 812 self.symlink_or_copy(
813 os.path.realpath(data) + ".bai", dest + ".bai"
814 )
798 else: 815 else:
799 log.warn("Could not find a bam index (.bai file) for %s", data) 816 log.warn("Could not find a bam index (.bai file) for %s", data)
800 trackDict = { 817 trackDict = {
801 "type": "AlignmentsTrack", 818 "type": "AlignmentsTrack",
802 "trackId": tId, 819 "trackId": tId,
821 style_json = self._prepare_track_style(trackDict) 838 style_json = self._prepare_track_style(trackDict)
822 trackDict["style"] = style_json 839 trackDict["style"] = style_json
823 self.tracksToAdd.append(trackDict) 840 self.tracksToAdd.append(trackDict)
824 self.trackIdlist.append(tId) 841 self.trackIdlist.append(tId)
825 842
843 def add_cram(self, data, trackData, cramOpts, cram_index=None, **kwargs):
844 tId = trackData["label"]
845 fname = "%s.cram" % trackData["label"]
846 dest = "%s/%s" % (self.outdir, fname)
847 url = fname
848 self.subprocess_check_call(["cp", data, dest])
849 bloc = {"uri": url}
850 if cram_index is not None and os.path.exists(
851 os.path.realpath(cram_index)
852 ):
853 # most probably made by galaxy and stored in galaxy dirs, need to copy it to dest
854 self.subprocess_check_call(
855 ["cp", os.path.realpath(cram_index), dest + ".crai"]
856 )
857 else:
858 # Can happen in exotic condition
859 # e.g. if bam imported as symlink with datatype=unsorted.bam, then datatype changed to bam
860 # => no index generated by galaxy, but there might be one next to the symlink target
861 # this trick allows to skip the bam sorting made by galaxy if already done outside
862 if os.path.exists(os.path.realpath(data) + ".crai"):
863 self.symlink_or_copy(
864 os.path.realpath(data) + ".crai", dest + ".crai"
865 )
866 else:
867 log.warn(
868 "Could not find a cram index (.crai file) for %s", data
869 )
870 trackDict = {
871 "type": "AlignmentsTrack",
872 "trackId": tId,
873 "name": trackData["name"],
874 "assemblyNames": [self.genome_name],
875 "adapter": {
876 "type": "CramAdapter",
877 "cramLocation": bloc,
878 "craiLocation": {"uri": fname + ".crai",},
879 "sequenceAdapter": self.genome_sequence_adapter,
880 },
881 "displays": [
882 {
883 "type": "LinearAlignmentsDisplay",
884 "displayId": "%s-LinearAlignmentsDisplay" % tId,
885 },
886 ],
887 }
888 style_json = self._prepare_track_style(trackDict)
889 trackDict["style"] = style_json
890 self.tracksToAdd.append(trackDict)
891 self.trackIdlist.append(tId)
892
826 def add_vcf(self, data, trackData): 893 def add_vcf(self, data, trackData):
827 tId = trackData["label"] 894 tId = trackData["label"]
828 url = "%s/api/datasets/%s/display" % ( 895 # url = "%s/api/datasets/%s/display" % (
829 self.giURL, 896 # self.giURL,
830 trackData["metadata"]["dataset_id"], 897 # trackData["metadata"]["dataset_id"],
831 ) 898 # )
832 url = "%s.vcf.gz" % tId 899 url = "%s.vcf.gz" % tId
833 dest = "%s/%s" % (self.outdir, url) 900 dest = "%s/%s" % (self.outdir, url)
834 cmd = "bgzip -c %s > %s" % (data, dest) 901 cmd = "bgzip -c %s > %s" % (data, dest)
835 self.subprocess_popen(cmd) 902 self.subprocess_popen(cmd)
836 cmd = ["tabix", "-f", "-p", "vcf", dest] 903 cmd = ["tabix", "-f", "-p", "vcf", dest]
877 cmd = "jbrowse sort-gff %s | bgzip -c > %s.gz" % ( 944 cmd = "jbrowse sort-gff %s | bgzip -c > %s.gz" % (
878 data, 945 data,
879 dest, 946 dest,
880 ) # "gff3sort.pl --precise '%s' | grep -v \"^$\" > '%s'" 947 ) # "gff3sort.pl --precise '%s' | grep -v \"^$\" > '%s'"
881 self.subprocess_popen(cmd) 948 self.subprocess_popen(cmd)
882 self.subprocess_check_call(["tabix", "-f", "-p", "gff", dest + ".gz"]) 949 self.subprocess_check_call(
950 ["tabix", "-f", "-p", "gff", dest + ".gz"]
951 )
883 952
884 def _sort_bed(self, data, dest): 953 def _sort_bed(self, data, dest):
885 # Only index if not already done 954 # Only index if not already done
886 if not os.path.exists(dest): 955 if not os.path.exists(dest):
887 cmd = "sort -k1,1 -k2,2n %s | bgzip -c > %s" % (data, dest) 956 cmd = "sort -k1,1 -k2,2n %s | bgzip -c > %s" % (data, dest)
1083 "style": {}, 1152 "style": {},
1084 } 1153 }
1085 1154
1086 outputTrackConfig["key"] = track_human_label 1155 outputTrackConfig["key"] = track_human_label
1087 1156
1088 # We add extra data to hash for the case of REST + SPARQL.
1089 if (
1090 "conf" in track
1091 and "options" in track["conf"]
1092 and "url" in track["conf"]["options"]
1093 ):
1094 rest_url = track["conf"]["options"]["url"]
1095 else:
1096 rest_url = ""
1097 outputTrackConfig["trackset"] = track.get("trackset", {}) 1157 outputTrackConfig["trackset"] = track.get("trackset", {})
1098 # I chose to use track['category'] instead of 'category' here. This 1158 outputTrackConfig["label"] = "%s_%i_%s" % (
1099 # is intentional. This way re-running the tool on a different date 1159 dataset_ext,
1100 # will not generate different hashes and make comparison of outputs 1160 i,
1101 # much simpler.
1102 hashData = [
1103 str(dataset_path),
1104 track_human_label, 1161 track_human_label,
1105 track["category"], 1162 )
1106 rest_url,
1107 ]
1108 hashData = "|".join(hashData).encode("utf-8")
1109 outputTrackConfig["label"] = hashlib.md5(hashData).hexdigest() + "_%s" % i
1110 outputTrackConfig["metadata"] = extra_metadata 1163 outputTrackConfig["metadata"] = extra_metadata
1111 outputTrackConfig["name"] = track_human_label 1164 outputTrackConfig["name"] = track_human_label
1112 1165
1113 if dataset_ext in ("gff", "gff3"): 1166 if dataset_ext in ("gff", "gff3"):
1114 self.add_gff( 1167 self.add_gff(
1136 self.add_bigwig( 1189 self.add_bigwig(
1137 dataset_path, 1190 dataset_path,
1138 outputTrackConfig, 1191 outputTrackConfig,
1139 ) 1192 )
1140 elif dataset_ext == "bam": 1193 elif dataset_ext == "bam":
1141 real_indexes = track["conf"]["options"]["pileup"]["bam_indices"][ 1194 real_indexes = track["conf"]["options"]["pileup"][
1142 "bam_index" 1195 "bam_indices"
1143 ] 1196 ]["bam_index"]
1144 if not isinstance(real_indexes, list): 1197 if not isinstance(real_indexes, list):
1145 # <bam_indices>
1146 # <bam_index>/path/to/a.bam.bai</bam_index>
1147 # </bam_indices>
1148 #
1149 # The above will result in the 'bam_index' key containing a
1150 # string. If there are two or more indices, the container
1151 # becomes a list. Fun!
1152 real_indexes = [real_indexes] 1198 real_indexes = [real_indexes]
1153 1199
1154 self.add_bam( 1200 self.add_bam(
1155 dataset_path, 1201 dataset_path,
1156 outputTrackConfig, 1202 outputTrackConfig,
1157 track["conf"]["options"]["pileup"], 1203 track["conf"]["options"]["pileup"],
1158 bam_index=real_indexes[i], 1204 bam_index=real_indexes[i],
1205 )
1206 elif dataset_ext == "cram":
1207 real_indexes = track["conf"]["options"]["cram"][
1208 "cram_indices"
1209 ]["cram_index"]
1210 if not isinstance(real_indexes, list):
1211 real_indexes = [real_indexes]
1212
1213 self.add_cram(
1214 dataset_path,
1215 outputTrackConfig,
1216 track["conf"]["options"]["cram"],
1217 cram_index=real_indexes[i],
1159 ) 1218 )
1160 elif dataset_ext == "blastxml": 1219 elif dataset_ext == "blastxml":
1161 self.add_blastxml( 1220 self.add_blastxml(
1162 dataset_path, 1221 dataset_path,
1163 outputTrackConfig, 1222 outputTrackConfig,
1288 config_json = {} 1347 config_json = {}
1289 if self.config_json: 1348 if self.config_json:
1290 config_json.update(self.config_json) 1349 config_json.update(self.config_json)
1291 config_data = {} 1350 config_data = {}
1292 1351
1293 config_data["disableAnalytics"] = data.get("analytics", "false") == "true" 1352 config_data["disableAnalytics"] = (
1353 data.get("analytics", "false") == "true"
1354 )
1294 1355
1295 config_data["theme"] = { 1356 config_data["theme"] = {
1296 "palette": { 1357 "palette": {
1297 "primary": {"main": data.get("primary_color", "#0D233F")}, 1358 "primary": {"main": data.get("primary_color", "#0D233F")},
1298 "secondary": {"main": data.get("secondary_color", "#721E63")}, 1359 "secondary": {"main": data.get("secondary_color", "#721E63")},
1299 "tertiary": {"main": data.get("tertiary_color", "#135560")}, 1360 "tertiary": {"main": data.get("tertiary_color", "#135560")},
1300 "quaternary": {"main": data.get("quaternary_color", "#FFB11D")}, 1361 "quaternary": {
1362 "main": data.get("quaternary_color", "#FFB11D")
1363 },
1301 }, 1364 },
1302 "typography": {"fontSize": int(data.get("font_size", 10))}, 1365 "typography": {"fontSize": int(data.get("font_size", 10))},
1303 } 1366 }
1304 if not config_json.get("configuration", None): 1367 if not config_json.get("configuration", None):
1305 config_json["configuration"] = {} 1368 config_json["configuration"] = {}
1349 1412
1350 if __name__ == "__main__": 1413 if __name__ == "__main__":
1351 parser = argparse.ArgumentParser(description="", epilog="") 1414 parser = argparse.ArgumentParser(description="", epilog="")
1352 parser.add_argument("--xml", help="Track Configuration") 1415 parser.add_argument("--xml", help="Track Configuration")
1353 parser.add_argument("--outdir", help="Output directory", default="out") 1416 parser.add_argument("--outdir", help="Output directory", default="out")
1354 parser.add_argument("--version", "-V", action="version", version="%(prog)s 2.0.1") 1417 parser.add_argument(
1418 "--version", "-V", action="version", version="%(prog)s 2.0.1"
1419 )
1355 args = parser.parse_args() 1420 args = parser.parse_args()
1356
1357 tree = ET.parse(args.xml) 1421 tree = ET.parse(args.xml)
1358 root = tree.getroot() 1422 root = tree.getroot()
1359 1423
1360 # This should be done ASAP 1424 # This should be done ASAP
1361 GALAXY_INFRASTRUCTURE_URL = root.find("metadata/galaxyUrl").text 1425 GALAXY_INFRASTRUCTURE_URL = root.find("metadata/galaxyUrl").text
1446 ) 1510 )
1447 track_conf["category"] = track.attrib["cat"] 1511 track_conf["category"] = track.attrib["cat"]
1448 track_conf["format"] = track.attrib["format"] 1512 track_conf["format"] = track.attrib["format"]
1449 if track.find("options/style"): 1513 if track.find("options/style"):
1450 track_conf["style"] = { 1514 track_conf["style"] = {
1451 item.tag: parse_style_conf(item) for item in track.find("options/style") 1515 item.tag: parse_style_conf(item)
1516 for item in track.find("options/style")
1452 } 1517 }
1453 if track.find("options/style_labels"): 1518 if track.find("options/style_labels"):
1454 track_conf["style_labels"] = { 1519 track_conf["style_labels"] = {
1455 item.tag: parse_style_conf(item) 1520 item.tag: parse_style_conf(item)
1456 for item in track.find("options/style_labels") 1521 for item in track.find("options/style_labels")
1459 track_conf["conf"] = etree_to_dict(track.find("options")) 1524 track_conf["conf"] = etree_to_dict(track.find("options"))
1460 track_conf["category"] = track.attrib["cat"] 1525 track_conf["category"] = track.attrib["cat"]
1461 track_conf["format"] = track.attrib["format"] 1526 track_conf["format"] = track.attrib["format"]
1462 try: 1527 try:
1463 # Only pertains to gff3 + blastxml. TODO? 1528 # Only pertains to gff3 + blastxml. TODO?
1464 track_conf["style"] = {t.tag: t.text for t in track.find("options/style")} 1529 track_conf["style"] = {
1530 t.tag: t.text for t in track.find("options/style")
1531 }
1465 except TypeError: 1532 except TypeError:
1466 track_conf["style"] = {} 1533 track_conf["style"] = {}
1467 pass 1534 pass
1468 track_conf["conf"] = etree_to_dict(track.find("options")) 1535 track_conf["conf"] = etree_to_dict(track.find("options"))
1469 keys = jc.process_annotations(track_conf) 1536 keys = jc.process_annotations(track_conf)
1490 general_data = { 1557 general_data = {
1491 "analytics": root.find("metadata/general/analytics").text, 1558 "analytics": root.find("metadata/general/analytics").text,
1492 "primary_color": root.find("metadata/general/primary_color").text, 1559 "primary_color": root.find("metadata/general/primary_color").text,
1493 "secondary_color": root.find("metadata/general/secondary_color").text, 1560 "secondary_color": root.find("metadata/general/secondary_color").text,
1494 "tertiary_color": root.find("metadata/general/tertiary_color").text, 1561 "tertiary_color": root.find("metadata/general/tertiary_color").text,
1495 "quaternary_color": root.find("metadata/general/quaternary_color").text, 1562 "quaternary_color": root.find(
1563 "metadata/general/quaternary_color"
1564 ).text,
1496 "font_size": root.find("metadata/general/font_size").text, 1565 "font_size": root.find("metadata/general/font_size").text,
1497 } 1566 }
1498 jc.add_general_configuration(general_data) 1567 jc.add_general_configuration(general_data)
1499 trackconf = jc.config_json.get("tracks", None) 1568 trackconf = jc.config_json.get("tracks", None)
1500 if trackconf: 1569 if trackconf: