From 171a1aeda71da109bc99ef629cba93529f74a69d Mon Sep 17 00:00:00 2001
From: fabrice <fabrice.allain@pasteur.fr>
Date: Mon, 11 Apr 2016 13:53:41 +0200
Subject: [PATCH] Bug Fixe: N_factor convert to int during mapfilter step.
 Float values wasn't taken into account before ...

---
 ariaec/commands.py      |   2 +-
 ariaec/commands.pyc     | Bin 10416 -> 10429 bytes
 ariaec/conf/aria_ec.ini |   1 -
 ariaec/maplot.py        |  52 +++++++++++++++++++++-------------------
 ariaec/maplot.pyc       | Bin 5130 -> 5288 bytes
 ariaec/protmap.py       |  32 +++++++++++++++----------
 ariaec/protmap.pyc      | Bin 47987 -> 48260 bytes
 7 files changed, 49 insertions(+), 38 deletions(-)

diff --git a/ariaec/commands.py b/ariaec/commands.py
index 4e80c19..866b10c 100644
--- a/ariaec/commands.py
+++ b/ariaec/commands.py
@@ -195,7 +195,7 @@ class AriaEcCommand:
                             default=False,
                             help="Use secondary structure index")
         parser.add_argument("--prefix", dest="prefix", default="",
-                            help="File name")
+                            help="Contact map name", nargs="+")
         return parser
 
     def create_settings(self):
