comparison jbrowse2.py @ 57:94264fe60478 draft

planemo upload for repository https://github.com/usegalaxy-eu/temporary-tools/tree/master/jbrowse2 commit 4b5df41484f6bdf316edaf95b53c92d328ec1674-dirty
author fubar
date Thu, 21 Mar 2024 08:01:42 +0000
parents c0097a584a8a
children f807e219cec3
comparison
equal deleted inserted replaced
56:c0097a584a8a 57:94264fe60478
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 json 6 import json
8 import os 8 import os
9 import re 9 import re
10 import shutil 10 import shutil
11 import struct 11 import struct
12 import subprocess 12 import subprocess
13 import sys
14 import tempfile 13 import tempfile
15 import urllib.request 14 import urllib.request
16 import xml.etree.ElementTree as ET 15 import xml.etree.ElementTree as ET
17 from collections import defaultdict 16 from collections import defaultdict
18 17
478 if len(fl.split()) > 1: 477 if len(fl.split()) > 1:
479 self.genome_firstcontig = fl.split()[0].strip() 478 self.genome_firstcontig = fl.split()[0].strip()
480 else: 479 else:
481 self.genome_firstcontig = fl 480 self.genome_firstcontig = fl
482 else: 481 else:
483 fl = urllib.request.urlopen(fapath+".fai").readline() 482 fl = urllib.request.urlopen(fapath + ".fai").readline()
484 if fl: # is first row of the text fai so the first contig name 483 if fl: # is first row of the text fai so the first contig name
485 self.genome_firstcontig = fl.decode('utf8').strip().split()[0] 484 self.genome_firstcontig = (
485 fl.decode("utf8").strip().split()[0]
486 )
486 if self.config_json.get("assemblies", None): 487 if self.config_json.get("assemblies", None):
487 self.config_json["assemblies"] += assemblies 488 self.config_json["assemblies"] += assemblies
488 else: 489 else:
489 self.config_json["assemblies"] = assemblies 490 self.config_json["assemblies"] = assemblies
490 491
536 "type": "ReferenceSequenceTrack", 537 "type": "ReferenceSequenceTrack",
537 "trackId": gname, 538 "trackId": gname,
538 "adapter": adapter, 539 "adapter": adapter,
539 }, 540 },
540 "rendering": {"type": "DivSequenceRenderer"}, 541 "rendering": {"type": "DivSequenceRenderer"},
542 "displays": [
543 {
544 "type": "LinearReferenceSequenceDisplay",
545 "displayId": "%s-LinearReferenceSequenceDisplay" % gname,
546 },
547 {
548 "type": "LinearGCContentDisplay",
549 "displayId": "%s-LinearGCContentDisplay" % gname,
550 },
551 ],
541 } 552 }
542 return trackDict 553 return trackDict
543 554
544 def add_default_view(self): 555 def add_default_view(self):
545 cmd = [ 556 cmd = [
602 useuri = trackData["useuri"].lower() == "yes" 613 useuri = trackData["useuri"].lower() == "yes"
603 if useuri: 614 if useuri:
604 uri = data 615 uri = data
605 else: 616 else:
606 uri = trackData["hic_url"] 617 uri = trackData["hic_url"]
607 categ = trackData['category'] 618 categ = trackData["category"]
608 trackDict = { 619 trackDict = {
609 "type": "HicTrack", 620 "type": "HicTrack",
610 "trackId": tId, 621 "trackId": tId,
611 "name": uri, 622 "name": uri,
612 "assemblyNames": [self.genome_name], 623 "assemblyNames": [self.genome_name],
613 "category": [categ,], 624 "category": [
625 categ,
626 ],
614 "adapter": { 627 "adapter": {
615 "type": "HicAdapter", 628 "type": "HicAdapter",
616 "hicLocation": uri, 629 "hicLocation": uri,
617 }, 630 },
618 "displays": [ 631 "displays": [
620 "type": "LinearHicDisplay", 633 "type": "LinearHicDisplay",
621 "displayId": "%s-LinearHicDisplay" % tId, 634 "displayId": "%s-LinearHicDisplay" % tId,
622 }, 635 },
623 ], 636 ],
624 } 637 }
625 style_json = self._prepare_track_style(trackDict)
626 trackDict["style"] = style_json
627 self.tracksToAdd.append(trackDict) 638 self.tracksToAdd.append(trackDict)
628 self.trackIdlist.append(tId) 639 self.trackIdlist.append(tId)
629 640
630 def add_maf(self, data, trackData): 641 def add_maf(self, data, trackData):
631 """ 642 """
641 "name": "MafViewer", 652 "name": "MafViewer",
642 "url": "https://unpkg.com/jbrowse-plugin-mafviewer/dist/jbrowse-plugin-mafviewer.umd.production.min.js", 653 "url": "https://unpkg.com/jbrowse-plugin-mafviewer/dist/jbrowse-plugin-mafviewer.umd.production.min.js",
643 } 654 }
644 ] 655 ]
645 } 656 }
646 categ = trackData['category'] 657 categ = trackData["category"]
647 fname = "%s.bed" % tId 658 fname = "%s.bed" % tId
648 dest = "%s/%s" % (self.outdir, fname) 659 dest = "%s/%s" % (self.outdir, fname)
649 gname = self.genome_name 660 gname = self.genome_name
650 cmd = [ 661 cmd = [
651 "bash", 662 "bash",
663 ps.wait() 674 ps.wait()
664 outp = output.decode("ascii") 675 outp = output.decode("ascii")
665 soutp = outp.split("\n") 676 soutp = outp.split("\n")
666 samp = [x.split("s ")[1] for x in soutp if x.startswith("s ")] 677 samp = [x.split("s ")[1] for x in soutp if x.startswith("s ")]
667 samples = [x.split(".")[0] for x in samp] 678 samples = [x.split(".")[0] for x in samp]
679 logging.warn("### maf convert cmd = %s,\nsamples=%s" % (' '.join(cmd), samples))
668 trackDict = { 680 trackDict = {
669 "type": "MafTrack", 681 "type": "MafTrack",
670 "trackId": tId, 682 "trackId": tId,
671 "name": trackData["name"], 683 "name": trackData["name"],
672 "category": [categ,], 684 "category": [
685 categ,
686 ],
673 "adapter": { 687 "adapter": {
674 "type": "MafTabixAdapter", 688 "type": "MafTabixAdapter",
675 "samples": samples, 689 "samples": samples,
676 "bedGzLocation": { 690 "bedGzLocation": {
677 "uri": fname + ".sorted.bed.gz", 691 "uri": fname + ".sorted.bed.gz",
692 "type": "LinearArcDisplay", 706 "type": "LinearArcDisplay",
693 "displayId": "%s-LinearArcDisplay" % tId, 707 "displayId": "%s-LinearArcDisplay" % tId,
694 }, 708 },
695 ], 709 ],
696 } 710 }
697 style_json = self._prepare_track_style(trackDict)
698 trackDict["style"] = style_json
699 self.tracksToAdd.append(trackDict) 711 self.tracksToAdd.append(trackDict)
700 self.trackIdlist.append(tId) 712 self.trackIdlist.append(tId)
701 if self.config_json.get("plugins", None): 713 if self.config_json.get("plugins", None):
702 self.config_json["plugins"].append(mafPlugin[0]) 714 self.config_json["plugins"].append(mafPlugin[0])
703 else: 715 else:
715 str(min_gap), 727 str(min_gap),
716 xml, 728 xml,
717 ] 729 ]
718 subprocess.check_call(cmd, cwd=self.outdir, stdout=gff3_unrebased) 730 subprocess.check_call(cmd, cwd=self.outdir, stdout=gff3_unrebased)
719 gff3_unrebased.close() 731 gff3_unrebased.close()
732 logging.warn("### blastxml to gff3 cmd = %s" % ' '.join(cmd))
720 return gff3_unrebased.name 733 return gff3_unrebased.name
721 734
722 def add_blastxml(self, data, trackData, blastOpts, **kwargs): 735 def add_blastxml(self, data, trackData, blastOpts, **kwargs):
723 gff3 = self._blastxml_to_gff3(data, min_gap=blastOpts["min_gap"]) 736 gff3 = self._blastxml_to_gff3(data, min_gap=blastOpts["min_gap"])
724
725 if "parent" in blastOpts and blastOpts["parent"] != "None": 737 if "parent" in blastOpts and blastOpts["parent"] != "None":
726 gff3_rebased = tempfile.NamedTemporaryFile(delete=False) 738 gff3_rebased = tempfile.NamedTemporaryFile(delete=False)
727 cmd = ["python", os.path.join(INSTALLED_TO, "gff3_rebase.py")] 739 cmd = ["python", os.path.join(INSTALLED_TO, "gff3_rebase.py")]
728 if blastOpts.get("protein", "false") == "true": 740 if blastOpts.get("protein", "false") == "true":
729 cmd.append("--protein2dna") 741 cmd.append("--protein2dna")
730 cmd.extend([os.path.realpath(blastOpts["parent"]), gff3]) 742 cmd.extend([os.path.realpath(blastOpts["parent"]), gff3])
731 subprocess.check_call(cmd, cwd=self.outdir, stdout=gff3_rebased) 743 subprocess.check_call(cmd, cwd=self.outdir, stdout=gff3_rebased)
744 logging.warn("### gff3rebase cmd = %s" % ' '.join(cmd))
732 gff3_rebased.close() 745 gff3_rebased.close()
733
734 # Replace original gff3 file 746 # Replace original gff3 file
735 shutil.copy(gff3_rebased.name, gff3) 747 shutil.copy(gff3_rebased.name, gff3)
736 os.unlink(gff3_rebased.name) 748 os.unlink(gff3_rebased.name)
737 url = "%s.gff3" % trackData["label"] 749 url = "%s.gff3.gz" % trackData["label"]
738 dest = "%s/%s" % (self.outdir, url) 750 dest = "%s/%s" % (self.outdir, url)
739 self._sort_gff(gff3, dest) 751 self._sort_gff(gff3, dest)
740 url = url + ".gz"
741 tId = trackData["label"] 752 tId = trackData["label"]
742 categ = trackData['category'] 753 categ = trackData["category"]
743 trackDict = { 754 trackDict = {
744 "type": "FeatureTrack", 755 "type": "FeatureTrack",
745 "trackId": tId, 756 "trackId": tId,
746 "name": trackData["name"], 757 "name": trackData["name"],
747 "assemblyNames": [self.genome_name], 758 "assemblyNames": [self.genome_name],
748 "category": [categ,], 759 "category": [
760 categ,
761 ],
749 "adapter": { 762 "adapter": {
750 "type": "Gff3TabixAdapter", 763 "type": "Gff3TabixAdapter",
751 "gffGzLocation": { 764 "gffGzLocation": {
752 "uri": url, 765 "uri": url,
753 }, 766 },
766 "type": "LinearArcDisplay", 779 "type": "LinearArcDisplay",
767 "displayId": "%s-LinearArcDisplay" % tId, 780 "displayId": "%s-LinearArcDisplay" % tId,
768 }, 781 },
769 ], 782 ],
770 } 783 }
771 style_json = self._prepare_track_style(trackDict)
772 trackDict["style"] = style_json
773 self.tracksToAdd.append(trackDict) 784 self.tracksToAdd.append(trackDict)
774 self.trackIdlist.append(tId) 785 self.trackIdlist.append(tId)
775 os.unlink(gff3) 786 os.unlink(gff3)
776 787
777 def add_bigwig(self, data, trackData): 788 def add_bigwig(self, data, trackData):
792 dest = os.path.join(self.outdir, url) 803 dest = os.path.join(self.outdir, url)
793 cmd = ["cp", data, dest] 804 cmd = ["cp", data, dest]
794 self.subprocess_check_call(cmd) 805 self.subprocess_check_call(cmd)
795 bwloc = {"uri": url} 806 bwloc = {"uri": url}
796 tId = trackData["label"] 807 tId = trackData["label"]
797 categ = trackData['category'] 808 categ = trackData["category"]
798 trackDict = { 809 trackDict = {
799 "type": "QuantitativeTrack", 810 "type": "QuantitativeTrack",
800 "trackId": tId, 811 "trackId": tId,
801 "name": trackData["name"], 812 "name": trackData["name"],
802 "category": [categ,], 813 "category": [
814 categ,
815 ],
803 "assemblyNames": [ 816 "assemblyNames": [
804 self.genome_name, 817 self.genome_name,
805 ], 818 ],
806 "adapter": { 819 "adapter": {
807 "type": "BigWigAdapter", 820 "type": "BigWigAdapter",
812 "type": "LinearWiggleDisplay", 825 "type": "LinearWiggleDisplay",
813 "displayId": "%s-LinearWiggleDisplay" % tId, 826 "displayId": "%s-LinearWiggleDisplay" % tId,
814 } 827 }
815 ], 828 ],
816 } 829 }
817 style_json = self._prepare_track_style(trackDict)
818 trackDict["style"] = style_json
819 self.tracksToAdd.append(trackDict) 830 self.tracksToAdd.append(trackDict)
820 self.trackIdlist.append(tId) 831 self.trackIdlist.append(tId)
821 832
822 def add_bam(self, data, trackData, bam_index=None, **kwargs): 833 def add_bam(self, data, trackData, bam_index=None, **kwargs):
823 tId = trackData["label"] 834 tId = trackData["label"]
824 useuri = trackData["useuri"].lower() == "yes" 835 useuri = trackData["useuri"].lower() == "yes"
825 bindex = bam_index 836 bindex = bam_index
826 categ = trackData['category'] 837 categ = trackData["category"]
827 if useuri: 838 if useuri:
828 url = data 839 url = data
829 else: 840 else:
830 fname = "%s.bam" % trackData["label"] 841 fname = "%s.bam" % trackData["label"]
831 dest = "%s/%s" % (self.outdir, fname) 842 dest = "%s/%s" % (self.outdir, fname)
832 url = fname 843 url = fname
833 bindex = fname + '.bai' 844 bindex = fname + ".bai"
834 self.subprocess_check_call(["cp", data, dest]) 845 self.subprocess_check_call(["cp", data, dest])
835 if bam_index is not None and os.path.exists(bam_index): 846 if bam_index is not None and os.path.exists(bam_index):
836 if not os.path.exists(bindex): 847 if not os.path.exists(bindex):
837 # bai most probably made by galaxy and stored in galaxy dirs, need to copy it to dest 848 # bai most probably made by galaxy and stored in galaxy dirs, need to copy it to dest
838 self.subprocess_check_call( 849 self.subprocess_check_call(["cp", bam_index, bindex])
839 ["cp", bam_index, bindex]
840 )
841 else: 850 else:
842 # Can happen in exotic condition 851 # Can happen in exotic condition
843 # e.g. if bam imported as symlink with datatype=unsorted.bam, then datatype changed to bam 852 # e.g. if bam imported as symlink with datatype=unsorted.bam, then datatype changed to bam
844 # => no index generated by galaxy, but there might be one next to the symlink target 853 # => no index generated by galaxy, but there might be one next to the symlink target
845 # this trick allows to skip the bam sorting made by galaxy if already done outside 854 # this trick allows to skip the bam sorting made by galaxy if already done outside
849 log.warn("Could not find a bam index (.bai file) for %s", data) 858 log.warn("Could not find a bam index (.bai file) for %s", data)
850 trackDict = { 859 trackDict = {
851 "type": "AlignmentsTrack", 860 "type": "AlignmentsTrack",
852 "trackId": tId, 861 "trackId": tId,
853 "name": trackData["name"], 862 "name": trackData["name"],
854 "category": [categ,], 863 "category": [
864 categ,
865 ],
855 "assemblyNames": [self.genome_name], 866 "assemblyNames": [self.genome_name],
856 "adapter": { 867 "adapter": {
857 "type": "BamAdapter", 868 "type": "BamAdapter",
858 "bamLocation": {"uri": url}, 869 "bamLocation": {"uri": url},
859 "index": { 870 "index": {
867 "type": "LinearAlignmentsDisplay", 878 "type": "LinearAlignmentsDisplay",
868 "displayId": "%s-LinearAlignmentsDisplay" % tId, 879 "displayId": "%s-LinearAlignmentsDisplay" % tId,
869 }, 880 },
870 ], 881 ],
871 } 882 }
872 style_json = self._prepare_track_style(trackDict)
873 trackDict["style"] = style_json
874 self.tracksToAdd.append(trackDict) 883 self.tracksToAdd.append(trackDict)
875 self.trackIdlist.append(tId) 884 self.trackIdlist.append(tId)
876 885
877 def add_cram(self, data, trackData, cram_index=None, **kwargs): 886 def add_cram(self, data, trackData, cram_index=None, **kwargs):
878 tId = trackData["label"] 887 tId = trackData["label"]
879 categ = trackData['category'] 888 categ = trackData["category"]
880 useuri = trackData["useuri"].lower() == "yes" 889 useuri = trackData["useuri"].lower() == "yes"
881 if useuri: 890 if useuri:
882 url = data 891 url = data
883 else: 892 else:
884 fname = "%s.cram" % trackData["label"] 893 fname = "%s.cram" % trackData["label"]
885 dest = "%s/%s" % (self.outdir, fname) 894 dest = "%s/%s" % (self.outdir, fname)
886 url = fname 895 url = fname
887 self.subprocess_check_call(["cp", data, dest]) 896 self.subprocess_check_call(["cp", data, dest])
888 if cram_index is not None and os.path.exists(cram_index): 897 if cram_index is not None and os.path.exists(cram_index):
889 if not os.path.exists(dest+'.crai'): 898 if not os.path.exists(dest + ".crai"):
890 # most probably made by galaxy and stored in galaxy dirs, need to copy it to dest 899 # most probably made by galaxy and stored in galaxy dirs, need to copy it to dest
891 self.subprocess_check_call( 900 self.subprocess_check_call(
892 ["cp", os.path.realpath(cram_index), dest + ".crai"] 901 ["cp", os.path.realpath(cram_index), dest + ".crai"]
893 ) 902 )
894 else: 903 else:
895 cpath = os.path.realpath(dest) + '.crai' 904 cpath = os.path.realpath(dest) + ".crai"
896 cmd = ["samtools", "index", "-c", "-o", cpath, os.path.realpath(dest)] 905 cmd = ["samtools", "index", "-c", "-o", cpath, os.path.realpath(dest)]
897 logging.debug('executing cmd %s' % ' '.join(cmd)) 906 logging.debug("executing cmd %s" % " ".join(cmd))
898 self.subprocess_check_call(cmd) 907 self.subprocess_check_call(cmd)
899 trackDict = { 908 trackDict = {
900 "type": "AlignmentsTrack", 909 "type": "AlignmentsTrack",
901 "trackId": tId, 910 "trackId": tId,
902 "name": trackData["name"], 911 "name": trackData["name"],
903 "category": [categ,], 912 "category": [
913 categ,
914 ],
904 "assemblyNames": [self.genome_name], 915 "assemblyNames": [self.genome_name],
905 "adapter": { 916 "adapter": {
906 "type": "CramAdapter", 917 "type": "CramAdapter",
907 "cramLocation": {"uri": url}, 918 "cramLocation": {"uri": url},
908 "craiLocation": { 919 "craiLocation": {
909 "uri": url + '.crai', 920 "uri": url + ".crai",
910 }, 921 },
911 "sequenceAdapter": self.genome_sequence_adapter, 922 "sequenceAdapter": self.genome_sequence_adapter,
912 }, 923 },
913 "displays": [ 924 "displays": [
914 { 925 {
915 "type": "LinearAlignmentsDisplay", 926 "type": "LinearAlignmentsDisplay",
916 "displayId": "%s-LinearAlignmentsDisplay" % tId, 927 "displayId": "%s-LinearAlignmentsDisplay" % tId,
917 }, 928 },
918 ], 929 ],
919 } 930 }
920 style_json = self._prepare_track_style(trackDict)
921 trackDict["style"] = style_json
922 self.tracksToAdd.append(trackDict) 931 self.tracksToAdd.append(trackDict)
923 self.trackIdlist.append(tId) 932 self.trackIdlist.append(tId)
924 933
925 def add_vcf(self, data, trackData): 934 def add_vcf(self, data, trackData):
926 tId = trackData["label"] 935 tId = trackData["label"]
927 # url = "%s/api/datasets/%s/display" % ( 936 # url = "%s/api/datasets/%s/display" % (
928 # self.giURL, 937 # self.giURL,
929 # trackData["metadata"]["dataset_id"], 938 # trackData["metadata"]["dataset_id"],
930 # ) 939 # )
931 categ = trackData['category'] 940 categ = trackData["category"]
932 useuri = trackData["useuri"].lower() == "yes" 941 useuri = trackData["useuri"].lower() == "yes"
933 if useuri: 942 if useuri:
934 url = data 943 url = data
935 else: 944 else:
936 url = "%s.vcf.gz" % tId 945 url = "%s.vcf.gz" % tId
942 trackDict = { 951 trackDict = {
943 "type": "VariantTrack", 952 "type": "VariantTrack",
944 "trackId": tId, 953 "trackId": tId,
945 "name": trackData["name"], 954 "name": trackData["name"],
946 "assemblyNames": [self.genome_name], 955 "assemblyNames": [self.genome_name],
947 "category": [categ,], 956 "category": [
957 categ,
958 ],
948 "adapter": { 959 "adapter": {
949 "type": "VcfTabixAdapter", 960 "type": "VcfTabixAdapter",
950 "vcfGzLocation": { 961 "vcfGzLocation": {"uri": url},
951 "uri": url
952 },
953 "index": { 962 "index": {
954 "location": { 963 "location": {
955 "uri": url + ".tbi", 964 "uri": url + ".tbi",
956 } 965 }
957 }, 966 },
969 "type": "LinearPairedArcDisplay", 978 "type": "LinearPairedArcDisplay",
970 "displayId": "%s-LinearPairedArcDisplay" % tId, 979 "displayId": "%s-LinearPairedArcDisplay" % tId,
971 }, 980 },
972 ], 981 ],
973 } 982 }
974 style_json = self._prepare_track_style(trackDict)
975 trackDict["style"] = style_json
976 self.tracksToAdd.append(trackDict) 983 self.tracksToAdd.append(trackDict)
977 self.trackIdlist.append(tId) 984 self.trackIdlist.append(tId)
978 985
979 def _sort_gff(self, data, dest): 986 def _sort_gff(self, data, dest):
980 # Only index if not already done 987 # Only index if not already done
1001 else: 1008 else:
1002 url = "%s.%s.gz" % (trackData["label"], ext) 1009 url = "%s.%s.gz" % (trackData["label"], ext)
1003 dest = "%s/%s" % (self.outdir, url) 1010 dest = "%s/%s" % (self.outdir, url)
1004 self._sort_gff(data, dest) 1011 self._sort_gff(data, dest)
1005 tId = trackData["label"] 1012 tId = trackData["label"]
1006 categ = trackData['category'] 1013 categ = trackData["category"]
1007 trackDict = { 1014 trackDict = {
1008 "type": "FeatureTrack", 1015 "type": "FeatureTrack",
1009 "trackId": tId, 1016 "trackId": tId,
1010 "name": trackData["name"], 1017 "name": trackData["name"],
1011 "assemblyNames": [self.genome_name], 1018 "assemblyNames": [self.genome_name],
1012 "category": [categ,], 1019 "category": [
1020 categ,
1021 ],
1013 "adapter": { 1022 "adapter": {
1014 "type": "Gff3TabixAdapter", 1023 "type": "Gff3TabixAdapter",
1015 "gffGzLocation": { 1024 "gffGzLocation": {
1016 "uri": url, 1025 "uri": url,
1017 }, 1026 },
1030 "type": "LinearArcDisplay", 1039 "type": "LinearArcDisplay",
1031 "displayId": "%s-LinearArcDisplay" % tId, 1040 "displayId": "%s-LinearArcDisplay" % tId,
1032 }, 1041 },
1033 ], 1042 ],
1034 } 1043 }
1035 style_json = self._prepare_track_style(trackDict)
1036 trackDict["style"] = style_json
1037 self.tracksToAdd.append(trackDict) 1044 self.tracksToAdd.append(trackDict)
1038 self.trackIdlist.append(tId) 1045 self.trackIdlist.append(tId)
1039 1046
1040 def add_bed(self, data, ext, trackData): 1047 def add_bed(self, data, ext, trackData):
1041 tId = trackData["label"] 1048 tId = trackData["label"]
1042 categ = trackData['category'] 1049 categ = trackData["category"]
1043 useuri = trackData["useuri"].lower() == "yes" 1050 useuri = trackData["useuri"].lower() == "yes"
1044 if useuri: 1051 if useuri:
1045 url = data 1052 url = data
1046 else: 1053 else:
1047 url = "%s.%s.gz" % (trackData["label"], ext) 1054 url = "%s.%s.gz" % (trackData["label"], ext)
1051 "type": "FeatureTrack", 1058 "type": "FeatureTrack",
1052 "trackId": tId, 1059 "trackId": tId,
1053 "name": trackData["name"], 1060 "name": trackData["name"],
1054 "assemblyNames": [self.genome_name], 1061 "assemblyNames": [self.genome_name],
1055 "adapter": { 1062 "adapter": {
1056 "category": [categ,], 1063 "category": [
1064 categ,
1065 ],
1057 "type": "BedTabixAdapter", 1066 "type": "BedTabixAdapter",
1058 "bedGzLocation": { 1067 "bedGzLocation": {
1059 "uri": url, 1068 "uri": url,
1060 }, 1069 },
1061 "index": { 1070 "index": {
1077 "type": "LinearArcDisplay", 1086 "type": "LinearArcDisplay",
1078 "displayId": "%s-LinearArcDisplay" % tId, 1087 "displayId": "%s-LinearArcDisplay" % tId,
1079 }, 1088 },
1080 ], 1089 ],
1081 } 1090 }
1082 style_json = self._prepare_track_style(trackDict)
1083 trackDict["style"] = style_json
1084 self.tracksToAdd.append(trackDict) 1091 self.tracksToAdd.append(trackDict)
1085 self.trackIdlist.append(tId) 1092 self.trackIdlist.append(tId)
1086 1093
1087 def add_paf(self, data, trackData, pafOpts, **kwargs): 1094 def add_paf(self, data, trackData, pafOpts, **kwargs):
1088 tname = trackData["name"] 1095 tname = trackData["name"]
1089 tId = trackData["label"] 1096 tId = trackData["label"]
1090 categ = trackData['category'] 1097 categ = trackData["category"]
1091 pgnames = [x.strip() for x in pafOpts["genome_label"].split(",")] 1098 pgnames = [x.strip() for x in pafOpts["genome_label"].split(",")]
1092 pgpaths = [x.strip() for x in pafOpts["genome"].split(",")] 1099 pgpaths = [x.strip() for x in pafOpts["genome"].split(",")]
1093 passnames = [self.genome_name] # always first 1100 passnames = [self.genome_name] # always first
1094 for i, gname in enumerate(pgnames): 1101 for i, gname in enumerate(pgnames):
1095 if len(gname.split()) > 1: 1102 if len(gname.split()) > 1:
1096 gname = gname.split()[0] 1103 gname = gname.split()[0]
1097 passnames.append(gname) 1104 passnames.append(gname)
1098 # trouble from spacey names in command lines avoidance 1105 # trouble from spacey names in command lines avoidance
1099 if gname not in self.genome_names: 1106 if gname not in self.genome_names:
1100 # ignore if already there - eg for duplicates among pafs. 1107 # ignore if already there - eg for duplicates among pafs.
1101 useuri = pgpaths[i].startswith('http://') or pgpaths[i].startswith('https://') 1108 useuri = pgpaths[i].startswith("http://") or pgpaths[i].startswith(
1109 "https://"
1110 )
1102 asstrack = self.make_assembly(pgpaths[i], gname, useuri) 1111 asstrack = self.make_assembly(pgpaths[i], gname, useuri)
1103 self.genome_names.append(gname) 1112 self.genome_names.append(gname)
1104 if self.config_json.get("assemblies", None): 1113 if self.config_json.get("assemblies", None):
1105 self.config_json["assemblies"].append(asstrack) 1114 self.config_json["assemblies"].append(asstrack)
1106 else: 1115 else:
1112 self.symlink_or_copy(os.path.realpath(data), dest) 1121 self.symlink_or_copy(os.path.realpath(data), dest)
1113 trackDict = { 1122 trackDict = {
1114 "type": "SyntenyTrack", 1123 "type": "SyntenyTrack",
1115 "trackId": tId, 1124 "trackId": tId,
1116 "assemblyNames": passnames, 1125 "assemblyNames": passnames,
1117 "category": [categ,], 1126 "category": [
1127 categ,
1128 ],
1118 "name": tname, 1129 "name": tname,
1119 "adapter": { 1130 "adapter": {
1120 "type": "PAFAdapter", 1131 "type": "PAFAdapter",
1121 "pafLocation": {"uri": url}, 1132 "pafLocation": {"uri": url},
1122 "assemblyNames": passnames, 1133 "assemblyNames": passnames,
1123 }, 1134 },
1124 "displays": [ 1135 "displays": [
1125 { 1136 {
1126 "type": "LinearSyntenyDisplay", 1137 "type": "LinearSyntenyDisplay",
1127 "displayId": "%s-LinearSyntenyDisplay" % tId, 1138 "displayId": "%s-LinearSyntenyDisplay" % tId,
1128 }, 1139 },
1129 { 1140 {
1130 "type": "DotPlotDisplay", 1141 "type": "DotPlotDisplay",
1131 "displayId": "%s-DotPlotDisplay" % tId, 1142 "displayId": "%s-DotPlotDisplay" % tId,
1132 }, 1143 },
1133 ], 1144 ],
1134 } 1145 }
1135 style_json = self._prepare_track_style(trackDict)
1136 trackDict["style"] = style_json
1137 self.tracksToAdd.append(trackDict) 1146 self.tracksToAdd.append(trackDict)
1138 self.trackIdlist.append(tId) 1147 self.trackIdlist.append(tId)
1139 1148
1140 def process_annotations(self, track): 1149 def process_annotations(self, track):
1141 category = track["category"].replace("__pd__date__pd__", TODAY) 1150 category = track["category"].replace("__pd__date__pd__", TODAY)
1247 else: 1256 else:
1248 logging.warn("Do not know how to handle %s", dataset_ext) 1257 logging.warn("Do not know how to handle %s", dataset_ext)
1249 # Return non-human label for use in other fields 1258 # Return non-human label for use in other fields
1250 yield outputTrackConfig["label"] 1259 yield outputTrackConfig["label"]
1251 1260
1252 def add_default_session(self, data): 1261 def add_default_session(self, default_data):
1253 """ 1262 """
1254 Add some default session settings: set some assemblies/tracks on/off 1263 Add some default session settings: set some assemblies/tracks on/off
1255 """ 1264 """
1256 tracks_data = [] 1265 tracks_data = []
1257 1266
1265 config_json.update(self.config_json) 1274 config_json.update(self.config_json)
1266 1275
1267 for track_conf in self.tracksToAdd: 1276 for track_conf in self.tracksToAdd:
1268 track_types[track_conf["trackId"]] = track_conf["type"] 1277 track_types[track_conf["trackId"]] = track_conf["type"]
1269 tId = track_conf["trackId"] 1278 tId = track_conf["trackId"]
1270 if tId in data["visibility"]["default_on"]: 1279 #if tId in data["visibility"]["default_on"]:
1280 style_data = default_data["style"].get(tId, None)
1281 if not style_data:
1282 logging.warn("### No style data in default data for %s" % tId)
1271 style_data = {"type": "LinearBasicDisplay"} 1283 style_data = {"type": "LinearBasicDisplay"}
1272 if "displays" in track_conf: 1284 if "displays" in track_conf:
1273 style_data["type"] = track_conf["displays"][0]["type"] 1285 disp = track_conf["displays"][0]["type"]
1274 if track_conf.get("style_labels", None): 1286 style_data["type"] = disp
1275 # TODO fix this: it should probably go in a renderer block (SvgFeatureRenderer) but still does not work 1287 style_data["configuration"] = "%s-%s" % (tId, disp)
1276 # TODO move this to per track displays? 1288 if track_conf.get("style_labels", None):
1277 style_data["labels"] = track_conf["style_labels"] 1289 # TODO fix this: it should probably go in a renderer block (SvgFeatureRenderer) but still does not work
1278 tracks_data.append( 1290 # TODO move this to per track displays?
1279 { 1291 style_data["labels"] = track_conf["style_labels"]
1280 "type": track_types[tId], 1292 tracks_data.append(
1281 "configuration": tId, 1293 {
1282 "displays": [style_data], 1294 "type": track_types[tId],
1283 } 1295 "configuration": tId,
1284 ) 1296 "displays": [style_data],
1297 }
1298 )
1285 1299
1286 # The view for the assembly we're adding 1300 # The view for the assembly we're adding
1287 view_json = {"type": "LinearGenomeView", "tracks": tracks_data} 1301 view_json = {"type": "LinearGenomeView", "tracks": tracks_data}
1288 1302
1289 refName = None 1303 refName = None
1290 drdict = { 1304 drdict = {
1291 "reversed": False, 1305 "reversed": False,
1292 "assemblyName": self.genome_name, 1306 "assemblyName": self.genome_name,
1293 "start": 2000, 1307 "start": 1,
1294 "end": 200000, 1308 "end": 100000,
1295 "refName": "x", 1309 "refName": "x",
1296 } 1310 }
1297 1311
1298 if data.get("defaultLocation", ""): 1312 if default_data.get("defaultLocation", ""):
1299 ddl = data["defaultLocation"] 1313 ddl = default_data["defaultLocation"]
1300 loc_match = re.search(r"^([^:]+):([\d,]*)\.*([\d,]*)$", ddl) 1314 loc_match = re.search(r"^([^:]+):([\d,]*)\.*([\d,]*)$", ddl)
1301 # allow commas like 100,000 but ignore as integer 1315 # allow commas like 100,000 but ignore as integer
1302 if loc_match: 1316 if loc_match:
1303 refName = loc_match.group(1) 1317 refName = loc_match.group(1)
1304 drdict["refName"] = refName 1318 drdict["refName"] = refName
1322 logging.info("@@@ defaultlocation %s for default session" % drdict) 1336 logging.info("@@@ defaultlocation %s for default session" % drdict)
1323 else: 1337 else:
1324 logging.info( 1338 logging.info(
1325 "@@@ no contig name found for default session - please add one!" 1339 "@@@ no contig name found for default session - please add one!"
1326 ) 1340 )
1327 session_name = data.get("session_name", "New session") 1341 session_name = default_data.get("session_name", "New session")
1328 for key, value in mapped_chars.items(): 1342 for key, value in mapped_chars.items():
1329 session_name = session_name.replace(value, key) 1343 session_name = session_name.replace(value, key)
1330 # Merge with possibly existing defaultSession (if upgrading a jbrowse instance) 1344 # Merge with possibly existing defaultSession (if upgrading a jbrowse instance)
1331 session_json = {} 1345 session_json = {}
1332 if "defaultSession" in config_json: 1346 if "defaultSession" in config_json:
1380 1394
1381 def clone_jbrowse(self, realclone=True): 1395 def clone_jbrowse(self, realclone=True):
1382 """Clone a JBrowse directory into a destination directory. This also works in Biocontainer testing now""" 1396 """Clone a JBrowse directory into a destination directory. This also works in Biocontainer testing now"""
1383 dest = self.outdir 1397 dest = self.outdir
1384 if realclone: 1398 if realclone:
1385 self.subprocess_check_call(['jbrowse', 'create', dest,"-f", '--tag', f"{JB2VER}"]) 1399 self.subprocess_check_call(
1400 ["jbrowse", "create", dest, "-f", "--tag", f"{JB2VER}"]
1401 )
1386 else: 1402 else:
1387 shutil.copytree(self.jbrowse2path, dest, dirs_exist_ok=True) 1403 shutil.copytree(self.jbrowse2path, dest, dirs_exist_ok=True)
1388 for fn in [ 1404 for fn in [
1389 "asset-manifest.json", 1405 "asset-manifest.json",
1390 "favicon.ico", 1406 "favicon.ico",
1398 cmd = ["cp", os.path.join(INSTALLED_TO, "jb2_webserver.py"), dest] 1414 cmd = ["cp", os.path.join(INSTALLED_TO, "jb2_webserver.py"), dest]
1399 self.subprocess_check_call(cmd) 1415 self.subprocess_check_call(cmd)
1400 1416
1401 1417
1402 def parse_style_conf(item): 1418 def parse_style_conf(item):
1403 if "type" in item.attrib and item.attrib["type"] in [ 1419 if item.text.lower() in ['false','true','yes','no']:
1404 "boolean", 1420 return item.text.lower in ("yes", "true")
1405 "integer",
1406 ]:
1407 if item.attrib["type"] == "boolean":
1408 return item.text in ("yes", "true", "True")
1409 elif item.attrib["type"] == "integer":
1410 return int(item.text)
1411 else: 1421 else:
1412 return item.text 1422 return item.text
1413 1423
1414 1424
1415 if __name__ == "__main__": 1425 if __name__ == "__main__":
1471 pass 1481 pass
1472 1482
1473 trackfiles = track.findall("files/trackFile") 1483 trackfiles = track.findall("files/trackFile")
1474 if trackfiles: 1484 if trackfiles:
1475 for x in track.findall("files/trackFile"): 1485 for x in track.findall("files/trackFile"):
1486 track_conf["label"] = x.attrib["label"]
1476 track_conf["useuri"] = x.attrib["useuri"] 1487 track_conf["useuri"] = x.attrib["useuri"]
1477 if is_multi_bigwig: 1488 if is_multi_bigwig:
1478 multi_bigwig_paths.append( 1489 multi_bigwig_paths.append(
1479 ( 1490 (
1480 x.attrib["label"], 1491 x.attrib["label"],
1519 track_conf["format"] = track.attrib["format"] 1530 track_conf["format"] = track.attrib["format"]
1520 if track.find("options/style"): 1531 if track.find("options/style"):
1521 track_conf["style"] = { 1532 track_conf["style"] = {
1522 item.tag: parse_style_conf(item) for item in track.find("options/style") 1533 item.tag: parse_style_conf(item) for item in track.find("options/style")
1523 } 1534 }
1535 else:
1536 track_conf["style"] = {}
1537 tst = track_conf["style"].get("type", None)
1538 if tst:
1539 track_conf["style"]["configuration"] = "%s-%s" % (track_conf["label"], tst)
1524 if track.find("options/style_labels"): 1540 if track.find("options/style_labels"):
1525 track_conf["style_labels"] = { 1541 track_conf["style_labels"] = {
1526 item.tag: parse_style_conf(item) 1542 item.tag: parse_style_conf(item)
1527 for item in track.find("options/style_labels") 1543 for item in track.find("options/style_labels")
1528 } 1544 }
1529 1545
1530 track_conf["conf"] = etree_to_dict(track.find("options")) 1546 track_conf["conf"] = etree_to_dict(track.find("options"))
1531 track_conf["category"] = track.attrib["cat"] 1547 track_conf["category"] = track.attrib["cat"]
1532 track_conf["format"] = track.attrib["format"] 1548 track_conf["format"] = track.attrib["format"]
1533 try:
1534 # Only pertains to gff3 + blastxml. TODO?
1535 track_conf["style"] = {t.tag: t.text for t in track.find("options/style")}
1536 except TypeError:
1537 track_conf["style"] = {}
1538 pass
1539 keys = jc.process_annotations(track_conf) 1549 keys = jc.process_annotations(track_conf)
1540 1550
1541 if keys: 1551 if keys:
1542 for key in keys: 1552 for key in keys:
1543 default_session_data["visibility"][ 1553 default_session_data["visibility"][
1544 track.attrib.get("visibility", "default_off") 1554 track.attrib.get("visibility", "default_off")
1545 ].append(key) 1555 ].append(key)
1546 if track_conf.get("style", None): 1556 if track_conf.get("style", None):
1547 default_session_data["style"][key] = track_conf[ 1557 default_session_data["style"][key] = track_conf["style"]
1548 "style"
1549 ] # TODO do we need this anymore?
1550 if track_conf.get("style_lables", None): 1558 if track_conf.get("style_lables", None):
1551 default_session_data["style_labels"][key] = track_conf.get( 1559 default_session_data["style_labels"][key] = track_conf.get(
1552 "style_labels", None 1560 "style_labels", None
1553 ) 1561 )
1554 default_session_data["defaultLocation"] = root.find( 1562 default_session_data["defaultLocation"] = root.find(