diff --git a/ariaec/commands.pyc b/ariaec/commands.pyc
index e58e41ac9f3a8f238b0b9abc9e6e13b9066d6d5a..6cb3f4ce9085f01222fdf50166463871c2fb80a2 100644
GIT binary patch
delta 70
zcmV-M0J;CLQN2+J1M>|Erd<nHu?UVC0brBq5G1p^88HC~WC{Re3jl)w1helNwE_<i
c0000(Z*Fv9V{{;GVQ`bI9rXbXv!Wgj3KH-Y$N&HU

delta 57
zcmV-90LK5lQLs@61M>|EFj%`*u?UVC0a}yk5G1p^88HC^g8>7x^%}JT2nhfH07hwS
PWs|ub^#KR7uO1ExFvk*f

diff --git a/ariaec/conf/aria_ec.ini b/ariaec/conf/aria_ec.ini
index 7468bfc..9cfbf07 100644
--- a/ariaec/conf/aria_ec.ini
+++ b/ariaec/conf/aria_ec.ini
@@ -131,7 +131,6 @@ pickle_output:                              no
 [contactmap]
 ; -------------------------- Contactmap parameters --------------------------- #
 ; Plot settings
-n_factor:                                   1.5
 save_fig:                                   True
 size_fig:                                   10
 plot_ext:                                   pdf
diff --git a/ariaec/maplot.py b/ariaec/maplot.py
index ba351a5..0dfe9f2 100644
--- a/ariaec/maplot.py
+++ b/ariaec/maplot.py
@@ -37,13 +37,13 @@ class AriaEcContactMap(object):
         if not self.settings.contactmap.args.get("onlyreport", False):
             self.settings.make_infra()
         # ----------------------------- Input -------------------------------- #
-        if self.settings.contactmap.args.get("prefix"):
-            self.outprefix = "_".join((get_filename(
-                self.settings.contactmap.args.get("seq", None)),
-                self.settings.contactmap.args.get("prefix", "")))
+        if self.settings.contactmap.args.get("prefix") and len(
+                self.settings.contactmap.args.get("infiles")) == len(
+                    self.settings.contactmap.args.get("prefix")):
+                self.outprefix = self.settings.contactmap.args.get("prefix", "")
         else:
-            self.outprefix = get_filename(
-                self.settings.contactmap.args.get("seq", None))
+            self.outprefix = get_filename(self.settings.contactmap.args.get("seq",
+                                                                            None))
         # Load Sequence file
         self.protein.set_aa_sequence(self.settings.contactmap.args.get("seq", None))
         # Load secondary structure prediction file
@@ -70,11 +70,13 @@ class AriaEcContactMap(object):
                 logger.info("%s map set as reference" % fo.filetype.capitalize())
                 self.refmap = fo.mapdict
                 self.reftype = fo.filetype
-                self.refname = fo.filename
+                self.refname = fo.filename if type(self.outprefix) != list \
+                    else self.outprefix[idx]
             if not self.settings.contactmap.args.get("nofilter"):
                 self.filter(fo.mapdict, fo.filetype, fo.contactlist,
                             self.protein, clashlist=fo.clashlist,
-                            outprefix=self.outprefix,
+                            outprefix=self.outprefix[idx] if type(
+                                self.outprefix) == list else self.outprefix,
                             outdir=self.settings.outdir)
             # else:
             #     Use only position filter
@@ -82,7 +84,9 @@ class AriaEcContactMap(object):
             #                 self.protein, clashlist=fo.clashlist,
             #                 outprefix=self.outprefix,
             #                 outdir=self.settings.outdir, mapfilters="pos")
-            self.allresmap[(fo.filename, fo.filetype)] = fo.mapdict
+            self.allresmap[(fo.filename if type(self.outprefix) != list else
+                            self.outprefix[idx], fo.filetype,
+                            fo.filepath)] = fo.mapdict
 
         try:
             refmap = self.refmap["contactmap"]
@@ -99,7 +103,8 @@ class AriaEcContactMap(object):
         if self.settings.contactmap.config.get("save_fig") and not \
                 self.settings.contactmap.args.get("onlyreport", False):
             refmap.saveplot(outdir=outdir,
-                            outprefix="_".join((self.outprefix, "pdb")),
+                            outprefix=self.outprefix[0] if type(
+                                self.outprefix) == list else self.outprefix,
                             **plotparams)
 
         if self.settings.contactmap.args.get("merge", None):
@@ -120,20 +125,20 @@ class AriaEcContactMap(object):
                             self.allresmap[mergekey] = {}
                             self.allresmap[mergekey]["contactmap"] = up_map
 
-        for mapname, mapt in self.allresmap.keys():
+        for mapname, mapt, mapath in self.allresmap.keys():
 
-            prefix = "_".join((self.outprefix, mapname, self.refname))
+            prefix = "_".join((mapname, self.refname))
 
             if mapname == self.refname:
+                if not self.settings.contactmap.args.get("onlyreport", False):
+                    refmap.write_contacts(mapname,
+                                          outdir=outdir,
+                                          scoremap=self.refmap.get("scoremap",
+                                                                   None))
                 continue
 
-            if self.settings.contactmap.args.get("onlyreport", False):
-                refmap.write_contacts("_".join((self.outprefix, mapt)),
-                                      outdir=outdir,
-                                      scoremap=self.refmap.get("scoremap",
-                                                               None))
-                continue
-            scoremap = self.allresmap[(mapname, mapt)].get('scoremap', None)
+            scoremap = self.allresmap[(mapname, mapt, mapath)].get(
+                'scoremap', None)
             # if self.allresmap[mapt].get("contactmap") is not None and \
             #         self.allresmap[mapt].get("scoremap") is not None:
             #     Get top contact map/list
@@ -143,10 +148,9 @@ class AriaEcContactMap(object):
             #         human_idx=True)[:nb_c]
             # elif self.allresmap[mapt].get("contactmap") is not None:
             #     If no score given, use all contact list
-            cmpmap = self.allresmap[(mapname, mapt)]["contactmap"]
-            cmplist = self.allresmap[(mapname, mapt)][
-                'contactmap'].contact_list(
-                human_idx=True)
+            cmpmap = self.allresmap[(mapname, mapt, mapath)]["contactmap"]
+            cmplist = self.allresmap[(mapname, mapt, mapath)][
+                'contactmap'].contact_list(human_idx=True)
             # else:
             #     logger.warning("%s map doesn't have any score related. Can't "
             #                    "define top list related to this map" % mapt)
@@ -165,7 +169,7 @@ class AriaEcContactMap(object):
             # TODO: elementwise error with compare method
             # Write cmp stats
             if not self.settings.contactmap.args.get("onlyreport", False):
-                cmpmap.write_contacts("_".join((self.outprefix, mapt)),
+                cmpmap.write_contacts(mapname,
                                       scoremap=scoremap,
                                       outdir=outdir)
                 cmpmap.compare_contactmap(refmap, cmplist, prefix,
diff --git a/ariaec/maplot.pyc b/ariaec/maplot.pyc
index f774d93fd4dbee644841d77ba4619ebb527daa0e..121f8e6c3cf140d785e1ede07d7763fb4714676b 100644
GIT binary patch
delta 1887
zcmZuyOKcle6g_WdY>)rHeC(ugnl%0;X+m29Ed=pV7IcBsx=2Q)Q3*@}nS@DfkE&Ff
z!AO?c3aNnfR2B%twqjGE?h%_V*sx&51|&8}h+SE*;&bmCJ0DW{&C`4Do_p`PpZEMx
z?S9?V|4hcd{v_V~#{5-J4FSl~r@tl8>BztI&$^G{#&HL*4cH;r5!fcI2zr9Y6GY*@
zXiG!;@iE0PEE7GA&#x!o%)m_^!$e_$F=YP^bi&EMjWH3Gh0qDHCYM4ty2`zETr<Tw
zR$5t1!^#Xy55p$M85FJT;An)PhS<9#+);Iuhh1RpmDOc&O@mKEho`~Hfg|}`b14Ny
zSb2E5oDEmI?xfO7u#$TcTRPgeHBW~<1t-=Qk$#aQorZ&f<NX{Cv1Vsf=iHtmtFTX~
zc}&eS3Qs`{t8E$92oAgKvQHxRkH-25rdo8ueZN)^6IHB&o}ml!9@uAW^@yE5^_TT0
zQ0Jq7O${45mRplr^Jb92i7u=HioSuSGY7-1V=IRCm%0#w6EzE~$l(ch4)#2(F|~07
z-nb2HP>sfM3$W&}LLfgh$V~-)5JJ#vVbyDstlM5PnEOEw%Bx1Ko1kNl&Q60O_Nc^1
zbJR~!S*a$tlm{vDLbwZ!Gjr4~tdsrrYrh^kE@HY7?EMZef|bjwzrZ))nQ#}BnJVl>
z^r(3$LUOhhMtes&C&5#UWA!M!s0vK=n;*m8y?td_H%qZcM!(ml<YhB|q6#lToy*xy
z!b_s$#ZVfhMa`O)ADY8m0;I4^2SIgd!|3JKBZEe>wPVm|QlNVU)hh#%E2|Ohnhrk>
zKLMXQ?G)@Y@Pf-ejSY1H{mj7$x7%;WauSlOhS{}3T!*s^?w2BH;0YD!%>IqmM9T`%
z=;xiN$2mMN%?(!Mr)7ZkgGT!wLZu-$h;(1~94WKNJ_oA|_h~AE@ad`&rzLnfw(4cM
zJ-p0-Uq${LEj(9MrViQ)R)~w#c@XZ`{uvcOjk}AUBqut+SL9->#9`+KVFxZ$ANGVM
zSnw<}@Q4R_tt-t5UK9h4L85xPE|}+e#q%)3;DHIa9l8qE?0`dPir+O(+ANdimZmo?
zNN|(h&?~ih`ETrEAwn<urn9lRz20d=Y3=GXb=F(*YP|aJZoDi+O+HNA6Yt22$rt6P
z$;FT$z;*d;^3BXVts19!TA-<RLDo}ehHAV|(&QR6t+n6nH0shxP2}0|_PW#H|Bwc6
z8hQCu>Oq!a?#<nGh2P%nxbn4hZM?#ODo;6<n=~=W-8J_;*-KwCS<BwpbmWg|TMWq;
zGUr8A-pDvPH%yZE*BICsr)A@;{3CN~;s;tnD~Y(^Z(L-wahgkFN*fkw`Ej<KEs4A+
z&@U%+Q4^WytMa?-C>5YAf67kHO=<-#O&SRirY|YN+K5QR#z-e`7U(Q3VkBQM2q7!E
fm&C68Apf@fKKDxa3X^zVX7kN(i<cLqlmFsBM4eho

delta 1719
zcmah}O=x3P6#njeFE2kY|LITCrs;2*q@A=gwt_PR6sd|Js1c0FjIrf4LtopB`9UhY
zm_=|DL2$T?tHG5Ecf&AyK@<dWF)+9-3T|AApj*$m?`7H|BDp#5+;h)4_q*RY_kLaZ
zv>ej^j72{D^5-`ngnrfI830N8>+cHmbosab#qbx{K{yurQG5b82AlvKvV>sM07e={
z;$KT9>@Y92#;eUZ+AIH`gxq+S1e~OoQx*c22+6fTUc4$_3cNpz@piW7b{<SZ*}bR)
z?9>?2Bpd>hLe5T)O;hA*h?C#YpH`*}oGeH0+<1iR8U{3UxEkyX4mEUJTAv{0U{Ao+
zWz8&Et`29OLz@fob8})i$<e)UHHN-OPH^%{&M3L0HX%$?YPt;D+cpk6JBGA^k)ew=
z{9sO0RQkM<GfZTy6Vn<Wcn6z<okMP5pwV8(zR_RBVFcZIT?oNoOR#4cljxV>RAA4l
zNn7BpkAW8Pm&a|uzJwie8U)Tz49u}kRW?<X7dW>2l`dZ~vYSy-T%vuAvAaa<wBH_#
zm=3h)SKJNYGiXBIF*Cy@zfHQ|8SHhwXiJ=X5X8yvaD&AEDFz|9A@tW3j3S&%7*UTA
z;tX<!Cc3A($Bk2EKaLK=4J)8IHI3lp?uB6aO=#xow&B-snZw*D!<?dM;WHhj{$N65
zaAPRA5fr9LDcdVD6`mYYDdMP+!S{|U?^<WupwZ}@>NFZuypyY{1;(&<Zj?3dCkun<
z1)5w-Wm-T>SC|ucV&R5M2Re@pN;hUp-ZMk;x)B<7j{{8p#>HgnFieqGk)n#5Q<M~+
z+)z!N<)q_SJ_k9z$78R7cYDq+D^k3cE8^N&7~7pq*sJJYrV5Ec8jS1;+!W_?liV3D
z^}L6vB%6_}D3hF8?p00yU{5KG749Q?D%#=kfmh^%NMZQcpj`iXR&NiLeIzu&u3HSj
zB_Ooznoj~LIS-_VWTfkYfo?0H=OHePclR5A3%2Tf+iOLyYrPw>&PC%6r&oknrO}{=
z@Qrd+-m+d!3wl4BeVt@)zf%v>S3a^zR*;l~cI)71zxVJjYgLGfoQvHRP5ChPY>>U*
zv-jj5vCFa)e>+*Fd3}S$CW-RX@=pB93l*NnNc0U7yWN|;`WnvyBwpM->h1R<q#f@b
z?l)<p?yhokZXLAioW9O)dp#x1#C`cgq7*Ojw9Fz+LWYyC$-U%($jG0P&rqcTsdlhF
z%gbBxqtxxWA4!E)5SHNotVn8E5vFfR)5W4Jr;D+K$kH!O)?{!&zLTC7lkz0JSj}q%
zEg?*8mLg3N6%ms2k!g`6EgZ_yEFmJ~v0;#h{677hIFk8^J$W<py!ko<sLA`8hI!2D
JH5r|__Yc#-JK+ET

diff --git a/ariaec/protmap.py b/ariaec/protmap.py
index 9074655..93a6c4c 100644
--- a/ariaec/protmap.py
+++ b/ariaec/protmap.py
@@ -200,11 +200,12 @@ class ProteinMap(Map):
             minticks = tickmin(self, shift=1)  # Nb graduations
 
             self._maplot = sns.heatmap(self, square=True, cbar=False,
-                                       linewidths=1, vmax=1, vmin=-1,
+                                       linewidths=0.5, vmax=1, vmin=-1,
                                        cmap=sns.diverging_palette(20, 220, n=7,
                                                                   as_cmap=True),
                                        xticklabels=minticks[0],
-                                       yticklabels=minticks[1])
+                                       yticklabels=minticks[1],
+                                       linecolor="grey")
         return self._maplot
 
     def saveplot(self, outdir='', outprefix="protein", size_fig=10,
@@ -269,7 +270,7 @@ class ProteinMap(Map):
                 protmap.__class__.__name__, self.__class__.__name__))
             return None
         else:
-            cmplist = protmap.contact_list()
+            cmplist = protmap.contact_list(human_idx=True)
 
             ymax = len(self.sequence) - 1
             if protmap.contact_flags:
@@ -286,19 +287,23 @@ class ProteinMap(Map):
                     color = pal[i]
                     mark = Line2D.filled_markers[i]
                     for x, y in zip(xind, yind):
-                        self.maplot.axes.scatter(x, y, s=10, c=color,
-                                                 linewidths=0, alpha=alpha,
+                        self.maplot.axes.scatter(x, y, s=8, c=color,
+                                                 linewidths=0.1, alpha=alpha,
                                                  marker=mark)
             else:
+                logger.info("Contact list: %s" % cmplist)
                 xind = [x - .5 for x in
                         zip(*cmplist)[0] + zip(*cmplist)[1]]
                 yind = [ymax - y + 1.5 for y in
                         zip(*cmplist)[1] + zip(*cmplist)[0]]
+                logger.debug("Xind: %s" % xind)
+                logger.debug("Yind: %s" % yind)
                 color = "red"
                 # width = [0.3 for _ in xind]
                 # for x, y, h in zip(xind, yind, width):
                 for x, y in zip(xind, yind):
-                    self.maplot.axes.scatter(x, y, s=10, c=color, linewidths=0,
+                    self.maplot.axes.scatter(x, y, s=30, c=color,
+                                             linewidths=0,
                                              alpha=alpha)
             if save_fig:
                 self.saveplot(**kwargs)
@@ -1239,7 +1244,9 @@ class MapFilter:
 
         # Contactmap always filtered
         # TODO: could set a treshold instead of n_factor
-        nb_c = int(len(mapdict["contactmap"].sequence) * int(
+        logger.info("Setting contact number with treshold %s" %
+                    self.settings.get("n_factor"))
+        nb_c = int(len(mapdict["contactmap"].sequence) * float(
             self.settings.get("n_factor")))
         nb_c = nb_c if nb_c < len(mapdict["contactmap"].contactset()) else len(
             mapdict["contactmap"].contactset())
@@ -1292,8 +1299,8 @@ class MapFilter:
             for clash_t in sorted(clash_dict.keys()):
                 if clash_dict[clash_t] and raw_contact in clash_dict[clash_t]:
                     clash = meta_clash[clash_t]["flag"]
-                    meta_clash[clash_t]["msg"] += """\
-{clash_type} flag at pair {pair_nb} : res {res1} and res {res2} {clash_desc}
+                    meta_clash[clash_t]["msg"] += """
+{clash_type} flag at pair {pair_nb} : res {res1} and res {res2} {clash_desc}\
 """.format(clash_type=clash, pair_nb=icontact + 1,
                         clash_desc=desc_dict.get(raw_contact, ''),
                         res1=contact[0], res2=contact[1])
@@ -1305,9 +1312,9 @@ class MapFilter:
                 else:
                     op = "added"
                     ctype = clash
-                meta_clash[clash_t]["warn"] += r"\n/!\ Clash: {clash_desc} {" \
-                                               r"clash} flag for contact " \
-                                               r"{res_pos} ({res1}, {res2})".format(
+                meta_clash[clash_t]["warn"] += "\n/!\ Clash: {clash_desc} {" \
+                                               "clash} flag for contact " \
+                                               "{res_pos} ({res1}, {res2})".format(
                     clash_desc=op, clash=ctype, res_pos=icontact + 1,
                     res1=contact[0], res2=contact[1])
 
@@ -1315,6 +1322,7 @@ class MapFilter:
             titleprint(out, progname=__doc__, desc='Contacts filter')
             for flt in ("nd", "pos", "cons", "ssclash", "cys"):
                 out.write('''
+
 {filter_desc}
 {hd}
 '''.format(filter_desc=meta_clash[flt]["desc"].capitalize(),
diff --git a/ariaec/protmap.pyc b/ariaec/protmap.pyc
index 61242a0e543a28f9c03da61b0534eb27a1e2a040..ebcc12d81cb6c0cffbdbad8743f6fb9a35d0eb05 100644
GIT binary patch
delta 5023
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
PwQaz5r!CPI8!!JC(z|;5

delta 4810
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
R*ecVXPal<@nVys?{}(bQN4Ed~

-- 
GitLab