diff -Nru mmass-3.12.1/configs/aminoacids.xml mmass-4.0.0/configs/aminoacids.xml --- mmass-3.12.1/configs/aminoacids.xml 2011-04-14 18:24:45.000000000 +0000 +++ mmass-4.0.0/configs/aminoacids.xml 1970-01-01 00:00:00.000000000 +0000 @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff -Nru mmass-3.12.1/configs/compounds.xml mmass-4.0.0/configs/compounds.xml --- mmass-3.12.1/configs/compounds.xml 2011-04-14 14:17:41.000000000 +0000 +++ mmass-4.0.0/configs/compounds.xml 2011-11-11 13:18:19.000000000 +0000 @@ -1,6 +1,6 @@ - + Fatty Acyls [FA] with formula: C40H66O5 Fatty Acyls [FA] with formula: C13H25NO5 @@ -14,48 +14,40 @@ Fatty Acyls [FA] with formula: C47H75N5O8 Fatty Acyls [FA] with formula: C2H4O2 Fatty Acyls [FA] with formula: C3H6O2 - Fatty Acyls [FA] with formula: C22H44O2 - Fatty Acyls [FA] with formula: C23H46O2 - Fatty Acyls [FA] with formula: C24H48O2 - Fatty Acyls [FA] with formula: C25H50O2 - Fatty Acyls [FA] with formula: C26H52O2 - Fatty Acyls [FA] with formula: C27H54O2 - Fatty Acyls [FA] with formula: C28H56O2 - Fatty Acyls [FA] with formula: C29H58O2 Fatty Acyls [FA] with formula: C33H66O2 Fatty Acyls [FA] with formula: C36H72O2 Fatty Acyls [FA] with formula: CH2O2 Fatty Acyls [FA] with formula: C31H62O2 - Fatty Acyls [FA] with formula: C21H42O2 Fatty Acyls [FA] with formula: C12H24O2 Fatty Acyls [FA] with formula: C4H8O2 Fatty Acyls [FA] with formula: C5H10O2 Fatty Acyls [FA] with formula: C7H14O2 - Fatty Acyls [FA] with formula: C11H22O2 + Fatty Acyls [FA] with formula: C11H22O2 Fatty Acyls [FA] with formula: C17H34O2 Fatty Acyls [FA] with formula: C5H8O2 Fatty Acyls [FA] with formula: C6H10O2 - Fatty Acyls [FA] with formula: C11H20O2 + Fatty Acyls [FA] with formula: C11H20O2 Fatty Acyls [FA] with formula: C14H26O2 - Fatty Acyls [FA] with formula: C16H30O2 - Fatty Acyls [FA] with formula: C22H42O2 - Fatty Acyls [FA] with formula: C21H40O2 - Fatty Acyls [FA] with formula: C19H36O2 - Fatty Acyls [FA] with formula: C21H38O2 + Fatty Acyls [FA] with formula: C22H42O2 + Fatty Acyls [FA] with formula: C21H40O2 + Fatty Acyls [FA] with formula: C19H36O2 + Fatty Acyls [FA] with formula: C21H42O2 + Fatty Acyls [FA] with formula: C22H44O2 + Fatty Acyls [FA] with formula: C23H46O2 + Fatty Acyls [FA] with formula: C24H48O2 Fatty Acyls [FA] with formula: C25H46O2 Fatty Acyls [FA] with formula: C30H60O2 Fatty Acyls [FA] with formula: C8H16O2 Fatty Acyls [FA] with formula: C10H20O2 - Fatty Acyls [FA] with formula: C15H30O2 - Fatty Acyls [FA] with formula: C16H32O2 - Fatty Acyls [FA] with formula: C13H26O2 - Fatty Acyls [FA] with formula: C27H52O2 + Fatty Acyls [FA] with formula: C15H30O2 + Fatty Acyls [FA] with formula: C16H32O2 + Fatty Acyls [FA] with formula: C13H26O2 + Fatty Acyls [FA] with formula: C27H52O2 Fatty Acyls [FA] with formula: C41H82O2 Fatty Acyls [FA] with formula: C14H28O2 Fatty Acyls [FA] with formula: C38H76O2 Fatty Acyls [FA] with formula: C5H8O3 Fatty Acyls [FA] with formula: C6H10O3 - Fatty Acyls [FA] with formula: C5H8O4 Fatty Acyls [FA] with formula: C37H74O2 Fatty Acyls [FA] with formula: C39H78O2 Fatty Acyls [FA] with formula: C40H80O2 @@ -63,6 +55,11 @@ Fatty Acyls [FA] with formula: C45H90O2 Fatty Acyls [FA] with formula: C46H92O2 Fatty Acyls [FA] with formula: C48H96O2 + Fatty Acyls [FA] with formula: C25H50O2 + Fatty Acyls [FA] with formula: C26H52O2 + Fatty Acyls [FA] with formula: C27H54O2 + Fatty Acyls [FA] with formula: C28H56O2 + Fatty Acyls [FA] with formula: C29H58O2 Fatty Acyls [FA] with formula: C32H64O2 Fatty Acyls [FA] with formula: C34H68O2 Fatty Acyls [FA] with formula: C35H70O2 @@ -81,45 +78,44 @@ Fatty Acyls [FA] with formula: C24H48O3 Fatty Acyls [FA] with formula: C27H54O3 Fatty Acyls [FA] with formula: C28H56O3 + Fatty Acyls [FA] with formula: C29H56O2 + Fatty Acyls [FA] with formula: C37H62O2 + Fatty Acyls [FA] with formula: C27H50O2 + Fatty Acyls [FA] with formula: C29H54O2 + Fatty Acyls [FA] with formula: C19H26O2 + Fatty Acyls [FA] with formula: C20H32O2 Fatty Acyls [FA] with formula: C4H6O2 - Fatty Acyls [FA] with formula: C13H24O2 - Fatty Acyls [FA] with formula: C24H46O2 - Fatty Acyls [FA] with formula: C26H50O2 - Fatty Acyls [FA] with formula: C28H54O2 - Fatty Acyls [FA] with formula: C30H58O2 - Fatty Acyls [FA] with formula: C32H62O2 + Fatty Acyls [FA] with formula: C24H46O2 + Fatty Acyls [FA] with formula: C26H50O2 + Fatty Acyls [FA] with formula: C28H54O2 + Fatty Acyls [FA] with formula: C30H58O2 + Fatty Acyls [FA] with formula: C32H62O2 Fatty Acyls [FA] with formula: C5H6O2 - Fatty Acyls [FA] with formula: C6H8O2 - Fatty Acyls [FA] with formula: C22H40O2 - Fatty Acyls [FA] with formula: C26H48O2 + Fatty Acyls [FA] with formula: C6H8O2 + Fatty Acyls [FA] with formula: C26H48O2 Fatty Acyls [FA] with formula: C3H4O2 Fatty Acyls [FA] with formula: C10H14O2 Fatty Acyls [FA] with formula: C11H18O2 - Fatty Acyls [FA] with formula: C12H20O2 + Fatty Acyls [FA] with formula: C12H20O2 Fatty Acyls [FA] with formula: C12H14O2 Fatty Acyls [FA] with formula: C14H18O2 - Fatty Acyls [FA] with formula: C16H24O2 - Fatty Acyls [FA] with formula: C17H32O2 - Fatty Acyls [FA] with formula: C18H26O2 - Fatty Acyls [FA] with formula: C19H34O2 - Fatty Acyls [FA] with formula: C22H38O2 - Fatty Acyls [FA] with formula: C23H44O2 - Fatty Acyls [FA] with formula: C24H44O2 - Fatty Acyls [FA] with formula: C25H48O2 - Fatty Acyls [FA] with formula: C26H46O2 + Fatty Acyls [FA] with formula: C17H32O2 + Fatty Acyls [FA] with formula: C18H26O2 + Fatty Acyls [FA] with formula: C23H44O2 + Fatty Acyls [FA] with formula: C25H48O2 + Fatty Acyls [FA] with formula: C26H46O2 Fatty Acyls [FA] with formula: C9H14O2 Fatty Acyls [FA] with formula: C10H12O2 Fatty Acyls [FA] with formula: C12H16O2 Fatty Acyls [FA] with formula: C12H12O2 - Fatty Acyls [FA] with formula: C17H26O2 + Fatty Acyls [FA] with formula: C17H26O2 Fatty Acyls [FA] with formula: C17H22O2 Fatty Acyls [FA] with formula: C17H28O2 - Fatty Acyls [FA] with formula: C19H26O2 - Fatty Acyls [FA] with formula: C18H28O2 - Fatty Acyls [FA] with formula: C18H24O2 + Fatty Acyls [FA] with formula: C18H28O2 + Fatty Acyls [FA] with formula: C18H24O2 Fatty Acyls [FA] with formula: C15H18O2 - Fatty Acyls [FA] with formula: C18H30O2 - Fatty Acyls [FA] with formula: C18H32O2 + Fatty Acyls [FA] with formula: C18H30O2 + Fatty Acyls [FA] with formula: C18H32O2 Fatty Acyls [FA] with formula: C14H16O2 Fatty Acyls [FA] with formula: C13H22O2 Fatty Acyls [FA] with formula: C16H31BrO2 @@ -128,7 +124,6 @@ Fatty Acyls [FA] with formula: C22H24O2 Fatty Acyls [FA] with formula: C22H28O2 Fatty Acyls [FA] with formula: C22H32O2 - Fatty Acyls [FA] with formula: C20H32O2 Fatty Acyls [FA] with formula: C20H24O2 Fatty Acyls [FA] with formula: C20H28O2 Fatty Acyls [FA] with formula: C27H46O2 @@ -144,49 +139,94 @@ Fatty Acyls [FA] with formula: C25H42O2 Fatty Acyls [FA] with formula: C24H24O2 Fatty Acyls [FA] with formula: C24H28O2 - Fatty Acyls [FA] with formula: C27H50O2 Fatty Acyls [FA] with formula: C11H10O2 Fatty Acyls [FA] with formula: C11H8O2 - Fatty Acyls [FA] with formula: C10H18O2 + Fatty Acyls [FA] with formula: C10H18O2 Fatty Acyls [FA] with formula: C7H8O2 Fatty Acyls [FA] with formula: C10H10O2 - Fatty Acyls [FA] with formula: C10H16O2 + Fatty Acyls [FA] with formula: C10H16O2 Fatty Acyls [FA] with formula: C12H20O3 - Fatty Acyls [FA] with formula: C12H22O2 - Fatty Acyls [FA] with formula: C14H24O2 - Fatty Acyls [FA] with formula: C24H36O2 + Fatty Acyls [FA] with formula: C12H22O2 + Fatty Acyls [FA] with formula: C24H36O2 Fatty Acyls [FA] with formula: C28H40O2 Fatty Acyls [FA] with formula: C21H32O2 + Fatty Acyls [FA] with formula: C26H44O2 + Fatty Acyls [FA] with formula: C28H48O2 + Fatty Acyls [FA] with formula: C30H52O2 + Fatty Acyls [FA] with formula: C32H56O2 + Fatty Acyls [FA] with formula: C34H60O2 + Fatty Acyls [FA] with formula: C36H64O2 + Fatty Acyls [FA] with formula: C38H68O2 + Fatty Acyls [FA] with formula: C26H40O2 + Fatty Acyls [FA] with formula: C28H44O2 + Fatty Acyls [FA] with formula: C30H48O2 + Fatty Acyls [FA] with formula: C32H52O2 + Fatty Acyls [FA] with formula: C34H56O2 + Fatty Acyls [FA] with formula: C36H60O2 + Fatty Acyls [FA] with formula: C38H64O2 + Fatty Acyls [FA] with formula: C26H42O2 + Fatty Acyls [FA] with formula: C28H46O2 + Fatty Acyls [FA] with formula: C30H50O2 + Fatty Acyls [FA] with formula: C32H54O2 + Fatty Acyls [FA] with formula: C34H58O2 + Fatty Acyls [FA] with formula: C36H62O2 + Fatty Acyls [FA] with formula: C38H66O2 + Fatty Acyls [FA] with formula: C24H34O2 + Fatty Acyls [FA] with formula: C23H34O2 + Fatty Acyls [FA] with formula: C21H38O2 + Fatty Acyls [FA] with formula: C21H36O2 + Fatty Acyls [FA] with formula: C16H24O2 + Fatty Acyls [FA] with formula: C30H54O2 + Fatty Acyls [FA] with formula: C28H52O2 + Fatty Acyls [FA] with formula: C28H50O2 + Fatty Acyls [FA] with formula: C30H56O2 + Fatty Acyls [FA] with formula: C27H49BrO2 + Fatty Acyls [FA] with formula: C28H51BrO2 + Fatty Acyls [FA] with formula: C29H53BrO2 + Fatty Acyls [FA] with formula: C13H24O2 + Fatty Acyls [FA] with formula: C16H30O2 + Fatty Acyls [FA] with formula: C18H34O2 + Fatty Acyls [FA] with formula: C14H24O2 + Fatty Acyls [FA] with formula: C20H36O2 + Fatty Acyls [FA] with formula: C19H34O2 + Fatty Acyls [FA] with formula: C24H44O2 + Fatty Acyls [FA] with formula: C24H42O2 + Fatty Acyls [FA] with formula: C27H48O2 + Fatty Acyls [FA] with formula: C29H52O2 Fatty Acyls [FA] with formula: C18H34O6 Fatty Acyls [FA] with formula: C19H30O6 Fatty Acyls [FA] with formula: C20H36O4 Fatty Acyls [FA] with formula: C23H42O4 Fatty Acyls [FA] with formula: C19H32O4 Fatty Acyls [FA] with formula: C19H32O6 + Fatty Acyls [FA] with formula: C22H36O6 Fatty Acyls [FA] with formula: C19H32O8 Fatty Acyls [FA] with formula: C8H16O3 Fatty Acyls [FA] with formula: C10H20O3 Fatty Acyls [FA] with formula: C13H26O3 - Fatty Acyls [FA] with formula: C14H28O3 + Fatty Acyls [FA] with formula: C14H28O3 Fatty Acyls [FA] with formula: C18H36O3 Fatty Acyls [FA] with formula: C19H38O3 Fatty Acyls [FA] with formula: C21H42O3 Fatty Acyls [FA] with formula: C22H44O3 Fatty Acyls [FA] with formula: C14H28O4 - Fatty Acyls [FA] with formula: C18H36O4 + Fatty Acyls [FA] with formula: C18H36O4 Fatty Acyls [FA] with formula: C20H40O4 Fatty Acyls [FA] with formula: C6H12O5 - Fatty Acyls [FA] with formula: C16H32O5 + Fatty Acyls [FA] with formula: C16H32O5 Fatty Acyls [FA] with formula: C18H36O5 Fatty Acyls [FA] with formula: C18H36O6 - Fatty Acyls [FA] with formula: C18H34O3 + Fatty Acyls [FA] with formula: C16H30O3 Fatty Acyls [FA] with formula: C25H48O3 Fatty Acyls [FA] with formula: C18H34O4 Fatty Acyls [FA] with formula: C18H34O5 Fatty Acyls [FA] with formula: C17H26O5 Fatty Acyls [FA] with formula: C13H18O5 + Fatty Acyls [FA] with formula: C11H22O3 Fatty Acyls [FA] with formula: C15H30O4 Fatty Acyls [FA] with formula: C16H32O4 + Fatty Acyls [FA] with formula: C17H28O3 + Fatty Acyls [FA] with formula: C18H34O3 Fatty Acyls [FA] with formula: C22H44O4 Fatty Acyls [FA] with formula: C23H46O3 Fatty Acyls [FA] with formula: C25H50O3 @@ -199,30 +239,30 @@ Fatty Acyls [FA] with formula: C20H40O3 Fatty Acyls [FA] with formula: C20H38O3 Fatty Acyls [FA] with formula: C17H26O3 - Fatty Acyls [FA] with formula: C17H30O3 + Fatty Acyls [FA] with formula: C17H30O3 Fatty Acyls [FA] with formula: C7H14O3 Fatty Acyls [FA] with formula: C7H10O3 - Fatty Acyls [FA] with formula: C26H52O3 - Fatty Acyls [FA] with formula: C16H30O3 + Fatty Acyls [FA] with formula: C26H52O3 Fatty Acyls [FA] with formula: C6H8O3 Fatty Acyls [FA] with formula: C9H18O3 Fatty Acyls [FA] with formula: C18H24O3 Fatty Acyls [FA] with formula: C18H26O3 Fatty Acyls [FA] with formula: C19H32O2 Fatty Acyls [FA] with formula: C15H30O3 - Fatty Acyls [FA] with formula: C11H22O3 Fatty Acyls [FA] with formula: C6H12O4 - Fatty Acyls [FA] with formula: C4H8O3 - Fatty Acyls [FA] with formula: C7H12O3 Fatty Acyls [FA] with formula: C5H10O4 Fatty Acyls [FA] with formula: C4H8O4 Fatty Acyls [FA] with formula: C5H10O5 Fatty Acyls [FA] with formula: C6H12O3 Fatty Acyls [FA] with formula: C5H10O3 - Fatty Acyls [FA] with formula: C16H32O3 + Fatty Acyls [FA] with formula: C16H32O3 Fatty Acyls [FA] with formula: C6H13O7P Fatty Acyls [FA] with formula: C6H14O10P2 - Fatty Acyls [FA] with formula: C4H6O3 + Fatty Acyls [FA] with formula: C4H8O3 + Fatty Acyls [FA] with formula: C24H46O4 + Fatty Acyls [FA] with formula: C18H32O3 + Fatty Acyls [FA] with formula: C4H6O3 + Fatty Acyls [FA] with formula: C7H12O3 Fatty Acyls [FA] with formula: C8H14O3 Fatty Acyls [FA] with formula: C9H16O3 Fatty Acyls [FA] with formula: C3H4O3 @@ -254,11 +294,10 @@ Fatty Acyls [FA] with formula: C6H7NO3 Fatty Acyls [FA] with formula: C4H4O6 Fatty Acyls [FA] with formula: C6H8O7 - Fatty Acyls [FA] with formula: C18H30O4 + Fatty Acyls [FA] with formula: C18H30O4 Fatty Acyls [FA] with formula: C19H32O3 - Fatty Acyls [FA] with formula: C18H28O3 - Fatty Acyls [FA] with formula: C18H32O3 - Fatty Acyls [FA] with formula: C16H26O3 + Fatty Acyls [FA] with formula: C18H28O3 + Fatty Acyls [FA] with formula: C16H26O3 Fatty Acyls [FA] with formula: C19H34O4 Fatty Acyls [FA] with formula: C20H38O5 Fatty Acyls [FA] with formula: C19H36O5 @@ -285,11 +324,11 @@ Fatty Acyls [FA] with formula: C16H30F2O2 Fatty Acyls [FA] with formula: C16H31ClO3 Fatty Acyls [FA] with formula: C18H35FO2 + Fatty Acyls [FA] with formula: C16H31ClO2 Fatty Acyls [FA] with formula: C13H27NO2 Fatty Acyls [FA] with formula: C10H21NO2 Fatty Acyls [FA] with formula: C11H23NO2 Fatty Acyls [FA] with formula: C12H25NO2 - Fatty Acyls [FA] with formula: C14H29NO2 Fatty Acyls [FA] with formula: C9H19NO2 Fatty Acyls [FA] with formula: C7H15NO2 Fatty Acyls [FA] with formula: C16H33NO2 @@ -297,10 +336,10 @@ Fatty Acyls [FA] with formula: C5H8N2O2 Fatty Acyls [FA] with formula: C3H7NO3 Fatty Acyls [FA] with formula: C5H11NO2 - Fatty Acyls [FA] with formula: C6H13NO2 + Fatty Acyls [FA] with formula: C6H13NO2 Fatty Acyls [FA] with formula: C3H8N2O2 Fatty Acyls [FA] with formula: C4H10N2O2 - Fatty Acyls [FA] with formula: C4H9NO2 + Fatty Acyls [FA] with formula: C4H9NO2 Fatty Acyls [FA] with formula: C5H9NO3 Fatty Acyls [FA] with formula: C8H17NO2 Fatty Acyls [FA] with formula: C25H45NO2 @@ -314,8 +353,8 @@ Fatty Acyls [FA] with formula: C16H22O2 Fatty Acyls [FA] with formula: C24H40O2 Fatty Acyls [FA] with formula: C24H38O2 - Fatty Acyls [FA] with formula: C19H30O2 - Fatty Acyls [FA] with formula: C20H34O2 + Fatty Acyls [FA] with formula: C19H30O2 + Fatty Acyls [FA] with formula: C20H34O2 Fatty Acyls [FA] with formula: C15H23BrO2 Fatty Acyls [FA] with formula: C22H38O3 Fatty Acyls [FA] with formula: C12H16O5 @@ -328,14 +367,13 @@ Fatty Acyls [FA] with formula: C11H20O4 Fatty Acyls [FA] with formula: C12H14O4 Fatty Acyls [FA] with formula: C12H22O4 - Fatty Acyls [FA] with formula: C13H24O4 + Fatty Acyls [FA] with formula: C13H24O4 Fatty Acyls [FA] with formula: C14H26O4 Fatty Acyls [FA] with formula: C15H28O4 Fatty Acyls [FA] with formula: C17H32O4 Fatty Acyls [FA] with formula: C21H40O4 Fatty Acyls [FA] with formula: C22H42O4 Fatty Acyls [FA] with formula: C23H44O4 - Fatty Acyls [FA] with formula: C24H46O4 Fatty Acyls [FA] with formula: C26H50O4 Fatty Acyls [FA] with formula: C3H4O4 Fatty Acyls [FA] with formula: C30H58O4 @@ -345,7 +383,7 @@ Fatty Acyls [FA] with formula: C16H30O4 Fatty Acyls [FA] with formula: C4H4O5 Fatty Acyls [FA] with formula: C7H10O6 - Fatty Acyls [FA] with formula: C5H6O4 + Fatty Acyls [FA] with formula: C5H6O4 Fatty Acyls [FA] with formula: C7H12O5 Fatty Acyls [FA] with formula: C7H6O6 Fatty Acyls [FA] with formula: C8H8O6 @@ -358,7 +396,7 @@ Fatty Acyls [FA] with formula: C17H30O7 Fatty Acyls [FA] with formula: C10H18O5 Fatty Acyls [FA] with formula: C6H7NO4 - Fatty Acyls [FA] with formula: C6H10O4 + Fatty Acyls [FA] with formula: C6H10O4 Fatty Acyls [FA] with formula: C8H12O4 Fatty Acyls [FA] with formula: C7H12O4 Fatty Acyls [FA] with formula: C6H10O5 @@ -367,6 +405,7 @@ Fatty Acyls [FA] with formula: C14H26O5 Fatty Acyls [FA] with formula: C6H11NO4 Fatty Acyls [FA] with formula: C7H14N2O4 + Fatty Acyls [FA] with formula: C5H8O4 Fatty Acyls [FA] with formula: C6H10O8 Fatty Acyls [FA] with formula: C4H5NO4 Fatty Acyls [FA] with formula: C4H6O4 @@ -375,7 +414,7 @@ Fatty Acyls [FA] with formula: C21H38O4 Fatty Acyls [FA] with formula: C21H36O4 Fatty Acyls [FA] with formula: C18H30O3 - Fatty Acyls [FA] with formula: C18H32O4 + Fatty Acyls [FA] with formula: C18H32O4 Fatty Acyls [FA] with formula: C14H22O3 Fatty Acyls [FA] with formula: C16H28O3 Fatty Acyls [FA] with formula: C14H24O3 @@ -384,7 +423,9 @@ Fatty Acyls [FA] with formula: C18H30O9 Fatty Acyls [FA] with formula: C13H20O3 Fatty Acyls [FA] with formula: C12H18O3 - Fatty Acyls [FA] with formula: C20H36O3 + Fatty Acyls [FA] with formula: C20H36O3 + Fatty Acyls [FA] with formula: C20H34O8 + Fatty Acyls [FA] with formula: C26H42O4 Fatty Acyls [FA] with formula: C21H34O4 Fatty Acyls [FA] with formula: C23H38O4 Fatty Acyls [FA] with formula: C22H28O5 @@ -394,12 +435,10 @@ Fatty Acyls [FA] with formula: C23H32O5 Fatty Acyls [FA] with formula: C22H36O4 Fatty Acyls [FA] with formula: C21H34O5 - Fatty Acyls [FA] with formula: C22H36O6 Fatty Acyls [FA] with formula: C23H38O6 Fatty Acyls [FA] with formula: C24H38O8 Fatty Acyls [FA] with formula: C25H40O8 Fatty Acyls [FA] with formula: C21H32O4 - Fatty Acyls [FA] with formula: C22H41NO3 Fatty Acyls [FA] with formula: C23H33NO4 Fatty Acyls [FA] with formula: C26H38O5 Fatty Acyls [FA] with formula: C20H36O5 @@ -407,14 +446,12 @@ Fatty Acyls [FA] with formula: C22H37NO5 Fatty Acyls [FA] with formula: C18H32O5 Fatty Acyls [FA] with formula: C22H38O5 - Fatty Acyls [FA] with formula: C22H32O3 Fatty Acyls [FA] with formula: C20H34O4 Fatty Acyls [FA] with formula: C20H36O6 - Fatty Acyls [FA] with formula: C20H30O5 - Fatty Acyls [FA] with formula: C18H30O5 - Fatty Acyls [FA] with formula: C20H32O5 - Fatty Acyls [FA] with formula: C20H30O3 - Fatty Acyls [FA] with formula: C20H28O3 + Fatty Acyls [FA] with formula: C20H30O5 + Fatty Acyls [FA] with formula: C18H30O5 + Fatty Acyls [FA] with formula: C20H30O3 + Fatty Acyls [FA] with formula: C20H28O3 Fatty Acyls [FA] with formula: C20H38O4 Fatty Acyls [FA] with formula: C23H40O7 Fatty Acyls [FA] with formula: C23H40O8 @@ -423,8 +460,8 @@ Fatty Acyls [FA] with formula: C23H41NO6 Fatty Acyls [FA] with formula: C16H24O7 Fatty Acyls [FA] with formula: C22H36O5 - Fatty Acyls [FA] with formula: C20H30O4 - Fatty Acyls [FA] with formula: C20H28O4 + Fatty Acyls [FA] with formula: C20H30O4 + Fatty Acyls [FA] with formula: C20H28O4 Fatty Acyls [FA] with formula: C23H36O6 Fatty Acyls [FA] with formula: C23H34O5 Fatty Acyls [FA] with formula: C22H39NO5 @@ -445,13 +482,15 @@ Fatty Acyls [FA] with formula: C19H34O5 Fatty Acyls [FA] with formula: C30H47N3O10S Fatty Acyls [FA] with formula: C25H40N2O7S - Fatty Acyls [FA] with formula: C17H28O3 Fatty Acyls [FA] with formula: C20H34O3 Fatty Acyls [FA] with formula: C21H34O8 - Fatty Acyls [FA] with formula: C20H32O4 - Fatty Acyls [FA] with formula: C20H32O6 - Fatty Acyls [FA] with formula: C20H32O3 - Fatty Acyls [FA] with formula: C20H34O5 + Fatty Acyls [FA] with formula: C20H32O4 + Fatty Acyls [FA] with formula: C20H32O6 + Fatty Acyls [FA] with formula: C20H32O3 + Fatty Acyls [FA] with formula: C30H49N3O10S + Fatty Acyls [FA] with formula: C25H42N2O7S + Fatty Acyls [FA] with formula: C20H32O5 + Fatty Acyls [FA] with formula: C20H34O5 Fatty Acyls [FA] with formula: C25H34O7 Fatty Acyls [FA] with formula: C27H36O9 Fatty Acyls [FA] with formula: C21H29ClO4 @@ -476,12 +515,15 @@ Fatty Acyls [FA] with formula: C23H33ClO6 Fatty Acyls [FA] with formula: C22H30O4 Fatty Acyls [FA] with formula: C22H32O5 - Fatty Acyls [FA] with formula: C22H30O3 Fatty Acyls [FA] with formula: C22H34O4 Fatty Acyls [FA] with formula: C22H34O5 - Fatty Acyls [FA] with formula: C22H32O4 - Fatty Acyls [FA] with formula: C22H34O2 - Fatty Acyls [FA] with formula: C22H36O2 + Fatty Acyls [FA] with formula: C22H32O4 + Fatty Acyls [FA] with formula: C22H30O3 + Fatty Acyls [FA] with formula: C22H32O3 + Fatty Acyls [FA] with formula: C22H38O2 + Fatty Acyls [FA] with formula: C22H34O2 + Fatty Acyls [FA] with formula: C22H40O2 + Fatty Acyls [FA] with formula: C22H36O2 Fatty Acyls [FA] with formula: C12H26O Fatty Acyls [FA] with formula: C26H54O Fatty Acyls [FA] with formula: C28H58O @@ -500,7 +542,7 @@ Fatty Acyls [FA] with formula: C15H30O Fatty Acyls [FA] with formula: C20H40O Fatty Acyls [FA] with formula: C17H34O - Fatty Acyls [FA] with formula: C18H34O + Fatty Acyls [FA] with formula: C18H34O Fatty Acyls [FA] with formula: C6H12O Fatty Acyls [FA] with formula: C10H22O Fatty Acyls [FA] with formula: C18H28O @@ -526,19 +568,19 @@ Fatty Acyls [FA] with formula: C7H16O Fatty Acyls [FA] with formula: C9H20O Fatty Acyls [FA] with formula: C8H18O - Fatty Acyls [FA] with formula: C9H18O2 + Fatty Acyls [FA] with formula: C9H18O2 Fatty Acyls [FA] with formula: C11H19ClO Fatty Acyls [FA] with formula: C11H24O Fatty Acyls [FA] with formula: C12H18F4O Fatty Acyls [FA] with formula: C12H20F2O Fatty Acyls [FA] with formula: C13H28O - Fatty Acyls [FA] with formula: C14H28O + Fatty Acyls [FA] with formula: C14H28O Fatty Acyls [FA] with formula: C14H26O Fatty Acyls [FA] with formula: C17H36O - Fatty Acyls [FA] with formula: C15H28O + Fatty Acyls [FA] with formula: C15H28O Fatty Acyls [FA] with formula: C15H32O Fatty Acyls [FA] with formula: C16H32O - Fatty Acyls [FA] with formula: C16H30O + Fatty Acyls [FA] with formula: C16H30O Fatty Acyls [FA] with formula: C20H36O Fatty Acyls [FA] with formula: C18H36O Fatty Acyls [FA] with formula: C18H32O @@ -546,28 +588,27 @@ Fatty Acyls [FA] with formula: C20H42O Fatty Acyls [FA] with formula: C24H50O Fatty Acyls [FA] with formula: C26H52O - Fatty Acyls [FA] with formula: C14H22O2 + Fatty Acyls [FA] with formula: C14H22O2 Fatty Acyls [FA] with formula: C14H21F5O2 Fatty Acyls [FA] with formula: C14H24F2O2 - Fatty Acyls [FA] with formula: C15H28O2 + Fatty Acyls [FA] with formula: C15H28O2 Fatty Acyls [FA] with formula: C15H24O2 Fatty Acyls [FA] with formula: C15H26O2 - Fatty Acyls [FA] with formula: C16H26O2 - Fatty Acyls [FA] with formula: C16H28O2 + Fatty Acyls [FA] with formula: C16H26O2 + Fatty Acyls [FA] with formula: C16H28O2 Fatty Acyls [FA] with formula: C16H27F3O2 Fatty Acyls [FA] with formula: C16H29FO2 - Fatty Acyls [FA] with formula: C17H30O2 - Fatty Acyls [FA] with formula: C18H34O2 + Fatty Acyls [FA] with formula: C17H30O2 Fatty Acyls [FA] with formula: C18H36O2 - Fatty Acyls [FA] with formula: C19H38O2 - Fatty Acyls [FA] with formula: C20H38O2 - Fatty Acyls [FA] with formula: C20H36O2 - Fatty Acyls [FA] with formula: C20H40O2 + Fatty Acyls [FA] with formula: C19H38O2 + Fatty Acyls [FA] with formula: C20H38O2 + Fatty Acyls [FA] with formula: C20H40O2 Fatty Acyls [FA] with formula: C27H42O2 Fatty Acyls [FA] with formula: C27H56O Fatty Acyls [FA] with formula: C29H60O Fatty Acyls [FA] with formula: C32H66O Fatty Acyls [FA] with formula: C34H70O + Fatty Acyls [FA] with formula: C16H33ClO Fatty Acyls [FA] with formula: C6H10O Fatty Acyls [FA] with formula: C6H8O Fatty Acyls [FA] with formula: C6H6O2 @@ -582,11 +623,11 @@ Fatty Acyls [FA] with formula: C8H10O Fatty Acyls [FA] with formula: C8H12O2 Fatty Acyls [FA] with formula: C8H14O2 - Fatty Acyls [FA] with formula: C9H16O Fatty Acyls [FA] with formula: C9H14O Fatty Acyls [FA] with formula: C9H4O Fatty Acyls [FA] with formula: C9H16O2 Fatty Acyls [FA] with formula: C10H20O + Fatty Acyls [FA] with formula: C10H16O Fatty Acyls [FA] with formula: C10H14O Fatty Acyls [FA] with formula: C10H12O Fatty Acyls [FA] with formula: C10H8O @@ -608,11 +649,11 @@ Fatty Acyls [FA] with formula: C16H31ClO Fatty Acyls [FA] with formula: C16H31BrO Fatty Acyls [FA] with formula: C9H12O - Fatty Acyls [FA] with formula: C10H16O - Fatty Acyls [FA] with formula: C10H18O - Fatty Acyls [FA] with formula: C12H24O - Fatty Acyls [FA] with formula: C12H20O - Fatty Acyls [FA] with formula: C12H22O + Fatty Acyls [FA] with formula: C9H16O + Fatty Acyls [FA] with formula: C10H18O + Fatty Acyls [FA] with formula: C12H24O + Fatty Acyls [FA] with formula: C12H20O + Fatty Acyls [FA] with formula: C12H22O Fatty Acyls [FA] with formula: C14H18O3 Fatty Acyls [FA] with formula: C17H30O Fatty Acyls [FA] with formula: C14H20O @@ -621,18 +662,25 @@ Fatty Acyls [FA] with formula: C15H26O Fatty Acyls [FA] with formula: C16H26O Fatty Acyls [FA] with formula: C20H32O - Fatty Acyls [FA] with formula: C16H28O + Fatty Acyls [FA] with formula: C16H28O Fatty Acyls [FA] with formula: C17H32O Fatty Acyls [FA] with formula: C18H30O Fatty Acyls [FA] with formula: C19H36O Fatty Acyls [FA] with formula: C19H38O Fatty Acyls [FA] with formula: C20H38O - Fatty Acyls [FA] with formula: C34H66O2 - Fatty Acyls [FA] with formula: C35H68O2 + Fatty Acyls [FA] with formula: C34H66O2 + Fatty Acyls [FA] with formula: C35H68O2 Fatty Acyls [FA] with formula: C42H84O2 Fatty Acyls [FA] with formula: C44H88O2 Fatty Acyls [FA] with formula: C36H64O4 Fatty Acyls [FA] with formula: C34H60O4 + Fatty Acyls [FA] with formula: C36H70O2 + Fatty Acyls [FA] with formula: C37H72O2 + Fatty Acyls [FA] with formula: C38H74O2 + Fatty Acyls [FA] with formula: C39H76O2 + Fatty Acyls [FA] with formula: C40H78O2 + Fatty Acyls [FA] with formula: C41H80O2 + Fatty Acyls [FA] with formula: C42H82O2 Fatty Acyls [FA] with formula: C42H82O4 Fatty Acyls [FA] with formula: C41H71NO4 Fatty Acyls [FA] with formula: C27H46N7O17P3S @@ -664,12 +712,12 @@ Fatty Acyls [FA] with formula: C43H74N7O17P3S Fatty Acyls [FA] with formula: C43H70N7O17P3S Fatty Acyls [FA] with formula: C45H74N7O17P3S + Fatty Acyls [FA] with formula: C45H72N7O17P3S Fatty Acyls [FA] with formula: C43H68N7O17P3S Fatty Acyls [FA] with formula: C41H68N7O17P3S Fatty Acyls [FA] with formula: C39H64N7O17P3S Fatty Acyls [FA] with formula: C39H62N7O17P3S Fatty Acyls [FA] with formula: C41H66N7O17P3S - Fatty Acyls [FA] with formula: C45H72N7O17P3S Fatty Acyls [FA] with formula: C43H66N7O17P3S Fatty Acyls [FA] with formula: C45H70N7O17P3S Fatty Acyls [FA] with formula: C43H78N7O17P3S @@ -682,6 +730,10 @@ Fatty Acyls [FA] with formula: C37H64N7O17P3S Fatty Acyls [FA] with formula: C41H70N7O17P3S Fatty Acyls [FA] with formula: C41H64N7O17P3S + Fatty Acyls [FA] with formula: C40H72N7O17P3S + Fatty Acyls [FA] with formula: C45H68N7O17P3S + Fatty Acyls [FA] with formula: C45H70N7O18P3S + Fatty Acyls [FA] with formula: C45H68N7O18P3S Fatty Acyls [FA] with formula: C393H636N95O143PS2 Fatty Acyls [FA] with formula: C393H636N95O142PS2 Fatty Acyls [FA] with formula: C391H632N95O142PS2 @@ -709,8 +761,8 @@ Fatty Acyls [FA] with formula: C21H35NO Fatty Acyls [FA] with formula: C23H39NO Fatty Acyls [FA] with formula: C24H41NO - Fatty Acyls [FA] with formula: C25H43NO - Fatty Acyls [FA] with formula: C23H39NO2 + Fatty Acyls [FA] with formula: C25H43NO + Fatty Acyls [FA] with formula: C23H39NO2 Fatty Acyls [FA] with formula: C24H41NO2 Fatty Acyls [FA] with formula: C26H46N2O Fatty Acyls [FA] with formula: C24H41NO3 @@ -730,10 +782,9 @@ Fatty Acyls [FA] with formula: C26H44FNO Fatty Acyls [FA] with formula: C27H46FNO Fatty Acyls [FA] with formula: C23H39NO3 - Fatty Acyls [FA] with formula: C24H39NO3 + Fatty Acyls [FA] with formula: C24H39NO3 Fatty Acyls [FA] with formula: C22H37NO4S Fatty Acyls [FA] with formula: C29H41NO4 - Fatty Acyls [FA] with formula: C20H39NO3 Fatty Acyls [FA] with formula: C20H41NO4S Fatty Acyls [FA] with formula: C18H35NO3 Fatty Acyls [FA] with formula: C18H37NO4S @@ -742,6 +793,54 @@ Fatty Acyls [FA] with formula: C24H49NO4S Fatty Acyls [FA] with formula: C28H41NO3 Fatty Acyls [FA] with formula: C18H29NO3 + Fatty Acyls [FA] with formula: C25H39NO5 + Fatty Acyls [FA] with formula: C21H39NO5 + Fatty Acyls [FA] with formula: C23H41NO5 + Fatty Acyls [FA] with formula: C27H39NO5 + Fatty Acyls [FA] with formula: C23H43NO5 + Fatty Acyls [FA] with formula: C25H41NO3 + Fatty Acyls [FA] with formula: C27H43NO3 + Fatty Acyls [FA] with formula: C27H45NO3 + Fatty Acyls [FA] with formula: C31H41NO3 + Fatty Acyls [FA] with formula: C27H42N2O3 + Fatty Acyls [FA] with formula: C29H44N2O3 + Fatty Acyls [FA] with formula: C29H46N2O3 + Fatty Acyls [FA] with formula: C25H41NO4 + Fatty Acyls [FA] with formula: C27H43NO4 + Fatty Acyls [FA] with formula: C27H45NO4 + Fatty Acyls [FA] with formula: C19H37NO4 + Fatty Acyls [FA] with formula: C21H41NO4 + Fatty Acyls [FA] with formula: C20H39NO3 + Fatty Acyls [FA] with formula: C22H41NO3 + Fatty Acyls [FA] with formula: C26H39NO3 + Fatty Acyls [FA] with formula: C22H43NO3 + Fatty Acyls [FA] with formula: C20H39NO4 + Fatty Acyls [FA] with formula: C22H41NO4 + Fatty Acyls [FA] with formula: C21H41NO3S + Fatty Acyls [FA] with formula: C23H43NO3S + Fatty Acyls [FA] with formula: C24H45NO3 + Fatty Acyls [FA] with formula: C21H39NO3 + Fatty Acyls [FA] with formula: C23H41NO3 + Fatty Acyls [FA] with formula: C23H43NO3 + Fatty Acyls [FA] with formula: C21H41NO3 + Fatty Acyls [FA] with formula: C23H45NO3 + Fatty Acyls [FA] with formula: C19H37NO3 + Fatty Acyls [FA] with formula: C25H40N2O4 + Fatty Acyls [FA] with formula: C21H40N2O4 + Fatty Acyls [FA] with formula: C23H42N2O4 + Fatty Acyls [FA] with formula: C27H40N2O4 + Fatty Acyls [FA] with formula: C23H44N2O4 + Fatty Acyls [FA] with formula: C26H39N3O3 + Fatty Acyls [FA] with formula: C22H39N3O3 + Fatty Acyls [FA] with formula: C24H41N3O3 + Fatty Acyls [FA] with formula: C28H39N3O3 + Fatty Acyls [FA] with formula: C24H43N3O3 + Fatty Acyls [FA] with formula: C23H46N4O3 + Fatty Acyls [FA] with formula: C22H40N2O4 + Fatty Acyls [FA] with formula: C20H37NO4S + Fatty Acyls [FA] with formula: C26H43NO3 + Fatty Acyls [FA] with formula: C30H42N2O2 + Fatty Acyls [FA] with formula: C7H15NO Fatty Acyls [FA] with formula: C16H27NO4 Fatty Acyls [FA] with formula: C8H13NO3 Fatty Acyls [FA] with formula: C10H15NO4 @@ -763,6 +862,7 @@ Fatty Acyls [FA] with formula: C22H39NO2 Fatty Acyls [FA] with formula: C22H45NO2 Fatty Acyls [FA] with formula: C22H37NO3 + Fatty Acyls [FA] with formula: C14H29NO2 Fatty Acyls [FA] with formula: C18H35NO2 Fatty Acyls [FA] with formula: C17H35NO2 Fatty Acyls [FA] with formula: C19H39NO2 @@ -785,12 +885,13 @@ Fatty Acyls [FA] with formula: C31H64 Fatty Acyls [FA] with formula: C30H60 Fatty Acyls [FA] with formula: C33H68 + Fatty Acyls [FA] with formula: C31H46 Fatty Acyls [FA] with formula: C11H22O Fatty Acyls [FA] with formula: C5H10O Fatty Acyls [FA] with formula: C7H14O Fatty Acyls [FA] with formula: C31H62O - Fatty Acyls [FA] with formula: C31H60O2 - Fatty Acyls [FA] with formula: C33H64O2 + Fatty Acyls [FA] with formula: C31H60O2 + Fatty Acyls [FA] with formula: C33H64O2 Fatty Acyls [FA] with formula: C29H58O Fatty Acyls [FA] with formula: C40H78O8 Fatty Acyls [FA] with formula: C42H82O8 @@ -804,7 +905,7 @@ Fatty Acyls [FA] with formula: C38H76O9 Fatty Acyls [FA] with formula: C34H66O8 Fatty Acyls [FA] with formula: C32H62O8 - Fatty Acyls [FA] with formula: C36H70O9 + Fatty Acyls [FA] with formula: C36H70O9 Fatty Acyls [FA] with formula: C32H64O8 Fatty Acyls [FA] with formula: C34H66O9 Fatty Acyls [FA] with formula: C38H74O9 @@ -816,7 +917,7 @@ Fatty Acyls [FA] with formula: C34H64O13 Fatty Acyls [FA] with formula: C27H50O9 - + Glycerolipids [GL] with formula: C50H85NO7 Glycerolipids [GL] with formula: C41H80O8 @@ -826,13 +927,15 @@ Glycerolipids [GL] with formula: C48H83NO7 Glycerolipids [GL] with formula: C20H40O4 Glycerolipids [GL] with formula: C21H42O4 - Glycerolipids [GL] with formula: C21H40O4 + Glycerolipids [GL] with formula: C21H40O4 Glycerolipids [GL] with formula: C21H38O4 Glycerolipids [GL] with formula: C23H46O4 Glycerolipids [GL] with formula: C15H30O4 - Glycerolipids [GL] with formula: C19H38O4 + Glycerolipids [GL] with formula: C19H38O4 Glycerolipids [GL] with formula: C23H38O4 - Glycerolipids [GL] with formula: C23H40O3 + Glycerolipids [GL] with formula: C23H36O4 + Glycerolipids [GL] with formula: C25H38O4 + Glycerolipids [GL] with formula: C23H40O3 Glycerolipids [GL] with formula: C9H20O3 Glycerolipids [GL] with formula: C11H24O3 Glycerolipids [GL] with formula: C35H68O5 @@ -1035,7 +1138,7 @@ Glycerolipids [GL] with formula: C59H100O6 Glycerolipids [GL] with formula: C60H106O6 Glycerolipids [GL] with formula: C59H96O6 - Glycerolipids [GL] with formula: C60H104O6 + Glycerolipids [GL] with formula: C60H104O6 Glycerolipids [GL] with formula: C59H94O6 Glycerolipids [GL] with formula: C62H118O6 Glycerolipids [GL] with formula: C59H92O6 @@ -1065,7 +1168,7 @@ Glycerolipids [GL] with formula: C61H94O6 Glycerolipids [GL] with formula: C64H122O6 Glycerolipids [GL] with formula: C65H126O6 - Glycerolipids [GL] with formula: C63H116O6 + Glycerolipids [GL] with formula: C63H116O6 Glycerolipids [GL] with formula: C62H104O6 Glycerolipids [GL] with formula: C62H108O6 Glycerolipids [GL] with formula: C61H98O6 @@ -1113,7 +1216,7 @@ Glycerolipids [GL] with formula: C63H94O6 Glycerolipids [GL] with formula: C64H104O6 Glycerolipids [GL] with formula: C65H108O6 - Glycerolipids [GL] with formula: C65H116O6 + Glycerolipids [GL] with formula: C65H116O6 Glycerolipids [GL] with formula: C66H120O6 Glycerolipids [GL] with formula: C65H106O6 Glycerolipids [GL] with formula: C67H124O6 @@ -1211,14 +1314,14 @@ Glycerolipids [GL] with formula: C43H80O10 Glycerolipids [GL] with formula: C43H78O10 Glycerolipids [GL] with formula: C43H68O11 + Glycerolipids [GL] with formula: C49H99N2O17P2 Glycerolipids [GL] with formula: C104H205O26PS Glycerolipids [GL] with formula: C55H108O16S Glycerolipids [GL] with formula: C61H118O21S Glycerolipids [GL] with formula: C99H197O21PS - + - Glycerophospholipids [GP] with formula: C43H82NO10P Glycerophospholipids [GP] with formula: C39H77O8PS Glycerophospholipids [GP] with formula: C35H69O8PS Glycerophospholipids [GP] with formula: C37H73O8PS @@ -1226,165 +1329,197 @@ Glycerophospholipids [GP] with formula: C51H101O8PS Glycerophospholipids [GP] with formula: C21H41O6P Glycerophospholipids [GP] with formula: C21H39O6P - Glycerophospholipids [GP] with formula: C10H18NO8P - Glycerophospholipids [GP] with formula: C45H82NO8P - Glycerophospholipids [GP] with formula: C51H90NO8P - Glycerophospholipids [GP] with formula: C36H68NO8P - Glycerophospholipids [GP] with formula: C32H64NO8P - Glycerophospholipids [GP] with formula: C33H66NO8P - Glycerophospholipids [GP] with formula: C35H70NO8P - Glycerophospholipids [GP] with formula: C36H72NO8P - Glycerophospholipids [GP] with formula: C37H74NO8P - Glycerophospholipids [GP] with formula: C30H56NO8P - Glycerophospholipids [GP] with formula: C35H68NO8P - Glycerophospholipids [GP] with formula: C30H60NO8P - Glycerophospholipids [GP] with formula: C31H62NO8P - Glycerophospholipids [GP] with formula: C38H74NO8P - Glycerophospholipids [GP] with formula: C22H44NO8P - Glycerophospholipids [GP] with formula: C42H72NO8P - Glycerophospholipids [GP] with formula: C40H72NO8P - Glycerophospholipids [GP] with formula: C39H76NO8P - Glycerophospholipids [GP] with formula: C41H78NO8P - Glycerophospholipids [GP] with formula: C42H78NO8P - Glycerophospholipids [GP] with formula: C43H86NO8P - Glycerophospholipids [GP] with formula: C39H78NO8P - Glycerophospholipids [GP] with formula: C40H80NO8P - Glycerophospholipids [GP] with formula: C41H82NO8P - Glycerophospholipids [GP] with formula: C42H82NO8P - Glycerophospholipids [GP] with formula: C43H80NO8P + Glycerophospholipids [GP] with formula: C19H37O6P + Glycerophospholipids [GP] with formula: C59H104NO11P + Glycerophospholipids [GP] with formula: C59H104NO12P + Glycerophospholipids [GP] with formula: C59H104NO13P + Glycerophospholipids [GP] with formula: C51H90NO8P + Glycerophospholipids [GP] with formula: C36H72NO8P + Glycerophospholipids [GP] with formula: C38H76NO8P + Glycerophospholipids [GP] with formula: C39H78NO8P + Glycerophospholipids [GP] with formula: C40H80NO8P + Glycerophospholipids [GP] with formula: C39H76NO8P Glycerophospholipids [GP] with formula: C27H52NO8P - Glycerophospholipids [GP] with formula: C29H56NO8P - Glycerophospholipids [GP] with formula: C40H76NO8P - Glycerophospholipids [GP] with formula: C42H74NO8P + Glycerophospholipids [GP] with formula: C42H74NO8P Glycerophospholipids [GP] with formula: C26H50NO8P - Glycerophospholipids [GP] with formula: C46H78NO8P - Glycerophospholipids [GP] with formula: C43H84NO8P - Glycerophospholipids [GP] with formula: C43H82NO8P - Glycerophospholipids [GP] with formula: C47H84NO8P - Glycerophospholipids [GP] with formula: C47H82NO8P - Glycerophospholipids [GP] with formula: C37H72NO8P - Glycerophospholipids [GP] with formula: C45H84NO8P - Glycerophospholipids [GP] with formula: C28H56NO8P - Glycerophospholipids [GP] with formula: C46H90NO8P - Glycerophospholipids [GP] with formula: C46H88NO8P - Glycerophospholipids [GP] with formula: C46H86NO8P - Glycerophospholipids [GP] with formula: C48H90NO8P - Glycerophospholipids [GP] with formula: C48H84NO8P - Glycerophospholipids [GP] with formula: C50H98NO8P - Glycerophospholipids [GP] with formula: C44H86NO8P - Glycerophospholipids [GP] with formula: C44H84NO8P - Glycerophospholipids [GP] with formula: C44H82NO8P - Glycerophospholipids [GP] with formula: C44H80NO8P - Glycerophospholipids [GP] with formula: C28H54NO8P - Glycerophospholipids [GP] with formula: C46H84NO8P - Glycerophospholipids [GP] with formula: C46H82NO8P - Glycerophospholipids [GP] with formula: C48H86NO8P - Glycerophospholipids [GP] with formula: C30H58NO8P - Glycerophospholipids [GP] with formula: C28H52NO8P - Glycerophospholipids [GP] with formula: C48H82NO8P - Glycerophospholipids [GP] with formula: C44H76NO8P - Glycerophospholipids [GP] with formula: C42H76NO8P - Glycerophospholipids [GP] with formula: C44H72NO8P - Glycerophospholipids [GP] with formula: C11H22NO8P - Glycerophospholipids [GP] with formula: C12H24NO8P - Glycerophospholipids [GP] with formula: C50H90NO8P - Glycerophospholipids [GP] with formula: C50H88NO8P - Glycerophospholipids [GP] with formula: C48H92NO8P - Glycerophospholipids [GP] with formula: C50H80NO8P - Glycerophospholipids [GP] with formula: C50H78NO8P - Glycerophospholipids [GP] with formula: C48H94NO8P - Glycerophospholipids [GP] with formula: C52H102NO8P + Glycerophospholipids [GP] with formula: C44H78NO8P + Glycerophospholipids [GP] with formula: C27H54NO8P + Glycerophospholipids [GP] with formula: C28H56NO8P + Glycerophospholipids [GP] with formula: C46H92NO8P + Glycerophospholipids [GP] with formula: C46H90NO8P + Glycerophospholipids [GP] with formula: C46H88NO8P + Glycerophospholipids [GP] with formula: C48H84NO8P + Glycerophospholipids [GP] with formula: C50H98NO8P + Glycerophospholipids [GP] with formula: C52H104NO8P + Glycerophospholipids [GP] with formula: C29H58NO8P + Glycerophospholipids [GP] with formula: C29H56NO8P + Glycerophospholipids [GP] with formula: C46H80NO8P + Glycerophospholipids [GP] with formula: C48H94NO8P + Glycerophospholipids [GP] with formula: C48H82NO8P + Glycerophospholipids [GP] with formula: C28H54NO8P + Glycerophospholipids [GP] with formula: C44H80NO8P + Glycerophospholipids [GP] with formula: C44H72NO8P + Glycerophospholipids [GP] with formula: C26H52NO8P + Glycerophospholipids [GP] with formula: C12H24NO8P + Glycerophospholipids [GP] with formula: C54H108NO8P + Glycerophospholipids [GP] with formula: C48H80NO8P + Glycerophospholipids [GP] with formula: C47H94NO8P Glycerophospholipids [GP] with formula: C54H106NO8P - Glycerophospholipids [GP] with formula: C52H100NO8P - Glycerophospholipids [GP] with formula: C52H96NO8P - Glycerophospholipids [GP] with formula: C48H88NO8P - Glycerophospholipids [GP] with formula: C46H80NO8P - Glycerophospholipids [GP] with formula: C48H80NO8P - Glycerophospholipids [GP] with formula: C52H80NO8P - Glycerophospholipids [GP] with formula: C54H104NO8P - Glycerophospholipids [GP] with formula: C57H114NO8P - Glycerophospholipids [GP] with formula: C58H116NO8P - Glycerophospholipids [GP] with formula: C56H108NO8P - Glycerophospholipids [GP] with formula: C56H104NO8P - Glycerophospholipids [GP] with formula: C44H88NO8P - Glycerophospholipids [GP] with formula: C45H90NO8P - Glycerophospholipids [GP] with formula: C59H118NO8P - Glycerophospholipids [GP] with formula: C60H120NO8P + Glycerophospholipids [GP] with formula: C52H80NO8P + Glycerophospholipids [GP] with formula: C54H104NO8P + Glycerophospholipids [GP] with formula: C48H96NO8P + Glycerophospholipids [GP] with formula: C56H112NO8P + Glycerophospholipids [GP] with formula: C56H108NO8P Glycerophospholipids [GP] with formula: C60H116NO8P - Glycerophospholipids [GP] with formula: C60H112NO8P - Glycerophospholipids [GP] with formula: C50H96NO8P - Glycerophospholipids [GP] with formula: C13H26NO8P - Glycerophospholipids [GP] with formula: C14H28NO8P - Glycerophospholipids [GP] with formula: C16H32NO8P - Glycerophospholipids [GP] with formula: C18H36NO8P - Glycerophospholipids [GP] with formula: C20H40NO8P + Glycerophospholipids [GP] with formula: C14H28NO8P + Glycerophospholipids [GP] with formula: C60H112NO8P + Glycerophospholipids [GP] with formula: C58H116NO8P + Glycerophospholipids [GP] with formula: C60H120NO8P + Glycerophospholipids [GP] with formula: C30H60NO8P + Glycerophospholipids [GP] with formula: C30H58NO8P + Glycerophospholipids [GP] with formula: C16H32NO8P + Glycerophospholipids [GP] with formula: C18H36NO8P + Glycerophospholipids [GP] with formula: C20H40NO8P + Glycerophospholipids [GP] with formula: C22H44NO8P Glycerophospholipids [GP] with formula: C20H32NO8P - Glycerophospholipids [GP] with formula: C28H48NO8P + Glycerophospholipids [GP] with formula: C28H48NO8P + Glycerophospholipids [GP] with formula: C37H74NO8P + Glycerophospholipids [GP] with formula: C24H48NO8P Glycerophospholipids [GP] with formula: C24H40NO8P - Glycerophospholipids [GP] with formula: C44H78NO8P - Glycerophospholipids [GP] with formula: C37H76NO7P - Glycerophospholipids [GP] with formula: C38H78NO7P - Glycerophospholipids [GP] with formula: C38H76NO7P - Glycerophospholipids [GP] with formula: C40H80NO7P - Glycerophospholipids [GP] with formula: C40H76NO7P - Glycerophospholipids [GP] with formula: C42H78NO7P - Glycerophospholipids [GP] with formula: C44H90NO7P - Glycerophospholipids [GP] with formula: C43H80NO7P - Glycerophospholipids [GP] with formula: C40H82NO7P - Glycerophospholipids [GP] with formula: C41H84NO7P - Glycerophospholipids [GP] with formula: C42H86NO7P - Glycerophospholipids [GP] with formula: C42H84NO7P - Glycerophospholipids [GP] with formula: C42H82NO7P - Glycerophospholipids [GP] with formula: C42H80NO7P - Glycerophospholipids [GP] with formula: C44H88NO7P - Glycerophospholipids [GP] with formula: C44H84NO7P - Glycerophospholipids [GP] with formula: C44H82NO7P - Glycerophospholipids [GP] with formula: C44H80NO7P - Glycerophospholipids [GP] with formula: C46H82NO7P - Glycerophospholipids [GP] with formula: C50H102NO7P - Glycerophospholipids [GP] with formula: C27H54NO7P - Glycerophospholipids [GP] with formula: C43H86NO7P - Glycerophospholipids [GP] with formula: C45H92NO7P - Glycerophospholipids [GP] with formula: C45H84NO7P - Glycerophospholipids [GP] with formula: C47H96NO7P - Glycerophospholipids [GP] with formula: C46H94NO7P - Glycerophospholipids [GP] with formula: C46H92NO7P - Glycerophospholipids [GP] with formula: C46H86NO7P - Glycerophospholipids [GP] with formula: C46H84NO7P - Glycerophospholipids [GP] with formula: C48H98NO7P - Glycerophospholipids [GP] with formula: C48H88NO7P - Glycerophospholipids [GP] with formula: C48H86NO7P - Glycerophospholipids [GP] with formula: C29H60NO7P - Glycerophospholipids [GP] with formula: C29H58NO7P - Glycerophospholipids [GP] with formula: C30H62NO7P - Glycerophospholipids [GP] with formula: C49H100NO7P - Glycerophospholipids [GP] with formula: C20H40NO7P - Glycerophospholipids [GP] with formula: C21H42NO7P - Glycerophospholipids [GP] with formula: C28H56NO7P - Glycerophospholipids [GP] with formula: C28H54NO7P - Glycerophospholipids [GP] with formula: C40H78NO7P + Glycerophospholipids [GP] with formula: C35H70NO8P + Glycerophospholipids [GP] with formula: C40H74NO8P + Glycerophospholipids [GP] with formula: C40H72NO8P + Glycerophospholipids [GP] with formula: C40H70NO8P + Glycerophospholipids [GP] with formula: C33H66NO8P + Glycerophospholipids [GP] with formula: C41H82NO8P + Glycerophospholipids [GP] with formula: C41H80NO8P + Glycerophospholipids [GP] with formula: C42H82NO8P + Glycerophospholipids [GP] with formula: C42H80NO8P + Glycerophospholipids [GP] with formula: C42H78NO8P + Glycerophospholipids [GP] with formula: C43H86NO8P + Glycerophospholipids [GP] with formula: C44H86NO8P + Glycerophospholipids [GP] with formula: C44H84NO8P + Glycerophospholipids [GP] with formula: C34H66NO8P + Glycerophospholipids [GP] with formula: C47H78NO8P + Glycerophospholipids [GP] with formula: C46H76NO8P + Glycerophospholipids [GP] with formula: C39H70NO8P + Glycerophospholipids [GP] with formula: C48H76NO8P + Glycerophospholipids [GP] with formula: C49H86NO8P + Glycerophospholipids [GP] with formula: C43H84NO8P + Glycerophospholipids [GP] with formula: C43H82NO8P + Glycerophospholipids [GP] with formula: C44H82NO8P + Glycerophospholipids [GP] with formula: C45H88NO8P + Glycerophospholipids [GP] with formula: C45H86NO8P + Glycerophospholipids [GP] with formula: C45H84NO8P + Glycerophospholipids [GP] with formula: C49H84NO8P + Glycerophospholipids [GP] with formula: C46H82NO8P + Glycerophospholipids [GP] with formula: C48H92NO8P + Glycerophospholipids [GP] with formula: C48H90NO8P + Glycerophospholipids [GP] with formula: C48H88NO8P + Glycerophospholipids [GP] with formula: C48H86NO8P + Glycerophospholipids [GP] with formula: C46H86NO8P + Glycerophospholipids [GP] with formula: C50H80NO8P + Glycerophospholipids [GP] with formula: C46H74NO8P + Glycerophospholipids [GP] with formula: C48H78NO8P + Glycerophospholipids [GP] with formula: C49H88NO8P + Glycerophospholipids [GP] with formula: C50H90NO8P + Glycerophospholipids [GP] with formula: C50H88NO8P + Glycerophospholipids [GP] with formula: C50H86NO8P + Glycerophospholipids [GP] with formula: C50H82NO8P + Glycerophospholipids [GP] with formula: C45H90NO8P + Glycerophospholipids [GP] with formula: C49H98NO8P + Glycerophospholipids [GP] with formula: C50H100NO8P + Glycerophospholipids [GP] with formula: C50H96NO8P + Glycerophospholipids [GP] with formula: C50H94NO8P + Glycerophospholipids [GP] with formula: C50H92NO8P + Glycerophospholipids [GP] with formula: C51H102NO8P + Glycerophospholipids [GP] with formula: C52H102NO8P + Glycerophospholipids [GP] with formula: C52H100NO8P + Glycerophospholipids [GP] with formula: C52H96NO8P + Glycerophospholipids [GP] with formula: C49H94NO8P + Glycerophospholipids [GP] with formula: C51H100NO8P + Glycerophospholipids [GP] with formula: C52H98NO8P + Glycerophospholipids [GP] with formula: C52H94NO8P + Glycerophospholipids [GP] with formula: C51H98NO8P + Glycerophospholipids [GP] with formula: C52H92NO8P + Glycerophospholipids [GP] with formula: C52H88NO8P + Glycerophospholipids [GP] with formula: C49H90NO8P + Glycerophospholipids [GP] with formula: C50H84NO8P + Glycerophospholipids [GP] with formula: C51H94NO8P + Glycerophospholipids [GP] with formula: C50H78NO8P + Glycerophospholipids [GP] with formula: C52H90NO8P + Glycerophospholipids [GP] with formula: C52H84NO8P + Glycerophospholipids [GP] with formula: C40H78NO7P + Glycerophospholipids [GP] with formula: C40H76NO7P + Glycerophospholipids [GP] with formula: C44H90NO7P + Glycerophospholipids [GP] with formula: C44H80NO7P + Glycerophospholipids [GP] with formula: C48H86NO7P + Glycerophospholipids [GP] with formula: C29H60NO7P + Glycerophospholipids [GP] with formula: C29H58NO7P + Glycerophospholipids [GP] with formula: C30H62NO7P + Glycerophospholipids [GP] with formula: C49H100NO7P + Glycerophospholipids [GP] with formula: C50H102NO7P + Glycerophospholipids [GP] with formula: C28H56NO7P + Glycerophospholipids [GP] with formula: C46H84NO7P + Glycerophospholipids [GP] with formula: C28H54NO7P + Glycerophospholipids [GP] with formula: C36H74NO7P + Glycerophospholipids [GP] with formula: C37H76NO7P + Glycerophospholipids [GP] with formula: C38H78NO7P + Glycerophospholipids [GP] with formula: C38H76NO7P + Glycerophospholipids [GP] with formula: C45H92NO7P + Glycerophospholipids [GP] with formula: C46H90NO7P + Glycerophospholipids [GP] with formula: C46H86NO7P + Glycerophospholipids [GP] with formula: C39H80NO7P + Glycerophospholipids [GP] with formula: C41H84NO7P + Glycerophospholipids [GP] with formula: C43H88NO7P + Glycerophospholipids [GP] with formula: C46H88NO7P + Glycerophospholipids [GP] with formula: C47H96NO7P + Glycerophospholipids [GP] with formula: C48H98NO7P + Glycerophospholipids [GP] with formula: C48H90NO7P + Glycerophospholipids [GP] with formula: C50H94NO7P + Glycerophospholipids [GP] with formula: C50H90NO7P Glycerophospholipids [GP] with formula: C48H84NO7P - Glycerophospholipids [GP] with formula: C21H46NO6P - Glycerophospholipids [GP] with formula: C36H76NO6P - Glycerophospholipids [GP] with formula: C40H84NO6P - Glycerophospholipids [GP] with formula: C42H88NO6P - Glycerophospholipids [GP] with formula: C42H86NO6P - Glycerophospholipids [GP] with formula: C26H56NO6P - Glycerophospholipids [GP] with formula: C28H60NO6P - Glycerophospholipids [GP] with formula: C29H62NO6P - Glycerophospholipids [GP] with formula: C30H64NO6P - Glycerophospholipids [GP] with formula: C27H58NO6P - Glycerophospholipids [GP] with formula: C44H92NO6P - Glycerophospholipids [GP] with formula: C28H58NO6P - Glycerophospholipids [GP] with formula: C29H61NO6P - Glycerophospholipids [GP] with formula: C27H56NO6P - Glycerophospholipids [GP] with formula: C44H88NO6P + Glycerophospholipids [GP] with formula: C46H80NO7P + Glycerophospholipids [GP] with formula: C50H74NO10P + Glycerophospholipids [GP] with formula: C39H76NO7P + Glycerophospholipids [GP] with formula: C42H76NO7P + Glycerophospholipids [GP] with formula: C44H78NO7P + Glycerophospholipids [GP] with formula: C41H80NO7P + Glycerophospholipids [GP] with formula: C43H82NO7P + Glycerophospholipids [GP] with formula: C44H88NO7P + Glycerophospholipids [GP] with formula: C44H84NO7P + Glycerophospholipids [GP] with formula: C44H82NO7P + Glycerophospholipids [GP] with formula: C46H82NO7P + Glycerophospholipids [GP] with formula: C48H96NO7P + Glycerophospholipids [GP] with formula: C48H94NO7P + Glycerophospholipids [GP] with formula: C48H92NO7P + Glycerophospholipids [GP] with formula: C48H88NO7P + Glycerophospholipids [GP] with formula: C40H80NO7P + Glycerophospholipids [GP] with formula: C41H82NO7P + Glycerophospholipids [GP] with formula: C42H84NO7P + Glycerophospholipids [GP] with formula: C42H82NO7P + Glycerophospholipids [GP] with formula: C43H86NO7P + Glycerophospholipids [GP] with formula: C43H84NO7P + Glycerophospholipids [GP] with formula: C49H98NO7P + Glycerophospholipids [GP] with formula: C50H100NO7P + Glycerophospholipids [GP] with formula: C50H98NO7P + Glycerophospholipids [GP] with formula: C50H96NO7P + Glycerophospholipids [GP] with formula: C50H92NO7P + Glycerophospholipids [GP] with formula: C50H88NO7P + Glycerophospholipids [GP] with formula: C21H46NO6P + Glycerophospholipids [GP] with formula: C32H68NO6P + Glycerophospholipids [GP] with formula: C36H76NO6P + Glycerophospholipids [GP] with formula: C40H84NO6P + Glycerophospholipids [GP] with formula: C42H88NO6P + Glycerophospholipids [GP] with formula: C26H56NO6P + Glycerophospholipids [GP] with formula: C27H58NO6P + Glycerophospholipids [GP] with formula: C27H56NO6P + Glycerophospholipids [GP] with formula: C42H86NO6P + Glycerophospholipids [GP] with formula: C44H88NO6P Glycerophospholipids [GP] with formula: C11H26NO6P - Glycerophospholipids [GP] with formula: C29H58NO6P - Glycerophospholipids [GP] with formula: C22H48NO6P - Glycerophospholipids [GP] with formula: C17H38NO6P - Glycerophospholipids [GP] with formula: C32H68NO6P - Glycerophospholipids [GP] with formula: C18H40NO6P + Glycerophospholipids [GP] with formula: C12H28NO6P + Glycerophospholipids [GP] with formula: C29H62NO6P + Glycerophospholipids [GP] with formula: C20H44NO6P Glycerophospholipids [GP] with formula: C46H78NO6P Glycerophospholipids [GP] with formula: C48H82NO6P Glycerophospholipids [GP] with formula: C46H80NO6P @@ -1396,261 +1531,1207 @@ Glycerophospholipids [GP] with formula: C48H88NO6P Glycerophospholipids [GP] with formula: C48H96NO6P Glycerophospholipids [GP] with formula: C48H100NO6P - Glycerophospholipids [GP] with formula: C25H50NO7P Glycerophospholipids [GP] with formula: C27H50NO7P Glycerophospholipids [GP] with formula: C29H52NO7P - Glycerophospholipids [GP] with formula: C24H48NO7P - Glycerophospholipids [GP] with formula: C26H52NO7P - Glycerophospholipids [GP] with formula: C26H50NO7P - Glycerophospholipids [GP] with formula: C26H48NO7P - Glycerophospholipids [GP] with formula: C26H46NO7P + Glycerophospholipids [GP] with formula: C20H42NO7P + Glycerophospholipids [GP] with formula: C24H48NO7P + Glycerophospholipids [GP] with formula: C26H50NO7P + Glycerophospholipids [GP] with formula: C26H46NO7P Glycerophospholipids [GP] with formula: C28H48NO7P - Glycerophospholipids [GP] with formula: C30H50NO7P - Glycerophospholipids [GP] with formula: C32H66NO7P - Glycerophospholipids [GP] with formula: C15H32NO7P - Glycerophospholipids [GP] with formula: C22H46NO7P - Glycerophospholipids [GP] with formula: C24H50NO7P - Glycerophospholipids [GP] with formula: C26H54NO7P - Glycerophospholipids [GP] with formula: C10H22NO7P - Glycerophospholipids [GP] with formula: C11H24NO7P - Glycerophospholipids [GP] with formula: C11H22NO7P - Glycerophospholipids [GP] with formula: C12H26NO7P - Glycerophospholipids [GP] with formula: C13H28NO7P - Glycerophospholipids [GP] with formula: C14H30NO7P - Glycerophospholipids [GP] with formula: C16H34NO7P - Glycerophospholipids [GP] with formula: C28H50NO7P - Glycerophospholipids [GP] with formula: C20H44NO6P - Glycerophospholipids [GP] with formula: C23H50NO6P - Glycerophospholipids [GP] with formula: C24H52NO6P - Glycerophospholipids [GP] with formula: C25H54NO6P - Glycerophospholipids [GP] with formula: C12H28NO6P + Glycerophospholipids [GP] with formula: C30H50NO7P + Glycerophospholipids [GP] with formula: C32H66NO7P + Glycerophospholipids [GP] with formula: C14H30NO7P + Glycerophospholipids [GP] with formula: C15H32NO7P + Glycerophospholipids [GP] with formula: C16H34NO7P + Glycerophospholipids [GP] with formula: C26H52NO7P + Glycerophospholipids [GP] with formula: C10H22NO7P + Glycerophospholipids [GP] with formula: C11H24NO7P + Glycerophospholipids [GP] with formula: C11H22NO7P + Glycerophospholipids [GP] with formula: C12H26NO7P + Glycerophospholipids [GP] with formula: C13H28NO7P + Glycerophospholipids [GP] with formula: C28H50NO7P + Glycerophospholipids [GP] with formula: C30H54NO7P + Glycerophospholipids [GP] with formula: C26H48NO7P + Glycerophospholipids [GP] with formula: C28H52NO7P + Glycerophospholipids [GP] with formula: C30H60NO7P + Glycerophospholipids [GP] with formula: C30H58NO7P + Glycerophospholipids [GP] with formula: C22H48NO6P Glycerophospholipids [GP] with formula: C13H30NO6P - Glycerophospholipids [GP] with formula: C14H32NO6P Glycerophospholipids [GP] with formula: C28H52NO6P Glycerophospholipids [GP] with formula: C18H38NO6P - Glycerophospholipids [GP] with formula: C24H48NO6P + Glycerophospholipids [GP] with formula: C24H52NO6P + Glycerophospholipids [GP] with formula: C28H60NO6P Glycerophospholipids [GP] with formula: C22H46NO6P - Glycerophospholipids [GP] with formula: C23H48NO6P - Glycerophospholipids [GP] with formula: C24H50NO6P - Glycerophospholipids [GP] with formula: C25H52NO6P - Glycerophospholipids [GP] with formula: C26H54NO6P + Glycerophospholipids [GP] with formula: C24H50NO6P + Glycerophospholipids [GP] with formula: C26H54NO6P Glycerophospholipids [GP] with formula: C27H54NO6P - Glycerophospholipids [GP] with formula: C26H52NO6P + Glycerophospholipids [GP] with formula: C26H52NO6P + Glycerophospholipids [GP] with formula: C28H58NO6P Glycerophospholipids [GP] with formula: C46H76NO7P Glycerophospholipids [GP] with formula: C48H80NO7P Glycerophospholipids [GP] with formula: C46H78NO7P Glycerophospholipids [GP] with formula: C48H82NO7P - Glycerophospholipids [GP] with formula: C44H86NO7P - Glycerophospholipids [GP] with formula: C25H52NO7P - Glycerophospholipids [GP] with formula: C28H58NO7P - Glycerophospholipids [GP] with formula: C27H56NO7P - Glycerophospholipids [GP] with formula: C36H70NO8P - Glycerophospholipids [GP] with formula: C25H50NO8P - Glycerophospholipids [GP] with formula: C37H70NO8P - Glycerophospholipids [GP] with formula: C41H70NO8P - Glycerophospholipids [GP] with formula: C45H74NO8P - Glycerophospholipids [GP] with formula: C39H74NO8P - Glycerophospholipids [GP] with formula: C41H76NO8P - Glycerophospholipids [GP] with formula: C39H72NO8P - Glycerophospholipids [GP] with formula: C26H52NO8P - Glycerophospholipids [GP] with formula: C27H54NO8P - Glycerophospholipids [GP] with formula: C29H58NO8P - Glycerophospholipids [GP] with formula: C50H100NO8P - Glycerophospholipids [GP] with formula: C51H102NO8P - Glycerophospholipids [GP] with formula: C52H104NO8P - Glycerophospholipids [GP] with formula: C53H106NO8P - Glycerophospholipids [GP] with formula: C54H108NO8P - Glycerophospholipids [GP] with formula: C55H110NO8P - Glycerophospholipids [GP] with formula: C56H112NO8P + Glycerophospholipids [GP] with formula: C42H78NO7P + Glycerophospholipids [GP] with formula: C25H52NO7P + Glycerophospholipids [GP] with formula: C40H82NO7P + Glycerophospholipids [GP] with formula: C42H86NO7P + Glycerophospholipids [GP] with formula: C28H58NO7P Glycerophospholipids [GP] with formula: C49H74NO8P - Glycerophospholipids [GP] with formula: C21H42NO8P - Glycerophospholipids [GP] with formula: C17H34NO8P - Glycerophospholipids [GP] with formula: C41H74NO8P - Glycerophospholipids [GP] with formula: C45H86NO8P - Glycerophospholipids [GP] with formula: C47H94NO8P - Glycerophospholipids [GP] with formula: C45H88NO8P - Glycerophospholipids [GP] with formula: C47H74NO8P - Glycerophospholipids [GP] with formula: C57H106NO8P - Glycerophospholipids [GP] with formula: C49H98NO8P - Glycerophospholipids [GP] with formula: C48H96NO8P - Glycerophospholipids [GP] with formula: C46H92NO8P - Glycerophospholipids [GP] with formula: C24H48NO8P - Glycerophospholipids [GP] with formula: C23H46NO8P - Glycerophospholipids [GP] with formula: C51H100NO8P - Glycerophospholipids [GP] with formula: C47H92NO8P - Glycerophospholipids [GP] with formula: C49H96NO8P - Glycerophospholipids [GP] with formula: C41H80NO8P - Glycerophospholipids [GP] with formula: C34H68NO8P - Glycerophospholipids [GP] with formula: C42H84NO8P - Glycerophospholipids [GP] with formula: C38H76NO8P - Glycerophospholipids [GP] with formula: C42H80NO8P - Glycerophospholipids [GP] with formula: C40H78NO8P + Glycerophospholipids [GP] with formula: C25H50NO8P + Glycerophospholipids [GP] with formula: C21H42NO8P + Glycerophospholipids [GP] with formula: C17H34NO8P + Glycerophospholipids [GP] with formula: C47H74NO8P + Glycerophospholipids [GP] with formula: C57H106NO8P + Glycerophospholipids [GP] with formula: C31H62NO8P + Glycerophospholipids [GP] with formula: C47H92NO8P + Glycerophospholipids [GP] with formula: C49H96NO8P Glycerophospholipids [GP] with formula: C57H108NO9P - Glycerophospholipids [GP] with formula: C39H80NO7P - Glycerophospholipids [GP] with formula: C43H78NO7P - Glycerophospholipids [GP] with formula: C43H88NO7P - Glycerophospholipids [GP] with formula: C39H78NO7P - Glycerophospholipids [GP] with formula: C41H76NO7P + Glycerophospholipids [GP] with formula: C37H68NO8P + Glycerophospholipids [GP] with formula: C37H66NO8P + Glycerophospholipids [GP] with formula: C37H64NO8P + Glycerophospholipids [GP] with formula: C36H64NO8P + Glycerophospholipids [GP] with formula: C38H68NO8P + Glycerophospholipids [GP] with formula: C31H60NO8P + Glycerophospholipids [GP] with formula: C41H72NO8P + Glycerophospholipids [GP] with formula: C41H68NO8P + Glycerophospholipids [GP] with formula: C32H64NO8P + Glycerophospholipids [GP] with formula: C34H68NO8P + Glycerophospholipids [GP] with formula: C37H72NO8P + Glycerophospholipids [GP] with formula: C38H70NO8P + Glycerophospholipids [GP] with formula: C32H62NO8P + Glycerophospholipids [GP] with formula: C33H64NO8P + Glycerophospholipids [GP] with formula: C34H64NO8P + Glycerophospholipids [GP] with formula: C35H66NO8P + Glycerophospholipids [GP] with formula: C38H66NO8P + Glycerophospholipids [GP] with formula: C40H68NO8P + Glycerophospholipids [GP] with formula: C44H74NO8P + Glycerophospholipids [GP] with formula: C36H66NO8P + Glycerophospholipids [GP] with formula: C42H76NO8P + Glycerophospholipids [GP] with formula: C42H72NO8P + Glycerophospholipids [GP] with formula: C42H70NO8P + Glycerophospholipids [GP] with formula: C42H84NO8P + Glycerophospholipids [GP] with formula: C44H88NO8P + Glycerophospholipids [GP] with formula: C35H68NO8P + Glycerophospholipids [GP] with formula: C36H70NO8P + Glycerophospholipids [GP] with formula: C37H70NO8P + Glycerophospholipids [GP] with formula: C38H74NO8P + Glycerophospholipids [GP] with formula: C38H72NO8P + Glycerophospholipids [GP] with formula: C36H68NO8P + Glycerophospholipids [GP] with formula: C39H72NO8P + Glycerophospholipids [GP] with formula: C43H80NO8P + Glycerophospholipids [GP] with formula: C43H78NO8P + Glycerophospholipids [GP] with formula: C43H76NO8P + Glycerophospholipids [GP] with formula: C43H72NO8P + Glycerophospholipids [GP] with formula: C35H64NO8P + Glycerophospholipids [GP] with formula: C43H70NO8P + Glycerophospholipids [GP] with formula: C35H62NO8P + Glycerophospholipids [GP] with formula: C41H66NO8P + Glycerophospholipids [GP] with formula: C41H76NO8P + Glycerophospholipids [GP] with formula: C46H78NO8P + Glycerophospholipids [GP] with formula: C47H86NO8P + Glycerophospholipids [GP] with formula: C39H74NO8P + Glycerophospholipids [GP] with formula: C40H78NO8P + Glycerophospholipids [GP] with formula: C40H76NO8P + Glycerophospholipids [GP] with formula: C41H78NO8P + Glycerophospholipids [GP] with formula: C47H90NO8P + Glycerophospholipids [GP] with formula: C47H88NO8P + Glycerophospholipids [GP] with formula: C47H84NO8P + Glycerophospholipids [GP] with formula: C39H68NO8P + Glycerophospholipids [GP] with formula: C43H68NO8P + Glycerophospholipids [GP] with formula: C45H72NO8P + Glycerophospholipids [GP] with formula: C45H70NO8P + Glycerophospholipids [GP] with formula: C47H82NO8P + Glycerophospholipids [GP] with formula: C47H80NO8P + Glycerophospholipids [GP] with formula: C47H76NO8P + Glycerophospholipids [GP] with formula: C49H92NO8P + Glycerophospholipids [GP] with formula: C49H82NO8P + Glycerophospholipids [GP] with formula: C44H76NO8P + Glycerophospholipids [GP] with formula: C45H82NO8P + Glycerophospholipids [GP] with formula: C45H80NO8P + Glycerophospholipids [GP] with formula: C45H78NO8P + Glycerophospholipids [GP] with formula: C45H76NO8P + Glycerophospholipids [GP] with formula: C45H74NO8P + Glycerophospholipids [GP] with formula: C46H84NO8P + Glycerophospholipids [GP] with formula: C49H78NO8P + Glycerophospholipids [GP] with formula: C47H72NO8P + Glycerophospholipids [GP] with formula: C43H74NO8P + Glycerophospholipids [GP] with formula: C41H74NO8P + Glycerophospholipids [GP] with formula: C33H62NO8P + Glycerophospholipids [GP] with formula: C41H70NO8P + Glycerophospholipids [GP] with formula: C39H66NO8P + Glycerophospholipids [GP] with formula: C33H68NO7P + Glycerophospholipids [GP] with formula: C34H70NO7P + Glycerophospholipids [GP] with formula: C35H72NO7P + Glycerophospholipids [GP] with formula: C37H74NO7P + Glycerophospholipids [GP] with formula: C41H78NO7P + Glycerophospholipids [GP] with formula: C41H76NO7P + Glycerophospholipids [GP] with formula: C39H78NO7P + Glycerophospholipids [GP] with formula: C46H94NO7P + Glycerophospholipids [GP] with formula: C47H88NO7P + Glycerophospholipids [GP] with formula: C47H84NO7P Glycerophospholipids [GP] with formula: C43H74NO7P - Glycerophospholipids [GP] with formula: C41H80NO7P Glycerophospholipids [GP] with formula: C45H78NO7P - Glycerophospholipids [GP] with formula: C37H78NO6P - Glycerophospholipids [GP] with formula: C41H86NO6P - Glycerophospholipids [GP] with formula: C39H82NO6P + Glycerophospholipids [GP] with formula: C33H66NO7P + Glycerophospholipids [GP] with formula: C34H68NO7P + Glycerophospholipids [GP] with formula: C35H68NO7P + Glycerophospholipids [GP] with formula: C36H70NO7P + Glycerophospholipids [GP] with formula: C38H72NO7P + Glycerophospholipids [GP] with formula: C39H72NO7P + Glycerophospholipids [GP] with formula: C39H70NO7P + Glycerophospholipids [GP] with formula: C41H72NO7P + Glycerophospholipids [GP] with formula: C35H70NO7P + Glycerophospholipids [GP] with formula: C36H72NO7P + Glycerophospholipids [GP] with formula: C37H72NO7P + Glycerophospholipids [GP] with formula: C38H74NO7P + Glycerophospholipids [GP] with formula: C43H76NO7P + Glycerophospholipids [GP] with formula: C42H80NO7P + Glycerophospholipids [GP] with formula: C43H80NO7P + Glycerophospholipids [GP] with formula: C43H78NO7P + Glycerophospholipids [GP] with formula: C44H86NO7P + Glycerophospholipids [GP] with formula: C45H90NO7P + Glycerophospholipids [GP] with formula: C45H88NO7P + Glycerophospholipids [GP] with formula: C45H86NO7P + Glycerophospholipids [GP] with formula: C45H84NO7P + Glycerophospholipids [GP] with formula: C45H82NO7P + Glycerophospholipids [GP] with formula: C45H80NO7P + Glycerophospholipids [GP] with formula: C46H92NO7P + Glycerophospholipids [GP] with formula: C47H94NO7P + Glycerophospholipids [GP] with formula: C47H92NO7P + Glycerophospholipids [GP] with formula: C47H90NO7P + Glycerophospholipids [GP] with formula: C47H86NO7P + Glycerophospholipids [GP] with formula: C47H82NO7P + Glycerophospholipids [GP] with formula: C41H74NO7P + Glycerophospholipids [GP] with formula: C39H74NO7P + Glycerophospholipids [GP] with formula: C37H78NO6P + Glycerophospholipids [GP] with formula: C41H86NO6P + Glycerophospholipids [GP] with formula: C39H82NO6P Glycerophospholipids [GP] with formula: C35H74NO6P Glycerophospholipids [GP] with formula: C34H72NO6P - Glycerophospholipids [GP] with formula: C38H80NO6P + Glycerophospholipids [GP] with formula: C38H80NO6P Glycerophospholipids [GP] with formula: C43H72NO6P Glycerophospholipids [GP] with formula: C45H76NO6P Glycerophospholipids [GP] with formula: C39H74NO6P Glycerophospholipids [GP] with formula: C43H74NO6P Glycerophospholipids [GP] with formula: C45H78NO6P Glycerophospholipids [GP] with formula: C45H94NO7P - Glycerophospholipids [GP] with formula: C23H48NO7P - Glycerophospholipids [GP] with formula: C21H44NO7P - Glycerophospholipids [GP] with formula: C19H40NO7P - Glycerophospholipids [GP] with formula: C17H36NO7P - Glycerophospholipids [GP] with formula: C23H46NO7P - Glycerophospholipids [GP] with formula: C18H38NO7P - Glycerophospholipids [GP] with formula: C22H44NO7P + Glycerophospholipids [GP] with formula: C23H48NO7P + Glycerophospholipids [GP] with formula: C21H44NO7P + Glycerophospholipids [GP] with formula: C19H40NO7P + Glycerophospholipids [GP] with formula: C23H46NO7P + Glycerophospholipids [GP] with formula: C17H36NO7P + Glycerophospholipids [GP] with formula: C18H38NO7P + Glycerophospholipids [GP] with formula: C22H44NO7P Glycerophospholipids [GP] with formula: C25H44NO7P + Glycerophospholipids [GP] with formula: C21H42NO7P + Glycerophospholipids [GP] with formula: C23H44NO7P + Glycerophospholipids [GP] with formula: C27H44NO7P + Glycerophospholipids [GP] with formula: C27H48NO7P + Glycerophospholipids [GP] with formula: C20H40NO7P + Glycerophospholipids [GP] with formula: C22H42NO7P + Glycerophospholipids [GP] with formula: C23H40NO7P + Glycerophospholipids [GP] with formula: C25H50NO7P + Glycerophospholipids [GP] with formula: C25H48NO7P + Glycerophospholipids [GP] with formula: C25H46NO7P + Glycerophospholipids [GP] with formula: C27H54NO7P + Glycerophospholipids [GP] with formula: C27H52NO7P + Glycerophospholipids [GP] with formula: C27H56NO7P + Glycerophospholipids [GP] with formula: C26H54NO7P + Glycerophospholipids [GP] with formula: C25H42NO7P + Glycerophospholipids [GP] with formula: C24H50NO7P + Glycerophospholipids [GP] with formula: C23H42NO7P + Glycerophospholipids [GP] with formula: C22H46NO7P + Glycerophospholipids [GP] with formula: C19H38NO7P Glycerophospholipids [GP] with formula: C25H46NO6P + Glycerophospholipids [GP] with formula: C23H50NO6P + Glycerophospholipids [GP] with formula: C25H54NO6P Glycerophospholipids [GP] with formula: C21H44NO6P + Glycerophospholipids [GP] with formula: C23H48NO6P + Glycerophospholipids [GP] with formula: C24H48NO6P + Glycerophospholipids [GP] with formula: C25H52NO6P Glycerophospholipids [GP] with formula: C43H70NO7P Glycerophospholipids [GP] with formula: C45H74NO7P - Glycerophospholipids [GP] with formula: C45H76NO7P - Glycerophospholipids [GP] with formula: C39H72NO7P + Glycerophospholipids [GP] with formula: C45H76NO7P Glycerophospholipids [GP] with formula: C43H72NO7P Glycerophospholipids [GP] with formula: C31H63N2O10P Glycerophospholipids [GP] with formula: C43H79N2O10P Glycerophospholipids [GP] with formula: C49H87N2O10P Glycerophospholipids [GP] with formula: C37H73N2O10P - Glycerophospholipids [GP] with formula: C42H76NO10P + Glycerophospholipids [GP] with formula: C18H34NO10P Glycerophospholipids [GP] with formula: C22H42NO10P Glycerophospholipids [GP] with formula: C26H50NO10P - Glycerophospholipids [GP] with formula: C42H74NO10P - Glycerophospholipids [GP] with formula: C40H76NO10P - Glycerophospholipids [GP] with formula: C42H80NO10P - Glycerophospholipids [GP] with formula: C18H34NO10P - Glycerophospholipids [GP] with formula: C30H58NO10P - Glycerophospholipids [GP] with formula: C34H66NO10P - Glycerophospholipids [GP] with formula: C38H74NO10P - Glycerophospholipids [GP] with formula: C42H78NO10P - Glycerophospholipids [GP] with formula: C42H82NO10P - Glycerophospholipids [GP] with formula: C43H84NO10P - Glycerophospholipids [GP] with formula: C44H78NO10P - Glycerophospholipids [GP] with formula: C46H78NO10P + Glycerophospholipids [GP] with formula: C30H58NO10P Glycerophospholipids [GP] with formula: C58H110NO11P Glycerophospholipids [GP] with formula: C61H114NO11P - Glycerophospholipids [GP] with formula: C38H78NO8P + Glycerophospholipids [GP] with formula: C32H60NO10P + Glycerophospholipids [GP] with formula: C35H68NO10P + Glycerophospholipids [GP] with formula: C31H60NO10P + Glycerophospholipids [GP] with formula: C37H64NO10P + Glycerophospholipids [GP] with formula: C39H68NO10P + Glycerophospholipids [GP] with formula: C39H66NO10P + Glycerophospholipids [GP] with formula: C33H62NO10P + Glycerophospholipids [GP] with formula: C34H64NO10P + Glycerophospholipids [GP] with formula: C35H66NO10P + Glycerophospholipids [GP] with formula: C35H64NO10P + Glycerophospholipids [GP] with formula: C36H68NO10P + Glycerophospholipids [GP] with formula: C37H70NO10P + Glycerophospholipids [GP] with formula: C37H66NO10P + Glycerophospholipids [GP] with formula: C38H72NO10P + Glycerophospholipids [GP] with formula: C40H66NO10P + Glycerophospholipids [GP] with formula: C42H80NO10P + Glycerophospholipids [GP] with formula: C42H72NO10P + Glycerophospholipids [GP] with formula: C42H68NO10P + Glycerophospholipids [GP] with formula: C33H64NO10P + Glycerophospholipids [GP] with formula: C45H74NO10P + Glycerophospholipids [GP] with formula: C41H72NO10P + Glycerophospholipids [GP] with formula: C41H68NO10P + Glycerophospholipids [GP] with formula: C43H80NO10P + Glycerophospholipids [GP] with formula: C43H72NO10P + Glycerophospholipids [GP] with formula: C43H70NO10P + Glycerophospholipids [GP] with formula: C45H84NO10P + Glycerophospholipids [GP] with formula: C45H82NO10P + Glycerophospholipids [GP] with formula: C45H80NO10P + Glycerophospholipids [GP] with formula: C45H76NO10P + Glycerophospholipids [GP] with formula: C45H72NO10P + Glycerophospholipids [GP] with formula: C37H72NO10P + Glycerophospholipids [GP] with formula: C46H88NO10P + Glycerophospholipids [GP] with formula: C46H86NO10P + Glycerophospholipids [GP] with formula: C39H74NO10P + Glycerophospholipids [GP] with formula: C41H78NO10P + Glycerophospholipids [GP] with formula: C46H84NO10P + Glycerophospholipids [GP] with formula: C36H66NO10P + Glycerophospholipids [GP] with formula: C37H68NO10P + Glycerophospholipids [GP] with formula: C38H70NO10P + Glycerophospholipids [GP] with formula: C38H68NO10P + Glycerophospholipids [GP] with formula: C39H72NO10P + Glycerophospholipids [GP] with formula: C39H70NO10P + Glycerophospholipids [GP] with formula: C40H72NO10P + Glycerophospholipids [GP] with formula: C41H76NO10P + Glycerophospholipids [GP] with formula: C41H74NO10P + Glycerophospholipids [GP] with formula: C36H64NO10P + Glycerophospholipids [GP] with formula: C44H72NO10P + Glycerophospholipids [GP] with formula: C44H70NO10P + Glycerophospholipids [GP] with formula: C36H62NO10P + Glycerophospholipids [GP] with formula: C41H70NO10P + Glycerophospholipids [GP] with formula: C42H74NO10P + Glycerophospholipids [GP] with formula: C42H66NO10P + Glycerophospholipids [GP] with formula: C46H82NO10P + Glycerophospholipids [GP] with formula: C46H80NO10P + Glycerophospholipids [GP] with formula: C46H78NO10P + Glycerophospholipids [GP] with formula: C46H74NO10P + Glycerophospholipids [GP] with formula: C46H70NO10P + Glycerophospholipids [GP] with formula: C45H78NO10P + Glycerophospholipids [GP] with formula: C46H90NO10P + Glycerophospholipids [GP] with formula: C47H92NO10P + Glycerophospholipids [GP] with formula: C47H90NO10P + Glycerophospholipids [GP] with formula: C47H88NO10P + Glycerophospholipids [GP] with formula: C47H84NO10P + Glycerophospholipids [GP] with formula: C47H80NO10P + Glycerophospholipids [GP] with formula: C43H82NO10P + Glycerophospholipids [GP] with formula: C43H78NO10P + Glycerophospholipids [GP] with formula: C43H76NO10P + Glycerophospholipids [GP] with formula: C43H74NO10P + Glycerophospholipids [GP] with formula: C44H84NO10P + Glycerophospholipids [GP] with formula: C44H82NO10P + Glycerophospholipids [GP] with formula: C45H86NO10P + Glycerophospholipids [GP] with formula: C47H78NO10P + Glycerophospholipids [GP] with formula: C40H76NO10P + Glycerophospholipids [GP] with formula: C41H80NO10P + Glycerophospholipids [GP] with formula: C44H80NO10P + Glycerophospholipids [GP] with formula: C48H92NO10P + Glycerophospholipids [GP] with formula: C48H90NO10P + Glycerophospholipids [GP] with formula: C48H88NO10P + Glycerophospholipids [GP] with formula: C48H84NO10P + Glycerophospholipids [GP] with formula: C48H80NO10P + Glycerophospholipids [GP] with formula: C44H78NO10P + Glycerophospholipids [GP] with formula: C44H76NO10P + Glycerophospholipids [GP] with formula: C44H74NO10P + Glycerophospholipids [GP] with formula: C46H76NO10P + Glycerophospholipids [GP] with formula: C48H86NO10P + Glycerophospholipids [GP] with formula: C38H64NO10P + Glycerophospholipids [GP] with formula: C44H68NO10P + Glycerophospholipids [GP] with formula: C47H82NO10P + Glycerophospholipids [GP] with formula: C43H84NO10P + Glycerophospholipids [GP] with formula: C44H86NO10P + Glycerophospholipids [GP] with formula: C47H86NO10P + Glycerophospholipids [GP] with formula: C49H96NO10P + Glycerophospholipids [GP] with formula: C49H94NO10P + Glycerophospholipids [GP] with formula: C50H96NO10P + Glycerophospholipids [GP] with formula: C50H94NO10P + Glycerophospholipids [GP] with formula: C50H92NO10P + Glycerophospholipids [GP] with formula: C50H88NO10P + Glycerophospholipids [GP] with formula: C50H84NO10P + Glycerophospholipids [GP] with formula: C40H74NO10P + Glycerophospholipids [GP] with formula: C42H78NO10P + Glycerophospholipids [GP] with formula: C42H76NO10P + Glycerophospholipids [GP] with formula: C49H92NO10P + Glycerophospholipids [GP] with formula: C50H90NO10P + Glycerophospholipids [GP] with formula: C50H86NO10P + Glycerophospholipids [GP] with formula: C50H82NO10P + Glycerophospholipids [GP] with formula: C46H72NO10P + Glycerophospholipids [GP] with formula: C48H82NO10P + Glycerophospholipids [GP] with formula: C48H78NO10P + Glycerophospholipids [GP] with formula: C48H76NO10P + Glycerophospholipids [GP] with formula: C48H74NO10P + Glycerophospholipids [GP] with formula: C49H84NO10P + Glycerophospholipids [GP] with formula: C50H78NO10P + Glycerophospholipids [GP] with formula: C48H94NO10P + Glycerophospholipids [GP] with formula: C45H88NO10P + Glycerophospholipids [GP] with formula: C48H72NO10P + Glycerophospholipids [GP] with formula: C39H76NO10P + Glycerophospholipids [GP] with formula: C36H70NO10P + Glycerophospholipids [GP] with formula: C34H62NO10P + Glycerophospholipids [GP] with formula: C42H70NO10P + Glycerophospholipids [GP] with formula: C42H82NO10P + Glycerophospholipids [GP] with formula: C40H68NO10P + Glycerophospholipids [GP] with formula: C40H70NO10P + Glycerophospholipids [GP] with formula: C40H78NO10P + Glycerophospholipids [GP] with formula: C38H66NO10P + Glycerophospholipids [GP] with formula: C38H74NO10P + Glycerophospholipids [GP] with formula: C34H66NO10P + Glycerophospholipids [GP] with formula: C50H98NO10P + Glycerophospholipids [GP] with formula: C32H62NO10P + Glycerophospholipids [GP] with formula: C34H68NO9P + Glycerophospholipids [GP] with formula: C35H70NO9P + Glycerophospholipids [GP] with formula: C36H70NO9P + Glycerophospholipids [GP] with formula: C37H72NO9P + Glycerophospholipids [GP] with formula: C38H74NO9P + Glycerophospholipids [GP] with formula: C40H72NO9P + Glycerophospholipids [GP] with formula: C42H82NO9P + Glycerophospholipids [GP] with formula: C42H80NO9P + Glycerophospholipids [GP] with formula: C43H86NO9P + Glycerophospholipids [GP] with formula: C44H86NO9P + Glycerophospholipids [GP] with formula: C44H84NO9P + Glycerophospholipids [GP] with formula: C44H80NO9P + Glycerophospholipids [GP] with formula: C36H72NO9P + Glycerophospholipids [GP] with formula: C37H74NO9P + Glycerophospholipids [GP] with formula: C41H82NO9P + Glycerophospholipids [GP] with formula: C42H78NO9P + Glycerophospholipids [GP] with formula: C43H84NO9P + Glycerophospholipids [GP] with formula: C45H90NO9P + Glycerophospholipids [GP] with formula: C47H94NO9P + Glycerophospholipids [GP] with formula: C48H94NO9P + Glycerophospholipids [GP] with formula: C48H92NO9P + Glycerophospholipids [GP] with formula: C48H88NO9P + Glycerophospholipids [GP] with formula: C48H96NO9P + Glycerophospholipids [GP] with formula: C40H74NO9P + Glycerophospholipids [GP] with formula: C40H80NO9P + Glycerophospholipids [GP] with formula: C39H78NO9P + Glycerophospholipids [GP] with formula: C38H76NO9P + Glycerophospholipids [GP] with formula: C46H80NO9P + Glycerophospholipids [GP] with formula: C46H92NO9P + Glycerophospholipids [GP] with formula: C42H84NO9P + Glycerophospholipids [GP] with formula: C44H88NO9P + Glycerophospholipids [GP] with formula: C48H84NO9P + Glycerophospholipids [GP] with formula: C34H66NO9P + Glycerophospholipids [GP] with formula: C35H68NO9P + Glycerophospholipids [GP] with formula: C36H68NO9P + Glycerophospholipids [GP] with formula: C37H70NO9P + Glycerophospholipids [GP] with formula: C39H74NO9P + Glycerophospholipids [GP] with formula: C39H72NO9P + Glycerophospholipids [GP] with formula: C40H70NO9P + Glycerophospholipids [GP] with formula: C41H80NO9P + Glycerophospholipids [GP] with formula: C41H78NO9P + Glycerophospholipids [GP] with formula: C42H72NO9P + Glycerophospholipids [GP] with formula: C38H72NO9P + Glycerophospholipids [GP] with formula: C41H76NO9P + Glycerophospholipids [GP] with formula: C42H76NO9P + Glycerophospholipids [GP] with formula: C42H74NO9P + Glycerophospholipids [GP] with formula: C43H82NO9P + Glycerophospholipids [GP] with formula: C44H82NO9P + Glycerophospholipids [GP] with formula: C44H76NO9P + Glycerophospholipids [GP] with formula: C45H88NO9P + Glycerophospholipids [GP] with formula: C46H90NO9P + Glycerophospholipids [GP] with formula: C46H88NO9P + Glycerophospholipids [GP] with formula: C46H86NO9P + Glycerophospholipids [GP] with formula: C39H76NO9P + Glycerophospholipids [GP] with formula: C40H78NO9P + Glycerophospholipids [GP] with formula: C40H76NO9P + Glycerophospholipids [GP] with formula: C43H80NO9P + Glycerophospholipids [GP] with formula: C44H78NO9P + Glycerophospholipids [GP] with formula: C45H86NO9P + Glycerophospholipids [GP] with formula: C47H92NO9P + Glycerophospholipids [GP] with formula: C48H90NO9P + Glycerophospholipids [GP] with formula: C48H86NO9P + Glycerophospholipids [GP] with formula: C46H78NO9P + Glycerophospholipids [GP] with formula: C44H74NO9P + Glycerophospholipids [GP] with formula: C48H82NO9P + Glycerophospholipids [GP] with formula: C24H46NO9P Glycerophospholipids [GP] with formula: C22H44NO9P - Glycerophospholipids [GP] with formula: C24H48NO9P - Glycerophospholipids [GP] with formula: C24H46NO9P Glycerophospholipids [GP] with formula: C19H38NO9P + Glycerophospholipids [GP] with formula: C24H48NO9P Glycerophospholipids [GP] with formula: C26H44NO9P + Glycerophospholipids [GP] with formula: C18H36NO9P + Glycerophospholipids [GP] with formula: C20H40NO9P + Glycerophospholipids [GP] with formula: C22H42NO9P + Glycerophospholipids [GP] with formula: C24H44NO9P + Glycerophospholipids [GP] with formula: C26H52NO9P + Glycerophospholipids [GP] with formula: C28H44NO9P + Glycerophospholipids [GP] with formula: C28H48NO9P + Glycerophospholipids [GP] with formula: C21H40NO9P + Glycerophospholipids [GP] with formula: C23H42NO9P + Glycerophospholipids [GP] with formula: C24H40NO9P + Glycerophospholipids [GP] with formula: C25H48NO9P + Glycerophospholipids [GP] with formula: C26H50NO9P + Glycerophospholipids [GP] with formula: C26H48NO9P + Glycerophospholipids [GP] with formula: C26H46NO9P + Glycerophospholipids [GP] with formula: C28H54NO9P + Glycerophospholipids [GP] with formula: C28H52NO9P + Glycerophospholipids [GP] with formula: C28H56NO9P + Glycerophospholipids [GP] with formula: C27H54NO9P + Glycerophospholipids [GP] with formula: C26H42NO9P + Glycerophospholipids [GP] with formula: C25H50NO9P + Glycerophospholipids [GP] with formula: C24H42NO9P + Glycerophospholipids [GP] with formula: C23H46NO9P + Glycerophospholipids [GP] with formula: C21H42NO9P + Glycerophospholipids [GP] with formula: C20H38NO9P + Glycerophospholipids [GP] with formula: C23H44NO9P + Glycerophospholipids [GP] with formula: C26H54NO8P + Glycerophospholipids [GP] with formula: C24H50NO8P + Glycerophospholipids [GP] with formula: C22H46NO8P Glycerophospholipids [GP] with formula: C31H64NO10P Glycerophospholipids [GP] with formula: C40H80NO10P - Glycerophospholipids [GP] with formula: C49H88NO10P - Glycerophospholipids [GP] with formula: C34H67O10P - Glycerophospholipids [GP] with formula: C43H80NO10P + Glycerophospholipids [GP] with formula: C49H88NO10P Glycerophospholipids [GP] with formula: C37H74NO10P - Glycerophospholipids [GP] with formula: C40H77O10P - Glycerophospholipids [GP] with formula: C40H79O10P - Glycerophospholipids [GP] with formula: C36H71O10P - Glycerophospholipids [GP] with formula: C38H75O10P - Glycerophospholipids [GP] with formula: C18H35O10P - Glycerophospholipids [GP] with formula: C22H43O10P - Glycerophospholipids [GP] with formula: C26H51O10P - Glycerophospholipids [GP] with formula: C42H79O10P - Glycerophospholipids [GP] with formula: C30H59O10P - Glycerophospholipids [GP] with formula: C42H75O10P - Glycerophospholipids [GP] with formula: C42H81O10P - Glycerophospholipids [GP] with formula: C42H83O10P - Glycerophospholipids [GP] with formula: C44H79O10P - Glycerophospholipids [GP] with formula: C46H79O10P - Glycerophospholipids [GP] with formula: C38H79O8P - Glycerophospholipids [GP] with formula: C44H73O8P - Glycerophospholipids [GP] with formula: C40H75O8P + Glycerophospholipids [GP] with formula: C34H67O10P + Glycerophospholipids [GP] with formula: C18H35O10P + Glycerophospholipids [GP] with formula: C22H43O10P + Glycerophospholipids [GP] with formula: C26H51O10P + Glycerophospholipids [GP] with formula: C30H59O10P + Glycerophospholipids [GP] with formula: C48H75O10P + Glycerophospholipids [GP] with formula: C33H63O10P + Glycerophospholipids [GP] with formula: C34H65O10P + Glycerophospholipids [GP] with formula: C31H61O10P + Glycerophospholipids [GP] with formula: C33H65O10P + Glycerophospholipids [GP] with formula: C32H61O10P + Glycerophospholipids [GP] with formula: C40H67O10P + Glycerophospholipids [GP] with formula: C35H69O10P + Glycerophospholipids [GP] with formula: C35H67O10P + Glycerophospholipids [GP] with formula: C36H69O10P + Glycerophospholipids [GP] with formula: C41H79O10P + Glycerophospholipids [GP] with formula: C41H77O10P + Glycerophospholipids [GP] with formula: C41H69O10P + Glycerophospholipids [GP] with formula: C43H83O10P + Glycerophospholipids [GP] with formula: C43H81O10P + Glycerophospholipids [GP] with formula: C43H79O10P + Glycerophospholipids [GP] with formula: C39H75O10P + Glycerophospholipids [GP] with formula: C40H75O10P + Glycerophospholipids [GP] with formula: C42H83O10P + Glycerophospholipids [GP] with formula: C37H71O10P + Glycerophospholipids [GP] with formula: C37H69O10P + Glycerophospholipids [GP] with formula: C43H75O10P + Glycerophospholipids [GP] with formula: C45H85O10P + Glycerophospholipids [GP] with formula: C35H65O10P + Glycerophospholipids [GP] with formula: C36H67O10P + Glycerophospholipids [GP] with formula: C43H77O10P + Glycerophospholipids [GP] with formula: C39H77O10P + Glycerophospholipids [GP] with formula: C45H89O10P + Glycerophospholipids [GP] with formula: C45H87O10P + Glycerophospholipids [GP] with formula: C44H81O10P + Glycerophospholipids [GP] with formula: C45H83O10P + Glycerophospholipids [GP] with formula: C36H65O10P + Glycerophospholipids [GP] with formula: C37H67O10P + Glycerophospholipids [GP] with formula: C38H69O10P + Glycerophospholipids [GP] with formula: C39H71O10P + Glycerophospholipids [GP] with formula: C40H71O10P + Glycerophospholipids [GP] with formula: C41H75O10P + Glycerophospholipids [GP] with formula: C41H73O10P + Glycerophospholipids [GP] with formula: C41H71O10P + Glycerophospholipids [GP] with formula: C42H73O10P + Glycerophospholipids [GP] with formula: C42H71O10P + Glycerophospholipids [GP] with formula: C46H85O10P + Glycerophospholipids [GP] with formula: C46H83O10P + Glycerophospholipids [GP] with formula: C46H81O10P + Glycerophospholipids [GP] with formula: C46H77O10P + Glycerophospholipids [GP] with formula: C46H73O10P + Glycerophospholipids [GP] with formula: C36H63O10P + Glycerophospholipids [GP] with formula: C37H65O10P + Glycerophospholipids [GP] with formula: C38H67O10P + Glycerophospholipids [GP] with formula: C38H65O10P + Glycerophospholipids [GP] with formula: C39H69O10P + Glycerophospholipids [GP] with formula: C40H69O10P + Glycerophospholipids [GP] with formula: C42H67O10P + Glycerophospholipids [GP] with formula: C46H71O10P + Glycerophospholipids [GP] with formula: C47H93O10P + Glycerophospholipids [GP] with formula: C47H85O10P + Glycerophospholipids [GP] with formula: C47H81O10P + Glycerophospholipids [GP] with formula: C39H73O10P + Glycerophospholipids [GP] with formula: C47H87O10P + Glycerophospholipids [GP] with formula: C47H79O10P + Glycerophospholipids [GP] with formula: C47H91O10P + Glycerophospholipids [GP] with formula: C48H93O10P + Glycerophospholipids [GP] with formula: C48H91O10P + Glycerophospholipids [GP] with formula: C48H89O10P + Glycerophospholipids [GP] with formula: C44H77O10P + Glycerophospholipids [GP] with formula: C44H75O10P + Glycerophospholipids [GP] with formula: C44H73O10P + Glycerophospholipids [GP] with formula: C44H71O10P + Glycerophospholipids [GP] with formula: C45H81O10P + Glycerophospholipids [GP] with formula: C45H79O10P + Glycerophospholipids [GP] with formula: C48H79O10P + Glycerophospholipids [GP] with formula: C39H67O10P + Glycerophospholipids [GP] with formula: C44H69O10P + Glycerophospholipids [GP] with formula: C49H95O10P + Glycerophospholipids [GP] with formula: C49H97O10P + Glycerophospholipids [GP] with formula: C50H97O10P + Glycerophospholipids [GP] with formula: C47H89O10P + Glycerophospholipids [GP] with formula: C48H81O10P + Glycerophospholipids [GP] with formula: C49H93O10P + Glycerophospholipids [GP] with formula: C50H95O10P + Glycerophospholipids [GP] with formula: C50H93O10P + Glycerophospholipids [GP] with formula: C50H91O10P + Glycerophospholipids [GP] with formula: C50H87O10P + Glycerophospholipids [GP] with formula: C50H83O10P + Glycerophospholipids [GP] with formula: C47H83O10P + Glycerophospholipids [GP] with formula: C48H87O10P + Glycerophospholipids [GP] with formula: C48H85O10P + Glycerophospholipids [GP] with formula: C48H83O10P + Glycerophospholipids [GP] with formula: C49H89O10P + Glycerophospholipids [GP] with formula: C50H89O10P + Glycerophospholipids [GP] with formula: C42H69O10P + Glycerophospholipids [GP] with formula: C43H73O10P + Glycerophospholipids [GP] with formula: C43H71O10P + Glycerophospholipids [GP] with formula: C45H77O10P + Glycerophospholipids [GP] with formula: C45H75O10P + Glycerophospholipids [GP] with formula: C45H73O10P + Glycerophospholipids [GP] with formula: C46H79O10P + Glycerophospholipids [GP] with formula: C46H75O10P + Glycerophospholipids [GP] with formula: C48H77O10P + Glycerophospholipids [GP] with formula: C48H73O10P + Glycerophospholipids [GP] with formula: C49H85O10P + Glycerophospholipids [GP] with formula: C50H85O10P + Glycerophospholipids [GP] with formula: C50H79O10P + Glycerophospholipids [GP] with formula: C48H95O10P + Glycerophospholipids [GP] with formula: C46H87O10P + Glycerophospholipids [GP] with formula: C40H79O10P + Glycerophospholipids [GP] with formula: C37H73O10P + Glycerophospholipids [GP] with formula: C36H71O10P + Glycerophospholipids [GP] with formula: C34H63O10P + Glycerophospholipids [GP] with formula: C32H63O10P + Glycerophospholipids [GP] with formula: C50H99O10P + Glycerophospholipids [GP] with formula: C41H81O10P + Glycerophospholipids [GP] with formula: C40H73O10P + Glycerophospholipids [GP] with formula: C42H75O10P + Glycerophospholipids [GP] with formula: C46H89O10P + Glycerophospholipids [GP] with formula: C42H77O10P + Glycerophospholipids [GP] with formula: C42H81O10P + Glycerophospholipids [GP] with formula: C40H77O10P + Glycerophospholipids [GP] with formula: C44H83O10P + Glycerophospholipids [GP] with formula: C44H85O10P + Glycerophospholipids [GP] with formula: C43H85O10P + Glycerophospholipids [GP] with formula: C38H71O10P + Glycerophospholipids [GP] with formula: C44H79O10P + Glycerophospholipids [GP] with formula: C44H87O10P + Glycerophospholipids [GP] with formula: C50H75O10P + Glycerophospholipids [GP] with formula: C46H91O10P + Glycerophospholipids [GP] with formula: C38H73O10P + Glycerophospholipids [GP] with formula: C42H79O10P + Glycerophospholipids [GP] with formula: C38H75O10P + Glycerophospholipids [GP] with formula: C34H69O9P + Glycerophospholipids [GP] with formula: C35H71O9P + Glycerophospholipids [GP] with formula: C39H75O9P + Glycerophospholipids [GP] with formula: C41H81O9P + Glycerophospholipids [GP] with formula: C42H83O9P + Glycerophospholipids [GP] with formula: C36H73O9P + Glycerophospholipids [GP] with formula: C37H75O9P + Glycerophospholipids [GP] with formula: C42H77O9P + Glycerophospholipids [GP] with formula: C43H87O9P + Glycerophospholipids [GP] with formula: C43H85O9P + Glycerophospholipids [GP] with formula: C38H77O9P + Glycerophospholipids [GP] with formula: C39H79O9P + Glycerophospholipids [GP] with formula: C43H83O9P + Glycerophospholipids [GP] with formula: C44H89O9P + Glycerophospholipids [GP] with formula: C44H87O9P + Glycerophospholipids [GP] with formula: C44H85O9P + Glycerophospholipids [GP] with formula: C44H83O9P + Glycerophospholipids [GP] with formula: C45H91O9P + Glycerophospholipids [GP] with formula: C46H93O9P + Glycerophospholipids [GP] with formula: C47H95O9P + Glycerophospholipids [GP] with formula: C48H95O9P + Glycerophospholipids [GP] with formula: C48H93O9P + Glycerophospholipids [GP] with formula: C48H89O9P + Glycerophospholipids [GP] with formula: C48H97O9P + Glycerophospholipids [GP] with formula: C42H85O9P + Glycerophospholipids [GP] with formula: C40H81O9P + Glycerophospholipids [GP] with formula: C42H75O9P + Glycerophospholipids [GP] with formula: C42H79O9P + Glycerophospholipids [GP] with formula: C41H83O9P + Glycerophospholipids [GP] with formula: C40H75O9P + Glycerophospholipids [GP] with formula: C48H85O9P + Glycerophospholipids [GP] with formula: C34H67O9P + Glycerophospholipids [GP] with formula: C35H69O9P + Glycerophospholipids [GP] with formula: C36H71O9P + Glycerophospholipids [GP] with formula: C36H69O9P + Glycerophospholipids [GP] with formula: C37H73O9P + Glycerophospholipids [GP] with formula: C37H71O9P + Glycerophospholipids [GP] with formula: C38H73O9P + Glycerophospholipids [GP] with formula: C39H73O9P + Glycerophospholipids [GP] with formula: C40H71O9P + Glycerophospholipids [GP] with formula: C42H73O9P + Glycerophospholipids [GP] with formula: C41H77O9P + Glycerophospholipids [GP] with formula: C44H77O9P + Glycerophospholipids [GP] with formula: C45H89O9P + Glycerophospholipids [GP] with formula: C46H91O9P + Glycerophospholipids [GP] with formula: C46H89O9P + Glycerophospholipids [GP] with formula: C46H87O9P + Glycerophospholipids [GP] with formula: C46H83O9P + Glycerophospholipids [GP] with formula: C38H75O9P + Glycerophospholipids [GP] with formula: C39H77O9P + Glycerophospholipids [GP] with formula: C40H79O9P + Glycerophospholipids [GP] with formula: C40H77O9P + Glycerophospholipids [GP] with formula: C41H79O9P + Glycerophospholipids [GP] with formula: C43H81O9P + Glycerophospholipids [GP] with formula: C44H81O9P + Glycerophospholipids [GP] with formula: C44H79O9P + Glycerophospholipids [GP] with formula: C45H87O9P + Glycerophospholipids [GP] with formula: C46H85O9P + Glycerophospholipids [GP] with formula: C46H81O9P + Glycerophospholipids [GP] with formula: C47H93O9P + Glycerophospholipids [GP] with formula: C48H91O9P + Glycerophospholipids [GP] with formula: C48H87O9P + Glycerophospholipids [GP] with formula: C46H79O9P + Glycerophospholipids [GP] with formula: C42H81O9P + Glycerophospholipids [GP] with formula: C44H75O9P + Glycerophospholipids [GP] with formula: C48H83O9P Glycerophospholipids [GP] with formula: C46H77O8P - Glycerophospholipids [GP] with formula: C46H79O8P + Glycerophospholipids [GP] with formula: C46H79O8P Glycerophospholipids [GP] with formula: C46H75O9P Glycerophospholipids [GP] with formula: C46H95O9P - Glycerophospholipids [GP] with formula: C20H41O9P - Glycerophospholipids [GP] with formula: C24H47O9P + Glycerophospholipids [GP] with formula: C24H47O9P Glycerophospholipids [GP] with formula: C19H39O9P - Glycerophospholipids [GP] with formula: C22H45O9P - Glycerophospholipids [GP] with formula: C24H49O9P + Glycerophospholipids [GP] with formula: C22H45O9P + Glycerophospholipids [GP] with formula: C24H49O9P Glycerophospholipids [GP] with formula: C26H45O9P + Glycerophospholipids [GP] with formula: C18H37O9P + Glycerophospholipids [GP] with formula: C20H41O9P + Glycerophospholipids [GP] with formula: C22H43O9P + Glycerophospholipids [GP] with formula: C24H45O9P + Glycerophospholipids [GP] with formula: C26H53O9P + Glycerophospholipids [GP] with formula: C28H45O9P + Glycerophospholipids [GP] with formula: C28H49O9P + Glycerophospholipids [GP] with formula: C21H41O9P + Glycerophospholipids [GP] with formula: C23H43O9P + Glycerophospholipids [GP] with formula: C24H41O9P + Glycerophospholipids [GP] with formula: C25H49O9P + Glycerophospholipids [GP] with formula: C26H51O9P + Glycerophospholipids [GP] with formula: C26H49O9P + Glycerophospholipids [GP] with formula: C26H47O9P + Glycerophospholipids [GP] with formula: C28H55O9P + Glycerophospholipids [GP] with formula: C28H53O9P + Glycerophospholipids [GP] with formula: C28H57O9P + Glycerophospholipids [GP] with formula: C27H55O9P + Glycerophospholipids [GP] with formula: C26H43O9P + Glycerophospholipids [GP] with formula: C25H51O9P + Glycerophospholipids [GP] with formula: C24H43O9P + Glycerophospholipids [GP] with formula: C23H47O9P + Glycerophospholipids [GP] with formula: C21H43O9P + Glycerophospholipids [GP] with formula: C20H39O9P + Glycerophospholipids [GP] with formula: C23H45O9P + Glycerophospholipids [GP] with formula: C26H55O8P + Glycerophospholipids [GP] with formula: C24H51O8P + Glycerophospholipids [GP] with formula: C22H47O8P + Glycerophospholipids [GP] with formula: C26H53O8P + Glycerophospholipids [GP] with formula: C24H49O8P + Glycerophospholipids [GP] with formula: C22H45O8P Glycerophospholipids [GP] with formula: C48H93O11P Glycerophospholipids [GP] with formula: C60H111O11P - Glycerophospholipids [GP] with formula: C44H71O10P - Glycerophospholipids [GP] with formula: C40H73O9P + Glycerophospholipids [GP] with formula: C40H73O9P Glycerophospholipids [GP] with formula: C44H71O9P Glycerophospholipids [GP] with formula: C44H73O9P Glycerophospholipids [GP] with formula: C46H77O9P Glycerophospholipids [GP] with formula: C40H78O13P2 - Glycerophospholipids [GP] with formula: C43H81O13P Glycerophospholipids [GP] with formula: C45H86NO13P Glycerophospholipids [GP] with formula: C34H68NO13P Glycerophospholipids [GP] with formula: C46H84NO13P Glycerophospholipids [GP] with formula: C52H92NO13P Glycerophospholipids [GP] with formula: C40H78NO13P - Glycerophospholipids [GP] with formula: C41H79O13P - Glycerophospholipids [GP] with formula: C45H87O13P - Glycerophospholipids [GP] with formula: C45H83O13P - Glycerophospholipids [GP] with formula: C47H83O13P + Glycerophospholipids [GP] with formula: C35H65O13P + Glycerophospholipids [GP] with formula: C36H69O13P + Glycerophospholipids [GP] with formula: C36H67O13P + Glycerophospholipids [GP] with formula: C37H69O13P + Glycerophospholipids [GP] with formula: C38H73O13P + Glycerophospholipids [GP] with formula: C38H71O13P + Glycerophospholipids [GP] with formula: C39H67O13P + Glycerophospholipids [GP] with formula: C41H71O13P + Glycerophospholipids [GP] with formula: C41H69O13P + Glycerophospholipids [GP] with formula: C42H81O13P + Glycerophospholipids [GP] with formula: C43H81O13P + Glycerophospholipids [GP] with formula: C34H65O13P + Glycerophospholipids [GP] with formula: C40H69O13P + Glycerophospholipids [GP] with formula: C41H77O13P + Glycerophospholipids [GP] with formula: C42H79O13P + Glycerophospholipids [GP] with formula: C42H77O13P + Glycerophospholipids [GP] with formula: C42H75O13P + Glycerophospholipids [GP] with formula: C42H71O13P + Glycerophospholipids [GP] with formula: C43H77O13P + Glycerophospholipids [GP] with formula: C43H73O13P + Glycerophospholipids [GP] with formula: C38H69O13P + Glycerophospholipids [GP] with formula: C44H73O13P + Glycerophospholipids [GP] with formula: C46H75O13P + Glycerophospholipids [GP] with formula: C39H71O13P + Glycerophospholipids [GP] with formula: C48H91O13P + Glycerophospholipids [GP] with formula: C48H89O13P + Glycerophospholipids [GP] with formula: C40H75O13P + Glycerophospholipids [GP] with formula: C40H73O13P + Glycerophospholipids [GP] with formula: C46H79O13P + Glycerophospholipids [GP] with formula: C46H77O13P + Glycerophospholipids [GP] with formula: C48H81O13P + Glycerophospholipids [GP] with formula: C48H77O13P + Glycerophospholipids [GP] with formula: C40H77O13P + Glycerophospholipids [GP] with formula: C44H85O13P + Glycerophospholipids [GP] with formula: C44H81O13P + Glycerophospholipids [GP] with formula: C45H81O13P + Glycerophospholipids [GP] with formula: C46H87O13P + Glycerophospholipids [GP] with formula: C48H93O13P + Glycerophospholipids [GP] with formula: C49H93O13P + Glycerophospholipids [GP] with formula: C45H73O13P + Glycerophospholipids [GP] with formula: C46H83O13P + Glycerophospholipids [GP] with formula: C46H81O13P + Glycerophospholipids [GP] with formula: C47H85O13P + Glycerophospholipids [GP] with formula: C47H83O13P + Glycerophospholipids [GP] with formula: C47H81O13P + Glycerophospholipids [GP] with formula: C47H79O13P + Glycerophospholipids [GP] with formula: C47H77O13P + Glycerophospholipids [GP] with formula: C47H75O13P + Glycerophospholipids [GP] with formula: C48H87O13P + Glycerophospholipids [GP] with formula: C39H69O13P + Glycerophospholipids [GP] with formula: C40H71O13P + Glycerophospholipids [GP] with formula: C42H73O13P + Glycerophospholipids [GP] with formula: C43H75O13P + Glycerophospholipids [GP] with formula: C44H79O13P + Glycerophospholipids [GP] with formula: C44H77O13P + Glycerophospholipids [GP] with formula: C44H75O13P + Glycerophospholipids [GP] with formula: C45H77O13P + Glycerophospholipids [GP] with formula: C45H75O13P + Glycerophospholipids [GP] with formula: C45H71O13P + Glycerophospholipids [GP] with formula: C49H85O13P + Glycerophospholipids [GP] with formula: C44H83O13P + Glycerophospholipids [GP] with formula: C45H87O13P + Glycerophospholipids [GP] with formula: C50H93O13P + Glycerophospholipids [GP] with formula: C46H85O13P + Glycerophospholipids [GP] with formula: C49H79O13P + Glycerophospholipids [GP] with formula: C50H91O13P + Glycerophospholipids [GP] with formula: C51H93O13P + Glycerophospholipids [GP] with formula: C51H91O13P + Glycerophospholipids [GP] with formula: C51H89O13P + Glycerophospholipids [GP] with formula: C51H81O13P + Glycerophospholipids [GP] with formula: C48H85O13P + Glycerophospholipids [GP] with formula: C48H83O13P + Glycerophospholipids [GP] with formula: C49H87O13P + Glycerophospholipids [GP] with formula: C49H83O13P + Glycerophospholipids [GP] with formula: C49H81O13P + Glycerophospholipids [GP] with formula: C47H73O13P + Glycerophospholipids [GP] with formula: C52H93O13P + Glycerophospholipids [GP] with formula: C49H89O13P + Glycerophospholipids [GP] with formula: C50H97O13P + Glycerophospholipids [GP] with formula: C50H95O13P + Glycerophospholipids [GP] with formula: C51H95O13P + Glycerophospholipids [GP] with formula: C52H101O13P + Glycerophospholipids [GP] with formula: C53H101O13P + Glycerophospholipids [GP] with formula: C52H99O13P + Glycerophospholipids [GP] with formula: C53H93O13P + Glycerophospholipids [GP] with formula: C52H97O13P + Glycerophospholipids [GP] with formula: C53H99O13P + Glycerophospholipids [GP] with formula: C53H97O13P + Glycerophospholipids [GP] with formula: C53H95O13P + Glycerophospholipids [GP] with formula: C53H87O13P + Glycerophospholipids [GP] with formula: C50H89O13P + Glycerophospholipids [GP] with formula: C50H87O13P + Glycerophospholipids [GP] with formula: C51H85O13P + Glycerophospholipids [GP] with formula: C48H79O13P + Glycerophospholipids [GP] with formula: C49H77O13P + Glycerophospholipids [GP] with formula: C49H75O13P + Glycerophospholipids [GP] with formula: C50H85O13P + Glycerophospholipids [GP] with formula: C50H83O13P + Glycerophospholipids [GP] with formula: C51H87O13P + Glycerophospholipids [GP] with formula: C51H83O13P + Glycerophospholipids [GP] with formula: C51H79O13P + Glycerophospholipids [GP] with formula: C51H77O13P + Glycerophospholipids [GP] with formula: C52H89O13P + Glycerophospholipids [GP] with formula: C53H89O13P + Glycerophospholipids [GP] with formula: C45H79O13P + Glycerophospholipids [GP] with formula: C37H67O13P + Glycerophospholipids [GP] with formula: C41H73O13P + Glycerophospholipids [GP] with formula: C43H71O13P + Glycerophospholipids [GP] with formula: C43H83O13P + Glycerophospholipids [GP] with formula: C41H79O13P + Glycerophospholipids [GP] with formula: C39H73O13P + Glycerophospholipids [GP] with formula: C39H75O13P + Glycerophospholipids [GP] with formula: C37H71O13P + Glycerophospholipids [GP] with formula: C53H103O13P + Glycerophospholipids [GP] with formula: C51H97O13P + Glycerophospholipids [GP] with formula: C51H99O13P + Glycerophospholipids [GP] with formula: C49H91O13P + Glycerophospholipids [GP] with formula: C47H89O13P + Glycerophospholipids [GP] with formula: C47H87O13P + Glycerophospholipids [GP] with formula: C47H91O13P + Glycerophospholipids [GP] with formula: C46H89O13P + Glycerophospholipids [GP] with formula: C41H75O13P + Glycerophospholipids [GP] with formula: C35H67O13P + Glycerophospholipids [GP] with formula: C53H79O13P + Glycerophospholipids [GP] with formula: C53H83O13P + Glycerophospholipids [GP] with formula: C53H91O13P + Glycerophospholipids [GP] with formula: C49H95O13P + Glycerophospholipids [GP] with formula: C45H83O13P + Glycerophospholipids [GP] with formula: C45H85O13P + Glycerophospholipids [GP] with formula: C43H79O13P + Glycerophospholipids [GP] with formula: C33H63O13P + Glycerophospholipids [GP] with formula: C51H89O12P + Glycerophospholipids [GP] with formula: C37H73O12P + Glycerophospholipids [GP] with formula: C38H75O12P + Glycerophospholipids [GP] with formula: C39H77O12P + Glycerophospholipids [GP] with formula: C39H75O12P + Glycerophospholipids [GP] with formula: C40H79O12P + Glycerophospholipids [GP] with formula: C41H81O12P + Glycerophospholipids [GP] with formula: C42H83O12P + Glycerophospholipids [GP] with formula: C49H93O12P + Glycerophospholipids [GP] with formula: C46H91O12P + Glycerophospholipids [GP] with formula: C46H89O12P + Glycerophospholipids [GP] with formula: C46H87O12P + Glycerophospholipids [GP] with formula: C47H93O12P + Glycerophospholipids [GP] with formula: C47H91O12P + Glycerophospholipids [GP] with formula: C47H87O12P + Glycerophospholipids [GP] with formula: C47H85O12P + Glycerophospholipids [GP] with formula: C48H95O12P + Glycerophospholipids [GP] with formula: C48H93O12P + Glycerophospholipids [GP] with formula: C49H97O12P + Glycerophospholipids [GP] with formula: C49H95O12P + Glycerophospholipids [GP] with formula: C49H87O12P + Glycerophospholipids [GP] with formula: C50H99O12P + Glycerophospholipids [GP] with formula: C51H99O12P + Glycerophospholipids [GP] with formula: C51H97O12P + Glycerophospholipids [GP] with formula: C51H93O12P + Glycerophospholipids [GP] with formula: C51H101O12P + Glycerophospholipids [GP] with formula: C45H89O12P + Glycerophospholipids [GP] with formula: C43H83O12P + Glycerophospholipids [GP] with formula: C43H85O12P + Glycerophospholipids [GP] with formula: C45H83O12P + Glycerophospholipids [GP] with formula: C44H87O12P + Glycerophospholipids [GP] with formula: C43H79O12P + Glycerophospholipids [GP] with formula: C49H85O12P + Glycerophospholipids [GP] with formula: C47H81O12P + Glycerophospholipids [GP] with formula: C51H87O12P + Glycerophospholipids [GP] with formula: C37H71O12P + Glycerophospholipids [GP] with formula: C38H73O12P + Glycerophospholipids [GP] with formula: C39H73O12P + Glycerophospholipids [GP] with formula: C40H75O12P + Glycerophospholipids [GP] with formula: C42H77O12P + Glycerophospholipids [GP] with formula: C43H77O12P + Glycerophospholipids [GP] with formula: C43H75O12P + Glycerophospholipids [GP] with formula: C45H77O12P + Glycerophospholipids [GP] with formula: C40H77O12P + Glycerophospholipids [GP] with formula: C41H79O12P + Glycerophospholipids [GP] with formula: C41H77O12P + Glycerophospholipids [GP] with formula: C42H81O12P + Glycerophospholipids [GP] with formula: C42H79O12P + Glycerophospholipids [GP] with formula: C43H81O12P + Glycerophospholipids [GP] with formula: C44H85O12P + Glycerophospholipids [GP] with formula: C44H83O12P + Glycerophospholipids [GP] with formula: C44H81O12P + Glycerophospholipids [GP] with formula: C45H87O12P + Glycerophospholipids [GP] with formula: C45H81O12P + Glycerophospholipids [GP] with formula: C45H79O12P + Glycerophospholipids [GP] with formula: C47H89O12P + Glycerophospholipids [GP] with formula: C46H85O12P + Glycerophospholipids [GP] with formula: C48H91O12P + Glycerophospholipids [GP] with formula: C49H91O12P + Glycerophospholipids [GP] with formula: C49H89O12P + Glycerophospholipids [GP] with formula: C50H97O12P + Glycerophospholipids [GP] with formula: C51H95O12P + Glycerophospholipids [GP] with formula: C51H91O12P + Glycerophospholipids [GP] with formula: C49H83O12P + Glycerophospholipids [GP] with formula: C47H83O12P + Glycerophospholipids [GP] with formula: C45H85O12P + Glycerophospholipids [GP] with formula: C47H79O12P Glycerophospholipids [GP] with formula: C59H119O11P Glycerophospholipids [GP] with formula: C22H43O12P Glycerophospholipids [GP] with formula: C25H49O12P - Glycerophospholipids [GP] with formula: C26H49O12P Glycerophospholipids [GP] with formula: C27H53O12P Glycerophospholipids [GP] with formula: C27H51O12P Glycerophospholipids [GP] with formula: C29H49O12P + Glycerophospholipids [GP] with formula: C21H41O12P + Glycerophospholipids [GP] with formula: C23H45O12P + Glycerophospholipids [GP] with formula: C25H47O12P + Glycerophospholipids [GP] with formula: C27H49O12P + Glycerophospholipids [GP] with formula: C29H57O12P + Glycerophospholipids [GP] with formula: C31H49O12P + Glycerophospholipids [GP] with formula: C31H53O12P + Glycerophospholipids [GP] with formula: C24H45O12P + Glycerophospholipids [GP] with formula: C26H47O12P + Glycerophospholipids [GP] with formula: C27H47O12P + Glycerophospholipids [GP] with formula: C27H45O12P + Glycerophospholipids [GP] with formula: C28H53O12P + Glycerophospholipids [GP] with formula: C29H55O12P + Glycerophospholipids [GP] with formula: C29H53O12P + Glycerophospholipids [GP] with formula: C29H51O12P + Glycerophospholipids [GP] with formula: C31H59O12P + Glycerophospholipids [GP] with formula: C31H57O12P + Glycerophospholipids [GP] with formula: C31H61O12P + Glycerophospholipids [GP] with formula: C30H59O12P + Glycerophospholipids [GP] with formula: C29H47O12P + Glycerophospholipids [GP] with formula: C28H55O12P + Glycerophospholipids [GP] with formula: C26H51O12P + Glycerophospholipids [GP] with formula: C24H47O12P + Glycerophospholipids [GP] with formula: C23H43O12P + Glycerophospholipids [GP] with formula: C26H49O12P + Glycerophospholipids [GP] with formula: C29H59O11P + Glycerophospholipids [GP] with formula: C27H55O11P + Glycerophospholipids [GP] with formula: C25H51O11P + Glycerophospholipids [GP] with formula: C29H57O11P + Glycerophospholipids [GP] with formula: C27H53O11P + Glycerophospholipids [GP] with formula: C25H49O11P Glycerophospholipids [GP] with formula: C43H82O16P2 Glycerophospholipids [GP] with formula: C46H88N2O16P2 Glycerophospholipids [GP] with formula: C46H92N3O19P3 Glycerophospholipids [GP] with formula: C46H84O22P4 Glycerophospholipids [GP] with formula: C28H58NO8P - Glycerophospholipids [GP] with formula: C40H74NO8P - Glycerophospholipids [GP] with formula: C33H65O8P - Glycerophospholipids [GP] with formula: C35H69O8P - Glycerophospholipids [GP] with formula: C39H77O8P - Glycerophospholipids [GP] with formula: C39H65O8P - Glycerophospholipids [GP] with formula: C35H67O8P Glycerophospholipids [GP] with formula: C15H29O8P Glycerophospholipids [GP] with formula: C19H37O8P - Glycerophospholipids [GP] with formula: C23H45O8P - Glycerophospholipids [GP] with formula: C37H69O8P - Glycerophospholipids [GP] with formula: C41H73O8P - Glycerophospholipids [GP] with formula: C39H69O8P - Glycerophospholipids [GP] with formula: C31H61O8P - Glycerophospholipids [GP] with formula: C27H53O8P - Glycerophospholipids [GP] with formula: C37H71O8P - Glycerophospholipids [GP] with formula: C43H85O8P - Glycerophospholipids [GP] with formula: C39H73O8P - Glycerophospholipids [GP] with formula: C39H75O8P - Glycerophospholipids [GP] with formula: C41H69O8P - Glycerophospholipids [GP] with formula: C43H73O8P - Glycerophospholipids [GP] with formula: C31H65O6P - Glycerophospholipids [GP] with formula: C35H73O6P + Glycerophospholipids [GP] with formula: C23H45O8P + Glycerophospholipids [GP] with formula: C27H53O8P + Glycerophospholipids [GP] with formula: C43H85O8P + Glycerophospholipids [GP] with formula: C47H69O8P + Glycerophospholipids [GP] with formula: C28H55O8P + Glycerophospholipids [GP] with formula: C30H59O8P + Glycerophospholipids [GP] with formula: C37H69O8P + Glycerophospholipids [GP] with formula: C29H55O8P + Glycerophospholipids [GP] with formula: C35H59O8P + Glycerophospholipids [GP] with formula: C37H63O8P + Glycerophospholipids [GP] with formula: C33H63O8P + Glycerophospholipids [GP] with formula: C35H67O8P + Glycerophospholipids [GP] with formula: C35H65O8P + Glycerophospholipids [GP] with formula: C36H69O8P + Glycerophospholipids [GP] with formula: C36H65O8P + Glycerophospholipids [GP] with formula: C36H63O8P + Glycerophospholipids [GP] with formula: C37H71O8P + Glycerophospholipids [GP] with formula: C38H73O8P + Glycerophospholipids [GP] with formula: C30H57O8P + Glycerophospholipids [GP] with formula: C31H59O8P + Glycerophospholipids [GP] with formula: C32H59O8P + Glycerophospholipids [GP] with formula: C33H61O8P + Glycerophospholipids [GP] with formula: C35H63O8P + Glycerophospholipids [GP] with formula: C36H61O8P + Glycerophospholipids [GP] with formula: C32H61O8P + Glycerophospholipids [GP] with formula: C34H65O8P + Glycerophospholipids [GP] with formula: C34H63O8P + Glycerophospholipids [GP] with formula: C38H63O8P + Glycerophospholipids [GP] with formula: C39H73O8P + Glycerophospholipids [GP] with formula: C40H71O8P + Glycerophospholipids [GP] with formula: C40H69O8P + Glycerophospholipids [GP] with formula: C40H67O8P + Glycerophospholipids [GP] with formula: C40H65O8P + Glycerophospholipids [GP] with formula: C38H71O8P + Glycerophospholipids [GP] with formula: C39H67O8P + Glycerophospholipids [GP] with formula: C39H65O8P + Glycerophospholipids [GP] with formula: C40H75O8P + Glycerophospholipids [GP] with formula: C40H73O8P + Glycerophospholipids [GP] with formula: C41H77O8P + Glycerophospholipids [GP] with formula: C41H75O8P + Glycerophospholipids [GP] with formula: C41H71O8P + Glycerophospholipids [GP] with formula: C37H65O8P + Glycerophospholipids [GP] with formula: C38H69O8P + Glycerophospholipids [GP] with formula: C38H67O8P + Glycerophospholipids [GP] with formula: C38H65O8P + Glycerophospholipids [GP] with formula: C39H71O8P + Glycerophospholipids [GP] with formula: C39H69O8P + Glycerophospholipids [GP] with formula: C33H59O8P + Glycerophospholipids [GP] with formula: C34H61O8P + Glycerophospholipids [GP] with formula: C39H63O8P + Glycerophospholipids [GP] with formula: C43H71O8P + Glycerophospholipids [GP] with formula: C43H67O8P + Glycerophospholipids [GP] with formula: C33H57O8P + Glycerophospholipids [GP] with formula: C34H59O8P + Glycerophospholipids [GP] with formula: C35H61O8P + Glycerophospholipids [GP] with formula: C39H61O8P + Glycerophospholipids [GP] with formula: C41H69O8P + Glycerophospholipids [GP] with formula: C41H65O8P + Glycerophospholipids [GP] with formula: C41H63O8P + Glycerophospholipids [GP] with formula: C44H75O8P + Glycerophospholipids [GP] with formula: C42H73O8P + Glycerophospholipids [GP] with formula: C42H71O8P + Glycerophospholipids [GP] with formula: C44H81O8P + Glycerophospholipids [GP] with formula: C44H77O8P + Glycerophospholipids [GP] with formula: C44H73O8P + Glycerophospholipids [GP] with formula: C44H87O8P + Glycerophospholipids [GP] with formula: C43H73O8P + Glycerophospholipids [GP] with formula: C45H77O8P + Glycerophospholipids [GP] with formula: C45H73O8P + Glycerophospholipids [GP] with formula: C45H75O8P + Glycerophospholipids [GP] with formula: C45H71O8P + Glycerophospholipids [GP] with formula: C41H67O8P + Glycerophospholipids [GP] with formula: C45H69O8P + Glycerophospholipids [GP] with formula: C43H65O8P + Glycerophospholipids [GP] with formula: C43H83O8P + Glycerophospholipids [GP] with formula: C46H83O8P + Glycerophospholipids [GP] with formula: C40H79O8P + Glycerophospholipids [GP] with formula: C40H77O8P + Glycerophospholipids [GP] with formula: C41H79O8P + Glycerophospholipids [GP] with formula: C42H83O8P + Glycerophospholipids [GP] with formula: C42H81O8P + Glycerophospholipids [GP] with formula: C42H79O8P + Glycerophospholipids [GP] with formula: C43H81O8P + Glycerophospholipids [GP] with formula: C46H91O8P + Glycerophospholipids [GP] with formula: C44H85O8P + Glycerophospholipids [GP] with formula: C44H83O8P + Glycerophospholipids [GP] with formula: C45H87O8P + Glycerophospholipids [GP] with formula: C45H85O8P + Glycerophospholipids [GP] with formula: C45H83O8P + Glycerophospholipids [GP] with formula: C45H81O8P + Glycerophospholipids [GP] with formula: C45H79O8P + Glycerophospholipids [GP] with formula: C46H89O8P + Glycerophospholipids [GP] with formula: C47H91O8P + Glycerophospholipids [GP] with formula: C47H89O8P + Glycerophospholipids [GP] with formula: C47H87O8P + Glycerophospholipids [GP] with formula: C47H83O8P + Glycerophospholipids [GP] with formula: C42H77O8P + Glycerophospholipids [GP] with formula: C42H75O8P + Glycerophospholipids [GP] with formula: C43H79O8P + Glycerophospholipids [GP] with formula: C43H77O8P + Glycerophospholipids [GP] with formula: C43H75O8P + Glycerophospholipids [GP] with formula: C46H87O8P + Glycerophospholipids [GP] with formula: C44H79O8P + Glycerophospholipids [GP] with formula: C47H85O8P + Glycerophospholipids [GP] with formula: C42H69O8P + Glycerophospholipids [GP] with formula: C42H67O8P + Glycerophospholipids [GP] with formula: C43H69O8P + Glycerophospholipids [GP] with formula: C45H67O8P + Glycerophospholipids [GP] with formula: C47H81O8P + Glycerophospholipids [GP] with formula: C47H79O8P + Glycerophospholipids [GP] with formula: C47H77O8P + Glycerophospholipids [GP] with formula: C47H73O8P + Glycerophospholipids [GP] with formula: C36H71O8P + Glycerophospholipids [GP] with formula: C34H67O8P + Glycerophospholipids [GP] with formula: C37H73O8P + Glycerophospholipids [GP] with formula: C36H67O8P + Glycerophospholipids [GP] with formula: C35H69O8P + Glycerophospholipids [GP] with formula: C31H57O8P + Glycerophospholipids [GP] with formula: C32H63O8P + Glycerophospholipids [GP] with formula: C29H57O8P + Glycerophospholipids [GP] with formula: C37H61O8P + Glycerophospholipids [GP] with formula: C47H93O8P + Glycerophospholipids [GP] with formula: C45H89O8P + Glycerophospholipids [GP] with formula: C41H73O8P + Glycerophospholipids [GP] with formula: C41H81O8P + Glycerophospholipids [GP] with formula: C39H75O8P + Glycerophospholipids [GP] with formula: C39H77O8P + Glycerophospholipids [GP] with formula: C38H75O8P + Glycerophospholipids [GP] with formula: C37H67O8P + Glycerophospholipids [GP] with formula: C31H61O8P + Glycerophospholipids [GP] with formula: C33H65O8P + Glycerophospholipids [GP] with formula: C31H63O7P + Glycerophospholipids [GP] with formula: C32H65O7P + Glycerophospholipids [GP] with formula: C33H67O7P + Glycerophospholipids [GP] with formula: C33H65O7P + Glycerophospholipids [GP] with formula: C34H67O7P + Glycerophospholipids [GP] with formula: C36H69O7P + Glycerophospholipids [GP] with formula: C37H67O7P + Glycerophospholipids [GP] with formula: C34H69O7P + Glycerophospholipids [GP] with formula: C35H69O7P + Glycerophospholipids [GP] with formula: C36H71O7P + Glycerophospholipids [GP] with formula: C38H77O7P + Glycerophospholipids [GP] with formula: C38H73O7P + Glycerophospholipids [GP] with formula: C39H77O7P + Glycerophospholipids [GP] with formula: C39H75O7P + Glycerophospholipids [GP] with formula: C43H85O7P + Glycerophospholipids [GP] with formula: C43H83O7P + Glycerophospholipids [GP] with formula: C43H79O7P + Glycerophospholipids [GP] with formula: C35H71O7P + Glycerophospholipids [GP] with formula: C36H73O7P + Glycerophospholipids [GP] with formula: C37H75O7P + Glycerophospholipids [GP] with formula: C37H73O7P + Glycerophospholipids [GP] with formula: C38H75O7P + Glycerophospholipids [GP] with formula: C40H81O7P + Glycerophospholipids [GP] with formula: C42H85O7P + Glycerophospholipids [GP] with formula: C42H83O7P + Glycerophospholipids [GP] with formula: C44H89O7P + Glycerophospholipids [GP] with formula: C45H83O7P + Glycerophospholipids [GP] with formula: C45H79O7P + Glycerophospholipids [GP] with formula: C45H91O7P + Glycerophospholipids [GP] with formula: C43H87O7P + Glycerophospholipids [GP] with formula: C41H71O7P + Glycerophospholipids [GP] with formula: C41H83O7P + Glycerophospholipids [GP] with formula: C39H79O7P + Glycerophospholipids [GP] with formula: C31H61O7P + Glycerophospholipids [GP] with formula: C32H63O7P + Glycerophospholipids [GP] with formula: C33H63O7P + Glycerophospholipids [GP] with formula: C34H65O7P + Glycerophospholipids [GP] with formula: C35H67O7P + Glycerophospholipids [GP] with formula: C36H67O7P + Glycerophospholipids [GP] with formula: C37H65O7P + Glycerophospholipids [GP] with formula: C39H67O7P + Glycerophospholipids [GP] with formula: C38H71O7P + Glycerophospholipids [GP] with formula: C39H73O7P + Glycerophospholipids [GP] with formula: C39H71O7P + Glycerophospholipids [GP] with formula: C39H69O7P + Glycerophospholipids [GP] with formula: C40H79O7P + Glycerophospholipids [GP] with formula: C40H77O7P + Glycerophospholipids [GP] with formula: C41H81O7P + Glycerophospholipids [GP] with formula: C41H79O7P + Glycerophospholipids [GP] with formula: C41H77O7P + Glycerophospholipids [GP] with formula: C41H75O7P + Glycerophospholipids [GP] with formula: C43H81O7P + Glycerophospholipids [GP] with formula: C43H77O7P + Glycerophospholipids [GP] with formula: C40H75O7P + Glycerophospholipids [GP] with formula: C41H73O7P + Glycerophospholipids [GP] with formula: C42H81O7P + Glycerophospholipids [GP] with formula: C43H75O7P + Glycerophospholipids [GP] with formula: C44H87O7P + Glycerophospholipids [GP] with formula: C45H89O7P + Glycerophospholipids [GP] with formula: C45H87O7P + Glycerophospholipids [GP] with formula: C45H85O7P + Glycerophospholipids [GP] with formula: C45H81O7P + Glycerophospholipids [GP] with formula: C45H77O7P + Glycerophospholipids [GP] with formula: C37H69O7P + Glycerophospholipids [GP] with formula: C37H71O7P + Glycerophospholipids [GP] with formula: C43H73O7P + Glycerophospholipids [GP] with formula: C41H69O7P + Glycerophospholipids [GP] with formula: C35H73O6P Glycerophospholipids [GP] with formula: C16H36NO7P - Glycerophospholipids [GP] with formula: C20H42NO7P Glycerophospholipids [GP] with formula: C24H44NO7P - Glycerophospholipids [GP] with formula: C22H42NO7P Glycerophospholipids [GP] with formula: C21H43O7P - Glycerophospholipids [GP] with formula: C19H39O7P - Glycerophospholipids [GP] with formula: C17H35O7P - Glycerophospholipids [GP] with formula: C21H41O7P - Glycerophospholipids [GP] with formula: C19H37O6P + Glycerophospholipids [GP] with formula: C19H39O7P + Glycerophospholipids [GP] with formula: C17H35O7P Glycerophospholipids [GP] with formula: C23H39O7P + Glycerophospholipids [GP] with formula: C21H41O7P + Glycerophospholipids [GP] with formula: C15H31O7P + Glycerophospholipids [GP] with formula: C19H37O7P + Glycerophospholipids [GP] with formula: C21H39O7P + Glycerophospholipids [GP] with formula: C23H47O7P + Glycerophospholipids [GP] with formula: C25H39O7P + Glycerophospholipids [GP] with formula: C25H43O7P + Glycerophospholipids [GP] with formula: C18H35O7P + Glycerophospholipids [GP] with formula: C20H37O7P + Glycerophospholipids [GP] with formula: C21H35O7P + Glycerophospholipids [GP] with formula: C22H43O7P + Glycerophospholipids [GP] with formula: C23H45O7P + Glycerophospholipids [GP] with formula: C23H43O7P + Glycerophospholipids [GP] with formula: C23H41O7P + Glycerophospholipids [GP] with formula: C25H49O7P + Glycerophospholipids [GP] with formula: C25H47O7P + Glycerophospholipids [GP] with formula: C25H51O7P + Glycerophospholipids [GP] with formula: C24H49O7P + Glycerophospholipids [GP] with formula: C23H37O7P + Glycerophospholipids [GP] with formula: C22H45O7P + Glycerophospholipids [GP] with formula: C21H37O7P + Glycerophospholipids [GP] with formula: C20H41O7P + Glycerophospholipids [GP] with formula: C18H37O7P + Glycerophospholipids [GP] with formula: C17H33O7P Glycerophospholipids [GP] with formula: C23H41O6P + Glycerophospholipids [GP] with formula: C23H49O6P + Glycerophospholipids [GP] with formula: C21H45O6P + Glycerophospholipids [GP] with formula: C19H41O6P + Glycerophospholipids [GP] with formula: C23H47O6P + Glycerophospholipids [GP] with formula: C21H43O6P + Glycerophospholipids [GP] with formula: C19H39O6P Glycerophospholipids [GP] with formula: C37H72O11P2 Glycerophospholipids [GP] with formula: C39H74O11P2 + Glycerophospholipids [GP] with formula: C81H142O17P2 Glycerophospholipids [GP] with formula: C95H184N2O17P2 Glycerophospholipids [GP] with formula: C66H126N2O17P2 Glycerophospholipids [GP] with formula: C70H140N2O17P2 Glycerophospholipids [GP] with formula: C89H172N2O17P2 Glycerophospholipids [GP] with formula: C77H146O17P2 + Glycerophospholipids [GP] with formula: C63H112O16P2 + Glycerophospholipids [GP] with formula: C45H82O15P2 Glycerophospholipids [GP] with formula: C89H182O13P2 Glycerophospholipids [GP] with formula: C36H65N3O15P2 Glycerophospholipids [GP] with formula: C46H83N3O15P2 @@ -1658,19 +2739,15 @@ Glycerophospholipids [GP] with formula: C48H85N3O15P2 Glycerophospholipids [GP] with formula: C65H129O16P Glycerophospholipids [GP] with formula: C64H121N2O35P2 - Glycerophospholipids [GP] with formula: C39H76NO7P Glycerophospholipids [GP] with formula: C88H178NO9P Glycerophospholipids [GP] with formula: C94H190NO15P - Glycerophospholipids [GP] with formula: C46H84NO9P - Glycerophospholipids [GP] with formula: C44H80NO9P - Glycerophospholipids [GP] with formula: C46H82NO9P + Glycerophospholipids [GP] with formula: C46H84NO9P + Glycerophospholipids [GP] with formula: C46H82NO9P Glycerophospholipids [GP] with formula: C43H78NO9P Glycerophospholipids [GP] with formula: C43H74NO9P Glycerophospholipids [GP] with formula: C45H78NO9P - Glycerophospholipids [GP] with formula: C43H76NO8P - Glycerophospholipids [GP] with formula: C43H78NO8P - Glycerophospholipids [GP] with formula: C43H74NO8P - Glycerophospholipids [GP] with formula: C45H78NO8P + Glycerophospholipids [GP] with formula: C81H142O19P2 + Glycerophospholipids [GP] with formula: C81H142O21P2 @@ -1720,6 +2797,15 @@ Prenol Lipids [PR] with formula: C12H20O2 Prenol Lipids [PR] with formula: C16H26O3 Prenol Lipids [PR] with formula: C15H28O7P2 + Prenol Lipids [PR] with formula: C17H34O2 + Prenol Lipids [PR] with formula: C21H40O2 + Prenol Lipids [PR] with formula: C23H44O2 + Prenol Lipids [PR] with formula: C25H48O2 + Prenol Lipids [PR] with formula: C23H42O2 + Prenol Lipids [PR] with formula: C25H46O2 + Prenol Lipids [PR] with formula: C23H40O2 + Prenol Lipids [PR] with formula: C25H44O2 + Prenol Lipids [PR] with formula: C27H48O2 Prenol Lipids [PR] with formula: C15H22O3 Prenol Lipids [PR] with formula: C14H24O Prenol Lipids [PR] with formula: C15H22O @@ -1736,7 +2822,7 @@ Prenol Lipids [PR] with formula: C15H18O3 Prenol Lipids [PR] with formula: C15H20O3 Prenol Lipids [PR] with formula: C15H22O5 - Prenol Lipids [PR] with formula: C15H24 + Prenol Lipids [PR] with formula: C15H24 Prenol Lipids [PR] with formula: C15H20O2 Prenol Lipids [PR] with formula: C15H18O Prenol Lipids [PR] with formula: C15H22O2 @@ -1745,12 +2831,12 @@ Prenol Lipids [PR] with formula: C30H30O8 Prenol Lipids [PR] with formula: C15H16O4 Prenol Lipids [PR] with formula: C17H28O4 - Prenol Lipids [PR] with formula: C15H20O4 Prenol Lipids [PR] with formula: C14H22O3 Prenol Lipids [PR] with formula: C34H50O12 Prenol Lipids [PR] with formula: C14H16 Prenol Lipids [PR] with formula: C17H22O5 Prenol Lipids [PR] with formula: C15H18 + Prenol Lipids [PR] with formula: C15H20O4 Prenol Lipids [PR] with formula: C17H24O3 Prenol Lipids [PR] with formula: C16H24 Prenol Lipids [PR] with formula: C18H30 @@ -1773,9 +2859,7 @@ Prenol Lipids [PR] with formula: C15H24O2 Prenol Lipids [PR] with formula: C15H24O Prenol Lipids [PR] with formula: C14H22O - Prenol Lipids [PR] with formula: C20H40O Prenol Lipids [PR] with formula: C20H40O2 - Prenol Lipids [PR] with formula: C20H42O Prenol Lipids [PR] with formula: C20H41O4P Prenol Lipids [PR] with formula: C20H34O2 Prenol Lipids [PR] with formula: C19H38O @@ -1787,7 +2871,16 @@ Prenol Lipids [PR] with formula: C20H24O4 Prenol Lipids [PR] with formula: C20H24O2 Prenol Lipids [PR] with formula: C19H38O2 - Prenol Lipids [PR] with formula: C20H38O2 + Prenol Lipids [PR] with formula: C20H38O2 + Prenol Lipids [PR] with formula: C20H38O + Prenol Lipids [PR] with formula: C20H42O + Prenol Lipids [PR] with formula: C20H40O + Prenol Lipids [PR] with formula: C26H50O2 + Prenol Lipids [PR] with formula: C28H54O2 + Prenol Lipids [PR] with formula: C30H58O2 + Prenol Lipids [PR] with formula: C28H52O2 + Prenol Lipids [PR] with formula: C30H56O2 + Prenol Lipids [PR] with formula: C28H50O2 Prenol Lipids [PR] with formula: C22H34O7 Prenol Lipids [PR] with formula: C20H36O7P2 Prenol Lipids [PR] with formula: C22H34O5 @@ -1876,24 +2969,25 @@ Prenol Lipids [PR] with formula: C25H38O4 Prenol Lipids [PR] with formula: C25H40O3 Prenol Lipids [PR] with formula: C24H38O2 + Prenol Lipids [PR] with formula: C30H50O2 Prenol Lipids [PR] with formula: C30H52O7P2 Prenol Lipids [PR] with formula: C30H54 Prenol Lipids [PR] with formula: C30H50 Prenol Lipids [PR] with formula: C30H62 + Prenol Lipids [PR] with formula: C30H52 Prenol Lipids [PR] with formula: C30H60 Prenol Lipids [PR] with formula: C34H58 Prenol Lipids [PR] with formula: C34H68 Prenol Lipids [PR] with formula: C31H48O6 Prenol Lipids [PR] with formula: C34H48O7 - Prenol Lipids [PR] with formula: C32H48O5 Prenol Lipids [PR] with formula: C30H52O2 - Prenol Lipids [PR] with formula: C30H50O + Prenol Lipids [PR] with formula: C30H50O Prenol Lipids [PR] with formula: C35H44O16 Prenol Lipids [PR] with formula: C22H28O6 Prenol Lipids [PR] with formula: C32H52O2 Prenol Lipids [PR] with formula: C30H46O3 Prenol Lipids [PR] with formula: C36H56O9 - Prenol Lipids [PR] with formula: C30H48O3 + Prenol Lipids [PR] with formula: C30H48O3 Prenol Lipids [PR] with formula: C30H48O4 Prenol Lipids [PR] with formula: C42H64O14 Prenol Lipids [PR] with formula: C30H48O5 @@ -1907,10 +3001,8 @@ Prenol Lipids [PR] with formula: C32H54O3 Prenol Lipids [PR] with formula: C30H52O Prenol Lipids [PR] with formula: C31H54O - Prenol Lipids [PR] with formula: C30H52 Prenol Lipids [PR] with formula: C31H50O3 Prenol Lipids [PR] with formula: C31H52O2 - Prenol Lipids [PR] with formula: C30H50O2 Prenol Lipids [PR] with formula: C39H50O7 Prenol Lipids [PR] with formula: C39H48O6 Prenol Lipids [PR] with formula: C47H66O9 @@ -1920,6 +3012,7 @@ Prenol Lipids [PR] with formula: C40H50 Prenol Lipids [PR] with formula: C40H52O Prenol Lipids [PR] with formula: C40H54O3 + Prenol Lipids [PR] with formula: C40H56O2 Prenol Lipids [PR] with formula: C40H50O4 Prenol Lipids [PR] with formula: C40H48O4 Prenol Lipids [PR] with formula: C40H52O2 @@ -1932,15 +3025,16 @@ Prenol Lipids [PR] with formula: C40H52O5 Prenol Lipids [PR] with formula: C40H50O3 Prenol Lipids [PR] with formula: C40H68 - Prenol Lipids [PR] with formula: C42H63 + Prenol Lipids [PR] with formula: C40H56 Prenol Lipids [PR] with formula: C40H58O2 Prenol Lipids [PR] with formula: C40H52O3 Prenol Lipids [PR] with formula: C52H76O12 Prenol Lipids [PR] with formula: C52H72O14 Prenol Lipids [PR] with formula: C40H54O4 - Prenol Lipids [PR] with formula: C40H56O4 + Prenol Lipids [PR] with formula: C40H56O4 Prenol Lipids [PR] with formula: C40H55NaO7S Prenol Lipids [PR] with formula: C40H54O5 + Prenol Lipids [PR] with formula: C61H94O8 Prenol Lipids [PR] with formula: C63H98O8 Prenol Lipids [PR] with formula: C82H134O14 Prenol Lipids [PR] with formula: C80H128O14 @@ -1971,17 +3065,15 @@ Prenol Lipids [PR] with formula: C52H76O4 Prenol Lipids [PR] with formula: C52H76O5 Prenol Lipids [PR] with formula: C40H53NaO8S - Prenol Lipids [PR] with formula: C40H54O2 + Prenol Lipids [PR] with formula: C40H54O2 Prenol Lipids [PR] with formula: C40H52 Prenol Lipids [PR] with formula: C47H68O6 Prenol Lipids [PR] with formula: C46H68O6 Prenol Lipids [PR] with formula: C47H70O7 Prenol Lipids [PR] with formula: C42H62O2 Prenol Lipids [PR] with formula: C46H66O8 - Prenol Lipids [PR] with formula: C40H56O2 Prenol Lipids [PR] with formula: C52H76O14 Prenol Lipids [PR] with formula: C35H46 - Prenol Lipids [PR] with formula: C61H94O8 Prenol Lipids [PR] with formula: C40H58 Prenol Lipids [PR] with formula: C40H56O5 Prenol Lipids [PR] with formula: C53H80O6 @@ -1993,7 +3085,6 @@ Prenol Lipids [PR] with formula: C26H32O4 Prenol Lipids [PR] with formula: C40H62O2 Prenol Lipids [PR] with formula: C40H58O3 - Prenol Lipids [PR] with formula: C40H56 Prenol Lipids [PR] with formula: C36H54O6 Prenol Lipids [PR] with formula: C40H68O7P2 Prenol Lipids [PR] with formula: C40H64 @@ -2002,13 +3093,13 @@ Prenol Lipids [PR] with formula: C40H74 Prenol Lipids [PR] with formula: C40H56O Prenol Lipids [PR] with formula: C25H34O3 - Prenol Lipids [PR] with formula: C40H60 + Prenol Lipids [PR] with formula: C40H60 Prenol Lipids [PR] with formula: C22H30O Prenol Lipids [PR] with formula: C30H42O Prenol Lipids [PR] with formula: C40H62 Prenol Lipids [PR] with formula: C50H72 Prenol Lipids [PR] with formula: C20H28O - Prenol Lipids [PR] with formula: C20H26O + Prenol Lipids [PR] with formula: C20H26O Prenol Lipids [PR] with formula: C20H30O Prenol Lipids [PR] with formula: C22H32O2 Prenol Lipids [PR] with formula: C36H60O2 @@ -2019,7 +3110,7 @@ Prenol Lipids [PR] with formula: C21H28O Prenol Lipids [PR] with formula: C23H32O Prenol Lipids [PR] with formula: C23H30O3 - Prenol Lipids [PR] with formula: C20H28O2 + Prenol Lipids [PR] with formula: C20H28O2 Prenol Lipids [PR] with formula: C26H36O8 Prenol Lipids [PR] with formula: C59H90O4 Prenol Lipids [PR] with formula: C39H58O4 @@ -2032,6 +3123,10 @@ Prenol Lipids [PR] with formula: C58H88O4 Prenol Lipids [PR] with formula: C53H80O4 Prenol Lipids [PR] with formula: C23H36O2 + Prenol Lipids [PR] with formula: C56H82O6S + Prenol Lipids [PR] with formula: C51H74O2 + Prenol Lipids [PR] with formula: C56H82O2 + Prenol Lipids [PR] with formula: C56H80O2 Prenol Lipids [PR] with formula: C29H50O2 Prenol Lipids [PR] with formula: C21H30O9 Prenol Lipids [PR] with formula: C29H44O2 @@ -2044,23 +3139,24 @@ Prenol Lipids [PR] with formula: C41H56O2 Prenol Lipids [PR] with formula: C50H70O2 Prenol Lipids [PR] with formula: C31H46O2 - Prenol Lipids [PR] with formula: C31H48O3 + Prenol Lipids [PR] with formula: C31H48O3 Prenol Lipids [PR] with formula: C31H48O2 Prenol Lipids [PR] with formula: C31H46O3 Prenol Lipids [PR] with formula: C55H90O Prenol Lipids [PR] with formula: C15H29O10P3 + Prenol Lipids [PR] with formula: C50H82O Prenol Lipids [PR] with formula: C55H91O4P Prenol Lipids [PR] with formula: C61H101O9P Prenol Lipids [PR] with formula: C31H51O10P Prenol Lipids [PR] with formula: C60H100NO7P - Prenol Lipids [PR] with formula: C50H83O4P + Prenol Lipids [PR] with formula: C50H83O4P Prenol Lipids [PR] with formula: C71H116N2O18P2 Prenol Lipids [PR] with formula: C95H156N8O28P2 Prenol Lipids [PR] with formula: C55H92O7P2 Prenol Lipids [PR] with formula: C35H60O7P2 Prenol Lipids [PR] with formula: C45H76O7P2 - Prenol Lipids [PR] with formula: C50H84O7P2 Prenol Lipids [PR] with formula: C61H102O12P2 + Prenol Lipids [PR] with formula: C50H84O7P2 Prenol Lipids [PR] with formula: C45H80O Prenol Lipids [PR] with formula: C95H156O Prenol Lipids [PR] with formula: C85H140O @@ -2112,6 +3208,69 @@ Saccharolipids [SL] with formula: C110H202N2O39P2 Saccharolipids [SL] with formula: C96H176N2O38P2 Saccharolipids [SL] with formula: C84H154N2O37P2 + Saccharolipids [SL] with formula: C52H98O14 + Saccharolipids [SL] with formula: C54H102O14 + Saccharolipids [SL] with formula: C56H106O14 + Saccharolipids [SL] with formula: C52H98O13 + Saccharolipids [SL] with formula: C53H100O13 + Saccharolipids [SL] with formula: C57H108O14 + Saccharolipids [SL] with formula: C58H110O14 + Saccharolipids [SL] with formula: C54H102O13 + Saccharolipids [SL] with formula: C55H104O13 + Saccharolipids [SL] with formula: C55H104O14 + Saccharolipids [SL] with formula: C59H112O14 + Saccharolipids [SL] with formula: C56H106O13 + Saccharolipids [SL] with formula: C57H108O13 + Saccharolipids [SL] with formula: C128H236O16 + Saccharolipids [SL] with formula: C130H242O17 + Saccharolipids [SL] with formula: C131H242O16 + Saccharolipids [SL] with formula: C133H246O16 + Saccharolipids [SL] with formula: C132H244O16 + Saccharolipids [SL] with formula: C130H240O16 + Saccharolipids [SL] with formula: C136H252O16 + Saccharolipids [SL] with formula: C136H254O17 + Saccharolipids [SL] with formula: C134H250O17 + Saccharolipids [SL] with formula: C136H256O18 + Saccharolipids [SL] with formula: C142H266O17 + Saccharolipids [SL] with formula: C133H248O17 + Saccharolipids [SL] with formula: C135H254O18 + Saccharolipids [SL] with formula: C134H252O18 + Saccharolipids [SL] with formula: C132H248O18 + Saccharolipids [SL] with formula: C134H254O19 + Saccharolipids [SL] with formula: C137H258O18 + Saccharolipids [SL] with formula: C140H264O18 + Saccharolipids [SL] with formula: C138H262O19 + Saccharolipids [SL] with formula: C136H258O19 + Saccharolipids [SL] with formula: C137H260O19 + Saccharolipids [SL] with formula: C136H260O20 + Saccharolipids [SL] with formula: C132H246O17 + Saccharolipids [SL] with formula: C134H248O16 + Saccharolipids [SL] with formula: C139H260O17 + Saccharolipids [SL] with formula: C140H262O17 + Saccharolipids [SL] with formula: C138H260O18 + Saccharolipids [SL] with formula: C135H250O16 + Saccharolipids [SL] with formula: C137H254O16 + Saccharolipids [SL] with formula: C138H256O16 + Saccharolipids [SL] with formula: C139H258O16 + Saccharolipids [SL] with formula: C137H256O17 + Saccharolipids [SL] with formula: C140H260O16 + Saccharolipids [SL] with formula: C135H252O17 + Saccharolipids [SL] with formula: C141H262O16 + Saccharolipids [SL] with formula: C144H268O16 + Saccharolipids [SL] with formula: C143H266O16 + Saccharolipids [SL] with formula: C145H270O16 + Saccharolipids [SL] with formula: C142H264O16 + Saccharolipids [SL] with formula: C146H272O16 + Saccharolipids [SL] with formula: C144H270O17 + Saccharolipids [SL] with formula: C142H268O18 + Saccharolipids [SL] with formula: C141H266O18 + Saccharolipids [SL] with formula: C140H266O19 + Saccharolipids [SL] with formula: C139H262O18 + Saccharolipids [SL] with formula: C143H268O17 + Saccharolipids [SL] with formula: C139H264O19 + Saccharolipids [SL] with formula: C138H258O17 + Saccharolipids [SL] with formula: C141H264O17 + Saccharolipids [SL] with formula: C138H264O20 Saccharolipids [SL] with formula: C18H32O8 @@ -2223,6 +3382,7 @@ Sphingolipids [SP] with formula: C36H71NO3 Sphingolipids [SP] with formula: C32H65NO3 Sphingolipids [SP] with formula: C42H85NO4 + Sphingolipids [SP] with formula: C35H71NO4 Sphingolipids [SP] with formula: C34H69NO4 Sphingolipids [SP] with formula: C42H85NO5 Sphingolipids [SP] with formula: C44H89NO5 @@ -2238,6 +3398,7 @@ Sphingolipids [SP] with formula: C42H84NO6P Sphingolipids [SP] with formula: C44H88NO6P Sphingolipids [SP] with formula: C46H90NO6P + Sphingolipids [SP] with formula: C26H52NO6P Sphingolipids [SP] with formula: C35H71N2O6P Sphingolipids [SP] with formula: C39H79N2O6P Sphingolipids [SP] with formula: C39H81N2O6P @@ -2284,9 +3445,20 @@ Sphingolipids [SP] with formula: C62H121NO26P2 Sphingolipids [SP] with formula: C56H110NO18P Sphingolipids [SP] with formula: C34H69N2O5P + Sphingolipids [SP] with formula: C36H73N2O5P + Sphingolipids [SP] with formula: C62H109NO10S + Sphingolipids [SP] with formula: C52H91NO13 + Sphingolipids [SP] with formula: C54H95NO13 + Sphingolipids [SP] with formula: C56H99NO13 + Sphingolipids [SP] with formula: C58H103NO13 + Sphingolipids [SP] with formula: C58H101NO13 + Sphingolipids [SP] with formula: C58H103NO14 + Sphingolipids [SP] with formula: C56H99NO14 + Sphingolipids [SP] with formula: C41H75NO9 Sphingolipids [SP] with formula: C36H69NO8 Sphingolipids [SP] with formula: C40H77NO8 Sphingolipids [SP] with formula: C40H79NO8 + Sphingolipids [SP] with formula: C46H89NO8 Sphingolipids [SP] with formula: C48H91NO8 Sphingolipids [SP] with formula: C50H95NO8 Sphingolipids [SP] with formula: C42H83NO8 @@ -2300,7 +3472,7 @@ Sphingolipids [SP] with formula: C42H79NO8 Sphingolipids [SP] with formula: C38H75NO8 Sphingolipids [SP] with formula: C42H81NO8 - Sphingolipids [SP] with formula: C44H85NO8 + Sphingolipids [SP] with formula: C44H85NO8 Sphingolipids [SP] with formula: C45H87NO8 Sphingolipids [SP] with formula: C47H91NO8 Sphingolipids [SP] with formula: C40H75NO8 @@ -2324,7 +3496,6 @@ Sphingolipids [SP] with formula: C56H107NO13 Sphingolipids [SP] with formula: C54H101NO13 Sphingolipids [SP] with formula: C48H91NO13 - Sphingolipids [SP] with formula: C46H89NO8 Sphingolipids [SP] with formula: C80H143N3O38 Sphingolipids [SP] with formula: C82H147N3O38 Sphingolipids [SP] with formula: C84H151N3O38 @@ -2435,7 +3606,7 @@ Sphingolipids [SP] with formula: C82H148N2O33 Sphingolipids [SP] with formula: C80H143N3O37 Sphingolipids [SP] with formula: C82H147N3O37 - Sphingolipids [SP] with formula: C84H151N3O37 + Sphingolipids [SP] with formula: C84H151N3O37 Sphingolipids [SP] with formula: C86H155N3O37 Sphingolipids [SP] with formula: C88H159N3O37 Sphingolipids [SP] with formula: C90H163N3O37 @@ -2596,10 +3767,10 @@ Sphingolipids [SP] with formula: C114H200N4O55 Sphingolipids [SP] with formula: C116H204N4O55 Sphingolipids [SP] with formula: C82H146N4O38 - Sphingolipids [SP] with formula: C84H150N4O38 - Sphingolipids [SP] with formula: C86H154N4O38 - Sphingolipids [SP] with formula: C88H158N4O38 - Sphingolipids [SP] with formula: C90H162N4O38 + Sphingolipids [SP] with formula: C84H150N4O38 + Sphingolipids [SP] with formula: C86H154N4O38 + Sphingolipids [SP] with formula: C88H158N4O38 + Sphingolipids [SP] with formula: C90H162N4O38 Sphingolipids [SP] with formula: C92H166N4O38 Sphingolipids [SP] with formula: C90H160N4O38 Sphingolipids [SP] with formula: C92H164N4O38 @@ -2789,7 +3960,7 @@ Sphingolipids [SP] with formula: C66H120N2O28 Sphingolipids [SP] with formula: C70H128N2O28 Sphingolipids [SP] with formula: C76H140N2O28 - Sphingolipids [SP] with formula: C72H131N3O28 + Sphingolipids [SP] with formula: C72H131N3O28 Sphingolipids [SP] with formula: C78H143N3O28 Sphingolipids [SP] with formula: C78H141N3O28 Sphingolipids [SP] with formula: C60H110N2O23 @@ -2800,6 +3971,8 @@ Sphingolipids [SP] with formula: C70H130N2O23 Sphingolipids [SP] with formula: C68H124N2O23 Sphingolipids [SP] with formula: C70H128N2O23 + Sphingolipids [SP] with formula: C53H92N3O27 + Sphingolipids [SP] with formula: C61H106N4O32 Sphingolipids [SP] with formula: C46H87NO13 Sphingolipids [SP] with formula: C56H105NO13 Sphingolipids [SP] with formula: C51H94N2O16 @@ -2885,7 +4058,7 @@ Sphingolipids [SP] with formula: C101H177N5O47 Sphingolipids [SP] with formula: C82H144N4O39 Sphingolipids [SP] with formula: C84H148N4O39 - Sphingolipids [SP] with formula: C86H152N4O39 + Sphingolipids [SP] with formula: C86H152N4O39 Sphingolipids [SP] with formula: C88H156N4O39 Sphingolipids [SP] with formula: C90H160N4O39 Sphingolipids [SP] with formula: C90H158N4O39 @@ -3005,14 +4178,14 @@ Sphingolipids [SP] with formula: C81H145N3O35 Sphingolipids [SP] with formula: C85H153N3O35 Sphingolipids [SP] with formula: C87H155N3O35 - Sphingolipids [SP] with formula: C57H103N2O22 - Sphingolipids [SP] with formula: C59H107N2O22 - Sphingolipids [SP] with formula: C61H111N2O22 - Sphingolipids [SP] with formula: C63H115N2O22 - Sphingolipids [SP] with formula: C65H119N2O22 - Sphingolipids [SP] with formula: C67H123N2O22 - Sphingolipids [SP] with formula: C65H117N2O22 - Sphingolipids [SP] with formula: C67H121N2O22 + Sphingolipids [SP] with formula: C65H117N3O27 + Sphingolipids [SP] with formula: C67H121N3O27 + Sphingolipids [SP] with formula: C69H125N3O27 + Sphingolipids [SP] with formula: C71H129N3O27 + Sphingolipids [SP] with formula: C73H133N3O27 + Sphingolipids [SP] with formula: C75H137N3O27 + Sphingolipids [SP] with formula: C74H133N3O27 + Sphingolipids [SP] with formula: C75H135N3O27 Sphingolipids [SP] with formula: C81H147N3O32 Sphingolipids [SP] with formula: C84H146N4O40 Sphingolipids [SP] with formula: C86H150N4O40 @@ -3322,32 +4495,29 @@ - Sterol Lipids [ST] with formula: C30H50O - Sterol Lipids [ST] with formula: C27H46O2 + Sterol Lipids [ST] with formula: C27H46O2 Sterol Lipids [ST] with formula: C27H48 Sterol Lipids [ST] with formula: C32H46O9 Sterol Lipids [ST] with formula: C32H46O8 Sterol Lipids [ST] with formula: C32H44O8 Sterol Lipids [ST] with formula: C30H42O7 Sterol Lipids [ST] with formula: C30H44O8 - Sterol Lipids [ST] with formula: C30H44O7 Sterol Lipids [ST] with formula: C30H46O7 - Sterol Lipids [ST] with formula: C30H48O7 Sterol Lipids [ST] with formula: C32H48O8 Sterol Lipids [ST] with formula: C30H42O6 - Sterol Lipids [ST] with formula: C29H46O2 + Sterol Lipids [ST] with formula: C28H44O + Sterol Lipids [ST] with formula: C28H46O2 Sterol Lipids [ST] with formula: C33H56O6 Sterol Lipids [ST] with formula: C27H44O9 Sterol Lipids [ST] with formula: C27H45O9P Sterol Lipids [ST] with formula: C27H45O8P Sterol Lipids [ST] with formula: C27H45O10P + Sterol Lipids [ST] with formula: C27H44O7 Sterol Lipids [ST] with formula: C29H47O10P Sterol Lipids [ST] with formula: C30H54 Sterol Lipids [ST] with formula: C29H46O7 Sterol Lipids [ST] with formula: C33H54O11 Sterol Lipids [ST] with formula: C27H42O6 - Sterol Lipids [ST] with formula: C27H44O7 - Sterol Lipids [ST] with formula: C27H44O6 Sterol Lipids [ST] with formula: C27H44O8 Sterol Lipids [ST] with formula: C26H45NO Sterol Lipids [ST] with formula: C26H46O5 @@ -3357,10 +4527,24 @@ Sterol Lipids [ST] with formula: C48H80N7O20P3S Sterol Lipids [ST] with formula: C48H78N7O19P3S Sterol Lipids [ST] with formula: C48H80N7O19P3S - Sterol Lipids [ST] with formula: C30H48O2 Sterol Lipids [ST] with formula: C30H50O2 - Sterol Lipids [ST] with formula: C30H52O2 Sterol Lipids [ST] with formula: C27H46 + Sterol Lipids [ST] with formula: C25H40O + Sterol Lipids [ST] with formula: C25H38O + Sterol Lipids [ST] with formula: C26H46O + Sterol Lipids [ST] with formula: C29H46O6 + Sterol Lipids [ST] with formula: C27H38O + Sterol Lipids [ST] with formula: C27H42O2 + Sterol Lipids [ST] with formula: C26H38O2 + Sterol Lipids [ST] with formula: C35H54O9 + Sterol Lipids [ST] with formula: C26H42O + Sterol Lipids [ST] with formula: C26H44O + Sterol Lipids [ST] with formula: C27H48O8 + Sterol Lipids [ST] with formula: C27H48O7 + Sterol Lipids [ST] with formula: C27H48O11S2 + Sterol Lipids [ST] with formula: C51H86O21 + Sterol Lipids [ST] with formula: C53H86O23 + Sterol Lipids [ST] with formula: C33H54O6 Sterol Lipids [ST] with formula: C39H68O2 Sterol Lipids [ST] with formula: C46H82O2 Sterol Lipids [ST] with formula: C45H78O2 @@ -3393,54 +4577,122 @@ Sterol Lipids [ST] with formula: C48H82O2 Sterol Lipids [ST] with formula: C43H72O2 Sterol Lipids [ST] with formula: C43H74O7 - Sterol Lipids [ST] with formula: C28H50O + Sterol Lipids [ST] with formula: C28H50O Sterol Lipids [ST] with formula: C30H48O - Sterol Lipids [ST] with formula: C29H50O - Sterol Lipids [ST] with formula: C28H46O - Sterol Lipids [ST] with formula: C29H48O - Sterol Lipids [ST] with formula: C28H48O - Sterol Lipids [ST] with formula: C28H50O3 - Sterol Lipids [ST] with formula: C28H50O4 + Sterol Lipids [ST] with formula: C28H46O + Sterol Lipids [ST] with formula: C28H48O + Sterol Lipids [ST] with formula: C28H50O3 + Sterol Lipids [ST] with formula: C28H50O4 Sterol Lipids [ST] with formula: C28H50O5 - Sterol Lipids [ST] with formula: C28H46O4 - Sterol Lipids [ST] with formula: C28H48O3 - Sterol Lipids [ST] with formula: C28H48O2 - Sterol Lipids [ST] with formula: C28H50O2 - Sterol Lipids [ST] with formula: C28H44O - Sterol Lipids [ST] with formula: C29H52O + Sterol Lipids [ST] with formula: C28H50O2 Sterol Lipids [ST] with formula: C28H42O - Sterol Lipids [ST] with formula: C28H46O2 - Sterol Lipids [ST] with formula: C29H44O Sterol Lipids [ST] with formula: C18H32O2 + Sterol Lipids [ST] with formula: C46H78O2 Sterol Lipids [ST] with formula: C46H76O2 Sterol Lipids [ST] with formula: C44H72O2 - Sterol Lipids [ST] with formula: C46H78O2 Sterol Lipids [ST] with formula: C44H74O2 Sterol Lipids [ST] with formula: C28H46O7 - Sterol Lipids [ST] with formula: C30H54O + Sterol Lipids [ST] with formula: C30H52O5 + Sterol Lipids [ST] with formula: C30H52O6 + Sterol Lipids [ST] with formula: C29H52O + Sterol Lipids [ST] with formula: C27H48O9 + Sterol Lipids [ST] with formula: C28H48O9 + Sterol Lipids [ST] with formula: C28H48O2 + Sterol Lipids [ST] with formula: C29H44O + Sterol Lipids [ST] with formula: C28H48O3 + Sterol Lipids [ST] with formula: C28H40O3 + Sterol Lipids [ST] with formula: C27H40O6S + Sterol Lipids [ST] with formula: C28H46O5 + Sterol Lipids [ST] with formula: C28H44O3 + Sterol Lipids [ST] with formula: C28H44O5 + Sterol Lipids [ST] with formula: C28H44O4 + Sterol Lipids [ST] with formula: C28H46O4 + Sterol Lipids [ST] with formula: C30H48O5 Sterol Lipids [ST] with formula: C29H40O8 Sterol Lipids [ST] with formula: C29H44O8 - Sterol Lipids [ST] with formula: C30H52O + Sterol Lipids [ST] with formula: C29H50O + Sterol Lipids [ST] with formula: C31H52O + Sterol Lipids [ST] with formula: C30H50O + Sterol Lipids [ST] with formula: C29H48O + Sterol Lipids [ST] with formula: C29H48O2 + Sterol Lipids [ST] with formula: C32H54O + Sterol Lipids [ST] with formula: C29H46O2 + Sterol Lipids [ST] with formula: C30H54O + Sterol Lipids [ST] with formula: C30H52O2 + Sterol Lipids [ST] with formula: C30H46O + Sterol Lipids [ST] with formula: C31H52O3 + Sterol Lipids [ST] with formula: C30H48O2 + Sterol Lipids [ST] with formula: C30H50O3 + Sterol Lipids [ST] with formula: C30H50O4 + Sterol Lipids [ST] with formula: C29H50O3 + Sterol Lipids [ST] with formula: C29H40O4 + Sterol Lipids [ST] with formula: C31H42O5 + Sterol Lipids [ST] with formula: C28H42O6S + Sterol Lipids [ST] with formula: C29H46O3 + Sterol Lipids [ST] with formula: C29H50O2 + Sterol Lipids [ST] with formula: C35H60O6 + Sterol Lipids [ST] with formula: C51H90O7 + Sterol Lipids [ST] with formula: C35H58O6 + Sterol Lipids [ST] with formula: C30H52O Sterol Lipids [ST] with formula: C31H50O - Sterol Lipids [ST] with formula: C31H52O - Sterol Lipids [ST] with formula: C31H54O Sterol Lipids [ST] with formula: C33H56O9 - Sterol Lipids [ST] with formula: C56H92O29 - Sterol Lipids [ST] with formula: C33H54O8 - Sterol Lipids [ST] with formula: C27H42O4 + Sterol Lipids [ST] with formula: C33H57NO8 + Sterol Lipids [ST] with formula: C57H92O27 + Sterol Lipids [ST] with formula: C59H100O26 + Sterol Lipids [ST] with formula: C53H88O23 + Sterol Lipids [ST] with formula: C52H86O21 + Sterol Lipids [ST] with formula: C53H88O22 + Sterol Lipids [ST] with formula: C53H90O22 + Sterol Lipids [ST] with formula: C52H88O22 + Sterol Lipids [ST] with formula: C54H94O22 + Sterol Lipids [ST] with formula: C56H92O29 + Sterol Lipids [ST] with formula: C33H54O8 + Sterol Lipids [ST] with formula: C34H48O7 + Sterol Lipids [ST] with formula: C27H40O5 + Sterol Lipids [ST] with formula: C27H42O3 + Sterol Lipids [ST] with formula: C26H36O8 + Sterol Lipids [ST] with formula: C27H40O4 + Sterol Lipids [ST] with formula: C27H40O3 + Sterol Lipids [ST] with formula: C46H76O16 + Sterol Lipids [ST] with formula: C40H66O12 + Sterol Lipids [ST] with formula: C52H86O22 + Sterol Lipids [ST] with formula: C46H76O17 + Sterol Lipids [ST] with formula: C52H86O20 + Sterol Lipids [ST] with formula: C40H66O14 + Sterol Lipids [ST] with formula: C40H66O15 + Sterol Lipids [ST] with formula: C40H66O16 + Sterol Lipids [ST] with formula: C57H96O28 + Sterol Lipids [ST] with formula: C34H58O10 + Sterol Lipids [ST] with formula: C40H68O15 + Sterol Lipids [ST] with formula: C57H96O27 + Sterol Lipids [ST] with formula: C56H94O27 + Sterol Lipids [ST] with formula: C34H56O9 + Sterol Lipids [ST] with formula: C46H76O19 + Sterol Lipids [ST] with formula: C51H86O23 + Sterol Lipids [ST] with formula: C51H84O23 + Sterol Lipids [ST] with formula: C52H86O23 + Sterol Lipids [ST] with formula: C57H94O27 + Sterol Lipids [ST] with formula: C56H92O27 + Sterol Lipids [ST] with formula: C58H98O27 + Sterol Lipids [ST] with formula: C34H58O9 + Sterol Lipids [ST] with formula: C56H92O28 + Sterol Lipids [ST] with formula: C34H56O8 + Sterol Lipids [ST] with formula: C27H42O4 Sterol Lipids [ST] with formula: C33H52O9 - Sterol Lipids [ST] with formula: C30H48O5 + Sterol Lipids [ST] with formula: C30H48O7 + Sterol Lipids [ST] with formula: C30H44O7 + Sterol Lipids [ST] with formula: C30H44O6 Sterol Lipids [ST] with formula: C37H58O10 Sterol Lipids [ST] with formula: C39H60O11 Sterol Lipids [ST] with formula: C36H54O10 - Sterol Lipids [ST] with formula: C29H46O + Sterol Lipids [ST] with formula: C29H46O + Sterol Lipids [ST] with formula: C31H54O4 Sterol Lipids [ST] with formula: C23H34O4 Sterol Lipids [ST] with formula: C23H32O5 Sterol Lipids [ST] with formula: C23H34O6 Sterol Lipids [ST] with formula: C23H34O5 Sterol Lipids [ST] with formula: C29H44O9 Sterol Lipids [ST] with formula: C42H66O18 - Sterol Lipids [ST] with formula: C41H64O15 Sterol Lipids [ST] with formula: C29H42O10 Sterol Lipids [ST] with formula: C36H56O14 Sterol Lipids [ST] with formula: C29H44O10 @@ -3457,15 +4709,21 @@ Sterol Lipids [ST] with formula: C30H42O8 Sterol Lipids [ST] with formula: C38H54O16 Sterol Lipids [ST] with formula: C27H45NO + Sterol Lipids [ST] with formula: C27H43NO2 Sterol Lipids [ST] with formula: C28H47NO Sterol Lipids [ST] with formula: C27H43NO Sterol Lipids [ST] with formula: C27H45NO2 - Sterol Lipids [ST] with formula: C27H43NO2 Sterol Lipids [ST] with formula: C50H83NO21 - Sterol Lipids [ST] with formula: C18H24O2 + Sterol Lipids [ST] with formula: C28H38O7 + Sterol Lipids [ST] with formula: C28H38O3 + Sterol Lipids [ST] with formula: C29H38O5 + Sterol Lipids [ST] with formula: C28H38O5 + Sterol Lipids [ST] with formula: C28H40O5 + Sterol Lipids [ST] with formula: C29H42O5 Sterol Lipids [ST] with formula: C18H24O3 Sterol Lipids [ST] with formula: C18H22O2 Sterol Lipids [ST] with formula: C18H18O2 + Sterol Lipids [ST] with formula: C18H24O2 Sterol Lipids [ST] with formula: C19H24O3 Sterol Lipids [ST] with formula: C18H30O2 Sterol Lipids [ST] with formula: C18H20O2 @@ -3484,8 +4742,8 @@ Sterol Lipids [ST] with formula: C19H30O Sterol Lipids [ST] with formula: C20H28O2 Sterol Lipids [ST] with formula: C19H27ClO2 - Sterol Lipids [ST] with formula: C19H30O2 Sterol Lipids [ST] with formula: C20H29FO3 + Sterol Lipids [ST] with formula: C19H30O2 Sterol Lipids [ST] with formula: C20H30O2 Sterol Lipids [ST] with formula: C19H32 Sterol Lipids [ST] with formula: C19H24O4 @@ -3495,19 +4753,20 @@ Sterol Lipids [ST] with formula: C19H26O2 Sterol Lipids [ST] with formula: C19H28O2 Sterol Lipids [ST] with formula: C19H30O3 - Sterol Lipids [ST] with formula: C19H28O3 + Sterol Lipids [ST] with formula: C19H28O3 Sterol Lipids [ST] with formula: C19H28O Sterol Lipids [ST] with formula: C19H32O Sterol Lipids [ST] with formula: C20H32O2 - Sterol Lipids [ST] with formula: C21H30O5 + Sterol Lipids [ST] with formula: C19H30O5 + Sterol Lipids [ST] with formula: C21H30O5 Sterol Lipids [ST] with formula: C23H32O6 Sterol Lipids [ST] with formula: C20H26O2 - Sterol Lipids [ST] with formula: C21H32O5 + Sterol Lipids [ST] with formula: C21H32O5 Sterol Lipids [ST] with formula: C21H28O4 - Sterol Lipids [ST] with formula: C21H30O4 + Sterol Lipids [ST] with formula: C21H30O4 Sterol Lipids [ST] with formula: C21H29FO5 Sterol Lipids [ST] with formula: C22H30O - Sterol Lipids [ST] with formula: C21H28O2 + Sterol Lipids [ST] with formula: C21H28O2 Sterol Lipids [ST] with formula: C23H30O6 Sterol Lipids [ST] with formula: C29H42O6 Sterol Lipids [ST] with formula: C23H31FO6 @@ -3517,55 +4776,58 @@ Sterol Lipids [ST] with formula: C20H28O Sterol Lipids [ST] with formula: C28H40O7 Sterol Lipids [ST] with formula: C27H40O6 - Sterol Lipids [ST] with formula: C21H34O2 Sterol Lipids [ST] with formula: C21H32O2 Sterol Lipids [ST] with formula: C21H30O2 - Sterol Lipids [ST] with formula: C21H34O5 + Sterol Lipids [ST] with formula: C21H30O3 + Sterol Lipids [ST] with formula: C21H34O5 Sterol Lipids [ST] with formula: C22H30O4 Sterol Lipids [ST] with formula: C21H34O - Sterol Lipids [ST] with formula: C21H32O3 + Sterol Lipids [ST] with formula: C21H32O3 + Sterol Lipids [ST] with formula: C21H34O2 Sterol Lipids [ST] with formula: C21H36O Sterol Lipids [ST] with formula: C22H32O3 Sterol Lipids [ST] with formula: C21H28O3 Sterol Lipids [ST] with formula: C22H30O5 Sterol Lipids [ST] with formula: C21H28O5 Sterol Lipids [ST] with formula: C21H26O5 - Sterol Lipids [ST] with formula: C21H32O4 Sterol Lipids [ST] with formula: C22H32O5 Sterol Lipids [ST] with formula: C20H28O4 Sterol Lipids [ST] with formula: C21H30O6 Sterol Lipids [ST] with formula: C21H28O6 - Sterol Lipids [ST] with formula: C21H36O2 + Sterol Lipids [ST] with formula: C21H32O4 + Sterol Lipids [ST] with formula: C21H36O2 + Sterol Lipids [ST] with formula: C20H30O + Sterol Lipids [ST] with formula: C21H34O8S + Sterol Lipids [ST] with formula: C21H34O7S + Sterol Lipids [ST] with formula: C33H52O11 + Sterol Lipids [ST] with formula: C39H62O15 + Sterol Lipids [ST] with formula: C40H64O16 + Sterol Lipids [ST] with formula: C51H82O23 Sterol Lipids [ST] with formula: C27H43NO4 Sterol Lipids [ST] with formula: C28H38F6O2 Sterol Lipids [ST] with formula: C28H41F3O2 Sterol Lipids [ST] with formula: C28H43FO3 - Sterol Lipids [ST] with formula: C28H44O2 + Sterol Lipids [ST] with formula: C28H44O2 Sterol Lipids [ST] with formula: C28H44O3S - Sterol Lipids [ST] with formula: C28H44O3 - Sterol Lipids [ST] with formula: C28H44O4 - Sterol Lipids [ST] with formula: C28H44O5 Sterol Lipids [ST] with formula: C34H52O7 - Sterol Lipids [ST] with formula: C21H30O3 Sterol Lipids [ST] with formula: C22H32O4S Sterol Lipids [ST] with formula: C22H34O2 Sterol Lipids [ST] with formula: C22H34O3 Sterol Lipids [ST] with formula: C22H34O4S - Sterol Lipids [ST] with formula: C23H36O2 + Sterol Lipids [ST] with formula: C23H36O2 Sterol Lipids [ST] with formula: C23H36O3 Sterol Lipids [ST] with formula: C26H39F3O2 Sterol Lipids [ST] with formula: C25H38O4 Sterol Lipids [ST] with formula: C25H40O3 Sterol Lipids [ST] with formula: C25H40O4S Sterol Lipids [ST] with formula: C25H42O3 - Sterol Lipids [ST] with formula: C26H38O3 + Sterol Lipids [ST] with formula: C26H38O3 Sterol Lipids [ST] with formula: C26H40O4 Sterol Lipids [ST] with formula: C26H40O5 Sterol Lipids [ST] with formula: C26H42O2 Sterol Lipids [ST] with formula: C26H42O2S Sterol Lipids [ST] with formula: C26H42O3S - Sterol Lipids [ST] with formula: C26H42O4 - Sterol Lipids [ST] with formula: C26H42O5 + Sterol Lipids [ST] with formula: C26H42O4 Sterol Lipids [ST] with formula: C26H43NO Sterol Lipids [ST] with formula: C26H43NO3 Sterol Lipids [ST] with formula: C26H43O3P @@ -3584,81 +4846,62 @@ Sterol Lipids [ST] with formula: C27H38F6O3 Sterol Lipids [ST] with formula: C27H38F6O4 Sterol Lipids [ST] with formula: C27H38O2 - Sterol Lipids [ST] with formula: C27H38O3 + Sterol Lipids [ST] with formula: C27H38O3 Sterol Lipids [ST] with formula: C27H39F3O3 - Sterol Lipids [ST] with formula: C27H40O2 - Sterol Lipids [ST] with formula: C27H40O3 - Sterol Lipids [ST] with formula: C27H40O4 - Sterol Lipids [ST] with formula: C27H40O5 + Sterol Lipids [ST] with formula: C27H40O2 Sterol Lipids [ST] with formula: C27H41FO3 Sterol Lipids [ST] with formula: C27H41F3O2 Sterol Lipids [ST] with formula: C27H41F3O3 Sterol Lipids [ST] with formula: C27H42F2O2 Sterol Lipids [ST] with formula: C27H42F2O3 Sterol Lipids [ST] with formula: C27H42F2O4 - Sterol Lipids [ST] with formula: C27H42O2 - Sterol Lipids [ST] with formula: C27H42O3 - Sterol Lipids [ST] with formula: C28H45O4 Sterol Lipids [ST] with formula: C27H43ClO3 - Sterol Lipids [ST] with formula: C27H43FO2 + Sterol Lipids [ST] with formula: C27H43FO2 Sterol Lipids [ST] with formula: C27H43FO3 - Sterol Lipids [ST] with formula: C27H44O3S - Sterol Lipids [ST] with formula: C26H42O3 + Sterol Lipids [ST] with formula: C27H44O3S + Sterol Lipids [ST] with formula: C26H42O3 Sterol Lipids [ST] with formula: C27H44O4S - Sterol Lipids [ST] with formula: C27H44O5 Sterol Lipids [ST] with formula: C27H44O5S - Sterol Lipids [ST] with formula: C27H46O - Sterol Lipids [ST] with formula: C27H46O3 - Sterol Lipids [ST] with formula: C28H38O3 - Sterol Lipids [ST] with formula: C28H40O3 + Sterol Lipids [ST] with formula: C27H46O + Sterol Lipids [ST] with formula: C27H46O3 Sterol Lipids [ST] with formula: C28H42O2 - Sterol Lipids [ST] with formula: C28H42O3 Sterol Lipids [ST] with formula: C28H42O4 Sterol Lipids [ST] with formula: C28H44F2O3 Sterol Lipids [ST] with formula: C28H45ClO3 Sterol Lipids [ST] with formula: C28H45FO3 - Sterol Lipids [ST] with formula: C28H46O3S - Sterol Lipids [ST] with formula: C28H46O3 + Sterol Lipids [ST] with formula: C28H46O3S Sterol Lipids [ST] with formula: C29H40O2 Sterol Lipids [ST] with formula: C29H42O3 Sterol Lipids [ST] with formula: C29H42O4 - Sterol Lipids [ST] with formula: C29H44O3 - Sterol Lipids [ST] with formula: C29H44O4 + Sterol Lipids [ST] with formula: C29H44O3 + Sterol Lipids [ST] with formula: C29H44O4 Sterol Lipids [ST] with formula: C29H46F2O3 - Sterol Lipids [ST] with formula: C29H46O3 - Sterol Lipids [ST] with formula: C29H46O4 - Sterol Lipids [ST] with formula: C29H46O5 - Sterol Lipids [ST] with formula: C29H48O2 - Sterol Lipids [ST] with formula: C29H48O3 - Sterol Lipids [ST] with formula: C29H48O3S - Sterol Lipids [ST] with formula: C29H48O4 - Sterol Lipids [ST] with formula: C29H48O5 - Sterol Lipids [ST] with formula: C29H50O2 + Sterol Lipids [ST] with formula: C29H46O4 + Sterol Lipids [ST] with formula: C29H46O5 + Sterol Lipids [ST] with formula: C29H48O3 + Sterol Lipids [ST] with formula: C29H48O3S + Sterol Lipids [ST] with formula: C29H48O4 + Sterol Lipids [ST] with formula: C29H48O5 Sterol Lipids [ST] with formula: C30H44O4 - Sterol Lipids [ST] with formula: C30H46O4 + Sterol Lipids [ST] with formula: C30H46O4 Sterol Lipids [ST] with formula: C30H48F2O3 - Sterol Lipids [ST] with formula: C30H48O3 Sterol Lipids [ST] with formula: C30H48O4 Sterol Lipids [ST] with formula: C30H50O3S - Sterol Lipids [ST] with formula: C30H50O4 - Sterol Lipids [ST] with formula: C30H50O5 + Sterol Lipids [ST] with formula: C30H50O5 Sterol Lipids [ST] with formula: C31H44O3 Sterol Lipids [ST] with formula: C31H46O3 - Sterol Lipids [ST] with formula: C31H48O3 - Sterol Lipids [ST] with formula: C31H48O4 + Sterol Lipids [ST] with formula: C31H48O4 Sterol Lipids [ST] with formula: C31H48O7 Sterol Lipids [ST] with formula: C31H50O3 Sterol Lipids [ST] with formula: C31H50O4 - Sterol Lipids [ST] with formula: C31H52O3 - Sterol Lipids [ST] with formula: C31H52O4 - Sterol Lipids [ST] with formula: C31H52O5 + Sterol Lipids [ST] with formula: C31H52O4 Sterol Lipids [ST] with formula: C32H42O3 Sterol Lipids [ST] with formula: C32H48O3 - Sterol Lipids [ST] with formula: C32H50O3 + Sterol Lipids [ST] with formula: C32H50O3 Sterol Lipids [ST] with formula: C32H50O4 Sterol Lipids [ST] with formula: C32H54O3 Sterol Lipids [ST] with formula: C32H54O4 - Sterol Lipids [ST] with formula: C32H54O5 + Sterol Lipids [ST] with formula: C32H54O5 Sterol Lipids [ST] with formula: C33H48O3 Sterol Lipids [ST] with formula: C33H56O3 Sterol Lipids [ST] with formula: C33H56O4 @@ -3666,19 +4909,22 @@ Sterol Lipids [ST] with formula: C35H49N3O3 Sterol Lipids [ST] with formula: C35H53NO3 Sterol Lipids [ST] with formula: C36H50O5 + Sterol Lipids [ST] with formula: C28H46O3 Sterol Lipids [ST] with formula: C42H59N5O6 Sterol Lipids [ST] with formula: C37H48O3 - Sterol Lipids [ST] with formula: C30H50O3 Sterol Lipids [ST] with formula: C26H32F6O3 Sterol Lipids [ST] with formula: C25H42O4 Sterol Lipids [ST] with formula: C26H44O4 - Sterol Lipids [ST] with formula: C29H50O5 + Sterol Lipids [ST] with formula: C29H50O5 Sterol Lipids [ST] with formula: C33H50O4 Sterol Lipids [ST] with formula: C26H44O2 Sterol Lipids [ST] with formula: C31H51FO3 + Sterol Lipids [ST] with formula: C31H48O3 + Sterol Lipids [ST] with formula: C30H48O3 Sterol Lipids [ST] with formula: C32H44O3 + Sterol Lipids [ST] with formula: C32H46O4 Sterol Lipids [ST] with formula: C34H50O4 - Sterol Lipids [ST] with formula: C27H38O4 + Sterol Lipids [ST] with formula: C27H38O4 Sterol Lipids [ST] with formula: C20H30O3 Sterol Lipids [ST] with formula: C33H52O7 Sterol Lipids [ST] with formula: C29H45BrO3 @@ -3694,16 +4940,16 @@ Sterol Lipids [ST] with formula: C32H50O7 Sterol Lipids [ST] with formula: C30H42O3S Sterol Lipids [ST] with formula: C30H46O3 - Sterol Lipids [ST] with formula: C30H44O3 - Sterol Lipids [ST] with formula: C26H40O3 - Sterol Lipids [ST] with formula: C27H44O2 + Sterol Lipids [ST] with formula: C30H44O3 + Sterol Lipids [ST] with formula: C26H40O3 + Sterol Lipids [ST] with formula: C27H44O2 Sterol Lipids [ST] with formula: C26H42F2O4 - Sterol Lipids [ST] with formula: C27H44O + Sterol Lipids [ST] with formula: C27H44O Sterol Lipids [ST] with formula: C30H52O3Si Sterol Lipids [ST] with formula: C31H50O2 Sterol Lipids [ST] with formula: C27H43F Sterol Lipids [ST] with formula: C27H43FO - Sterol Lipids [ST] with formula: C27H42O + Sterol Lipids [ST] with formula: C27H42O Sterol Lipids [ST] with formula: C27H42F2O Sterol Lipids [ST] with formula: C39H64O12 Sterol Lipids [ST] with formula: C33H52O8 @@ -3711,59 +4957,63 @@ Sterol Lipids [ST] with formula: C27H44N3O Sterol Lipids [ST] with formula: C29H45NO3 Sterol Lipids [ST] with formula: C31H44O4 - Sterol Lipids [ST] with formula: C32H46O4 Sterol Lipids [ST] with formula: C30H51NO2 + Sterol Lipids [ST] with formula: C31H52O5 Sterol Lipids [ST] with formula: C23H34O3 Sterol Lipids [ST] with formula: C24H40O2 + Sterol Lipids [ST] with formula: C24H40O4 Sterol Lipids [ST] with formula: C24H38O5 Sterol Lipids [ST] with formula: C24H38O2 - Sterol Lipids [ST] with formula: C24H42O4 + Sterol Lipids [ST] with formula: C24H42O4 Sterol Lipids [ST] with formula: C24H42O3 Sterol Lipids [ST] with formula: C24H42O2 Sterol Lipids [ST] with formula: C24H30O4 Sterol Lipids [ST] with formula: C24H36O2 Sterol Lipids [ST] with formula: C24H34O2 - Sterol Lipids [ST] with formula: C24H36O3 + Sterol Lipids [ST] with formula: C24H36O3 Sterol Lipids [ST] with formula: C24H34O3 Sterol Lipids [ST] with formula: C24H34O4 - Sterol Lipids [ST] with formula: C24H40O3 - Sterol Lipids [ST] with formula: C24H38O3 + Sterol Lipids [ST] with formula: C24H40O3 + Sterol Lipids [ST] with formula: C24H38O3 Sterol Lipids [ST] with formula: C24H38O4 - Sterol Lipids [ST] with formula: C24H36O4 + Sterol Lipids [ST] with formula: C24H36O4 Sterol Lipids [ST] with formula: C24H32O5 Sterol Lipids [ST] with formula: C24H30O5 Sterol Lipids [ST] with formula: C24H32O4 - Sterol Lipids [ST] with formula: C24H40O4 Sterol Lipids [ST] with formula: C24H36O5 Sterol Lipids [ST] with formula: C24H38O6 Sterol Lipids [ST] with formula: C24H34O5 - Sterol Lipids [ST] with formula: C24H40O5 - Sterol Lipids [ST] with formula: C24H40O6 + Sterol Lipids [ST] with formula: C24H40O5 + Sterol Lipids [ST] with formula: C24H40O6 Sterol Lipids [ST] with formula: C24H32O3 Sterol Lipids [ST] with formula: C24H40O8S Sterol Lipids [ST] with formula: C26H43NO5 Sterol Lipids [ST] with formula: C26H46O6 - Sterol Lipids [ST] with formula: C27H48O5 - Sterol Lipids [ST] with formula: C27H48O4 - Sterol Lipids [ST] with formula: C27H48O3 - Sterol Lipids [ST] with formula: C27H46O6 - Sterol Lipids [ST] with formula: C27H44O4 - Sterol Lipids [ST] with formula: C27H44O3 + Sterol Lipids [ST] with formula: C27H48O6 + Sterol Lipids [ST] with formula: C27H48O5 + Sterol Lipids [ST] with formula: C27H48O4 + Sterol Lipids [ST] with formula: C27H48O3 + Sterol Lipids [ST] with formula: C27H44O4 + Sterol Lipids [ST] with formula: C27H44O3 Sterol Lipids [ST] with formula: C27H48O2 Sterol Lipids [ST] with formula: C27H48O - Sterol Lipids [ST] with formula: C27H42O5 - Sterol Lipids [ST] with formula: C27H46O4 - Sterol Lipids [ST] with formula: C27H46O5 - Sterol Lipids [ST] with formula: C27H48O6 - Sterol Lipids [ST] with formula: C28H48O6 - Sterol Lipids [ST] with formula: C28H48O5 - Sterol Lipids [ST] with formula: C28H46O5 - Sterol Lipids [ST] with formula: C28H48O4 + Sterol Lipids [ST] with formula: C27H42O5 + Sterol Lipids [ST] with formula: C27H46O4 + Sterol Lipids [ST] with formula: C27H46O5 + Sterol Lipids [ST] with formula: C26H42O5 + Sterol Lipids [ST] with formula: C27H44O6 + Sterol Lipids [ST] with formula: C27H44O5 + Sterol Lipids [ST] with formula: C27H46O6 + Sterol Lipids [ST] with formula: C28H42O3 + Sterol Lipids [ST] with formula: C30H44O5 + Sterol Lipids [ST] with formula: C28H48O6 + Sterol Lipids [ST] with formula: C28H48O5 + Sterol Lipids [ST] with formula: C28H48O4 Sterol Lipids [ST] with formula: C22H36O5 Sterol Lipids [ST] with formula: C23H40O5 - Sterol Lipids [ST] with formula: C23H38O4 + Sterol Lipids [ST] with formula: C23H38O4 Sterol Lipids [ST] with formula: C23H40O4 - Sterol Lipids [ST] with formula: C23H40O3 + Sterol Lipids [ST] with formula: C23H40O3 Sterol Lipids [ST] with formula: C23H38O3 Sterol Lipids [ST] with formula: C23H38O2 Sterol Lipids [ST] with formula: C25H40O4 @@ -3788,7 +5038,7 @@ Sterol Lipids [ST] with formula: C24H32O11S Sterol Lipids [ST] with formula: C25H40O9 Sterol Lipids [ST] with formula: C25H34O9 - Sterol Lipids [ST] with formula: C25H38O8 + Sterol Lipids [ST] with formula: C25H38O8 Sterol Lipids [ST] with formula: C33H56O10 Sterol Lipids [ST] with formula: C33H54O7 Sterol Lipids [ST] with formula: C30H48O11 @@ -3811,27 +5061,45 @@ Sterol Lipids [ST] with formula: C21H32O6S Sterol Lipids [ST] with formula: C19H28O6S Sterol Lipids [ST] with formula: C19H30O5S + Sterol Lipids [ST] with formula: C24H40O7S Sterol Lipids [ST] with formula: C24H40O10S2 Sterol Lipids [ST] with formula: C26H45NO8S2 Sterol Lipids [ST] with formula: C26H45NO9S2 Sterol Lipids [ST] with formula: C26H45NO10S2 Sterol Lipids [ST] with formula: C19H28O5S - Sterol Lipids [ST] with formula: C24H40O7S Sterol Lipids [ST] with formula: C26H42NO7S Sterol Lipids [ST] with formula: C26H43NO6 Sterol Lipids [ST] with formula: C26H43NO4 - Sterol Lipids [ST] with formula: C26H43NO9S + Sterol Lipids [ST] with formula: C26H43NO9S Sterol Lipids [ST] with formula: C26H43NO8S - Sterol Lipids [ST] with formula: C21H34O3 + Sterol Lipids [ST] with formula: C21H34O3 Sterol Lipids [ST] with formula: C21H34O4 Sterol Lipids [ST] with formula: C26H45NO5S - Sterol Lipids [ST] with formula: C29H51NO7S + Sterol Lipids [ST] with formula: C29H51NO7S Sterol Lipids [ST] with formula: C29H51NO6S Sterol Lipids [ST] with formula: C32H53NO11S Sterol Lipids [ST] with formula: C26H45NO7S Sterol Lipids [ST] with formula: C26H45NO6S - Sterol Lipids [ST] with formula: C30H50 - Sterol Lipids [ST] with formula: C16H32O2 + Sterol Lipids [ST] with formula: C27H44O14S2 + Sterol Lipids [ST] with formula: C27H44O11S + Sterol Lipids [ST] with formula: C41H64O15 + Sterol Lipids [ST] with formula: C35H54O10 + Sterol Lipids [ST] with formula: C39H64O13 + Sterol Lipids [ST] with formula: C28H42O7 + Sterol Lipids [ST] with formula: C31H51NaO12S + Sterol Lipids [ST] with formula: C33H58O10 + Sterol Lipids [ST] with formula: C37H64O13 + Sterol Lipids [ST] with formula: C33H55NaO12S + Sterol Lipids [ST] with formula: C32H53NaO12S + Sterol Lipids [ST] with formula: C33H58O11 + Sterol Lipids [ST] with formula: C32H54O10 + Sterol Lipids [ST] with formula: C32H54O11 + Sterol Lipids [ST] with formula: C33H55NaO13S + Sterol Lipids [ST] with formula: C43H72O19 + Sterol Lipids [ST] with formula: C38H68O15 + Sterol Lipids [ST] with formula: C38H65NO9 + Sterol Lipids [ST] with formula: C33H53Na3O16S3 + Sterol Lipids [ST] with formula: C36H56NNa3O17S3 @@ -4449,4 +5717,326 @@ Trichoderma viride + + Aspergillus niger, CAS307304-29-6 + Aspergillus niger, CAS307304-30-9 + Aspergillus viride-nutans, CAS287102-34-5 + Aspergillus flavus, CAS120-72-9 + Aspergillus fumigatus, CAS111427-99-7 + Aspergillus terreus, CAS2207-58-1 + Aspergillus terreus, CAS2913-48-6 + Aspergillus terreus, CAS15254-70-3 + Aspergillus silvaticus, CAS4707-46-4 + CAS6152-57-4 + Aspergillus candidus, CAS66163-76-6 + Aspergillus flavipes, CAS57514-29-1 + Aspergillus multicolor, CAS74494-65-8 + Aspergillus multicolor, CAS65176-75-2 + Aspergillus versicolor, CAS55483-01-7 + CAS22897-08-1 + Aspergillus wentii, CAS77282-69-0 + Aspergillus versicolor, CAS30517-65-8 + Aspergillus terreus, CAS19314-92-2 + Aspergillus variecolor, CAS13410-15-6 + Aspergillus niger, CAS307001-93-0 + Aspergillus flavus, CAS1162-65-8 + Aspergillus flavus, CAS7220-81-7 + CAS52373-83-8 + Aspergillus flavus, CAS1165-39-5 + CAS20421-10-7 + Aspergillus flavus, CAS6795-23-9 + Aspergillus flavus, CAS6885-57-0 + Aspergillus flavus, CAS32215-02-4 + Aspergillus flavus, CAS52819-96-2 + Aspergillus flavus, CAS61740-00-9 + Aspergillus flavus, CAS70553-75-2 + Aspergillus flavus, CAS74328-59-9 + CAS641-38-3 + Aspergillus variecolor, CAS60451-42-5 + Aspergillus variecolor, CAS60451-43-6 + Aspergillus variecolor, CAS72693-37-9 + Aspergillus variecolor, CAS72676-00-7 + Aspergillus variecolor, CAS79874-93-4 + Aspergillus panamensis, CAS75916-46-0 + Aspergillus flavipes, CAS63631-36-7 + Aspergillus nidulans, CAS30387-51-0 + Aspergillus microcysticus, CAS72363-48-5 + Aspergillus microcysticus, CAS72363-47-4 + Aspergillus micorcysticus, CAS72401-79-7 + Aspergillus microcysticus, CAS71968-02-0 + Aspergillus terreus, CAS67309-95-9 + Aspergillus terreus, CAS55215-37-7 + Aspergillus melleus, CAS17398-00-4 + Aspergillus terreus, CAS75310-10-0 + Aspergillus variecolor, CAS55778-98-8 + Aspergillus variecolor, CAS78834-89-6 + Aspergillus terreus, CAS86925-92-0 + Aspergillus terreus, CAS577-64-0 + Aspergillus terreus, CAS60924-75-6 + Aspergillus terreus, CAS78723-14-5 + Aspergillus terreus, CAS78723-15-6 + Aspergillus terreus, CAS78723-16-7 + Aspergillus terreus, CAS78708-35-7 + Aspergillus terreus, CAS78708-36-8 + Aspergillus terreus, CAS78708-37-9 + Aspergillus terreus, CAS78723-17-8 + Aspergillus terreus, CAS78723-18-9 + Aspergillus terreus, CAS78708-38-0 + Aspergillus terreus, CAS78723-19-0 + Aspergillus chevalieri, CAS41451-81-4 + Aspergillus niger, CAS61103-89-7 + Aspergillus niger, CAS72040-27-8 + Aspergillus multicolor, CAS14016-29-6 + Aspergillus terreus, CAS87414-44-6 + Aspergillus terreus, CAS87414-45-7 + Aspergillus terreus, CAS271587-58-7 + Aspergillus candidus, CAS81474-59-1 + Aspergillus candidus, CAS81474-60-4 + Aspergillus candidus, CAS267007-58-9 + CAS50335-03-0 + Aspergillus candidus, CAS23363-64-6 + CAS42599-89-3 + Aspergillus silvaticus, CAS114090-43-6 + Aspergillus wentii, CAS616-02-4 + Aspergillus carneus, CAS518-75-2 + Aspergillus ruber, CAS68836-03-3 + CAS109171-13-3 + CAS109171-14-4 + CAS109171-15-5 + Aspergillus versicolor, CAS477-99-6 + Aspergillus flavus, CAS18172-33-3 + Aspergillus niger, CAS82893-35-4 + Aspergillus versicolor, CAS61407-06-5 + Aspergillus versicolor, CAS61407-05-4 + Aspergillus terreus, CAS18818-30-9 + Aspergillus flavus, CAS7241-98-7 + Aspergillus chevalieri, CAS77102-91-1 + Aspergillus carneus, CAS65718-85-6 + Aspergillus terreus, CAS11029-16-6 + Aspergillus terreus aureus, CAS2151-16-8 + CAS17878-54-5 + Aspergillus terreus, CAS77517-29-4 + CAS6795-16-0 + Aspergillus flavus, CAS76410-56-5 + Aspergillus flavus, CAS64947-43-9 + Aspergillus terreus, CAS87869-00-9 + Aspergillus terreus, CAS518-82-1 + Aspergillus sydowi, CAS68027-81-6 + Aspergillus silvaticus, CAS31581-32-5 + Aspergillus ruber, CAS523-73-9 + CAS113706-21-1 + Aspergillus fumigatus, CAS12626-18-5 + Aspergillus fumigatus, CAS12626-17-4 + Aspergillus terreus, CAS427-63-4 + Aspergillus fumigatus, CAS67-99-2 + Aspergillus panamensis, CAS65794-79-8 + Aspergillus panamensis, CAS58801-71-1 + Aspergillus panamensis, CAS65831-50-7 + Aspergillus sydowi, CAS65967-72-8 + Aspergillus ruber, CAS74886-31-0 + Aspergillus wentii, CAS77282-68-9 + Aspergillus wentii, CAS77282-74-7 + Aspergillus ruber, CAS74886-32-1 + Aspergillus fumigatus, CAS61897-83-4 + Aspergillus candidus, CAS501-30-4 + Aspergillus viride-nutans, CAS19504-77-9 + CAS3022-92-2 + CAS83680-20-0 + CAS138875-32-8 + CAS138797-31-6 + CAS149596-54-3 + CAS149596-55-4 + CAS149596-56-5 + Aspergillus niger, CAS59926-78-2 + CAS108351-20-8 + CAS24280-93-1 + Aspergillus nidulans, CAS21259-20-1 + Aspergillus flavipes, CAS4503-96-2 + Aspergillus terreus, CAS15254-67-8 + Aspergillus versicolor, CAS17811-38-0 + CAS24779-38-2 + Aspergillus fumigatus, CAS61897-84-5 + Aspergillus parvulus, CAS56495-98-8 + CAS24945-81-1 + Aspergillus parasiticus, CAS17878-69-2 + Aspergillus melleus, CAS480-33-1 + Aspergillus terreus, CAS87414-49-1 + Aspergillus niger, CAS69975-77-5 + Aspergillus silvaticus, CAS77392-58-6 + CAS23315-33-5 + Aspergillus parvulus, CAS73027-01-7 + Aspergillus flavus, CAS63722-91-8 + Aspergillus melleus, CAS90-65-3 + Aspergillus ustus, CAS74798-20-2 + Aspergillus viride-nutans, CAS164415-86-5 + Aspergillus silvaticus, CAS642-27-3 + Aspergillus terreus, CAS3774-64-9 + Aspergillus terreus aureus, CAS87686-82-6 + + Aspergillus carneus, CAS13277-76-4 + Aspergillus variecolor, CAS53377-54-1 + Aspergillus silvaticus, CAS73606-98-1 + Aspergillus silvaticus, CAS17811-36-8 + Aspergillus multicolor, CAS10048-13-2 + Aspergillus terreus, CAS519-57-3 + Aspergillus terreus aureus, CAS89367-84-0 + Aspergillus sydowi,CAS65967-73-9 + CAS77782-90-2 + Aspergillus candidus, CAS52452-60-5 + Aspergillus terreus, CAS121-40-4 + Aspergillus terreus, CAS582-46-7 + Aspergillus terreus, CAS18746-82-2 + Aspergillus chevalieri, CAS40434-07-9 + Aspergillus fumigatus, CAS61897-87-8 + Aspergillus fumigatus, CAS61897-89-0 + Aspergillus fumigatus, CAS61897-91-4 + Aspergillus fumigatus, CAS61949-67-5 + Aspergillus fumigatus, CAS66180-23-2 + Aspergillus fumigatus, CAS66212-51-9 + Aspergillus fumigatus, CAS69483-20-1 + Aspergillus fumigatus, ACS69575-59-3 + Aspergillus fumigatus, CAS60676-61-1 + CAS88389-71-3 + Aspergillus versicolor, CAS6807-96-1 + Aspergillus multicolor, CAS16049-49-3 + Aspergillus versicolor, CAS84062-31-7 + Aspergillus parasiticus, CAS52021-61-1 + Aspergillus parasiticus, CAS62886-00-4 + Aspergillus parasiticus, CAS22268-13-9 + Aspergillus parasiticus, CAS70979-72-5 + Aspergillus versicolor, CAS59684-36-5 + Aspergillus viride-nutans, CAS287102-33-4 + Aspergillus viride-nutans, CAS117841-42-6 + Aspergillus viride-nutans, CAS287102-35-6 + Aspergillus candidus, CAS61391-08-0 + Aspergillus candidus, CAS62002-87-3 + Aspergillus candidus, CAS62002-86-2 + Aspergillus candidus, CAS580-74-5 + Aspergillus niger, CAS307304-24-1 + Aspergillus niger, CAS307304-25-2 + Aspergillus niger, CAS307304-26-3 + Aspergillus niger, CAS307304-27-4 + Aspergillus niger, CAS307304-28-5 + Aspergillus variecolor, CAS72746-68-0 + Aspergillus variecolor, CAS72746-69-1 + Aspergillus melleus, CAS32885-83-9 + Aspergillus aculeatus, CAS35287-69-5 + Aspergillus aculeatus, CAS60687-07-2 + + + + CAS921928-12-3 + CAS56072-96-9 + CAS147317-12-2 + CAS58814-86-1 + CAS64763-82-2 + CAS26048-05-5 + CAS75947-02-3 + CAS75899-64-8 + CAS75947-01-2 + CAS75947-00-1 + CAS62995-91-9 + CAS76265-41-3 + CAS76265-42-4 + CAS154491-56-2 + + + + + + + + + + + + CAS74149-38-5 + CAS139959-75-4 + CAS139959-76-5 + CAS162808-62-0 + CAS53342-16-8 + CAS12663-46-6 + CAS59865-13-3 + CAS63775-95-1 + CAS59787-61-0 + CAS63775-96-2 + CAS63798-73-2 + CAS83574-28-1 + CAS74436-00-3 + CAS83602-39-5 + CAS83563-93-3 + CAS121604-28-2 + CAS108027-38-9 + CAS108027-39-0 + CAS108044-39-9 + CAS108027-40-3 + CAS108044-40-2 + CAS108027-41-4 + CAS108027-42-5 + CAS108066-10-0 + CAS108027-43-6 + CAS108027-44-7 + CAS108027-45-8 + CAS108027-46-9 + CAS108044-41-3 + CAS108027-47-0 + CAS108027-48-1 + CAS108027-49-2 + CAS42002-26-6 + CAS149437-28-5 + CAS27482-48-0 + CAS6686-70-0 + CAS79386-03-1 + CAS79386-02-0 + CAS148440-84-0 + CAS176391-30-3 + CAS176391-31-4 + CAS2503-26-6 + CAS79386-01-9 + + CAS27482-49-1 + CAS79385-99-2 + CAS121723-07-7 + CAS27482-50-4 + CAS79385-98-1 + CAS79385-97-0 + CAS76689-14-0 + CAS79385-96-9 + CAS121740-98-5 + CAS134316-37-3 + CAS207342-10-7 + CAS148440-85-1 + CAS30845-05-7 + CAS26912-16-3 + CAS79814-65-6, CAS54651-05-07 + CAS19893-23-3 + CAS67-99-2 + CAS83209-65-8 + CAS110538-19-7 + CAS235114-32-6 + CAS108351-20-8 + CAS133413-70-4 + CAS64925-80-0 + CAS1233083-92-5 + CAS1233083-94-7 + CAS1233083-97-0 + CAS1233083-99-2 + CAS1233084-00-8 + CAS58523-30-1 + CAS168972-17-6 + + + CAS55466-29-0 + + CAS641630-37-7 + CAS24181-12-2 + CAS2900-38-1 + CAS28540-82-1 + CAS133155-89-2 + CAS832150-38-6 + CAS74758-64-8 + CAS86402-37-1 + CAS1260586-31-9 + + \ No newline at end of file diff -Nru mmass-3.12.1/configs/config.xml mmass-4.0.0/configs/config.xml --- mmass-3.12.1/configs/config.xml 2011-07-01 07:27:19.000000000 +0000 +++ mmass-4.0.0/configs/config.xml 2011-11-28 11:32:18.000000000 +0000 @@ -11,6 +11,7 @@ + @@ -149,7 +150,7 @@ - + @@ -168,6 +169,9 @@ + + + @@ -178,17 +182,14 @@ - - + - - @@ -199,7 +200,6 @@ - @@ -240,6 +240,14 @@ + + + + + + + + diff -Nru mmass-3.12.1/configs/monomers.xml mmass-4.0.0/configs/monomers.xml --- mmass-3.12.1/configs/monomers.xml 1970-01-01 00:00:00.000000000 +0000 +++ mmass-4.0.0/configs/monomers.xml 2011-11-28 17:24:47.000000000 +0000 @@ -0,0 +1,536 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff -Nru mmass-3.12.1/configs/presets.xml mmass-4.0.0/configs/presets.xml --- mmass-3.12.1/configs/presets.xml 2011-05-10 07:53:42.000000000 +0000 +++ mmass-4.0.0/configs/presets.xml 2011-11-29 12:31:56.000000000 +0000 @@ -33,14 +33,21 @@ - + - + + + + + + + + @@ -74,9 +81,16 @@ - + + + + + + + + @@ -110,9 +124,16 @@ - + + + + + + + + @@ -121,7 +142,7 @@ - + @@ -146,9 +167,16 @@ - + + + + + + + + @@ -182,9 +210,16 @@ - + + + + + + + + @@ -218,9 +253,16 @@ - + + + + + + + + @@ -230,10 +272,12 @@ - + - - + + + + diff -Nru mmass-3.12.1/configs/references.xml mmass-4.0.0/configs/references.xml --- mmass-3.12.1/configs/references.xml 2011-02-18 14:55:16.000000000 +0000 +++ mmass-4.0.0/configs/references.xml 2011-11-28 17:10:05.000000000 +0000 @@ -1,31 +1,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - @@ -137,151 +112,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -299,23 +130,29 @@ - - - - - - - - - - + + + + + + + + + + + + - + + - + + + - + + \ No newline at end of file diff -Nru mmass-3.12.1/debian/changelog mmass-4.0.0/debian/changelog --- mmass-3.12.1/debian/changelog 2011-08-29 07:38:48.000000000 +0000 +++ mmass-4.0.0/debian/changelog 2011-12-07 21:23:08.000000000 +0000 @@ -1,3 +1,13 @@ +mmass (4.0.0-1) unstable; urgency=low + + * New upstream release. + + - Feature improvements. One of these was suggested by me: provide + automatically the charge of the ion that produced one isotopic peak + over which the space ruler is used. + + -- Filippo Rusconi Wed, 07 Dec 2011 22:04:02 +0100 + mmass (3.12.1-1) unstable; urgency=low * New upstream release. diff -Nru mmass-3.12.1/debian/rules mmass-4.0.0/debian/rules --- mmass-3.12.1/debian/rules 2011-08-29 07:38:48.000000000 +0000 +++ mmass-4.0.0/debian/rules 2011-12-07 21:23:08.000000000 +0000 @@ -6,7 +6,7 @@ export DH_VERBOSE=1 PACKAGE=mmass -VERSION="3.11.0" +VERSION="4.0.0" PYVERS=$(shell pyversions -r) INSTALLDIR=$(CURDIR)/debian/$(PACKAGE) diff -Nru mmass-3.12.1/gui/config.py mmass-4.0.0/gui/config.py --- mmass-3.12.1/gui/config.py 2011-08-28 19:04:44.000000000 +0000 +++ mmass-4.0.0/gui/config.py 2011-12-01 12:00:53.000000000 +0000 @@ -25,7 +25,7 @@ # SET VERSION # ----------- -version = '3.12.1' +version = '4.0.0' nightbuild = '' @@ -84,6 +84,7 @@ 'lastSeqDir': '', 'errorUnits': 'Da', 'printQuality': 5, + 'reverseScrolling': 0, 'macListCtrlGeneric': 1, 'peaklistColumns': ['mz', 'int', 'rel', 'sn', 'z', 'fwhm', 'resol'], 'donate': '', @@ -223,7 +224,7 @@ 'isotopeShift': 0.0, 'removeIsotopes': 1, 'removeUnknown': 1, - 'labelEnvelope': 'monoisotopic', + 'labelEnvelope': '1st', 'envelopeIntensity': 'maximum', 'setAsMonoisotopic': 0, }, @@ -243,6 +244,9 @@ } sequence={ + 'editor':{ + 'gridSize': 20, + }, 'digest':{ 'maxMods': 1, 'maxCharge': 1, @@ -253,17 +257,22 @@ 'highMass': 5000, 'retainPos': 0, 'allowMods': 0, - 'listFormat': 'b.S.a [m]', - 'matchFormat': '[r] b.S.a [m]', + 'listTemplateAmino': 'b.S.a [m]', + 'listTemplateCustom': 'b . [ S ] . a [m]', + 'matchTemplateAmino': 'h b.S.a [m]', + 'matchTemplateCustom': ' h b . [ S ] . a [m]', }, 'fragment':{ 'maxMods': 1, 'maxCharge': 1, 'massType': 1, 'fragments': ['a','b','y','-NH3','-H2O'], + 'maxLosses': 2, 'filterFragments': 1, - 'listFormat': 'b.S.a [m]', - 'matchFormat': 'f [r] [m]', + 'listTemplateAmino': 'b.S.a [m]', + 'listTemplateCustom': 'b . [ S ] . a [m]', + 'matchTemplateAmino': 'f h [m]', + 'matchTemplateCustom': 'f h [m]', }, 'search':{ 'mass': 0, @@ -275,7 +284,8 @@ 'tolerance': 0.2, 'units': 'Da', 'retainPos': 0, - 'listFormat': 'b.S.a [m]', + 'listTemplateAmino': 'b.S.a [m]', + 'listTemplateCustom': 'b . [ S ] . a [m]', }, } @@ -323,6 +333,19 @@ 'showFlipped': 0, } +envfit={ + 'loss': 'H', + 'gain': 'H{2}', + 'fit': 'spectrum', + 'scaleMin': 0, + 'scaleMax': 10, + 'charge': 1, + 'fwhm': 0.01, + 'forceFwhm': 0, + 'autoAlign': 1, + 'relThreshold': 0.05, +} + mascot={ 'common':{ 'title':'', @@ -641,6 +664,10 @@ sequenceTags = document.getElementsByTagName('sequence') if sequenceTags: + editorTags = sequenceTags[0].getElementsByTagName('editor') + if editorTags: + _getParams(editorTags[0], sequence['editor']) + digestTags = sequenceTags[0].getElementsByTagName('digest') if digestTags: _getParams(digestTags[0], sequence['digest']) @@ -684,6 +711,11 @@ if generatorTags: _getParams(generatorTags[0], generator) + # envelope fit + envfitTags = document.getElementsByTagName('envfit') + if envfitTags: + _getParams(envfitTags[0], envfit) + # mascot mascotTags = document.getElementsByTagName('mascot') if mascotTags: @@ -770,6 +802,7 @@ buff += ' \n' % (main['documentsHeight']) buff += ' \n' % (main['peaklistWidth']) buff += ' \n' % (main['peaklistHeight']) + buff += ' \n' % (bool(main['reverseScrolling'])) buff += ' \n' % (bool(main['macListCtrlGeneric'])) buff += ' \n' % (';'.join(main['peaklistColumns'])) buff += ' \n' % (main['mzDigits']) @@ -916,6 +949,9 @@ # sequence buff += ' \n' + buff += ' \n' + buff += ' \n' % (sequence['editor']['gridSize']) + buff += ' \n' buff += ' \n' buff += ' \n' % (sequence['digest']['maxMods']) buff += ' \n' % (sequence['digest']['maxCharge']) @@ -926,17 +962,14 @@ buff += ' \n' % (sequence['digest']['highMass']) buff += ' \n' % (bool(sequence['digest']['retainPos'])) buff += ' \n' % (bool(sequence['digest']['allowMods'])) - buff += ' \n' % (sequence['digest']['listFormat']) - buff += ' \n' % (sequence['digest']['matchFormat']) buff += ' \n' buff += ' \n' buff += ' \n' % (sequence['fragment']['maxMods']) buff += ' \n' % (sequence['fragment']['maxCharge']) buff += ' \n' % (sequence['fragment']['massType']) buff += ' \n' % (';'.join(sequence['fragment']['fragments'])) + buff += ' \n' % (sequence['fragment']['maxLosses']) buff += ' \n' % (bool(sequence['fragment']['filterFragments'])) - buff += ' \n' % (sequence['fragment']['listFormat']) - buff += ' \n' % (sequence['fragment']['matchFormat']) buff += ' \n' buff += ' \n' buff += ' \n' % (sequence['search']['maxMods']) @@ -947,7 +980,6 @@ buff += ' \n' % (sequence['search']['tolerance']) buff += ' \n' % (sequence['search']['units']) buff += ' \n' % (bool(sequence['search']['retainPos'])) - buff += ' \n' % (sequence['search']['listFormat']) buff += ' \n' buff += ' \n\n' @@ -993,6 +1025,15 @@ buff += ' \n' % (bool(generator['showOverlay'])) buff += ' \n\n' + # envelope fit + buff += ' \n' + buff += ' \n' % (envfit['fit']) + buff += ' \n' % (envfit['fwhm']) + buff += ' \n' % (bool(envfit['forceFwhm'])) + buff += ' \n' % (bool(envfit['autoAlign'])) + buff += ' \n' % (envfit['relThreshold']) + buff += ' \n\n' + # mascot buff += ' \n' buff += ' \n' diff -Nru mmass-3.12.1/gui/dlg_clipboard_editor.py mmass-4.0.0/gui/dlg_clipboard_editor.py --- mmass-3.12.1/gui/dlg_clipboard_editor.py 2011-07-01 13:17:50.000000000 +0000 +++ mmass-4.0.0/gui/dlg_clipboard_editor.py 2011-10-17 11:58:02.000000000 +0000 @@ -56,10 +56,13 @@ """Make GUI elements.""" # make elements - self.data_value = wx.TextCtrl(self, -1, "Reading data...", size=(300,400), style=wx.TE_MULTILINE) + self.data_value = wx.TextCtrl(self, -1, "Reading data...", size=(250,300), style=wx.TE_MULTILINE) self.data_value.Bind(wx.EVT_TEXT_ENTER, self.onOK) self.data_value.SetFont(wx.SMALL_FONT) + note_label = wx.StaticText(self, -1, "Please edit your clipboard data to consist\nof m/z and intensity columns only.\nRemove all non-digit characters.", style=wx.ALIGN_CENTER) + note_label.SetFont(wx.SMALL_FONT) + cancel_butt = wx.Button(self, wx.ID_CANCEL, "Cancel") ok_butt = wx.Button(self, wx.ID_OK, "Import") ok_butt.Bind(wx.EVT_BUTTON, self.onOK) @@ -71,6 +74,7 @@ mainSizer = wx.BoxSizer(wx.VERTICAL) mainSizer.Add(self.data_value, 1, wx.EXPAND|wx.CENTER|wx.TOP|wx.LEFT|wx.RIGHT, mwx.PANEL_SPACE_MAIN) + mainSizer.Add(note_label, 0, wx.CENTER|wx.TOP|wx.LEFT|wx.RIGHT, mwx.PANEL_SPACE_MAIN) mainSizer.Add(buttons, 0, wx.CENTER|wx.ALL, mwx.PANEL_SPACE_MAIN) return mainSizer diff -Nru mmass-3.12.1/gui/dlg_compounds_editor.py mmass-4.0.0/gui/dlg_compounds_editor.py --- mmass-3.12.1/gui/dlg_compounds_editor.py 2011-06-28 14:42:53.000000000 +0000 +++ mmass-4.0.0/gui/dlg_compounds_editor.py 2011-11-04 14:01:39.000000000 +0000 @@ -142,7 +142,7 @@ self.itemDescription_value = wx.TextCtrl(self, -1, "", size=(250, -1)) itemFormula_label = wx.StaticText(self, -1, "Formula:") - self.itemFormula_value = wx.TextCtrl(self, -1, "", size=(250, -1)) + self.itemFormula_value = mwx.formulaCtrl(self, -1, "", size=(250, -1)) self.itemFormula_value.Bind(wx.EVT_TEXT, self.onFormulaEdited) itemMoMass_label = wx.StaticText(self, -1, "Mo. mass:") @@ -212,7 +212,7 @@ # update item editor self.itemName_value.SetValue(name) self.itemDescription_value.SetValue(compound.description) - self.itemFormula_value.SetValue(compound.rawFormula) + self.itemFormula_value.SetValue(compound.expression) # ---- @@ -484,7 +484,7 @@ mass = compound.mass() self.itemsMap.append(( name, - compound.rawFormula, + compound.expression, mass[0], mass[1], compound.description, diff -Nru mmass-3.12.1/gui/dlg_enzymes_editor.py mmass-4.0.0/gui/dlg_enzymes_editor.py --- mmass-3.12.1/gui/dlg_enzymes_editor.py 2011-06-28 14:42:53.000000000 +0000 +++ mmass-4.0.0/gui/dlg_enzymes_editor.py 2011-11-04 14:02:07.000000000 +0000 @@ -105,10 +105,10 @@ self.itemExpression_value = wx.TextCtrl(self, -1, "", size=(200, -1)) itemCTerm_label = wx.StaticText(self, -1, "C-term formula:") - self.itemCTerm_value = wx.TextCtrl(self, -1, "", size=(200, -1)) + self.itemCTerm_value = mwx.formulaCtrl(self, -1, "", size=(200, -1)) itemNTerm_label = wx.StaticText(self, -1, "N-term formula:") - self.itemNTerm_value = wx.TextCtrl(self, -1, "", size=(200, -1)) + self.itemNTerm_value = mwx.formulaCtrl(self, -1, "", size=(200, -1)) self.itemModsBefore_check = wx.CheckBox(self, -1, "Allow modification before cut") @@ -307,14 +307,14 @@ # make enzyme try: expr = re.compile(expression) - enzyme = mspy.enzyme( \ - name=name, \ - expression=expression, \ - cTermFormula=cTermFormula, \ - nTermFormula=nTermFormula, \ - modsBefore=modsBefore, \ - modsAfter=modsAfter \ - ) + enzyme = mspy.enzyme( + name = name, + expression = expression, + cTermFormula = cTermFormula, + nTermFormula = nTermFormula, + modsBefore = modsBefore, + modsAfter = modsAfter + ) except: wx.Bell() return False diff -Nru mmass-3.12.1/gui/dlg_modifications_editor.py mmass-4.0.0/gui/dlg_modifications_editor.py --- mmass-3.12.1/gui/dlg_modifications_editor.py 2011-06-28 14:42:53.000000000 +0000 +++ mmass-4.0.0/gui/dlg_modifications_editor.py 2011-11-10 14:02:05.000000000 +0000 @@ -73,7 +73,7 @@ """Make list for items.""" # init list - self.itemsList = mwx.sortListCtrl(self, -1, size=(751, 250), style=mwx.LISTCTRL_STYLE_MULTI) + self.itemsList = mwx.sortListCtrl(self, -1, size=(771, 250), style=mwx.LISTCTRL_STYLE_MULTI) self.itemsList.SetFont(wx.SMALL_FONT) self.itemsList.setAltColour(mwx.LISTCTRL_ALTCOLOUR) @@ -91,7 +91,7 @@ self.itemsList.InsertColumn(7, "description", wx.LIST_FORMAT_LEFT) # set column widths - for col, width in enumerate((110,100,60,80,80,100,50,150)): + for col, width in enumerate((110,100,60,90,90,100,50,150)): self.itemsList.SetColumnWidth(col, width) # ---- @@ -116,11 +116,11 @@ self.itemTermSpecifity_combo.SetValue('None') itemGainFormula_label = wx.StaticText(self, -1, "Gain formula:") - self.itemGainFormula_value = wx.TextCtrl(self, -1, "", size=(150, -1)) + self.itemGainFormula_value = mwx.formulaCtrl(self, -1, "", size=(150, -1)) self.itemGainFormula_value.Bind(wx.EVT_TEXT, self.onFormulaEdited) itemLossFormula_label = wx.StaticText(self, -1, "Loss formula:") - self.itemLossFormula_value = wx.TextCtrl(self, -1, "", size=(150, -1)) + self.itemLossFormula_value = mwx.formulaCtrl(self, -1, "", size=(150, -1)) self.itemLossFormula_value.Bind(wx.EVT_TEXT, self.onFormulaEdited) itemMoMass_label = wx.StaticText(self, -1, "Mo. mass:") @@ -382,13 +382,13 @@ # make compound try: - modification = mspy.modification( \ - name=name, \ - gainFormula=gainFormula, \ - lossFormula=lossFormula, \ - aminoSpecifity=aminoSpecifity, \ - termSpecifity=termSpecifity, \ - description=description \ + modification = mspy.modification( + name = name, + gainFormula = gainFormula, + lossFormula = lossFormula, + aminoSpecifity = aminoSpecifity, + termSpecifity = termSpecifity, + description = description ) except: wx.Bell() diff -Nru mmass-3.12.1/gui/dlg_monomers_editor.py mmass-4.0.0/gui/dlg_monomers_editor.py --- mmass-3.12.1/gui/dlg_monomers_editor.py 1970-01-01 00:00:00.000000000 +0000 +++ mmass-4.0.0/gui/dlg_monomers_editor.py 2011-11-28 16:36:46.000000000 +0000 @@ -0,0 +1,473 @@ +# ------------------------------------------------------------------------- +# Copyright (C) 2005-2011 Martin Strohalm + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# Complete text of GNU GPL can be found in the file LICENSE.TXT in the +# main directory of the program +# ------------------------------------------------------------------------- + +# load libs +import re +import wx + +# load modules +import mwx +import config +import mspy + + +# MONOMERS EDITOR +# --------------- + +class dlgMonomersEditor(wx.Dialog): + """Edit monomers library.""" + + def __init__(self, parent): + wx.Dialog.__init__(self, parent, -1, "Monomers Library", style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER) + + self.itemsMap = [] + + # make GUI + sizer = self.makeGUI() + + # fit layout + self.Layout() + sizer.Fit(self) + self.SetSizer(sizer) + self.SetMinSize(self.GetSize()) + self.Centre() + + # get regular amino acids + self._aminoacids = [] + for abbr in mspy.monomers: + if mspy.monomers[abbr].category == '_InternalAA': + self._aminoacids.append(abbr) + + # get used monomers + self.used = parent.getUsedMonomers() + + # show data + self.updateItemsList() + # ---- + + + def makeGUI(self): + """Make GUI elements.""" + + # make GUI elements + self.makeItemsList() + editor = self.makeItemEditor() + + # pack elements + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add(self.itemsList, 1, wx.EXPAND|wx.TOP|wx.LEFT|wx.RIGHT, mwx.LISTCTRL_SPACE) + sizer.Add(editor, 0, wx.EXPAND|wx.CENTER|wx.ALL, mwx.PANEL_SPACE_MAIN) + + return sizer + # ---- + + + def makeItemsList(self): + """Make list for items.""" + + # init list + self.itemsList = mwx.sortListCtrl(self, -1, size=(871, 250), style=mwx.LISTCTRL_STYLE_MULTI) + self.itemsList.SetFont(wx.SMALL_FONT) + self.itemsList.setAltColour(mwx.LISTCTRL_ALTCOLOUR) + + # set events + self.itemsList.Bind(wx.EVT_LIST_ITEM_SELECTED, self.onItemSelected) + + # make columns + self.itemsList.InsertColumn(0, "abbr.", wx.LIST_FORMAT_LEFT) + self.itemsList.InsertColumn(1, "name", wx.LIST_FORMAT_LEFT) + self.itemsList.InsertColumn(2, "category", wx.LIST_FORMAT_LEFT) + self.itemsList.InsertColumn(3, "formula", wx.LIST_FORMAT_LEFT) + self.itemsList.InsertColumn(4, "mo. mass", wx.LIST_FORMAT_RIGHT) + self.itemsList.InsertColumn(5, "av. mass", wx.LIST_FORMAT_RIGHT) + self.itemsList.InsertColumn(6, "losses", wx.LIST_FORMAT_LEFT) + + # set column widths + for col, width in enumerate((110,180,90,110,90,90,180)): + self.itemsList.SetColumnWidth(col, width) + # ---- + + + def makeItemEditor(self): + """Make items editor.""" + + mainSizer = wx.StaticBoxSizer(wx.StaticBox(self, -1, ""), wx.VERTICAL) + + # make elements + itemSearch_label = wx.StaticText(self, -1, "Search:") + self.itemSearch_value = wx.TextCtrl(self, -1, "", size=(200, -1), style=wx.TE_PROCESS_ENTER) + self.itemSearch_value.Bind(wx.EVT_TEXT, self.onSearch) + + itemAbbr_label = wx.StaticText(self, -1, "Abbr.:") + self.itemAbbr_value = wx.TextCtrl(self, -1, "", size=(200, -1)) + + itemName_label = wx.StaticText(self, -1, "Name:") + self.itemName_value = wx.TextCtrl(self, -1, "", size=(200, -1)) + + itemCategory_label = wx.StaticText(self, -1, "Category:") + self.itemCategory_value = wx.TextCtrl(self, -1, "", size=(200, -1)) + + itemFormula_label = wx.StaticText(self, -1, "Formula:") + self.itemFormula_value = mwx.formulaCtrl(self, -1, "", size=(150, -1)) + self.itemFormula_value.Bind(wx.EVT_TEXT, self.onFormulaEdited) + + itemMoMass_label = wx.StaticText(self, -1, "Mo. mass:") + self.itemMoMass_value = wx.TextCtrl(self, -1, "", size=(150, -1)) + itemMoMass_label.Enable(False) + self.itemMoMass_value.Enable(False) + + itemAvMass_label = wx.StaticText(self, -1, "Av. mass:") + self.itemAvMass_value = wx.TextCtrl(self, -1, "", size=(150, -1)) + itemAvMass_label.Enable(False) + self.itemAvMass_value.Enable(False) + + itemLossMoMass_label = wx.StaticText(self, -1, "Mo. loss mass:") + self.itemLossMoMass_value = wx.TextCtrl(self, -1, "", size=(150, -1)) + itemLossMoMass_label.Enable(False) + self.itemLossMoMass_value.Enable(False) + + itemLosses_label = wx.StaticText(self, -1, "Losses:") + self.itemLosses_values = [] + for x in range(4): + item = mwx.formulaCtrl(self, -1, "", size=(100, -1)) + item.Bind(wx.EVT_TEXT, self.onLossFormula) + item.Bind(wx.EVT_SET_FOCUS, self.onLossFormula) + item.Bind(wx.EVT_KILL_FOCUS, self.onLossFormula) + self.itemLosses_values.append(item) + + # buttons + add_butt = wx.Button(self, -1, "Add", size=(80,-1)) + add_butt.Bind(wx.EVT_BUTTON, self.onAddItem) + + delete_butt = wx.Button(self, -1, "Delete", size=(80,-1)) + delete_butt.Bind(wx.EVT_BUTTON, self.onDeleteItem) + + # pack elements + grid = wx.GridBagSizer(mwx.GRIDBAG_VSPACE, mwx.GRIDBAG_HSPACE) + + grid.Add(itemSearch_label, (0,0), flag=wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL) + grid.Add(self.itemSearch_value, (0,1), flag=wx.ALIGN_CENTER_VERTICAL) + grid.Add(itemAbbr_label, (1,0), flag=wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL) + grid.Add(self.itemAbbr_value, (1,1), flag=wx.ALIGN_CENTER_VERTICAL) + grid.Add(itemName_label, (2,0), flag=wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL) + grid.Add(self.itemName_value, (2,1), flag=wx.ALIGN_CENTER_VERTICAL) + grid.Add(itemCategory_label, (3,0), flag=wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL) + grid.Add(self.itemCategory_value, (3,1), flag=wx.ALIGN_CENTER_VERTICAL) + + grid.Add(itemFormula_label, (0,3), flag=wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL) + grid.Add(self.itemFormula_value, (0,4), flag=wx.ALIGN_CENTER_VERTICAL) + grid.Add(itemMoMass_label, (1,3), flag=wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL) + grid.Add(self.itemMoMass_value, (1,4), flag=wx.ALIGN_CENTER_VERTICAL) + grid.Add(itemAvMass_label, (2,3), flag=wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL) + grid.Add(self.itemAvMass_value, (2,4), flag=wx.ALIGN_CENTER_VERTICAL) + grid.Add(itemLossMoMass_label, (3,3), flag=wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL) + grid.Add(self.itemLossMoMass_value, (3,4), flag=wx.ALIGN_CENTER_VERTICAL) + + grid.Add(itemLosses_label, (0,6), flag=wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL) + grid.Add(self.itemLosses_values[0], (0,7), flag=wx.ALIGN_CENTER_VERTICAL) + grid.Add(self.itemLosses_values[1], (1,7), flag=wx.ALIGN_CENTER_VERTICAL) + grid.Add(self.itemLosses_values[2], (2,7), flag=wx.ALIGN_CENTER_VERTICAL) + grid.Add(self.itemLosses_values[3], (3,7), flag=wx.ALIGN_CENTER_VERTICAL) + + grid.Add(add_butt, (0,10), flag=wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL) + grid.Add(delete_butt, (1,10), flag=wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL) + + mainSizer.Add(grid, 0, wx.ALIGN_CENTER|wx.ALL, 10) + + return mainSizer + # ---- + + + def onItemSelected(self, evt): + """Update item editor with selected item.""" + + # get selected item + abbr = evt.GetText() + monomer = mspy.monomers[abbr] + + # update item editor + self.itemAbbr_value.SetValue(abbr) + self.itemName_value.SetValue(monomer.name) + self.itemCategory_value.SetValue(monomer.category) + self.itemFormula_value.SetValue(monomer.formula) + + for x in range(4): + self.itemLosses_values[x].SetValue('') + if x < len(monomer.losses): + self.itemLosses_values[x].SetValue(monomer.losses[x]) + # ---- + + + def onAddItem(self, evt): + """Add/replace item.""" + + # get item data + itemData = self.getItemData() + if not itemData: + return + + # check regular amino acids + if itemData.abbr in self._aminoacids: + wx.Bell() + dlg = mwx.dlgMessage(self, title='Specified abbreviation is reserved!', message='Specified abbreviation is already used for regular amino acids\nwhich cannot be modified.') + dlg.ShowModal() + dlg.Destroy() + return + + # check name + if itemData.abbr in mspy.monomers: + wx.Bell() + title = 'Monomer with the same abbreviation already exists.\nDo you want to replace it?' + message = 'Old monomer definition will be lost.' + buttons = [(wx.ID_CANCEL, "Cancel", 80, False, 15), (wx.ID_OK, "Replace", 80, True, 0)] + dlg = mwx.dlgMessage(self, title, message, buttons) + if dlg.ShowModal() != wx.ID_OK: + dlg.Destroy() + return + else: + dlg.Destroy() + + # add/replace item + mspy.monomers[itemData.abbr] = itemData + + # update gui + self.updateItemsList() + self.clearEditor() + # ---- + + + def onDeleteItem(self, evt): + """Remove selected items.""" + + # delete? + title = 'Do you really want to delete selected monomers?' + message = 'Monomer definitions will be lost.' + buttons = [(wx.ID_CANCEL, "Cancel", 80, False, 15), (wx.ID_OK, "Delete", 80, True, 0)] + dlg = mwx.dlgMessage(self, title, message, buttons) + if dlg.ShowModal() != wx.ID_OK: + dlg.Destroy() + return + else: + dlg.Destroy() + + # delete items + for i in self.itemsList.getSelected(): + index = self.itemsList.GetItemData(i) + name = self.itemsMap[index][0] + if not name in self.used: + del mspy.monomers[name] + else: + wx.Bell() + dlg = mwx.dlgMessage(self, title='Monomer "'+name+'" is currently used\nand cannot be removed.', message='Remove the monomer from all of your documents first.') + dlg.ShowModal() + dlg.Destroy() + + # update gui + self.updateItemsList() + self.clearEditor() + # ---- + + + def onSearch(self, evt): + """Search monomers library.""" + + # clear editor + self.clearEditor() + + # update list + self.updateItemsList() + # ---- + + + def onFormulaEdited(self, evt): + """Update formula mass while editing.""" + evt.Skip() + wx.CallAfter(self.updateFormulaMass) + # ---- + + + def onLossFormula(self, evt): + """Update loss formula mass while editing.""" + evt.Skip() + wx.CallAfter(self.updateLossFormulaMass) + # ---- + + + def updateItemsMap(self): + """Update items map.""" + + self.itemsMap = [] + + # get search + search = self.itemSearch_value.GetValue().lower().split() + + # make map + for abbr, monomer in sorted(mspy.monomers.items()): + + # skip regular amino acids + if monomer.category == '_InternalAA': + continue + + # skip by search filter + if search and not ( + all(map(lambda x: x in monomer.abbr.lower(), search)) or + all(map(lambda x: x in monomer.name.lower(), search)) + ): + continue + + # append monomer + self.itemsMap.append(( + abbr, + monomer.name, + monomer.category, + monomer.formula, + monomer.mass[0], + monomer.mass[1], + ', '.join(monomer.losses), + )) + # ---- + + + def updateItemsList(self): + """Update items list.""" + + # clear previous data and set new + self.updateItemsMap() + self.itemsList.DeleteAllItems() + self.itemsList.setDataMap(self.itemsMap) + + # check data + if not self.itemsMap: + return + + # add new data + digits = '%0.' + `config.main['mzDigits']` + 'f' + for row, item in enumerate(self.itemsMap): + + # format data + moMass = digits % (item[4]) + avMass = digits % (item[5]) + + # add data + self.itemsList.InsertStringItem(row, item[0]) + self.itemsList.SetStringItem(row, 1, item[1]) + self.itemsList.SetStringItem(row, 2, item[2]) + self.itemsList.SetStringItem(row, 3, item[3]) + self.itemsList.SetStringItem(row, 4, str(moMass)) + self.itemsList.SetStringItem(row, 5, str(avMass)) + self.itemsList.SetStringItem(row, 6, item[6]) + self.itemsList.SetItemData(row, row) + + # sort + self.itemsList.sort() + # ---- + + + def updateFormulaMass(self): + """Update formula mass.""" + + # get formula + formula = self.itemFormula_value.GetValue() + + # show formula masses + try: + formula = mspy.compound(formula) + mass = formula.mass() + self.itemMoMass_value.SetValue(str(mass[0])) + self.itemAvMass_value.SetValue(str(mass[1])) + except: + self.itemMoMass_value.SetValue('') + self.itemAvMass_value.SetValue('') + # ---- + + + def updateLossFormulaMass(self): + """Update loss formula mass.""" + + # erase old value + self.itemLossMoMass_value.SetValue('') + + # get current item + focus = self.FindFocus() + for x in range(4): + item = self.itemLosses_values[x] + + # found focused item + if item is focus: + try: + formula = item.GetValue() + formula = mspy.compound(formula) + mass = formula.mass() + self.itemLossMoMass_value.SetValue(str(mass[0])) + except: + pass + # ---- + + + def clearEditor(self): + """Clear item editor.""" + + # update editor + self.itemAbbr_value.SetValue('') + self.itemName_value.SetValue('') + self.itemCategory_value.SetValue('') + self.itemFormula_value.SetValue('') + self.itemMoMass_value.SetValue('') + self.itemAvMass_value.SetValue('') + + for x in range(4): + self.itemLosses_values[x].SetValue('') + # ---- + + + def getItemData(self): + """Get formated item data.""" + + # get data + abbr = self.itemAbbr_value.GetValue() + name = self.itemName_value.GetValue() + category = self.itemCategory_value.GetValue() + formula = self.itemFormula_value.GetValue() + + losses = [] + for item in self.itemLosses_values: + if item.GetValue(): + losses.append(item.GetValue()) + + # check values + if not abbr or not formula or not re.match('^[A-Za-z0-9\-_]*$', abbr): + wx.Bell() + return False + + # make monomer + try: + monomer = mspy.monomer( + abbr = abbr, + name = name, + formula = formula, + losses = losses, + category = category + ) + except: + wx.Bell() + return False + + return monomer + # ---- + + + diff -Nru mmass-3.12.1/gui/dlg_notation.py mmass-4.0.0/gui/dlg_notation.py --- mmass-3.12.1/gui/dlg_notation.py 2011-04-17 20:23:29.000000000 +0000 +++ mmass-4.0.0/gui/dlg_notation.py 2011-11-10 14:20:50.000000000 +0000 @@ -67,7 +67,7 @@ self.label_value.Bind(wx.EVT_TEXT_ENTER, self.onOK) formula_label = wx.StaticText(self, -1, "Formula:", style=wx.ALIGN_RIGHT) - self.formula_value = wx.TextCtrl(self, -1, '', size=(300,-1), style=wx.TE_PROCESS_ENTER) + self.formula_value = mwx.formulaCtrl(self, -1, '', size=(300,-1), style=wx.TE_PROCESS_ENTER) self.formula_value.Bind(wx.EVT_TEXT, self.onFormula) self.formula_value.Bind(wx.EVT_TEXT_ENTER, self.onOK) @@ -241,6 +241,9 @@ def onFormula(self, evt=None): """Check formula and calculate m/z.""" + if evt != None: + evt.Skip() + # user-defined m/z if self.mzByUser_radio.GetValue(): return diff -Nru mmass-3.12.1/gui/dlg_preferences.py mmass-4.0.0/gui/dlg_preferences.py --- mmass-3.12.1/gui/dlg_preferences.py 2011-04-14 18:08:00.000000000 +0000 +++ mmass-4.0.0/gui/dlg_preferences.py 2011-11-30 16:13:36.000000000 +0000 @@ -54,9 +54,9 @@ self.notebook = wx.Notebook(self, -1) # add pages - self.notebook.AddPage(self.makeUpdatesPage(), 'Software Updates') if wx.Platform == '__WXMSW__': self.notebook.AddPage(self.makeCompassPanel(), 'CompassXport') + self.notebook.AddPage(self.makeUpdatesPage(), 'Software Updates') # pack elements mainSizer = wx.BoxSizer(wx.VERTICAL) @@ -149,7 +149,7 @@ def onUpdateNow(self, evt): """Check for available updates now.""" - self.parent.onUpdate() + self.parent.onHelpUpdate() # ---- diff -Nru mmass-3.12.1/gui/dlg_select_scans.py mmass-4.0.0/gui/dlg_select_scans.py --- mmass-3.12.1/gui/dlg_select_scans.py 2011-05-02 09:16:27.000000000 +0000 +++ mmass-4.0.0/gui/dlg_select_scans.py 2011-11-25 13:42:21.000000000 +0000 @@ -147,6 +147,7 @@ self.chromCanvas.setProperties(autoScaleY=True) self.chromCanvas.setProperties(xPosDigits=2) self.chromCanvas.setProperties(yPosDigits=2) + self.chromCanvas.setProperties(reverseScrolling=config.main['reverseScrolling']) self.chromCanvas.setProperties(reverseDrawing=True) self.chromCanvas.setMFunction('cross') diff -Nru mmass-3.12.1/gui/doc.py mmass-4.0.0/gui/doc.py --- mmass-3.12.1/gui/doc.py 2011-06-29 11:30:44.000000000 +0000 +++ mmass-4.0.0/gui/doc.py 2011-11-16 14:32:15.000000000 +0000 @@ -184,7 +184,7 @@ """Make mSD XML.""" buff = '\n' - buff += '\n\n' + buff += '\n\n' # format description buff += ' \n' @@ -223,80 +223,99 @@ buff += ' \n\n' # format peaklist - buff += ' \n' - for peak in self.spectrum.peaklist: - attributes = 'mz="%.6f" intensity="%.6f" baseline="%.6f"' % (peak.mz, peak.ai, peak.base) - if peak.sn != None: - attributes += ' sn="%.3f"' % peak.sn - if peak.charge != None: - attributes += ' charge="%d"' % peak.charge - if peak.isotope != None: - attributes += ' isotope="%d"' % peak.isotope - if peak.fwhm != None: - attributes += ' fwhm="%.6f"' % peak.fwhm - if peak.group: - attributes += ' group="%s"' % self._escape(peak.group) - buff += ' \n' % attributes - buff += ' \n\n' + if len(self.spectrum.peaklist): + buff += ' \n' + for peak in self.spectrum.peaklist: + attributes = 'mz="%.6f" intensity="%.6f" baseline="%.6f"' % (peak.mz, peak.ai, peak.base) + if peak.sn != None: + attributes += ' sn="%.3f"' % peak.sn + if peak.charge != None: + attributes += ' charge="%d"' % peak.charge + if peak.isotope != None: + attributes += ' isotope="%d"' % peak.isotope + if peak.fwhm != None: + attributes += ' fwhm="%.6f"' % peak.fwhm + if peak.group: + attributes += ' group="%s"' % self._escape(peak.group) + buff += ' \n' % attributes + buff += ' \n\n' # format annotations - buff += ' \n' - for annot in self.annotations: - attributes = 'peakMZ="%.6f" peakIntensity="%.6f" peakBaseline="%.6f"' % (annot.mz, annot.ai, annot.base) - if annot.charge != None: - attributes += ' charge="%d"' % annot.charge - if annot.radical: - attributes += ' radical="1"' - if annot.theoretical != None: - attributes += ' calcMZ="%.6f"' % annot.theoretical - if annot.formula != None: - attributes += ' formula="%s"' % annot.formula - buff += ' %s\n' % (attributes, self._escape(annot.label)) - buff += ' \n\n' + if len(self.annotations): + buff += ' \n' + for annot in self.annotations: + attributes = 'peakMZ="%.6f" peakIntensity="%.6f" peakBaseline="%.6f"' % (annot.mz, annot.ai, annot.base) + if annot.charge != None: + attributes += ' charge="%d"' % annot.charge + if annot.radical: + attributes += ' radical="1"' + if annot.theoretical != None: + attributes += ' calcMZ="%.6f"' % annot.theoretical + if annot.formula != None: + attributes += ' formula="%s"' % annot.formula + buff += ' %s\n' % (attributes, self._escape(annot.label)) + buff += ' \n\n' # format sequences - buff += ' \n\n' - for index, sequence in enumerate(self.sequences): - attributes = 'index="%d"' % index - buff += ' \n' % attributes - buff += ' %s\n' % self._escape(sequence.title) - buff += ' %s\n' % self._escape(sequence.accession) - buff += ' %s\n' % sequence.format('S') - - # format modifications - buff += ' \n' - for mod in sequence.modifications: - gainFormula = mspy.modifications[mod[0]].gainFormula - lossFormula = mspy.modifications[mod[0]].lossFormula - modtype = 'fixed' - if mod[2] == 'v': - modtype = 'variable' - buff += ' \n' % (mod[0], mod[1], modtype, gainFormula, lossFormula) - buff += ' \n' - - # format matches - buff += ' \n' - for match in sequence.matches: - attributes = 'peakMZ="%.6f" peakIntensity="%.6f" peakBaseline="%.6f"' % (match.mz, match.ai, match.base) - if match.charge != None: - attributes += ' charge="%d"' % match.charge - if match.radical: - attributes += ' radical="1"' - if match.theoretical != None: - attributes += ' calcMZ="%.6f"' % match.theoretical - if match.formula != None: - attributes += ' formula="%s"' % match.formula - if match.sequenceRange != None: - attributes += ' sequenceRange="%d-%d"' % tuple(match.sequenceRange) - if match.fragmentSerie != None: - attributes += ' fragmentSerie="%s"' % match.fragmentSerie - if match.fragmentIndex != None: - attributes += ' fragmentIndex="%s"' % match.fragmentIndex - buff += ' %s\n' % (attributes, self._escape(match.label)) - buff += ' \n' - - buff += ' \n\n' - buff += ' \n\n' + if len(self.sequences): + buff += ' \n\n' + for index, sequence in enumerate(self.sequences): + buff += ' \n' % index + buff += ' %s\n' % self._escape(sequence.title) + buff += ' %s\n' % self._escape(sequence.accession) + + attributes = 'type="%s"' % sequence.chainType + if sequence.cyclic: + attributes += ' cyclic="1"' + buff += ' %s\n' % (attributes, sequence.format('S')) + + # save monomers for custom sequences + if sequence.chainType != 'aminoacids': + buff += ' \n' + savedMonomers = [] + for abbr in sequence.chain: + if not abbr in savedMonomers: + savedMonomers.append(abbr) + formula = mspy.monomers[abbr].formula + buff += ' \n' % (abbr, formula) + buff += ' \n' + + # format modifications + if len(sequence.modifications): + buff += ' \n' + for mod in sequence.modifications: + gainFormula = mspy.modifications[mod[0]].gainFormula + lossFormula = mspy.modifications[mod[0]].lossFormula + modtype = 'fixed' + if mod[2] == 'v': + modtype = 'variable' + buff += ' \n' % (mod[0], mod[1], modtype, gainFormula, lossFormula) + buff += ' \n' + + # format matches + if len(sequence.matches): + buff += ' \n' + for match in sequence.matches: + attributes = 'peakMZ="%.6f" peakIntensity="%.6f" peakBaseline="%.6f"' % (match.mz, match.ai, match.base) + if match.charge != None: + attributes += ' charge="%d"' % match.charge + if match.radical: + attributes += ' radical="1"' + if match.theoretical != None: + attributes += ' calcMZ="%.6f"' % match.theoretical + if match.formula != None: + attributes += ' formula="%s"' % match.formula + if match.sequenceRange != None: + attributes += ' sequenceRange="%d-%d"' % tuple(match.sequenceRange) + if match.fragmentSerie != None: + attributes += ' fragmentSerie="%s"' % match.fragmentSerie + if match.fragmentIndex != None: + attributes += ' fragmentIndex="%s"' % match.fragmentIndex + buff += ' %s\n' % (attributes, self._escape(match.label)) + buff += ' \n' + + buff += ' \n\n' + buff += ' \n\n' buff += '\n' @@ -375,8 +394,9 @@ buff += ' δ (Da)\n' buff += ' δ (ppm)\n' buff += ' Rel. Int. (%)\n' - buff += ' Annotation\n' - buff += ' Formula\n' + buff += ' z\n' + buff += ' Annotation\n' + buff += ' Formula\n' buff += ' \n' buff += ' \n' buff += ' \n' % tableID @@ -384,6 +404,7 @@ mz = mzFormat % annot.mz relIntensity = '' theoretical = '' + charge = '' deltaDa = '' deltaPpm = '' formula = '' @@ -397,8 +418,12 @@ deltaPpm = ppmFormat % annot.delta('ppm') if annot.formula: formula = annot.formula + if annot.charge: + charge = annot.charge + if annot.radical: + charge = str(annot.charge) + ' •' - buff += ' %s%s%s%s%s%s%s\n' % (mz, theoretical, deltaDa, deltaPpm, relIntensity, label, formula) + buff += ' %s%s%s%s%s%s%s%s\n' % (mz, theoretical, deltaDa, deltaPpm, relIntensity, charge, label, formula) buff += ' \n' buff += ' \n' @@ -411,8 +436,13 @@ avMass = mzFormat % mass[1] chain = self._formatSequence(sequence) coverage = self._getSequenceCoverage(sequence) + matchedInt = self._getMatchedIntensity(self.spectrum.peaklist, sequence.matches) tableID = 'tableSequenceMatches%d' % x + cyclic = '' + if sequence.cyclic: + cyclic = ' (Cyclic)' + if accession: buff += '

Sequence - %s - [%s]

\n' % (sequence.title, accession) else: @@ -420,11 +450,11 @@ buff += ' \n' buff += ' \n' - buff += ' \n' + buff += ' \n' buff += ' \n' buff += ' \n' - buff += ' \n' % (accession, len(sequence), moMass, avMass, coverage) - buff += ' \n' % chain + buff += ' \n' % (accession, len(sequence), cyclic, moMass, avMass, coverage, matchedInt) + buff += ' \n' % chain buff += ' \n' buff += '
AccessionAminoacidsMo. MassAv. MassCoverage
AccessionLengthMo. MassAv. MassCoverageMatched Int.
%s%s%s%s%s
%s
%s%s%s%s%s%s%s
%s
\n' @@ -448,8 +478,9 @@ buff += ' δ (Da)\n' buff += ' δ (ppm)\n' buff += ' Rel. Int. (%)\n' - buff += ' Annotation\n' - buff += ' Formula\n' + buff += ' z\n' + buff += ' Annotation\n' + buff += ' Formula\n' buff += ' \n' buff += ' \n' buff += ' \n' % tableID @@ -457,6 +488,7 @@ mz = mzFormat % m.mz relIntensity = '' theoretical = '' + charge = '' deltaDa = '' deltaPpm = '' formula = '' @@ -469,8 +501,12 @@ deltaPpm = ppmFormat % m.delta('ppm') if m.formula: formula = m.formula + if m.charge: + charge = m.charge + if m.radical: + charge = str(m.charge) + ' •' - buff += ' %s%s%s%s%s%s%s\n' % (mz, theoretical, deltaDa, deltaPpm, relIntensity, m.label, formula) + buff += ' %s%s%s%s%s%s%s%s\n' % (mz, theoretical, deltaDa, deltaPpm, relIntensity, charge, m.label, formula) buff += ' \n' buff += ' \n' @@ -536,19 +572,22 @@ # format sequence buff = '' - for x, amino in enumerate(sequence): + for x, monomer in enumerate(sequence): attributes = '' if sequence.ismodified(x, True): attributes += 'modified ' if coverage[x]: attributes += 'matched ' + if attributes: - buff += '%s' % (attributes, amino) + buff += '%s' % (attributes, monomer) else: - buff += amino + buff += monomer - if not (x+1) % 10: + if sequence.chainType != 'aminoacids' and (x+1) != len(sequence): + buff += ' | ' + elif not (x+1) % 10: buff += ' ' return buff @@ -611,6 +650,34 @@ # ---- + def _getMatchedIntensity(self, peaklist, matches): + """Get total matched intensity.""" + + # get total intensity + totalInt = 0 + buff = {} + for peak in peaklist: + totalInt += peak.intensity + buff[round(peak.mz, 6)] = peak.intensity + + # get matched intensity + matchedInt = 0 + for item in matches: + mz = round(item.mz, 6) + if mz in buff: + matchedInt += buff[mz] + del buff[mz] + + # get percentage + matched = '0.0' + if totalInt: + matched = '%.1f' % (100*matchedInt/totalInt) + matched += ' %' + + return matched + # ---- + + def _replaceLabelIDs(self, section, label): """Replace IDs with links in annotations.""" @@ -709,6 +776,7 @@ def __init__(self, path): self.path = path + self.errors = [] self._version = None self._parsedData = None @@ -722,6 +790,8 @@ def getDocument(self): """Get document.""" + self.errors = [] + # parse data if not self._parsedData: try: @@ -752,6 +822,8 @@ def getSequences(self): """Get list of available sequences.""" + self.errors = [] + # parse data if not self._parsedData: try: @@ -955,6 +1027,7 @@ group = peakTag.getAttribute('group') except ValueError: + self.errors.append('Incorrect peak data.') continue # make peak @@ -1005,6 +1078,7 @@ annot = annotation(label=label, mz=mz, ai=ai, base=base, charge=charge, radical=radical, theoretical=theoretical, formula=formula) except ValueError: + self.errors.append('Incorrect annotation data.') continue # append annotation @@ -1044,17 +1118,34 @@ if accessionTags: accession = self._getNodeText(accessionTags[0]) - # get sequence + # get chain chain = '' + chainType = 'aminoacids' + cyclic = False seqTags = sequenceTag.getElementsByTagName('seq') if seqTags: chain = self._getNodeText(seqTags[0]) + + if seqTags[0].hasAttribute('type'): + chainType = str(seqTags[0].getAttribute('type')) + if seqTags[0].hasAttribute('cyclic'): + try: cyclic = bool(int(seqTags[0].getAttribute('cyclic'))) + except ValueError: pass + + # get monomers + monomerTags = sequenceTag.getElementsByTagName('monomer') + for monomerTag in monomerTags: + abbr = monomerTag.getAttribute('abbr') + formula = monomerTag.getAttribute('formula') + if not abbr in mspy.monomers: + self._addMonomer(abbr, formula) # make sequence try: - sequence = mspy.sequence(chain, title=title, accession=accession) + sequence = mspy.sequence(chain, title=title, accession=accession, chainType=chainType, cyclic=cyclic) sequence.matches = [] except: + self.errors.append('Unknown monomers in sequence data.') return False # get modifications @@ -1080,6 +1171,16 @@ sequence.modify(name, position, modtype) # get matches + sequence.matches[:] = self.handleSequenceMatches(sequenceTag) + + return sequence + # ---- + + + def handleSequenceMatches(self, sequenceTag): + """Get sequence amtches.""" + + # get matches matches = [] matchTags = sequenceTag.getElementsByTagName('match') for matchTag in matchTags: @@ -1121,12 +1222,13 @@ m.fragmentSerie = fragmentSerie m.fragmentIndex = fragmentIndex - sequence.matches.append(m) + matches.append(m) except ValueError: + self.errors.append('Incorrect sequence match data.') continue - return sequence + return matches # ---- @@ -1152,6 +1254,7 @@ ai = float(peakTag.getAttribute('intens')) annot = peakTag.getAttribute('annots') except ValueError: + self.errors.append('Incorrect peak data.') continue # make peak @@ -1202,6 +1305,7 @@ sequence = mspy.sequence(chain, title=title) sequence.matches = [] except: + self.errors.append('Unknown monomers in sequence data.') return False # get modifications @@ -1251,6 +1355,7 @@ return data except: + self.errors.append('Incorrect spectrum data.') return False # ---- @@ -1289,28 +1394,39 @@ # ---- - def _addModification(self, name, gainFormula, lossFormula): - """Add modification to the library.""" + def _addMonomer(self, abbr, formula, losses=[], name='', category=''): + """Add monomer to library.""" - # check name - if not name or name in mspy.modifications: + # check data + if not abbr or not formula or not re.match('^[A-Za-z0-9\-_]*$', abbr): return False - # check gain and loss - if not gainFormula and not lossFormula: - return False + # add new monomer try: - formula = mspy.compound(gainFormula) - formula = mspy.compound(lossFormula) + monomer = mspy.monomer(abbr=abbr, formula=formula, losses=losses, name=name, category=category) + mspy.monomers[abbr] = monomer + mspy.saveMonomers(os.path.join(config.confdir,'monomers.xml')) + return True except: return False + # ---- + + + def _addModification(self, name, gainFormula, lossFormula, aminoSpecifity=''): + """Add modification to library.""" - # make modification - modification = mspy.modification(name=name, gainFormula=gainFormula, lossFormula=lossFormula, aminoSpecifity='ACDEFGHIKLMNPQRSTVWY') - mspy.modifications[name] = modification - mspy.saveModifications() + # check data + if not name or not (gainFormula or lossFormula): + return False - return True + # add new modification + try: + modification = mspy.modification(name=name, gainFormula=gainFormula, lossFormula=lossFormula, aminoSpecifity=aminoSpecifity) + mspy.modifications[name] = modification + mspy.saveModifications(os.path.join(config.confdir,'modifications.xml')) + return True + except: + return False # ---- @@ -1343,8 +1459,10 @@ #tableMainInfo td{text-align: left;} #spectrum{text-align: center;} #footer{font-size: .8em; font-style: italic; text-align: center; color: #aaa; margin: 2em 0 1em 0; padding-top: 0.5em; border-top: 1px solid #000;} - .nowrap{white-space:nowrap;} + .left{text-align: left;} .right{text-align: right;} + .center{text-align: center;} + .nowrap{white-space:nowrap;} .sequence{font-size: 1.1em; font-family: monospace;} .modified{color: #f00; font-weight: bold;} .matched{text-decoration: underline;} diff -Nru mmass-3.12.1/gui/ids.py mmass-4.0.0/gui/ids.py --- mmass-3.12.1/gui/ids.py 2011-07-01 12:23:55.000000000 +0000 +++ mmass-4.0.0/gui/ids.py 2011-11-30 15:15:29.000000000 +0000 @@ -38,6 +38,7 @@ ID_documentCloseAll = wx.NewId() ID_documentSave = wx.NewId() ID_documentSaveAs = wx.NewId() +ID_documentSaveAll = wx.NewId() ID_documentExport = wx.NewId() ID_documentInfo = wx.NewId() ID_documentPrintSpectrum = wx.NewId() @@ -49,7 +50,8 @@ ID_documentColour = wx.NewId() ID_documentAnnotationEdit = wx.NewId() ID_documentAnnotationDelete = wx.NewId() -ID_documentAnnotationPattern = wx.NewId() +ID_documentAnnotationSendToMassCalculator = wx.NewId() +ID_documentAnnotationSendToEnvelopeFit = wx.NewId() ID_documentAnnotationsDelete = wx.NewId() ID_documentAnnotationsCalibrateBy = wx.NewId() ID_documentNotationsDelete = wx.NewId() @@ -73,6 +75,7 @@ HK_documentCloseAll = '\tShift+Ctrl+W' HK_documentSave = '\tCtrl+S' HK_documentSaveAs = '\tShift+Ctrl+S' +HK_documentSaveAll = '\tAlt+Ctrl+S' HK_documentExport = '\tCtrl+E' HK_documentInfo = '\tCtrl+I' HK_documentPrintSpectrum = '\tCtrl+P' @@ -153,11 +156,14 @@ ID_sequenceDigest = wx.NewId() ID_sequenceFragment = wx.NewId() ID_sequenceSearch = wx.NewId() +ID_sequenceSendToMassCalculator = wx.NewId() +ID_sequenceSendToEnvelopeFit = wx.NewId() ID_sequenceDelete = wx.NewId() ID_sequenceSort = wx.NewId() ID_sequenceMatchEdit = wx.NewId() ID_sequenceMatchDelete = wx.NewId() -ID_sequenceMatchPattern = wx.NewId() +ID_sequenceMatchSendToMassCalculator = wx.NewId() +ID_sequenceMatchSendToEnvelopeFit = wx.NewId() ID_sequenceMatchesDelete = wx.NewId() ID_sequenceMatchesCalibrateBy = wx.NewId() @@ -172,12 +178,13 @@ ID_toolsMeasure = wx.NewId() ID_toolsOffset = wx.NewId() ID_toolsPeriodicTable = wx.NewId() -ID_toolsMasscalc = wx.NewId() +ID_toolsMassCalculator = wx.NewId() ID_toolsMassFilter = wx.NewId() ID_toolsCompoundsSearch = wx.NewId() ID_toolsPeakDifferences = wx.NewId() ID_toolsComparePeaklists = wx.NewId() ID_toolsSpectrumGenerator = wx.NewId() +ID_toolsEnvelopeFit = wx.NewId() ID_toolsMascot = wx.NewId() ID_toolsProfound = wx.NewId() ID_toolsProspector = wx.NewId() @@ -192,20 +199,22 @@ HK_toolsDeleteLabel = '\tShift+Ctrl+X' HK_toolsMeasure = '\tShift+Ctrl+H' HK_toolsPeriodicTable = '\tShift+Ctrl+T' -HK_toolsMasscalc = '\tShift+Ctrl+M' +HK_toolsMassCalculator = '\tShift+Ctrl+M' HK_toolsMassFilter = '\tShift+Ctrl+F' HK_toolsCompoundsSearch = '\tShift+Ctrl+U' HK_toolsPeakDifferences = '\tShift+Ctrl+D' HK_toolsComparePeaklists = '\tShift+Ctrl+C' HK_toolsSpectrumGenerator = '\tShift+Ctrl+G' +HK_toolsEnvelopeFit = '\tShift+Ctrl+V' # library +ID_libraryCompounds = wx.NewId() ID_libraryModifications = wx.NewId() +ID_libraryMonomers = wx.NewId() ID_libraryEnzymes = wx.NewId() -ID_libraryCompounds = wx.NewId() ID_libraryReferences = wx.NewId() -ID_libraryPresets = wx.NewId() ID_libraryMascot = wx.NewId() +ID_libraryPresets = wx.NewId() # links ID_linksBiomedMSTools = wx.NewId() @@ -241,6 +250,7 @@ ID_helpCite = wx.NewId() ID_helpDonate = wx.NewId() ID_helpUpdate = wx.NewId() +ID_helpUserGuide = wx.NewId() # calibration panel ID_calibrationReferences = wx.NewId() @@ -294,6 +304,7 @@ ID_dlgReplace = wx.NewId() ID_dlgReplaceAll = wx.NewId() ID_dlgSkip = wx.NewId() +ID_dlgAppend = wx.NewId() # list pop-up menu ID_listViewAll = wx.NewId() @@ -301,3 +312,6 @@ ID_listViewUnmatched = wx.NewId() ID_listCopy = wx.NewId() ID_listCopySequence = wx.NewId() +ID_listCopyFormula = wx.NewId() +ID_listSendToMassCalculator = wx.NewId() +ID_listSendToEnvelopeFit = wx.NewId() Binary files /tmp/R798YdfeM1/mmass-3.12.1/gui/images/gtk/bgr_bottombar.png and /tmp/oRFJixBtcD/mmass-4.0.0/gui/images/gtk/bgr_bottombar.png differ Binary files /tmp/R798YdfeM1/mmass-3.12.1/gui/images/gtk/bgr_controlbar_double.png and /tmp/oRFJixBtcD/mmass-4.0.0/gui/images/gtk/bgr_controlbar_double.png differ Binary files /tmp/R798YdfeM1/mmass-3.12.1/gui/images/gtk/bgr_controlbar.png and /tmp/oRFJixBtcD/mmass-4.0.0/gui/images/gtk/bgr_controlbar.png differ Binary files /tmp/R798YdfeM1/mmass-3.12.1/gui/images/gtk/bgr_peakeditor.png and /tmp/oRFJixBtcD/mmass-4.0.0/gui/images/gtk/bgr_peakeditor.png differ Binary files /tmp/R798YdfeM1/mmass-3.12.1/gui/images/gtk/bgr_toolbar_noborder.png and /tmp/oRFJixBtcD/mmass-4.0.0/gui/images/gtk/bgr_toolbar_noborder.png differ Binary files /tmp/R798YdfeM1/mmass-3.12.1/gui/images/gtk/bgr_toolbar.png and /tmp/oRFJixBtcD/mmass-4.0.0/gui/images/gtk/bgr_toolbar.png differ Binary files /tmp/R798YdfeM1/mmass-3.12.1/gui/images/gtk/bottombars_on.png and /tmp/oRFJixBtcD/mmass-4.0.0/gui/images/gtk/bottombars_on.png differ Binary files /tmp/R798YdfeM1/mmass-3.12.1/gui/images/gtk/toolbars_off.png and /tmp/oRFJixBtcD/mmass-4.0.0/gui/images/gtk/toolbars_off.png differ Binary files /tmp/R798YdfeM1/mmass-3.12.1/gui/images/gtk/toolbars_on.png and /tmp/oRFJixBtcD/mmass-4.0.0/gui/images/gtk/toolbars_on.png differ Binary files /tmp/R798YdfeM1/mmass-3.12.1/gui/images/gtk/tools.png and /tmp/oRFJixBtcD/mmass-4.0.0/gui/images/gtk/tools.png differ diff -Nru mmass-3.12.1/gui/images_lib_gtk.py mmass-4.0.0/gui/images_lib_gtk.py --- mmass-3.12.1/gui/images_lib_gtk.py 2011-06-30 11:52:00.000000000 +0000 +++ mmass-4.0.0/gui/images_lib_gtk.py 2011-12-01 17:21:41.000000000 +0000 @@ -8657,7 +8657,16 @@ #---------------------------------------------------------------------- BgrToolbar = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAACMAAAAkCAYAAAAD3IPhAAAACXBIWXMAAAsTAAALEwEAmpwY" + "iVBORw0KGgoAAAANSUhEUgAAACMAAAAkCAYAAAAD3IPhAAAAGXRFWHRTb2Z0d2FyZQBBZG9i" + "ZSBJbWFnZVJlYWR5ccllPAAAAD1JREFUeNrs0LEJACAUQ0E/OLibRytnSHGB1x+ZJKtlAwMD" + "AwMDAwMDAwMDAwMDAwMD8zGv04LZTc9cAQYAXRFpP7LCOH4AAAAASUVORK5CYII=") +getBgrToolbarData = BgrToolbar.GetData +getBgrToolbarImage = BgrToolbar.GetImage +getBgrToolbarBitmap = BgrToolbar.GetBitmap + +#---------------------------------------------------------------------- +BgrToolbarNoBorder = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACMAAAAmCAYAAABOFCLqAAAACXBIWXMAAAsTAAALEwEAmpwY" "AAAKT2lDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVNnVFPpFj333vRCS4iAlEtvUhUI" "IFJCi4AUkSYqIQkQSoghodkVUcERRUUEG8igiAOOjoCMFVEsDIoK2AfkIaKOg6OIisr74Xuj" "a9a89+bN/rXXPues852zzwfACAyWSDNRNYAMqUIeEeCDx8TG4eQuQIEKJHAAEAizZCFz/SMB" @@ -8707,17 +8716,16 @@ "Ft1+cif9zsu72Xcn7q28T7xf9EDtQdlD3YfVP1v+3Njv3H9qwHeg89HcR/cGhYPP/pH1jw9D" "BY+Zj8uGDYbrnjg+OTniP3L96fynQ89kzyaeF/6i/suuFxYvfvjV69fO0ZjRoZfyl5O/bXyl" "/erA6xmv28bCxh6+yXgzMV70VvvtwXfcdx3vo98PT+R8IH8o/2j5sfVT0Kf7kxmTk/8EA5jz" - "/GMzLdsAAAAgY0hSTQAAeiUAAICDAAD5/wAAgOkAAHUwAADqYAAAOpgAABdvkl/FRgAAAGZJ" - "REFUeNrs1qEOgDAMhOE7wvtb4C0BU1kUyyAYXJf8p9aK9kvVfB57qkgmFQoYMGDAgAEDBszo" - "mDkiuAwYMGDAgAEDZuj/zLJurchM2W5vSbL96P/Je97XjL7vvLcWyAUAAP//AwCDkR7GsW/B" - "2QAAAABJRU5ErkJggg==") -getBgrToolbarData = BgrToolbar.GetData -getBgrToolbarImage = BgrToolbar.GetImage -getBgrToolbarBitmap = BgrToolbar.GetBitmap + "/GMzLdsAAAAgY0hSTQAAeiUAAICDAAD5/wAAgOkAAHUwAADqYAAAOpgAABdvkl/FRgAAADlJ" + "REFUeNrszgENAAAIAyC1f+dbQzdIQCepK6YOkZGRkZGRkZGRkZGRkZGRkZGRkfmVWQAAAP//" + "AwC5TQNJT4QhUAAAAABJRU5ErkJggg==") +getBgrToolbarNoBorderData = BgrToolbarNoBorder.GetData +getBgrToolbarNoBorderImage = BgrToolbarNoBorder.GetImage +getBgrToolbarNoBorderBitmap = BgrToolbarNoBorder.GetBitmap #---------------------------------------------------------------------- -BgrToolbarNoBorder = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAACMAAAAkCAYAAAAD3IPhAAAACXBIWXMAAAsTAAALEwEAmpwY" +BgrControlbar = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACMAAAAmCAYAAABOFCLqAAAACXBIWXMAAAsTAAALEwEAmpwY" "AAAKT2lDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVNnVFPpFj333vRCS4iAlEtvUhUI" "IFJCi4AUkSYqIQkQSoghodkVUcERRUUEG8igiAOOjoCMFVEsDIoK2AfkIaKOg6OIisr74Xuj" "a9a89+bN/rXXPues852zzwfACAyWSDNRNYAMqUIeEeCDx8TG4eQuQIEKJHAAEAizZCFz/SMB" @@ -8767,15 +8775,15 @@ "Ft1+cif9zsu72Xcn7q28T7xf9EDtQdlD3YfVP1v+3Njv3H9qwHeg89HcR/cGhYPP/pH1jw9D" "BY+Zj8uGDYbrnjg+OTniP3L96fynQ89kzyaeF/6i/suuFxYvfvjV69fO0ZjRoZfyl5O/bXyl" "/erA6xmv28bCxh6+yXgzMV70VvvtwXfcdx3vo98PT+R8IH8o/2j5sfVT0Kf7kxmTk/8EA5jz" - "/GMzLdsAAAAgY0hSTQAAeiUAAICDAAD5/wAAgOkAAHUwAADqYAAAOpgAABdvkl/FRgAAAEJJ" - "REFUeNrs0MERABAMAMEw+q8VnzxpI8xeBTvX9ponitSjUDAwMDAwMDAwr2NGZjoDAwMDAwMD" - "A/Mj5gIAAP//AwBajQcBeUkNKwAAAABJRU5ErkJggg==") -getBgrToolbarNoBorderData = BgrToolbarNoBorder.GetData -getBgrToolbarNoBorderImage = BgrToolbarNoBorder.GetImage -getBgrToolbarNoBorderBitmap = BgrToolbarNoBorder.GetBitmap + "/GMzLdsAAAAgY0hSTQAAeiUAAICDAAD5/wAAgOkAAHUwAADqYAAAOpgAABdvkl/FRgAAADlJ" + "REFUeNrszgENAAAIAyC1f+dbQzdIQCepK6YOkZGRkZGRkZGRkZGRkZGRkZGRkfmVWQAAAP//" + "AwC5TQNJT4QhUAAAAABJRU5ErkJggg==") +getBgrControlbarData = BgrControlbar.GetData +getBgrControlbarImage = BgrControlbar.GetImage +getBgrControlbarBitmap = BgrControlbar.GetBitmap #---------------------------------------------------------------------- -BgrControlbar = PyEmbeddedImage( +BgrControlbarDouble = PyEmbeddedImage( "iVBORw0KGgoAAAANSUhEUgAAACMAAAAmCAYAAABOFCLqAAAACXBIWXMAAAsTAAALEwEAmpwY" "AAAKT2lDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVNnVFPpFj333vRCS4iAlEtvUhUI" "IFJCi4AUkSYqIQkQSoghodkVUcERRUUEG8igiAOOjoCMFVEsDIoK2AfkIaKOg6OIisr74Xuj" @@ -8826,12 +8834,12 @@ "Ft1+cif9zsu72Xcn7q28T7xf9EDtQdlD3YfVP1v+3Njv3H9qwHeg89HcR/cGhYPP/pH1jw9D" "BY+Zj8uGDYbrnjg+OTniP3L96fynQ89kzyaeF/6i/suuFxYvfvjV69fO0ZjRoZfyl5O/bXyl" "/erA6xmv28bCxh6+yXgzMV70VvvtwXfcdx3vo98PT+R8IH8o/2j5sfVT0Kf7kxmTk/8EA5jz" - "/GMzLdsAAAAgY0hSTQAAeiUAAICDAAD5/wAAgOkAAHUwAADqYAAAOpgAABdvkl/FRgAAADxJ" - "REFUeNrszgENACAIADCkf1M0A9TA7U/w8251LJGxiIyMjIyMjIyMjIyMjIyMjIyMjMxfmQEA" - "AP//AwDmyQQP7AZRewAAAABJRU5ErkJggg==") -getBgrControlbarData = BgrControlbar.GetData -getBgrControlbarImage = BgrControlbar.GetImage -getBgrControlbarBitmap = BgrControlbar.GetBitmap + "/GMzLdsAAAAgY0hSTQAAeiUAAICDAAD5/wAAgOkAAHUwAADqYAAAOpgAABdvkl/FRgAAADlJ" + "REFUeNrszgENAAAIAyC1f+dbQzdIQCepK6YOkZGRkZGRkZGRkZGRkZGRkZGRkfmVWQAAAP//" + "AwC5TQNJT4QhUAAAAABJRU5ErkJggg==") +getBgrControlbarDoubleData = BgrControlbarDouble.GetData +getBgrControlbarDoubleImage = BgrControlbarDouble.GetImage +getBgrControlbarDoubleBitmap = BgrControlbarDouble.GetBitmap #---------------------------------------------------------------------- BgrBottombar = PyEmbeddedImage( @@ -8885,17 +8893,17 @@ "Ft1+cif9zsu72Xcn7q28T7xf9EDtQdlD3YfVP1v+3Njv3H9qwHeg89HcR/cGhYPP/pH1jw9D" "BY+Zj8uGDYbrnjg+OTniP3L96fynQ89kzyaeF/6i/suuFxYvfvjV69fO0ZjRoZfyl5O/bXyl" "/erA6xmv28bCxh6+yXgzMV70VvvtwXfcdx3vo98PT+R8IH8o/2j5sfVT0Kf7kxmTk/8EA5jz" - "/GMzLdsAAAAgY0hSTQAAeiUAAICDAAD5/wAAgOkAAHUwAADqYAAAOpgAABdvkl/FRgAAAGtJ" - "REFUeNrs0QENADAIwLBz/05/NIANSDoJa+R/dTSmawEQAQEiIEAEBIiAABEQAQEiIEAEBIiA" - "ABEQAQEiIEAEBIiAABEQAQEiIEAEBIiAABEQAQEiIEAEBIiAABEQAQEiIEtrAAAA//8DAMYH" - "BCmP7+Z9AAAAAElFTkSuQmCC") + "/GMzLdsAAAAgY0hSTQAAeiUAAICDAAD5/wAAgOkAAHUwAADqYAAAOpgAABdvkl/FRgAAAGdJ" + "REFUeNrs0QENAAAIwzDAv+djA5JOwtpJSncaC4AICBABASIgQAQEiIAICBABASIgQAQEiIAI" + "CBABASIgQAQEiIAICBABASIgQAQEiIAICBABASIgQAQEiIAICBABedoCAAD//wMA/FsDY7NR" + "5NQAAAAASUVORK5CYII=") getBgrBottombarData = BgrBottombar.GetData getBgrBottombarImage = BgrBottombar.GetImage getBgrBottombarBitmap = BgrBottombar.GetBitmap #---------------------------------------------------------------------- BgrPeakEditor = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAACMAAAFmCAYAAADnOyMyAAAACXBIWXMAAAsTAAALEwEAmpwY" + "iVBORw0KGgoAAAANSUhEUgAAACMAAADICAYAAABiWlgYAAAACXBIWXMAAAsTAAALEwEAmpwY" "AAAKT2lDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVNnVFPpFj333vRCS4iAlEtvUhUI" "IFJCi4AUkSYqIQkQSoghodkVUcERRUUEG8igiAOOjoCMFVEsDIoK2AfkIaKOg6OIisr74Xuj" "a9a89+bN/rXXPues852zzwfACAyWSDNRNYAMqUIeEeCDx8TG4eQuQIEKJHAAEAizZCFz/SMB" @@ -8945,12 +8953,11 @@ "Ft1+cif9zsu72Xcn7q28T7xf9EDtQdlD3YfVP1v+3Njv3H9qwHeg89HcR/cGhYPP/pH1jw9D" "BY+Zj8uGDYbrnjg+OTniP3L96fynQ89kzyaeF/6i/suuFxYvfvjV69fO0ZjRoZfyl5O/bXyl" "/erA6xmv28bCxh6+yXgzMV70VvvtwXfcdx3vo98PT+R8IH8o/2j5sfVT0Kf7kxmTk/8EA5jz" - "/GMzLdsAAAAgY0hSTQAAeiUAAICDAAD5/wAAgOkAAHUwAADqYAAAOpgAABdvkl/FRgAAAOZJ" - "REFUeNrszkEBACAIBDCwf1Mlg9S4x5ZgPe/+CnEqiIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyM" - "jIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyM" - "jIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyM" - "jIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyM" - "jIyMjIyMjIxMWmYHAHGwBo+RFG7aAAAAAElFTkSuQmCC") + "/GMzLdsAAAAgY0hSTQAAeiUAAICDAAD5/wAAgOkAAHUwAADqYAAAOpgAABdvkl/FRgAAAJFJ" + "REFUeNrszjEBAAAIAyC1f+fZwcsDEtBJ6oupR2RkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRk" + "ZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRk" + "ZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZG4WAAD//wMAvUcEjQNPYZUAAAAASUVORK5C" + "YII=") getBgrPeakEditorData = BgrPeakEditor.GetData getBgrPeakEditorImage = BgrPeakEditor.GetImage getBgrPeakEditorBitmap = BgrPeakEditor.GetBitmap @@ -8987,7 +8994,7 @@ #---------------------------------------------------------------------- Tools = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAAY0AAAAXCAYAAAD3LRNAAAAAGXRFWHRTb2Z0d2FyZQBBZG9i" + "iVBORw0KGgoAAAANSUhEUgAAAbgAAAAXCAYAAAB591o8AAAAGXRFWHRTb2Z0d2FyZQBBZG9i" "ZSBJbWFnZVJlYWR5ccllPAAAA2ZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tl" "dCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1l" "dGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUu" @@ -8998,57 +9005,68 @@ "YmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9u" "cy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRp" "ZDowMTgwMTE3NDA3MjA2ODExOTEwOUIwQzIyRTBFN0VGRiIgeG1wTU06RG9jdW1lbnRJRD0i" - "eG1wLmRpZDozODYzQ0U4QjlCMzMxMUUwOEE4OUU2MTY0MUIzOTE0NCIgeG1wTU06SW5zdGFu" - "Y2VJRD0ieG1wLmlpZDozODYzQ0U4QTlCMzMxMUUwOEE4OUU2MTY0MUIzOTE0NCIgeG1wOkNy" + "eG1wLmRpZDpGRkZDQzY2MEYwMkYxMUUwOEIzRURDRTlEMEI2RjYwNiIgeG1wTU06SW5zdGFu" + "Y2VJRD0ieG1wLmlpZDpGRkZDQzY1RkYwMkYxMUUwOEIzRURDRTlEMEI2RjYwNiIgeG1wOkNy" "ZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IE1hY2ludG9zaCI+IDx4bXBNTTpEZXJp" - "dmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjAzODAxMTc0MDcyMDY4MTE4NzQ4" - "RDIyRkJBOTlFQzkxIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjAxODAxMTc0MDcyMDY4" + "dmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkZEN0YxMTc0MDcyMDY4MTE5MTA5" + "QjE0MEFDMDgzOEM1IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjAxODAxMTc0MDcyMDY4" "MTE5MTA5QjBDMjJFMEU3RUZGIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwv" - "eDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+VUBApgAACS5JREFUeNrsXLGO4zgM1QID" - "pxlNozROlTRJk6km//8F6bZyNVflmk1zmcZu5hJAwr3lkhIpJ4tZnAgIji1boSiK4iNlO9eo" - "UaNGjRo1atSoUaNGjRo1atSoUaNGjRo1avT16ZtwvbsWH4+Jpmu5xGMNcW2WyPKfmvbn9uFe" - "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") + "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" + "AABJRU5ErkJggg==") getToolsData = Tools.GetData getToolsImage = Tools.GetImage getToolsBitmap = Tools.GetBitmap @@ -9066,61 +9084,61 @@ "YmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9u" "cy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRp" "ZDowOTgwMTE3NDA3MjA2ODExOTEwOURDQkFDQjFGMDFEOCIgeG1wTU06RG9jdW1lbnRJRD0i" - "eG1wLmRpZDpENUE5MDQ5QTU0N0ExMUUwOTg4M0ZFNjBENDk0NUM4QiIgeG1wTU06SW5zdGFu" - "Y2VJRD0ieG1wLmlpZDpENUE5MDQ5OTU0N0ExMUUwOTg4M0ZFNjBENDk0NUM4QiIgeG1wOkNy" + "eG1wLmRpZDpGMDI4Qjk3OUQxNTgxMUUwQUJCMEFBNzg4OTFEQjQ4MiIgeG1wTU06SW5zdGFu" + "Y2VJRD0ieG1wLmlpZDpGMDI4Qjk3OEQxNTgxMUUwQUJCMEFBNzg4OTFEQjQ4MiIgeG1wOkNy" "ZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IE1hY2ludG9zaCI+IDx4bXBNTTpEZXJp" - "dmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjAxODAxMTc0MDcyMDY4MTE5N0E1" + "dmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjAyODAxMTc0MDcyMDY4MTE5N0E1" "OTQ1MTJEN0FBRjE3IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjA5ODAxMTc0MDcyMDY4" "MTE5MTA5RENCQUNCMUYwMUQ4Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwv" - "eDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+laOwSgAAChlJREFUeNrsnb9y2zgQh5Eb" - "D91EbuQmqs6Vq3R5iDzyPYQ7Va7cKU3cWG7ExkdegPN6DZAACIgS9X0zGv2jvQQE/LAAwd0v" - "b29vBgBgTv6iCgAAIQIAhIgqAACECAAQIqoAAObmKuagLz8/vG26x8q+3nePVn759g+VCgD1" - "PaJehH7bx4oqBIA5hKgJvAYAqDc1E9Ox/nktPnevW980bQrddFDa9PG/TaaDAJchRG46ptmK" - "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") + "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" + "AAAAAElFTkSuQmCC") getBottombarsOnData = BottombarsOn.GetData getBottombarsOnImage = BottombarsOn.GetImage getBottombarsOnBitmap = BottombarsOn.GetBitmap @@ -9200,7 +9218,7 @@ #---------------------------------------------------------------------- ToolbarsOn = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAAMsAAADcCAYAAADeKFUQAAAAGXRFWHRTb2Z0d2FyZQBBZG9i" + "iVBORw0KGgoAAAANSUhEUgAAAMsAAADyCAYAAADjjjFWAAAAGXRFWHRTb2Z0d2FyZQBBZG9i" "ZSBJbWFnZVJlYWR5ccllPAAAA2ZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tl" "dCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1l" "dGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUu" @@ -9211,136 +9229,143 @@ "YmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9u" "cy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRp" "ZDowMTgwMTE3NDA3MjA2ODExOTEwOURDQkFDQjFGMDFEOCIgeG1wTU06RG9jdW1lbnRJRD0i" - "eG1wLmRpZDo5MkNEMjgxOTlBODExMUUwODY3Q0U2MzRDNzYzRjNGMiIgeG1wTU06SW5zdGFu" - "Y2VJRD0ieG1wLmlpZDo5MkNEMjgxODlBODExMUUwODY3Q0U2MzRDNzYzRjNGMiIgeG1wOkNy" + "eG1wLmRpZDo3MDRCRDA4RkJBQTUxMUUwQjQ4NkRCM0I1Nzk0NTg3MiIgeG1wTU06SW5zdGFu" + "Y2VJRD0ieG1wLmlpZDo3MDRCRDA4RUJBQTUxMUUwQjQ4NkRCM0I1Nzk0NTg3MiIgeG1wOkNy" "ZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IE1hY2ludG9zaCI+IDx4bXBNTTpEZXJp" - "dmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjA1ODAxMTc0MDcyMDY4MTE5OTRD" - "Qzc2RTMwRTk0MDg1IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjAxODAxMTc0MDcyMDY4" + "dmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjAxODAxMTc0MDcyMDY4MTE5NUZF" + "REI1MDhCOEE3MTU2IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjAxODAxMTc0MDcyMDY4" "MTE5MTA5RENCQUNCMUYwMUQ4Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwv" - "eDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+C64xIwAAGGNJREFUeNrsXU2IJFdyjpHG" - "VSu5q2VRg2DqYKYFdsFCgxHNHnwSuxh8NNLio42xQPiwAiH2IgvGrIQvPgj2sqdl8Yq9rbBZ" - "jL3Iwvjig0Td+rCUfajBLD1gT9ny1EizlbMa+b2ZiKno1+9lvr/66e7vgyArs7LyZWbF9yLi" - "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") + "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") getToolbarsOnData = ToolbarsOn.GetData getToolbarsOnImage = ToolbarsOn.GetImage getToolbarsOnBitmap = ToolbarsOn.GetBitmap #---------------------------------------------------------------------- ToolbarsOff = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAAMsAAADcCAYAAADeKFUQAAAAGXRFWHRTb2Z0d2FyZQBBZG9i" + "iVBORw0KGgoAAAANSUhEUgAAAMsAAADyCAYAAADjjjFWAAAAGXRFWHRTb2Z0d2FyZQBBZG9i" "ZSBJbWFnZVJlYWR5ccllPAAAA2ZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tl" "dCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1l" "dGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUu" @@ -9351,131 +9376,138 @@ "YmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9u" "cy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRp" "ZDowMTgwMTE3NDA3MjA2ODExOTEwOURDQkFDQjFGMDFEOCIgeG1wTU06RG9jdW1lbnRJRD0i" - "eG1wLmRpZDpDMUQyNzdDQTlBODExMUUwODY3Q0U2MzRDNzYzRjNGMiIgeG1wTU06SW5zdGFu" - "Y2VJRD0ieG1wLmlpZDpDMUQyNzdDOTlBODExMUUwODY3Q0U2MzRDNzYzRjNGMiIgeG1wOkNy" + "eG1wLmRpZDo4RTM5NjVDRUJBQTUxMUUwQjQ4NkRCM0I1Nzk0NTg3MiIgeG1wTU06SW5zdGFu" + "Y2VJRD0ieG1wLmlpZDo4RTM5NjVDREJBQTUxMUUwQjQ4NkRCM0I1Nzk0NTg3MiIgeG1wOkNy" "ZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IE1hY2ludG9zaCI+IDx4bXBNTTpEZXJp" - "dmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjA1ODAxMTc0MDcyMDY4MTE5OTRD" - "Qzc2RTMwRTk0MDg1IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjAxODAxMTc0MDcyMDY4" + "dmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjAxODAxMTc0MDcyMDY4MTE5NUZF" + "REI1MDhCOEE3MTU2IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjAxODAxMTc0MDcyMDY4" "MTE5MTA5RENCQUNCMUYwMUQ4Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwv" - "eDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+Q9PQiAAAGNhJREFUeNrsXU2IbMd1rpGe" - "u5/k6XkRdxCZhsAbkUwTo4GgN3iRlXDIPkghWdkJwSCysCEIbxSBgiWyyULgjddJ8C6CYEIc" - "FG2zkOjdLMJkM4KYHgjTifP6Sbjv83ty1bxzpk/XVN1bf7enZ/r74HB/+vat+3O+OufUrTq1" - "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") + "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") getToolbarsOffData = ToolbarsOff.GetData getToolbarsOffImage = ToolbarsOff.GetImage getToolbarsOffBitmap = ToolbarsOff.GetBitmap diff -Nru mmass-3.12.1/gui/images_lib_mac.py mmass-4.0.0/gui/images_lib_mac.py --- mmass-3.12.1/gui/images_lib_mac.py 2011-06-30 11:51:59.000000000 +0000 +++ mmass-4.0.0/gui/images_lib_mac.py 2011-12-01 17:21:41.000000000 +0000 @@ -8697,6 +8697,65 @@ getBgrControlbarBitmap = BgrControlbar.GetBitmap #---------------------------------------------------------------------- +BgrControlbarDouble = PyEmbeddedImage( + "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") +getBgrControlbarDoubleData = BgrControlbarDouble.GetData +getBgrControlbarDoubleImage = BgrControlbarDouble.GetImage +getBgrControlbarDoubleBitmap = BgrControlbarDouble.GetBitmap + +#---------------------------------------------------------------------- BgrBottombar = PyEmbeddedImage( "iVBORw0KGgoAAAANSUhEUgAAAGQAAAAzCAIAAADuCzpMAAAAGXRFWHRTb2Z0d2FyZQBBZG9i" "ZSBJbWFnZVJlYWR5ccllPAAAAHhJREFUeNrs1MENABAQRUFEf6IQ0f9lVwuuZH4Jk7db117F" @@ -8799,7 +8858,7 @@ #---------------------------------------------------------------------- Tools = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAAcIAAAAWCAYAAABTwJzIAAAAGXRFWHRTb2Z0d2FyZQBBZG9i" + "iVBORw0KGgoAAAANSUhEUgAAAf4AAAAXCAYAAADqUy3bAAAAGXRFWHRTb2Z0d2FyZQBBZG9i" "ZSBJbWFnZVJlYWR5ccllPAAAA2ZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tl" "dCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1l" "dGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUu" @@ -8810,88 +8869,126 @@ "YmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9u" "cy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRp" "ZDowMTgwMTE3NDA3MjA2ODExOTEwOUIwQzIyRTBFN0VGRiIgeG1wTU06RG9jdW1lbnRJRD0i" - "eG1wLmRpZDoxQTFCQUQ1QzVDNzcxMUUwQTg5NUJGNEIwOTA4NkJDNiIgeG1wTU06SW5zdGFu" - "Y2VJRD0ieG1wLmlpZDoxQTFCQUQ1QjVDNzcxMUUwQTg5NUJGNEIwOTA4NkJDNiIgeG1wOkNy" + "eG1wLmRpZDoxMDRCMjJCOUYwRDkxMUUwQTQ4Q0VBN0VFRjlCQTk5MSIgeG1wTU06SW5zdGFu" + "Y2VJRD0ieG1wLmlpZDoxMDRCMjJCOEYwRDkxMUUwQTQ4Q0VBN0VFRjlCQTk5MSIgeG1wOkNy" "ZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IE1hY2ludG9zaCI+IDx4bXBNTTpEZXJp" - "dmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkY3N0YxMTc0MDcyMDY4MTE5NUZF" - "QTY3MTUyOUYyODY3IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjAxODAxMTc0MDcyMDY4" + "dmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkVFQ0Q3NTgyMjQyMDY4MTE5MTA5" + "RUQ3QUYzNkI1QjJGIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjAxODAxMTc0MDcyMDY4" "MTE5MTA5QjBDMjJFMEU3RUZGIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwv" - "eDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+JzkUqwAAD59JREFUeNrsnemrHUUaxjtO" - "3Le4G9BA4geFiBuIoqIxLqiYhWhiRBEJouCA84/MlxFGUERE3B1DoqLi1UmURJSIUVFRP+iX" - "iEvc4hY3zNxfwXN4z3uruquq742Z0AWH6u6qrqeed63qPvfcWbt27WqWLVv296Zprp38LGpm" - "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" - "RU5ErkJggg==") + "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") getToolsData = Tools.GetData getToolsImage = Tools.GetImage getToolsBitmap = Tools.GetBitmap @@ -8909,101 +9006,132 @@ "YmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9u" "cy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRp" "ZDowOTgwMTE3NDA3MjA2ODExOTEwOURDQkFDQjFGMDFEOCIgeG1wTU06RG9jdW1lbnRJRD0i" - "eG1wLmRpZDpBQTIzQzQ0RjU0N0ExMUUwOTg4M0ZFNjBENDk0NUM4QiIgeG1wTU06SW5zdGFu" - "Y2VJRD0ieG1wLmlpZDpBQTIzQzQ0RTU0N0ExMUUwOTg4M0ZFNjBENDk0NUM4QiIgeG1wOkNy" + "eG1wLmRpZDowNDAxREZEMkY5NzAxMUUwOTI5OUIxMThFMjdGMTA4QiIgeG1wTU06SW5zdGFu" + "Y2VJRD0ieG1wLmlpZDowNDAxREZEMUY5NzAxMUUwOTI5OUIxMThFMjdGMTA4QiIgeG1wOkNy" "ZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IE1hY2ludG9zaCI+IDx4bXBNTTpEZXJp" - "dmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjAxODAxMTc0MDcyMDY4MTE5N0E1" - "OTQ1MTJEN0FBRjE3IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjA5ODAxMTc0MDcyMDY4" + "dmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjAxODAxMTc0MDcyMDY4MTE5MkIw" + "OEEzNjZBNEQxM0ZBIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjA5ODAxMTc0MDcyMDY4" "MTE5MTA5RENCQUNCMUYwMUQ4Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwv" - "eDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+z+fP6AAAEmlJREFUeNrsnUmv5UQShe8r" - "HkMxSPULkGAFf4B1r2qLegUCinkoxgJW9KLXsEJqUEExz4iWetFv+1a9Zd8SSC3Vgl+AmOfq" - "91mcp6iozHSmr13v2jeOZPle29fHkXaGI9K+cXYuXLiwuv322/+5Wq1OHkwnVsvC1wfT/t7e" - "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" - "m3aeeCgp8AAAAABJRU5ErkJggg==") + "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") getBottombarsOnData = BottombarsOn.GetData getBottombarsOnImage = BottombarsOn.GetImage getBottombarsOnBitmap = BottombarsOn.GetBitmap @@ -9021,110 +9149,135 @@ "YmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9u" "cy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRp" "ZDowOTgwMTE3NDA3MjA2ODExOTEwOURDQkFDQjFGMDFEOCIgeG1wTU06RG9jdW1lbnRJRD0i" - "eG1wLmRpZDpBQTIzQzQ1MzU0N0ExMUUwOTg4M0ZFNjBENDk0NUM4QiIgeG1wTU06SW5zdGFu" - "Y2VJRD0ieG1wLmlpZDpBQTIzQzQ1MjU0N0ExMUUwOTg4M0ZFNjBENDk0NUM4QiIgeG1wOkNy" + "eG1wLmRpZDo0RkZCQTdDMUYwRDgxMUUwQTQ4Q0VBN0VFRjlCQTk5MSIgeG1wTU06SW5zdGFu" + "Y2VJRD0ieG1wLmlpZDo0RkZCQTdDMEYwRDgxMUUwQTQ4Q0VBN0VFRjlCQTk5MSIgeG1wOkNy" "ZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IE1hY2ludG9zaCI+IDx4bXBNTTpEZXJp" - "dmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjAxODAxMTc0MDcyMDY4MTE5N0E1" - "OTQ1MTJEN0FBRjE3IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjA5ODAxMTc0MDcyMDY4" + "dmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkU5Q0Q3NTgyMjQyMDY4MTE5MTA5" + "RUQ3QUYzNkI1QjJGIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjA5ODAxMTc0MDcyMDY4" "MTE5MTA5RENCQUNCMUYwMUQ4Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwv" - "eDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+IC44+AAAEtBJREFUeNrsXV2IHUUW7gnx" - "X+MYiObBFyOLDypEMSb4g9HEwYgxEtEYEBER9CXs6+7DIj75vMyu+CAShvgTXWVGReXq1Qgm" - "GJREYRSiJL4koA7qxFEjUcner8nXnKmp6qrq7nvndvf54NL//dWprjp9qm/3+UZOnTqVbNmy" - "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" - "sKMAAAAASUVORK5CYII=") + "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" + "YII=") getBottombarsOffData = BottombarsOff.GetData getBottombarsOffImage = BottombarsOff.GetImage getBottombarsOffBitmap = BottombarsOff.GetBitmap #---------------------------------------------------------------------- ToolbarsOn = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAAMsAAADcCAYAAADeKFUQAAAAGXRFWHRTb2Z0d2FyZQBBZG9i" + "iVBORw0KGgoAAAANSUhEUgAAAMsAAADyCAYAAADjjjFWAAAAGXRFWHRTb2Z0d2FyZQBBZG9i" "ZSBJbWFnZVJlYWR5ccllPAAAA2ZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tl" "dCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1l" "dGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUu" @@ -9135,215 +9288,308 @@ "YmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9u" "cy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRp" "ZDowMTgwMTE3NDA3MjA2ODExOTEwOURDQkFDQjFGMDFEOCIgeG1wTU06RG9jdW1lbnRJRD0i" - "eG1wLmRpZDo1QkEzNDNFMDlBODExMUUwODY3Q0U2MzRDNzYzRjNGMiIgeG1wTU06SW5zdGFu" - "Y2VJRD0ieG1wLmlpZDo1QkEzNDNERjlBODExMUUwODY3Q0U2MzRDNzYzRjNGMiIgeG1wOkNy" + "eG1wLmRpZDozRTdEODk3REY5NzExMUUwOTI5OUIxMThFMjdGMTA4QiIgeG1wTU06SW5zdGFu" + "Y2VJRD0ieG1wLmlpZDozRTdEODk3Q0Y5NzExMUUwOTI5OUIxMThFMjdGMTA4QiIgeG1wOkNy" "ZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IE1hY2ludG9zaCI+IDx4bXBNTTpEZXJp" - "dmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjA0ODAxMTc0MDcyMDY4MTE5OTRD" - "Qzc2RTMwRTk0MDg1IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjAxODAxMTc0MDcyMDY4" + "dmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkVEQ0Q3NTgyMjQyMDY4MTE5MTA5" + "RUQ3QUYzNkI1QjJGIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjAxODAxMTc0MDcyMDY4" "MTE5MTA5RENCQUNCMUYwMUQ4Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwv" - "eDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+j4mR0gAAKQpJREFUeNrsnd3vFVfVxwfE" - "19pqmjQhmCjEBmpjTAAtvwsDxCZi8AKf5FGb1kqptrUvQOkf0kopKr7X2hax+jxcYNTe/IyS" - "hkK50KSVihj1Qm6MIWrrOw+fefyeLBZ7z+w5Zw6tM2slc+bMnDl7zctas9fes9dnlpw/f77a" - "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") + "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") getToolbarsOnData = ToolbarsOn.GetData getToolbarsOnImage = ToolbarsOn.GetImage getToolbarsOnBitmap = ToolbarsOn.GetBitmap #---------------------------------------------------------------------- ToolbarsOff = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAAMsAAADcCAYAAADeKFUQAAAAGXRFWHRTb2Z0d2FyZQBBZG9i" + "iVBORw0KGgoAAAANSUhEUgAAAMsAAADyCAYAAADjjjFWAAAAGXRFWHRTb2Z0d2FyZQBBZG9i" "ZSBJbWFnZVJlYWR5ccllPAAAA2ZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tl" "dCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1l" "dGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUu" @@ -9354,207 +9600,291 @@ "YmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9u" "cy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRp" "ZDowMTgwMTE3NDA3MjA2ODExOTEwOURDQkFDQjFGMDFEOCIgeG1wTU06RG9jdW1lbnRJRD0i" - "eG1wLmRpZDo1QkEzNDNEQzlBODExMUUwODY3Q0U2MzRDNzYzRjNGMiIgeG1wTU06SW5zdGFu" - "Y2VJRD0ieG1wLmlpZDo1QkEzNDNEQjlBODExMUUwODY3Q0U2MzRDNzYzRjNGMiIgeG1wOkNy" + "eG1wLmRpZDo4RDYwQkY4RUYwRDgxMUUwQTQ4Q0VBN0VFRjlCQTk5MSIgeG1wTU06SW5zdGFu" + "Y2VJRD0ieG1wLmlpZDo4RDYwQkY4REYwRDgxMUUwQTQ4Q0VBN0VFRjlCQTk5MSIgeG1wOkNy" "ZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IE1hY2ludG9zaCI+IDx4bXBNTTpEZXJp" - "dmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjA0ODAxMTc0MDcyMDY4MTE5OTRD" - "Qzc2RTMwRTk0MDg1IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjAxODAxMTc0MDcyMDY4" + "dmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkVCQ0Q3NTgyMjQyMDY4MTE5MTA5" + "RUQ3QUYzNkI1QjJGIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjAxODAxMTc0MDcyMDY4" "MTE5MTA5RENCQUNCMUYwMUQ4Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwv" - "eDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+vqGfkgAAKMdJREFUeNrsnW3MHVXV94cX" - "FVQUBBGiMaGa2hSslLbWApa2QkOJUB68aUshrTFUW27tHdP4RWOaiIWkJqY3vnwwaKQVbEV8" - "qJKCiBSrrdQSarE0SGL5oqm2xTd8AV/qw28//Z+sa3fPzJ5z5lxtz1krua6Z2bNnr9kza+21" - "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" - "AInzC9/yqBJgAAAAAElFTkSuQmCC") + "eDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+R6cApwAAOotJREFUeNrsnWnMXVX1xi+I" + "ihaJSKpYMX6RNuGLQwghBANlRrCIQNEiZZ4nGYIQteLIoCCjMlXGMA+lioJAWyiIYEhICIng" + "BxUoKM44j/z72+E5ed7dfYb7vve9/L13reRmn3v2PnudYa291t5nrees9corr/ROOOGEz/d6" + "vQWrf7N7o0XP/Oc//7l+dfmFCy64oBcUNBVaB0VZLVCnf+xjH+ttvvnm087wM5/5TO8rX/nK" + "UC7usccem33nnXee/urfL8TjDpqSsmBRUJQPfvCDvX//+99pJ9amjtZaa61qu9SOevY3tROf" + "pn4Gwe8DH/hAKm+//fYFoSxBU1aW1VZl9vve974kwLng+X8JoP/P25Xq83bQap6N/QySH9e2" + "Wllmx6MOGoRl6f33v/+tBE9CiKCx3wVQQqh2+q92Xl/Xbtj83OIEBU1ZWWRV8lHbBZgyH7Ul" + "9Hl9UzusShd+//rXv3r/+Mc/0vbrXve6Ce3WWWed3tprr92Jn7aDgqZKa8stQqgo9UNY/b9+" + "ebt//vOfVfnnP/+595e//KX3t7/9LZX8V73668qPPrbffvvedtttl/raeuute7/5zW9622yz" + "TeqX3x//+MdUB4+m/oKCBuqGIVQaiRnRKRm93/CGN6SRXaR2PqJjKRDYnXbaKbX57ne/29tt" + "t93S9r333tt7/etfX7Xryo/+3vve9/bOP//8anuvvfZKJYrCtgh+6667brI4+XkFBQ1UWTT6" + "ImAI5i677FI1uPPOO5MgyhXyibq7OAjmD37wg7T997//PW3L7crnDV34yeXadddde0uWLEnb" + "3/nOd3gnlHihNNB5552XFHPp0qW9N73pTek8w/UKmvY5CwKKoD3wwANptEeQEcTbbrutN2PG" + "jAkWReST6x133DFt33777dU2Ap4f04UfCrN48eLU/uWXX+5deeWVvT/84Q+pfOmll6q+pCjz" + "5s1LfKXY4udWMShoynMWhNcn3n/961+Tq4MgMqrvueeeaW4gd4t65gSa1FPy/3vf+17v+9//" + "fmpHyX/qvF1Xflgn9v3pT39K7Zif4GaxD1ft4osvTn1hYVAULBLvi2jPufh5BQUNTFkQLAk/" + "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") getToolbarsOffData = ToolbarsOff.GetData getToolbarsOffImage = ToolbarsOff.GetImage getToolbarsOffBitmap = ToolbarsOff.GetBitmap diff -Nru mmass-3.12.1/gui/images_lib_msw.py mmass-4.0.0/gui/images_lib_msw.py --- mmass-3.12.1/gui/images_lib_msw.py 2011-06-30 11:52:00.000000000 +0000 +++ mmass-4.0.0/gui/images_lib_msw.py 2011-12-01 17:21:41.000000000 +0000 @@ -8783,6 +8783,65 @@ getBgrControlbarBitmap = BgrControlbar.GetBitmap #---------------------------------------------------------------------- +BgrControlbarDouble = PyEmbeddedImage( + "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" + "AwC5TQNJT4QhUAAAAABJRU5ErkJggg==") +getBgrControlbarDoubleData = BgrControlbarDouble.GetData +getBgrControlbarDoubleImage = BgrControlbarDouble.GetImage +getBgrControlbarDoubleBitmap = BgrControlbarDouble.GetBitmap + +#---------------------------------------------------------------------- BgrBottombar = PyEmbeddedImage( "iVBORw0KGgoAAAANSUhEUgAAAGQAAAAzCAYAAABhaa0bAAAACXBIWXMAAAsTAAALEwEAmpwY" "AAAKT2lDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVNnVFPpFj333vRCS4iAlEtvUhUI" @@ -8929,7 +8988,7 @@ #---------------------------------------------------------------------- Tools = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAAY0AAAAXCAYAAAD3LRNAAAAAGXRFWHRTb2Z0d2FyZQBBZG9i" + "iVBORw0KGgoAAAANSUhEUgAAAbgAAAAXCAYAAAB591o8AAAAGXRFWHRTb2Z0d2FyZQBBZG9i" "ZSBJbWFnZVJlYWR5ccllPAAAA2ZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tl" "dCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1l" "dGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUu" @@ -8940,57 +8999,68 @@ "YmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9u" "cy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRp" "ZDowMTgwMTE3NDA3MjA2ODExOTEwOUIwQzIyRTBFN0VGRiIgeG1wTU06RG9jdW1lbnRJRD0i" - "eG1wLmRpZDozODYzQ0U4RjlCMzMxMUUwOEE4OUU2MTY0MUIzOTE0NCIgeG1wTU06SW5zdGFu" - "Y2VJRD0ieG1wLmlpZDozODYzQ0U4RTlCMzMxMUUwOEE4OUU2MTY0MUIzOTE0NCIgeG1wOkNy" + "eG1wLmRpZDo2NkU5M0ZCOUYwMzAxMUUwOEIzRURDRTlEMEI2RjYwNiIgeG1wTU06SW5zdGFu" + "Y2VJRD0ieG1wLmlpZDo2NkU5M0ZCOEYwMzAxMUUwOEIzRURDRTlEMEI2RjYwNiIgeG1wOkNy" "ZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IE1hY2ludG9zaCI+IDx4bXBNTTpEZXJp" - "dmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjAzODAxMTc0MDcyMDY4MTE4NzQ4" - "RDIyRkJBOTlFQzkxIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjAxODAxMTc0MDcyMDY4" + "dmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkZEN0YxMTc0MDcyMDY4MTE5MTA5" + "QjE0MEFDMDgzOEM1IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjAxODAxMTc0MDcyMDY4" "MTE5MTA5QjBDMjJFMEU3RUZGIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwv" - "eDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+7QT34QAACS5JREFUeNrsXLGO4zgM1QID" - "pxlNozROlTRJk6km//8F6bZyNVflmk1zmcZu5hJAwr3lkhIpJ4tZnAgIji1boSiK4iNlO9eo" - "UaNGjRo1atSoUaNGjRo1atSoUaNGjRo1avT16ZtwvbsWH4+Jpmu5xGMNcW2WyPKfmvbn9uFe" - "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") + "eDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+FyR43QAAC2pJREFUeNrsXT1z2zgQhW88" + "UiO6oRqpihqrOVXW//8F6lyx8lVKEzVHN2TjkzKA8/y0Cywgyckl2BkOLYIEl4vdtx8A6bu3" + "tzdXqVKlSpUq/W70VxVBpUqVKlWqDq5SpUqVKlWqDq5SpUqVKlX6eXQf/ri7u8Pjk+PW+H2g" + "8bj1fq+SNKfn+5b6TNGHe3LfBp6j/cV4vjYJvE6P26DIU23/v86Z0vNbKCUj9zvIpdJP0bcY" + "VpxhBOpWpF/ssxgrfxLmmG3ts+yswGe8yxx5vFcGanncXoS21XHbWwBH6LP11+bSiZeD4Z4n" + "QXwz9Df3/VmMIgjYWRTWqBAo39P+Vbhs5mVVKu/PcEZXMQohaAkyP+lLd9zWfrz647mjxqu/" + "jvnhYxrP2rVakOcK28aIbjlF13LPK+EpCs5hjGBssoNIiz4ogBzomsFeCiusmIM0pT6zbNco" + "2yiYG/j797g9CHoY8MjEM/CKOhnsh3VN07PUc8T8kEb8bGcOLtXpiwecPjOza7zgtsdt5/cD" + "KTAq8hTO28ecEvFuBWZLdBf+3oPSj5c4O0G+wemvAcxP+w3I+6c4uQyQsIyNyzBy1r8uAMax" + "fS85OZLrmkC98zI8eHlLOoznBVlrIDj3+5K2g6IHD/7YNwJHR+fNPW/fBBDV+F15m9orbSiX" + "FDhbg8gSB8H2FwKcgBlrsLv+QnsIGLAFPUDQ3Wc8AzriFcjxJdM2rLJNBuqJcYnhkZVn5BV1" + "XtP/0GcTaZPu8QLjlKI+WqKELCvlMbsChZ4IzHSRe6wLnZeLCGRXoGhbesYdDUpuhjcl+U4p" + "Im/oeFC6h1/AwUnZUMnYxKJ3VOoAaMH5xIwP5dopgdkycQ7LelIQIFnb+DkHn7U7Cmwc6cvE" + "y2QtyAT7DwHSsz9nE2lbgzyCM9FkPTHa3r5QZ6UAZyeM2bWCqoBDSwgA5uDgc8B+5fvbAs+T" + "zGd3Nz5/D06oJEOS7r2g49KYt/54W3gPK3bPYw6ugWyi96ARGB4M2Vmu0q0B0JOeOJN27jq0" + "U/5uCzO8gaK8gZ65p+MYgUsOIVZaKmqLlDwuzdjEYADKUhOQ60k3/jlla8f2A4Bwe/zd++PI" + "K8pVy+BelXP4vEEA7OBod34/FrRpxivpypai151SdrxGgFHiyLkCM4DTHMA55waAjfDcvL9G" + "gCZlNWt/ziRTthMIRC7hcUw8N+/HzOfGqpTm3LYFQcmzgN9zyMAdZeKI/4cMvOfrN57XLjZe" + "90Lj6YZfvUBCzbZ3toUROZSTweVSaQYXBh+FuSZ+t/R3LMOTlHgPQHvw8nW0nyVKRegQ9kJp" + "yRW2jQZDLgVUnKN4z/hPTso7uSnI9X2+zTuzHsbgga4Lcj24H3Oa4fwg3wECtQdBh1/h2lGJ" + "8tdkrLltVoBzQqQtnWMFnVWkbevkOeDUvaQKzFzIhLAilKNjEh1AJiVBMGZag1CO7ArxZ4xg" + "TJNRqu1BfinntsyQQZh7WyuBBGPkyhkXdgkVAbTFnoL5XSbepOjgt1UsC73PqNkGQc0BLHIZ" + "HECRN06fg5sImUwqM2iNzqx1eh2/IeD/nknA310kq9tlGMReAVqUwUNCxjyv6SA7kaKmVJs1" + "MwvR4LRg7JfgXL87uaOTGqE9yLg5ZW7euWEW8L2cR9kbOvvwjDO6d+o3Z3CjYAeNMtY5bZzV" + "OMr65+zg/fMzsI8JEOX5qkYA76DLcwCJHQBQCkCxAhNs9tX3NxFA1KJjMTyZeZ6s82+8oKEl" + "O5gLGVxT4Dz7CMh2GWCOQVrMya2VQCyF400kkGAsSPGMx7/icbDLk+3uqQQe5HytNQWj+7iG" + "4ZxODHmmTrXUN6iptvA7OJAFnNdADfb9utAfbnDOF/g7tS38+WrffqCs/Un9T0gGLZ3zCFnd" + "o9LPI7U9KX1LRqcdU0mQ6bW2RaJEGe73N+0XFp5Jp578viUZLEiuC5Lt9/EgHQggfy05sF4/" + "0h75z2lbCLw+hfuBPqOd4daCjjRwnzfQn5bO4wCgBX2Wfi+k6wWde4zIDm3yidpbDSPg+b8k" + "xucL25bSV2voBzGObVrEnYgzxXF7FPpT5SoEayy/J4EviwxQDmivC5JDI8hd5dmf/+j7/IJ6" + "I9x/IeGMhmsRfHuK9KP6oHtDuaChstrKna/GyYniDxDJTyPnHFx6UpLnDVOZR5hzwgnXg1Am" + "COXGTihROmOGJ0Wr0jyWdMyyBH9MlHe7zLYxUcOfghxdQQbnFOBFGSxBzzolIl77eTl8bUCb" + "g8spX2lzcBwBbwrbnJCphgxKW0HKhAtgsIQ+QAYQyw64xBP7nSKeQw/TGDOhsmDNCkewy4Uv" + "e3EGY602pALGF7D1SzI4Sb5cOuu4NG/oK1y/hdLhweUtgEE5TAVbx0xtyOB5ItjnMpJFl5Zt" + "pepf1hzkvbFzNNQZKFkpTd355KSLzBukBq/3Qou9N9OCI9Hmk0a/7QhUr0UI6COVY/GYZUGH" + "VBrBebbctj4xd7FJlCwtJetRuRZXj4bnmnkdYaf8bnje0Y1On4PTnDXzekiUhPfAx5T0w9qG" + "MugVANKWRYegbxD0VnuXbYTsbIyMzUAAOKF+NeoUu31RnJulLIWA+HqB83KGe63cj1cucubg" + "JiQr7d1CLp1tnf31A2lh34zw4hLsHT224Bjn8Mwrdkd2uhCwdReUbZFe3cd1CkPEiUYd3BTK" + "FxjdbskQFoWRfOPSS1NLHGiYI1y68mXKLlKblv6WMrygFH1iPoGfEY9JTm+MRLvSSsnSNksE" + "KD1LcC6xRUhh7jU4Llymzr/npMgxw3OJOTgpU9uTcY/GAG9X2GaJUHkuLCfo43eMOIjhdy3X" + "lLUyuKWAWMvgnCtfUKC9opPrvAI/aEstBNWY5edmcIwzWpbNWV3ue72OZPlMelW62hztdUry" + "LOEZj02EDzVIWBrs9ODsc6qD8MyaE406uAkZyk7ZPxuiHVbIaQQoeTVOTpQWFj0EJV17Ac9I" + "Mdfu/E16zTCYhzDIPHCdoJBzJ38Op1GCBO1Y6+KTvrllKUubo2ygNRi8g7Ku9kLu1H18peKV" + "yt4H+v3h1QWfrWmGN7r0O24cQOUEQJiJbSNZ2taQwbHeNTAWg5MXX+2AZ+fkRSoTcv5T4onf" + "tWxAFls6ZgHizuCEL1ktp+HOygjurONYlhvcjxWVLy5/FeUy4uRjVZZLXnPYQMCRu9AmZa8H" + "stkcnltykNLL3Kd7fKUAKuxjK875PlrAaipRoqFsjJnZkHAWONC4OshCLLhUv7mkRUFoGLyC" + "bTRmeJoj6CJRWezYGSDf+JtwU0FJd8Z9J0SzQVfmQlkt/O6l8hg8Z8zwrHNwqbk27RoEMnwv" + "L6dNA74OHNc+UVIbSI8ksN9Bf7lVCmtAKWHEAMeDLHLnWjDrwsrRriDil/oOFYEWMCaM0QbK" + "16msex/JHB6EKgvqrdVBS5nS1wI77oz2iplnimeU/zPhaaPw3meWV9nen0vK0nf0nbmLvxeZ" + "+NhySf9q3/Syc2uM3s8MBWRg4SfrU16Z3/GLDVzut+eK6UJeRZ4V2Sa/FUkfuuWFGJghWBbm" + "5HzAuXW3+1QX65H2vcgzWTr95ekWspK9EElLy7U7KFW9aCXKQox40ID8M75FmbBlbWzFMRN0" + "0DIH5yJjLel2ikcx00nIwGrHlm+lYjVF/aaki3xv0mV8i/JaH1u+I3C/+hf/afBy+//U/yZQ" + "+MX76JcaLujb5YDDlR3cVfuLOLgSuvgD2Jn3udXHlm/BLwcLlkUnyUUmBRgRfV6jg7vIFi74" + "bwJxwLyibST6Nf13ggtk8CvYsvocl9wj5uBuAsC36vva/X7GwP2pdAvZ3lLOt+L3VvpwS/n+" + "6UHar8xvxZeEXKuAKlWqVKnS70j1P3pXqlSpUqXq4CpVqlSpUqX/C/0nwAC90+UfLSTIAwAA" + "AABJRU5ErkJggg==") getToolsData = Tools.GetData getToolsImage = Tools.GetImage getToolsBitmap = Tools.GetBitmap @@ -9008,63 +9078,63 @@ "YmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9u" "cy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRp" "ZDowOTgwMTE3NDA3MjA2ODExOTEwOURDQkFDQjFGMDFEOCIgeG1wTU06RG9jdW1lbnRJRD0i" - "eG1wLmRpZDpENUE5MDQ5NjU0N0ExMUUwOTg4M0ZFNjBENDk0NUM4QiIgeG1wTU06SW5zdGFu" - "Y2VJRD0ieG1wLmlpZDpENUE5MDQ5NTU0N0ExMUUwOTg4M0ZFNjBENDk0NUM4QiIgeG1wOkNy" + "eG1wLmRpZDpDQzJCN0I0NkQxNTgxMUUwQUJCMEFBNzg4OTFEQjQ4MiIgeG1wTU06SW5zdGFu" + "Y2VJRD0ieG1wLmlpZDpDQzJCN0I0NUQxNTgxMUUwQUJCMEFBNzg4OTFEQjQ4MiIgeG1wOkNy" "ZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IE1hY2ludG9zaCI+IDx4bXBNTTpEZXJp" - "dmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjAxODAxMTc0MDcyMDY4MTE5N0E1" + "dmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjAyODAxMTc0MDcyMDY4MTE5N0E1" "OTQ1MTJEN0FBRjE3IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjA5ODAxMTc0MDcyMDY4" "MTE5MTA5RENCQUNCMUYwMUQ4Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwv" - "eDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+j8iuxgAACnxJREFUeNrsnbuS4joQhsUp" - "yiQLCZOsozPRRJPNQ+xjzWOdhyAjIiJjkyUZSFAyx96VdppGsnX19f+qKG6eaUvIv7plu3vx" - "+fkpAACgT/5BFwAAIEQAAAgRugAAMDshWiwW79XTO7oeAACPCAAwGJZOXsyPu7dF9Vir15fq" - "IemXn/+hUwEA+T2iWoR+qccaXQgA6EOICstrAADIF5qRcKx+3pLP9WtpCtNiqMJBatPEX5sI" - "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") + "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" + "gg==") getBottombarsOnData = BottombarsOn.GetData getBottombarsOnImage = BottombarsOn.GetImage getBottombarsOnBitmap = BottombarsOn.GetBitmap @@ -9082,70 +9152,69 @@ "YmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9u" "cy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRp" "ZDowOTgwMTE3NDA3MjA2ODExOTEwOURDQkFDQjFGMDFEOCIgeG1wTU06RG9jdW1lbnRJRD0i" - "eG1wLmRpZDpBQTIzQzQ1NzU0N0ExMUUwOTg4M0ZFNjBENDk0NUM4QiIgeG1wTU06SW5zdGFu" - "Y2VJRD0ieG1wLmlpZDpBQTIzQzQ1NjU0N0ExMUUwOTg4M0ZFNjBENDk0NUM4QiIgeG1wOkNy" + "eG1wLmRpZDpDQzJCN0I0QUQxNTgxMUUwQUJCMEFBNzg4OTFEQjQ4MiIgeG1wTU06SW5zdGFu" + "Y2VJRD0ieG1wLmlpZDpDQzJCN0I0OUQxNTgxMUUwQUJCMEFBNzg4OTFEQjQ4MiIgeG1wOkNy" "ZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IE1hY2ludG9zaCI+IDx4bXBNTTpEZXJp" - "dmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjAxODAxMTc0MDcyMDY4MTE5N0E1" + "dmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjAyODAxMTc0MDcyMDY4MTE5N0E1" "OTQ1MTJEN0FBRjE3IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjA5ODAxMTc0MDcyMDY4" "MTE5MTA5RENCQUNCMUYwMUQ4Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwv" - "eDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+mGqPvwAACl5JREFUeNrsnbty2zoQhuGM" - "hmoiNXRjVseVK3d5wDygOlWq3ClN1ERuhCaHTIBovQaIO6//N8PR1V4CAn7uguTuw+/fvwUA" - "AIzJA4QIAAAhAgBAiCBEAIDVCdHDw8N3ZfM7uh8A0PEFXQAAGJuNpxdDX1bttlPPr+0m6YcI" - "9QAAQ3hEnQj9VNsOXQgAGEOIKstzAAAoF5qRcKx7rMn7+rk0hWkptOEgtWnin02EgwCsQ4h0" - "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" - "AAAAAElFTkSuQmCC") + "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") getBottombarsOffData = BottombarsOff.GetData getBottombarsOffImage = BottombarsOff.GetImage getBottombarsOffBitmap = BottombarsOff.GetBitmap #---------------------------------------------------------------------- ToolbarsOn = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAAMsAAADcCAYAAADeKFUQAAAAGXRFWHRTb2Z0d2FyZQBBZG9i" + "iVBORw0KGgoAAAANSUhEUgAAAMsAAADyCAYAAADjjjFWAAAAGXRFWHRTb2Z0d2FyZQBBZG9i" "ZSBJbWFnZVJlYWR5ccllPAAAA2ZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tl" "dCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1l" "dGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUu" @@ -9156,138 +9225,146 @@ "YmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9u" "cy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRp" "ZDowMTgwMTE3NDA3MjA2ODExOTEwOURDQkFDQjFGMDFEOCIgeG1wTU06RG9jdW1lbnRJRD0i" - "eG1wLmRpZDo5MkNEMjgxNTlBODExMUUwODY3Q0U2MzRDNzYzRjNGMiIgeG1wTU06SW5zdGFu" - "Y2VJRD0ieG1wLmlpZDo5MkNEMjgxNDlBODExMUUwODY3Q0U2MzRDNzYzRjNGMiIgeG1wOkNy" + "eG1wLmRpZDo3MDRCRDA4QkJBQTUxMUUwQjQ4NkRCM0I1Nzk0NTg3MiIgeG1wTU06SW5zdGFu" + "Y2VJRD0ieG1wLmlpZDo3MDRCRDA4QUJBQTUxMUUwQjQ4NkRCM0I1Nzk0NTg3MiIgeG1wOkNy" "ZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IE1hY2ludG9zaCI+IDx4bXBNTTpEZXJp" - "dmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjA1ODAxMTc0MDcyMDY4MTE5OTRD" - "Qzc2RTMwRTk0MDg1IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjAxODAxMTc0MDcyMDY4" + "dmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjAxODAxMTc0MDcyMDY4MTE5NUZF" + "REI1MDhCOEE3MTU2IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjAxODAxMTc0MDcyMDY4" "MTE5MTA5RENCQUNCMUYwMUQ4Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwv" - "eDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+GBLuqwAAGNlJREFUeNrsXU2IZNd1vi1N" - "qiylq2VRg2BqEaYFSYGhIYjGi6yETcDLIJksE0IEIgsLhPBGEcxgiWyyEHjjlQmx8M4iwYTE" - "KCJkk4VE7XphKlnUEEwPJFOJMjXSuN54pnPv9Dldp2/f+979q1d/3weHV+/Vq7rv53z3nHPf" - "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") + "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" + "AElFTkSuQmCC") getToolbarsOnData = ToolbarsOn.GetData getToolbarsOnImage = ToolbarsOn.GetImage getToolbarsOnBitmap = ToolbarsOn.GetBitmap #---------------------------------------------------------------------- ToolbarsOff = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAAMsAAADcCAYAAADeKFUQAAAAGXRFWHRTb2Z0d2FyZQBBZG9i" + "iVBORw0KGgoAAAANSUhEUgAAAMsAAADyCAYAAADjjjFWAAAAGXRFWHRTb2Z0d2FyZQBBZG9i" "ZSBJbWFnZVJlYWR5ccllPAAAA2ZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tl" "dCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1l" "dGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUu" @@ -9298,131 +9375,139 @@ "YmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9u" "cy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRp" "ZDowMTgwMTE3NDA3MjA2ODExOTEwOURDQkFDQjFGMDFEOCIgeG1wTU06RG9jdW1lbnRJRD0i" - "eG1wLmRpZDo5MkNEMjgxMTlBODExMUUwODY3Q0U2MzRDNzYzRjNGMiIgeG1wTU06SW5zdGFu" - "Y2VJRD0ieG1wLmlpZDo5MkNEMjgxMDlBODExMUUwODY3Q0U2MzRDNzYzRjNGMiIgeG1wOkNy" + "eG1wLmRpZDo3MDRCRDA4N0JBQTUxMUUwQjQ4NkRCM0I1Nzk0NTg3MiIgeG1wTU06SW5zdGFu" + "Y2VJRD0ieG1wLmlpZDo3MDRCRDA4NkJBQTUxMUUwQjQ4NkRCM0I1Nzk0NTg3MiIgeG1wOkNy" "ZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IE1hY2ludG9zaCI+IDx4bXBNTTpEZXJp" - "dmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjA1ODAxMTc0MDcyMDY4MTE5OTRD" - "Qzc2RTMwRTk0MDg1IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjAxODAxMTc0MDcyMDY4" + "dmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjAxODAxMTc0MDcyMDY4MTE5NUZF" + "REI1MDhCOEE3MTU2IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjAxODAxMTc0MDcyMDY4" "MTE5MTA5RENCQUNCMUYwMUQ4Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwv" - "eDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+oFZZ7AAAGMhJREFUeNrsXU2IJEd2jpbG" - "VSu5q2VRjaDrYKYF3oKFBiOaPfgkdvHdSIuPNsYC4cMKhNiLLJhhJXzxQbCXPRnjFXtbYbMY" - "28jC+OKDRN36sJR9qMEsPWBP2fLUSLOVsyM5QvNe16voiMz4q6y/74NH/lRWRWbW++K9Fxnv" - "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") + "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" + "SUVORK5CYII=") getToolbarsOffData = ToolbarsOff.GetData getToolbarsOffImage = ToolbarsOff.GetImage getToolbarsOffBitmap = ToolbarsOff.GetBitmap diff -Nru mmass-3.12.1/gui/images.py mmass-4.0.0/gui/images.py --- mmass-3.12.1/gui/images.py 2011-06-30 11:47:28.000000000 +0000 +++ mmass-4.0.0/gui/images.py 2011-11-28 11:36:18.000000000 +0000 @@ -115,6 +115,7 @@ lib['bgrToolbar'] = images_lib.getBgrToolbarBitmap() lib['bgrToolbarNoBorder'] = images_lib.getBgrToolbarNoBorderBitmap() lib['bgrControlbar'] = images_lib.getBgrControlbarBitmap() + lib['bgrControlbarDouble'] = images_lib.getBgrControlbarDoubleBitmap() lib['bgrBottombar'] = images_lib.getBgrBottombarBitmap() lib['bgrPeakEditor'] = images_lib.getBgrPeakEditorBitmap() @@ -132,27 +133,28 @@ # tools if wx.Platform == '__WXMAC__': tools = images_lib.getToolsBitmap() - lib['toolsProcessing'] = tools.GetSubBitmap(wx.Rect(0, 0, 30, 22)) - lib['toolsCalibration'] = tools.GetSubBitmap(wx.Rect(30, 0, 30, 22)) - lib['toolsSequence'] = tools.GetSubBitmap(wx.Rect(60, 0, 30, 22)) - lib['toolsMassCalculator'] = tools.GetSubBitmap(wx.Rect(90, 0, 30, 22)) - lib['toolsCompoundsSearch'] = tools.GetSubBitmap(wx.Rect(120, 0, 30, 22)) - lib['toolsPeakDifferences'] = tools.GetSubBitmap(wx.Rect(150, 0, 30, 22)) - lib['toolsComparePeaklists'] = tools.GetSubBitmap(wx.Rect(180, 0, 30, 22)) - lib['toolsMascot'] = tools.GetSubBitmap(wx.Rect(210, 0, 30, 22)) - lib['toolsProfound'] = tools.GetSubBitmap(wx.Rect(240, 0, 30, 22)) - lib['toolsDocumentInfo'] = tools.GetSubBitmap(wx.Rect(270, 0, 30, 22)) - lib['toolsDocumentReport'] = tools.GetSubBitmap(wx.Rect(300, 0, 30, 22)) - lib['toolsDocumentExport'] = tools.GetSubBitmap(wx.Rect(330, 0, 30, 22)) + lib['toolsProcessing'] = tools.GetSubBitmap(wx.Rect(0, 0, 30, 23)) + lib['toolsCalibration'] = tools.GetSubBitmap(wx.Rect(30, 0, 30, 23)) + lib['toolsSequence'] = tools.GetSubBitmap(wx.Rect(60, 0, 30, 23)) + lib['toolsMassCalculator'] = tools.GetSubBitmap(wx.Rect(90, 0, 30, 23)) + lib['toolsCompoundsSearch'] = tools.GetSubBitmap(wx.Rect(120, 0, 30, 23)) + lib['toolsPeakDifferences'] = tools.GetSubBitmap(wx.Rect(150, 0, 30, 23)) + lib['toolsComparePeaklists'] = tools.GetSubBitmap(wx.Rect(180, 0, 30, 23)) + lib['toolsMascot'] = tools.GetSubBitmap(wx.Rect(210, 0, 30, 23)) + lib['toolsProfound'] = tools.GetSubBitmap(wx.Rect(240, 0, 30, 23)) + lib['toolsDocumentInfo'] = tools.GetSubBitmap(wx.Rect(270, 0, 30, 23)) + lib['toolsDocumentReport'] = tools.GetSubBitmap(wx.Rect(300, 0, 30, 23)) + lib['toolsDocumentExport'] = tools.GetSubBitmap(wx.Rect(330, 0, 30, 23)) lib['toolsPresets'] = tools.GetSubBitmap(wx.Rect(360, 0, 30, 22)) - lib['toolsMassFilter'] = tools.GetSubBitmap(wx.Rect(390, 0, 30, 22)) - lib['toolsSpectrumGenerator'] = tools.GetSubBitmap(wx.Rect(420, 0, 30, 22)) + lib['toolsMassFilter'] = tools.GetSubBitmap(wx.Rect(390, 0, 30, 23)) + lib['toolsSpectrumGenerator'] = tools.GetSubBitmap(wx.Rect(420, 0, 30, 23)) + lib['toolsEnvelopeFit'] = tools.GetSubBitmap(wx.Rect(450, 0, 30, 23)) + lib['toolsLibrary'] = tools.GetSubBitmap(wx.Rect(480, 0, 30, 22)) else: tools = images_lib.getToolsBitmap() lib['toolsOpen'] = tools.GetSubBitmap(wx.Rect(0, 0, 22, 22)) lib['toolsSave'] = tools.GetSubBitmap(wx.Rect(22, 0, 22, 22)) lib['toolsPrint'] = tools.GetSubBitmap(wx.Rect(44, 0, 22, 22)) - lib['toolsProcessing'] = tools.GetSubBitmap(wx.Rect(66, 0, 22, 22)) lib['toolsCalibration'] = tools.GetSubBitmap(wx.Rect(88, 0, 22, 22)) lib['toolsSequence'] = tools.GetSubBitmap(wx.Rect(110, 0, 22, 22)) @@ -168,6 +170,8 @@ lib['toolsPresets'] = tools.GetSubBitmap(wx.Rect(330, 0, 22, 22)) lib['toolsMassFilter'] = tools.GetSubBitmap(wx.Rect(352, 0, 22, 22)) lib['toolsSpectrumGenerator'] = tools.GetSubBitmap(wx.Rect(374, 0, 22, 22)) + lib['toolsEnvelopeFit'] = tools.GetSubBitmap(wx.Rect(396, 0, 22, 22)) + lib['toolsLibrary'] = tools.GetSubBitmap(wx.Rect(418, 0, 22, 22)) # bottombars bottombarsOn = images_lib.getBottombarsOnBitmap() @@ -182,25 +186,24 @@ lib['peaklistEditorOn'] = bottombarsOn.GetSubBitmap(wx.Rect(87, 22, 29, 22)) lib['peaklistEditorOff'] = bottombarsOff.GetSubBitmap(wx.Rect(87, 22, 29, 22)) - lib['spectrumParams'] = bottombarsOff.GetSubBitmap(wx.Rect(0, 44, 29, 22)) - lib['spectrumLabelsOn'] = bottombarsOn.GetSubBitmap(wx.Rect(29, 44, 29, 22)) - lib['spectrumLabelsOff'] = bottombarsOff.GetSubBitmap(wx.Rect(29, 44, 29, 22)) - lib['spectrumTicksOn'] = bottombarsOn.GetSubBitmap(wx.Rect(58, 44, 29, 22)) - lib['spectrumTicksOff'] = bottombarsOff.GetSubBitmap(wx.Rect(58, 44, 29, 22)) - lib['spectrumNotationsOn'] = bottombarsOn.GetSubBitmap(wx.Rect(87, 44, 29, 22)) - lib['spectrumNotationsOff'] = bottombarsOff.GetSubBitmap(wx.Rect(87, 44, 29, 22)) - lib['spectrumLabelAngleOn'] = bottombarsOn.GetSubBitmap(wx.Rect(116, 44, 29, 22)) - lib['spectrumLabelAngleOff'] = bottombarsOff.GetSubBitmap(wx.Rect(116, 44, 29, 22)) - lib['spectrumPosBarsOn'] = bottombarsOn.GetSubBitmap(wx.Rect(145, 44, 29, 22)) - lib['spectrumPosBarsOff'] = bottombarsOff.GetSubBitmap(wx.Rect(145, 44, 29, 22)) - lib['spectrumGelOn'] = bottombarsOn.GetSubBitmap(wx.Rect(174, 44, 29, 22)) - lib['spectrumGelOff'] = bottombarsOff.GetSubBitmap(wx.Rect(174, 44, 29, 22)) - lib['spectrumTrackerOn'] = bottombarsOn.GetSubBitmap(wx.Rect(203, 44, 29, 22)) - lib['spectrumTrackerOff'] = bottombarsOff.GetSubBitmap(wx.Rect(203, 44, 29, 22)) - lib['spectrumAutoscaleOn'] = bottombarsOn.GetSubBitmap(wx.Rect(232, 44, 29, 22)) - lib['spectrumAutoscaleOff'] = bottombarsOff.GetSubBitmap(wx.Rect(232, 44, 29, 22)) - lib['spectrumNormalizeOn'] = bottombarsOn.GetSubBitmap(wx.Rect(261, 44, 29, 22)) - lib['spectrumNormalizeOff'] = bottombarsOff.GetSubBitmap(wx.Rect(261, 44, 29, 22)) + lib['spectrumLabelsOn'] = bottombarsOn.GetSubBitmap(wx.Rect(0, 44, 29, 22)) + lib['spectrumLabelsOff'] = bottombarsOff.GetSubBitmap(wx.Rect(0, 44, 29, 22)) + lib['spectrumTicksOn'] = bottombarsOn.GetSubBitmap(wx.Rect(29, 44, 29, 22)) + lib['spectrumTicksOff'] = bottombarsOff.GetSubBitmap(wx.Rect(29, 44, 29, 22)) + lib['spectrumNotationsOn'] = bottombarsOn.GetSubBitmap(wx.Rect(58, 44, 29, 22)) + lib['spectrumNotationsOff'] = bottombarsOff.GetSubBitmap(wx.Rect(58, 44, 29, 22)) + lib['spectrumLabelAngleOn'] = bottombarsOn.GetSubBitmap(wx.Rect(87, 44, 29, 22)) + lib['spectrumLabelAngleOff'] = bottombarsOff.GetSubBitmap(wx.Rect(87, 44, 29, 22)) + lib['spectrumPosBarsOn'] = bottombarsOn.GetSubBitmap(wx.Rect(116, 44, 29, 22)) + lib['spectrumPosBarsOff'] = bottombarsOff.GetSubBitmap(wx.Rect(116, 44, 29, 22)) + lib['spectrumGelOn'] = bottombarsOn.GetSubBitmap(wx.Rect(145, 44, 29, 22)) + lib['spectrumGelOff'] = bottombarsOff.GetSubBitmap(wx.Rect(145, 44, 29, 22)) + lib['spectrumTrackerOn'] = bottombarsOn.GetSubBitmap(wx.Rect(174, 44, 29, 22)) + lib['spectrumTrackerOff'] = bottombarsOff.GetSubBitmap(wx.Rect(174, 44, 29, 22)) + lib['spectrumAutoscaleOn'] = bottombarsOn.GetSubBitmap(wx.Rect(203, 44, 29, 22)) + lib['spectrumAutoscaleOff'] = bottombarsOff.GetSubBitmap(wx.Rect(203, 44, 29, 22)) + lib['spectrumNormalizeOn'] = bottombarsOn.GetSubBitmap(wx.Rect(232, 44, 29, 22)) + lib['spectrumNormalizeOff'] = bottombarsOff.GetSubBitmap(wx.Rect(232, 44, 29, 22)) lib['spectrumLabelPeakOn'] = bottombarsOn.GetSubBitmap(wx.Rect(0, 66, 29, 22)) lib['spectrumLabelPeakOff'] = bottombarsOff.GetSubBitmap(wx.Rect(0, 66, 29, 22)) @@ -661,6 +664,7 @@ "-a -u -n BgrToolbar images/"+platform+"/bgr_toolbar.png images_lib_"+platform+".py", "-a -u -n BgrToolbarNoBorder images/"+platform+"/bgr_toolbar_noborder.png images_lib_"+platform+".py", "-a -u -n BgrControlbar images/"+platform+"/bgr_controlbar.png images_lib_"+platform+".py", + "-a -u -n BgrControlbarDouble images/"+platform+"/bgr_controlbar_double.png images_lib_"+platform+".py", "-a -u -n BgrBottombar images/"+platform+"/bgr_bottombar.png images_lib_"+platform+".py", "-a -u -n BgrPeakEditor images/"+platform+"/bgr_peakeditor.png images_lib_"+platform+".py", diff -Nru mmass-3.12.1/gui/libs.py mmass-4.0.0/gui/libs.py --- mmass-3.12.1/gui/libs.py 2011-06-30 11:24:20.000000000 +0000 +++ mmass-4.0.0/gui/libs.py 2011-11-29 12:31:21.000000000 +0000 @@ -16,7 +16,9 @@ # ------------------------------------------------------------------------- # load libs +import sys import os.path +import shutil import xml.dom.minidom import copy @@ -25,11 +27,20 @@ import mspy +# ENSURE DEFAULT LIBS ARE AVAILABLE AFTER MAC INSTALLATION +# -------------------------------------------------------- +if sys.platform == 'darwin': + for item in ('monomers.xml', 'modifications.xml', 'enzymes.xml', 'presets.xml', 'references.xml', 'compounds.xml', 'mascot.xml'): + if not os.path.exists(os.path.join(config.confdir, item)): + try: shutil.copyfile(os.path.join('configs', item), os.path.join(config.confdir, item)) + except: pass + + # LOAD USER'S LIBS INTO MSPY # -------------------------- -try: mspy.loadAminoacids(os.path.join(config.confdir,'aminoacids.xml'), clear=False) -except: mspy.saveAminoacids(os.path.join(config.confdir,'aminoacids.xml')) +try: mspy.loadMonomers(os.path.join(config.confdir,'monomers.xml'), clear=False) +except: mspy.saveMonomers(os.path.join(config.confdir,'monomers.xml')) try: mspy.loadModifications(os.path.join(config.confdir,'modifications.xml'), clear=False) except: mspy.saveModifications(os.path.join(config.confdir,'modifications.xml')) @@ -76,7 +87,7 @@ 'removeIsotopes': 1, 'removeUnknown': 1, 'setAsMonoisotopic': 1, - 'labelEnvelope': 'monoisotopic', + 'labelEnvelope': '1st', 'envelopeIntensity': 'maximum', }, 'deconvolution':{ @@ -118,7 +129,7 @@ 'removeIsotopes': 1, 'removeUnknown': 1, 'setAsMonoisotopic': 1, - 'labelEnvelope': 'monoisotopic', + 'labelEnvelope': '1st', 'envelopeIntensity': 'maximum', }, 'deconvolution':{ @@ -160,7 +171,7 @@ 'removeIsotopes': 0, 'removeUnknown': 0, 'setAsMonoisotopic': 0, - 'labelEnvelope': 'monoisotopic', + 'labelEnvelope': '1st', 'envelopeIntensity': 'maximum', }, 'deconvolution':{ @@ -176,7 +187,7 @@ 'highMass': 4000, }, 'baseline':{ - 'precision': 100, + 'precision': 20, 'offset': 0.25, }, 'smoothing':{ @@ -202,7 +213,7 @@ 'removeIsotopes': 1, 'removeUnknown': 0, 'setAsMonoisotopic': 1, - 'labelEnvelope': 'monoisotopic', + 'labelEnvelope': '1st', 'envelopeIntensity': 'maximum', }, 'deconvolution':{ @@ -244,7 +255,7 @@ 'removeIsotopes': 1, 'removeUnknown': 1, 'setAsMonoisotopic': 1, - 'labelEnvelope': 'monoisotopic', + 'labelEnvelope': '1st', 'envelopeIntensity': 'maximum', }, 'deconvolution':{ @@ -286,7 +297,7 @@ 'removeIsotopes': 1, 'removeUnknown': 1, 'setAsMonoisotopic': 1, - 'labelEnvelope': 'monoisotopic', + 'labelEnvelope': '1st', 'envelopeIntensity': 'maximum', }, 'deconvolution':{ @@ -299,15 +310,16 @@ }, 'modifications':{ '-None-':[], - 'Carbamidomethyl (C) Oxidation (MW)':[ + 'Carbamidomethyl (C)':[ ['Carbamidomethyl', 'C', 'f'], - ['Oxidation', 'M', 'v'], - ['Oxidation', 'W', 'v'], ], 'Oxidation (MW)':[ ['Oxidation', 'M', 'v'], ['Oxidation', 'W', 'v'], ], + 'N-Formyl Met':[ + ['FormylMet', 0, 'v'] + ], }, 'fragments':{ '-None-':[], @@ -321,71 +333,7 @@ } references = { - 'PepMix Bruker - MALDI Pos Mo':[ - ('Bradykinin (1-7) [M+H]+', 757.399150), - ('Angiotensin II [M+H]+', 1046.541792), - ('Angiotensin I [M+H]+', 1296.684768), - ('Substance P [M+H]+', 1347.735423), - ('Bombesin [M+H]+', 1619.822341), - ('ACTH clip (1-17) [M+H]+', 2093.086160), - ('ACTH clip (18-39) [M+H]+', 2465.198332), - ('Somatostatin 28 [M+H]+', 3147.470975), - ], - 'PepMix Bruker - MALDI Neg Mo':[ - ('Angiotensin II [M-H]-', 1044.527247), - ('Angiotensin I [M-H]-', 1294.670247), - ('Substance P [M-H]-', 1345.720847), - ('Bombesin [M-H]-', 1617.807747), - ('ACTH clip (1-17) [M-H]-', 2091.071647), - ('ACTH clip (18-39) [M-H]-', 2463.183747), - ('Somatostatin 28 [M-H]-', 3145.456447), - ], - 'PepMix Bruker PAC - MALDI Pos Mo':[ - ('Bradykinin (1-7) [M+H]+', 757.399160), - ('Angiotensin III [M+H]+', 931.514849), - ('Angiotensin II [M+H]+', 1046.541792), - ('Angiotensin I [M+H]+', 1296.684768), - ('Substance P [M+H]+', 1347.735423), - ('Bombesin [M+H]+', 1619.822341), - ('Neurotensin [M+H]+', 1672.917000), - ('Renin Substrate [M+H]+', 1758.932610), - ('ACTH clip (1-17) [M+H]+', 2093.086160), - ('ACTH clip (18-39) [M+H]+', 2465.198332), - ('ACTH clip (1-24) [M+H]+', 2932.587870), - ('Somatostatin 28 [M+H]+', 3147.470975), - ('ACTH clip (7-38) [M+H]+', 3657.928900), - ], - 'ProtMix I Bruker - MALDI Pos Av':[ - ('Insulin [M+H]+', 5735), - ('Cytochrome C [M+2H]2+', 6181), - ('Myoglobin [M+2H]2+', 8477), - ('Ubiquitin I [M+H]+', 8566), - ('Cytochrom C [M+H]+', 12361), - ('Myoglobin [M+H]+', 16953), - ], - 'ProtMix I Bruker - MALDI Neg Av':[ - ('Insulin [M-H]-', 5733), - ('Cytochrome C [M-2H]2-', 6179), - ('Myoglobin [M-2H]2-', 8475), - ('Ubiquitin I [M-H]-', 8564), - ('Cytochrom C [M-H]-', 12359), - ('Myoglobin [M-H]-', 16951), - ], - 'ProtMix II Bruker - MALDI Pos Av':[ - ('Trypsinogen [M+H]+', 23982), - ('Protein A [M+2H]2+', 22306), - ('Albumin Bovine [M+2H]2+', 33216), - ('Protein A [M+H]+', 44613), - ('Albumin Bovine [M+H]+', 66431), - ], - 'ProtMix II Bruker - MALDI Neg Av':[ - ('Trypsinogen [M+H]+', 23980), - ('Protein A [M+2H]2+', 22304), - ('Albumin Bovine [M+2H]2+', 33214), - ('Protein A [M+H]+', 44611), - ('Albumin Bovine [M+H]+', 66429), - ], - 'Trypsin Promega (Porcine) - MALDI Pos Mo':[ + 'Trypsin (Porcine) - MALDI Pos Mo':[ ('Trypsin (108-115) [M+H]+', 842.5094), ('Trypsin (209-216) [M+H]+', 906.5044), ('Trypsin (1-8) [M+H]+', 952.3894), @@ -402,23 +350,6 @@ ('Trypsin (78-97) [M+H]+', 2283.1802), ('Trypsin (179-208) [M+H]+', 3013.3237), ], - 'Trypsin Roche (Bovine) - MALDI Pos Mo':[ - ('Trypsin (112-119) [M+H]+', 805.4163), - ('Trypsin (160-169) [M+H]+', 1020.503), - ('Trypsin (229-237) [M+H]+', 1111.5605), - ('Trypsin (207-220) [M+H]+', 1433.7206), - ('Trypsin (70-89) [M+H]+', 2163.0564), - ('Trypsin (90-109) [M+H]+', 2273.1595), - ], - 'Trypsin Roche (Porcine) - MALDI Pos Mo':[ - ('Trypsin (108-115) [M+H]+', 842.5094), - ('Trypsin (134-147) [M+H]+', 1469.7305), - ('Trypsin (58-74) [M+H]+', 1940.9354), - ('Trypsin (116-133) [M+H]+', 1768.7993), - ('Trypsin (98-107) [M+H]+', 1045.5637), - ('Trypsin (58-77) [M+H]+', 2211.104), - ('Trypsin (148-157) [M+H]+', 1006.4874), - ], 'HCCA Clusters - MALDI Pos Mo':[ ('HCCA [M+H-H2O]+', 172.039304), ('HCCA [M+H]+', 190.049869), @@ -528,79 +459,7 @@ ('DHB [7M+K]+', 1117.149421), ('DHB [7M+K+Na-H2O]+', 1122.128077), ], - 'PEG - MALDI Pos':[ - ('C6H15O4 [M+H]+', 151.096485), - ('C6H14O4 [M+Na]+', 173.078430), - ('C8H19O5 [M+H]+', 195.122700), - ('C8H18O5 [M+Na]+', 217.104645), - ('C10H23O6 [M+H]+', 239.148915), - ('C10H22O6 [M+Na]+', 261.130860), - ('C12H27O7 [M+H]+', 283.175130), - ('C12H26O7 [M+Na]+', 305.157074), - ('C14H31O8 [M+H]+', 327.201344), - ('C14H30O8 [M+Na]+', 349.183289), - ('C16H35O9 [M+H]+', 371.227559), - ('C16H34O9 [M+Na]+', 393.209504), - ('C18H39O10 [M+H]+', 415.253774), - ('C18H38O10 [M+Na]+', 437.235719), - ('C20H43O11 [M+H]+', 459.279989), - ('C20H42O11 [M+Na]+', 481.261933), - ('C22H47O12 [M+H]+', 503.306203), - ('C22H46O12 [M+Na]+', 525.288148), - ('C24H51O13 [M+H]+', 547.332418), - ('C24H50O13 [M+Na]+', 569.314363), - ('C26H55O14 [M+H]+', 591.358633), - ('C26H54O14 [M+Na]+', 613.340578), - ('C28H59O15 [M+H]+', 635.384848), - ('C28H58O15 [M+Na]+', 657.366792), - ('C30H62O16 [M+Na]+', 701.393007), - ('C32H66O17 [M+Na]+', 745.419222), - ('C34H70O18 [M+Na]+', 789.445437), - ('C36H74O19 [M+Na]+', 833.471651), - ('C38H78O20 [M+Na]+', 877.497866), - ('C40H82O21 [M+Na]+', 921.524081), - ('C42H86O22 [M+Na]+', 965.550296), - ('C44H90O23 [M+Na]+', 1009.576510), - ('C46H94O24 [M+Na]+', 1053.602725), - ('C48H98O25 [M+Na]+', 1097.628940), - ('C50H102O26 [M+Na]+', 1141.655155), - ('C52H106O27 [M+Na]+', 1185.681369), - ('C54H110O28 [M+Na]+', 1229.707584), - ('C56H114O29 [M+Na]+', 1273.733799), - ('C58H118O30 [M+Na]+', 1317.760014), - ('C60H122O31 [M+Na]+', 1361.786228), - ('C62H126O32 [M+Na]+', 1405.812443), - ('C64H130O33 [M+Na]+', 1449.838658), - ('C66H134O34 [M+Na]+', 1493.864873), - ('C68H138O35 [M+Na]+', 1537.891087), - ('C70H142O36 [M+Na]+', 1581.917302), - ('C72H146O37 [M+Na]+', 1625.943517), - ('C74H150O38 [M+Na]+', 1669.969732), - ('C76H154O39 [M+Na]+', 1713.995946), - ('C78H158O40 [M+Na]+', 1758.022161), - ('C80H162O41 [M+Na]+', 1802.048376), - ('C82H166O42 [M+Na]+', 1846.074591), - ('C84H170O43 [M+Na]+', 1890.100805), - ('C86H174O44 [M+Na]+', 1934.127020), - ('C88H178O45 [M+Na]+', 1978.153235), - ('C90H182O46 [M+Na]+', 2022.179450), - ('C92H186O47 [M+Na]+', 2066.205664), - ('C94H190O48 [M+Na]+', 2110.231879), - ('C96H194O49 [M+Na]+', 2154.258094), - ('C98H198O50 [M+Na]+', 2198.284309), - ('C100H2O2O51 [M+Na]+', 2242.310523), - ('C104H210O53 [M+Na]+', 2330.362953), - ('C108H218O55 [M+Na]+', 2418.415382), - ('C112H226O57 [M+Na]+', 2506.467812), - ('C116H234O59 [M+Na]+', 2594.520241), - ('C120H242O61 [M+Na]+', 2682.572671), - ('C124H250O63 [M+Na]+', 2770.652100), - ('C128H258O65 [M+Na]+', 2858.677530), - ('C132H266O67 [M+Na]+', 2946.729959), - ('C136H274O69 [M+Na]+', 3034.782389), - ('C140H282O71 [M+Na]+', 3122.834828), - ], - 'Contaminants - Trypsin In-Gel - MALDI Pos Mo':[ + 'In-Gel (Trypsin) - MALDI Pos Mo':[ ('Keratin 10 [M+H]+', 1165.5853), ('Keratin 1/II [M+H]+', 1179.6010), ('Keratin 1/II [M+H]+', 1300.5302), @@ -643,7 +502,7 @@ # LOAD FUNCTIONS # -------------- -def loadPresets(path=os.path.join(config.confdir, 'presets.xml'), clear=False): +def loadPresets(path=os.path.join(config.confdir, 'presets.xml'), clear=True, replace=True): """Parse processing presets XML and get data.""" container = {} @@ -734,14 +593,15 @@ # update current lib for group in container: - if clear: + if container[group] and clear: presets[group].clear() for key in container[group]: - presets[group][key] = container[group][key] + if replace or not key in presets[group]: + presets[group][key] = container[group][key] # ---- -def loadReferences(path=os.path.join(config.confdir, 'references.xml'), clear=False): +def loadReferences(path=os.path.join(config.confdir, 'references.xml'), clear=True): """Parse calibration references XML and get data.""" container = {} @@ -764,14 +624,14 @@ container[groupName].append((name, float(mass))) # update current lib - if clear: + if container and clear: references.clear() for group in container: references[group] = container[group] # ---- -def loadCompounds(path=os.path.join(config.confdir, 'compounds.xml'), clear=False): +def loadCompounds(path=os.path.join(config.confdir, 'compounds.xml'), clear=True): """Parse compounds XML and get data.""" container = {} @@ -798,14 +658,14 @@ pass # update current lib - if clear: + if container and clear: compounds.clear() for group in container: compounds[group] = container[group] # ---- -def loadMascot(path=os.path.join(config.confdir, 'mascot.xml'), clear=False): +def loadMascot(path=os.path.join(config.confdir, 'mascot.xml'), clear=True, replace=True): """Parse mascot servers XML and get data.""" container = {} @@ -829,7 +689,7 @@ _getParams(serverTag, container[name]) # update current lib - if clear: + if container and clear: mascot.clear() for server in container: mascot[server] = container[server] @@ -1003,7 +863,7 @@ for group in sorted(compounds.keys()): buff += ' \n' % (_escape(group)) for name, compound in sorted(compounds[group].items()): - buff += ' %s\n' % (_escape(name), compound.rawFormula, _escape(compound.description)) + buff += ' %s\n' % (_escape(name), compound.expression, _escape(compound.description)) buff += ' \n\n' buff += '' diff -Nru mmass-3.12.1/gui/main_frame.py mmass-4.0.0/gui/main_frame.py --- mmass-3.12.1/gui/main_frame.py 2011-08-28 19:04:07.000000000 +0000 +++ mmass-4.0.0/gui/main_frame.py 2011-11-30 17:49:23.000000000 +0000 @@ -63,11 +63,13 @@ from panel_sequence import panelSequence from panel_spectrum import panelSpectrum, dlgViewRange, dlgSpectrumOffset from panel_spectrum_generator import panelSpectrumGenerator +from panel_envelope_fit import panelEnvelopeFit from dlg_compounds_editor import dlgCompoundsEditor from dlg_enzymes_editor import dlgEnzymesEditor from dlg_mascot_editor import dlgMascotEditor from dlg_modifications_editor import dlgModificationsEditor +from dlg_monomers_editor import dlgMonomersEditor from dlg_presets_editor import dlgPresetsEditor from dlg_references_editor import dlgReferencesEditor @@ -170,6 +172,8 @@ document.Append(ID_documentCloseAll, "Close All"+HK_documentCloseAll, "") document.Append(ID_documentSave, "Save"+HK_documentSave, "") document.Append(ID_documentSaveAs, "Save As..."+HK_documentSaveAs, "") + document.Append(ID_documentSaveAll, "Save All"+HK_documentSaveAll, "") + document.AppendSeparator() document.Append(ID_documentExport, "Export..."+HK_documentExport, "") document.AppendSeparator() document.Append(ID_documentPrintSpectrum, "Print Spectrum..."+HK_documentPrintSpectrum, "") @@ -188,6 +192,7 @@ self.Bind(wx.EVT_MENU, self.onDocumentCloseAll, id=ID_documentCloseAll) self.Bind(wx.EVT_MENU, self.onDocumentSave, id=ID_documentSave) self.Bind(wx.EVT_MENU, self.onDocumentSave, id=ID_documentSaveAs) + self.Bind(wx.EVT_MENU, self.onDocumentSaveAll, id=ID_documentSaveAll) self.Bind(wx.EVT_MENU, self.onDocumentExport, id=ID_documentExport) self.Bind(wx.EVT_MENU, self.onDocumentInfo, id=ID_documentInfo) self.Bind(wx.EVT_MENU, self.onDocumentPrintSpectrum, id=ID_documentPrintSpectrum) @@ -377,12 +382,15 @@ sequence.Append(ID_sequenceFragment, "Fragment Peptide...", "") sequence.Append(ID_sequenceSearch, "Mass Search...", "") sequence.AppendSeparator() + sequence.Append(ID_sequenceSendToMassCalculator, "Show Isotopic Pattern...", "") + sequence.Append(ID_sequenceSendToEnvelopeFit, "Send to Envelope Fit...", "") + sequence.AppendSeparator() sequence.Append(ID_sequenceMatchesCalibrateBy, "Calibrate by Matches...", "") sequence.AppendSeparator() sequence.Append(ID_sequenceMatchesDelete, "Delete All Matches", "") sequence.Append(ID_sequenceDelete, "Delete Sequence", "") sequence.AppendSeparator() - sequence.Append(ID_sequenceSort, "Sort By Titles", "") + sequence.Append(ID_sequenceSort, "Sort by Titles", "") self.Bind(wx.EVT_MENU, self.onSequenceNew, id=ID_sequenceNew) self.Bind(wx.EVT_MENU, self.onSequenceImport, id=ID_sequenceImport) @@ -391,6 +399,8 @@ self.Bind(wx.EVT_MENU, self.onToolsSequence, id=ID_sequenceDigest) self.Bind(wx.EVT_MENU, self.onToolsSequence, id=ID_sequenceFragment) self.Bind(wx.EVT_MENU, self.onToolsSequence, id=ID_sequenceSearch) + self.Bind(wx.EVT_MENU, self.onSequenceSendToMassCalculator, id=ID_sequenceSendToMassCalculator) + self.Bind(wx.EVT_MENU, self.onSequenceSendToEnvelopeFit, id=ID_sequenceSendToEnvelopeFit) self.Bind(wx.EVT_MENU, self.onSequenceMatchesCalibrateBy, id=ID_sequenceMatchesCalibrateBy) self.Bind(wx.EVT_MENU, self.onSequenceMatchesDelete, id=ID_sequenceMatchesDelete) self.Bind(wx.EVT_MENU, self.onSequenceDelete, id=ID_sequenceDelete) @@ -404,16 +414,17 @@ tools.Append(ID_toolsLabelPoint, "Label Point"+HK_toolsLabelPoint, "", wx.ITEM_RADIO) tools.Append(ID_toolsLabelEnvelope, "Label Envelope"+HK_toolsLabelEnvelope, "", wx.ITEM_RADIO) tools.Append(ID_toolsDeleteLabel, "Delete Label"+HK_toolsDeleteLabel, "", wx.ITEM_RADIO) - tools.Append(ID_toolsMeasure, "Measure Distances"+HK_toolsMeasure, "", wx.ITEM_RADIO) + tools.Append(ID_toolsMeasure, "Measure Distance"+HK_toolsMeasure, "", wx.ITEM_RADIO) tools.Append(ID_toolsOffset, "Offset Spectrum", "", wx.ITEM_RADIO) tools.AppendSeparator() tools.Append(ID_toolsPeriodicTable, "Periodic Table"+HK_toolsPeriodicTable, "") - tools.Append(ID_toolsMasscalc, "Mass Calculator"+HK_toolsMasscalc, "") + tools.Append(ID_toolsMassCalculator, "Mass Calculator"+HK_toolsMassCalculator, "") tools.Append(ID_toolsMassFilter, "Mass Filter"+HK_toolsMassFilter, "") tools.Append(ID_toolsCompoundsSearch, "Compounds Search"+HK_toolsCompoundsSearch, "") tools.Append(ID_toolsPeakDifferences, "Peak Differences"+HK_toolsPeakDifferences, "") tools.Append(ID_toolsComparePeaklists, "Compare Peak Lists"+HK_toolsComparePeaklists, "") tools.Append(ID_toolsSpectrumGenerator, "Spectrum Generator"+HK_toolsSpectrumGenerator, "") + tools.Append(ID_toolsEnvelopeFit, "Envelope Fit"+HK_toolsEnvelopeFit, "") tools.AppendSeparator() tools.Append(ID_mascotPMF, "Mascot PMF", "") tools.Append(ID_mascotMIS, "Mascot MS/MS Search", "") @@ -431,12 +442,13 @@ self.Bind(wx.EVT_MENU, self.onToolsSpectrum, id=ID_toolsMeasure) self.Bind(wx.EVT_MENU, self.onToolsSpectrum, id=ID_toolsOffset) self.Bind(wx.EVT_MENU, self.onToolsPeriodicTable, id=ID_toolsPeriodicTable) - self.Bind(wx.EVT_MENU, self.onToolsMassCalculator, id=ID_toolsMasscalc) + self.Bind(wx.EVT_MENU, self.onToolsMassCalculator, id=ID_toolsMassCalculator) self.Bind(wx.EVT_MENU, self.onToolsMassFilter, id=ID_toolsMassFilter) self.Bind(wx.EVT_MENU, self.onToolsCompoundsSearch, id=ID_toolsCompoundsSearch) self.Bind(wx.EVT_MENU, self.onToolsPeakDifferences, id=ID_toolsPeakDifferences) self.Bind(wx.EVT_MENU, self.onToolsComparePeaklists, id=ID_toolsComparePeaklists) self.Bind(wx.EVT_MENU, self.onToolsSpectrumGenerator, id=ID_toolsSpectrumGenerator) + self.Bind(wx.EVT_MENU, self.onToolsEnvelopeFit, id=ID_toolsEnvelopeFit) self.Bind(wx.EVT_MENU, self.onToolsMascot, id=ID_mascotPMF) self.Bind(wx.EVT_MENU, self.onToolsMascot, id=ID_mascotMIS) self.Bind(wx.EVT_MENU, self.onToolsMascot, id=ID_mascotSQ) @@ -450,20 +462,22 @@ # libraries libraries = wx.Menu() + libraries.Append(ID_libraryCompounds, "Compounds...", "") libraries.Append(ID_libraryModifications, "Modifications...", "") + libraries.Append(ID_libraryMonomers, "Monomers...", "") libraries.Append(ID_libraryEnzymes, "Enzymes...", "") - libraries.Append(ID_libraryCompounds, "Compounds...", "") libraries.Append(ID_libraryReferences, "Reference Masses...", "") libraries.Append(ID_libraryMascot, "Mascot Servers...", "") libraries.AppendSeparator() libraries.Append(ID_libraryPresets, "Presets...", "") + self.Bind(wx.EVT_MENU, self.onLibraryEdit, id=ID_libraryCompounds) self.Bind(wx.EVT_MENU, self.onLibraryEdit, id=ID_libraryModifications) + self.Bind(wx.EVT_MENU, self.onLibraryEdit, id=ID_libraryMonomers) self.Bind(wx.EVT_MENU, self.onLibraryEdit, id=ID_libraryEnzymes) - self.Bind(wx.EVT_MENU, self.onLibraryEdit, id=ID_libraryCompounds) self.Bind(wx.EVT_MENU, self.onLibraryEdit, id=ID_libraryReferences) - self.Bind(wx.EVT_MENU, self.onLibraryEdit, id=ID_libraryPresets) self.Bind(wx.EVT_MENU, self.onLibraryEdit, id=ID_libraryMascot) + self.Bind(wx.EVT_MENU, self.onLibraryEdit, id=ID_libraryPresets) self.menubar.Append(libraries, "Libraries") @@ -545,6 +559,8 @@ # help help = wx.Menu() + help.Append(ID_helpUserGuide, "User's Guide...", "") + help.AppendSeparator() help.Append(ID_helpHomepage, "Homepage...", "") help.Append(ID_helpForum, "Support Forum...", "") help.Append(ID_helpTwitter, "Twitter...", "") @@ -557,13 +573,14 @@ help.AppendSeparator() help.Append(ID_helpAbout, "About mMass", "") + self.Bind(wx.EVT_MENU, self.onHelpUserGuide, id=ID_helpUserGuide) self.Bind(wx.EVT_MENU, self.onLibraryLink, id=ID_helpHomepage) self.Bind(wx.EVT_MENU, self.onLibraryLink, id=ID_helpForum) self.Bind(wx.EVT_MENU, self.onLibraryLink, id=ID_helpTwitter) self.Bind(wx.EVT_MENU, self.onLibraryLink, id=ID_helpCite) self.Bind(wx.EVT_MENU, self.onLibraryLink, id=ID_helpDonate) - self.Bind(wx.EVT_MENU, self.onUpdate, id=ID_helpUpdate) - self.Bind(wx.EVT_MENU, self.onAbout, id=ID_helpAbout) + self.Bind(wx.EVT_MENU, self.onHelpUpdate, id=ID_helpUpdate) + self.Bind(wx.EVT_MENU, self.onHelpAbout, id=ID_helpAbout) self.menubar.Append(help, "&Help") # ---- @@ -592,25 +609,33 @@ # tools self.toolbar.AddLabelTool(ID_toolsProcessing, "Processing", images.lib['toolsProcessing'], shortHelp="Data processing...", longHelp="Mass spectrum processing") self.toolbar.AddLabelTool(ID_toolsCalibration, "Calibration", images.lib['toolsCalibration'], shortHelp="Re-calibrate data...", longHelp="Mass spectrum calibration") + + self.toolbar.AddSeparator() + self.toolbar.AddLabelTool(ID_toolsSequence, "Sequence", images.lib['toolsSequence'], shortHelp="Sequence editor...", longHelp="Sequence editor and tool") - self.toolbar.AddLabelTool(ID_toolsMasscalc, "Masscalc", images.lib['toolsMassCalculator'], shortHelp="Mass calculator...", longHelp="Calculate ion series and isotopic pattern") + self.toolbar.AddLabelTool(ID_toolsMassCalculator, "Masscalc", images.lib['toolsMassCalculator'], shortHelp="Mass calculator...", longHelp="Calculate ion series and isotopic pattern") self.toolbar.AddLabelTool(ID_toolsMassFilter, "Mass Filter", images.lib['toolsMassFilter'], shortHelp="Mass filter...", longHelp="Filter spectrum contaminants") self.toolbar.AddLabelTool(ID_toolsCompoundsSearch, "Compounds", images.lib['toolsCompoundsSearch'], shortHelp="Compounds search...", longHelp="Search for compounds") self.toolbar.AddLabelTool(ID_toolsPeakDifferences, "Differences", images.lib['toolsPeakDifferences'], shortHelp="Peak differences...", longHelp="Calculate peak differences") self.toolbar.AddLabelTool(ID_toolsComparePeaklists, "Compare", images.lib['toolsComparePeaklists'], shortHelp="Compare peak lists...", longHelp="Compare multiple peaklists") self.toolbar.AddLabelTool(ID_toolsSpectrumGenerator, "Generator", images.lib['toolsSpectrumGenerator'], shortHelp="Generate mass spectrum...", longHelp="Generate mass spectrum from current peak list") + self.toolbar.AddLabelTool(ID_toolsEnvelopeFit, "Envelope Fit", images.lib['toolsEnvelopeFit'], shortHelp="Calculate atom exchange...", longHelp="Calculate atom exchange from peak envelope") + + self.toolbar.AddSeparator() + self.toolbar.AddLabelTool(ID_toolsMascot, "Mascot", images.lib['toolsMascot'], shortHelp="Mascot search...", longHelp="Send data to Mascot server") self.toolbar.AddLabelTool(ID_toolsProfound, "ProFound", images.lib['toolsProfound'], shortHelp="ProFound search...", longHelp="Send data to ProFound server") self.toolbar.Bind(wx.EVT_TOOL, self.onToolsProcessing, id=ID_toolsProcessing) self.toolbar.Bind(wx.EVT_TOOL, self.onToolsCalibration, id=ID_toolsCalibration) self.toolbar.Bind(wx.EVT_TOOL, self.onToolsSequence, id=ID_toolsSequence) - self.toolbar.Bind(wx.EVT_TOOL, self.onToolsMassCalculator, id=ID_toolsMasscalc) + self.toolbar.Bind(wx.EVT_TOOL, self.onToolsMassCalculator, id=ID_toolsMassCalculator) self.toolbar.Bind(wx.EVT_TOOL, self.onToolsMassFilter, id=ID_toolsMassFilter) self.toolbar.Bind(wx.EVT_TOOL, self.onToolsCompoundsSearch, id=ID_toolsCompoundsSearch) self.toolbar.Bind(wx.EVT_TOOL, self.onToolsPeakDifferences, id=ID_toolsPeakDifferences) self.toolbar.Bind(wx.EVT_TOOL, self.onToolsComparePeaklists, id=ID_toolsComparePeaklists) self.toolbar.Bind(wx.EVT_TOOL, self.onToolsSpectrumGenerator, id=ID_toolsSpectrumGenerator) + self.toolbar.Bind(wx.EVT_TOOL, self.onToolsEnvelopeFit, id=ID_toolsEnvelopeFit) self.toolbar.Bind(wx.EVT_TOOL, self.onToolsMascot, id=ID_toolsMascot) self.toolbar.Bind(wx.EVT_TOOL, self.onToolsProfound, id=ID_toolsProfound) @@ -625,11 +650,11 @@ self.toolbar.Bind(wx.EVT_TOOL, self.onDocumentExport, id=ID_toolsDocumentExport) # search - if wx.Platform == '__WXMAC__': - self.toolbar.AddSeparator() - self.search = wx.SearchCtrl(self.toolbar, -1, size=(150, -1), style=wx.TE_PROCESS_ENTER, validator=mwx.validator('floatPos')) - self.search.Bind(wx.EVT_TEXT, self.onToolsSearch) - self.toolbar.AddControl(self.search) + # if wx.Platform == '__WXMAC__': + # self.toolbar.AddSeparator() + # self.search = wx.SearchCtrl(self.toolbar, -1, size=(150, -1), style=wx.TE_PROCESS_ENTER, validator=mwx.validator('floatPos')) + # self.search.Bind(wx.EVT_TEXT, self.onToolsSearch) + # self.toolbar.AddControl(self.search) # ---- @@ -655,6 +680,7 @@ self.peakDifferencesPanel = None self.comparePeaklistsPanel = None self.spectrumGeneratorPanel = None + self.envelopeFitPanel = None self.sequencePanel = None self.mascotPanel = None self.profoundPanel = None @@ -753,57 +779,6 @@ # ---- - def onAbout(self, evt): - """Show About mMass panel.""" - - about = panelAbout(self) - about.Centre() - about.Show() - about.SetFocus() - # ---- - - - def onUpdate(self, evt=None): - """Check for available updates.""" - - # check for available updates - if not self.getAvailableUpdates(): - wx.Bell() - title = 'Update Error!' - message = 'An error occured in retrieving update information.\nPlease try again later.' - buttons = [(wx.ID_CANCEL, "Cancel Update", -1, True, 0)] - dlg = mwx.dlgMessage(self, title, message, buttons) - dlg.ShowModal() - dlg.Destroy() - return - - # newer version is available - if config.main['updatesAvailable'] != config.version or config.nightbuild: - if config.nightbuild: - title = 'Different stable version of mMass is available.' - message = "Version %s is the latest stable version available for download.\nYou are currently using test version %s (%s)." % (config.main['updatesAvailable'], config.version, config.nightbuild) - else: - title = 'A newer version of mMass is available from mMass.org' - message = "Version %s is now available for download.\nYou are currently using version %s." % (config.main['updatesAvailable'], config.version) - buttons = [(wx.ID_CANCEL, "Ask Again Later", -1, False, 15), (wx.ID_OK, "Upgrade Now", -1, True, 0)] - dlg = mwx.dlgMessage(self, title, message, buttons) - if dlg.ShowModal() == wx.ID_OK: - dlg.Destroy() - try: webbrowser.open(config.links['mMassDownload'], autoraise=1) - except: pass - else: - dlg.Destroy() - - # you are up to date - else: - title = "You're up to date!" - message = "mMass %s is currently the newest version available." % config.version - dlg = mwx.dlgMessage(self, title, message) - dlg.ShowModal() - dlg.Destroy() - # ---- - - def onPreferences(self, evt): """Show mMass preferences.""" @@ -890,6 +865,10 @@ if self.spectrumGeneratorPanel: self.spectrumGeneratorPanel.setData(docData) + # update envelope fit panel + if self.envelopeFitPanel: + self.envelopeFitPanel.setData(docData) + # update sequence panel if self.sequencePanel: self.sequencePanel.setData(None) @@ -959,29 +938,35 @@ # update data-dependent panels if 'spectrum' in items: + docData = self.documents[self.currentDocument] + # update document info panel if self.documentInfoPanel: - self.documentInfoPanel.setData(self.documents[self.currentDocument]) + self.documentInfoPanel.setData(docData) # update mascot panel if self.mascotPanel: - self.mascotPanel.setData(self.documents[self.currentDocument]) + self.mascotPanel.setData(docData) # update profound panel if self.profoundPanel: - self.profoundPanel.setData(self.documents[self.currentDocument]) + self.profoundPanel.setData(docData) # update prospector panel if self.prospectorPanel: - self.prospectorPanel.setData(self.documents[self.currentDocument]) + self.prospectorPanel.setData(docData) # update differences panel if self.peakDifferencesPanel: - self.peakDifferencesPanel.setData(self.documents[self.currentDocument]) + self.peakDifferencesPanel.setData(docData) # update spectrum generator panel if self.spectrumGeneratorPanel: - self.spectrumGeneratorPanel.setData(self.documents[self.currentDocument]) + self.spectrumGeneratorPanel.setData(docData) + + # update envelope fit panel + if self.envelopeFitPanel: + self.envelopeFitPanel.setData(docData) # update sequence panel if self.sequencePanel: @@ -1204,7 +1189,6 @@ self.documentsPanel.deleteDocument(docIndex) self.spectrumPanel.deleteSpectrum(docIndex) del self.documents[docIndex] - self.currentDocument = None # select previous visible document if selectPrevious: @@ -1252,6 +1236,8 @@ self.comparePeaklistsPanel.Close() if self.spectrumGeneratorPanel: self.spectrumGeneratorPanel.Close() + if self.envelopeFitPanel: + self.envelopeFitPanel.Close() if self.sequencePanel: self.sequencePanel.Close() if self.mascotPanel: @@ -1296,20 +1282,30 @@ # ---- - def onDocumentSave(self, evt=None): + def onDocumentSave(self, evt=None, docIndex=None): """Save current document.""" # check document - if self.currentDocument == None: + if docIndex == None: + docIndex = self.currentDocument + if docIndex == None: wx.Bell() return False # get document - document = self.documents[self.currentDocument] + document = self.documents[docIndex] path = document.path # check doctype and ask to save if not path or document.format != 'mSD' or (evt and evt.GetId()==ID_documentSaveAs): + + # ensure document is selected + if docIndex != self.currentDocument: + if not self.documents[docIndex].visible: + self.onDocumentEnable(docIndex) + self.documentsPanel.selectDocument(docIndex) + + # ask for name fileName = document.title+'.msd' dlg = wx.FileDialog(self, "Save", config.main['lastDir'], fileName, "mMass Spectrum Document|*.msd", wx.SAVE|wx.OVERWRITE_PROMPT) if dlg.ShowModal() == wx.ID_OK: @@ -1325,7 +1321,7 @@ gauge.show() # get document XML - process = threading.Thread(target=self.runDocumentSave) + process = threading.Thread(target=self.runDocumentSave, kwargs={'docIndex':docIndex}) process.start() while process.isAlive(): gauge.pulse() @@ -1350,6 +1346,14 @@ # processing failed if failed: wx.Bell() + + # ensure document is selected + if docIndex != self.currentDocument: + if not self.documents[docIndex].visible: + self.onDocumentEnable(docIndex) + self.documentsPanel.selectDocument(docIndex) + + # show error message dlg = mwx.dlgMessage(self, title="Unable to save the document.", message='Please ensure that you have sufficient permissions\nto write into the document folder.') dlg.ShowModal() dlg.Destroy() @@ -1360,22 +1364,33 @@ document.path = path document.dirty = False - # update document and app title - self.documentsPanel.updateDocumentTitle(self.currentDocument) - title = 'mMass - %s' % (self.documents[self.currentDocument].title) - self.SetTitle(title) + # update document title + self.documentsPanel.updateDocumentTitle(docIndex) + + # update app title + if docIndex == self.currentDocument: + title = 'mMass - %s' % (self.documents[docIndex].title) + self.SetTitle(title) + self.updateControls() # update recent files self.updateRecentFiles(path) - # update menubar and toolbar - self.updateControls() - # document saved return True # ---- + def onDocumentSaveAll(self, evt=None): + """Save all documents.""" + + # save documents + for docIndex, document in enumerate(self.documents): + if document.dirty: + self.onDocumentSave(docIndex=docIndex) + # ---- + + def onDocumentPrintSpectrum(self, evt): """Print spectrum.""" @@ -1826,7 +1841,7 @@ self.spectrumPanel.updateCanvasProperties(ID) self.spectrumPanel.spectrumCanvas.SetFocus() - # update spectrum generator + # update spectrum generator panel if self.spectrumGeneratorPanel: self.spectrumGeneratorPanel.updateCanvasProperties() # ---- @@ -2175,14 +2190,14 @@ intensity = 2*baseline # set data - self.massCalculatorPanel.setData( \ - formula=formula, \ - charge=charge, \ - agentFormula=agentFormula, \ - agentCharge=agentCharge, \ - fwhm=fwhm, \ - intensity=intensity, \ - baseline=baseline \ + self.massCalculatorPanel.setData( + formula = formula, + charge = charge, + agentFormula = agentFormula, + agentCharge = agentCharge, + fwhm = fwhm, + intensity = intensity, + baseline = baseline ) # raise panel @@ -2331,6 +2346,49 @@ # ---- + def onToolsEnvelopeFit(self, evt=None, formula=None, sequence=None, charge=None, scale=None): + """Show envelope fit panel.""" + + # check document + if not self.envelopeFitPanel and self.currentDocument == None: + wx.Bell() + return + + # destroy panel + if self.envelopeFitPanel and evt: + self.envelopeFitPanel.Close() + return + + # init panel + if not self.envelopeFitPanel: + self.envelopeFitPanel = panelEnvelopeFit(self) + self.envelopeFitPanel.Centre() + self.envelopeFitPanel.Show(True) + + # get current document + docData = None + if self.currentDocument != None: + docData = self.documents[self.currentDocument] + + # get data from sequence + if sequence != None: + formula = sequence.formula() + if scale == None and config.envfit['loss'] == 'H' and config.envfit['gain'] == 'H{2}': + scale = (0, len(sequence) - sequence.count('P') - 1) + + # set current data + self.envelopeFitPanel.setData( + document = docData, + formula = formula, + charge = charge, + scale = scale + ) + + # raise panel + self.envelopeFitPanel.Raise() + # ---- + + def onToolsMascot(self, evt=None): """Show Mascot search panel.""" @@ -2521,8 +2579,8 @@ if self.sequencePanel: self.sequencePanel.setData(seqData) - # update menubar and toolbar - self.updateControls() + # update menubar and toolbar + self.updateControls() # ---- @@ -2694,6 +2752,39 @@ # ---- + def onSequenceSendToMassCalculator(self, evt): + """Show isotopic pattern of current sequence.""" + + # check selection + if self.currentDocument == None or self.currentSequence == None: + wx.Bell() + return + + # get data + seqData = self.documents[self.currentDocument].sequences[self.currentSequence] + formula = seqData.formula() + + # send data to Mass Calculator + self.onToolsMassCalculator(formula=formula) + # ---- + + + def onSequenceSendToEnvelopeFit(self, evt): + """Send current sequence to envelope fit tool.""" + + # check selection + if self.currentDocument == None or self.currentSequence == None: + wx.Bell() + return + + # get data + seqData = self.documents[self.currentDocument].sequences[self.currentSequence] + + # send data to envelope fit + self.onToolsEnvelopeFit(sequence=seqData) + # ---- + + # LIBRARIES @@ -2701,35 +2792,39 @@ """Edit library.""" # set library to edit - if evt.GetId() == ID_libraryModifications: + if evt.GetId() == ID_libraryCompounds: + library = 'compounds' + dlg = dlgCompoundsEditor(self) + + elif evt.GetId() == ID_libraryModifications: library = 'modifications' dlg = dlgModificationsEditor(self) + elif evt.GetId() == ID_libraryMonomers: + library = 'monomers' + dlg = dlgMonomersEditor(self) + elif evt.GetId() == ID_libraryEnzymes: library = 'enzymes' dlg = dlgEnzymesEditor(self) - elif evt.GetId() == ID_libraryCompounds: - library = 'compounds' - dlg = dlgCompoundsEditor(self) - elif evt.GetId() == ID_libraryReferences: library = 'references' dlg = dlgReferencesEditor(self) - elif evt.GetId() == ID_libraryPresets: - library = 'presets' - dlg = dlgPresetsEditor(self) - elif evt.GetId() == ID_libraryMascot: library = 'mascot' dlg = dlgMascotEditor(self) + elif evt.GetId() == ID_libraryPresets: + library = 'presets' + dlg = dlgPresetsEditor(self) + # close related panels - if library in ('modifications', 'enzymes') and self.sequencePanel: - self.sequencePanel.Close() - elif library == 'compounds' and self.compoundsSearchPanel: + if library == 'compounds' and self.compoundsSearchPanel: self.compoundsSearchPanel.Close() + elif library in ('modifications', 'monomers', 'enzymes') and self.sequencePanel: + self.sequencePanel.Close() elif library == 'references': if self.calibrationPanel: self.calibrationPanel.Close() @@ -2854,6 +2949,99 @@ + # HELP + + def onHelpUserGuide(self, evt): + """Open User's Guide PDF.""" + + # get path + if sys.platform == 'darwin': + path = '' + else: + path = os.path.sep + for folder in os.path.dirname(os.path.realpath(__file__)).split(os.path.sep)[:-1]: + tmp = os.path.join(path, folder) + if os.path.isdir(tmp): + path = tmp + + path = os.path.join(path, "User Guide.pdf") + + # check path + if not os.path.exists(path): + wx.Bell() + dlg = mwx.dlgMessage(self, title="User's Guide PDF doesn't exists.", message="Please go to the mMass website, download the User's Guide PDF\nand move it into your mMass application folder.") + dlg.ShowModal() + dlg.Destroy() + return + + # try to open pdf + try: + if wx.Platform == '__WXMSW__': + os.startfile(path) + else: + try: subprocess.Popen(['xdg-open', path]) + except: subprocess.Popen(['open', path]) + except: + wx.Bell() + dlg = mwx.dlgMessage(self, title="Unable to open User's Guide.", message="Please make sure that you have any application associated\nwith a PDF format.") + dlg.ShowModal() + dlg.Destroy() + return + # ---- + + + def onHelpUpdate(self, evt=None): + """Check for available updates.""" + + # check for available updates + if not self.getAvailableUpdates(): + wx.Bell() + title = 'Update Error!' + message = 'An error occured in retrieving update information.\nPlease try again later.' + buttons = [(wx.ID_CANCEL, "Cancel Update", -1, True, 0)] + dlg = mwx.dlgMessage(self, title, message, buttons) + dlg.ShowModal() + dlg.Destroy() + return + + # newer version is available + if config.main['updatesAvailable'] != config.version or config.nightbuild: + if config.nightbuild: + title = 'Different stable version of mMass is available.' + message = "Version %s is the latest stable version available for download.\nYou are currently using test version %s (%s)." % (config.main['updatesAvailable'], config.version, config.nightbuild) + else: + title = 'A newer version of mMass is available from mMass.org' + message = "Version %s is now available for download.\nYou are currently using version %s." % (config.main['updatesAvailable'], config.version) + buttons = [(wx.ID_CANCEL, "Ask Again Later", -1, False, 15), (wx.ID_OK, "Upgrade Now", -1, True, 0)] + dlg = mwx.dlgMessage(self, title, message, buttons) + if dlg.ShowModal() == wx.ID_OK: + dlg.Destroy() + try: webbrowser.open(config.links['mMassDownload'], autoraise=1) + except: pass + else: + dlg.Destroy() + + # you are up to date + else: + title = "You're up to date!" + message = "mMass %s is currently the newest version available." % config.version + dlg = mwx.dlgMessage(self, title, message) + dlg.ShowModal() + dlg.Destroy() + # ---- + + + def onHelpAbout(self, evt): + """Show About mMass panel.""" + + about = panelAbout(self) + about.Centre() + about.Show() + about.SetFocus() + # ---- + + + # DOCUMENT IMPORT def importDocumentQueue(self): @@ -3184,12 +3372,11 @@ # ---- - def runDocumentSave(self): + def runDocumentSave(self, docIndex): """Save current document.""" - # get XML data for current document - document = self.documents[self.currentDocument] - self.currentDocumentXML = document.msd() + # get XML data for selected document + self.currentDocumentXML = self.documents[docIndex].msd() # ---- @@ -3199,18 +3386,20 @@ self.tmpLibrarySaved = False # set process - if library == 'modifications': + if library == 'compounds': + self.tmpLibrarySaved = libs.saveCompounds() + elif library == 'modifications': self.tmpLibrarySaved = mspy.saveModifications(os.path.join(config.confdir,'modifications.xml')) + elif library == 'monomers': + self.tmpLibrarySaved = mspy.saveMonomers(os.path.join(config.confdir,'monomers.xml')) elif library == 'enzymes': self.tmpLibrarySaved = mspy.saveEnzymes(os.path.join(config.confdir,'enzymes.xml')) - elif library == 'compounds': - self.tmpLibrarySaved = libs.saveCompounds() elif library == 'references': self.tmpLibrarySaved = libs.saveReferences() - elif library == 'presets': - self.tmpLibrarySaved = libs.savePresets() elif library == 'mascot': self.tmpLibrarySaved = libs.saveMascot() + elif library == 'presets': + self.tmpLibrarySaved = libs.savePresets() # ---- @@ -3428,7 +3617,7 @@ points += [[a.mz, a.ai, a.label] for a in document.annotations] # get sequence matches - elif selected in ('sequence', 'match'): + elif selected in ('sequence', 'match') and self.currentSequence != None: sequence = self.documents[self.currentDocument].sequences[self.currentSequence] points += [[m.mz, m.ai, m.label] for m in sequence.matches] @@ -3466,6 +3655,7 @@ self.menubar.Enable(ID_documentCloseAll, bool(self.documents)) self.menubar.Enable(ID_documentSave, enable) self.menubar.Enable(ID_documentSaveAs, enable) + self.menubar.Enable(ID_documentSaveAll, bool(self.documents)) self.menubar.Enable(ID_documentExport, bool(self.documents)) self.menubar.Enable(ID_documentReport, enable) self.menubar.Enable(ID_documentInfo, enable) @@ -3490,6 +3680,8 @@ self.menubar.Enable(ID_toolsPeakDifferences, enable) self.menubar.Enable(ID_toolsComparePeaklists, bool(self.documents)) self.menubar.Enable(ID_toolsSpectrumGenerator, enable) + self.menubar.Enable(ID_toolsEnvelopeFit, enable) + self.menubar.Enable(ID_toolsEnvelopeFit, enable) self.menubar.Enable(ID_mascotPMF, enable) self.menubar.Enable(ID_mascotSQ, enable) self.menubar.Enable(ID_mascotMIS, enable) @@ -3508,6 +3700,7 @@ self.toolbar.EnableTool(ID_toolsPeakDifferences, enable) self.toolbar.EnableTool(ID_toolsComparePeaklists, bool(self.documents)) self.toolbar.EnableTool(ID_toolsSpectrumGenerator, enable) + self.toolbar.EnableTool(ID_toolsEnvelopeFit, enable) self.toolbar.EnableTool(ID_toolsMascot, enable) self.toolbar.EnableTool(ID_toolsProfound, enable) self.toolbar.EnableTool(ID_toolsDocumentExport, bool(self.documents)) @@ -3528,6 +3721,8 @@ self.menubar.Enable(ID_sequenceDigest, enable) self.menubar.Enable(ID_sequenceFragment, enable) self.menubar.Enable(ID_sequenceSearch, enable) + self.menubar.Enable(ID_sequenceSendToMassCalculator, enable) + self.menubar.Enable(ID_sequenceSendToEnvelopeFit, enable) self.menubar.Enable(ID_sequenceMatchesCalibrateBy, bool(enable and sequence.matches)) self.menubar.Enable(ID_sequenceMatchesDelete, bool(enable and sequence.matches)) self.menubar.Enable(ID_sequenceDelete, enable) @@ -3680,6 +3875,20 @@ # ---- + def getUsedMonomers(self): + """Search all sequences for used monomers.""" + + # get monomers + monomers = [] + for document in self.documents: + for sequence in document.sequences: + for monomer in sequence: + monomers.append(monomer) + + return monomers + # ---- + + def getUsedModifications(self): """Search all sequences for used modifications.""" diff -Nru mmass-3.12.1/gui/mwx.py mmass-4.0.0/gui/mwx.py --- mmass-3.12.1/gui/mwx.py 2011-07-01 13:59:39.000000000 +0000 +++ mmass-4.0.0/gui/mwx.py 2011-11-11 14:32:55.000000000 +0000 @@ -24,6 +24,7 @@ from ids import * import images import config +import mspy # GUI CONSTANTS @@ -49,6 +50,7 @@ TOOLBAR_RSPACE = 10 TOOLBAR_TOOLSIZE = (-1,-1) CONTROLBAR_HEIGHT = 32 +CONTROLBAR_DOUBLE_HEIGHT = 61 CONTROLBAR_LSPACE = 10 CONTROLBAR_RSPACE = 10 BOTTOMBAR_HEIGHT = 22 @@ -58,6 +60,7 @@ SMALL_COMBO_HEIGHT = -1 SMALL_BUTTON_HEIGHT = 22 SMALL_TEXTCTRL_HEIGHT = -1 +SMALL_SEARCH_HEIGHT = -1 BUTTON_SIZE_CORRECTION = 0 COMBO_HEIGHT = -1 @@ -98,21 +101,21 @@ GAUGE_HEIGHT = 11 GAUGE_SPACE = 15 - MAIN_TOOLBAR_TOOLSIZE = (30,22) + MAIN_TOOLBAR_TOOLSIZE = (30,23) MAIN_TOOLBAR_STYLE = wx.TB_FLAT|wx.TB_NODIVIDER|wx.TB_HORIZONTAL|wx.TB_TEXT TOOLBAR_HEIGHT = 38 TOOLBAR_LSPACE = 15 TOOLBAR_RSPACE = 15 - CONTROLBAR_HEIGHT = 32 CONTROLBAR_LSPACE = 15 CONTROLBAR_RSPACE = 15 - BOTTOMBAR_HEIGHT = 32 + BOTTOMBAR_HEIGHT = 33 BOTTOMBAR_LSPACE = 10 BOTTOMBAR_RSPACE = 10 SMALL_COMBO_HEIGHT = 22 SMALL_BUTTON_HEIGHT = -1 SMALL_TEXTCTRL_HEIGHT = 18 + SMALL_SEARCH_HEIGHT = 22 BUTTON_SIZE_CORRECTION = -3 COMBO_HEIGHT = 22 @@ -147,6 +150,7 @@ elif wx.Platform == '__WXMSW__': SMALL_COMBO_HEIGHT = 22 SMALL_BUTTON_HEIGHT = 22 + SMALL_SEARCH_HEIGHT = 22 DASHED_LINE = wx.DOT @@ -155,7 +159,6 @@ SMALL_FONT_SIZE = 10 NORMAL_FONT_SIZE = 11 SASH_SIZE = 6 - SASH_COLOUR = (237,236,235) TOOLBAR_TOOLSIZE = (32,26) BOTTOMBAR_HEIGHT = 28 @@ -163,6 +166,7 @@ SMALL_COMBO_HEIGHT = 25 SMALL_BUTTON_HEIGHT = 25 SMALL_TEXTCTRL_HEIGHT = 25 + SMALL_SEARCH_HEIGHT = 25 DOCTREE_BULLETSIZE = 4 DOCTREE_STYLE = wx.TR_DEFAULT_STYLE|wx.TR_HAS_BUTTONS|wx.TR_HIDE_ROOT|wx.SUNKEN_BORDER @@ -214,7 +218,7 @@ # create paint surface dc = wx.PaintDC(self) - dc.Clear() + #dc.Clear() # tile/wallpaper the image across the canvas for x in range(0, self.GetSize()[0], self.image.GetWidth()): @@ -633,6 +637,37 @@ +class formulaCtrl(wx.TextCtrl): + """TextCtrl to molecular formulae.""" + + def __init__(self, parent, id=-1, value="", pos=wx.DefaultPosition, size=wx.DefaultSize, style=0, validator=wx.DefaultValidator): + wx.TextCtrl.__init__(self, parent, id, value, pos, size, style, validator) + self.Bind(wx.EVT_TEXT, self._onText) + # ---- + + + def _onText(self, evt): + """Check current formula.""" + evt.Skip() + wx.CallAfter(self._checkFormula) + # ---- + + + def _checkFormula(self): + """Check current formula.""" + + try: + formula = mspy.compound(self.GetValue()) + self.SetBackgroundColour(wx.NullColour) + except: + self.SetBackgroundColour((250,100,100)) + + self.Refresh() + # ---- + + + + class gauge(wx.Gauge): """Gauge.""" diff -Nru mmass-3.12.1/gui/panel_calibration.py mmass-4.0.0/gui/panel_calibration.py --- mmass-3.12.1/gui/panel_calibration.py 2011-06-29 11:31:31.000000000 +0000 +++ mmass-4.0.0/gui/panel_calibration.py 2011-11-25 13:43:21.000000000 +0000 @@ -267,6 +267,7 @@ self.errorCanvas.setProperties(autoScaleY=False) self.errorCanvas.setProperties(xPosDigits=config.main['mzDigits']) self.errorCanvas.setProperties(yPosDigits=2) + self.errorCanvas.setProperties(reverseScrolling=config.main['reverseScrolling']) self.errorCanvas.setProperties(reverseDrawing=True) self.errorCanvas.setMFunction('cross') diff -Nru mmass-3.12.1/gui/panel_compounds_search.py mmass-4.0.0/gui/panel_compounds_search.py --- mmass-3.12.1/gui/panel_compounds_search.py 2011-06-28 13:29:30.000000000 +0000 +++ mmass-4.0.0/gui/panel_compounds_search.py 2011-11-10 14:28:18.000000000 +0000 @@ -406,20 +406,55 @@ def onItemActivated(self, evt): """Show isotopic pattern for selected compound.""" + self.onItemSendToMassCalculator(evt) + # ---- + + + def onItemSendToMassCalculator(self, evt): + """Show isotopic pattern for selected compound.""" - # get formula and charge - item = self.currentCompounds[evt.GetData()] - formula = item[4] - charge = item[2] + # get data + selected = self.compoundsList.getSelected() + if selected: + index = self.compoundsList.GetItemData(selected[0]) + formula = self.currentCompounds[index][4] + charge = self.currentCompounds[index][2] + radical = self.currentCompounds[index][3] + else: + wx.Bell() + return - # send to masscalc - if item[3] == 'radical': + # send data to masscalc + if radical == 'radical': self.parent.onToolsMassCalculator(formula=formula, charge=charge, agentFormula='e', agentCharge=-1) else: self.parent.onToolsMassCalculator(formula=formula, charge=charge, agentFormula='H', agentCharge=1) # ---- + def onItemCopyFormula(self, evt): + """Copy selected compound formula into clipboard.""" + + # get data + selected = self.compoundsList.getSelected() + if selected: + index = self.compoundsList.GetItemData(selected[0]) + formula = self.currentCompounds[index][4] + else: + wx.Bell() + return + + # make text object for data + obj = wx.TextDataObject() + obj.SetText(formula) + + # paste to clipboard + if wx.TheClipboard.Open(): + wx.TheClipboard.SetData(obj) + wx.TheClipboard.Close() + # ---- + + def onListKey(self, evt): """Export list if Ctrl+C.""" @@ -445,7 +480,10 @@ menu.Append(ID_listViewMatched, "Show Matched Only", "", wx.ITEM_RADIO) menu.Append(ID_listViewUnmatched, "Show Unmatched Only", "", wx.ITEM_RADIO) menu.AppendSeparator() - menu.Append(ID_listCopy, "Copy All") + menu.Append(ID_listSendToMassCalculator, "Show Isotopic Pattern", "") + menu.AppendSeparator() + menu.Append(ID_listCopyFormula, "Copy Formula") + menu.Append(ID_listCopy, "Copy List") # check item if self._compoundsFilter == 1: @@ -459,6 +497,8 @@ self.Bind(wx.EVT_MENU, self.onListFilter, id=ID_listViewAll) self.Bind(wx.EVT_MENU, self.onListFilter, id=ID_listViewMatched) self.Bind(wx.EVT_MENU, self.onListFilter, id=ID_listViewUnmatched) + self.Bind(wx.EVT_MENU, self.onItemSendToMassCalculator, id=ID_listSendToMassCalculator) + self.Bind(wx.EVT_MENU, self.onItemCopyFormula, id=ID_listCopyFormula) self.Bind(wx.EVT_MENU, self.onListCopy, id=ID_listCopy) # show menu @@ -787,12 +827,12 @@ # main ion mz = compound.mz(z*polarity)[config.compounds['massType']] - self.currentCompounds.append([name, mz, z*polarity, None, compound.rawFormula, None, []]) + self.currentCompounds.append([name, mz, z*polarity, None, compound.expression, None, []]) # radicals if config.compounds['radicals']: mz = compound.mz(z*polarity, agentFormula='e', agentCharge=-1)[config.compounds['massType']] - self.currentCompounds.append([name, mz, z*polarity, 'radical', compound.rawFormula, None, []]) + self.currentCompounds.append([name, mz, z*polarity, 'radical', compound.expression, None, []]) mspy.CHECK_FORCE_QUIT() @@ -800,14 +840,14 @@ for item in config.compounds['adducts']: if item in ('Na', 'K', 'Li', 'NH4', 'ACN', 'MeOH'): - formula = '%s(%s)(H-1)' % (compound.rawFormula, adducts[item]) + formula = '%s(%s)(H-1)' % (compound.expression, adducts[item]) elif item in ('-H2O'): - formula = '%s(%s)' % (compound.rawFormula, adducts[item]) + formula = '%s(%s)' % (compound.expression, adducts[item]) formula = mspy.compound(formula) if formula.isvalid(): mz = formula.mz(z*polarity)[config.compounds['massType']] - self.currentCompounds.append([name, mz, z*polarity, item, formula.rawFormula, None, []]) + self.currentCompounds.append([name, mz, z*polarity, item, formula.expression, None, []]) mspy.CHECK_FORCE_QUIT() @@ -819,15 +859,15 @@ if item2 in ('ACN', 'MeOH'): adduct = '%s+%s' % (item1, item2) - formula = '%s(%s)(%s)(H-2)' % (compound.rawFormula, adducts[item1], adducts[item2]) + formula = '%s(%s)(%s)(H-2)' % (compound.expression, adducts[item1], adducts[item2]) elif item2 in ('-H2O'): adduct = '%s%s' % (item1, item2) - formula = '%s(%s)(%s)(H-1)' % (compound.rawFormula, adducts[item1], adducts[item2]) + formula = '%s(%s)(%s)(H-1)' % (compound.expression, adducts[item1], adducts[item2]) formula = mspy.compound(formula) if formula.isvalid(): mz = formula.mz(z*polarity)[config.compounds['massType']] - self.currentCompounds.append([name, mz, z*polarity, adduct, formula.rawFormula, None, []]) + self.currentCompounds.append([name, mz, z*polarity, adduct, formula.expression, None, []]) # task canceled except mspy.ForceQuit: diff -Nru mmass-3.12.1/gui/panel_document_export.py mmass-4.0.0/gui/panel_document_export.py --- mmass-3.12.1/gui/panel_document_export.py 2011-06-14 15:51:38.000000000 +0000 +++ mmass-4.0.0/gui/panel_document_export.py 2011-09-02 12:19:00.000000000 +0000 @@ -746,7 +746,7 @@ if 'int' in config.export['peaklistColumns']: line += str(peak.intensity) + separator if 'rel' in config.export['peaklistColumns']: - line += str(peak.relIntensity*100) + separator + line += str(peak.ri*100) + separator if 'sn' in config.export['peaklistColumns']: line += str(peak.sn) + separator if 'z' in config.export['peaklistColumns']: diff -Nru mmass-3.12.1/gui/panel_document_info.py mmass-4.0.0/gui/panel_document_info.py --- mmass-3.12.1/gui/panel_document_info.py 2011-06-13 10:02:50.000000000 +0000 +++ mmass-4.0.0/gui/panel_document_info.py 2011-09-02 12:51:04.000000000 +0000 @@ -151,6 +151,9 @@ self.date_value = wx.TextCtrl(panel, -1, "", size=(300, -1)) self.date_value.Bind(wx.EVT_TEXT, self.onSave) + path_label = wx.StaticText(panel, -1, "Path:") + self.path_value = wx.TextCtrl(panel, -1, "", size=(300, -1)) + # pack elements grid = wx.GridBagSizer(mwx.GRIDBAG_VSPACE, mwx.GRIDBAG_HSPACE) grid.Add(title_label, (0,0), flag=wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT) @@ -165,6 +168,8 @@ grid.Add(self.instrument_value, (4,1)) grid.Add(date_label, (5,0), flag=wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT) grid.Add(self.date_value, (5,1)) + grid.Add(path_label, (6,0), flag=wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT) + grid.Add(self.path_value, (6,1)) mainSizer = wx.BoxSizer(wx.VERTICAL) mainSizer.Add(grid, 0, wx.ALIGN_CENTER|wx.ALL, mwx.PANEL_SPACE_MAIN) @@ -442,6 +447,7 @@ # clear previous values self.title_value.ChangeValue('') self.date_value.ChangeValue('') + self.path_value.ChangeValue('') self.operator_value.ChangeValue('') self.contact_value.ChangeValue('') self.institution_value.ChangeValue('') @@ -460,6 +466,7 @@ if self.currentDocument: self.title_value.ChangeValue(document.title) self.date_value.ChangeValue(document.date) + self.path_value.ChangeValue(document.path) self.operator_value.ChangeValue(document.operator) self.contact_value.ChangeValue(document.contact) self.institution_value.ChangeValue(document.institution) diff -Nru mmass-3.12.1/gui/panel_documents.py mmass-4.0.0/gui/panel_documents.py --- mmass-3.12.1/gui/panel_documents.py 2011-06-26 17:54:47.000000000 +0000 +++ mmass-4.0.0/gui/panel_documents.py 2011-12-01 13:07:11.000000000 +0000 @@ -215,6 +215,7 @@ menu.Append(ID_documentDuplicate, "Duplicate Document") menu.AppendSeparator() menu.Append(ID_documentClose, "Close Document") + menu.Append(ID_documentCloseAll, "Close All Documents") if config.spectrum['normalize']: menu.Enable(ID_documentOffset, False) @@ -232,7 +233,9 @@ elif itemType == 'annotation': menu.Append(ID_documentAnnotationEdit, "Edit Annotation...") - menu.Append(ID_documentAnnotationPattern, "Show Isotopic Pattern...") + menu.AppendSeparator() + menu.Append(ID_documentAnnotationSendToMassCalculator, "Show Isotopic Pattern...") + menu.Append(ID_documentAnnotationSendToEnvelopeFit, "Send to Envelope Fit...") menu.AppendSeparator() menu.Append(ID_documentAnnotationsCalibrateBy, "Calibrate by Annotations...") menu.AppendSeparator() @@ -240,7 +243,8 @@ menu.Append(ID_documentAnnotationsDelete, "Delete All Annotations") if not itemData.formula: - menu.Enable(ID_documentAnnotationPattern, False) + menu.Enable(ID_documentAnnotationSendToMassCalculator, False) + menu.Enable(ID_documentAnnotationSendToEnvelopeFit, False) elif itemType == 'sequence': menu.Append(ID_sequenceEditor, "Edit Sequence...") @@ -250,6 +254,9 @@ menu.Append(ID_sequenceFragment, "Fragment Peptide...") menu.Append(ID_sequenceSearch, "Mass Search...") menu.AppendSeparator() + menu.Append(ID_sequenceSendToMassCalculator, "Show Isotopic Pattern...") + menu.Append(ID_sequenceSendToEnvelopeFit, "Send to Envelope Fit...") + menu.AppendSeparator() menu.Append(ID_sequenceMatchesCalibrateBy, "Calibrate by Matches...") menu.AppendSeparator() menu.Append(ID_sequenceMatchesDelete, "Delete All Matches") @@ -261,7 +268,9 @@ elif itemType == 'match': menu.Append(ID_sequenceMatchEdit, "Edit Match...") - menu.Append(ID_sequenceMatchPattern, "Show Isotopic Pattern...") + menu.AppendSeparator() + menu.Append(ID_sequenceMatchSendToMassCalculator, "Show Isotopic Pattern...") + menu.Append(ID_sequenceMatchSendToEnvelopeFit, "Send to Envelope Fit...") menu.AppendSeparator() menu.Append(ID_sequenceMatchesCalibrateBy, "Calibrate by Matches...") menu.AppendSeparator() @@ -269,7 +278,8 @@ menu.Append(ID_sequenceMatchesDelete, "Delete All Matches") if not itemData.formula: - menu.Enable(ID_documentAnnotationPattern, False) + menu.Enable(ID_sequenceMatchSendToMassCalculator, False) + menu.Enable(ID_sequenceMatchSendToEnvelopeFit, False) # bind events self.Bind(wx.EVT_MENU, self.parent.onDocumentInfo, id=ID_documentInfo) @@ -280,9 +290,11 @@ self.Bind(wx.EVT_MENU, self.parent.onDocumentNotationsDelete, id=ID_documentNotationsDelete) self.Bind(wx.EVT_MENU, self.parent.onDocumentDuplicate, id=ID_documentDuplicate) self.Bind(wx.EVT_MENU, self.parent.onDocumentClose, id=ID_documentClose) + self.Bind(wx.EVT_MENU, self.parent.onDocumentCloseAll, id=ID_documentCloseAll) self.Bind(wx.EVT_MENU, self.onNotationEdit, id=ID_documentAnnotationEdit) - self.Bind(wx.EVT_MENU, self.onNotationPattern, id=ID_documentAnnotationPattern) + self.Bind(wx.EVT_MENU, self.onSendToMassCalculator, id=ID_documentAnnotationSendToMassCalculator) + self.Bind(wx.EVT_MENU, self.onSendToEnvelopeFit, id=ID_documentAnnotationSendToEnvelopeFit) self.Bind(wx.EVT_MENU, self.parent.onDocumentAnnotationsCalibrateBy, id=ID_documentAnnotationsCalibrateBy) self.Bind(wx.EVT_MENU, self.onNotationDelete, id=ID_documentAnnotationDelete) self.Bind(wx.EVT_MENU, self.parent.onDocumentAnnotationsDelete, id=ID_documentAnnotationsDelete) @@ -293,10 +305,13 @@ self.Bind(wx.EVT_MENU, self.parent.onToolsSequence, id=ID_sequenceDigest) self.Bind(wx.EVT_MENU, self.parent.onToolsSequence, id=ID_sequenceFragment) self.Bind(wx.EVT_MENU, self.parent.onToolsSequence, id=ID_sequenceSearch) + self.Bind(wx.EVT_MENU, self.onSendToMassCalculator, id=ID_sequenceSendToMassCalculator) + self.Bind(wx.EVT_MENU, self.onSendToEnvelopeFit, id=ID_sequenceSendToEnvelopeFit) self.Bind(wx.EVT_MENU, self.parent.onSequenceDelete, id=ID_sequenceDelete) self.Bind(wx.EVT_MENU, self.onNotationEdit, id=ID_sequenceMatchEdit) - self.Bind(wx.EVT_MENU, self.onNotationPattern, id=ID_sequenceMatchPattern) + self.Bind(wx.EVT_MENU, self.onSendToMassCalculator, id=ID_sequenceMatchSendToMassCalculator) + self.Bind(wx.EVT_MENU, self.onSendToEnvelopeFit, id=ID_sequenceMatchSendToEnvelopeFit) self.Bind(wx.EVT_MENU, self.parent.onSequenceMatchesCalibrateBy, id=ID_sequenceMatchesCalibrateBy) self.Bind(wx.EVT_MENU, self.onNotationDelete, id=ID_sequenceMatchDelete) self.Bind(wx.EVT_MENU, self.parent.onSequenceMatchesDelete, id=ID_sequenceMatchesDelete) @@ -344,7 +359,7 @@ seqIndex = self._getSequenceIndex(item) self.parent.onSequenceSelected(seqIndex) - # highlight matches and annotations + # update notation marks self.parent.updateNotationMarks() # highlight mass of selected match or annotation @@ -397,7 +412,9 @@ # popup menu menu = wx.Menu() menu.Append(ID_sequenceNew, "New Sequence...") + menu.AppendSeparator() menu.Append(ID_documentNew, "New Document") + menu.Append(ID_documentNewFromClipboard, "New from Clipboard") menu.AppendSeparator() menu.Append(ID_documentOpen, "Open Document...") @@ -406,6 +423,7 @@ # set events self.Bind(wx.EVT_MENU, self.parent.onSequenceNew, id=ID_sequenceNew) self.Bind(wx.EVT_MENU, self.parent.onDocumentNew, id=ID_documentNew) + self.Bind(wx.EVT_MENU, self.parent.onDocumentNewFromClipboard, id=ID_documentNewFromClipboard) self.Bind(wx.EVT_MENU, self.parent.onDocumentOpen, id=ID_documentOpen) self.PopupMenu(menu) @@ -507,22 +525,6 @@ # ---- - def onNotationPattern(self, evt=None): - """Show isotopic pattern for selected annotation or sequence match.""" - - # get selected item - item = self.documentTree.GetSelection() - itemData = self.documentTree.GetPyData(item) - - # show profile - if itemData.formula: - if itemData.radical: - self.parent.onToolsMassCalculator(formula=itemData.formula, charge=itemData.charge, agentFormula='e', agentCharge=-1) - else: - self.parent.onToolsMassCalculator(formula=itemData.formula, charge=itemData.charge, agentFormula='H', agentCharge=1) - # ---- - - def onNotationDelete(self, evt=None): """Delete selected annotation or sequence match.""" @@ -544,6 +546,50 @@ # ---- + def onSendToMassCalculator(self, evt=None): + """Send selected item to Mass Calculator panel.""" + + # get selected item + item = self.documentTree.GetSelection() + itemType = self.documentTree.getItemType(item) + itemData = self.documentTree.GetPyData(item) + + # send data to Mass Calculator + if itemType == 'sequence': + self.parent.onToolsMassCalculator(formula=itemData.formula()) + elif itemType in ('annotation', 'match'): + if itemData.radical: + self.parent.onToolsMassCalculator(formula=itemData.formula, charge=itemData.charge, agentFormula='e', agentCharge=-1) + else: + self.parent.onToolsMassCalculator(formula=itemData.formula, charge=itemData.charge, agentFormula='H', agentCharge=1) + # ---- + + + def onSendToEnvelopeFit(self, evt=None): + """Send selected item to envelope fit panel.""" + + # get selected item + item = self.documentTree.GetSelection() + itemType = self.documentTree.getItemType(item) + itemData = self.documentTree.GetPyData(item) + + # send data to envelope fit + if itemType == 'sequence': + self.parent.onToolsEnvelopeFit(sequence=itemData) + + elif itemType == 'annotation': + self.parent.onToolsEnvelopeFit(formula=itemData.formula, charge=itemData.charge) + + elif itemType == 'match': + + scale = None + if itemData.sequenceRange and config.envfit['loss'] == 'H' and config.envfit['gain'] == 'H{2}': + scale = [0, itemData.sequenceRange[1]-itemData.sequenceRange[0]] + + self.parent.onToolsEnvelopeFit(formula=itemData.formula, charge=itemData.charge, scale=scale) + # ---- + + # DOCUMENT @@ -553,6 +599,7 @@ # deselect all documents if docIndex == None: self.documentTree.Unselect() + self.parent.onDocumentSelected(None) return # get item diff -Nru mmass-3.12.1/gui/panel_envelope_fit.py mmass-4.0.0/gui/panel_envelope_fit.py --- mmass-3.12.1/gui/panel_envelope_fit.py 1970-01-01 00:00:00.000000000 +0000 +++ mmass-4.0.0/gui/panel_envelope_fit.py 2011-11-30 18:09:56.000000000 +0000 @@ -0,0 +1,679 @@ +# ------------------------------------------------------------------------- +# Copyright (C) 2005-2011 Martin Strohalm + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# Complete text of GNU GPL can be found in the file LICENSE.TXT in the +# main directory of the program +# ------------------------------------------------------------------------- + +# load libs +import threading +import wx + +# load modules +from ids import * +import mwx +import images +import config +import libs +import mspy + + +# FLOATING PANEL WITH ENVELOPE FIT TOOL +# ------------------------------------- + +class panelEnvelopeFit(wx.MiniFrame): + """Envelope fit tool.""" + + def __init__(self, parent): + wx.MiniFrame.__init__(self, parent, -1, 'Envelope Fit', size=(400, 300), style=wx.DEFAULT_FRAME_STYLE & ~ (wx.RESIZE_BOX | wx.MAXIMIZE_BOX)) + + self.parent = parent + + self.processing = None + + self.currentDocument = None + self.currentCompound = None + self.currentFit = None + + # make gui items + self.makeGUI() + wx.EVT_CLOSE(self, self.onClose) + # ---- + + + def makeGUI(self): + """Make panel gui.""" + + # make toolbar + toolbar = self.makeToolbar() + controlbar = self.makeControlbar() + + # make panels + results = self.makeResultsPanel() + gauge = self.makeGaugePanel() + + # pack element + self.mainSizer = wx.BoxSizer(wx.VERTICAL) + self.mainSizer.Add(toolbar, 0, wx.EXPAND, 0) + self.mainSizer.Add(controlbar, 0, wx.EXPAND, 0) + self.mainSizer.Add(results, 1, wx.EXPAND, 0) + self.mainSizer.Add(gauge, 0, wx.EXPAND, 0) + + # hide gauge + self.mainSizer.Hide(3) + + # fit layout + self.mainSizer.Fit(self) + self.SetSizer(self.mainSizer) + self.SetMinSize(self.GetSize()) + mwx.layout(self, self.mainSizer) + # ---- + + + def makeToolbar(self): + """Make toolbar.""" + + # init toolbar + panel = mwx.bgrPanel(self, -1, images.lib['bgrToolbar'], size=(-1, mwx.TOOLBAR_HEIGHT)) + + # make elements + formula_label = wx.StaticText(panel, -1, "Formula:") + formula_label.SetFont(wx.SMALL_FONT) + self.formula_value = mwx.formulaCtrl(panel, -1, "", size=(220, -1)) + + charge_label = wx.StaticText(panel, -1, "Charge:") + charge_label.SetFont(wx.SMALL_FONT) + self.charge_value = wx.TextCtrl(panel, -1, str(config.envfit['charge']), size=(35, -1), validator=mwx.validator('int')) + + exchange_label = wx.StaticText(panel, -1, "Exchange:") + exchange_label.SetFont(wx.SMALL_FONT) + self.exchangeLoss_value = mwx.formulaCtrl(panel, -1, str(config.envfit['loss']), size=(40, -1)) + exchangeVs_label = wx.StaticText(panel, -1, " vs.") + exchangeVs_label.SetFont(wx.SMALL_FONT) + self.exchangeGain_value = mwx.formulaCtrl(panel, -1, str(config.envfit['gain']), size=(40, -1)) + + scale_label = wx.StaticText(panel, -1, "Range:") + scale_label.SetFont(wx.SMALL_FONT) + scaleDash_label = wx.StaticText(panel, -1, "-") + scaleDash_label.SetFont(wx.SMALL_FONT) + self.scaleMin_value = wx.TextCtrl(panel, -1, str(config.envfit['scaleMin']), size=(35, -1), validator=mwx.validator('intPos')) + self.scaleMax_value = wx.TextCtrl(panel, -1, str(config.envfit['scaleMax']), size=(35, -1), validator=mwx.validator('intPos')) + + self.calculate_butt = wx.Button(panel, -1, "Calculate", size=(-1, mwx.SMALL_BUTTON_HEIGHT)) + self.calculate_butt.SetFont(wx.SMALL_FONT) + self.calculate_butt.Bind(wx.EVT_BUTTON, self.onCalculate) + + # pack elements + sizer = wx.BoxSizer(wx.HORIZONTAL) + sizer.AddSpacer(mwx.CONTROLBAR_LSPACE) + sizer.Add(formula_label, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 5) + sizer.Add(self.formula_value, 0, wx.ALIGN_CENTER_VERTICAL) + sizer.AddSpacer(20) + sizer.Add(charge_label, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 5) + sizer.Add(self.charge_value, 0, wx.ALIGN_CENTER_VERTICAL) + sizer.AddSpacer(20) + sizer.Add(exchange_label, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 5) + sizer.Add(self.exchangeLoss_value, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 5) + sizer.Add(exchangeVs_label, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 5) + sizer.Add(self.exchangeGain_value, 0, wx.ALIGN_CENTER_VERTICAL) + sizer.AddSpacer(20) + sizer.Add(scale_label, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 5) + sizer.Add(self.scaleMin_value, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 5) + sizer.Add(scaleDash_label, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 5) + sizer.Add(self.scaleMax_value, 0, wx.ALIGN_CENTER_VERTICAL) + sizer.AddStretchSpacer() + sizer.AddSpacer(20) + sizer.Add(self.calculate_butt, 0, wx.ALIGN_CENTER_VERTICAL) + sizer.AddSpacer(mwx.CONTROLBAR_RSPACE) + + mainSizer = wx.BoxSizer(wx.VERTICAL) + mainSizer.Add(sizer, 1, wx.EXPAND) + panel.SetSizer(mainSizer) + mainSizer.Fit(panel) + + return panel + # ---- + + + def makeControlbar(self): + """Make controlbar.""" + + # init toolbar + panel = mwx.bgrPanel(self, -1, images.lib['bgrControlbar'], size=(-1, mwx.CONTROLBAR_HEIGHT)) + + # make elements + self.collapse_butt = wx.BitmapButton(panel, -1, images.lib['arrowsDown'], size=(mwx.TOOLBAR_TOOLSIZE), style=wx.BORDER_NONE) + self.collapse_butt.Bind(wx.EVT_BUTTON, self.onCollapse) + + fitTo_label = wx.StaticText(panel, -1, "Fit to:") + fitTo_label.SetFont(wx.SMALL_FONT) + + self.fitToPeaklist_radio = wx.RadioButton(panel, -1, "Peak list", style=wx.RB_GROUP) + self.fitToPeaklist_radio.SetFont(wx.SMALL_FONT) + + self.fitToSpectrum_radio = wx.RadioButton(panel, -1, "Spectrum") + self.fitToSpectrum_radio.SetFont(wx.SMALL_FONT) + + self.fitToPeaklist_radio.SetValue(True) + if config.envfit['fit'] == 'spectrum': + self.fitToSpectrum_radio.SetValue(True) + + fwhm_label = wx.StaticText(panel, -1, "Default FWHM:") + fwhm_label.SetFont(wx.SMALL_FONT) + self.fwhm_value = wx.TextCtrl(panel, -1, str(config.envfit['fwhm']), size=(50, mwx.SMALL_TEXTCTRL_HEIGHT), validator=mwx.validator('floatPos')) + self.fwhm_value.SetFont(wx.SMALL_FONT) + + self.forceFwhm_check = wx.CheckBox(panel, -1, "Force") + self.forceFwhm_check.SetFont(wx.SMALL_FONT) + self.forceFwhm_check.SetValue(config.envfit['forceFwhm']) + + relThreshold_label = wx.StaticText(panel, -1, "Rel. threshold:") + relThreshold_label.SetFont(wx.SMALL_FONT) + relThresholdUnits_label = wx.StaticText(panel, -1, "%") + relThresholdUnits_label.SetFont(wx.SMALL_FONT) + self.relThreshold_value = wx.TextCtrl(panel, -1, str(config.envfit['relThreshold']*100), size=(50, mwx.SMALL_TEXTCTRL_HEIGHT), validator=mwx.validator('floatPos')) + self.relThreshold_value.SetFont(wx.SMALL_FONT) + + self.autoAlign_check = wx.CheckBox(panel, -1, "Auto align") + self.autoAlign_check.SetFont(wx.SMALL_FONT) + self.autoAlign_check.SetValue(config.envfit['autoAlign']) + + self.average_label = wx.StaticText(panel, -1, "", size=(100, -1)) + self.average_label.SetFont(wx.SMALL_FONT) + self.updateAverageLabel() + + # pack elements + sizer = wx.BoxSizer(wx.HORIZONTAL) + sizer.AddSpacer(mwx.CONTROLBAR_LSPACE) + sizer.Add(self.collapse_butt, 0, wx.ALIGN_CENTER_VERTICAL) + sizer.AddSpacer(10) + sizer.Add(fitTo_label, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 5) + sizer.Add(self.fitToPeaklist_radio, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 5) + sizer.Add(self.fitToSpectrum_radio, 0, wx.ALIGN_CENTER_VERTICAL) + sizer.AddSpacer(20) + sizer.Add(fwhm_label, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 5) + sizer.Add(self.fwhm_value, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 5) + sizer.Add(self.forceFwhm_check, 0, wx.ALIGN_CENTER_VERTICAL) + sizer.AddSpacer(20) + sizer.Add(relThreshold_label, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 5) + sizer.Add(self.relThreshold_value, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 5) + sizer.Add(relThresholdUnits_label, 0, wx.ALIGN_CENTER_VERTICAL) + sizer.AddSpacer(20) + sizer.Add(self.autoAlign_check, 0, wx.ALIGN_CENTER_VERTICAL) + sizer.AddSpacer(20) + sizer.Add(self.average_label, 0, wx.ALIGN_CENTER_VERTICAL) + sizer.AddSpacer(mwx.CONTROLBAR_RSPACE) + + mainSizer = wx.BoxSizer(wx.VERTICAL) + mainSizer.Add(sizer, 1, wx.EXPAND) + mainSizer.Fit(panel) + panel.SetSizer(mainSizer) + + return panel + # ---- + + + def makeResultsPanel(self): + """Make results panel.""" + + panel = wx.Panel(self, -1) + + # make table + self.makeSpectrumCanvas(panel) + self.makeResultsList(panel) + + # pack main + mainSizer = wx.BoxSizer(wx.HORIZONTAL) + mainSizer.Add(self.spectrumCanvas, 1, wx.EXPAND) + mainSizer.AddSpacer(mwx.SASH_SIZE) + mainSizer.Add(self.resultsList, 0, wx.EXPAND|wx.ALL, mwx.LISTCTRL_NO_SPACE) + + # fit layout + panel.SetSizer(mainSizer) + + return panel + # ---- + + + def makeSpectrumCanvas(self, panel): + """Make spectrum canvas and set defalt parameters.""" + + # init canvas + self.spectrumCanvas = mspy.plot.canvas(panel, size=(600, 350), style=mwx.PLOTCANVAS_STYLE_PANEL) + + # set default params + self.spectrumCanvas.setProperties(xLabel='m/z') + self.spectrumCanvas.setProperties(yLabel='a.i.') + self.spectrumCanvas.setProperties(showLegend=True) + self.spectrumCanvas.setProperties(showPosBar=False) + self.spectrumCanvas.setProperties(showIntBar=True) + self.spectrumCanvas.setProperties(intBarHeight=6) + self.spectrumCanvas.setProperties(showGel=False) + self.spectrumCanvas.setProperties(checkLimits=True) + self.spectrumCanvas.setProperties(autoScaleY=True) + self.spectrumCanvas.setProperties(overlapLabels=False) + self.spectrumCanvas.setProperties(xPosDigits=5) + self.spectrumCanvas.setProperties(yPosDigits=2) + self.spectrumCanvas.setProperties(distanceDigits=5) + self.spectrumCanvas.setProperties(reverseScrolling=config.main['reverseScrolling']) + self.spectrumCanvas.setProperties(reverseDrawing=False) + self.spectrumCanvas.setLMBFunction('xDistance') + self.spectrumCanvas.setMFunction('cross') + + axisFont = wx.Font(config.spectrum['axisFontSize'], wx.SWISS, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, 0) + self.spectrumCanvas.setProperties(axisFont=axisFont) + + self.spectrumCanvas.draw(mspy.plot.container([])) + + return self.spectrumCanvas + # ---- + + + def makeResultsList(self, panel): + """Make results list.""" + + # init results list + self.resultsList = mwx.sortListCtrl(panel, -1, size=(171, -1), style=mwx.LISTCTRL_STYLE_MULTI) + self.resultsList.SetFont(wx.SMALL_FONT) + self.resultsList.setAltColour(mwx.LISTCTRL_ALTCOLOUR) + self.resultsList.Bind(wx.EVT_KEY_DOWN, self.onListKey) + + # make columns + self.resultsList.InsertColumn(0, "# of X", wx.LIST_FORMAT_LEFT) + self.resultsList.InsertColumn(1, "%", wx.LIST_FORMAT_RIGHT) + + # set column widths + for col, width in enumerate((75,75)): + self.resultsList.SetColumnWidth(col, width) + # ---- + + + def makeGaugePanel(self): + """Make processing gauge.""" + + panel = wx.Panel(self, -1) + + # make elements + self.gauge = mwx.gauge(panel, -1) + + stop_butt = wx.BitmapButton(panel, -1, images.lib['stopper'], style=wx.BORDER_NONE) + stop_butt.Bind(wx.EVT_BUTTON, self.onStop) + + # pack elements + sizer = wx.BoxSizer(wx.HORIZONTAL) + sizer.Add(self.gauge, 1, wx.ALIGN_CENTER_VERTICAL) + sizer.AddSpacer(10) + sizer.Add(stop_butt, 0, wx.ALIGN_CENTER_VERTICAL) + + # fit layout + mainSizer = wx.BoxSizer(wx.VERTICAL) + if wx.Platform == '__WXMAC__': + mainSizer.Add(wx.StaticLine(panel), 0, wx.EXPAND|wx.TOP, -1) + mainSizer.Add(sizer, 1, wx.EXPAND|wx.ALL, mwx.GAUGE_SPACE) + panel.SetSizer(mainSizer) + mainSizer.Fit(panel) + + return panel + # ---- + + + def onClose(self, evt): + """Close panel.""" + + # check processing + if self.processing != None: + wx.Bell() + return + + # clear tmp spectrum + self.parent.updateTmpSpectrum(None) + + # close self + self.Destroy() + # ---- + + + def onProcessing(self, status=True): + """Show processing gauge.""" + + self.gauge.SetValue(0) + + if status: + self.MakeModal(True) + self.mainSizer.Show(3) + else: + self.MakeModal(False) + self.mainSizer.Hide(3) + self.processing = None + mspy.start() + + # fit layout + self.Layout() + self.mainSizer.Fit(self) + try: wx.Yield() + except: pass + # ---- + + + def onStop(self, evt): + """Cancel current processing.""" + + if self.processing and self.processing.isAlive(): + mspy.stop() + else: + wx.Bell() + # ---- + + + def onListKey(self, evt): + """Export list if Ctrl+C.""" + + # get key + key = evt.GetKeyCode() + + # copy + if key == 67 and evt.CmdDown(): + self.resultsList.copyToClipboard() + + # select all + elif key == 65 and evt.CmdDown(): + for x in range(self.resultsList.GetItemCount()): + self.resultsList.SetItemState(x, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED) + + # other keys + else: + evt.Skip() + # ---- + + + def onCalculate(self, evt): + """Generate compounds ions.""" + + # check processing + if self.processing: + return + + # clear recent + self.currentCompound = None + self.currentFit = None + + # check document + if not self.currentDocument or not (self.currentDocument.spectrum.hasPoints() or self.currentDocument.spectrum.hasPeaks()): + wx.Bell() + return + + # get params + if not self.getParams(): + self.updateAverageLabel() + self.updateSpectrumCanvas() + self.updateResultsList() + return + + # show processing gauge + self.onProcessing(True) + self.calculate_butt.Enable(False) + + # do processing + self.processing = threading.Thread(target=self.runEnvelopeFit) + self.processing.start() + + # pulse gauge while working + while self.processing and self.processing.isAlive(): + self.gauge.pulse() + + # update gui + self.updateAverageLabel() + self.updateSpectrumCanvas() + self.updateResultsList() + + # hide processing gauge + self.onProcessing(False) + self.calculate_butt.Enable(True) + + # check errors + if self.currentFit != None and self.currentFit.error == 1: + wx.Bell() + dlg = mwx.dlgMessage(self, title="No data to fit.", message="There are no data in relevant mass range. Please check\nyour specified formula and charge.") + dlg.ShowModal() + dlg.Destroy() + # ---- + + + def onCollapse(self, evt): + """Collapse spectrum panel.""" + + # Show / hide panel + if self.mainSizer.IsShown(2): + self.mainSizer.Hide(2) + self.collapse_butt.SetBitmapLabel(images.lib['arrowsRight']) + else: + self.mainSizer.Show(2) + self.collapse_butt.SetBitmapLabel(images.lib['arrowsDown']) + + # fit layout + self.SetMinSize((-1,-1)) + self.Layout() + self.mainSizer.Fit(self) + self.SetMinSize(self.GetSize()) + # ---- + + + def setData(self, document=None, formula=None, charge=None, fwhm=None, scale=None): + """Set current data.""" + + self.currentCompound = None + self.currentFit = None + + # set values + self.currentDocument = document + if formula: + self.formula_value.SetValue(str(formula)) + if charge: + self.charge_value.SetValue(str(charge)) + if fwhm: + self.fwhm_value.SetValue(str(fwhm)) + if scale: + self.scaleMin_value.SetValue(str(scale[0])) + self.scaleMax_value.SetValue(str(scale[1])) + + # update fitting options + if self.currentDocument and not self.currentDocument.spectrum.hasPoints(): + self.fitToPeaklist_radio.SetValue(True) + self.fitToSpectrum_radio.Disable() + elif self.currentDocument and not self.currentDocument.spectrum.hasPeaks(): + self.fitToPeaklist_radio.Disable() + self.fitToSpectrum_radio.SetValue(True) + else: + self.fitToPeaklist_radio.Enable() + self.fitToSpectrum_radio.Enable() + + # clear gui + self.updateAverageLabel() + self.updateSpectrumCanvas() + self.updateResultsList() + # ---- + + + def getParams(self): + """Get all params from dialog.""" + + # try to get values + try: + + formula = self.formula_value.GetValue() + loss = self.exchangeLoss_value.GetValue() + gain = self.exchangeGain_value.GetValue() + + if not formula or not loss or not gain: + raise ValueError + + self.currentCompound = mspy.compound(formula) + lossCmpd = mspy.compound(loss) + gainCmpd = mspy.compound(gain) + + config.envfit['loss'] = str(loss) + config.envfit['gain'] = str(gain) + + config.envfit['fit'] = 'peaklist' + if self.fitToSpectrum_radio.GetValue(): + config.envfit['fit'] = 'spectrum' + + config.envfit['charge'] = int(self.charge_value.GetValue()) + config.envfit['scaleMin'] = int(self.scaleMin_value.GetValue()) + config.envfit['scaleMax'] = int(self.scaleMax_value.GetValue()) + config.envfit['fwhm'] = float(self.fwhm_value.GetValue()) + config.envfit['forceFwhm'] = self.forceFwhm_check.GetValue() + config.envfit['autoAlign'] = self.autoAlign_check.GetValue() + config.envfit['relThreshold'] = float(self.relThreshold_value.GetValue())/100. + + return True + + except: + wx.Bell() + return False + # ---- + + + def updateAverageLabel(self): + """Update average label value.""" + + # get label + label = "Average X: " + if self.currentFit != None and not self.currentFit.error: + label += '%0.2f' % (self.currentFit.average) + #label += '%0.2f (%s%0.2f)' % (self.currentFit.average, unichr(177), self.currentFit.std) + + # set label + self.average_label.SetLabel(label) + # ---- + + + def updateSpectrumCanvas(self): + """Update spectrum canvas.""" + + # check fit + if self.currentFit == None or self.currentFit.error: + self.spectrumCanvas.draw(mspy.plot.container([])) + self.parent.updateTmpSpectrum(None) + return + + # make container + container = mspy.plot.container([]) + + # show results + container.append(mspy.plot.points(self.currentFit.spectrum, legend='measured', showPoints=False, exactFit=True, lineColour=(16, 71, 185))) + container.append(mspy.plot.points(self.currentFit.envelope(), legend='model', showPoints=False, exactFit=True, lineColour=(241,144,0))) + container.append(mspy.plot.points(self.currentFit.data, legend='', showLines=False, pointColour=(16, 71, 185))) + container.append(mspy.plot.points(self.currentFit.model, legend='', showLines=False, pointColour=(241,144,0))) + + # draw container + self.spectrumCanvas.draw(container) + + # update spectrum overlay + self.parent.updateTmpSpectrum(self.currentFit.envelope()) + # ---- + + + def updateResultsList(self): + """Update results list.""" + + # make data map + if self.currentFit == None or self.currentFit.error: + data = [] + else: + data = self.currentFit.ncomposition.items() + data.sort() + + # clear previous data and set new + self.resultsList.DeleteAllItems() + self.resultsList.setDataMap(data) + + # check data + if not data: + return + + # add new data + for row, item in enumerate(data): + self.resultsList.InsertStringItem(row, str(item[0])) + self.resultsList.SetStringItem(row, 1, str(round(item[1]*100, 1))) + self.resultsList.SetItemData(row, row) + + # sort data + self.resultsList.sort() + + # scroll top + if self.resultsList.GetItemCount(): + self.resultsList.EnsureVisible(0) + # ---- + + + def runEnvelopeFit(self): + """Run envelope fitting.""" + + # run task + try: + + # init module + self.currentFit = mspy.envelopeFit( + formula = self.currentCompound.formula(), + charge = config.envfit['charge'], + scale = (config.envfit['scaleMin'], config.envfit['scaleMax']), + loss = config.envfit['loss'], + gain = config.envfit['gain'] + ) + + # fit data to peaklist + if config.envfit['fit'] == 'peaklist': + self.currentFit.fitToPeaklist( + peaklist = self.currentDocument.spectrum.peaklist, + fwhm = config.envfit['fwhm'], + forceFwhm = config.envfit['forceFwhm'], + autoAlign = config.envfit['autoAlign'], + iterLimit = 100*config.envfit['scaleMax'] + ) + + # fit data to spectrum + elif config.envfit['fit'] == 'spectrum': + + # get baseline window + baselineWindow = 1. + if config.processing['peakpicking']['baseline']: + baselineWindow = 1./config.processing['baseline']['precision'] + + # get baseline + baseline = self.currentDocument.spectrum.baseline( + window = baselineWindow, + smooth = True, + offset = config.processing['baseline']['offset'] + ) + + # fit data to spectrum + self.currentFit.fitToSpectrum( + points = self.currentDocument.spectrum.points, + fwhm = config.envfit['fwhm'], + forceFwhm = config.envfit['forceFwhm'], + autoAlign = config.envfit['autoAlign'], + iterLimit = 100*config.envfit['scaleMax'], + pickingHeight = config.processing['peakpicking']['pickingHeight'], + relThreshold = config.envfit['relThreshold'], + baselineData = baseline + ) + + # task canceled + except mspy.ForceQuit: + self.currentFit = None + return + # ---- + + + \ No newline at end of file diff -Nru mmass-3.12.1/gui/panel_mass_calculator.py mmass-4.0.0/gui/panel_mass_calculator.py --- mmass-3.12.1/gui/panel_mass_calculator.py 2011-07-01 14:02:13.000000000 +0000 +++ mmass-4.0.0/gui/panel_mass_calculator.py 2011-11-30 11:15:20.000000000 +0000 @@ -108,9 +108,10 @@ # make compound fields compound_label = wx.StaticText(panel, -1, "Formula:") - self.compound_value = wx.TextCtrl(panel, -1, "", size=(250, -1)) + self.compound_value = mwx.formulaCtrl(panel, -1, "", size=(250, -1), style=wx.TE_PROCESS_ENTER) compound_label.SetFont(wx.SMALL_FONT) self.compound_value.Bind(wx.EVT_TEXT, self.onCompoundChanged) + self.compound_value.Bind(wx.EVT_TEXT_ENTER, self.onCompoundChanged) # make save button self.save_butt = wx.Button(panel, -1, "Save", size=(-1, mwx.SMALL_BUTTON_HEIGHT)) @@ -268,7 +269,7 @@ patternShift_label = wx.StaticText(ctrlPanel, -1, "Shift:") patternShift_label.SetFont(wx.SMALL_FONT) - self.patternShift_value = mwx.scrollTextCtrl(ctrlPanel, -1, str(0), step=0.001, digits=3, limits=(-1.,1.), size=(55, mwx.SMALL_TEXTCTRL_HEIGHT)) + self.patternShift_value = mwx.scrollTextCtrl(ctrlPanel, -1, "0", step=0.001, digits=3, limits=(-1.,1.), size=(55, mwx.SMALL_TEXTCTRL_HEIGHT)) self.patternShift_value.SetFont(wx.SMALL_FONT) self.patternShift_value.Bind(wx.EVT_TEXT, self.onPatternChanged) @@ -338,16 +339,18 @@ self.patternCanvas.setProperties(xLabel='m/z') self.patternCanvas.setProperties(yLabel='a.i.') self.patternCanvas.setProperties(showLegend=True) - self.patternCanvas.setProperties(showPosBar=False) + self.patternCanvas.setProperties(showPosBar=True) self.patternCanvas.setProperties(showIntBar=True) + self.patternCanvas.setProperties(posBarHeight=6) self.patternCanvas.setProperties(intBarHeight=6) self.patternCanvas.setProperties(showGel=False) - self.patternCanvas.setProperties(checkLimits=False) + self.patternCanvas.setProperties(checkLimits=True) self.patternCanvas.setProperties(autoScaleY=True) self.patternCanvas.setProperties(overlapLabels=False) self.patternCanvas.setProperties(xPosDigits=5) self.patternCanvas.setProperties(yPosDigits=2) self.patternCanvas.setProperties(distanceDigits=5) + self.patternCanvas.setProperties(reverseScrolling=config.main['reverseScrolling']) self.patternCanvas.setProperties(reverseDrawing=True) self.patternCanvas.setLMBFunction('xDistance') self.patternCanvas.setMFunction('cross') @@ -445,6 +448,9 @@ def onCompoundChanged(self, evt=None): """Recalc all if compound changed.""" + if evt != None: + evt.Skip() + # get all params if not self.getParams(): self.currentCompound = None @@ -789,27 +795,27 @@ # add main profile spectrum to container labelFont = wx.Font(config.spectrum['labelFontSize'], wx.SWISS, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, 0) - spectrum = mspy.plot.spectrum(self.currentPatternScan, \ - legend=legend, \ - spectrumColour=(16,71,185), \ - tickColour=(255,0,0), \ - showPoints=False, \ - showLabels=True, \ - showTicks=True, \ - labelDigits=config.main['mzDigits'], \ - labelBgr=True, \ - labelAngle=90, - labelFont=labelFont \ + spectrum = mspy.plot.spectrum(self.currentPatternScan, + legend = legend, + spectrumColour = (16,71,185), + tickColour = (255,0,0), + showPoints = False, + showLabels = True, + showTicks = True, + labelDigits = config.main['mzDigits'], + labelBgr = True, + labelAngle = 90, + labelFont = labelFont ) container.append(spectrum) # add individual peaks to container for peak in self.currentPatternPeaks: - spectrum = mspy.plot.points(peak, \ - lineColour=(50,140,0), \ - showLines=True, \ - showPoints=False, \ - exactFit=True \ + spectrum = mspy.plot.points(peak, + lineColour = (50,140,0), + showLines = True, + showPoints = False, + exactFit = True ) container.append(spectrum) @@ -817,6 +823,9 @@ if not rescale: xAxis = self.patternCanvas.getCurrentXRange() yAxis = self.patternCanvas.getCurrentYRange() + if xAxis == (0,1) or yAxis == (0,1): + xAxis = None + yAxis = None else: xAxis = None yAxis = None @@ -902,24 +911,24 @@ charge = self.currentIon[3] # calculate compound pattern - pattern = self.currentCompound.pattern(\ - fwhm=min(0.9, config.masscalc['patternFwhm']), \ - threshold=config.masscalc['patternThreshold'], \ - charge=charge, \ - agentFormula=config.masscalc['ionseriesAgent'], \ - agentCharge=config.masscalc['ionseriesAgentCharge'] \ + pattern = self.currentCompound.pattern( + fwhm = min(0.9, config.masscalc['patternFwhm']), + threshold = config.masscalc['patternThreshold'], + charge = charge, + agentFormula = config.masscalc['ionseriesAgent'], + agentCharge = config.masscalc['ionseriesAgentCharge'] ) # make peaklist from pattern peaklist = [] for isotope in pattern: ai = isotope[1]*(config.masscalc['patternIntensity'] - config.masscalc['patternBaseline']) + config.masscalc['patternBaseline'] - peak = mspy.peak( \ - mz=isotope[0], \ - ai=ai, \ - base=config.masscalc['patternBaseline'], \ - fwhm=config.masscalc['patternFwhm'], \ - charge=charge \ + peak = mspy.peak( + mz = isotope[0], + ai = ai, + base = config.masscalc['patternBaseline'], + fwhm = config.masscalc['patternFwhm'], + charge = charge ) peaklist.append(peak) peaklist = mspy.peaklist(peaklist) @@ -927,11 +936,11 @@ # make peaks self.currentPatternPeaks = [] for isotope in peaklist: - peak = mspy.gaussian(\ - mz=isotope.mz, \ - ai=isotope.ai, \ - base=isotope.base, \ - fwhm=isotope.fwhm \ + peak = mspy.gaussian( + mz = isotope.mz, + ai = isotope.ai, + base = isotope.base, + fwhm = isotope.fwhm ) self.currentPatternPeaks.append(peak) diff -Nru mmass-3.12.1/gui/panel_mass_filter.py mmass-4.0.0/gui/panel_mass_filter.py --- mmass-3.12.1/gui/panel_mass_filter.py 2011-04-14 18:18:47.000000000 +0000 +++ mmass-4.0.0/gui/panel_mass_filter.py 2011-10-31 11:12:15.000000000 +0000 @@ -113,7 +113,7 @@ sizer.Add(self.match_butt, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 10) sizer.Add(self.annotate_butt, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 10) sizer.Add(self.remove_butt, 0, wx.ALIGN_CENTER_VERTICAL) - sizer.AddSpacer(mwx.CONTROLBAR_LSPACE) + sizer.AddSpacer(mwx.TOOLBAR_RSPACE) mainSizer = wx.BoxSizer(wx.VERTICAL) mainSizer.Add(sizer, 1, wx.EXPAND) diff -Nru mmass-3.12.1/gui/panel_match.py mmass-4.0.0/gui/panel_match.py --- mmass-3.12.1/gui/panel_match.py 2011-06-29 11:32:05.000000000 +0000 +++ mmass-4.0.0/gui/panel_match.py 2011-11-25 13:44:14.000000000 +0000 @@ -245,6 +245,7 @@ self.errorCanvas.setProperties(autoScaleY=False) self.errorCanvas.setProperties(xPosDigits=config.main['mzDigits']) self.errorCanvas.setProperties(yPosDigits=2) + self.errorCanvas.setProperties(reverseScrolling=config.main['reverseScrolling']) self.errorCanvas.setProperties(reverseDrawing=True) self.errorCanvas.setMFunction('cross') @@ -571,9 +572,9 @@ errorCol = 5 matchObject = doc.match elif self.currentModule == 'fragment': - massCol = 3 - chargeCol = 4 - errorCol = 6 + massCol = 2 + chargeCol = 3 + errorCol = 5 matchObject = doc.match elif self.currentModule == 'compounds': massCol = 1 @@ -757,12 +758,31 @@ label = 'Number of %s matched' % itemName self.currentSummary.append((label, sumMatched)) + # get matched intensity + totalInt = 0 + buff = {} + for peak in self.currentPeaklist: + totalInt += peak.intensity + buff[round(peak.mz, 6)] = peak.intensity + matchedInt = 0 + for item in self.currentData: + for n in item[-1]: + mz = round(n.mz,6) + if mz in buff: + matchedInt += buff[mz] + del buff[mz] + if totalInt: + value = '%0.f %s' % ((100*matchedInt/totalInt), '%') + else: + value = '0 %' + self.currentSummary.append(('Intensity matched', value)) + # get sequence coverage if self.currentModule == 'digest': sumPeptides = [] for item in self.currentData: if item[-1]: - sumPeptides.append(item[0]) + sumPeptides.append([item[6].history[-1][1]+1, item[6].history[-1][2]]) coverage = mspy.coverage(sumPeptides, self.currentSummaryData['sequenceLength']) value = '%0.f %s' % (coverage, '%') self.currentSummary.append(('Sequence length', self.currentSummaryData['sequenceLength'])) @@ -774,18 +794,29 @@ series = {} for item in self.currentData: - if item[0][:3] == 'int': + frag = item[6] + + if not frag.fragmentSerie in ('a','b','c','x','y','z','n-ladder','c-ladder'): + continue + elif 'break' in [x[0] for x in frag.history]: continue - if not item[0] in series: - series[item[0]] = [] + + name = frag.fragmentSerie + for loss in frag.fragmentLosses: + name += ' -'+loss + for gain in frag.fragmentGains: + name += ' +'+gain + + if not name in series: + series[name] = [] if item[-1]: - series[item[0]].append(item[1]) + series[name].append(frag.fragmentIndex) for serie in sorted(series.keys()): matches = series[serie] matches.sort() value = ', '.join(str(n) for n in matches) - label = 'Ion serie "%s" matches' % serie + label = 'Ion serie matches for "%s"' % serie self.currentSummary.append((label, value)) # ---- diff -Nru mmass-3.12.1/gui/panel_monomer_library.py mmass-4.0.0/gui/panel_monomer_library.py --- mmass-3.12.1/gui/panel_monomer_library.py 1970-01-01 00:00:00.000000000 +0000 +++ mmass-4.0.0/gui/panel_monomer_library.py 2011-11-10 12:29:22.000000000 +0000 @@ -0,0 +1,234 @@ +# ------------------------------------------------------------------------- +# Copyright (C) 2005-2011 Martin Strohalm + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# Complete text of GNU GPL can be found in the file LICENSE.TXT in the +# main directory of the program +# ------------------------------------------------------------------------- + +# load libs +import wx + +# load modules +from ids import * +import mwx +import images +import config +import libs +import mspy + + +# FLOATING PANEL WITH MONOMER LIBRARY +# ----------------------------------- + +class panelMonomerLibrary(wx.MiniFrame): + """Monomer library.""" + + def __init__(self, parent, filterIn=[], filterOut=[], DnD=True): + wx.MiniFrame.__init__(self, parent, -1, 'Monomer Library', size=(250, 300), style=wx.DEFAULT_FRAME_STYLE & ~ (wx.RESIZE_BOX | wx.MAXIMIZE_BOX)) + + self.parent = parent + self.filterIn = filterIn + self.filterOut = filterOut + self.DnD = DnD + + # make gui items + self.makeGUI() + wx.EVT_CLOSE(self, self.onClose) + + # update list + self.updateMonomerList() + # ---- + + + def makeGUI(self): + """Make panel gui.""" + + # make toolbar + toolbar = self.makeToolbar() + + # make list + self.makeMonomerList() + + # pack elements + self.mainSizer = wx.BoxSizer(wx.VERTICAL) + self.mainSizer.Add(toolbar, 0, wx.EXPAND, 0) + self.mainSizer.Add(self.monomerList, 1, wx.EXPAND|wx.ALL, mwx.LISTCTRL_NO_SPACE) + + # fit layout + self.mainSizer.Fit(self) + self.SetSizer(self.mainSizer) + self.SetMinSize(self.GetSize()) + # ---- + + + def makeToolbar(self): + """Make toolbar.""" + + # init toolbar + panel = mwx.bgrPanel(self, -1, images.lib['bgrToolbarNoBorder'], size=(-1, mwx.TOOLBAR_HEIGHT)) + + # make elements + if wx.Platform == '__WXMAC__': + self.search_value = wx.SearchCtrl(panel, -1, size=(150, mwx.SMALL_SEARCH_HEIGHT), style=wx.TE_PROCESS_ENTER) + self.search_value.ShowCancelButton(True) + self.search_value.SetDescriptiveText('Search') + self.search_value.Bind(wx.EVT_TEXT, self.onSearch) + self.search_value.Bind(wx.EVT_SEARCHCTRL_CANCEL_BTN, lambda evt: self.search_value.SetValue('')) + else: + self.search_value = wx.TextCtrl(panel, -1, size=(150, mwx.SMALL_SEARCH_HEIGHT), style=wx.TE_PROCESS_ENTER) + self.search_value.Bind(wx.EVT_TEXT, self.onSearch) + + # pack elements + sizer = wx.BoxSizer(wx.HORIZONTAL) + sizer.AddSpacer(mwx.TOOLBAR_LSPACE) + sizer.Add(self.search_value, 1, wx.ALIGN_CENTER_VERTICAL) + sizer.AddSpacer(mwx.TOOLBAR_LSPACE) + + mainSizer = wx.BoxSizer(wx.VERTICAL) + mainSizer.Add(sizer, 1, wx.EXPAND) + panel.SetSizer(mainSizer) + mainSizer.Fit(panel) + + return panel + # ---- + + + def makeMonomerList(self): + """Make references list.""" + + # init list + self.monomerList = mwx.sortListCtrl(self, -1, size=(231, 300), style=mwx.LISTCTRL_STYLE_SINGLE) + self.monomerList.SetFont(wx.SMALL_FONT) + self.monomerList.setAltColour(mwx.LISTCTRL_ALTCOLOUR) + + # set events + self.monomerList.Bind(wx.EVT_LIST_BEGIN_DRAG, self.onBeginDrag) + + # make columns + self.monomerList.InsertColumn(0, "abbr", wx.LIST_FORMAT_LEFT) + self.monomerList.InsertColumn(1, "name", wx.LIST_FORMAT_LEFT) + + # set column widths + for col, width in enumerate((100,110)): + self.monomerList.SetColumnWidth(col, width) + # ---- + + + def onClose(self, evt): + """Hide this frame.""" + self.Destroy() + # ---- + + + def onSearch(self, evt): + """Search monomer library.""" + self.updateMonomerList() + # ---- + + + def onBeginDrag(self, evt): + """Start item drag.""" + + # check if enabled + if not self.DnD: + evt.Veto() + return + + # get item + index = self.monomerList.getSelected() + if not index: + return + + # get monomer abbr + abbr = self.monomerMap[index[0]][0] + + # create data object with text + dataObject = wx.PyTextDataObject() + dataObject.SetText(abbr) + + # create drop source + dropSource = wx.DropSource(self) + dropSource.SetData(dataObject) + dropSource.DoDragDrop(flags=wx.Drag_CopyOnly) + # ---- + + + def setFilter(self, filterIn=[], filterOut=[]): + """Set current group filter.""" + + # set filters + self.filterIn = filterIn + self.filterOut = filterOut + + # update list + self.updateMonomerList() + # ---- + + + def enableDnD(self, enable): + """Enable / disable drag and drop.""" + self.DnD = enable + # ---- + + + def updateMonomerMap(self): + """Update items map.""" + + self.monomerMap = [] + + # get search + search = self.search_value.GetValue().lower().split() + + # make map + for abbr, monomer in sorted(mspy.monomers.items()): + + # check filters + if self.filterIn and not monomer.category in self.filterIn: + continue + elif self.filterOut and monomer.category in self.filterOut: + continue + + # check search + if search and not ( + all(map(lambda x: x in monomer.abbr.lower(), search)) or + all(map(lambda x: x in monomer.name.lower(), search)) + ): + continue + + # append item + self.monomerMap.append((abbr, monomer.name)) + # ---- + + + def updateMonomerList(self): + """Update items list.""" + + # clear previous data and set new + self.updateMonomerMap() + self.monomerList.DeleteAllItems() + self.monomerList.setDataMap(self.monomerMap) + + # check data + if not self.monomerMap: + return + + # add new data + for row, item in enumerate(self.monomerMap): + self.monomerList.InsertStringItem(row, item[0]) + self.monomerList.SetStringItem(row, 1, item[1]) + self.monomerList.SetItemData(row, row) + + # sort + self.monomerList.sort() + # ---- + diff -Nru mmass-3.12.1/gui/panel_peak_differences.py mmass-4.0.0/gui/panel_peak_differences.py --- mmass-3.12.1/gui/panel_peak_differences.py 2011-04-14 18:14:46.000000000 +0000 +++ mmass-4.0.0/gui/panel_peak_differences.py 2011-11-28 16:24:40.000000000 +0000 @@ -425,6 +425,12 @@ def searchAll(self): """Search differences for specified value, aminoacids or dipeptides.""" + # get amino acids + aminoacids = [] + for abbr in mspy.monomers: + if mspy.monomers[abbr].category == '_InternalAA': + aminoacids.append(abbr) + # get maxima aaMin = 0 aaMax = 0 @@ -432,8 +438,8 @@ dipMax = 0 if config.differences['aminoacids'] or config.differences['dipeptides']: masses = [] - for aa in mspy.aminoacids: - masses.append(mspy.aminoacids[aa].mass[config.differences['massType']]) + for aa in aminoacids: + masses.append(mspy.monomers[aa].mass[config.differences['massType']]) aaMin = min(masses) - config.differences['tolerance'] aaMax = max(masses) + config.differences['tolerance'] dipMin = min(masses)*2 - config.differences['tolerance'] @@ -467,8 +473,8 @@ # search for aminoacids if not matched and config.differences['aminoacids'] and aaMin <= diff <= aaMax: - for aa in mspy.aminoacids: - if diffMin <= mspy.aminoacids[aa].mass[config.differences['massType']] <= diffMax: + for aa in aminoacids: + if diffMin <= mspy.monomers[aa].mass[config.differences['massType']] <= diffMax: self.currentDifferences[x][y][1] = 'amino' matched = True @@ -486,6 +492,12 @@ self.currentMatches = [] + # get amino acids + aminoacids = [] + for abbr in mspy.monomers: + if mspy.monomers[abbr].category == '_InternalAA': + aminoacids.append(abbr) + # search for value if self.difference: error = diff - self.difference @@ -494,8 +506,8 @@ # search for aminoacids if config.differences['aminoacids']: - for aa in mspy.aminoacids: - error = diff - mspy.aminoacids[aa].mass[config.differences['massType']] + for aa in aminoacids: + error = diff - mspy.monomers[aa].mass[config.differences['massType']] if abs(error) <= config.differences['tolerance']: self.currentMatches.append([aa, error]) @@ -531,16 +543,21 @@ def calcDipeptides(self): """Calculate dipeptides masses.""" + # get amino acids + aminoacids = [] + for abbr in mspy.monomers: + if mspy.monomers[abbr].category == '_InternalAA': + aminoacids.append(abbr) + self.dipeptides = {} - symbols = mspy.aminoacids.keys() - for x in range(len(symbols)): - for y in range(x, len(symbols)): + for x in range(len(aminoacids)): + for y in range(x, len(aminoacids)): - aX = symbols[x] - aY = symbols[y] + aX = aminoacids[x] + aY = aminoacids[y] - massX = mspy.aminoacids[aX].mass - massY = mspy.aminoacids[aY].mass + massX = mspy.monomers[aX].mass + massY = mspy.monomers[aY].mass mass = (massX[0] + massY[0], massX[1] + massY[1]) if aX != aY: diff -Nru mmass-3.12.1/gui/panel_peaklist.py mmass-4.0.0/gui/panel_peaklist.py --- mmass-3.12.1/gui/panel_peaklist.py 2011-06-30 11:28:37.000000000 +0000 +++ mmass-4.0.0/gui/panel_peaklist.py 2011-10-21 14:05:37.000000000 +0000 @@ -424,6 +424,11 @@ def onDelete(self, evt): """Minus button pressed.""" + # check document + if self.currentDocument == None: + wx.Bell() + return + # popup menu menuDeleteSelectedID = wx.NewId() menuDeleteByThresholdID = wx.NewId() @@ -547,7 +552,7 @@ elif thresholdType == 'Relative Intensity': threshold /= 100 for i, peak in enumerate(self.currentDocument.spectrum.peaklist): - if peak.relIntensity < threshold: + if peak.ri < threshold: indexes.append(i) # use s/n @@ -676,7 +681,7 @@ elif column == 'int': row.append(peak.intensity) elif column == 'rel': - row.append(peak.relIntensity*100) + row.append(peak.ri*100) elif column == 'sn': row.append(peak.sn) elif column == 'z': @@ -911,7 +916,7 @@ if 'int' in config.export['peaklistColumns']: line += str(peak.intensity) + '\t' if 'rel' in config.export['peaklistColumns']: - line += str(peak.relIntensity*100) + '\t' + line += str(peak.ri*100) + '\t' if 'sn' in config.export['peaklistColumns']: line += str(peak.sn) + '\t' if 'z' in config.export['peaklistColumns']: @@ -1032,6 +1037,7 @@ + class dlgCopy(wx.Dialog): """Set coumns to copy.""" @@ -1151,6 +1157,7 @@ config.export['peaklistColumns'].append('group') # ---- + class fileDropTarget(wx.FileDropTarget): diff -Nru mmass-3.12.1/gui/panel_processing.py mmass-4.0.0/gui/panel_processing.py --- mmass-3.12.1/gui/panel_processing.py 2011-07-01 11:31:42.000000000 +0000 +++ mmass-4.0.0/gui/panel_processing.py 2011-11-30 14:29:17.000000000 +0000 @@ -184,18 +184,17 @@ self.updateAvailableDocuments() mathOperation_label = wx.StaticText(panel, -1, "Operation:") - self.mathOperationAdd_radio = wx.RadioButton(panel, -1, "A + B ", style=wx.RB_GROUP) + self.mathOperationNorm_radio = wx.RadioButton(panel, -1, "Normalize", style=wx.RB_GROUP) + self.mathOperationAdd_radio = wx.RadioButton(panel, -1, "A + B ") self.mathOperationSub_radio = wx.RadioButton(panel, -1, "A - B ") - self.mathOperationMul_radio = wx.RadioButton(panel, -1, "A * X") - self.mathOperationNorm_radio = wx.RadioButton(panel, -1, "Normalize") - self.mathOperationAdd_radio.SetValue(True) + self.mathOperationMul_radio = wx.RadioButton(panel, -1, "A x") + self.mathOperationNorm_radio.SetValue(True) + self.mathOperationNorm_radio.Bind(wx.EVT_RADIOBUTTON, self.onMathChanged) self.mathOperationAdd_radio.Bind(wx.EVT_RADIOBUTTON, self.onMathChanged) self.mathOperationSub_radio.Bind(wx.EVT_RADIOBUTTON, self.onMathChanged) self.mathOperationMul_radio.Bind(wx.EVT_RADIOBUTTON, self.onMathChanged) - self.mathOperationNorm_radio.Bind(wx.EVT_RADIOBUTTON, self.onMathChanged) - mathMul_label = wx.StaticText(panel, -1, "Multiplier X:") self.mathMul_value = wx.TextCtrl(panel, -1, '1', size=(70, -1), validator=mwx.validator('floatPos')) self.mathMul_value.Bind(wx.EVT_TEXT, self.onMathChanged) self.mathMul_value.Disable() @@ -203,14 +202,13 @@ # pack elements grid = wx.GridBagSizer(mwx.GRIDBAG_VSPACE, mwx.GRIDBAG_HSPACE) grid.Add(mathOperation_label, (0,0), flag=wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL) - grid.Add(self.mathOperationAdd_radio, (0,1)) - grid.Add(self.mathOperationSub_radio, (1,1)) - grid.Add(self.mathOperationMul_radio, (2,1)) - grid.Add(self.mathOperationNorm_radio, (3,1)) + grid.Add(self.mathOperationNorm_radio, (0,1), (1,2)) + grid.Add(self.mathOperationAdd_radio, (1,1), (1,2)) + grid.Add(self.mathOperationSub_radio, (2,1), (1,2)) + grid.Add(self.mathOperationMul_radio, (3,1)) + grid.Add(self.mathMul_value, (3,2), flag=wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL) grid.Add(mathSpectrumB_label, (4,0), flag=wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL) - grid.Add(self.mathSpectrumB_combo, (4,1), (1,3)) - grid.Add(mathMul_label, (5,0), flag=wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL) - grid.Add(self.mathMul_value, (5,1), (1,3)) + grid.Add(self.mathSpectrumB_combo, (4,1), (1,2)) mainSizer = wx.BoxSizer(wx.VERTICAL) mainSizer.Add(grid, 0, wx.ALIGN_CENTER|wx.ALL, mwx.PANEL_SPACE_MAIN) @@ -298,10 +296,12 @@ # make elements smoothingMethod_label = wx.StaticText(panel, -1, "Method:") - self.smoothingMethod_combo = wx.ComboBox(panel, -1, choices=['Moving Average', 'Savitzky-Golay'], size=(150, mwx.COMBO_HEIGHT), style=wx.CB_READONLY) + self.smoothingMethod_combo = wx.ComboBox(panel, -1, choices=['Moving Average', 'Gaussian', 'Savitzky-Golay'], size=(150, mwx.COMBO_HEIGHT), style=wx.CB_READONLY) self.smoothingMethod_combo.Select(0) - if config.processing['smoothing']['method']=='SG': + if config.processing['smoothing']['method']=='GA': self.smoothingMethod_combo.Select(1) + elif config.processing['smoothing']['method']=='SG': + self.smoothingMethod_combo.Select(2) self.smoothingMethod_combo.Bind(wx.EVT_COMBOBOX, self.onSmoothingChanged) smoothingWindow_label = wx.StaticText(panel, -1, "Window size:") @@ -441,9 +441,9 @@ self.deisotopingRemoveUnknown_check.SetValue(bool(config.processing['deisotoping']['removeUnknown'])) deisotopingLabelEnvelopeTool_label = wx.StaticText(panel, -1, "Label envelope tool:") - self.deisotopingLabelEnvelopeTool_combo = wx.ComboBox(panel, -1, choices=['Monoisotopic Mass', 'Envelope Centroid', 'All Isotopes'], size=(160, mwx.COMBO_HEIGHT), style=wx.CB_READONLY) + self.deisotopingLabelEnvelopeTool_combo = wx.ComboBox(panel, -1, choices=['1st Selected', 'Monoisotopic Mass', 'Envelope Centroid', 'All Isotopes'], size=(160, mwx.COMBO_HEIGHT), style=wx.CB_READONLY) self.deisotopingLabelEnvelopeTool_combo.Select(1) - choices=['monoisotopic', 'centroid', 'isotopes'] + choices=['1st', 'monoisotope', 'centroid', 'isotopes'] if config.processing['deisotoping']['labelEnvelope'] in choices: self.deisotopingLabelEnvelopeTool_combo.Select(choices.index(config.processing['deisotoping']['labelEnvelope'])) self.deisotopingLabelEnvelopeTool_combo.Bind(wx.EVT_COMBOBOX, self.getParams) @@ -764,10 +764,12 @@ self.baselineOffset_slider.SetValue(presets['baseline']['offset']*100) # set smoothing - if presets['smoothing']['method']=='MA': + if presets['smoothing']['method'] == 'MA': self.smoothingMethod_combo.Select(0) - else: + elif presets['smoothing']['method'] == 'GA': self.smoothingMethod_combo.Select(1) + else: + self.smoothingMethod_combo.Select(2) self.smoothingWindow_value.SetValue(str(presets['smoothing']['windowSize'])) self.smoothingCycles_slider.SetValue(presets['smoothing']['cycles']) @@ -791,7 +793,7 @@ self.deisotopingRemoveUnknown_check.SetValue(bool(presets['deisotoping']['removeUnknown'])) self.deisotopingSetAsMonoisotopic_check.SetValue(bool(presets['deisotoping']['setAsMonoisotopic'])) - choices=['monoisotopic', 'centroid', 'isotopes'] + choices=['1st', 'monoisotope', 'centroid', 'isotopes'] if presets['deisotoping']['labelEnvelope'] in choices: self.deisotopingLabelEnvelopeTool_combo.Select(choices.index(presets['deisotoping']['labelEnvelope'])) else: @@ -849,7 +851,10 @@ return # disable / enable items - if self.mathOperationAdd_radio.GetValue(): + if self.mathOperationNorm_radio.GetValue(): + self.mathSpectrumB_combo.Disable() + self.mathMul_value.Disable() + elif self.mathOperationAdd_radio.GetValue(): self.mathSpectrumB_combo.Enable() self.mathMul_value.Disable() elif self.mathOperationSub_radio.GetValue(): @@ -858,9 +863,6 @@ elif self.mathOperationMul_radio.GetValue(): self.mathSpectrumB_combo.Disable() self.mathMul_value.Enable() - elif self.mathOperationNorm_radio.GetValue(): - self.mathSpectrumB_combo.Disable() - self.mathMul_value.Disable() # ---- @@ -880,10 +882,10 @@ return # get baseline - baseline = self.currentDocument.spectrum.baseline(\ - window=(1./config.processing['baseline']['precision']), \ - smooth=True, \ - offset=config.processing['baseline']['offset'] \ + baseline = self.currentDocument.spectrum.baseline( + window = (1./config.processing['baseline']['precision']), + smooth = True, + offset = config.processing['baseline']['offset'] ) # make tmp spectrum @@ -1079,7 +1081,9 @@ try: # math operations - if self.mathOperationAdd_radio.GetValue(): + if self.mathOperationNorm_radio.GetValue(): + config.processing['math']['operation'] = 'norm' + elif self.mathOperationAdd_radio.GetValue(): config.processing['math']['operation'] = 'add' config.processing['math']['spectrumB'] = self.mathSpectrumB_combo.GetValue() elif self.mathOperationSub_radio.GetValue(): @@ -1088,8 +1092,6 @@ elif self.mathOperationMul_radio.GetValue(): config.processing['math']['operation'] = 'mul' config.processing['math']['multiplier'] = float(self.mathMul_value.GetValue()) - elif self.mathOperationNorm_radio.GetValue(): - config.processing['math']['operation'] = 'norm' # crop config.processing['crop']['lowMass'] = float(self.cropLowMass_value.GetValue()) @@ -1104,7 +1106,9 @@ config.processing['smoothing']['cycles'] = int(self.smoothingCycles_slider.GetValue()) config.processing['smoothing']['method'] = 'MA' - if self.smoothingMethod_combo.GetValue() == 'Savitzky-Golay': + if self.smoothingMethod_combo.GetValue() == 'Gaussian': + config.processing['smoothing']['method'] = 'GA' + elif self.smoothingMethod_combo.GetValue() == 'Savitzky-Golay': config.processing['smoothing']['method'] = 'SG' # peak picking @@ -1127,8 +1131,10 @@ config.processing['deisotoping']['setAsMonoisotopic'] = bool(self.deisotopingSetAsMonoisotopic_check.GetValue()) labelEnvelope = self.deisotopingLabelEnvelopeTool_combo.GetValue() - if labelEnvelope == 'Monoisotopic Mass': - config.processing['deisotoping']['labelEnvelope'] = 'monoisotopic' + if labelEnvelope == '1st Selected': + config.processing['deisotoping']['labelEnvelope'] = '1st' + elif labelEnvelope == 'Monoisotopic Mass': + config.processing['deisotoping']['labelEnvelope'] = 'monoisotope' elif labelEnvelope == 'Envelope Centroid': config.processing['deisotoping']['labelEnvelope'] = 'centroid' elif labelEnvelope == 'All Isotopes': @@ -1193,11 +1199,11 @@ try: # correct baseline - self.previewData = mspy.correctBaseline(\ - points=self.currentDocument.spectrum.points, \ - window=(1./config.processing['baseline']['precision']), \ - smooth=True, \ - offset=config.processing['baseline']['offset'] \ + self.previewData = mspy.correctBaseline( + points = self.currentDocument.spectrum.points, + window = (1./config.processing['baseline']['precision']), + smooth = True, + offset = config.processing['baseline']['offset'] ) # task canceled @@ -1214,20 +1220,29 @@ # smooth data by MA if config.processing['smoothing']['method']=='MA': + + self.previewData = mspy.smoothMA( + points = self.currentDocument.spectrum.points, + window = config.processing['smoothing']['windowSize'], + cycles = config.processing['smoothing']['cycles'] + ) - self.previewData = mspy.smoothMA(\ - points=self.currentDocument.spectrum.points, \ - window=config.processing['smoothing']['windowSize'], \ - cycles=config.processing['smoothing']['cycles']\ + # smooth data by GA + elif config.processing['smoothing']['method']=='GA': + + self.previewData = mspy.smoothGA( + points = self.currentDocument.spectrum.points, + window = config.processing['smoothing']['windowSize'], + cycles = config.processing['smoothing']['cycles'] ) # smooth data by SG elif config.processing['smoothing']['method']=='SG': - - self.previewData = mspy.smoothSG(\ - points=self.currentDocument.spectrum.points, \ - window=config.processing['smoothing']['windowSize'], \ - cycles=config.processing['smoothing']['cycles']\ + + self.previewData = mspy.smoothSG( + points = self.currentDocument.spectrum.points, + window = config.processing['smoothing']['windowSize'], + cycles = config.processing['smoothing']['cycles'] ) # task canceled @@ -1256,7 +1271,10 @@ return # process spectrum - if config.processing['math']['operation'] == 'add': + if config.processing['math']['operation'] == 'norm': + self.currentDocument.spectrum.normalize() + + elif config.processing['math']['operation'] == 'add': self.currentDocument.spectrum.concatenate(spectrumB) elif config.processing['math']['operation'] == 'sub': @@ -1265,9 +1283,6 @@ elif config.processing['math']['operation'] == 'mul': self.currentDocument.spectrum.multiply(config.processing['math']['multiplier']) - elif config.processing['math']['operation'] == 'norm': - self.currentDocument.spectrum.normalize() - # remove notations del self.currentDocument.annotations[:] for sequence in self.currentDocument.sequences: @@ -1326,10 +1341,10 @@ self.currentDocument.backup(('spectrum', 'notations')) # correct baseline - self.currentDocument.spectrum.correctBaseline(\ - window=(1./config.processing['baseline']['precision']), \ - smooth=True, \ - offset=config.processing['baseline']['offset'] \ + self.currentDocument.spectrum.correctBaseline( + window = (1./config.processing['baseline']['precision']), + smooth = True, + offset = config.processing['baseline']['offset'] ) # remove notations @@ -1353,10 +1368,10 @@ self.currentDocument.backup(('spectrum', 'notations')) # smooth spectrum - self.currentDocument.spectrum.smooth(\ - method=config.processing['smoothing']['method'], \ - window=config.processing['smoothing']['windowSize'], \ - cycles=config.processing['smoothing']['cycles'] \ + self.currentDocument.spectrum.smooth( + method = config.processing['smoothing']['method'], + window = config.processing['smoothing']['windowSize'], + cycles = config.processing['smoothing']['cycles'] ) # remove notations @@ -1390,18 +1405,18 @@ smoothMethod = config.processing['smoothing']['method'] # label spectrum - self.currentDocument.spectrum.labelScan(\ - pickingHeight=config.processing['peakpicking']['pickingHeight'], \ - absThreshold=config.processing['peakpicking']['absIntThreshold'], \ - relThreshold=config.processing['peakpicking']['relIntThreshold'], \ - snThreshold=config.processing['peakpicking']['snThreshold'], \ - baselineWindow=baselineWindow, \ - baselineSmooth=True, \ - baselineOffset=config.processing['baseline']['offset'], \ - smoothMethod=smoothMethod, \ - smoothWindow=config.processing['smoothing']['windowSize'], \ - smoothCycles=config.processing['smoothing']['cycles'] \ - ) + self.currentDocument.spectrum.labelScan( + pickingHeight = config.processing['peakpicking']['pickingHeight'], + absThreshold = config.processing['peakpicking']['absIntThreshold'], + relThreshold = config.processing['peakpicking']['relIntThreshold'], + snThreshold = config.processing['peakpicking']['snThreshold'], + baselineWindow = baselineWindow, + baselineSmooth = True, + baselineOffset = config.processing['baseline']['offset'], + smoothMethod = smoothMethod, + smoothWindow = config.processing['smoothing']['windowSize'], + smoothCycles = config.processing['smoothing']['cycles'] + ) # remove shoulder peaks if config.processing['peakpicking']['removeShoulders']: @@ -1409,11 +1424,11 @@ # find isotopes and calculate charges if config.processing['peakpicking']['deisotoping']: - self.currentDocument.spectrum.findIsotopes(\ - maxCharge=config.processing['deisotoping']['maxCharge'], \ - mzTolerance=config.processing['deisotoping']['massTolerance'], \ - intTolerance=config.processing['deisotoping']['intTolerance'], \ - isotopeShift=config.processing['deisotoping']['isotopeShift'] \ + self.currentDocument.spectrum.findIsotopes( + maxCharge = config.processing['deisotoping']['maxCharge'], + mzTolerance = config.processing['deisotoping']['massTolerance'], + intTolerance = config.processing['deisotoping']['intTolerance'], + isotopeShift = config.processing['deisotoping']['isotopeShift'] ) # remove isotopes @@ -1445,11 +1460,11 @@ self.currentDocument.backup(('spectrum', 'notations')) # find isotopes and calculate charges - self.currentDocument.spectrum.findIsotopes(\ - maxCharge=config.processing['deisotoping']['maxCharge'], \ - mzTolerance=config.processing['deisotoping']['massTolerance'], \ - intTolerance=config.processing['deisotoping']['intTolerance'], \ - isotopeShift=config.processing['deisotoping']['isotopeShift'] \ + self.currentDocument.spectrum.findIsotopes( + maxCharge = config.processing['deisotoping']['maxCharge'], + mzTolerance = config.processing['deisotoping']['massTolerance'], + intTolerance = config.processing['deisotoping']['intTolerance'], + isotopeShift = config.processing['deisotoping']['isotopeShift'] ) # remove isotopes @@ -1491,14 +1506,13 @@ del sequence.matches[:] # deconvolute peaklist - massType = ['mo', 'av'] - docData.spectrum.deconvolute(massType=massType[config.processing['deconvolution']['massType']]) + docData.spectrum.deconvolute(massType=config.processing['deconvolution']['massType']) # group peaks if config.processing['deconvolution']['groupPeaks']: docData.spectrum.groupPeaks( - window=config.processing['deconvolution']['groupWindow'], \ - forceWindow=config.processing['deconvolution']['forceGroupWindow'] + window = config.processing['deconvolution']['groupWindow'], + forceWindow = config.processing['deconvolution']['forceGroupWindow'] ) # append new document @@ -1561,11 +1575,11 @@ window = 1./config.processing['baseline']['precision'] # get curent baseline - baseline = self.currentDocument.spectrum.baseline(\ - window=window, \ - smooth=True, \ - offset=config.processing['baseline']['offset'] \ - ) + baseline = self.currentDocument.spectrum.baseline( + window = window, + smooth = True, + offset = config.processing['baseline']['offset'] + ) # get basepeak (approx. only) index = self.currentDocument.spectrum.points.argmax(axis=0)[1] diff -Nru mmass-3.12.1/gui/panel_sequence.py mmass-4.0.0/gui/panel_sequence.py --- mmass-3.12.1/gui/panel_sequence.py 2011-06-13 09:59:39.000000000 +0000 +++ mmass-4.0.0/gui/panel_sequence.py 2011-11-30 10:59:51.000000000 +0000 @@ -29,6 +29,7 @@ import mspy from gui.panel_match import panelMatch +from gui.panel_monomer_library import panelMonomerLibrary # FLOATING PANEL WITH SEQUENCE TOOLS @@ -37,11 +38,12 @@ class panelSequence(wx.MiniFrame): """Sequence tools.""" - def __init__(self, parent, tool='sequence'): + def __init__(self, parent, tool='editor'): wx.MiniFrame.__init__(self, parent, -1, 'Sequence', size=(500, 300), style=wx.DEFAULT_FRAME_STYLE & ~ (wx.RESIZE_BOX | wx.MAXIMIZE_BOX)) self.parent = parent self.matchPanel = None + self.monomerLibraryPanel = None self.processing = None @@ -164,8 +166,21 @@ """Make toolbar for sequence panel.""" # make elements - self.sequenceInfo_label = wx.StaticText(panel, -1, "", size=(330,-1)) - self.sequenceInfo_label.SetFont(wx.SMALL_FONT) + self.monomerLibrary_butt = wx.BitmapButton(panel, -1, images.lib['toolsLibrary'], size=(mwx.TOOLBAR_TOOLSIZE), style=wx.BORDER_NONE) + self.monomerLibrary_butt.SetToolTip(wx.ToolTip("Monomer library")) + self.monomerLibrary_butt.Bind(wx.EVT_BUTTON, self.onMonomerLibrary) + + sequenceType_label = wx.StaticText(panel, -1, "Sequence type:") + sequenceType_label.SetFont(wx.SMALL_FONT) + + self.sequenceType_combo = wx.ComboBox(panel, -1, choices=['Regular amino acids', 'Custom'], size=(-1, mwx.SMALL_COMBO_HEIGHT), style=wx.CB_READONLY) + self.sequenceType_combo.SetFont(wx.SMALL_FONT) + self.sequenceType_combo.Select(0) + self.sequenceType_combo.Bind(wx.EVT_COMBOBOX, self.onSequenceType) + + self.sequenceCyclic_check = wx.CheckBox(panel, -1, "Cyclic") + self.sequenceCyclic_check.SetFont(wx.SMALL_FONT) + self.sequenceCyclic_check.Bind(wx.EVT_CHECKBOX, self.onSequenceCyclic) self.pattern_butt = wx.Button(panel, -1, "Pattern", size=(-1, mwx.SMALL_BUTTON_HEIGHT)) self.pattern_butt.SetFont(wx.SMALL_FONT) @@ -174,7 +189,12 @@ # pack elements sizer = wx.BoxSizer(wx.HORIZONTAL) sizer.AddSpacer(20) - sizer.Add(self.sequenceInfo_label, 0, wx.ALIGN_CENTER_VERTICAL) + sizer.Add(self.monomerLibrary_butt, 0, wx.ALIGN_CENTER_VERTICAL) + sizer.AddSpacer(20) + sizer.Add(sequenceType_label, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 5) + sizer.Add(self.sequenceType_combo, 0, wx.ALIGN_CENTER_VERTICAL) + sizer.AddSpacer(20) + sizer.Add(self.sequenceCyclic_check, 0, wx.ALIGN_CENTER_VERTICAL) sizer.AddStretchSpacer() sizer.AddSpacer(20) sizer.Add(self.pattern_butt, 0, wx.ALIGN_CENTER_VERTICAL) @@ -380,10 +400,16 @@ def makeSequencePanel(self): """Make compound summary panel.""" + # init panels + ctrlPanel = mwx.bgrPanel(self, -1, images.lib['bgrControlbar'], size=(-1, mwx.CONTROLBAR_HEIGHT)) panel = wx.Panel(self, -1) + # make controls + self.sequenceInfo_label = wx.StaticText(ctrlPanel, -1, "Sequence Info", size=(600,-1)) + self.sequenceInfo_label.SetFont(wx.SMALL_FONT) + # make elements - self.sequenceTitle_value = wx.TextCtrl(panel, -1, self.currentSequence.title, size=(250, -1)) + self.sequenceTitle_value = wx.TextCtrl(panel, -1, self.currentSequence.title, size=(420, -1)) self.sequenceTitle_value.Bind(wx.EVT_TEXT, self.onSequenceTitle) sequenceAccession_label = wx.StaticText(panel, -1, "Acc.:") @@ -398,21 +424,40 @@ self.sequenceCanvas.Bind(wx.EVT_RIGHT_DOWN, self.onSequence) self.sequenceCanvas.Bind(wx.EVT_MOTION, self.onSequence) + self.sequenceGrid = sequenceGrid(self, panel, sequence=self.currentSequence, items=config.sequence['editor']['gridSize']) + + # pack controls + controls = wx.BoxSizer(wx.HORIZONTAL) + controls.AddSpacer(mwx.CONTROLBAR_LSPACE) + controls.Add(self.sequenceInfo_label, 0, wx.ALIGN_CENTER_VERTICAL) + controls.AddSpacer(mwx.CONTROLBAR_RSPACE) + controls.Fit(ctrlPanel) + ctrlPanel.SetSizer(controls) + # pack elements - sizer = wx.BoxSizer(wx.HORIZONTAL) - sizer.Add(self.sequenceTitle_value, 1, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 10) - sizer.Add(sequenceAccession_label, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 5) - sizer.Add(self.sequenceAccession_value, 0) + sequenceTitleSizer = wx.BoxSizer(wx.HORIZONTAL) + sequenceTitleSizer.Add(self.sequenceTitle_value, 1, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 10) + sequenceTitleSizer.Add(sequenceAccession_label, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 5) + sequenceTitleSizer.Add(self.sequenceAccession_value, 0) - mainSizer = wx.BoxSizer(wx.VERTICAL) - mainSizer.Add(sizer, 0, wx.EXPAND|wx.ALIGN_CENTER|wx.ALL, mwx.PANEL_SPACE_MAIN) - mainSizer.Add(self.sequenceCanvas, 1, wx.EXPAND|wx.ALIGN_CENTER|wx.LEFT|wx.RIGHT|wx.BOTTOM, mwx.PANEL_SPACE_MAIN) + self.sequenceEditorSizer = wx.BoxSizer(wx.VERTICAL) + if wx.Platform == '__WXMAC__': + self.sequenceEditorSizer.Add(sequenceTitleSizer, 0, wx.EXPAND|wx.ALIGN_CENTER|wx.ALL, mwx.PANEL_SPACE_MAIN) + else: + self.sequenceEditorSizer.Add(sequenceTitleSizer, 0, wx.EXPAND|wx.ALIGN_CENTER|wx.LEFT|wx.RIGHT|wx.BOTTOM, mwx.PANEL_SPACE_MAIN) + self.sequenceEditorSizer.Add(self.sequenceCanvas, 1, wx.EXPAND|wx.ALIGN_CENTER|wx.LEFT|wx.RIGHT|wx.BOTTOM, mwx.PANEL_SPACE_MAIN) + self.sequenceEditorSizer.Add(self.sequenceGrid, 1, wx.EXPAND|wx.ALIGN_CENTER|wx.LEFT|wx.RIGHT|wx.BOTTOM, mwx.PANEL_SPACE_MAIN) + self.sequenceEditorSizer.Hide(2) - # fit layout - mainSizer.Fit(panel) - panel.SetSizer(mainSizer) + self.sequenceEditorSizer.Fit(panel) + panel.SetSizer(self.sequenceEditorSizer) - return panel + # pack main + mainSizer = wx.BoxSizer(wx.VERTICAL) + mainSizer.Add(ctrlPanel, 0, wx.EXPAND) + mainSizer.Add(panel, 1, wx.EXPAND) + + return mainSizer # ---- @@ -426,7 +471,7 @@ modsPosition_label = wx.StaticText(ctrlPanel, -1, "Position:") modsPosition_label.SetFont(wx.SMALL_FONT) - self.modsResidue_combo = wx.ComboBox(ctrlPanel, -1, choices=['Glutamic acid'], size=(130, mwx.SMALL_COMBO_HEIGHT), style=wx.CB_READONLY) + self.modsResidue_combo = wx.ComboBox(ctrlPanel, -1, choices=[], size=(130, mwx.SMALL_COMBO_HEIGHT), style=wx.CB_READONLY) self.modsResidue_combo.SetFont(wx.SMALL_FONT) self.modsResidue_combo.Bind(wx.EVT_COMBOBOX, self.onResidueSelected) @@ -550,11 +595,16 @@ """Make controls for peptide fragmentation.""" # init panel - ctrlPanel = mwx.bgrPanel(self, -1, images.lib['bgrControlbar'], size=(-1, mwx.CONTROLBAR_HEIGHT)) + ctrlPanel = mwx.bgrPanel(self, -1, images.lib['bgrControlbarDouble'], size=(-1, mwx.CONTROLBAR_DOUBLE_HEIGHT)) # make controls - fragmentIons_label = wx.StaticText(ctrlPanel, -1, "Ions:") - fragmentIons_label.SetFont(wx.SMALL_FONT) + self.fragmentM_check = wx.CheckBox(ctrlPanel, -1, "M") + self.fragmentM_check.SetFont(wx.SMALL_FONT) + self.fragmentM_check.SetValue(config.sequence['fragment']['fragments'].count('M')) + + self.fragmentIm_check = wx.CheckBox(ctrlPanel, -1, "im") + self.fragmentIm_check.SetFont(wx.SMALL_FONT) + self.fragmentIm_check.SetValue(config.sequence['fragment']['fragments'].count('im')) self.fragmentA_check = wx.CheckBox(ctrlPanel, -1, "a") self.fragmentA_check.SetFont(wx.SMALL_FONT) @@ -580,74 +630,102 @@ self.fragmentZ_check.SetFont(wx.SMALL_FONT) self.fragmentZ_check.SetValue(config.sequence['fragment']['fragments'].count('z')) - self.fragmentIm_check = wx.CheckBox(ctrlPanel, -1, "im") - self.fragmentIm_check.SetFont(wx.SMALL_FONT) - self.fragmentIm_check.SetValue(config.sequence['fragment']['fragments'].count('im')) - - self.fragmentIntB_check = wx.CheckBox(ctrlPanel, -1, "int-b") - self.fragmentIntB_check.SetFont(wx.SMALL_FONT) - self.fragmentIntB_check.SetValue(config.sequence['fragment']['fragments'].count('int')) - self.fragmentIntA_check = wx.CheckBox(ctrlPanel, -1, "int-a") self.fragmentIntA_check.SetFont(wx.SMALL_FONT) - self.fragmentIntA_check.SetValue(config.sequence['fragment']['fragments'].count('int-CO')) + self.fragmentIntA_check.SetValue(config.sequence['fragment']['fragments'].count('int-a')) - fragmentLoss_label = wx.StaticText(ctrlPanel, -1, 'Loss:') - fragmentLoss_label.SetFont(wx.SMALL_FONT) - - self.fragmentH2O_check = wx.CheckBox(ctrlPanel, -1, "-H2O") - self.fragmentH2O_check.SetFont(wx.SMALL_FONT) - self.fragmentH2O_check.SetValue(config.sequence['fragment']['fragments'].count('-H2O')) - - self.fragmentNH3_check = wx.CheckBox(ctrlPanel, -1, "-NH3") - self.fragmentNH3_check.SetFont(wx.SMALL_FONT) - self.fragmentNH3_check.SetValue(config.sequence['fragment']['fragments'].count('-NH3')) - - self.fragmentH3PO4_check = wx.CheckBox(ctrlPanel, -1, "-H3PO4") - self.fragmentH3PO4_check.SetFont(wx.SMALL_FONT) - self.fragmentH3PO4_check.SetValue(config.sequence['fragment']['fragments'].count('-H3PO4')) - - fragmentLadder_label = wx.StaticText(ctrlPanel, -1, 'Ladder:') - fragmentLadder_label.SetFont(wx.SMALL_FONT) + self.fragmentIntB_check = wx.CheckBox(ctrlPanel, -1, "int-b") + self.fragmentIntB_check.SetFont(wx.SMALL_FONT) + self.fragmentIntB_check.SetValue(config.sequence['fragment']['fragments'].count('int-b')) - self.fragmentNLadder_check = wx.CheckBox(ctrlPanel, -1, "N") + self.fragmentNLadder_check = wx.CheckBox(ctrlPanel, -1, "N-ladder") self.fragmentNLadder_check.SetFont(wx.SMALL_FONT) self.fragmentNLadder_check.SetValue(config.sequence['fragment']['fragments'].count('n-ladder')) - self.fragmentCLadder_check = wx.CheckBox(ctrlPanel, -1, "C") + self.fragmentCLadder_check = wx.CheckBox(ctrlPanel, -1, "C-ladder") self.fragmentCLadder_check.SetFont(wx.SMALL_FONT) self.fragmentCLadder_check.SetValue(config.sequence['fragment']['fragments'].count('c-ladder')) - self.fragmentFilter_check = wx.CheckBox(ctrlPanel, -1, "Filter") - self.fragmentFilter_check.SetFont(wx.SMALL_FONT) - self.fragmentFilter_check.SetValue(config.sequence['fragment']['filterFragments']) + self.fragmentLossH2O_check = wx.CheckBox(ctrlPanel, -1, "-H2O") + self.fragmentLossH2O_check.SetFont(wx.SMALL_FONT) + self.fragmentLossH2O_check.SetValue(config.sequence['fragment']['fragments'].count('-H2O')) + + self.fragmentLossNH3_check = wx.CheckBox(ctrlPanel, -1, "-NH3") + self.fragmentLossNH3_check.SetFont(wx.SMALL_FONT) + self.fragmentLossNH3_check.SetValue(config.sequence['fragment']['fragments'].count('-NH3')) + + self.fragmentLossCO_check = wx.CheckBox(ctrlPanel, -1, "-CO") + self.fragmentLossCO_check.SetFont(wx.SMALL_FONT) + self.fragmentLossCO_check.SetValue(config.sequence['fragment']['fragments'].count('-CO')) + + self.fragmentLossH3PO4_check = wx.CheckBox(ctrlPanel, -1, "-H3PO4") + self.fragmentLossH3PO4_check.SetFont(wx.SMALL_FONT) + self.fragmentLossH3PO4_check.SetValue(config.sequence['fragment']['fragments'].count('-H3PO4')) + + self.fragmentLossDefined_check = wx.CheckBox(ctrlPanel, -1, "Defined losses") + self.fragmentLossDefined_check.SetFont(wx.SMALL_FONT) + self.fragmentLossDefined_check.SetValue(config.sequence['fragment']['fragments'].count('losses')) + self.fragmentLossDefined_check.SetToolTip(wx.ToolTip("Apply specific losses from monomer library.")) + + self.fragmentLossCombi_check = wx.CheckBox(ctrlPanel, -1, "Combinations") + self.fragmentLossCombi_check.SetFont(wx.SMALL_FONT) + self.fragmentLossCombi_check.SetValue(config.sequence['fragment']['fragments'].count('losscombi')) + + self.fragmentGainH2O_check = wx.CheckBox(ctrlPanel, -1, "+H2O") + self.fragmentGainH2O_check.SetFont(wx.SMALL_FONT) + self.fragmentGainH2O_check.SetValue(config.sequence['fragment']['fragments'].count('+H2O')) + self.fragmentGainH2O_check.SetToolTip(wx.ToolTip("Allowed for 'b' ions only.")) + + self.fragmentGainCO_check = wx.CheckBox(ctrlPanel, -1, "+CO") + self.fragmentGainCO_check.SetFont(wx.SMALL_FONT) + self.fragmentGainCO_check.SetValue(config.sequence['fragment']['fragments'].count('+CO')) + self.fragmentGainCO_check.SetToolTip(wx.ToolTip("Allowed for 'b' and 'c' ions only.")) + + self.fragmentScrambling_check = wx.CheckBox(ctrlPanel, -1, "Allow scrambling") + self.fragmentScrambling_check.SetFont(wx.SMALL_FONT) + self.fragmentScrambling_check.SetValue(config.sequence['fragment']['fragments'].count('scrambling')) + self.fragmentScrambling_check.SetToolTip(wx.ToolTip("Allow non-direct sequencing.")) + self.fragmentScrambling_check.Bind(wx.EVT_CHECKBOX, self.updateAvailableFragments) + + self.fragmentRemoveFiltered_check = wx.CheckBox(ctrlPanel, -1, "Remove filtered") + self.fragmentRemoveFiltered_check.SetFont(wx.SMALL_FONT) + self.fragmentRemoveFiltered_check.SetValue(config.sequence['fragment']['filterFragments']) self.makeFragmentsList() # pack controls + grid = wx.GridBagSizer(mwx.GRIDBAG_VSPACE, mwx.GRIDBAG_HSPACE) + grid.Add(self.fragmentM_check, (0,0)) + grid.Add(self.fragmentIm_check, (1,0)) + + grid.Add(self.fragmentA_check, (0,2)) + grid.Add(self.fragmentB_check, (0,3)) + grid.Add(self.fragmentC_check, (0,4)) + grid.Add(self.fragmentX_check, (1,2)) + grid.Add(self.fragmentY_check, (1,3)) + grid.Add(self.fragmentZ_check, (1,4)) + + grid.Add(self.fragmentIntA_check, (0,6)) + grid.Add(self.fragmentIntB_check, (1,6)) + grid.Add(self.fragmentNLadder_check, (0,7)) + grid.Add(self.fragmentCLadder_check, (1,7)) + + grid.Add(self.fragmentLossH2O_check, (0,9)) + grid.Add(self.fragmentLossNH3_check, (1,9)) + grid.Add(self.fragmentLossCO_check, (0,10)) + grid.Add(self.fragmentLossH3PO4_check, (1,10)) + grid.Add(self.fragmentLossDefined_check, (0,11)) + grid.Add(self.fragmentLossCombi_check, (1,11)) + + grid.Add(self.fragmentGainH2O_check, (0,13)) + grid.Add(self.fragmentGainCO_check, (1,13)) + + grid.Add(self.fragmentScrambling_check, (0,15)) + grid.Add(self.fragmentRemoveFiltered_check, (1,15)) + controls = wx.BoxSizer(wx.HORIZONTAL) controls.AddSpacer(mwx.CONTROLBAR_LSPACE) - controls.Add(fragmentIons_label, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 5) - controls.Add(self.fragmentA_check, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 5) - controls.Add(self.fragmentB_check, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 5) - controls.Add(self.fragmentC_check, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 5) - controls.Add(self.fragmentX_check, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 5) - controls.Add(self.fragmentY_check, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 5) - controls.Add(self.fragmentZ_check, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 5) - controls.Add(self.fragmentIm_check, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 5) - controls.Add(self.fragmentIntB_check, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 5) - controls.Add(self.fragmentIntA_check, 0, wx.ALIGN_CENTER_VERTICAL) - controls.AddSpacer(20) - controls.Add(fragmentLoss_label, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 5) - controls.Add(self.fragmentH2O_check, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 5) - controls.Add(self.fragmentNH3_check, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 5) - controls.Add(self.fragmentH3PO4_check, 0, wx.ALIGN_CENTER_VERTICAL) - controls.AddSpacer(20) - controls.Add(fragmentLadder_label, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 5) - controls.Add(self.fragmentNLadder_check, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 5) - controls.Add(self.fragmentCLadder_check, 0, wx.ALIGN_CENTER_VERTICAL) - controls.AddSpacer(20) - controls.Add(self.fragmentFilter_check, 0, wx.ALIGN_CENTER_VERTICAL) + controls.Add(grid, 0, wx.ALIGN_CENTER_VERTICAL) controls.AddSpacer(mwx.CONTROLBAR_RSPACE) controls.Fit(ctrlPanel) ctrlPanel.SetSizer(controls) @@ -781,7 +859,7 @@ """Make digest list.""" # init peaklist - self.digestList = mwx.sortListCtrl(self, -1, size=(738, 300), style=mwx.LISTCTRL_STYLE_SINGLE) + self.digestList = mwx.sortListCtrl(self, -1, size=(778, 300), style=mwx.LISTCTRL_STYLE_SINGLE) self.digestList.SetFont(wx.SMALL_FONT) self.digestList.setSecondarySortColumn(2) self.digestList.setAltColour(mwx.LISTCTRL_ALTCOLOUR) @@ -796,7 +874,7 @@ self.digestList.Bind(wx.EVT_LIST_ITEM_RIGHT_CLICK, self.onListRMU) # make columns - self.digestList.InsertColumn(0, "range", wx.LIST_FORMAT_CENTER) + self.digestList.InsertColumn(0, "slice", wx.LIST_FORMAT_CENTER) self.digestList.InsertColumn(1, "mis.", wx.LIST_FORMAT_CENTER) self.digestList.InsertColumn(2, "m/z", wx.LIST_FORMAT_RIGHT) self.digestList.InsertColumn(3, "z", wx.LIST_FORMAT_CENTER) @@ -804,7 +882,7 @@ self.digestList.InsertColumn(5, "error", wx.LIST_FORMAT_RIGHT) # set column widths - for col, width in enumerate((80,47,90,40,400,60)): + for col, width in enumerate((80,47,90,40,440,60)): self.digestList.SetColumnWidth(col, width) # ---- @@ -813,9 +891,9 @@ """Make fragments list.""" # init peaklist - self.fragmentsList = mwx.sortListCtrl(self, -1, size=(816, 300), style=mwx.LISTCTRL_STYLE_SINGLE) + self.fragmentsList = mwx.sortListCtrl(self, -1, size=(801, 300), style=mwx.LISTCTRL_STYLE_SINGLE) self.fragmentsList.SetFont(wx.SMALL_FONT) - self.fragmentsList.setSecondarySortColumn(2) + self.fragmentsList.setSecondarySortColumn(1) self.fragmentsList.setAltColour(mwx.LISTCTRL_ALTCOLOUR) # set events @@ -828,16 +906,15 @@ self.fragmentsList.Bind(wx.EVT_LIST_ITEM_RIGHT_CLICK, self.onListRMU) # make columns - self.fragmentsList.InsertColumn(0, "ion", wx.LIST_FORMAT_CENTER) - self.fragmentsList.InsertColumn(1, "#", wx.LIST_FORMAT_CENTER) - self.fragmentsList.InsertColumn(2, "range", wx.LIST_FORMAT_CENTER) - self.fragmentsList.InsertColumn(3, "m/z", wx.LIST_FORMAT_RIGHT) - self.fragmentsList.InsertColumn(4, "z", wx.LIST_FORMAT_CENTER) - self.fragmentsList.InsertColumn(5, "sequence", wx.LIST_FORMAT_LEFT) - self.fragmentsList.InsertColumn(6, "error", wx.LIST_FORMAT_RIGHT) + self.fragmentsList.InsertColumn(0, "ion", wx.LIST_FORMAT_LEFT) + self.fragmentsList.InsertColumn(1, "slice", wx.LIST_FORMAT_CENTER) + self.fragmentsList.InsertColumn(2, "m/z", wx.LIST_FORMAT_RIGHT) + self.fragmentsList.InsertColumn(3, "z", wx.LIST_FORMAT_CENTER) + self.fragmentsList.InsertColumn(4, "sequence", wx.LIST_FORMAT_LEFT) + self.fragmentsList.InsertColumn(5, "error", wx.LIST_FORMAT_RIGHT) # set column widths - for col, width in enumerate((80,40,70,90,40,415,60)): + for col, width in enumerate((120,130,90,40,340,60)): self.fragmentsList.SetColumnWidth(col, width) # ---- @@ -861,7 +938,7 @@ self.searchList.Bind(wx.EVT_LIST_ITEM_RIGHT_CLICK, self.onListRMU) # make columns - self.searchList.InsertColumn(0, "range", wx.LIST_FORMAT_CENTER) + self.searchList.InsertColumn(0, "slice", wx.LIST_FORMAT_CENTER) self.searchList.InsertColumn(1, "m/z", wx.LIST_FORMAT_RIGHT) self.searchList.InsertColumn(2, "sequence", wx.LIST_FORMAT_LEFT) self.searchList.InsertColumn(3, "error", wx.LIST_FORMAT_RIGHT) @@ -884,6 +961,10 @@ if self.matchPanel: self.matchPanel.Close() + # close library panel + if self.monomerLibraryPanel: + self.monomerLibraryPanel.Close() + # close self self.Destroy() # ---- @@ -999,6 +1080,29 @@ elif evt and evt.GetId() == ID_sequenceSearch: tool = 'search' + # block some tools for cyclic or custom sequence + if tool == 'editor': + pass + elif self.currentSequence == None: + wx.Bell() + return + elif self.currentSequence.chainType != 'aminoacids' and not tool in ('editor', 'fragment'): + wx.Bell() + title = "Selected tool is not available for custom-type sequences." + message = "To enable this tool, check the sequence type specified in the editor\nand if possible, convert your sequence to use regular amino acids." + dlg = mwx.dlgMessage(self, title, message) + dlg.ShowModal() + dlg.Destroy() + return + elif self.currentSequence.cyclic and not tool in ('editor', 'modifications','fragment'): + wx.Bell() + title = "Selected tool is not available for cyclic sequences." + message = "To enable this tool, linearize the sequence in the editor." + dlg = mwx.dlgMessage(self, title, message) + dlg.ShowModal() + dlg.Destroy() + return + # set current tool self.currentTool = tool @@ -1030,7 +1134,7 @@ self.toolbar.Show(1) self.mainSizer.Show(1) - if tool == 'modifications': + elif tool == 'modifications': self.SetTitle("Sequence Modifications") self.modifications_butt.SetBitmapLabel(images.lib['sequenceModificationsOn']) self.toolbar.Show(2) @@ -1059,6 +1163,116 @@ # ---- + def onMonomerLibrary(self, evt): + """Show monomers library.""" + + # destroy panel + if self.monomerLibraryPanel: + self.monomerLibraryPanel.Close() + return + + # set filters + filterIn = [] + filterOut = [] + if self.currentSequence == None or self.currentSequence.chainType == 'aminoacids': + filterIn = ['_InternalAA'] + DnD = False + else: + filterOut = ['_InternalAA'] + DnD = True + + # init library panel + if not self.monomerLibraryPanel: + self.monomerLibraryPanel = panelMonomerLibrary(self, filterIn=filterIn, filterOut=filterOut, DnD=DnD) + pos = self.GetPosition() + size = self.monomerLibraryPanel.GetSize() + self.monomerLibraryPanel.SetPosition((pos[0]-size[0]-20, pos[1]+50)) + self.monomerLibraryPanel.Show(True) + + # raise panel + self.monomerLibraryPanel.Raise() + # ---- + + + def onSequenceType(self, evt=None, chainType='aminoacids'): + """Change sequence editor and chain type.""" + + # switch sequence type + if evt != None: + + # get chain type + if self.sequenceType_combo.GetValue() == 'Regular amino acids': + chainType = 'aminoacids' + before = 'Custom' + elif self.sequenceType_combo.GetValue() == 'Custom': + chainType = 'custom' + before = 'Regular amino acids' + + # ask to process + if len(self.currentSequence): + title = 'Do you really want to change the sequence type?' + message = 'Current sequence definition will be lost.' + buttons = [(wx.ID_CANCEL, "Cancel", 80, False, 15), (wx.ID_OK, "Change", 80, True, 0)] + dlg = mwx.dlgMessage(self, title, message, buttons) + if dlg.ShowModal() == wx.ID_OK: + dlg.Destroy() + else: + dlg.Destroy() + self.sequenceType_combo.SetValue(before) + return + + # reset sequence + del self.currentSequence[:] + self.currentSequence.chainType = chainType + + # set editors + if chainType == 'aminoacids': + self.sequenceCanvas.setData(self.currentSequence) + self.sequenceGrid.setData(None) + self.sequenceGrid.setModified(True) + self.sequenceEditorSizer.Hide(2) + self.sequenceEditorSizer.Show(1) + elif chainType == 'custom': + self.sequenceGrid.setData(self.currentSequence) + self.sequenceCanvas.setData(None) + self.sequenceCanvas.setModified(True) + self.sequenceEditorSizer.Hide(1) + self.sequenceEditorSizer.Show(2) + + # update sequence info + self.onSequenceChanged() + + # set monomer filter to library + if self.monomerLibraryPanel and chainType == 'aminoacids': + self.monomerLibraryPanel.setFilter(filterIn=['_InternalAA']) + self.monomerLibraryPanel.enableDnD(False) + elif self.monomerLibraryPanel and chainType == 'custom': + self.monomerLibraryPanel.setFilter(filterOut=['_InternalAA']) + self.monomerLibraryPanel.enableDnD(True) + + # fit layout + mwx.layout(self, self.mainSizer) + # ---- + + + def onSequenceCyclic(self, evt): + """Set current sequence cyclic or linear.""" + + # make sequence cyclic/linear + value = self.sequenceCyclic_check.IsChecked() + self.currentSequence.cyclize(value) + + # set editor as modified + if self.currentSequence.chainType != 'aminoacids': + self.sequenceGrid.setModified(True) + else: + self.sequenceCanvas.setModified(True) + + # update sequence info + self.onSequenceChanged() + # ---- + + def onSequenceTitle(self, evt): """Update sequence title.""" @@ -1088,27 +1302,37 @@ # update sequence info self.updateSequenceInfo() + # check sequence + if self.currentSequence == None: + return + + # set editor + editor = self.sequenceCanvas + if self.currentSequence.chainType != 'aminoacids': + editor = self.sequenceGrid + # skip if sequence has not changed - cursor move only - if self.sequenceCanvas.ismodified(): - self.sequenceCanvas.setModified(False) + if editor.ismodified(): + editor.setModified(False) # update modifications panel self.updateAvailableResidues() self.updateModificationsList() # update digest panel - if self.currentDigest !=None: + if self.currentDigest != None: self.currentDigest = None self.updateDigestList() self.updateCoverage() # update fragment panel - if self.currentFragments !=None: + self.updateAvailableFragments() + if self.currentFragments != None: self.currentFragments = None self.updateFragmentsList() # update search panel - if self.currentSearch !=None: + if self.currentSearch != None: self.currentSearch = None self.updateSearchList() @@ -1129,7 +1353,7 @@ """Show isotopic pattern for whole sequence.""" # get formula - if len(self.currentSequence) != 0: + if self.currentSequence: formula = self.currentSequence.formula() else: wx.Bell() @@ -1239,7 +1463,7 @@ if self.currentTool=='digest': mz = self.currentDigest[evt.GetData()][2] elif self.currentTool=='fragment': - mz = self.currentFragments[evt.GetData()][3] + mz = self.currentFragments[evt.GetData()][2] elif self.currentTool=='search': mz = self.currentSearch[evt.GetData()][1] @@ -1250,26 +1474,151 @@ def onItemActivated(self, evt): """Show isotopic pattern for selected peptide/fragment.""" + self.onItemSendToMassCalculator(evt) + # ---- + + + def onItemSendToMassCalculator(self, evt): + """Send selected item to Mass Calculator panel.""" - # get formula and charge - if self.currentTool=='digest': - item = self.currentDigest[evt.GetData()] - formula = item[6].formula() - charge = item[3] - elif self.currentTool=='fragment': - item = self.currentFragments[evt.GetData()] - formula = item[7].formula() - charge = item[4] - elif self.currentTool=='search': - item = self.currentSearch[evt.GetData()] - formula = item[5].formula() - charge = item[2] + # get data + if self.currentTool == 'digest': + selected = self.digestList.getSelected() + if selected: + index = self.digestList.GetItemData(selected[0]) + formula = self.currentDigest[index][6].formula() + charge = self.currentDigest[index][3] - # send to masscalc + elif self.currentTool == 'fragment': + selected = self.fragmentsList.getSelected() + if selected: + index = self.fragmentsList.GetItemData(selected[0]) + formula = self.currentFragments[index][6].formula() + charge = self.currentFragments[index][3] + + elif self.currentTool == 'search': + selected = self.searchList.getSelected() + if selected: + index = self.searchList.GetItemData(selected[0]) + formula = self.currentSearch[index][5].formula() + charge = self.currentSearch[index][2] + + # check selection + if not selected: + wx.Bell() + return + + # send data to masscalc self.parent.onToolsMassCalculator(formula=formula, charge=charge, agentFormula='H', agentCharge=1) # ---- + def onItemSendToEnvelopeFit(self, evt): + """Send selected item to envelope fit panel.""" + + # get data + if self.currentTool == 'digest': + selected = self.digestList.getSelected() + if selected: + index = self.digestList.GetItemData(selected[0]) + sequence = self.currentDigest[index][6] + charge = self.currentDigest[index][3] + + elif self.currentTool == 'fragment': + selected = self.fragmentsList.getSelected() + if selected: + index = self.fragmentsList.GetItemData(selected[0]) + sequence = self.currentFragments[index][6] + charge = self.currentFragments[index][3] + + elif self.currentTool == 'search': + selected = self.searchList.getSelected() + if selected: + index = self.searchList.GetItemData(selected[0]) + sequence = self.currentSearch[index][5] + charge = self.currentSearch[index][2] + + # send data to envelope fit + self.parent.onToolsEnvelopeFit(sequence=sequence, charge=charge) + # ---- + + + def onItemCopySequence(self, evt): + """Copy selected sequence into clipboard.""" + + # get list + if self.currentTool == 'digest': + selected = self.digestList.getSelected() + if selected: + index = self.digestList.GetItemData(selected[0]) + sequence = self.currentDigest[index][6].format('S') + + elif self.currentTool == 'fragment': + selected = self.fragmentsList.getSelected() + if selected: + index = self.fragmentsList.GetItemData(selected[0]) + sequence = self.currentFragments[index][6].format('S') + + elif self.currentTool == 'search': + selected = self.searchList.getSelected() + if selected: + index = self.searchList.GetItemData(selected[0]) + sequence = self.currentSearch[index][5].format('S') + + # check selection + if not selected: + wx.Bell() + return + + # make text object for data + obj = wx.TextDataObject() + obj.SetText(sequence) + + # paste to clipboard + if wx.TheClipboard.Open(): + wx.TheClipboard.SetData(obj) + wx.TheClipboard.Close() + # ---- + + + def onItemCopyFormula(self, evt): + """Copy selected sequence formula into clipboard.""" + + # get list + if self.currentTool == 'digest': + selected = self.digestList.getSelected() + if selected: + index = self.digestList.GetItemData(selected[0]) + formula = self.currentDigest[index][6].formula() + + elif self.currentTool == 'fragment': + selected = self.fragmentsList.getSelected() + if selected: + index = self.fragmentsList.GetItemData(selected[0]) + formula = self.currentFragments[index][6].formula() + + elif self.currentTool == 'search': + selected = self.searchList.getSelected() + if selected: + index = self.searchList.GetItemData(selected[0]) + formula = self.currentSearch[index][5].formula() + + # check selection + if not selected: + wx.Bell() + return + + # make text object for data + obj = wx.TextDataObject() + obj.SetText(formula) + + # paste to clipboard + if wx.TheClipboard.Open(): + wx.TheClipboard.SetData(obj) + wx.TheClipboard.Close() + # ---- + + def onListKey(self, evt): """Export list if Ctrl+C.""" @@ -1296,7 +1645,12 @@ menu.Append(ID_listViewMatched, "Show Matched Only", "", wx.ITEM_RADIO) menu.Append(ID_listViewUnmatched, "Show Unmatched Only", "", wx.ITEM_RADIO) menu.AppendSeparator() - menu.Append(ID_listCopySequence, "Copy Selected Sequence", "") + menu.Append(ID_listSendToMassCalculator, "Show Isotopic Pattern...", "") + if self.currentTool in ('digest', 'search'): + menu.Append(ID_listSendToEnvelopeFit, "Send to Envelope Fit...", "") + menu.AppendSeparator() + menu.Append(ID_listCopySequence, "Copy Sequence", "") + menu.Append(ID_listCopyFormula, "Copy Formula", "") menu.Append(ID_listCopy, "Copy List") # check item @@ -1310,11 +1664,13 @@ menu.Check(ID_listViewAll, True) # bind events - if self.currentTool in ('digest', 'fragment'): - self.Bind(wx.EVT_MENU, self.onListFilter, id=ID_listViewAll) - self.Bind(wx.EVT_MENU, self.onListFilter, id=ID_listViewMatched) - self.Bind(wx.EVT_MENU, self.onListFilter, id=ID_listViewUnmatched) - self.Bind(wx.EVT_MENU, self.onListCopySequence, id=ID_listCopySequence) + self.Bind(wx.EVT_MENU, self.onListFilter, id=ID_listViewAll) + self.Bind(wx.EVT_MENU, self.onListFilter, id=ID_listViewMatched) + self.Bind(wx.EVT_MENU, self.onListFilter, id=ID_listViewUnmatched) + self.Bind(wx.EVT_MENU, self.onItemSendToMassCalculator, id=ID_listSendToMassCalculator) + self.Bind(wx.EVT_MENU, self.onItemSendToEnvelopeFit, id=ID_listSendToEnvelopeFit) + self.Bind(wx.EVT_MENU, self.onItemCopySequence, id=ID_listCopySequence) + self.Bind(wx.EVT_MENU, self.onItemCopyFormula, id=ID_listCopyFormula) self.Bind(wx.EVT_MENU, self.onListCopy, id=ID_listCopy) # show menu @@ -1362,44 +1718,6 @@ # ---- - def onListCopySequence(self, evt): - """Copy selected sequence into clipboard.""" - - # get list - if self.currentTool=='digest': - selected = self.digestList.getSelected() - if selected: - index = self.digestList.GetItemData(selected[0]) - sequence = self.currentDigest[index][6].format('S') - - elif self.currentTool=='fragment': - selected = self.fragmentsList.getSelected() - if selected: - index = self.fragmentsList.GetItemData(selected[0]) - sequence = self.currentFragments[index][7].format('S') - - elif self.currentTool=='search': - selected = self.searchList.getSelected() - if selected: - index = self.searchList.GetItemData(selected[0]) - sequence = self.currentSearch[index][5].format('S') - - # check selection - if not selected: - wx.Bell() - return - - # make text object for data - obj = wx.TextDataObject() - obj.SetText(sequence) - - # paste to clipboard - if wx.TheClipboard.Open(): - wx.TheClipboard.SetData(obj) - wx.TheClipboard.Close() - # ---- - - def onDigest(self, evt): """Digest sequence.""" @@ -1421,7 +1739,7 @@ return # check sequence - if len(self.currentSequence) == 0: + if not self.currentSequence or self.currentSequence.chainType != 'aminoacids': wx.Bell() return @@ -1477,7 +1795,7 @@ return # check sequence - if len(self.currentSequence) == 0: + if not self.currentSequence: wx.Bell() return @@ -1528,7 +1846,7 @@ return # check sequence - if len(self.currentSequence) == 0: + if not self.currentSequence or self.currentSequence.chainType != 'aminoacids': wx.Bell() return @@ -1586,28 +1904,33 @@ buff = [] + # get template + template = 'matchTemplateAmino' + if self.currentSequence.chainType != 'aminoacids': + template = 'matchTemplateCustom' + # get digest data if self.currentTool == 'digest' and self.currentDigest: for item in self.currentDigest: obj = item[6] - title = '%s' % (obj.format(config.sequence['digest']['matchFormat'])) + title = obj.format(config.sequence['digest'][template]) for match in item[-1]: match.label = title match.charge = item[3] match.formula = obj.formula() - match.sequenceRange = obj.userRange[:] + match.sequenceRange = [obj.history[-1][1]+1, obj.history[-1][2]] buff.append((match.mz, match.delta('Da'), match)) # get fragment data elif self.currentTool == 'fragment' and self.currentFragments: for item in self.currentFragments: - obj = item[7] - title = '%s' % (obj.format(config.sequence['fragment']['matchFormat'])) + obj = item[6] + title = obj.format(config.sequence['fragment'][template]) for match in item[-1]: match.label = title - match.charge = item[4] + match.charge = item[3] match.formula = obj.formula() - match.sequenceRange = obj.userRange[:] + match.sequenceRange = [obj.history[-1][1]+1, obj.history[-1][2]] match.fragmentSerie = obj.fragmentSerie match.fragmentIndex = obj.fragmentIndex buff.append((match.mz, match.delta('Da'), match)) @@ -1631,26 +1954,35 @@ def setData(self, sequence=None): """Set current sequence.""" + self.currentSequence = sequence + # check sequence - if sequence == None: - sequence = mspy.sequence('') + if self.currentSequence == None: + self.sequenceType_combo.Enable(False) + self.sequenceCyclic_check.Enable(False) self.sequenceTitle_value.Enable(False) self.sequenceAccession_value.Enable(False) - self.sequenceCanvas.Enable(False) + self.sequenceCyclic_check.SetValue(False) + self.sequenceTitle_value.ChangeValue('') + self.sequenceAccession_value.ChangeValue('') else: + self.sequenceType_combo.Enable(True) + self.sequenceCyclic_check.Enable(True) self.sequenceTitle_value.Enable(True) self.sequenceAccession_value.Enable(True) - self.sequenceCanvas.Enable(True) - - # set data - self.currentSequence = sequence - self.sequenceTitle_value.ChangeValue(self.currentSequence.title) - self.sequenceAccession_value.ChangeValue(self.currentSequence.accession) - self.sequenceCanvas.setData(self.currentSequence) - self.sequenceCanvas.setModified(False) - - # update sequence info - self.updateSequenceInfo() + self.sequenceCyclic_check.SetValue(self.currentSequence.cyclic) + self.sequenceTitle_value.ChangeValue(self.currentSequence.title) + self.sequenceAccession_value.ChangeValue(self.currentSequence.accession) + + # select editor + if self.currentSequence == None or self.currentSequence.chainType == 'aminoacids': + self.sequenceType_combo.Select(0) + self.sequenceCanvas.setData(self.currentSequence) + self.onSequenceType(chainType='aminoacids') + else: + self.sequenceType_combo.Select(1) + self.sequenceGrid.setData(self.currentSequence) + self.onSequenceType(chainType='custom') # update modifications panel self.updateAvailableResidues() @@ -1663,6 +1995,7 @@ self.updateCoverage() # update fragment panel + self.updateAvailableFragments() if self.currentFragments != None: self.currentFragments = None self.updateFragmentsList() @@ -1675,6 +2008,9 @@ # clear match panel if self.matchPanel: self.matchPanel.Close() + + # select editor tool + self.onToolSelected(tool='editor') # ---- @@ -1710,6 +2046,10 @@ config.sequence['fragment']['massType'] = 1 config.sequence['fragment']['fragments'] = [] + if self.fragmentM_check.GetValue(): + config.sequence['fragment']['fragments'].append('M') + if self.fragmentIm_check.GetValue(): + config.sequence['fragment']['fragments'].append('im') if self.fragmentA_check.GetValue(): config.sequence['fragment']['fragments'].append('a') if self.fragmentB_check.GetValue(): @@ -1722,24 +2062,38 @@ config.sequence['fragment']['fragments'].append('y') if self.fragmentZ_check.GetValue(): config.sequence['fragment']['fragments'].append('z') - if self.fragmentIm_check.GetValue(): - config.sequence['fragment']['fragments'].append('im') - if self.fragmentIntB_check.GetValue(): - config.sequence['fragment']['fragments'].append('int') + if self.fragmentIntA_check.GetValue(): - config.sequence['fragment']['fragments'].append('int-CO') - if self.fragmentH2O_check.GetValue(): - config.sequence['fragment']['fragments'].append('-H2O') - if self.fragmentNH3_check.GetValue(): - config.sequence['fragment']['fragments'].append('-NH3') - if self.fragmentH3PO4_check.GetValue(): - config.sequence['fragment']['fragments'].append('-H3PO4') + config.sequence['fragment']['fragments'].append('int-a') + if self.fragmentIntB_check.GetValue(): + config.sequence['fragment']['fragments'].append('int-b') if self.fragmentNLadder_check.GetValue(): config.sequence['fragment']['fragments'].append('n-ladder') if self.fragmentCLadder_check.GetValue(): config.sequence['fragment']['fragments'].append('c-ladder') - if self.fragmentFilter_check.GetValue(): + if self.fragmentLossH2O_check.GetValue(): + config.sequence['fragment']['fragments'].append('-H2O') + if self.fragmentLossNH3_check.GetValue(): + config.sequence['fragment']['fragments'].append('-NH3') + if self.fragmentLossCO_check.GetValue(): + config.sequence['fragment']['fragments'].append('-CO') + if self.fragmentLossH3PO4_check.GetValue(): + config.sequence['fragment']['fragments'].append('-H3PO4') + if self.fragmentLossDefined_check.GetValue(): + config.sequence['fragment']['fragments'].append('losses') + if self.fragmentLossCombi_check.GetValue(): + config.sequence['fragment']['fragments'].append('losscombi') + + if self.fragmentGainH2O_check.GetValue(): + config.sequence['fragment']['fragments'].append('+H2O') + if self.fragmentGainCO_check.GetValue(): + config.sequence['fragment']['fragments'].append('+CO') + + if self.fragmentScrambling_check.GetValue(): + config.sequence['fragment']['fragments'].append('scrambling') + + if self.fragmentRemoveFiltered_check.GetValue(): config.sequence['fragment']['filterFragments'] = 1 else: config.sequence['fragment']['filterFragments'] = 0 @@ -1773,24 +2127,30 @@ def updateSequenceInfo(self): """Update sequence info.""" - # make label label = '' - length = len(self.currentSequence) - if length > 0: + # check sequence + if not self.currentSequence: + self.sequenceInfo_label.SetLabel('No sequence defined') + return + + # get mass + if len(self.currentSequence): format = '%0.' + `config.main['mzDigits']` + 'f' mass = self.currentSequence.mass() + label += 'Mo. mass: '+format % mass[0] + label += ' Av. mass: '+format % mass[1] + + # get length + label += ' Length: %d' % len(self.currentSequence) + + # get cursor position + if len(self.currentSequence) and self.currentSequence.chainType == 'aminoacids': selection = self.sequenceCanvas.getSequenceSelection() - - label += 'Mo: '+format % mass[0] - label += ' Av: '+format % mass[1] - - if selection[0]==selection[1]: - label += ' Position: %s/%s' % (selection[0]+1,length) - elif selection[1] > length: - label += ' Selection: %s-%s' % ((selection[0]+1), selection[1]-1) + if selection[0] == selection[1]: + label += ' Cursor: %s' % (selection[0]+1) else: - label += ' Selection: %s-%s' % ((selection[0]+1), selection[1]) + label += ' Cursor: %s-%s' % ((selection[0]+1), min(selection[1], len(self.currentSequence))) self.sequenceInfo_label.SetLabel(label) # ---- @@ -1804,10 +2164,14 @@ self.modsPosition_combo.Clear() self.modsMod_combo.Clear() + # check sequence type + if not self.currentSequence or self.currentSequence.chainType != 'aminoacids': + return + # get residues residues = [] - for amino in self.currentSequence: - name = '%s (%s)' % (mspy.aminoacids[amino].name, amino) + for monomer in self.currentSequence: + name = '%s (%s)' % (mspy.monomers[monomer].name, monomer) if not name in residues: residues.append(name) @@ -1947,6 +2311,45 @@ # ---- + def updateAvailableFragments(self, evt=None): + """Update available fragments.""" + + # no sequence defined + if self.currentSequence == None: + self.fragmentIntA_check.Enable() + self.fragmentIntB_check.Enable() + self.fragmentNLadder_check.Enable() + self.fragmentCLadder_check.Enable() + self.fragmentGainCO_check.SetValue(False) + self.fragmentGainCO_check.Disable() + + # cyclic sequence + elif self.currentSequence.cyclic: + self.fragmentIntA_check.SetValue(False) + self.fragmentIntB_check.SetValue(False) + self.fragmentNLadder_check.SetValue(False) + self.fragmentCLadder_check.SetValue(False) + self.fragmentIntA_check.Disable() + self.fragmentIntB_check.Disable() + self.fragmentNLadder_check.Disable() + self.fragmentCLadder_check.Disable() + self.fragmentGainCO_check.Enable() + + # linear sequence + else: + self.fragmentIntA_check.Enable() + self.fragmentIntB_check.Enable() + self.fragmentNLadder_check.Enable() + self.fragmentCLadder_check.Enable() + self.fragmentGainCO_check.SetValue(False) + self.fragmentGainCO_check.Disable() + + # scrambling enabled + if self.fragmentScrambling_check.IsChecked(): + self.fragmentGainCO_check.Enable() + # ---- + + def updateDigestList(self): """Update digest list.""" @@ -1975,7 +2378,7 @@ continue # format data - userRange = '[%s-%s]' % tuple(item[0]) + section = item[6].format('h') mz = mzFormat % (item[2]) error = '' @@ -1984,7 +2387,7 @@ # add data row += 1 - self.digestList.InsertStringItem(row, userRange) + self.digestList.InsertStringItem(row, section) self.digestList.SetStringItem(row, 1, str(item[1])) self.digestList.SetStringItem(row, 2, mz) self.digestList.SetStringItem(row, 3, str(item[3])) @@ -2029,43 +2432,37 @@ for index, item in enumerate(self.currentFragments): # filter data - if self._fragmentsFilter == 1 and item[6] == None: + if self._fragmentsFilter == 1 and item[5] == None: continue - elif self._fragmentsFilter == -1 and item[6] != None: + elif self._fragmentsFilter == -1 and item[5] != None: continue # format data - if type(item[1]) == int: - idx = str(item[1]) - else: - idx = '-' - - urange = '[%s-%s]' % tuple(item[2]) - mz = mzFormat % (item[3]) + section = item[6].format('h') + mz = mzFormat % (item[2]) error = '' - if item[6] != None: - error = errFormat % (item[6]) + if item[5] != None: + error = errFormat % (item[5]) # add data row += 1 self.fragmentsList.InsertStringItem(row, item[0]) - self.fragmentsList.SetStringItem(row, 1, idx) - self.fragmentsList.SetStringItem(row, 2, urange) - self.fragmentsList.SetStringItem(row, 3, mz) - self.fragmentsList.SetStringItem(row, 4, str(item[4])) - self.fragmentsList.SetStringItem(row, 5, item[5]) - self.fragmentsList.SetStringItem(row, 6, error) + self.fragmentsList.SetStringItem(row, 1, section) + self.fragmentsList.SetStringItem(row, 2, mz) + self.fragmentsList.SetStringItem(row, 3, str(item[3])) + self.fragmentsList.SetStringItem(row, 4, item[4]) + self.fragmentsList.SetStringItem(row, 5, error) self.fragmentsList.SetItemData(row, index) # mark filtered and matched fragments - if item[7].fragmentFiltered and item[6] == None: + if item[6].fragmentFiltered and item[5] == None: self.fragmentsList.SetItemTextColour(row, (150,150,150)) self.fragmentsList.SetItemFont(row, fontFiltered) - elif item[7].fragmentFiltered and item[6] != None: + elif item[6].fragmentFiltered and item[5] != None: self.fragmentsList.SetItemTextColour(row, (0,200,0)) self.fragmentsList.SetItemFont(row, fontFiltered) - elif item[6] != None: + elif item[5] != None: self.fragmentsList.SetItemTextColour(row, (0,200,0)) self.fragmentsList.SetItemFont(row, fontMatched) @@ -2099,13 +2496,13 @@ for index, item in enumerate(self.currentSearch): # format data - userRange = '[%s-%s]' % tuple(item[0]) + section = item[5].format('h') mz = mzFormat % (item[1]) error = errFormat % (item[4]) # add data row += 1 - self.searchList.InsertStringItem(row, userRange) + self.searchList.InsertStringItem(row, section) self.searchList.SetStringItem(row, 1, mz) self.searchList.SetStringItem(row, 2, item[3]) self.searchList.SetStringItem(row, 3, error) @@ -2150,16 +2547,17 @@ totalRanges = [] matchedRanges = [] for peptide in self.currentDigest: - totalRanges.append(peptide[0]) + section = [peptide[6].history[-1][1]+1, peptide[6].history[-1][2]] + totalRanges.append(section) if peptide[5] != None: - matchedRanges.append(peptide[0]) + matchedRanges.append(section) # get coverages totalCoverage = mspy.coverage(totalRanges, len(self.currentSequence)) matchedCoverage = mspy.coverage(matchedRanges, len(self.currentSequence)) # set new label - label = 'Cov.: %0.0f/%0.0f' % (matchedCoverage, totalCoverage) + label = 'Coverage: %0.0f/%0.0f' % (matchedCoverage, totalCoverage) label += ' %' self.digestCoverage_label.SetLabel(label) # ---- @@ -2172,7 +2570,7 @@ presets = libs.presets['modifications'][name] # check sequence - if len(self.currentSequence) == 0: + if not self.currentSequence: wx.Bell() dlg = mwx.dlgMessage(self, title="No sequence defined.", message='Modifications cannot be applied on empty sequence.') dlg.ShowModal() @@ -2189,22 +2587,30 @@ dlg.Destroy() return - # remove current modifications - self.currentSequence.unmodify(None) + # remove previous modifications if empty presets + if not presets: + self.currentSequence.unmodify(None) + + # ask to replace previous modifications + if self.currentSequence.modifications: + title = 'Modifications already applied!' + message = "There are some modifications already applied to the sequence\nyou can either replace previous or append new." + buttons = [(ID_dlgReplace, "Replace", 80, False, 15), (ID_dlgAppend, "Append", 80, True, 0)] + dlg = mwx.dlgMessage(self, title, message, buttons) + if dlg.ShowModal() == ID_dlgReplace: + self.currentSequence.unmodify(None) # check and apply modifications valid = True for mod in presets: - if not mod[1] in self.currentSequence: - continue - elif self.checkModifications(self.currentSequence, [mod[0], mod[1], mod[2]], config.sequence['digest']['maxMods']): + if self.checkModifications(self.currentSequence, [mod[0], mod[1], mod[2]], config.sequence['digest']['maxMods']): self.currentSequence.modify(mod[0], mod[1], mod[2]) else: valid = False if not valid: wx.Bell() - dlg = mwx.dlgMessage(self, title="Some of your modifications cannot be applied.", message='Maximum number of fixed modification is already applied\nto a single position.') + dlg = mwx.dlgMessage(self, title="Some of your modifications cannot be applied.", message='Maximum number of fixed modifications per single position\nis already applied.') dlg.ShowModal() dlg.Destroy() @@ -2222,36 +2628,55 @@ presets = libs.presets['fragments'][name] # set fragments + self.fragmentM_check.SetValue(presets.count('M')) + self.fragmentIm_check.SetValue(presets.count('im')) self.fragmentA_check.SetValue(presets.count('a')) self.fragmentB_check.SetValue(presets.count('b')) self.fragmentC_check.SetValue(presets.count('c')) self.fragmentX_check.SetValue(presets.count('x')) self.fragmentY_check.SetValue(presets.count('y')) self.fragmentZ_check.SetValue(presets.count('z')) - self.fragmentIm_check.SetValue(presets.count('im')) - self.fragmentIntB_check.SetValue(presets.count('int')) - self.fragmentIntA_check.SetValue(presets.count('int-CO')) - self.fragmentH2O_check.SetValue(presets.count('-H2O')) - self.fragmentNH3_check.SetValue(presets.count('-NH3')) - self.fragmentH3PO4_check.SetValue(presets.count('-H3PO4')) + + self.fragmentIntB_check.SetValue(presets.count('int-b')) + self.fragmentIntA_check.SetValue(presets.count('int-a')) self.fragmentNLadder_check.SetValue(presets.count('n-ladder')) self.fragmentCLadder_check.SetValue(presets.count('c-ladder')) + + self.fragmentLossH2O_check.SetValue(presets.count('-H2O')) + self.fragmentLossNH3_check.SetValue(presets.count('-NH3')) + self.fragmentLossCO_check.SetValue(presets.count('-CO')) + self.fragmentLossH3PO4_check.SetValue(presets.count('-H3PO4')) + self.fragmentLossDefined_check.SetValue(presets.count('losses')) + self.fragmentLossCombi_check.SetValue(presets.count('losscombi')) + + self.fragmentGainCO_check.SetValue(presets.count('+CO')) + self.fragmentGainH2O_check.SetValue(presets.count('+H2O')) + + self.fragmentScrambling_check.SetValue(presets.count('scrambling')) + + # enable/disable some fragments + self.updateAvailableFragments() # ---- def saveModificationsPresets(self): """Save applied global modifications as presets.""" + # check sequence + if not self.currentSequence: + wx.Bell() + return + # get modifications modifications = [] for mod in self.currentSequence.modifications: - if type(mod[1]) in (str, unicode): + if type(mod[1]) in (str, unicode) or mod[1] == 0: modifications.append(mod) # check presets if not modifications: wx.Bell() - dlg = mwx.dlgMessage(self, title="Global modifications not found.", message='Global modifications only can be saved in presets.') + dlg = mwx.dlgMessage(self, title="Presets cannot be saved.", message='Global and N-terminal modifications can only be saved in presets.') dlg.ShowModal() dlg.Destroy() return @@ -2333,7 +2758,13 @@ self.currentDigest = [] # digest sequence - peptides = self.currentSequence.digest(enzyme=config.sequence['digest']['enzyme'], miscleavage=config.sequence['digest']['miscl'], allowMods=config.sequence['digest']['allowMods'], strict=False) + peptides = mspy.digest( + sequence = self.currentSequence, + enzyme = config.sequence['digest']['enzyme'], + miscleavage = config.sequence['digest']['miscl'], + allowMods = config.sequence['digest']['allowMods'], + strict = False + ) # do not cleave if modified enzyme = config.sequence['digest']['enzyme'] @@ -2352,6 +2783,11 @@ polarity = -1 maxCharge = abs(config.sequence['digest']['maxCharge'])+1 + # get list template + template = config.sequence['digest']['listTemplateAmino'] + if self.currentSequence.chainType != 'aminoacids': + template = config.sequence['digest']['listTemplateCustom'] + # calculate mz and check limits buff = [] for peptide in peptides: @@ -2362,11 +2798,11 @@ mz = peptide.mz(z*polarity)[config.sequence['digest']['massType']] if mz >= config.sequence['digest']['lowMass'] and mz <= config.sequence['digest']['highMass']: buff.append([ - peptide.userRange, + peptide.history, peptide.miscleavages, mz, z*polarity, - peptide.format(config.sequence['digest']['listFormat']), + peptide.format(template), None, peptide, [], @@ -2388,45 +2824,84 @@ self.currentFragments = [] - # get fragment types + # get fragment series series = [] - + if 'M' in config.sequence['fragment']['fragments']: + series.append('M') + if 'im' in config.sequence['fragment']['fragments']: + series.append('im') if 'a' in config.sequence['fragment']['fragments']: series.append('a') if 'b' in config.sequence['fragment']['fragments']: series.append('b') - if 'y' in config.sequence['fragment']['fragments']: - series.append('y') - if 'int' in config.sequence['fragment']['fragments']: - series.append('int') - - for serie in series[:]: - if '-H2O' in config.sequence['fragment']['fragments']: - series.append(serie+'-H2O') - if '-NH3' in config.sequence['fragment']['fragments']: - series.append(serie+'-NH3') - if '-H3PO4' in config.sequence['fragment']['fragments']: - series.append(serie+'-H3PO4') - if 'c' in config.sequence['fragment']['fragments']: series.append('c') if 'x' in config.sequence['fragment']['fragments']: series.append('x') + if 'y' in config.sequence['fragment']['fragments']: + series.append('y') if 'z' in config.sequence['fragment']['fragments']: series.append('z') - if 'im' in config.sequence['fragment']['fragments']: - series.append('im') - if 'int-CO' in config.sequence['fragment']['fragments']: - series.append('int-CO') + if 'int-b' in config.sequence['fragment']['fragments']: + series.append('int-b') + if 'int-a' in config.sequence['fragment']['fragments']: + series.append('int-a') if 'n-ladder' in config.sequence['fragment']['fragments']: series.append('n-ladder') if 'c-ladder' in config.sequence['fragment']['fragments']: series.append('c-ladder') - # fragment sequence - fragments = [] - for serie in series: - fragments += self.currentSequence.fragment(serie) + # get losses + userLosses = [] + definedLosses = False + if '-H2O' in config.sequence['fragment']['fragments']: + userLosses.append('H2O') + if '-NH3' in config.sequence['fragment']['fragments']: + userLosses.append('NH3') + if '-CO' in config.sequence['fragment']['fragments']: + userLosses.append('CO') + if '-H3PO4' in config.sequence['fragment']['fragments']: + userLosses.append('H3PO4') + if 'losses' in config.sequence['fragment']['fragments']: + definedLosses = True + + # get gains + userGains = [] + if '+H2O' in config.sequence['fragment']['fragments']: + userGains.append('H2O') + if '+CO' in config.sequence['fragment']['fragments']: + userGains.append('CO') + + # get scrambling + scrambling = False + if 'scrambling' in config.sequence['fragment']['fragments']: + scrambling = True + + # get loss combinations + maxLosses = 1 + if 'losscombi' in config.sequence['fragment']['fragments']: + maxLosses = config.sequence['fragment']['maxLosses'] + + # generate basic fragments + fragments = mspy.fragment( + sequence = self.currentSequence, + series = series, + scrambling = scrambling + ) + + # apply neutral losses + fragments += mspy.fragmentLosses( + fragments = fragments, + losses = userLosses, + defined = definedLosses, + limit = maxLosses + ) + + # apply neutral gains + fragments += mspy.fragmentGains( + fragments = fragments, + gains = userGains, + ) # variate mods buff = [] @@ -2440,7 +2915,12 @@ polarity = -1 maxCharge = abs(config.sequence['fragment']['maxCharge'])+1 - # calculate mz + # get list template + template = config.sequence['fragment']['listTemplateAmino'] + if self.currentSequence.chainType != 'aminoacids': + template = config.sequence['fragment']['listTemplateCustom'] + + # calculate mz and store fragments buff = [] for fragment in fragments: for z in range(1, maxCharge): @@ -2449,12 +2929,11 @@ if not config.sequence['fragment']['filterFragments'] or not fragment.fragmentFiltered: buff.append([ - fragment.fragmentSerie, - fragment.fragmentIndex, - fragment.userRange, + fragment.format('f'), + fragment.history, fragment.mz(z*polarity)[config.sequence['fragment']['massType']], z*polarity, - fragment.format(config.sequence['fragment']['listFormat']), + fragment.format(template), None, fragment, [], @@ -2477,26 +2956,31 @@ self.currentSearch = [] # search sequence - peptides = self.currentSequence.search(\ - mass=config.sequence['search']['mass'], \ - charge=config.sequence['search']['charge'], \ - tolerance=config.sequence['search']['tolerance'], \ - enzyme=config.sequence['search']['enzyme'], \ - semiSpecific=config.sequence['search']['semiSpecific'], \ - tolUnits=config.sequence['search']['units'], \ - massType=config.sequence['search']['massType'], \ - maxMods=config.sequence['search']['maxMods'], \ - position=config.sequence['search']['retainPos']\ + peptides = self.currentSequence.search( + mass = config.sequence['search']['mass'], + charge = config.sequence['search']['charge'], + tolerance = config.sequence['search']['tolerance'], + enzyme = config.sequence['search']['enzyme'], + semiSpecific = config.sequence['search']['semiSpecific'], + tolUnits = config.sequence['search']['units'], + massType = config.sequence['search']['massType'], + maxMods = config.sequence['search']['maxMods'], + position = config.sequence['search']['retainPos'] ) + # get list template + template = config.sequence['search']['listTemplateAmino'] + if self.currentSequence.chainType != 'aminoacids': + template = config.sequence['search']['listTemplateCustom'] + buff = [] for peptide in peptides: mz = peptide.mz(config.sequence['search']['charge'])[config.sequence['search']['massType']] buff.append([ - peptide.userRange, + peptide.history, mz, config.sequence['search']['charge'], - peptide.format(config.sequence['search']['listFormat']), + peptide.format(template), mspy.delta(mz, config.sequence['search']['mass'], config.sequence['search']['units']), peptide, ]) @@ -2515,19 +2999,25 @@ # ---- - def checkModifications(self, currentSequence, modification, maxMods): + def checkModifications(self, sequence, modification, maxMods): """Do not allow multiple modifications on single residue.""" + # check same modifications + if str(modification[1]).isdigit(): + modification[1] = int(modification[1]) + if modification in sequence.modifications: + return False + # get occupied positions occupied = [] - for mod in currentSequence.modifications: + for mod in sequence.modifications: if mod[2] == 'f': - count = max(1, currentSequence.count(str(mod[1]))) + count = max(1, sequence.count(str(mod[1]))) occupied += [mod[1]]*count # apply current modification if modification[2] == 'f': - count = max(1, currentSequence.count(str(modification[1]))) + count = max(1, sequence.count(str(modification[1]))) occupied += [modification[1]]*count else: occupied.append(modification[1]) @@ -2536,14 +3026,14 @@ for x in occupied: count = occupied.count(x) if type(x) == int: - if count>maxMods: + if count > maxMods: return False elif type(x) in (str, unicode): - available = currentSequence.count(x) + available = sequence.count(x) for y in occupied: - if type(y) == int and currentSequence[y] == x: + if type(y) == int and sequence[y] == x: available -= 1 - if count>(available*maxMods): + if count > (available*maxMods): return False return True @@ -2553,7 +3043,7 @@ class sequenceCanvas(wx.TextCtrl): - """Sequence editor canvas.""" + """Sequence editor canvas for amino acids.""" def __init__(self, parent, id, sequence=None, size=(-1,-1), style=wx.TE_MULTILINE|wx.TE_RICH): wx.TextCtrl.__init__(self, parent, id, size=size, style=style) @@ -2566,8 +3056,12 @@ self.currentSequence = sequence elif sequence == None: self.currentSequence = mspy.sequence('') - elif type(sequence) in (str, unicode): - self.currentSequence = mspy.sequence(sequence) + + # get regular amino acids + self._aminoacids = [] + for abbr in mspy.monomers: + if mspy.monomers[abbr].category == '_InternalAA': + self._aminoacids.append(abbr) # set events self.Bind(wx.EVT_KEY_DOWN, self._onKey) @@ -2581,7 +3075,7 @@ self.SetDefaultStyle(self.styles['default']) # show current sequence - self.updateCanvas() + self.refresh() # ---- @@ -2679,9 +3173,9 @@ curSelection = self.GetSelection() seqSelection = self._positionEditorToSequence(curSelection) - if char in mspy.aminoacids: + if char in self._aminoacids: self.currentSequence[seqSelection[0]:seqSelection[1]] = mspy.sequence(char) - self.updateCanvas() + self.refresh() self.setInsertionPoint(seqSelection[0]+1) self.modified = True else: @@ -2714,10 +3208,10 @@ curSelection = self.GetSelection() seqSelection = self._positionEditorToSequence(curSelection) - sequence = self.getSequenceFromClipboard() + sequence = self._getSequenceFromClipboard() if sequence: self.currentSequence[seqSelection[0]:seqSelection[1]] = sequence - self.updateCanvas() + self.refresh() self.setInsertionPoint(seqSelection[0]+len(sequence)) self.modified = True @@ -2752,7 +3246,7 @@ else: del self.currentSequence[seqSelection[0]:seqSelection[1]] - self.updateCanvas() + self.refresh() self.setInsertionPoint(seqSelection[0]) self.modified = True # ---- @@ -2766,12 +3260,12 @@ if seqSelection[0] == seqSelection[1] and seqSelection[0] != 0: del self.currentSequence[seqSelection[0]-1:seqSelection[1]] - self.updateCanvas() + self.refresh() self.setInsertionPoint(seqSelection[0]-1) self.modified = True else: del self.currentSequence[seqSelection[0]:seqSelection[1]] - self.updateCanvas() + self.refresh() self.setInsertionPoint(seqSelection[0]) self.modified = True # ---- @@ -2783,6 +3277,37 @@ # ---- + def _updateCanvas(self): + """Show current sequence in canvas.""" + + # check sequence + if self.currentSequence == None: + self.ChangeValue('') + return + + # format sequence + sequence = '' + modifications = [] + for x, amino in enumerate(self.currentSequence): + sequence += amino + if not (x+1) % 10: + sequence += ' ' + if self.currentSequence.ismodified(x, True): + modifications.append(x) + + # update sequence + self.ChangeValue(sequence) + + # set default style + self.SetStyle(0, len(sequence), self.styles['default']) + + # highlight modifications + for pos in modifications: + x, y = self._positionSequenceToEditor([pos, pos]) + self.SetStyle(x, x+1, self.styles['modified']) + # ---- + + def _positionEditorToSequence(self, selection): """Get sequence coordinates for editor selection.""" @@ -2805,22 +3330,61 @@ # ---- + def _getSequenceFromClipboard(self): + """Get sequence from clipboard.""" + + # get data from clipboard + success = False + data = wx.TextDataObject() + if wx.TheClipboard.Open(): + success = wx.TheClipboard.GetData(data) + wx.TheClipboard.Close() + + # parse sequence if data in clipboard + if success: + + # get text from clipboard + data = data.GetText() + + # remove whitespaces + for char in ('\t','\n','\r','\f','\v', ' ', '-', '*', '.'): + data = data.replace(char, '') + + # remove numbers + for char in ('0','1','2','3','4','5','6','7','8','9'): + data = data.replace(char, '') + + # make sequence object + try: + sequence = mspy.sequence(data) + return sequence + except: + pass + + wx.Bell() + return False + # ---- + + def setData(self, sequence): """Set sequence object.""" - # make sequence - if isinstance(sequence, mspy.sequence): - self.currentSequence = sequence - elif sequence == None: - self.currentSequence = mspy.sequence('') - elif type(sequence) in (str, unicode): - self.currentSequence = mspy.sequence(sequence) + # set current sequence + self.currentSequence = sequence - # set modified - self.modified = True + # disable editor + if self.currentSequence == None: + self.refresh() + self.enable(False) + return + + # check sequence + if not isinstance(sequence, mspy.sequence): + raise TypeError, 'Sequence must be mspy.sequence object!' # update gui - self.updateCanvas() + self.enable(True) + self.refresh() # ---- @@ -2850,71 +3414,246 @@ # ---- - def getSequenceFromClipboard(self): - """Get sequence from clipboard.""" + def enable(self, enable=True): + """Enable or disable editor.""" + self.Enable(enable) + # ---- + + + def refresh(self): + """Redraw current sequence.""" + self._updateCanvas() + # ---- + + + def ismodified(self): + """Modified status.""" + return self.modified + # ---- + + + + +class sequenceGrid(wx.StaticBoxSizer): + """Sequence editor for all monomers.""" + + def __init__(self, parent, panel, sequence=None, items=20): + wx.StaticBoxSizer.__init__(self, wx.StaticBox(panel, -1, ""), wx.VERTICAL) - # get data from clipboard - success = False - data = wx.TextDataObject() - if wx.TheClipboard.Open(): - success = wx.TheClipboard.GetData(data) - wx.TheClipboard.Close() + self.parent = parent + self.panel = panel + self.modified = False - # parse sequence if data in clipboard - if success: - - # get text from clipboard - data = data.GetText() - - # remove whitespaces - for char in ('\t','\n','\r','\f','\v', ' ', '-', '*', '.'): - data = data.replace(char, '') - - # remove numbers - for char in ('0','1','2','3','4','5','6','7','8','9'): - data = data.replace(char, '') + self.items = [] + + # make sequence + if isinstance(sequence, mspy.sequence): + self.currentSequence = sequence + elif sequence == None: + self.currentSequence = mspy.sequence('') + + # make items grid + items = max(items, len(self.currentSequence)) + self._makeGUI(items) + # -- + + + def _onSequence(self, evt=None): + """Get current sequence from grid.""" + + self.modified = True + + # get sequence + sequence = [] + gap = False + for x, item in enumerate(self.items): + monomer = item.GetValue() + + if not monomer: + gap = True + item.SetBackgroundColour(wx.NullColour) + elif not monomer in mspy.monomers: + gap = True + item.SetBackgroundColour((250,100,100)) + elif not gap: + sequence.append(monomer) + item.SetBackgroundColour(wx.NullColour) + else: + item.SetBackgroundColour(wx.NullColour) - # make sequence object - try: - sequence = mspy.sequence(data) - return sequence - except: - pass + item.Refresh() - wx.Bell() - return False + # update sequence + self.currentSequence[:] = mspy.sequence(sequence, chainType='custom') + + # lock items + self._lockItems() + + # send notification up + self.parent.onSequenceChanged() # ---- - def updateCanvas(self): - """Show current sequence in canvas.""" + def _makeGUI(self, items): + """Make monomer items.""" - # format and sequence - sequence = '' - modifications = [] - for x, amino in enumerate(self.currentSequence): - sequence += amino - if not (x+1) % 10: - sequence += ' ' - if self.currentSequence.ismodified(x, True): - modifications.append(x) + # make items grid + self.grid = wx.GridBagSizer(mwx.GRIDBAG_VSPACE, mwx.GRIDBAG_HSPACE) + self.grid.AddGrowableCol(1) + self.grid.AddGrowableCol(3) + self.grid.AddGrowableCol(5) + self.grid.AddGrowableCol(7) + self.grid.AddGrowableCol(9) - # update sequence - self.ChangeValue(sequence) + # make items + while len(self.items) < items: + self.addRow() - # set default style - self.SetStyle(0, len(sequence), self.styles['default']) + # add to self + self.Add(self.grid, 1, wx.EXPAND|wx.ALIGN_CENTER|wx.ALL, 10) - # highlight modifications - for pos in modifications: - x, y = self._positionSequenceToEditor([pos, pos]) - self.SetStyle(x, x+1, self.styles['modified']) + # lock items + self._lockItems() + # ---- + + + def _updateGrid(self): + """Show current sequence in grid.""" + + # clear items + for item in self.items: + item.ChangeValue('') + item.SetBackgroundColour(wx.NullColour) + + # update items + if self.currentSequence != None: + for x, monomer in enumerate(self.currentSequence): + self.items[x].ChangeValue(monomer) + + # lock items + self._lockItems() + # ---- + + + def _lockItems(self): + """Disable unset items.""" + + # check sequence + if self.currentSequence == None: + for item in self.items: + item.Disable() + item.SetBackgroundColour((230,230,230)) + return + + # enable/disable items + length = len(self.currentSequence) + end = 0 + for x in reversed(range(len(self.items))): + item = self.items[x] + value = self.items[x].GetValue() + + # set sequence end by last specified item + if x > end and value: + end = x + + # value specified + if value: + item.Enable() + + # space right next to the sequence + elif x == length and x > end: + item.Enable() + self.items[x].SetBackgroundColour(wx.NullColour) + + # space out of specified sequence + elif x > end: + item.Disable() + self.items[x].SetBackgroundColour((230,230,230)) + + # gap + elif x < end: + item.Enable() + self.items[x].SetBackgroundColour((240,100,100)) + # ---- + + + def setData(self, sequence): + """Set sequence object.""" + + # set current sequence + self.currentSequence = sequence + + # disable editor + if self.currentSequence == None: + self.refresh() + self.enable(False) + return + + # check sequence + if not isinstance(sequence, mspy.sequence): + raise TypeError, 'Sequence must be mspy.sequence object!' + + # check number of items + while len(self.currentSequence) - len(self.items) > 0: + self.addRow() + + # update gui + self.enable(True) + self.refresh() + # ---- + + + def setModified(self, status=True): + """Set modified status.""" + self.modified = status + # ---- + + + def getData(self): + """Get current sequence.""" + return self.currentSequence + # ---- + + + def addRow(self): + """Append new row of items.""" + + length = len(self.items) + for x in range(5): + + # make item + item = wx.TextCtrl(self.panel, -1, '', size=(85, -1)) + item.Bind(wx.EVT_TEXT, self._onSequence) + dropTarget = monomerDropTarget(item) + item.SetDropTarget(dropTarget) + self.items.append(item) + + # add to grid + row = (length + x) / 5 + col = 2 * (x % 5) + + label = wx.StaticText(self.panel, -1, str(length+x+1)) + label.SetFont(wx.SMALL_FONT) + + self.grid.Add(label, (row, col), flag=wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL) + self.grid.Add(item, (row, col+1), flag=wx.EXPAND) + # ---- + + + def enable(self, enable=True): + """Enable or disable editor.""" + + for item in self.items: + item.Enable(enable) + + if enable: + self._lockItems() # ---- def refresh(self): """Redraw current sequence.""" - self.updateCanvas() + self._updateGrid() # ---- @@ -2986,3 +3725,29 @@ wx.Bell() # ---- + + + +class monomerDropTarget(wx.TextDropTarget): + """Monomer droptarget definition.""" + + def __init__(self, item): + wx.TextDropTarget.__init__(self) + self.item = item + # ---- + + + def OnDropText(self, x, y, text): + if not self.item.IsEnabled(): + wx.Bell() + return wx.DragNone + elif wx.Platform == '__WXGTK__': + self.item.SetValue('') + return + else: + self.item.SetValue(text) + return wx.DragCopy + # ---- + + + diff -Nru mmass-3.12.1/gui/panel_spectrum_generator.py mmass-4.0.0/gui/panel_spectrum_generator.py --- mmass-3.12.1/gui/panel_spectrum_generator.py 2011-06-30 11:56:13.000000000 +0000 +++ mmass-4.0.0/gui/panel_spectrum_generator.py 2011-11-29 14:55:09.000000000 +0000 @@ -78,9 +78,8 @@ # fit layout self.mainSizer.Fit(self) self.SetSizer(self.mainSizer) - size = self.GetSize() - self.SetSize((size[0],size[1]+1)) # layout hack self.SetMinSize(self.GetSize()) + mwx.layout(self, self.mainSizer) # ---- @@ -91,7 +90,7 @@ panel = mwx.bgrPanel(self, -1, images.lib['bgrToolbar'], size=(-1, mwx.TOOLBAR_HEIGHT)) # make elements - fwhm_label = wx.StaticText(panel, -1, "Default FWHM:") + fwhm_label = wx.StaticText(panel, -1, "FWHM:") fwhm_label.SetFont(wx.SMALL_FONT) self.fwhm_value = wx.TextCtrl(panel, -1, str(config.generator['fwhm']), size=(60, -1), validator=mwx.validator('floatPos')) @@ -204,6 +203,7 @@ self.spectrumCanvas.setProperties(showCurXPos=True) self.spectrumCanvas.setProperties(showCurYPos=True) self.spectrumCanvas.setProperties(showCurCharge=True) + self.spectrumCanvas.setProperties(reverseScrolling=config.main['reverseScrolling']) self.spectrumCanvas.setProperties(reverseDrawing=True) self.spectrumCanvas.setLMBFunction('xDistance') @@ -513,16 +513,17 @@ # add main profile spectrum to container labelFont = wx.Font(config.spectrum['labelFontSize'], wx.SWISS, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, 0) - spectrum = mspy.plot.spectrum(mspy.scan(points=profile, peaks=peaklist), \ - spectrumColour=(16,71,185), \ - tickColour=(255,0,0), \ - showPoints=config.spectrum['showDataPoints'], \ - showLabels=config.spectrum['showLabels'], \ - showTicks=True, \ - labelDigits=config.main['mzDigits'], \ - labelBgr=config.spectrum['labelBgr'], \ - labelAngle=config.spectrum['labelAngle'], - labelFont=labelFont + spectrum = mspy.plot.spectrum( + scan = mspy.scan(points=profile, peaks=peaklist), + spectrumColour = (16,71,185), + tickColour = (255,0,0), + showPoints = config.spectrum['showDataPoints'], + showLabels = config.spectrum['showLabels'], + showTicks = True, + labelDigits = config.main['mzDigits'], + labelBgr = config.spectrum['labelBgr'], + labelAngle = config.spectrum['labelAngle'], + labelFont = labelFont ) self.spectrumContainer.append(spectrum) @@ -530,11 +531,12 @@ if config.generator['showPeaks']: if self.currentPeaks != None: for peak in self.currentPeaks: - spectrum = mspy.plot.points(peak, \ - lineColour=(50,140,0), \ - showLines=True, \ - showPoints=False, \ - exactFit=True + spectrum = mspy.plot.points( + points = peak, + lineColour = (50,140,0), + showLines = True, + showPoints = False, + exactFit = True ) self.spectrumContainer.append(spectrum) @@ -572,12 +574,12 @@ try: # make profile spectrum - self.currentProfile = mspy.profile( \ - peaklist=self.currentDocument.spectrum.peaklist, \ - fwhm=config.generator['fwhm'], \ - points=config.generator['points'], \ - noise=config.generator['noise'], \ - forceFwhm=config.generator['forceFwhm'] \ + self.currentProfile = mspy.profile( + peaklist = self.currentDocument.spectrum.peaklist, + fwhm = config.generator['fwhm'], + points = config.generator['points'], + noise = config.generator['noise'], + forceFwhm = config.generator['forceFwhm'] ) # make peak spectra @@ -590,11 +592,11 @@ fwhm = peak.fwhm # calc peak - points = mspy.gaussian( \ - mz=peak.mz, \ - ai=peak.ai, \ - base=peak.base, \ - fwhm=fwhm \ + points = mspy.gaussian( + mz = peak.mz, + ai = peak.ai, + base = peak.base, + fwhm = fwhm ) self.currentPeaks.append(points) diff -Nru mmass-3.12.1/gui/panel_spectrum.py mmass-4.0.0/gui/panel_spectrum.py --- mmass-3.12.1/gui/panel_spectrum.py 2011-06-29 11:42:48.000000000 +0000 +++ mmass-4.0.0/gui/panel_spectrum.py 2011-11-30 12:59:27.000000000 +0000 @@ -110,6 +110,8 @@ self.spectrumCanvas.setProperties(xPosDigits=config.main['mzDigits']) self.spectrumCanvas.setProperties(yPosDigits=config.main['intDigits']) self.spectrumCanvas.setProperties(distanceDigits=config.main['mzDigits']) + self.spectrumCanvas.setProperties(checkLimits=True) + self.spectrumCanvas.setProperties(reverseScrolling=config.main['reverseScrolling']) self.spectrumCanvas.setProperties(reverseDrawing=True) axisFont = wx.Font(config.spectrum['axisFontSize'], wx.SWISS, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, 0) @@ -133,10 +135,6 @@ panel = mwx.bgrPanel(self, -1, images.lib['bgrBottombar'], size=(-1, mwx.BOTTOMBAR_HEIGHT)) # make canvas toolset - self.canvasParameters_butt = wx.BitmapButton(panel, ID_viewCanvasProperties, images.lib['spectrumParams'], size=(mwx.BOTTOMBAR_TOOLSIZE), style=wx.BORDER_NONE) - self.canvasParameters_butt.SetToolTip(wx.ToolTip("Canvas properties...")) - self.canvasParameters_butt.Bind(wx.EVT_BUTTON, self.onCanvasProperties) - image = (images.lib['spectrumLabelsOff'], images.lib['spectrumLabelsOn'])[config.spectrum['showLabels']] self.showLabels_butt = wx.BitmapButton(panel, ID_viewLabels, image, size=(mwx.BOTTOMBAR_TOOLSIZE), style=wx.BORDER_NONE) self.showLabels_butt.SetToolTip(wx.ToolTip("Show / hide labels")) @@ -214,8 +212,7 @@ # pack elements sizer = wx.BoxSizer(wx.HORIZONTAL) sizer.AddSpacer(mwx.BOTTOMBAR_LSPACE) - sizer.Add(self.canvasParameters_butt, 0, wx.ALIGN_CENTER_VERTICAL) - sizer.Add(self.showLabels_butt, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, mwx.BUTTON_SIZE_CORRECTION) + sizer.Add(self.showLabels_butt, 0, wx.ALIGN_CENTER_VERTICAL) sizer.Add(self.showTicks_butt, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, mwx.BUTTON_SIZE_CORRECTION) sizer.Add(self.showNotations_butt, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, mwx.BUTTON_SIZE_CORRECTION) sizer.Add(self.labelAngle_butt, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, mwx.BUTTON_SIZE_CORRECTION) @@ -438,6 +435,7 @@ spectrum.setProperties(labelCharge=config.spectrum['labelCharge']) spectrum.setProperties(labelDigits=config.main['mzDigits']) spectrum.setProperties(labelBgr=config.spectrum['labelBgr']) + spectrum.setProperties(isotopeColour=None) labelFont = wx.Font(config.spectrum['labelFontSize'], wx.SWISS, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, 0) spectrum.setProperties(labelFont=labelFont) @@ -553,6 +551,9 @@ ppmFormat = '%0.' + `config.main['ppmDigits']` + 'f' chargeFormat = '%d' + if position and abs(position[1]) > 10000: + intFormat = '%.2e' + # offset dragging if self.currentTool == 'offset' and distance and position: format = 'a.i.: %s dist: %s' % (intFormat, intFormat) @@ -566,8 +567,11 @@ # distance measurement elif distance and position: - format = 'm/z: %s dist: %s ppm: %s' % (mzFormat, mzFormat, ppmFormat) - label += format % (position[0], distance[0], 1e6*distance[0]/position[0]) + charge = 0 + if distance[0]: + charge = int(abs(round(1/distance[0],0))) + format = 'm/z: %s dist: %s ppm: %s z: %s' % (mzFormat, mzFormat, ppmFormat, chargeFormat) + label += format % (position[0], distance[0], 1e6*distance[0]/position[0], charge*polarity) # no specific fce elif position: @@ -611,17 +615,18 @@ flipped = self.documents[self.currentDocument].flipped # make tmp spectrum - obj = mspy.plot.points(points, \ - normalized=config.spectrum['normalize'], \ - flipped=flipped, \ - xOffset=xOffset, \ - yOffset=yOffset, \ - showInGel=False, \ - showLines=True, \ - showPoints=False, \ - exactFit=True, \ - pointColour=config.spectrum['tmpSpectrumColour'], \ - lineColour=config.spectrum['tmpSpectrumColour'] \ + obj = mspy.plot.points( + points = points, + normalized = config.spectrum['normalize'], + flipped = flipped, + xOffset = xOffset, + yOffset = yOffset, + showInGel = False, + showLines = True, + showPoints = False, + exactFit = True, + pointColour = config.spectrum['tmpSpectrumColour'], + lineColour = config.spectrum['tmpSpectrumColour'] ) # set normalization @@ -667,22 +672,23 @@ # add points to container labelFont = wx.Font(config.spectrum['labelFontSize'], wx.SWISS, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, 0) - obj = mspy.plot.annotations(notations, \ - normalized=config.spectrum['normalize'], \ - flipped=flipped, \ - xOffset=xOffset, \ - yOffset=yOffset, \ - exactFit=True, \ - showInGel=False, \ - showPoints=config.spectrum['notationMarks'], \ - showLabels=config.spectrum['notationLabels'], \ - showXPos=config.spectrum['notationMZ'], \ - xPosDigits=config.main['mzDigits'], \ - pointColour=config.spectrum['notationMarksColour'], \ - labelAngle=config.spectrum['labelAngle'], \ - labelBgr=config.spectrum['labelBgr'], \ - labelFont=labelFont, \ - labelMaxLength=config.spectrum['notationMaxLength'], \ + obj = mspy.plot.annotations( + points = notations, + normalized = config.spectrum['normalize'], + flipped = flipped, + xOffset = xOffset, + yOffset = yOffset, + exactFit = True, + showInGel = False, + showPoints = config.spectrum['notationMarks'], + showLabels = config.spectrum['notationLabels'], + showXPos = config.spectrum['notationMZ'], + xPosDigits = config.main['mzDigits'], + pointColour = config.spectrum['notationMarksColour'], + labelAngle = config.spectrum['labelAngle'], + labelBgr = config.spectrum['labelBgr'], + labelFont = labelFont, + labelMaxLength = config.spectrum['notationMaxLength'] ) # set normalization @@ -818,19 +824,19 @@ baselineWindow = 1./config.processing['baseline']['precision'] # get baseline - baseline = self.documents[self.currentDocument].spectrum.baseline(\ - window=baselineWindow, \ - smooth=True, \ - offset=config.processing['baseline']['offset'] \ + baseline = self.documents[self.currentDocument].spectrum.baseline( + window = baselineWindow, + smooth = True, + offset = config.processing['baseline']['offset'] ) # label peak - peak = mspy.labelPeak(\ - points=self.documents[self.currentDocument].spectrum.points, \ - minX=selection[0], \ - maxX=selection[2], \ - pickingHeight=config.processing['peakpicking']['pickingHeight'], \ - baselineData=baseline \ + peak = mspy.labelPeak( + points = self.documents[self.currentDocument].spectrum.points, + minX = selection[0], + maxX = selection[2], + pickingHeight = config.processing['peakpicking']['pickingHeight'], + baselineData = baseline ) if peak: @@ -859,17 +865,17 @@ baselineWindow = 1./config.processing['baseline']['precision'] # get baseline - baseline = self.documents[self.currentDocument].spectrum.baseline(\ - window=baselineWindow, \ - smooth=True, \ - offset=config.processing['baseline']['offset'] \ + baseline = self.documents[self.currentDocument].spectrum.baseline( + window = baselineWindow, + smooth = True, + offset = config.processing['baseline']['offset'] ) # label point - peak = mspy.labelPoint(\ - points=self.documents[self.currentDocument].spectrum.points, \ - mz=mz, \ - baselineData=baseline \ + peak = mspy.labelPoint( + points = self.documents[self.currentDocument].spectrum.points, + mz = mz, + baselineData = baseline ) if peak: @@ -898,21 +904,21 @@ baselineWindow = 1./config.processing['baseline']['precision'] # get baseline - baseline = self.documents[self.currentDocument].spectrum.baseline(\ - window=baselineWindow, \ - smooth=True, \ - offset=config.processing['baseline']['offset'] \ + baseline = self.documents[self.currentDocument].spectrum.baseline( + window = baselineWindow, + smooth = True, + offset = config.processing['baseline']['offset'] ) # label isotopes peaks = [] buff = [] for isotope in isotopes: - peak = mspy.labelPeak(\ - points=self.documents[self.currentDocument].spectrum.points, \ - mz=isotope, \ - pickingHeight=config.processing['peakpicking']['pickingHeight'], \ - baselineData=baseline \ + peak = mspy.labelPeak( + points = self.documents[self.currentDocument].spectrum.points, + mz = isotope, + pickingHeight = config.processing['peakpicking']['pickingHeight'], + baselineData = baseline ) if peak and not peak.mz in buff: peaks.append(peak) @@ -930,17 +936,8 @@ if self.documents[self.currentDocument].spectrum.polarity == -1: polarity = -1 - # label all isotopes - if config.processing['deisotoping']['labelEnvelope'] == 'isotopes': - groupname = self.documents[self.currentDocument].spectrum.peaklist.nextGroupName() - for x, peak in enumerate(peaks): - peak.setIsotope(x) - peak.setCharge(charge*polarity) - peak.setGroup(groupname) - self.documents[self.currentDocument].spectrum.peaklist.append(peak) - - # label monoisotopic peak - elif config.processing['deisotoping']['labelEnvelope'] == 'monoisotopic': + # label 1st isotope + if config.processing['deisotoping']['labelEnvelope'] == '1st': basepeak = peaks[0] sumIntensity = 0 @@ -963,17 +960,25 @@ ai = base + sumIntensity / len(isotopes) sn = (ai - base) * basepeak.sn / (basepeak.ai - basepeak.base) - peak = mspy.peak(mz=peaks[0].mz, \ - ai=ai, \ - base=base, \ - sn=sn, \ - charge=charge*polarity, \ - isotope=0, \ - fwhm=None \ + peak = mspy.peak( + mz = peaks[0].mz, + ai = ai, + base = base, + sn = sn, + charge = charge*polarity, + isotope = 0, + fwhm = None ) self.documents[self.currentDocument].spectrum.peaklist.append(peak) + # label monoisotopic peak + elif config.processing['deisotoping']['labelEnvelope'] == 'monoisotope': + peak = mspy.envelopeMonoisotope(peaks, charge=charge*polarity, intensity=config.processing['deisotoping']['envelopeIntensity']) + if peak: + peak.setCharge(charge*polarity) + self.documents[self.currentDocument].spectrum.peaklist.append(peak) + # label envelope centroid elif config.processing['deisotoping']['labelEnvelope'] == 'centroid': peak = mspy.envelopeCentroid(peaks, height=0.5, intensity=config.processing['deisotoping']['envelopeIntensity']) @@ -981,6 +986,15 @@ peak.setCharge(charge*polarity) self.documents[self.currentDocument].spectrum.peaklist.append(peak) + # label all isotopes + if config.processing['deisotoping']['labelEnvelope'] == 'isotopes': + groupname = self.documents[self.currentDocument].spectrum.peaklist.nextGroupName() + for x, peak in enumerate(peaks): + peak.setIsotope(x) + peak.setCharge(charge*polarity) + peak.setGroup(groupname) + self.documents[self.currentDocument].spectrum.peaklist.append(peak) + # update gui self.parent.onDocumentChanged(('spectrum')) # ---- diff -Nru mmass-3.12.1/mspy/blocks.py mmass-4.0.0/mspy/blocks.py --- mmass-3.12.1/mspy/blocks.py 2011-06-14 14:24:52.000000000 +0000 +++ mmass-4.0.0/mspy/blocks.py 2011-11-28 17:23:11.000000000 +0000 @@ -37,7 +37,7 @@ isotopes: (dict) dict of isotopes {mass number:(mass, abundance),...} """ - def __init__(self, name='', symbol='', atomicNumber='', isotopes={}): + def __init__(self, name, symbol, atomicNumber, isotopes={}): self.name = name self.symbol = symbol @@ -62,25 +62,31 @@ -class aminoacid: - """Amino acid object definition. - name: (str) name - symbol: (str) one-letter symbol +class monomer: + """Monomer object definition. + abbr: (str) unique monomer abbreviation formula: (str) molecular formula - abbr: (str) three-letter abbreviation + losses: (list) list of applicable neutral losses + name: (str) name + category: (str) category name """ - def __init__(self, name='', symbol='', formula='', abbr=''): + def __init__(self, abbr, formula, losses=[], name='', category=''): - self.name = name - self.symbol = symbol - self.formula = formula self.abbr = abbr + self.formula = formula + self.losses = losses + self.name = name + self.category = category # init masses and composition cmpd = objects.compound(self.formula) self.composition = cmpd.composition() self.mass = cmpd.mass() + + # check formulae + for loss in losses: + cmpd = objects.compound(loss) # ---- @@ -103,6 +109,10 @@ self.cTermFormula = cTermFormula self.modsBefore = modsBefore self.modsAfter = modsAfter + + # check formulae + cmpd = objects.compound(nTermFormula) + cmpd = objects.compound(cTermFormula) # ---- @@ -110,25 +120,25 @@ class fragment: """Peptide ion fragment object definition. name: (str) name - teminus: (N or C on S or I) fragment type (N-terminal, C-terminal, I-internal, S-single amino) - specifity: (str) specific amino acids for this fragment + teminus: (M or N or C on S or I) fragment type (M-molecular ion, N-terminal, C-terminal, I-internal, S-single amino) nTermFormula: (str) molecular formula of N-terminal gain or loss cTermFormula: (str) molecular formula of C-terminal gain or loss - lossFormula: (str) molecular formula of neutral loss nTermFilter: (bool) filter N-terminal fragment cTermFilter: (bool) filter C-terminal fragment """ - def __init__(self, name='', terminus='', specifity='', nTermFormula='', cTermFormula='', lossFormula='', nTermFilter=False, cTermFilter=False): + def __init__(self, name='', terminus='', nTermFormula='', cTermFormula='', nTermFilter=False, cTermFilter=False): self.name = name self.terminus = terminus - self.specifity = specifity self.nTermFormula = nTermFormula self.cTermFormula = cTermFormula - self.lossFormula = lossFormula self.nTermFilter = nTermFilter self.cTermFilter = cTermFilter + + # check formulae + cmpd = objects.compound(nTermFormula) + cmpd = objects.compound(cTermFormula) # ---- @@ -282,28 +292,30 @@ 'Zr': element( name='Zirconium', symbol='Zr', atomicNumber=40, isotopes={96: (95.908276000000001, 0.028000000000000001), 90: (89.904703699999999, 0.51449999999999996), 91: (90.905645000000007, 0.11219999999999999), 92: (91.905040099999994, 0.17150000000000001), 94: (93.906315800000002, 0.17380000000000001)}), } -aminoacids = { - 'A': aminoacid( name='Alanine', symbol='A', formula='C3H5NO', abbr='Ala'), - 'C': aminoacid( name='Cysteine', symbol='C', formula='C3H5NOS', abbr='Cys'), - 'D': aminoacid( name='Aspartic Acid', symbol='D', formula='C4H5NO3', abbr='Asp'), - 'E': aminoacid( name='Glutamic Acid', symbol='E', formula='C5H7NO3', abbr='Glu'), - 'F': aminoacid( name='Phenylalanine', symbol='F', formula='C9H9NO', abbr='Phe'), - 'G': aminoacid( name='Glycine', symbol='G', formula='C2H3NO', abbr='Gly'), - 'H': aminoacid( name='Histidine', symbol='H', formula='C6H7N3O', abbr='His'), - 'I': aminoacid( name='Isoleucine', symbol='I', formula='C6H11NO', abbr='Ile'), - 'K': aminoacid( name='Lysine', symbol='K', formula='C6H12N2O', abbr='Lys'), - 'L': aminoacid( name='Leucine', symbol='L', formula='C6H11NO', abbr='Leu'), - 'M': aminoacid( name='Methionine', symbol='M', formula='C5H9NSO', abbr='Met'), - 'N': aminoacid( name='Asparagine', symbol='N', formula='C4H6O2N2', abbr='Asn'), - 'O': aminoacid( name='Ornithine', symbol='O', formula='C5H10N2O', abbr='Ort'), - 'P': aminoacid( name='Proline', symbol='P', formula='C5H7NO', abbr='Pro'), - 'Q': aminoacid( name='Glutamine', symbol='Q', formula='C5H8N2O2', abbr='Gln'), - 'R': aminoacid( name='Arginine', symbol='R', formula='C6H12N4O', abbr='Arg'), - 'S': aminoacid( name='Serine', symbol='S', formula='C3H5NO2', abbr='Ser'), - 'T': aminoacid( name='Threonine', symbol='T', formula='C4H7NO2', abbr='Thr'), - 'V': aminoacid( name='Valine', symbol='V', formula='C5H9NO', abbr='Val'), - 'W': aminoacid( name='Tryptophan', symbol='W', formula='C11H10N2O', abbr='Trp'), - 'Y': aminoacid( name='Tyrosine', symbol='Y', formula='C9H9NO2', abbr='Tyr'), +monomers = { + + # regular amino acids for protein and peptide sequences + 'A': monomer( abbr='A', name='Alanine', formula='C3H5NO', category='_InternalAA'), + 'C': monomer( abbr='C', name='Cysteine', formula='C3H5NOS', category='_InternalAA'), + 'D': monomer( abbr='D', name='Aspartic Acid', formula='C4H5NO3', losses=['H2O'], category='_InternalAA'), + 'E': monomer( abbr='E', name='Glutamic Acid', formula='C5H7NO3', losses=['H2O'], category='_InternalAA'), + 'F': monomer( abbr='F', name='Phenylalanine', formula='C9H9NO', category='_InternalAA'), + 'G': monomer( abbr='G', name='Glycine', formula='C2H3NO', category='_InternalAA'), + 'H': monomer( abbr='H', name='Histidine', formula='C6H7N3O', category='_InternalAA'), + 'I': monomer( abbr='I', name='Isoleucine', formula='C6H11NO', category='_InternalAA'), + 'K': monomer( abbr='K', name='Lysine', formula='C6H12N2O', losses=['NH3'], category='_InternalAA'), + 'L': monomer( abbr='L', name='Leucine', formula='C6H11NO', category='_InternalAA'), + 'M': monomer( abbr='M', name='Methionine', formula='C5H9NSO', category='_InternalAA'), + 'N': monomer( abbr='N', name='Asparagine', formula='C4H6O2N2', losses=['NH3'], category='_InternalAA'), + 'O': monomer( abbr='O', name='Ornithine', formula='C5H10N2O', category='_InternalAA'), + 'P': monomer( abbr='P', name='Proline', formula='C5H7NO', category='_InternalAA'), + 'Q': monomer( abbr='Q', name='Glutamine', formula='C5H8N2O2', losses=['NH3'], category='_InternalAA'), + 'R': monomer( abbr='R', name='Arginine', formula='C6H12N4O', losses=['NH3'], category='_InternalAA'), + 'S': monomer( abbr='S', name='Serine', formula='C3H5NO2', losses=['H2O','H3PO4'], category='_InternalAA'), + 'T': monomer( abbr='T', name='Threonine', formula='C4H7NO2', losses=['H2O','H3PO4'], category='_InternalAA'), + 'V': monomer( abbr='V', name='Valine', formula='C5H9NO', category='_InternalAA'), + 'W': monomer( abbr='W', name='Tryptophan', formula='C11H10N2O', category='_InternalAA'), + 'Y': monomer( abbr='Y', name='Tyrosine', formula='C9H9NO2', losses=['H3PO4'], category='_InternalAA'), } enzymes = { @@ -335,29 +347,18 @@ } fragments = { - 'a': fragment( name='a', terminus='N', specifity='', nTermFormula='', cTermFormula='C-1O-1H-1', lossFormula='', nTermFilter=True, cTermFilter=True), - 'a-H2O': fragment( name='a-H2O', terminus='N', specifity='STED', nTermFormula='', cTermFormula='C-1O-1H-1', lossFormula='H2O', nTermFilter=True, cTermFilter=True), - 'a-H3PO4': fragment( name='a-H3PO4', terminus='N', specifity='STY', nTermFormula='', cTermFormula='C-1O-1H-1', lossFormula='H3PO4', nTermFilter=True, cTermFilter=True), - 'a-NH3': fragment( name='a-NH3', terminus='N', specifity='RKQN', nTermFormula='', cTermFormula='C-1O-1H-1', lossFormula='NH3', nTermFilter=True, cTermFilter=True), - 'b': fragment( name='b', terminus='N', specifity='', nTermFormula='', cTermFormula='H-1', lossFormula='', nTermFilter=True, cTermFilter=True), - 'b-H2O': fragment( name='b-H2O', terminus='N', specifity='STED', nTermFormula='', cTermFormula='H-1', lossFormula='H2O', nTermFilter=True, cTermFilter=True), - 'b-H3PO4': fragment( name='b-H3PO4', terminus='N', specifity='STY', nTermFormula='', cTermFormula='H-1', lossFormula='H3PO4', nTermFilter=True, cTermFilter=True), - 'b-NH3': fragment( name='b-NH3', terminus='N', specifity='RKQN', nTermFormula='', cTermFormula='H-1', lossFormula='NH3', nTermFilter=True, cTermFilter=True), - 'c': fragment( name='c', terminus='N', specifity='', nTermFormula='', cTermFormula='NH2', lossFormula='', nTermFilter=True, cTermFilter=True), - 'c-ladder': fragment( name='c-ladder', terminus='N', specifity='', nTermFormula='', cTermFormula='OH', lossFormula='', nTermFilter=False, cTermFilter=True), - 'im': fragment( name='im', terminus='S', specifity='', nTermFormula='H', cTermFormula='C-1O-1H-1', lossFormula='', nTermFilter=True, cTermFilter=False), - 'int': fragment( name='int', terminus='I', specifity='', nTermFormula='H', cTermFormula='H-1', lossFormula='', nTermFilter=False, cTermFilter=False), - 'int-CO': fragment( name='int-CO', terminus='I', specifity='', nTermFormula='H', cTermFormula='C-1O-1H-1', lossFormula='', nTermFilter=False, cTermFilter=False), - 'int-H2O': fragment( name='int-H2O', terminus='I', specifity='STED', nTermFormula='H', cTermFormula='H-1', lossFormula='H2O', nTermFilter=False, cTermFilter=False), - 'int-H3PO4': fragment( name='int-H3PO4', terminus='C', specifity='STY', nTermFormula='H', cTermFormula='H-1', lossFormula='H3PO4', nTermFilter=False, cTermFilter=False), - 'int-NH3': fragment( name='int-NH3', terminus='I', specifity='RKQN', nTermFormula='H', cTermFormula='H-1', lossFormula='NH3', nTermFilter=False, cTermFilter=False), - 'n-ladder': fragment( name='n-ladder', terminus='C', specifity='', nTermFormula='H', cTermFormula='', lossFormula='', nTermFilter=True, cTermFilter=False), - 'x': fragment( name='x', terminus='C', specifity='', nTermFormula='COH-1', cTermFormula='', lossFormula='', nTermFilter=False, cTermFilter=True), - 'y': fragment( name='y', terminus='C', specifity='', nTermFormula='H', cTermFormula='', lossFormula='', nTermFilter=True, cTermFilter=False), - 'y-H2O': fragment( name='y-H2O', terminus='C', specifity='STED', nTermFormula='H', cTermFormula='', lossFormula='H2O', nTermFilter=True, cTermFilter=False), - 'y-H3PO4': fragment( name='y-H3PO4', terminus='C', specifity='STY', nTermFormula='H', cTermFormula='', lossFormula='H3PO4', nTermFilter=True, cTermFilter=False), - 'y-NH3': fragment( name='y-NH3', terminus='C', specifity='RKQN', nTermFormula='H', cTermFormula='', lossFormula='NH3', nTermFilter=True, cTermFilter=False), - 'z': fragment( name='z', terminus='C', specifity='', nTermFormula='N-1H-1', cTermFormula='', lossFormula='', nTermFilter=True, cTermFilter=False), + 'M': fragment( name='M', terminus='M', nTermFilter=False, cTermFilter=False), + 'im': fragment( name='im', terminus='S', nTermFormula='H', cTermFormula='C-1O-1H-1', nTermFilter=False, cTermFilter=False), + 'a': fragment( name='a', terminus='N', cTermFormula='C-1O-1H-1', nTermFilter=True, cTermFilter=True), + 'b': fragment( name='b', terminus='N', cTermFormula='H-1', nTermFilter=True, cTermFilter=True), + 'c': fragment( name='c', terminus='N', cTermFormula='NH2', nTermFilter=False, cTermFilter=True), + 'x': fragment( name='x', terminus='C', nTermFormula='COH-1', nTermFilter=True, cTermFilter=False), + 'y': fragment( name='y', terminus='C', nTermFormula='H', nTermFilter=True, cTermFilter=False), + 'z': fragment( name='z', terminus='C', nTermFormula='N-1H-2', nTermFilter=True, cTermFilter=False), + 'c-ladder': fragment( name='c-ladder', terminus='N', cTermFormula='OH', nTermFilter=True, cTermFilter=True), + 'n-ladder': fragment( name='n-ladder', terminus='C', nTermFormula='H', nTermFilter=True, cTermFilter=False), + 'int-b': fragment( name='int-b', terminus='I', nTermFormula='H', cTermFormula='H-1'), + 'int-a': fragment( name='int-a', terminus='I', nTermFormula='H', cTermFormula='C-1O-1H-1'), } modifications = { @@ -422,89 +423,49 @@ # LOAD FUNCTIONS # -------------- -def loadElements(path=os.path.join(blocksdir, 'elements.xml'), clear=False): - """Parse elements XML and get data.""" +def loadMonomers(path=os.path.join(blocksdir, 'monomers.xml'), clear=False, replace=False): + """Parse monomers XML and get data.""" container = {} # parse XML document = xml.dom.minidom.parse(path) - # get elements - elementTags = document.getElementsByTagName('element') - for x, elementTag in enumerate(elementTags): - - # get symbol, name and atomic number - name = elementTag.getAttribute('name') - symbol = str(elementTag.getAttribute('symbol')) - atomicNumber = elementTag.getAttribute('atomicNumber') - - # get masses - massTags = elementTag.getElementsByTagName('mass') - massMo = float(massTags[0].getAttribute('monoisotopic')) - massAv = float(massTags[0].getAttribute('average')) - mass = (massMo, massAv) - - # get isotopes - isotopes = {} - isotopeTags = elementTag.getElementsByTagName('isotope') - for isotopeTag in isotopeTags: - massNumber = int(isotopeTag.getAttribute('massNumber')) - imass = float(isotopeTag.getAttribute('mass')) - abundance = float(isotopeTag.getAttribute('abundance')) - isotopes[massNumber] = (imass,abundance) - - # add object - container[symbol] = element( \ - name=name, \ - symbol=symbol, \ - atomicNumber=atomicNumber, \ - isotopes=isotopes \ - ) - - # update current lib - if clear: - elements.clear() - for key in container: - elements[key] = container[key] -# ---- - - -def loadAminoacids(path=os.path.join(blocksdir, 'aminoacids.xml'), clear=False): - """Parse amino acid XML and get data.""" - - container = {} - - # parse XML - document = xml.dom.minidom.parse(path) - - # get aminoacids - aminoacidTags = document.getElementsByTagName('aminoacid') - for x, aminoacidTag in enumerate(aminoacidTags): + # get monomers + monomerTags = document.getElementsByTagName('monomer') + for x, monomerTag in enumerate(monomerTags): # get basic data - name = aminoacidTag.getAttribute('name') - symbol = aminoacidTag.getAttribute('symbol') - abbr = aminoacidTag.getAttribute('abbr') - formula = aminoacidTag.getAttribute('formula') + abbr = monomerTag.getAttribute('abbr') + name = monomerTag.getAttribute('name') + category = monomerTag.getAttribute('category') + formula = monomerTag.getAttribute('formula') + + # get losses + losses = [] + attr = monomerTag.getAttribute('losses') + if attr: + losses = attr.split(';') # add object - container[symbol] = aminoacid( \ - name=name, \ - symbol=symbol, \ - formula=formula, \ - abbr=abbr \ + container[abbr] = monomer( + abbr = abbr, + formula = formula, + losses = losses, + name = name, + category = category ) # update current lib - if clear: - aminoacids.clear() + if container and clear: + monomers.clear() for key in container: - aminoacids[key] = container[key] + if replace or not key in monomers: + monomers[key] = container[key] # ---- -def loadEnzymes(path=os.path.join(blocksdir, 'enzymes.xml'), clear=False): +def loadEnzymes(path=os.path.join(blocksdir, 'enzymes.xml'), clear=False, replace=True): """Parse enzymes XML and get data.""" container = {} @@ -534,72 +495,25 @@ modsAfter = bool(int(allowModsTags[0].getAttribute('after'))) # add objects - container[name] = enzyme( \ - name=name, \ - expression=expression, \ - nTermFormula=nTermFormula, \ - cTermFormula=cTermFormula, \ - modsBefore=modsBefore, \ - modsAfter=modsAfter \ + container[name] = enzyme( + name = name, + expression = expression, + nTermFormula = nTermFormula, + cTermFormula = cTermFormula, + modsBefore = modsBefore, + modsAfter = modsAfter ) # update current lib - if clear: + if container and clear: enzymes.clear() for key in container: - enzymes[key] = container[key] -# ---- - - -def loadFragments(path=os.path.join(blocksdir, 'fragments.xml'), clear=False): - """Parse fragments XML and get data.""" - - container = {} - - # parse XML - document = xml.dom.minidom.parse(path) - - # get fragments - fragmentTags = document.getElementsByTagName('fragment') - for x, fragmentTag in enumerate(fragmentTags): - - # get basic data - name = fragmentTag.getAttribute('name') - terminus = fragmentTag.getAttribute('terminus') - specifity = fragmentTag.getAttribute('specifity') - - # get formula - formulaTags = fragmentTag.getElementsByTagName('formula') - cTermFormula = str(formulaTags[0].getAttribute('cTerm')) - nTermFormula = str(formulaTags[0].getAttribute('nTerm')) - lossFormula = str(formulaTags[0].getAttribute('neutralLoss')) - - # get filter - termFilterTags = fragmentTag.getElementsByTagName('termFilter') - nTermFilter = bool(int(termFilterTags[0].getAttribute('nTerm'))) - cTermFilter = bool(int(termFilterTags[0].getAttribute('cTerm'))) - - # add object - container[name] = fragment( - name=name, \ - terminus=terminus, \ - specifity=specifity, \ - cTermFormula=cTermFormula, \ - nTermFormula=nTermFormula, \ - lossFormula=lossFormula, \ - nTermFilter=nTermFilter, \ - cTermFilter=cTermFilter \ - ) - - # update current lib - if clear: - fragments.clear() - for key in container: - fragments[key] = container[key] + if replace or not key in enzymes: + enzymes[key] = container[key] # ---- -def loadModifications(path=os.path.join(blocksdir, 'modifications.xml'), clear=False): +def loadModifications(path=os.path.join(blocksdir, 'modifications.xml'), clear=False, replace=True): """Parse modifications XML and get data.""" container = {} @@ -629,20 +543,21 @@ description = _getNodeText(descriptionTags[0]) # add object - container[name] = modification( \ - name=name, \ - gainFormula=gainFormula, \ - lossFormula=lossFormula, \ - aminoSpecifity=aminoSpecifity, \ - termSpecifity=termSpecifity, \ - description=description \ + container[name] = modification( + name = name, + gainFormula = gainFormula, + lossFormula = lossFormula, + aminoSpecifity = aminoSpecifity, + termSpecifity = termSpecifity, + description = description ) # update current lib - if clear: + if container and clear: modifications.clear() for key in container: - modifications[key] = container[key] + if replace or not key in modifications: + modifications[key] = container[key] # ---- @@ -662,56 +577,22 @@ # SAVE FUNCTIONS # -------------- -def saveElements(path=os.path.join(blocksdir, 'elements.xml')): - """Make and save elements XML.""" +def saveMonomers(path=os.path.join(blocksdir, 'monomers.xml')): + """Make and save monomers XML.""" - # make elements xml + # make monomers xml buff = '\n' - buff += '\n' + buff += '\n' - symbols = elements.keys() - symbols.sort() - for symbol in symbols: - buff += ' \n' % (elements[symbol].symbol, elements[symbol].name, elements[symbol].atomicNumber) - buff += ' \n' % elements[symbol].mass - buff += ' \n' - - isotopes = elements[symbol].isotopes.keys() - isotopes.sort() - for isotope in isotopes: - buff += ' \n' % (isotope, elements[symbol].isotopes[isotope][0], elements[symbol].isotopes[isotope][1]) - - buff += ' \n' - buff += ' \n' + abbrs = monomers.keys() + abbrs.sort() + for abbr in abbrs: + if monomers[abbr].category != '_InternalAA': + buff += ' \n' % (monomers[abbr].abbr, monomers[abbr].name, monomers[abbr].formula, monomers[abbr].category, ';'.join(monomers[abbr].losses)) - buff += '' + buff += '' - # save elements file - try: - save = file(path, 'w') - save.write(buff.encode("utf-8")) - save.close() - return True - except: - return False -# ---- - - -def saveAminoacids(path=os.path.join(blocksdir, 'aminoacids.xml')): - """Make and save aminoacids XML.""" - - # make aminoacids xml - buff = '\n' - buff += '\n' - - symbols = aminoacids.keys() - symbols.sort() - for symbol in symbols: - buff += ' \n' % (aminoacids[symbol].symbol, aminoacids[symbol].name, aminoacids[symbol].abbr, aminoacids[symbol].formula) - - buff += '' - - # save aminoacids file + # save monomers file try: save = file(path, 'w') save.write(buff.encode("utf-8")) @@ -751,34 +632,6 @@ # ---- -def saveFragments(path=os.path.join(blocksdir, 'fragments.xml')): - """Make and save fragments XML.""" - - # make fragments xml - buff = '\n' - buff += '\n' - - names = fragments.keys() - names.sort() - for name in names: - buff += ' \n' % (_escape(fragments[name].name), fragments[name].terminus, fragments[name].specifity) - buff += ' \n' % (fragments[name].nTermFormula, fragments[name].cTermFormula, fragments[name].lossFormula) - buff += ' \n' % (int(fragments[name].nTermFilter), int(fragments[name].cTermFilter)) - buff += ' \n' - - buff += '' - - # save fragments file - try: - save = file(path, 'w') - save.write(buff.encode("utf-8")) - save.close() - return True - except: - return False -# ---- - - def saveModifications(path=os.path.join(blocksdir, 'modifications.xml')): """Make and save modifications XML.""" diff -Nru mmass-3.12.1/mspy/envfit.py mmass-4.0.0/mspy/envfit.py --- mmass-3.12.1/mspy/envfit.py 1970-01-01 00:00:00.000000000 +0000 +++ mmass-4.0.0/mspy/envfit.py 2011-11-29 14:55:52.000000000 +0000 @@ -0,0 +1,438 @@ +# ------------------------------------------------------------------------- +# Copyright (C) 2005-2011 Martin Strohalm + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# Complete text of GNU GPL can be found in the file LICENSE.TXT in the +# main directory of the program +# ------------------------------------------------------------------------- + +# load libs +import math +import numpy +from numpy.linalg import solve as solveLinEq + +# load stopper +from stopper import CHECK_FORCE_QUIT + +# register essential objects and modules +import objects +import processing + + +# ENVELOPE FIT +# ------------ + +class envelopeFit(): + """Fit modeled profiles with exchanged atoms to acquired data.""" + + def __init__(self, formula, charge, scale, loss='H', gain='H{2}'): + + self.error = None # 1 - no data in relevant mass range + + loss = objects.compound(loss) + loss.negate() + self._lossFormula = loss.formula() + self._gainFormula = gain + + self.formula = formula + self.charge = charge + self.scale = self._validateScale(scale) + self.mzRange = self._calcMZRange() + + self.fwhm = 0.1 + self.spectrum = [] + self.data = [] + self.model = [] + self.params = None + self.composition = None + self.ncomposition = None + self.average = None + self.std = None + # ---- + + + def fitToSpectrum(self, points, fwhm=0.1, forceFwhm=True, autoAlign=True, iterLimit=None, pickingHeight=0.85, relThreshold=0., baselineWindow=0.1, baselineSmooth=True, baselineOffset=0.25, baselineData=None): + """Fit modeled profiles to spectrum using tmp peaklist. + points: (numpy array) m/z - intensity pairs or raw spectrum + fwhm: (float) defaut fwhm + forceFwhm: (bool) use default fwhm + autoAlign: (bool) automatic m/z shift + iterLimit: (int) maximum number of iterations + pickingHeight: (float) peak picking height for centroiding + relThreshold: (float) relative intensity threshold + baselineWindow: (float) noise calculation window in %/100 + baselineSmooth: (bool) smooth baseline + baselineOffset: (float) baseline intensity offset in %/100 + baselineData: (list of [x, noiseLevel, noiseWidth]) precalculated baseline + """ + + # get spectrum baseline + if baselineData == None: + baselineData = processing.baseline( + points = points, + window = baselineWindow, + smooth = baselineSmooth, + offset = baselineOffset + ) + + # crop points to relevant m/z range + i1 = processing.findIndex(points, self.mzRange[0], dim=2) + i2 = processing.findIndex(points, self.mzRange[1], dim=2) + points = points[i1:i2] + + # get peaklist from spectrum points + peaklist = processing.labelScan( + points = points, + pickingHeight = pickingHeight, + relThreshold = relThreshold, + baselineData = baselineData + ) + + # correct spectrum baseline + self.spectrum = processing.correctBaseline(points, baselineData=baselineData) + + # fit to peaklist + self.fitToPeaklist( + peaklist = peaklist, + fwhm = fwhm, + forceFwhm = forceFwhm, + autoAlign = autoAlign, + iterLimit = iterLimit + ) + # ---- + + + def fitToPeaklist(self, peaklist, fwhm=0.1, forceFwhm=True, autoAlign=True, iterLimit=None): + """Fit modeled profiles to peaklist. + peaklist: (mspy.peaklist) peak list + fwhm: (float) defaut fwhm + forceFwhm: (bool) use default fwhm + autoAlign: (bool) automatic m/z shift + iterLimit: (int) maximum number of iterations + """ + + # check peaklist object + if not isinstance(peaklist, objects.peaklist): + peaklist = objects.peaklist(peaklist) + + # crop peaklist to relevant m/z range + buff = [] + for peak in peaklist: + if self.mzRange[0] <= peak.mz <= self.mzRange[1]: + buff.append(peak) + peaklist = objects.peaklist(buff) + + # get fwhm from basepeak + if not forceFwhm and peaklist.basepeak and peaklist.basepeak.fwhm: + fwhm = peaklist.basepeak.fwhm + + # fit to points + self.data = numpy.array([(p.mz, p.intensity) for p in peaklist]) + if not autoAlign: + self.fitToPoints(self.data, fwhm=fwhm, iterLimit=iterLimit) + else: + self.fitToPoints(self.data, fwhm=fwhm, iterLimit=self.scale[1]/2) + self._alignData() + self.fitToPoints(self.data, fwhm=fwhm, iterLimit=iterLimit) + # ---- + + + def fitToPoints(self, points, fwhm=0.1, iterLimit=None): + """Fit modeled profiles to given points. + points: (numpy array or list) m/z - intensity pairs + fwhm: (float) defaut fwhm + iterLimit: (int) maximum number of iterations + """ + + self.fwhm = fwhm + + # crop points to relevant m/z range + i1 = processing.findIndex(points, self.mzRange[0], dim=2) + i2 = processing.findIndex(points, self.mzRange[1], dim=2) + self.data = numpy.array(points[i1:i2]) + + # check data + if len(self.data) == 0: + self.error = 1 + return + + # split data to raster and intensities + xAxis, yAxis = numpy.hsplit(self.data, 2) + raster = xAxis.flatten() + intensities = yAxis.flatten() + + # model profiles + models, exchanged = self._makeModels(raster) + + # fit data to model + self.params = self._leastSquare(intensities, models, iterLimit=iterLimit) + + # calc compositions + self.composition = {} + self.ncomposition = {} + f = 1./sum(self.params) + for i, value in enumerate(self.params): + self.composition[exchanged[i]] = value + self.ncomposition[exchanged[i]] = f*value + + # calc average exchange + self.average = 0. + for x in self.ncomposition: + self.average += x * self.ncomposition[x] + + # calc standard deviation + self.std = 0. + err = 0. + for x in self.ncomposition: + err += self.ncomposition[x] * (x - self.average)**2 + self.std = math.sqrt(err) + + # calc fitted points + intensities = numpy.sum(models * [[x] for x in self.params], axis=0) + intensities.shape = (-1,1) + raster.shape = (-1,1) + self.model = numpy.concatenate((raster, intensities), axis=1).copy() + # ---- + + + def envelope(self, points=5): + """Return calculated envelope for current composition.""" + + # check composition + if self.composition == None: + return [] + + # get peak width + width = self.fwhm/1.66 + + # get isotopes for all profiles + isotopes = [] + for x, abundance in self.composition.items(): + item = "%s(%s)%d(%s)%d" % (self.formula, self._lossFormula, x, self._gainFormula, x) + compound = objects.compound(item) + pattern = compound.pattern(fwhm=self.fwhm, charge=self.charge) + isotopes += [(p[0], p[1]*abundance) for p in pattern] + + # make profile from isotopes + profile = processing.profile(isotopes, fwhm=self.fwhm, points=points) + + return profile + # ---- + + + def _validateScale(self, scale): + """Check if compounds are valid for given scale.""" + + for x in range(scale[0], scale[1]+1): + item = "%s(%s)%d(%s)%d" % (self.formula, self._lossFormula, x, self._gainFormula, x) + compound = objects.compound(item) + if not compound.isvalid(charge=self.charge): + return (scale[0], x-1) + + return scale + # ---- + + + def _calcMZRange(self): + """Calculate relevant m/z range for current formula and scale.""" + + # set additional space + space = .001 + + # get m/z range + item = "%s(%s)%d(%s)%d" % (self.formula, self._lossFormula, self.scale[0], self._gainFormula, self.scale[0]) + compound = objects.compound(item) + minX = compound.pattern(fwhm=0.5, charge=self.charge)[0][0] + minX -= minX * space + + item = "%s(%s)%d(%s)%d" % (self.formula, self._lossFormula, self.scale[1], self._gainFormula, self.scale[1]) + compound = objects.compound(item) + maxX = compound.pattern(fwhm=0.5, charge=self.charge)[-1][0] + maxX += maxX * space + + return (minX, maxX) + # ---- + + + def _makeModels(self, raster): + """Make individual profiles to fit.""" + + # get peak width + width = self.fwhm/1.66 + + # get raster + rasterMin = raster[0] - self.fwhm + rasterMax = raster[-1] + self.fwhm + + # calculate profiles + models = [] + exchanged = [] + for x in range(self.scale[0], self.scale[1]+1): + + CHECK_FORCE_QUIT() + + # generate new formula with H/D exchange + item = "%s(%s)%d(%s)%d" % (self.formula, self._lossFormula, x, self._gainFormula, x) + compound = objects.compound(item) + mz = compound.mz(self.charge) + + # check theoretical mass with current m/z raster + if mz[0] < rasterMax and mz[1] > rasterMin: + + # calculate isotopic pattern + pattern = compound.pattern(fwhm=self.fwhm, charge=self.charge) + + # calculate intensities by adding peak gaussians + model = numpy.zeros(raster.size, float) + for peak in pattern: + i1 = processing.findIndex(raster, (peak[0]-5*width), dim=1) + i2 = processing.findIndex(raster, (peak[0]+5*width), dim=1) + for i in range(i1, i2): + model[i] += peak[1]*numpy.exp(-1*(pow(raster[i]-peak[0],2))/pow(width,2)) + + # store data + if model.any(): + models.append(model) + exchanged.append(x) + + # convert profiles to matrix + models = numpy.array(models) + + return models, exchanged + # ---- + + + def _alignData(self): + """Re-calibrate data using theoretical envelope.""" + + # check composition + if not self.composition: + return + + # make theoretical profile + width = self.fwhm/1.66 + isotopes = [] + for x, abundance in self.composition.items(): + item = "%s(%s)%d(%s)%d" % (self.formula, self._lossFormula, x, self._gainFormula, x) + compound = objects.compound(item) + pattern = compound.pattern(fwhm=self.fwhm, charge=self.charge) + isotopes += [(p[0], p[1]*abundance) for p in pattern] + profile = processing.profile(isotopes, fwhm=self.fwhm, points=5) + + # label peaks in profile + peaklist = processing.labelScan(profile, pickingHeight=0.95, relThreshold=0.01) + + # find peaks within tolerance + calibrants = [] + tolerance = self.fwhm/1.5 + previous = None + for peak in peaklist: + for point in self.data: + delta = point[0] - peak.mz + + if abs(delta) <= tolerance: + if previous and previous[0] == peak.mz and previous[1] < point[1]: + calibrants[-1] = (point[0], peak.mz) + else: + calibrants.append((point[0], peak.mz)) + previous = (peak.mz, point[1]) + + elif delta > tolerance: + break + + # calc calibration + if len(calibrants) > 3: + model, params, chi = processing.calibration(calibrants, model='quadratic') + elif len(calibrants) > 1: + model, params, chi = processing.calibration(calibrants, model='linear') + else: + return + + # apply calibration to data + for x in range(len(self.data)): + self.data[x][0] = model(params, self.data[x][0]) + for x in range(len(self.spectrum)): + self.spectrum[x][0] = model(params, self.spectrum[x][0]) + # ---- + + + def _leastSquare(self, data, models, iterLimit=None, chiLimit=1e-3): + """Least-square fitting. Adapted from the original code by Konrad Hinsen.""" + + normf = 100./numpy.max(data) + data *= normf + + params = [50.] * len(models) + id = numpy.identity(len(params)) + chisq, alpha = self._chiSquare(data, models, params) + l = 0.001 + + niter = 0 + while True: + + CHECK_FORCE_QUIT() + + niter += 1 + delta = solveLinEq(alpha+l*numpy.diagonal(alpha)*id,-0.5*numpy.array(chisq[1])) + next_params = map(lambda a,b: a+b, params, delta) + + for x in range(len(next_params)): + if next_params[x] < 0.: + next_params[x] = 0. + + next_chisq, next_alpha = self._chiSquare(data, models, next_params) + if next_chisq[0] > chisq[0]: + l = 5.*l + elif chisq[0] - next_chisq[0] < chiLimit: + break + else: + l = 0.5*l + params = next_params + chisq = next_chisq + alpha = next_alpha + + if iterLimit and niter == iterLimit: + break + + next_params /= normf + + return next_params + # ---- + + + def _chiSquare(self, data, models, params): + """Calculate fitting chi-square for current parameter set.""" + + # calculate differences and chi-square value between calculated and real data + differences = numpy.sum(models * [[x] for x in params], axis=0) - data + chisq_value = numpy.sum(differences**2) + + # calculate chi-square deriv and alpha + cycles = len(models) + chisq_deriv = cycles*[0] + alpha = numpy.zeros((len(params), len(params))) + for x in range(len(data)): + + deriv = cycles*[0] + for i in range(cycles): + p_deriv = cycles*[0] + p_deriv[i] = models[i][x] + deriv = map(lambda a,b: a+b, deriv, p_deriv) + chisq_deriv = map(lambda a,b: a+b, chisq_deriv, map(lambda x,f=differences[x]*2:f*x, deriv)) + + d = numpy.array(deriv) + alpha = alpha + d[:,numpy.newaxis]*d + + return [chisq_value, chisq_deriv], alpha + # ---- + + \ No newline at end of file diff -Nru mmass-3.12.1/mspy/__init__.py mmass-4.0.0/mspy/__init__.py --- mmass-3.12.1/mspy/__init__.py 2011-04-29 15:17:03.000000000 +0000 +++ mmass-4.0.0/mspy/__init__.py 2011-11-28 11:20:22.000000000 +0000 @@ -23,7 +23,8 @@ # register modules from utilities import * from processing import * -from mascot import * +from proteo import * +from envfit import * # register parsers from parser_xy import parseXY diff -Nru mmass-3.12.1/mspy/objects.py mmass-4.0.0/mspy/objects.py --- mmass-3.12.1/mspy/objects.py 2011-06-30 11:05:14.000000000 +0000 +++ mmass-4.0.0/mspy/objects.py 2011-11-29 18:34:37.000000000 +0000 @@ -28,6 +28,7 @@ # register essential modules import processing +import proteo # compile basic patterns @@ -57,47 +58,68 @@ class compound: """Compound object definition.""" - def __init__(self, rawFormula): + def __init__(self, expression): - # user defined formula - self.rawFormula = rawFormula + # check formula + self._checkFormula(expression) + self.expression = expression # buffers - self._formula = None self._composition = None + self._formula = None self._mass = None # user defined params self.userParams = {} + # ---- + + + def __iadd__(self, other): + """Append formula.""" - # check formula - if not formulaPattern.match(self.rawFormula): - raise ValueError, 'Wrong formula! --> ' + self.rawFormula + # check and append value + if isinstance(other, compound): + self.expression += other.expression + else: + self._checkFormula(other) + self.expression += other - # check elements and isotopes - for atom in elementPattern.findall(self.rawFormula): - if not atom[0] in blocks.elements: - raise ValueError, 'Unknown element in formula! --> ' + atom[0] + ' in ' + self.rawFormula - elif atom[1] and not int(atom[1]) in blocks.elements[atom[0]].isotopes: - raise ValueError, 'Unknown isotope in formula! --> ' + atom[0] + atom[1] + ' in ' + self.rawFormula + # clear buffers + self.reset() - # check brackets - if self.rawFormula.count(')') != self.rawFormula.count('('): - raise ValueError, 'Wrong number of brackets in formula! --> ' + self.rawFormula + return self # ---- def reset(self): """Clear formula buffers.""" + self._composition = None self._formula = None self._mass = None - self._composition = None # ---- # GETTERS + def count(self, item): + """Count atom in formula.""" + + # pre-check atom + if not item in self.expression: + return 0 + + # get composition + comp = self.composition() + + # count atom + if item in comp: + return comp[item] + else: + return 0 + # ---- + + def formula(self): """Get formula.""" @@ -121,16 +143,16 @@ def composition(self): - """Get elemental composition as dict.""" + """Get elemental composition.""" # check composition buffer if self._composition != None: return self._composition # unfold brackets - unfoldedFormula = self._unfoldBrackets(self.rawFormula) + unfoldedFormula = self._unfoldBrackets(self.expression) - # group same elements + # group elements self._composition = {} for symbol, isotop, count in elementPattern.findall(unfoldedFormula): @@ -161,7 +183,7 @@ # ---- - def mass(self): + def mass(self, massType=None): """Get mass.""" # get mass @@ -185,40 +207,49 @@ else: atomMass = blocks.elements[symbol].mass - # multiply atom + # multiply atom mass massMo += atomMass[0]*count massAv += atomMass[1]*count # store mass in buffer self._mass = (massMo, massAv) - return self._mass + # return mass + if massType == 0: + return self._mass[0] + elif massType == 1: + return self._mass[1] + else: + return self._mass # ---- def mz(self, charge, agentFormula='H', agentCharge=1): """Get ion m/z.""" - # get current mass and calculate mz - return processing.mz(self.mass(), charge, agentFormula=agentFormula, agentCharge=agentCharge) + return processing.mz(self.mass(), + charge = charge, + agentFormula = agentFormula, + agentCharge = agentCharge + ) # ---- def pattern(self, fwhm=0.1, threshold=0.01, charge=0, agentFormula='H', agentCharge=1): """Get isotopic pattern.""" - return processing.pattern(self, \ - fwhm=fwhm, \ - threshold=threshold, \ - charge=charge, \ - agentFormula=agentFormula, \ - agentCharge=agentCharge \ + return processing.pattern(self, + fwhm = fwhm, + threshold = threshold, + charge = charge, + agentFormula = agentFormula, + agentCharge = agentCharge ) # ---- def isvalid(self, charge=0, agentFormula='H', agentCharge=1): - """Utility to check ion composition.""" + """Check ion composition.""" # check agent formula if agentFormula != 'e' and not isinstance(agentFormula, compound): @@ -226,12 +257,12 @@ # make ion compound if charge and agentFormula != 'e': - ionFormula = self.rawFormula + ionFormula = self.expression for atom, count in agentFormula.composition().items(): ionFormula += '%s%d' % (atom, count*(charge/agentCharge)) ion = compound(ionFormula) else: - ion = compound(self.rawFormula) + ion = compound(self.expression) # get composition for atom, count in ion.composition().items(): @@ -242,8 +273,47 @@ # ---- + # MODIFIERS + + def negate(self): + """Make all atom counts negative.""" + + # get composition + comp = self.composition() + + # negate composition + formula = '' + for el in sorted(comp.keys()): + formula += '%s%d' % (el, -1*comp[el]) + self.expression = formula + + # clear buffers + self.reset() + # ---- + + # HELPERS + def _checkFormula(self, formula): + """Check given formula.""" + + # check formula + if not formulaPattern.match(formula): + raise ValueError, 'Wrong formula! --> ' + formula + + # check elements and isotopes + for atom in elementPattern.findall(formula): + if not atom[0] in blocks.elements: + raise ValueError, 'Unknown element in formula! --> ' + atom[0] + ' in ' + formula + elif atom[1] and not int(atom[1]) in blocks.elements[atom[0]].isotopes: + raise ValueError, 'Unknown isotope in formula! --> ' + atom[0] + atom[1] + ' in ' + formula + + # check brackets + if formula.count(')') != formula.count('('): + raise ValueError, 'Wrong number of brackets in formula! --> ' + formula + # ---- + + def _unfoldBrackets(self, string): """Unfold formula and count each atom.""" @@ -286,6 +356,7 @@ brackets = [0,0] i += 1 + return unfoldedFormula # ---- @@ -294,18 +365,41 @@ class sequence: """Sequence object definition.""" - def __init__(self, chain, title='', accession='', nTermFormula='H', cTermFormula='OH', lossFormula=''): + def __init__(self, chain, title='', accession='', chainType='aminoacids', cyclic=False): - # get chain - chain = chain.upper() - for char in ('\t','\n','\r','\f','\v', ' ', '-', '*', '.'): - chain = chain.replace(char, '') - self.chain = chain.upper() - - self.nTermFormula = nTermFormula - self.cTermFormula = cTermFormula - self.modifications = [] # [[name, position=[#|symbol], state[f|v]], ] (f-fixed, v-variable) - self.labels = [] # [[name, position=[#|symbol], state[f|v]], ] (f-fixed, v-variable) + self.chain = [] + self.chainType = chainType + self.cyclic = cyclic + + # get sequence chain + if type(chain) == list: + self.chain = chain + + elif self.chainType == 'aminoacids': + for symbol in chain.upper(): + if not symbol in ('\t','\n','\r','\f','\v', ' ', '-', '*', '.', ''): + self.chain.append(symbol) + else: + for symbol in chain.split('|'): + symbol = symbol.strip() + if not symbol in ('\t','\n','\r','\f','\v', ' ', '-', '*', '.', ''): + self.chain.append(symbol) + + for monomer in self.chain: + if not monomer in blocks.monomers: + raise KeyError, 'Unknown monomer in the sequence! --> ' + monomer + + # set terminal groups + if self.cyclic: + self.nTermFormula = '' + self.cTermFormula = '' + else: + self.nTermFormula = 'H' + self.cTermFormula = 'OH' + + # [[name, position=[#|symbol], state=[f|v]], ] (f->fixed, v->variable) + self.modifications = [] + self.labels = [] # for proteins self.title = title @@ -315,29 +409,31 @@ self.score = None # for peptides - self.userRange = [] - self.aaBefore = '' - self.aaAfter = '' + self.history = [('init', 0, len(self.chain))] + self.itemBefore = '' + self.itemAfter = '' self.miscleavages = 0 # for fragments self.fragmentSerie = None self.fragmentIndex = None + self.fragmentLosses = [] + self.fragmentGains = [] self.fragmentFiltered = False - self.lossFormula = lossFormula # buffers self._formula = None self._composition = None - self._mass = None # (monoisotopic, average) + self._mass = None # user defined params self.userParams = {} - - # check amino acids - for amino in self.chain: - if not amino in blocks.aminoacids: - raise ValueError, 'Unknown amino acid in sequence! --> ' + amino + # ---- + + + def __nonzero__(self): + """Check sequence length.""" + return bool(len(self.chain)) # ---- @@ -356,50 +452,80 @@ """Get slice of the sequence.""" # check slice - if stop < start: - raise ValueError, 'Invalid sequence slice definition!' + if stop < start and not self.cyclic: + raise ValueError, 'Invalid slice!' # break the links parent = copy.deepcopy(self) # check slice start = max(start, 0) - stop = min(stop, len(parent.chain)) + stop = min(stop, len(parent)) # make new sequence object - seq = parent.chain[start:stop] - peptide = sequence(seq) + if start < stop: + seq = parent.chain[start:stop] + peptide = sequence(seq, chainType=parent.chainType, cyclic=False) + elif self.cyclic: + seq = parent.chain[start:] + parent.chain[:stop] + peptide = sequence(seq, chainType=parent.chainType, cyclic=False) + + # add previous history + peptide.history = parent.history + + # add fragment losses and gains + peptide.fragmentLosses = parent.fragmentLosses + peptide.fragmentGains = parent.fragmentGains # add modifications for mod in parent.modifications: - if type(mod[1]) == int and mod[1] >= start and mod[1] < stop: - mod[1] -= start - peptide.modifications.append(mod) - elif type(mod[1]) in (str, unicode) and mod[1] in peptide.chain: + if type(mod[1]) in (str, unicode) and mod[1] in peptide.chain: peptide.modifications.append(mod) + elif type(mod[1]) == int: + if start <= mod[1] < stop: + mod[1] -= start + peptide.modifications.append(mod) + elif start >= stop and mod[1] >= start: + mod[1] -= start + peptide.modifications.append(mod) + elif start >= stop and mod[1] < stop: + mod[1] += len(parent) - start + peptide.modifications.append(mod) # add labels for mod in parent.labels: - if type(mod[1]) == int and mod[1] >= start and mod[1] < stop: - mod[1] -= start - peptide.labels.append(mod) - elif type(mod[1]) in (str, unicode) and mod[1] in peptide.chain: + if type(mod[1]) in (str, unicode) and mod[1] in peptide.chain: peptide.labels.append(mod) - - # set range in user coordinates - peptide.userRange = [start+1, stop] - - # set adjacent amino acids - if start > 0: - peptide.aaBefore = parent.chain[start-1] - if stop < len(parent.chain): - peptide.aaAfter = parent.chain[stop] + elif type(mod[1]) == int: + if start <= mod[1] < stop: + mod[1] -= start + peptide.labels.append(mod) + elif start >= stop and mod[1] >= start: + mod[1] -= start + peptide.labels.append(mod) + elif start >= stop and mod[1] < stop: + mod[1] += len(parent) - start + peptide.labels.append(mod) # add terminal modifications if start == 0: peptide.nTermFormula = parent.nTermFormula - if stop >= len(parent.chain): + if stop >= len(parent): peptide.cTermFormula = parent.cTermFormula + if parent.cyclic: + peptide.nTermFormula = 'H' + peptide.cTermFormula = 'OH' + + # set adjacent monomers + if start > 0 or parent.cyclic: + peptide.itemBefore = parent.chain[start-1] + if stop < len(parent): + peptide.itemAfter = parent.chain[stop] + if stop == len(parent) and parent.cyclic: + peptide.itemAfter = parent.chain[0] + + # add to history + peptide.history.append(('slice', start, stop)) # ensure buffers are cleaned peptide.reset() @@ -419,6 +545,10 @@ if not isinstance(value, sequence): raise TypeError, 'Invalid object to instert!' + # check chain type + if value.chainType != self.chainType: + raise TypeError, 'Invalid chain type to instert!' + # break the links value = copy.deepcopy(value) @@ -452,9 +582,9 @@ self.labels.append(mod) # clear some values - self.userRange = [] - self.aaBefore = '' - self.aaAfter = '' + self.history = [('init', 0, len(self.chain))] + self.itemBefore = '' + self.itemAfter = '' self.miscleavages = 0 # clear buffers @@ -495,9 +625,9 @@ self.labels = keep # clear some values - self.userRange = [] - self.aaBefore = '' - self.aaAfter = '' + self.history = [('init', 0, len(self.chain))] + self.itemBefore = '' + self.itemAfter = '' self.miscleavages = 0 # clear buffers @@ -505,27 +635,39 @@ #---- - def __add__(self, value): + def __add__(self, other): """Join sequences and return result (essential for sequence editor).""" # check value - if not isinstance(value, sequence): - raise TypeError, 'Invalid object to join with sequence!' + if not isinstance(other, sequence): + raise TypeError, 'Invalid object to join with!' + + # check chain type + if value.chainType != self.chainType: + raise TypeError, 'Invalid chain type to join with!' + + # check cyclic peptides + if self.cyclic or other.cyclic: + raise TypeError, 'Cannot join cyclic peptides!' + + # break the links + other = copy.deepcopy(other) # join sequences result = self[:] - result[len(result):] = value + result[len(result):] = other # set C terminus - result.cTermFormula = value.cTermFormula + result.cTermFormula = other.cTermFormula - # set neutral loss - result.lossFormula = value.lossFormula + # set neutral loss and gain + result.fragmentLosses = other.fragmentLosses + result.fragmentGains = other.fragmentGains # clear some values - result.userRange = [] - result.aaBefore = '' - result.aaAfter = '' + result.history = [('init', 0, len(self.chain))] + result.itemBefore = '' + result.itemAfter = '' result.miscleavages = 0 # clear buffers @@ -563,7 +705,11 @@ def duplicate(self): """Return copy of current sequence.""" - return copy.deepcopy(self) + + dupl = copy.deepcopy(self) + dupl.reset() + + return dupl # ---- @@ -596,7 +742,7 @@ def composition(self): - """Get elemental composition as dict.""" + """Get elemental composition.""" # check composition buffer if self._composition != None: @@ -604,9 +750,9 @@ self._composition = {} - # add amino acids to formula - for amino in self.chain: - for el, count in blocks.aminoacids[amino].composition.items(): + # add monomers to formula + for monomer in self.chain: + for el, count in blocks.monomers[monomer].composition.items(): if el in self._composition: self._composition[el] += count else: @@ -625,20 +771,31 @@ self._composition[el] = multi*count # add terminal modifications - termCmpd = compound(self.nTermFormula + self.cTermFormula) - for el, count in termCmpd.composition().items(): - if el in self._composition: - self._composition[el] += count - else: - self._composition[el] = count + if not self.cyclic: + termCmpd = compound(self.nTermFormula + self.cTermFormula) + for el, count in termCmpd.composition().items(): + if el in self._composition: + self._composition[el] += count + else: + self._composition[el] = count - # subtract neutral loss for fragments - lossCmpd = compound(self.lossFormula) - for el, count in lossCmpd.composition().items(): - if el in self._composition: - self._composition[el] -= count - else: - self._composition[el] = -1*count + # subtract neutral losses for fragments + for loss in self.fragmentLosses: + lossCmpd = compound(loss) + for el, count in lossCmpd.composition().items(): + if el in self._composition: + self._composition[el] -= count + else: + self._composition[el] = -1*count + + # add neutral gains for fragments + for gain in self.fragmentGains: + gainCmpd = compound(gain) + for el, count in gainCmpd.composition().items(): + if el in self._composition: + self._composition[el] += count + else: + self._composition[el] = count # remove zeros for atom in self._composition.keys(): @@ -649,37 +806,43 @@ # ---- - def mass(self): + def mass(self, massType=None): """Get mass.""" - # check mass buffer - if self._mass != None: - return self._mass - # get mass - self._mass = compound(self.formula()).mass() + if self._mass == None: + self._mass = compound(self.formula()).mass() - return self._mass + # return mass + if massType == 0: + return self._mass[0] + elif massType == 1: + return self._mass[1] + else: + return self._mass # ---- def mz(self, charge, agentFormula='H', agentCharge=1): """Get ion m/z""" - # get current mass and calculate mz - return processing.mz(self.mass(), charge, agentFormula=agentFormula, agentCharge=agentCharge) + return processing.mz(self.mass(), + charge = charge, + agentFormula = agentFormula, + agentCharge = agentCharge + ) # ---- def pattern(self, fwhm=0.1, threshold=0.01, charge=0, agentFormula='H', agentCharge=1): """Get isotopic pattern.""" - return processing.pattern(self, \ - fwhm=fwhm, \ - threshold=threshold, \ - charge=charge, \ - agentFormula=agentFormula, \ - agentCharge=agentCharge \ + return processing.pattern(self, + fwhm = fwhm, + threshold = threshold, + charge = charge, + agentFormula = agentFormula, + agentCharge = agentCharge ) # ---- @@ -687,28 +850,53 @@ def format(self, template='S [m]'): """Get formated sequence.""" - # make keys keys = {} - keys['s'] = self.chain.lower() - keys['S'] = self.chain + + # make sequence keys + if self.chainType == 'aminoacids': + keys['S'] = ''.join(self.chain) + keys['s'] = ''.join(self.chain).lower() + keys['B'] = self.itemBefore + keys['A'] = self.itemAfter + keys['b'] = self.itemBefore.lower() + keys['a'] = self.itemAfter.lower() + else: + keys['S'] = ' | '.join(self.chain) + keys['s'] = '|'.join(self.chain) + keys['b'] = self.itemBefore + keys['a'] = self.itemAfter + keys['B'] = self.itemBefore + keys['A'] = self.itemAfter + + # make terminal formula keys keys['N'] = self.nTermFormula keys['C'] = self.cTermFormula - keys['b'] = self.aaBefore.lower() - keys['B'] = self.aaBefore - keys['a'] = self.aaAfter.lower() - keys['A'] = self.aaAfter + + # make modification keys keys['m'] = self._formatModifications(self.modifications) keys['M'] = self._formatModifications(self.modifications + self.labels) keys['l'] = self._formatModifications(self.labels) keys['p'] = self.miscleavages - if self.userRange: - keys['r'] = '%s-%s' % tuple(self.userRange) - - if self.fragmentSerie != None and self.fragmentIndex != None: - keys['f'] = '%s %s' % (self.fragmentSerie, self.fragmentIndex) - elif self.fragmentSerie != None: - keys['f'] = self.fragmentSerie + # make history key + keys['h'] = '' + if 'h' in template: + for item in self.history[1:]: + if item[0] == 'slice': + keys['h'] += '[%s-%s]' % (item[1]+1, item[2]) + elif item[0] == 'break': + keys['h'] += '[%s|%s]' % (item[1]+1, item[2]+1) + + # make fragment name key + keys['f'] = '' + if 'f' in template and self.fragmentSerie: + keys['f'] = self.fragmentSerie + if self.fragmentIndex != None: + keys['f'] += str(self.fragmentIndex) + for gain in self.fragmentGains: + keys['f'] += ' +'+gain + for loss in self.fragmentLosses: + keys['f'] += ' -'+loss # format buff = '' @@ -727,37 +915,7 @@ # ---- - def digest(self, enzyme, miscleavage=0, allowMods=False, strict=True): - """Digest seuence by specified enzyme. - enzyme: (str) enzyme name - must be defined in mspy.enzymes - miscleavage: (int) number of allowed misscleavages - allowMods: (bool) do not care about modifications in cleavage site - strict: (bool) do not cleave even if variable modification is in cleavage site - """ - - return processing.digest(self, - enzyme=enzyme, \ - miscleavage=miscleavage, \ - allowMods=allowMods, \ - strict=strict - ) - # ---- - - - def fragment(self, serie, index=None): - """Generate list of neutral peptide fragments from given peptide. - serie: (str) fragment serie name - must be defined in mspy.fragments - index: (int) fragment index - """ - - return processing.fragment(self, \ - serie=serie, \ - index=index \ - ) - # ---- - - - def search(self, mass, charge, tolerance, enzyme=None, semiSpecific=True, tolUnits='Da', massType='mo', maxMods=1, position=False): + def search(self, mass, charge, tolerance, enzyme=None, semiSpecific=True, tolUnits='Da', massType=0, maxMods=1, position=False): """Search sequence for specified ion. mass: (float) m/z value to search for charge: (int) charge of the m/z value @@ -765,18 +923,16 @@ tolUnits: ('Da', 'ppm') tolerance units enzyme: (str) enzyme used for peptides endings, if None H/OH is used semiSpecific: (bool) semispecific cleavage is checked (enzyme must be set) - massType: ('mo' or 'av') mass type of the mass value + massType: (0 or 1) mass type of the mass value, 0 = monoisotopic, 1 = average maxMods: (int) maximum number of modifications at one residue position: (bool) retain position for variable modifications (much slower) """ - matches = [] + # check cyclic peptides + if self.cyclic: + raise TypeError, 'Search function is not supported for cyclic peptides!' - # set mass type - if massType == 'mo': - massType = 0 - elif massType == 'av': - massType = 1 + matches = [] # set terminal modifications if enzyme: @@ -812,8 +968,8 @@ peptide.cTerminalFormula = cTerm # check enzyme specifity - if semiSpecific and peptide.aaBefore and peptide.aaAfter: - if not expression.search(peptide.aaBefore+peptide.chain[0]) and not expression.search(peptide.chain[-1]+peptide.aaAfter): + if semiSpecific and peptide.itemBefore and peptide.itemAfter: + if not expression.search(peptide.itemBefore+peptide.chain[0]) and not expression.search(peptide.chain[-1]+peptide.itemAfter): continue # variate modifications @@ -861,8 +1017,8 @@ if not position: variableMods += [mod] * self.chain.count(mod[1]) else: - for x, amino in enumerate(self.chain): - if amino == mod[1]: + for x, symbol in enumerate(self.chain): + if symbol == mod[1]: variableMods.append([mod[0], x, 'v']) # make combinations of variable modifications @@ -880,9 +1036,9 @@ # disable modifications at cleavage sites if enzyme: enz = blocks.enzymes[enzyme] - if not enz.modsBefore and self.aaAfter: - occupied += [len(self.chain)-1]*maxMods - if not enz.modsAfter and self.aaBefore: + if not enz.modsBefore and self.itemAfter: + occupied += [len(self)-1]*maxMods + if not enz.modsAfter and self.itemBefore: occupied += [0]*maxMods CHECK_FORCE_QUIT() @@ -918,10 +1074,10 @@ CHECK_FORCE_QUIT() - variablePeptide = copy.deepcopy(self) + variablePeptide = self.duplicate() variablePeptide.modifications[:] = fixedMods+combination - variablePeptide.reset() + # check composition if variablePeptide.isvalid(): variablePeptides.append(variablePeptide) @@ -929,6 +1085,53 @@ # ---- + def linearized(self, breakPoint=None): + """Return list of all linearized sequences resulted from cyclic parent.""" + + # ensure sequence is cyclic + cyclic = self.cyclic + self.cyclic = True + + # set break points + breakPoints = range(len(self)) + if breakPoint != None: + breakPoints = [breakPoint] + + # make peptides for all break points + peptides = [] + for x in breakPoints: + peptide = self[x:x] + del peptide.history[-1] + if x != 0: + peptide.history.append(('break', x-1, x)) + else: + peptide.history.append(('break', len(self)-1, x)) + peptides.append(peptide) + + # revert to original cyclization + self.cyclic = cyclic + + if breakPoint: + return peptides[0] + else: + return peptides + # ---- + + + def indexes(self): + """Calculate parent indexes from sequence history.""" + + ranges = range(self.history[0][1], self.history[0][2]) + for item in self.history[1:]: + if item[0] == 'slice': + ranges = ranges[item[1] : item[2]] + elif item[0] == 'break': + ranges = ranges[item[2]:]+ranges[:item[1]+1] + + return ranges + # ---- + + def ismodified(self, position=None, strict=False): """Check if selected amino acid or whole sequence has any modification. position: (int) amino acid index @@ -955,8 +1158,14 @@ def isvalid(self, charge=0, agentFormula='H', agentCharge=1): """Utility to check ion composition.""" + # make compound formula = compound(self.formula()) - return formula.isvalid(charge=charge, agentFormula=agentFormula, agentCharge=agentCharge) + + # check ion composition + return formula.isvalid(charge = charge, + agentFormula = agentFormula, + agentCharge = agentCharge + ) # ---- @@ -972,7 +1181,9 @@ # check position try: position = int(position) except: position = str(position) - if type(position) == str and self.chain.count(position) == 0: + if type(position) == str and not position in self.chain: + return False + elif type(position) == int and (position < 0 or position >= len(self)): return False # add modification @@ -997,8 +1208,7 @@ try: mod = [name, int(position), str(state)] except: mod = [name, str(position), str(state)] while mod in self.modifications: - i = self.modifications.index(mod) - del self.modifications[i] + del self.modifications[self.modifications.index(mod)] # clear buffers self.reset() @@ -1015,7 +1225,9 @@ # check position try: position = int(position) except: position = str(position) - if type(position) == str and self.chain.count(position) == 0: + if type(position) == str and not position in self.chain: + return False + elif type(position) == int and (position < 0 or position >= len(self)): return False # add label @@ -1028,6 +1240,24 @@ # ---- + def cyclize(self, cyclic=True): + """Make current sequence cyclic/linear.""" + + # make sequence cyclic + if cyclic: + self.cyclic = True + self.nTermFormula = '' + self.cTermFormula = '' + else: + self.cyclic = False + self.nTermFormula = 'H' + self.cTermFormula = 'OH' + + # clear buffers + self.reset() + # ---- + + # HELPERS def _formatModifications(self, modifications): @@ -1130,8 +1360,8 @@ self.childScanNumber = None # set intensity + self.ri = 1. self.intensity = self.ai - self.base - self.relIntensity = 1. # set resolution self.resolution = None @@ -1139,7 +1369,7 @@ self.resolution = self.mz/self.fwhm # set buffers - self._mass = None # neutral mass + self._mass = None # user defined params self.userParams = {} @@ -1174,7 +1404,7 @@ # check mass buffer if self._mass != None: return self._mass - + # calculate neutral mass self._mass = processing.mz(self.mz, 0, self.charge, agentFormula='H', agentCharge=1) @@ -1313,7 +1543,7 @@ # lower than basepeak elif self.basepeak: - item.relIntensity = item.intensity / self.basepeak.intensity + item.ri = item.intensity / self.basepeak.intensity self.peaks[i] = item # no basepeak set @@ -1352,11 +1582,11 @@ # ---- - def __add__(self, peaksB): + def __add__(self, other): """Return A+B.""" new = self.duplicate() - new.concatenate(peaksB) + new.concatenate(other) return new # ---- @@ -1371,6 +1601,7 @@ def next(self): + if self._index < len(self.peaks): self._index += 1 return self.peaks[self._index-1] @@ -1401,11 +1632,11 @@ # lower than basepeak elif self.basepeak and self.basepeak.intensity != 0: - item.relIntensity = item.intensity / self.basepeak.intensity + item.ri = item.intensity / self.basepeak.intensity # no basepeak set else: - item.relIntensity = 1. + item.ri = 1. self._setBasepeak() # ---- @@ -1536,14 +1767,12 @@ # ---- - def concatenate(self, peaksB): - """Add data from given peaklist. - peaksB: (peaklist or list of peaks) peaklist to be added - """ + def concatenate(self, other): + """Add data from given peaklist.""" # check peaks buff = [] - for peak in copy.deepcopy(peaksB): + for peak in copy.deepcopy(other): peak = self._checkPeak(peak) buff.append(peak) @@ -1587,18 +1816,18 @@ # find isotops processing.findIsotopes( - peaklist=self, \ - maxCharge=maxCharge, \ - mzTolerance=mzTolerance, \ - intTolerance=intTolerance, \ - isotopeShift=isotopeShift \ + peaklist = self, + maxCharge = maxCharge, + mzTolerance = mzTolerance, + intTolerance = intTolerance, + isotopeShift = isotopeShift ) # ---- - def deconvolute(self, massType='mo'): + def deconvolute(self, massType=0): """Recalculate peaklist to singly charged. - massType: ('mo' or 'av') mass type used for m/z re-calculation + massType: (0 or 1) mass type used for m/z re-calculation, 0 = monoisotopic, 1 = average """ # check peaklist @@ -1607,8 +1836,8 @@ # deconvolute peaklist peaks = processing.deconvolute( - peaklist=self, \ - massType=massType \ + peaklist = self, + massType = massType ) # store data @@ -1795,7 +2024,7 @@ return item # make peak from list or tuple - elif type(item) in (list, tuple) and len(item)==2: + elif type(item) in (list, tuple) or len(item)==2: return peak(item[0], item[1]) # not valid peak data @@ -1832,10 +2061,10 @@ maxInt = self.basepeak.intensity if maxInt: for item in self.peaks: - item.relIntensity = item.intensity / maxInt + item.ri = item.intensity / maxInt else: for item in self.peaks: - item.relIntensity = 1. + item.ri = 1. # ---- @@ -1881,10 +2110,9 @@ self.points = numpy.array(points) # convert peaks to peaklist - if isinstance(peaks, peaklist): - self.peaklist = peaks - else: - self.peaklist = peaklist(peaks) + if not isinstance(peaks, peaklist): + peaks = peaklist(peaks) + self.peaklist = peaks # ---- @@ -1893,20 +2121,20 @@ # ---- - def __add__(self, scanB): + def __add__(self, other): """Return A+B.""" new = self.duplicate() - new.concatenate(peaksB) + new.concatenate(other) return new # ---- - def __sub__(self, scanB): + def __sub__(self, other): """Return A-B.""" new = self.duplicate() - new.subtract(peaksB) + new.subtract(other) return new # ---- @@ -1945,7 +2173,12 @@ """ # calculate noise - return processing.noise(self.points, minX=minX, maxX=maxX, mz=mz, window=window) + return processing.noise(self.points, + minX = minX, + maxX = maxX, + mz = mz, + window = window + ) # ---- @@ -2011,11 +2244,11 @@ # check slice if maxX < minX: - raise ValueError, 'Invalid m/z slice definition!' + raise ValueError, 'Invalid slice!' # crop points - i1 = self._getIndex(self.points, minX) - i2 = self._getIndex(self.points, maxX) + i1 = processing.findIndex(self.points, minX, dim=2) + i2 = processing.findIndex(self.points, maxX, dim=2) return self.points[i1:i2] # ---- @@ -2064,7 +2297,7 @@ def setPeaklist(self, peaks): - """Set new point.""" + """Set new peaklist.""" # convert peaks to peaklist if isinstance(peaks, peaklist): @@ -2103,8 +2336,8 @@ """ # crop spectrum data - i1 = self._getIndex(self.points, minX) - i2 = self._getIndex(self.points, maxX) + i1 = processing.findIndex(self.points, minX, dim=2) + i2 = processing.findIndex(self.points, maxX, dim=2) self.points = self.points[i1:i2] # crop peaklist data @@ -2155,20 +2388,18 @@ # ---- - def concatenate(self, scanB): - """Add data from given scan. - scanB: (scan) scan to be added - """ + def concatenate(self, other): + """Add data from given scan.""" # check scan - if not isinstance(scanB, scan): + if not isinstance(other, scan): raise TypeError, "Cannot concatenate with non-scan object!" # use spectra only - if len(self.points) or len(scanB.points): + if len(self.points) or len(other.points): # unify raster - data = processing.unifyRaster(self.points, scanB.points) + data = processing.unifyRaster(self.points, other.points) # convert back to arrays pointsA = numpy.array(data[0]) @@ -2184,26 +2415,26 @@ self.peaklist.empty() # use peaklists only - elif len(self.peaklist) or len(scanB.peaklist): - self.peaklist.concatenate(scanB.peaklist) + elif len(self.peaklist) or len(other.peaklist): + self.peaklist.concatenate(other.peaklist) # clear buffers self.reset() # ---- - def subtract(self, scanB): + def subtract(self, other): """Subtract given data points from current scan.""" # check scan - if not isinstance(scanB, scan): + if not isinstance(other, scan): raise TypeError, "Cannot subtract non-scan object!" # use spectra only - if len(self.points) and len(scanB.points): + if len(self.points) and len(other.points): # unify raster - data = processing.unifyRaster(self.points, scanB.points) + data = processing.unifyRaster(self.points, other.points) # convert back to arrays pointsA = numpy.array(data[0]) @@ -2225,7 +2456,7 @@ def smooth(self, method, window, cycles=1): """Smooth data points. - method: ('MA' or 'SG') smoothing method, MA - moving average, SG - Savitzky-Golay + method: ('MA', 'GA' or 'SG') smoothing method, MA - moving average, GA - Gaussian, SG - Savitzky-Golay window: (float) m/z window size for smoothing cycles: (int) number of repeating cycles """ @@ -2234,13 +2465,17 @@ if method.upper() == 'MA': points = processing.smoothMA(self.points, window, cycles) + # apply Gaussian filter + elif method.upper() == 'GA': + points = processing.smoothGA(self.points, window, cycles) + # apply Savitzky-Golay filter elif method.upper() == 'SG': points = processing.smoothSG(self.points, window, cycles) # unknown method else: - raise KeyError, "Unknown smoothing method" + raise KeyError, "Unknown smoothing method! --> " + method # store data self.points = points @@ -2277,11 +2512,11 @@ """ # correct baseline - points = processing.correctBaseline(\ - points=self.points, \ - window=window, \ - smooth=smooth, \ - offset=offset \ + points = processing.correctBaseline( + points = self.points, + window = window, + smooth = smooth, + offset = offset ) # store data @@ -2302,23 +2537,24 @@ baselineWindow: (float) noise calculation window in %/100 baselineSmooth: (bool) smooth baseline baselineOffset: (float) baseline intensity offset in %/100 - smoothMethod: (None or MA or SG) smoothing method, MA - moving average, SG - Savitzky-Golay + smoothMethod: (None, MA, GA or SG) smoothing method, MA - moving average, GA - Gaussian, SG - Savitzky-Golay smoothWindows: (float) m/z window size for smoothing smoothCycles: (int) number of repeating cycles """ # label scan - newPeaklist = processing.labelScan(self.points, \ - pickingHeight=pickingHeight, \ - absThreshold=absThreshold, \ - relThreshold=relThreshold, \ - snThreshold=snThreshold, \ - baselineWindow=baselineWindow, \ - baselineSmooth=baselineSmooth, \ - baselineOffset=baselineOffset, \ - smoothMethod=smoothMethod, \ - smoothWindow=smoothWindow, \ - smoothCycles=smoothCycles + newPeaklist = processing.labelScan( + points = self.points, + pickingHeight = pickingHeight, + absThreshold = absThreshold, + relThreshold = relThreshold, + snThreshold = snThreshold, + baselineWindow = baselineWindow, + baselineSmooth = baselineSmooth, + baselineOffset = baselineOffset, + smoothMethod = smoothMethod, + smoothWindow = smoothWindow, + smoothCycles = smoothCycles ) # update peaklist @@ -2343,15 +2579,16 @@ """ # label peak - newPeak = processing.labelPeak(self.points, \ - mz=mz, \ - minX=minX, \ - maxX=maxX, \ - pickingHeight=pickingHeight, \ - baselineWindow=baselineWindow, \ - baselineSmooth=baselineSmooth, \ - baselineOffset=baselineOffset, \ - baselineData=baselineData \ + newPeak = processing.labelPeak( + points = self.points, + mz = mz, + minX = minX, + maxX = maxX, + pickingHeight = pickingHeight, + baselineWindow = baselineWindow, + baselineSmooth = baselineSmooth, + baselineOffset = baselineOffset, + baselineData = baselineData ) # append peak @@ -2373,12 +2610,13 @@ """ # label point - newPeak = processing.labelPoint(self.points, \ - mz=mz, \ - baselineWindow=baselineWindow, \ - baselineSmooth=baselineSmooth, \ - baselineOffset=baselineOffset, \ - baselineData=baselineData \ + newPeak = processing.labelPoint( + points = self.points, + mz = mz, + baselineWindow = baselineWindow, + baselineSmooth = baselineSmooth, + baselineOffset = baselineOffset, + baselineData = baselineData ) # append peak @@ -2400,17 +2638,17 @@ # find istopes self.peaklist.findIsotopes( - maxCharge=maxCharge, \ - mzTolerance=mzTolerance, \ - intTolerance=intTolerance, \ - isotopeShift=isotopeShift \ + maxCharge = maxCharge, + mzTolerance = mzTolerance, + intTolerance = intTolerance, + isotopeShift = isotopeShift ) # ---- - def deconvolute(self, massType='mo'): + def deconvolute(self, massType=0): """Recalculate peaklist to singly charged. - massType: ('mo' or 'av') mass type used for m/z re-calculation + massType: (0 or 1) mass type used for m/z re-calculation, 0 = monoisotopic, 1 = average """ # delete spectrum points @@ -2430,10 +2668,9 @@ forceWindow: (bool) use default window for all peaks instead of fwhm """ - # group near peaks self.peaklist.groupPeaks( - window=window, \ - forceWindow=forceWindow \ + window = window, + forceWindow = forceWindow ) # ---- @@ -2445,12 +2682,11 @@ snThreshold: (float) signal to noise threshold """ - # remove peaks below threshold - self.peaklist.removeBelow( \ - absThreshold=absThreshold, \ - relThreshold=relThreshold, \ - snThreshold=snThreshold \ - ) + self.peaklist.removeBelow( + absThreshold = absThreshold, + relThreshold = relThreshold, + snThreshold = snThreshold + ) # ---- @@ -2461,68 +2697,24 @@ fwhm: (float) default peak width if not set in peak """ - # remove shoulder peaks - self.peaklist.removeShoulders(\ - window=window, \ - relThreshold=relThreshold, \ - fwhm=fwhm \ - ) + self.peaklist.removeShoulders( + window = window, + relThreshold = relThreshold, + fwhm = fwhm + ) # ---- def removeIsotopes(self): """Remove isotopes from current peaklist.""" - - # remove isotopes self.peaklist.removeIsotopes() # ---- def removeUnknown(self): """Remove unknown peaks (no charge set) from current peaklist.""" - - # remove unknowns self.peaklist.removeUnknown() # ---- - # HELPERS - - def _getIndex(self, points, x): - """Get nearest higher index for selected point.""" - - lo = 0 - hi = len(points) - while lo < hi: - mid = (lo + hi) / 2 - if x < points[mid][0]: - hi = mid - else: - lo = mid + 1 - - return lo - # ---- - - - def _interpolateLine(self, p1, p2, x=None, y=None): - """Get line interpolated X or Y value.""" - - # check points - if p1[0] == p2[0] and x!=None: - return max(p1[1], p2[1]) - elif p1[0] == p2[0] and y!=None: - return p1[0] - - # get equation - m = (p2[1] - p1[1])/(p2[0] - p1[0]) - b = p1[1] - m * p1[0] - - # get point - if x != None: - return m * x + b - elif y != None: - return (y - b) / m - # ---- - - diff -Nru mmass-3.12.1/mspy/plot/canvas.py mmass-4.0.0/mspy/plot/canvas.py --- mmass-3.12.1/mspy/plot/canvas.py 2011-06-23 12:16:48.000000000 +0000 +++ mmass-4.0.0/mspy/plot/canvas.py 2011-11-28 15:25:57.000000000 +0000 @@ -69,6 +69,7 @@ 'yScaleFactor': 0.1, 'maxZoom': 0.001, 'checkLimits': True, + 'reverseScrolling': False, 'reverseDrawing': False, 'canvasColour': (255, 255, 255), 'plotColour': (255, 255, 255), @@ -162,7 +163,10 @@ minX = rangeXmin if maxX > rangeXmax: maxX = rangeXmax - + if minX > maxX: + minX = rangeXmin + maxX = rangeXmax + # draw plot self.draw(self.lastDraw[0], (minX, maxX), (minY, maxY)) else: @@ -549,13 +553,15 @@ direction = 1 if evt.GetWheelRotation() < 0: direction = -1 + if self.properties['reverseScrolling']: + direction *= -1 # set new charge and count for isotope ruler if self.mouseFce == 'isotoperuler' and evt.ShiftDown(): if evt.AltDown() or evt.ControlDown(): - self.currentIsotopeLines = min(50, self.currentIsotopeLines + 1*direction) + self.currentIsotopeLines = min(50, self.currentIsotopeLines + direction) else: - self.currentCharge = max(1, self.currentCharge + 1*direction) + self.currentCharge = max(1, self.currentCharge + direction) self.currentCharge = min(50, self.currentCharge) self.drawMouseTracker() return @@ -1466,7 +1472,7 @@ xFormat = '%0.'+`self.properties['xPosDigits']`+'f' yFormat = '%0.'+`self.properties['yPosDigits']`+'f' xText = xFormat % (self.cursorPosition[0]) - if self.cursorPosition[1] > 10000: + if abs(self.cursorPosition[1]) > 10000: yFormat = '%.2e' yText = yFormat % (self.cursorPosition[1]) diff -Nru mmass-3.12.1/mspy/plot/objects.py mmass-4.0.0/mspy/plot/objects.py --- mmass-3.12.1/mspy/plot/objects.py 2011-07-12 12:33:08.000000000 +0000 +++ mmass-4.0.0/mspy/plot/objects.py 2011-08-23 07:55:59.000000000 +0000 @@ -871,7 +871,7 @@ # draw points if self.properties['showPoints']: pencolour = [max(x-70,0) for x in self.properties['pointColour']] - pen = wx.Pen(pencolour, 1*printerScale['drawings'], wx.SOLID) + pen = wx.Pen(pencolour, self.properties['lineWidth']*printerScale['drawings'], wx.SOLID) brush = wx.Brush(self.properties['pointColour'], wx.SOLID) dc.SetPen(pen) dc.SetBrush(brush) @@ -1725,7 +1725,7 @@ def _getIndex(points, x): - """Get nearest index for selected point.""" + """Get nearest lower index for selected point.""" lo = 0 hi = len(points) diff -Nru mmass-3.12.1/mspy/plot/viewer.py mmass-4.0.0/mspy/plot/viewer.py --- mmass-3.12.1/mspy/plot/viewer.py 2011-07-04 07:19:16.000000000 +0000 +++ mmass-4.0.0/mspy/plot/viewer.py 2011-11-29 14:56:46.000000000 +0000 @@ -57,14 +57,15 @@ ] # init plot canvas - self.plotCanvas = canvas.canvas(self, size=(700,400), \ - xLabel='m/z', \ - yLabel='a.i.', \ - showPosBar=True, \ - showIntBar=True, \ - posBarHeight=6, \ - intBarHeight=6, \ - xPosDigits=4, \ + self.plotCanvas = canvas.canvas(self, + size = (700,400), + xLabel = 'm/z', + yLabel = 'a.i.', + showPosBar = True, + showIntBar = True, + posBarHeight = 6, + intBarHeight = 6, + xPosDigits = 4 ) self.plotCanvas.setProperties(**attr) self.plotCanvas.setMFunction('cross') @@ -75,7 +76,11 @@ # append data sets for x, item in enumerate(data): - if isinstance(item, mspy.scan): + if isinstance(item, mspy.plot.points): + obj = item + elif isinstance(item, mspy.plot.spectrum): + obj = item + elif isinstance(item, mspy.scan): obj = objects.spectrum(item) else: obj = objects.points(item) diff -Nru mmass-3.12.1/mspy/processing.py mmass-4.0.0/mspy/processing.py --- mmass-3.12.1/mspy/processing.py 2011-08-28 19:11:39.000000000 +0000 +++ mmass-4.0.0/mspy/processing.py 2011-11-30 12:58:29.000000000 +0000 @@ -16,17 +16,14 @@ # ------------------------------------------------------------------------- # load libs -import re -import os.path import copy import numpy -import math from numpy.linalg import solve as solveLinEq # load stopper from stopper import CHECK_FORCE_QUIT -# register essential objects +# register essential objects and modules import objects import blocks @@ -61,24 +58,16 @@ # ---- -def mz(mass, charge, currentCharge=0, agentFormula='H', agentCharge=1, massType='mo'): +def mz(mass, charge, currentCharge=0, agentFormula='H', agentCharge=1, massType=0): """Calculate m/z value for given mass and charge. mass: (tuple of (Mo,Av) or float) charge: (int) desired charge of ion currentCharge: (int) if mass is charged already agentFormula: (str or formula) charging agent formula agentCharge: (int) charging agent charge - massType: ('mo' or 'av') used mass type if mass value is float + massType: (0 or 1) used mass type if mass value is float, 0 = monoisotopic, 1 = average """ - # set mass type - if massType == 'mo': - massType = 0 - elif massType == 'av': - massType = 1 - else: - raise ValueError, "Mass type must be 'mo' or 'av' --> " + massType - # check agent formula if agentFormula != 'e' and not isinstance(agentFormula, objects.compound): agentFormula = objects.compound(agentFormula) @@ -113,33 +102,6 @@ # ---- -def coverage(ranges, length, trueIndexes=False): - """Calculate sequence coverage. - ranges: (list of mspy.sequence or list of user ranges (start,stop)) - length: (int) parent sequence length - """ - - # check data - if not ranges: - return 0. - - # make a blank sequence - blank = length*[0] - - # list of ranges - for r in ranges: - if trueIndexes: - for x in range(r[0], r[1]): - blank[x]=(1) - else: - for x in range(r[0]-1, r[1]): - blank[x]=(1) - - # get sequence coverage - return 100.0*blank.count(1)/length -# ---- - - # ISOTOPIC PATTERN # ---------------- @@ -297,11 +259,10 @@ peakWidth = fwhm/1.66 # calulate peak - x = _getIndex1D(raster, (peak.mz-5*peakFwhm)) - i2 = _getIndex1D(raster, (peak.mz+5*peakFwhm)) - while x < i2: - intensities[x] += peak.intensity*numpy.exp(-1*(pow(raster[x]-peak.mz,2))/pow(peakWidth,2)) - x += 1 + i1 = findIndex(raster, (peak.mz-5*peakFwhm), dim=1) + i2 = findIndex(raster, (peak.mz+5*peakFwhm), dim=1) + for i in xrange(i1, i2): + intensities[i] += peak.intensity*numpy.exp(-1*(pow(raster[i]-peak.mz,2))/pow(peakWidth,2)) # add random noise if noise: @@ -353,36 +314,34 @@ # ---- -def averagine(mass, composition, threshold=0.005, fwhm=0.2): - """Calculate isotopic distribution for given mass and building block. +def averagine(mass, charge=0, composition=AVERAGE_AMINO): + """Calculate average formula for given mass and building block composition. mass: (float) neutral mass to be modeled + charge: (int) charge to be calculated composition: (dict) building block composition - relIntThreshold: (float) peak intensity threshold - fwhm: (float) peak fwhm """ - # get number of possible blocks for given m/z value - blockFormula = '' + # get average mass of block + blockMass = 0 for element in composition: - blockFormula += '%s%0.f' % (element, composition[element]*100) - blockMass = objects.compound(blockFormula).mass() - count = int(max(1, (round(mass/blockMass[0]*100)))) + blockMass += blocks.elements[element].mass[1] * composition[element] + + # get block count + neutralMass = mz(mass, charge=0, currentCharge=charge, massType=1) + count = max(1, neutralMass/blockMass) # make formula formula = '' for element in composition: - formula += '%s%0.f' % (element, composition[element]*count) + formula += '%s%d' % (element, int(composition[element]*count)) formula = objects.compound(formula) - # calc pattern - distribution = [] - pattern = formula.pattern(threshold=threshold, fwhm=fwhm) - - # make distribution - for peak in pattern: - distribution.append(peak[1]) + # add some hydrogens + hydrogens = int(round((neutralMass - formula.mass(1)) / blocks.elements['H'].mass[1])) + hydrogens = max(hydrogens, -1*formula.count('H')) + formula += 'H%d' % hydrogens - return distribution + return formula # ---- @@ -416,8 +375,8 @@ m = (rasterRange[1] - rasterRange[0]) / (mzRange[1] - mzRange[0]) b = rasterRange[0] - m * mzRange[0] - size = int((mzRange[1] - mzRange[0]) / rasterRange[0]) + 1 - raster = numpy.zeros(size, float) + size = ((mzRange[1] - mzRange[0]) / rasterRange[0]) + 2 + raster = numpy.zeros(int(size), float) i = 0 x = mzRange[0] @@ -447,12 +406,12 @@ pass elif mz != None: window = mz*window - i1 = _getIndex2D(points, mz-window) - i2 = _getIndex2D(points, mz+window) + i1 = findIndex(points, mz-window, dim=2) + i2 = findIndex(points, mz+window, dim=2) points = points[i1:i2] elif minX != None and maxX != None: - i1 = _getIndex2D(points, minX) - i2 = _getIndex2D(points, maxX) + i1 = findIndex(points, minX, dim=2) + i2 = findIndex(points, maxX, dim=2) # check indexes if i1 == i2: @@ -507,22 +466,26 @@ levels = [] widths = [] for x in raster: - i1 = _getIndex2D(points, x-x*window) - i2 = _getIndex2D(points, x+x*window) + i1 = findIndex(points, x-x*window, dim=2) + i2 = findIndex(points, x+x*window, dim=2) if i1 == i2: noiseLevel = 0.0 noiseWidth = 1.0 else: noiseLevel = numpy.median(intArr[i1:i2]) - noiseWidth = float(numpy.median(numpy.absolute(intArr[i1:i2] - noiseLevel)))*2 + noiseWidth = abs(float(numpy.median(numpy.absolute(intArr[i1:i2] - noiseLevel)))*2) levels.append([x, noiseLevel]) widths.append([x, noiseWidth]) # smooth baseline if smooth: - window = 5 * window * (points[-1][0]-points[0][0]) + window = 5 * window * (points[-1][0] - points[0][0]) levels = smoothSG(numpy.array(levels), window, 2) - widths = smoothSG(numpy.array(widths), window, 2) + widths = smoothGA(numpy.array(widths), window, 2) + + # ensure there are positive values in widths + for i in range(len(widths)): + widths[i][1] = abs(widths[i][1]) # apply relative offset and add widths to baseline buff = [] @@ -533,7 +496,7 @@ # ---- -def smoothMA(points, window, cycles=1): +def smoothMA(points, window, cycles=1, style='flat'): """Return data points smoothed by moving average. points: (numpy.array) points to be smoothed window: (float) m/z window size for smoothing @@ -542,10 +505,11 @@ # approximate number of points within window window = int(window*len(points)/(points[-1][0]-points[0][0])) - if window < 2: + window = min(window, len(points)) + if window < 3: return points.copy() if not window % 2: - window += 1 + window -= 1 # unpack mz and intensity xAxis, yAxis = numpy.hsplit(points,2) @@ -557,9 +521,16 @@ CHECK_FORCE_QUIT() - s=numpy.r_[2*yAxis[0]-yAxis[window:1:-1],yAxis,2*yAxis[-1]-yAxis[-1:-window:-1]] - w=numpy.ones(window,'f') - y=numpy.convolve(w/w.sum(),s,mode='same') + if style == 'flat': + w = numpy.ones(window,'f') + elif style == 'gaussian': + r = numpy.array([(i-(window-1)/2.) for i in range(window)]) + w = numpy.exp(-(r**2/(window/4.)**2)) + else: + w = eval('numpy.'+style+'(window)') + + s = numpy.r_[yAxis[window-1:0:-1], yAxis, yAxis[-2:-window-1:-1]] + y = numpy.convolve(w/w.sum(), s, mode='same') yAxis = y[window-1:-window+1] cycles -=1 @@ -572,6 +543,22 @@ # ---- +def smoothGA(points, window, cycles=1): + """Return data points smoothed by Gaussian filter. + points: (numpy.array) points to be smoothed + window: (float) m/z window size for smoothing + cycles: (int) number of repeating cycles + """ + + return smoothMA( + points = points, + window = window, + cycles = cycles, + style = 'gaussian' + ) +# ---- + + def smoothSG(points, window, cycles=1, order=3): """Return data points smoothed by Savitzky-Golay filter. points: (numpy.array) points to be smoothed @@ -638,12 +625,12 @@ return False # get mz index - index = _getIndex2D(points, mz) + index = findIndex(points, mz, dim=2) if not index or index == len(points): return False # get intensity - intens = _interpolateLine(points[index-1], points[index], x=mz) + intens = interpolateLine(points[index-1], points[index], x=mz) return intens # ---- @@ -661,11 +648,11 @@ return None # get indexes - index = _getIndex2D(points, mz) - if index < 1: + index = findIndex(points, mz, dim=2) + if index < 1 or index == len(points): return None - leftIndx = index-1 + leftIndx = index - 1 while leftIndx >= 0: if points[leftIndx][1] <= intensity: break @@ -679,10 +666,10 @@ rightIndx += 1 # get mz - leftMZ = _interpolateLine(points[leftIndx], points[leftIndx+1], y=intensity) - rightMZ = _interpolateLine(points[rightIndx-1], points[rightIndx], y=intensity) + leftMZ = interpolateLine(points[leftIndx], points[leftIndx+1], y=intensity) + rightMZ = interpolateLine(points[rightIndx-1], points[rightIndx], y=intensity) - return rightMZ - leftMZ + return abs(rightMZ - leftMZ) # ---- @@ -715,10 +702,13 @@ # get peak baseline and s/n i = 0 - while baselineData[i][0] < mz: + while i < len(baselineData)-1 and baselineData[i][0] < mz: i += 1 - base = _interpolateLine((baselineData[i-1][0], baselineData[i-1][1]), (baselineData[i][0], baselineData[i][1]), x=mz) - sn = (intens - base) / _interpolateLine((baselineData[i-1][0], baselineData[i-1][2]), (baselineData[i][0], baselineData[i][2]), x=mz) + base = interpolateLine((baselineData[i-1][0], baselineData[i-1][1]), (baselineData[i][0], baselineData[i][1]), x=mz) + noiseWidth = interpolateLine((baselineData[i-1][0], baselineData[i-1][2]), (baselineData[i][0], baselineData[i][2]), x=mz) + sn = None + if noiseWidth: + sn = (intens - base) / interpolateLine((baselineData[i-1][0], baselineData[i-1][2]), (baselineData[i][0], baselineData[i][2]), x=mz) # check peak intensity if intens <= base: @@ -762,14 +752,14 @@ return False # get left index - i1 = _getIndex2D(points, minX) + i1 = findIndex(points, minX, dim=2) indexMax = i1 if not (0 < i1 < len(points)): return False # get right index if maxX != None: - i2 = _getIndex2D(points, maxX) + i2 = findIndex(points, maxX, dim=2) if not (0 < i2 < len(points)): return False @@ -785,9 +775,9 @@ # get picking height i = 0 mzMax = points[indexMax][0] - while baselineData[i][0] < mzMax: + while i < len(baselineData)-1 and baselineData[i][0] < mzMax: i += 1 - noiseLevel = _interpolateLine((baselineData[i-1][0], baselineData[i-1][1]), (baselineData[i][0], baselineData[i][1]), x=mzMax) + noiseLevel = interpolateLine((baselineData[i-1][0], baselineData[i-1][1]), (baselineData[i][0], baselineData[i][1]), x=mzMax) height = ((points[indexMax][1] - noiseLevel) * pickingHeight) + noiseLevel # get centroided m/z @@ -796,44 +786,46 @@ if points[leftIndx][1] <= height: break leftIndx -= 1 - leftMZ = _interpolateLine(points[leftIndx], points[leftIndx+1], y=height) + leftMZ = interpolateLine(points[leftIndx], points[leftIndx+1], y=height) rightIndx = indexMax while rightIndx < (len(points)-1): if points[rightIndx][1] <= height: break rightIndx += 1 - rightMZ = _interpolateLine(points[rightIndx-1], points[rightIndx], y=height) + rightMZ = interpolateLine(points[rightIndx-1], points[rightIndx], y=height) # check range - if mz == None and (leftMZ < minX or rightMZ > maxX): + if mz == None and (leftMZ < minX or rightMZ > maxX) and (leftMZ != rightMZ): return False # label peak in the newly found selection - if mz != None: - peak = labelPeak(\ - points=points, \ - minX=leftMZ, \ - maxX=rightMZ, \ - pickingHeight=pickingHeight, \ - baselineData=baselineData \ + if mz != None and leftMZ != rightMZ: + peak = labelPeak( + points = points, + minX = leftMZ, + maxX = rightMZ, + pickingHeight = pickingHeight, + baselineData = baselineData ) return peak # label current point else: - peak = labelPoint(\ - points=points, \ - mz=((leftMZ + rightMZ)/2), \ - baselineData=baselineData \ + peak = labelPoint( + points = points, + mz = ((leftMZ + rightMZ)/2), + baselineData = baselineData ) return peak # ---- -def labelScan(points, pickingHeight=0.75, absThreshold=0., relThreshold=0., snThreshold=0., baselineWindow=0.1, baselineSmooth=True, baselineOffset=0., smoothMethod=None, smoothWindow=0.2, smoothCycles=1): +def labelScan(points, minX=None, maxX=None, pickingHeight=0.75, absThreshold=0., relThreshold=0., snThreshold=0., baselineWindow=0.1, baselineSmooth=True, baselineOffset=0., baselineData=None, smoothMethod=None, smoothWindow=0.2, smoothCycles=1): """Return centroided peaklist for given data points. points: (numpy array) spectrum data points + minX: (float) starting m/z value + maxX: (float) ending m/z value pickingHeight: (float) peak picking height for centroiding absThreshold: (float) absolute intensity threshold relThreshold: (float) relative intensity threshold @@ -841,7 +833,8 @@ baselineWindow: (float) noise calculation window in %/100 baselineSmooth: (bool) smooth baseline baselineOffset: (float) baseline intensity offset in %/100 - smoothMethod: (None or MA or SG) smoothing method, MA - moving average, SG - Savitzky-Golay + baselineData: (list of [x, noiseLevel, noiseWidth]) precalculated baseline + smoothMethod: (None, MA GA or SG) smoothing method, MA - moving average, GA - Gaussian, SG - Savitzky-Golay smoothWindows: (float) m/z window size for smoothing smoothCycles: (int) number of repeating cycles """ @@ -850,14 +843,23 @@ if len(points) == 0: return objects.peaklist() - # get original baseline - oribase = baseline(points, window=baselineWindow, smooth=baselineSmooth, offset=baselineOffset) + # get baseline data + if baselineData == None: + baselineData = baseline(points, window=baselineWindow, smooth=baselineSmooth, offset=baselineOffset) CHECK_FORCE_QUIT() + # crop data + if minX != None and maxX != None: + i1 = findIndex(points, minX, dim=2) + i2 = findIndex(points, maxX, dim=2) + points = points[i1:i2] + # apply smoothing if smoothMethod and smoothMethod.upper() == 'MA': points = smoothMA(points, smoothWindow, smoothCycles) + elif smoothMethod and smoothMethod.upper() == 'GA': + points = smoothGA(points, smoothWindow, smoothCycles) elif smoothMethod and smoothMethod.upper() == 'SG': points = smoothSG(points, smoothWindow, smoothCycles) @@ -885,13 +887,15 @@ i = 0 basepeak = 0 for peak in buff: - while oribase[i][0] < peak[0]: + while i < len(baselineData)-1 and baselineData[i][0] < peak[0]: i += 1 - b1 = oribase[i-1] - b2 = oribase[i] - peak[2] = _interpolateLine((b1[0], b1[1]), (b2[0], b2[1]), x=peak[0]) + b1 = baselineData[i-1] + b2 = baselineData[i] + peak[2] = interpolateLine((b1[0], b1[1]), (b2[0], b2[1]), x=peak[0]) intens = peak[1] - peak[2] - peak[3] = intens/_interpolateLine((b1[0], b1[2]), (b2[0], b2[2]), x=peak[0]) + noiseWidth = interpolateLine((b1[0], b1[2]), (b2[0], b2[2]), x=peak[0]) + if noiseWidth: + peak[3] = intens/noiseWidth if intens > basepeak: basepeak = intens @@ -901,7 +905,7 @@ threshold = max(basepeak * relThreshold, absThreshold) localMaxima = [] for peak in buff: - if peak[0] > 0 and (peak[1] - peak[2]) >= threshold and peak[3] >= snThreshold: + if peak[0] > 0 and (peak[1] - peak[2]) >= threshold and (not peak[3] or peak[3] >= snThreshold): localMaxima.append(peak) # make centroides @@ -918,7 +922,7 @@ height = ((peak[1]-peak[2]) * pickingHeight) + peak[2] # get peak indexes - index = _getIndex2D(points, peak[0]) + index = findIndex(points, peak[0], dim=2) if not (0 < index < len(points)): continue @@ -936,8 +940,8 @@ rightIndx += 1 # get mz - leftMZ = _interpolateLine(points[leftIndx], points[leftIndx+1], y=height) - rightMZ = _interpolateLine(points[rightIndx-1], points[rightIndx], y=height) + leftMZ = interpolateLine(points[leftIndx], points[leftIndx+1], y=height) + rightMZ = interpolateLine(points[rightIndx-1], points[rightIndx], y=height) peak[0] = (leftMZ + rightMZ)/2 # get intensity @@ -962,13 +966,15 @@ i = 0 basepeak = 0 for peak in buff: - while oribase[i][0] < peak[0]: + while i < len(baselineData)-1 and baselineData[i][0] < peak[0]: i += 1 - b1 = oribase[i-1] - b2 = oribase[i] - peak[2] = _interpolateLine((b1[0], b1[1]), (b2[0], b2[1]), x=peak[0]) + b1 = baselineData[i-1] + b2 = baselineData[i] + peak[2] = interpolateLine((b1[0], b1[1]), (b2[0], b2[1]), x=peak[0]) intens = peak[1] - peak[2] - peak[3] = intens/_interpolateLine((b1[0], b1[2]), (b2[0], b2[2]), x=peak[0]) + noiseWidth = interpolateLine((b1[0], b1[2]), (b2[0], b2[2]), x=peak[0]) + if noiseWidth: + peak[3] = intens/noiseWidth peak[4] = peakWidth(points, peak[0], (peak[2] + intens * 0.5)) if intens > basepeak: basepeak = intens @@ -979,7 +985,7 @@ threshold = max(basepeak * relThreshold, absThreshold) centroides = [] for peak in buff: - if peak[0] > 0 and (peak[1] - peak[2]) >= threshold and peak[3] >= snThreshold: + if peak[0] > 0 and (peak[1] - peak[2]) >= threshold and (not peak[3] or peak[3] >= snThreshold): centroides.append(objects.peak(mz=peak[0], ai=peak[1], base=peak[2], sn=peak[3], fwhm=peak[4])) # return peaklist object @@ -1000,39 +1006,35 @@ elif len(isotopes) == 1: return isotopes[0] + # check peaklist object + if not isinstance(isotopes, objects.peaklist): + isotopes = objects.peaklist(isotopes) + # get sums sumMZ = 0 sumIntensity = 0 - sumBase = 0 for isotope in isotopes: sumMZ += isotope.mz * isotope.intensity sumIntensity += isotope.intensity - sumBase += isotope.base - # get m/z + # get average m/z mz = sumMZ / sumIntensity - # get basepeak - basepeak = isotopes[0] - for isotope in isotopes: - if isotope.intensity > basepeak.intensity: - basepeak = isotope - # get ai, base and sn - base = basepeak.base - ai = basepeak.ai - sn = basepeak.sn + base = isotopes.basepeak.base + sn = isotopes.basepeak.sn + fwhm = isotopes.basepeak.fwhm if intensity == 'sum': - base = sumBase / len(isotopes) ai = base + sumIntensity - sn = (ai - base) * basepeak.sn / (basepeak.ai - basepeak.base) elif intensity == 'average': - base = sumBase / len(isotopes) ai = base + sumIntensity / len(isotopes) - sn = (ai - base) * basepeak.sn / (basepeak.ai - basepeak.base) + else: + ai = isotopes.basepeak.ai + if isotopes.basepeak.sn: + sn = (ai - base) * isotopes.basepeak.sn / (isotopes.basepeak.ai - base) # get envelope width - minInt = basepeak.intensity * height + minInt = isotopes.basepeak.intensity * height i1 = None i2 = None for x, isotope in enumerate(isotopes): @@ -1044,17 +1046,78 @@ mz1 = isotopes[i1].mz mz2 = isotopes[i2].mz if i1 != 0: - mz1 = _interpolateLine((isotopes[i1-1].mz, isotopes[i1-1].ai), (isotopes[i1].mz, isotopes[i1].ai), y=minInt) + mz1 = interpolateLine((isotopes[i1-1].mz, isotopes[i1-1].ai), (isotopes[i1].mz, isotopes[i1].ai), y=minInt) if i2 < len(isotopes)-1: - mz2 = _interpolateLine((isotopes[i2].mz, isotopes[i2].ai), (isotopes[i2+1].mz, isotopes[i2+1].ai), y=minInt) + mz2 = interpolateLine((isotopes[i2].mz, isotopes[i2].ai), (isotopes[i2+1].mz, isotopes[i2+1].ai), y=minInt) + if mz1 != mz2: + fwhm = abs(mz2 - mz1) + + # make peak + peak = objects.peak(mz=mz, ai=ai, base=base, sn=sn, fwhm=fwhm) + + return peak +# ---- + + +def envelopeMonoisotope(isotopes, charge, intensity='maximum'): + """Calculate envelope centroid for given isotopes. + isotopes: (mspy.peaklist or list of peaks) + charge: (int) peak charge + intensity: (maximum | sum | average) haw to calculate envelope label intensity + """ + + # check isotopes + if len(isotopes) == 0: + return False + + # check peaklist object + if not isinstance(isotopes, objects.peaklist): + isotopes = objects.peaklist(isotopes) + + # calc averagine + avFormula = averagine(isotopes.basepeak.mz, charge=charge, composition=AVERAGE_AMINO) + avPattern = avFormula.pattern(fwhm=0.1, threshold=0.001, charge=charge) + avPattern = objects.peaklist(avPattern) + + # get envelope centroid + points = numpy.array([(p.mz, p.intensity) for p in isotopes]) + baseline = numpy.array([(points[0][0], 0., 0.), (points[-1][0], 0., 0.)]) + centroid = labelPeak(points, mz=isotopes.basepeak.mz, pickingHeight=0.8, baselineData=baseline) + if not centroid: + centroid = isotopes.basepeak + + # get averagine centroid + points = numpy.array([(p.mz, p.intensity) for p in avPattern]) + baseline = numpy.array([(points[0][0], 0., 0.), (points[-1][0], 0., 0.)]) + avCentroid = labelPeak(points, mz=avPattern.basepeak.mz, pickingHeight=0.8, baselineData=baseline) + if not avCentroid: + avCentroid = avPattern.basepeak + + # align profiles and get monoisotopic mass + shift = centroid.mz - avCentroid.mz + errors = [(abs(p.mz - avPattern.basepeak.mz - shift), p.mz) for p in isotopes] + mz = min(errors)[1] - (avPattern.basepeak.mz - avFormula.mz(charge)[0]) + + # sum intensities + sumIntensity = 0 + for isotope in isotopes: + sumIntensity += isotope.intensity - if mz1 == mz2: - fwhm = basepeak.fwhm + # get ai, base and sn + base = isotopes.basepeak.base + sn = isotopes.basepeak.sn + fwhm = isotopes.basepeak.fwhm + if intensity == 'sum': + ai = base + sumIntensity + elif intensity == 'average': + ai = base + sumIntensity / len(isotopes) else: - fwhm = mz2 - mz1 + ai = isotopes.basepeak.ai + if isotopes.basepeak.sn: + sn = (ai - base) * isotopes.basepeak.sn / (isotopes.basepeak.ai - base) # make peak - peak = objects.peak(mz=mz, ai=ai, base=base, sn=sn, fwhm=fwhm) + peak = objects.peak(mz=mz, ai=ai, base=base, sn=sn, fwhm=fwhm, isotope=0) return peak # ---- @@ -1161,10 +1224,10 @@ # ---- -def deconvolute(peaklist, massType='mo'): +def deconvolute(peaklist, massType=0): """Recalculate peaklist to singly charged. peaklist: (mspy.peaklist) peak list to deconvolute - massType: ('mo' or 'av') mass type used for m/z re-calculation + massType: (0 or 1) mass type used for m/z re-calculation, 0 = monoisotopic, 1 = average """ # recalculate peaks @@ -1226,6 +1289,10 @@ baselineData: (list of [x, noiseLevel]) precalculated baseline """ + # check points + if len(points) == 0: + return points + # get baseline if baselineData == None: baselineData = baseline(points, window=window, smooth=smooth, offset=offset) @@ -1301,12 +1368,12 @@ break if pointsA[i][0] < pointsB[i][0]: - intens = _interpolateLine(pointsB[i-1], pointsB[i], x=pointsA[i][0]) + intens = interpolateLine(pointsB[i-1], pointsB[i], x=pointsA[i][0]) pointsB.insert(i, [pointsA[i][0], intens]) countB += 1 elif pointsA[i][0] > pointsB[i][0]: - intens = _interpolateLine(pointsA[i-1], pointsA[i], x=pointsB[i][0]) + intens = interpolateLine(pointsA[i-1], pointsA[i], x=pointsB[i][0]) pointsA.insert(i, [pointsB[i][0], intens]) countA += 1 @@ -1390,7 +1457,7 @@ # ---- -def _leastSquaresFit(model, parameters, data, max_iterations=None, stopping_limit=1e-7): +def _leastSquaresFit(model, parameters, data, maxIterations=None, limit=1e-7): """General non-linear least-squares fit using the Levenberg-Marquardt algorithm and automatic derivatives.""" @@ -1404,355 +1471,166 @@ l = 0.001 chi_sq, alpha = _chiSquare(model, p, data) niter = 0 - while 1: + + while True: + niter += 1 + delta = solveLinEq(alpha+l*numpy.diagonal(alpha)*id,-0.5*numpy.array(chi_sq[1])) next_p = map(lambda a,b: a+b, p, delta) + next_chi_sq, next_alpha = _chiSquare(model, next_p, data) if next_chi_sq > chi_sq: l = 10.*l + elif chi_sq[0] - next_chi_sq[0] < limit: + break else: l = 0.1*l - if chi_sq[0] - next_chi_sq[0] < stopping_limit: break p = next_p chi_sq = next_chi_sq alpha = next_alpha - niter = niter + 1 - if max_iterations is not None and niter == max_iterations: - pass + + if maxIterations and niter == maxIterations: + break + return map(lambda p: p[0], next_p), next_chi_sq[0] # ---- -def _isDerivVar(x): - """Returns 1 if |x| is a DerivVar object.""" - return hasattr(x,'value') and hasattr(x,'deriv') -# ---- - - def _chiSquare(model, parameters, data): - """ Count Chi-square. """ + """Count chi-square.""" n_param = len(parameters) - chi_sq = 0. alpha = numpy.zeros((n_param, n_param)) + + chi_sq = _DerivVar(0., []) for point in data: - sigma = 1 - if len(point) == 3: - sigma = point[2] f = model(parameters, point[0]) - chi_sq = chi_sq + ((f-point[1])/sigma)**2 - d = numpy.array(f[1])/sigma + chi_sq += (f-point[1])**2 + d = numpy.array(f[1]) alpha = alpha + d[:,numpy.newaxis]*d - return chi_sq, alpha -# ---- - - -def _mapderiv(func, a, b): - """ Map a binary function on two first derivative lists. """ - nvars = max(len(a), len(b)) - a = a + (nvars-len(a))*[0] - b = b + (nvars-len(b))*[0] - return map(func, a, b) + return chi_sq, alpha # ---- class _DerivVar: """This module provides automatic differentiation for functions with any number of variables.""" - def __init__(self, value, index=0, order=1): - if order > 1: - raise ValueError, 'Only first-order derivatives' + def __init__(self, value, index=0): self.value = value - if order == 0: - self.deriv = [] - elif type(index) == type([]): + if type(index) == type([]): self.deriv = index else: self.deriv = index*[0] + [1] + def _mapderiv(self, func, a, b): + nvars = max(len(a), len(b)) + a = a + (nvars-len(a))*[0] + b = b + (nvars-len(b))*[0] + return map(func, a, b) + def __getitem__(self, item): - if item < 0 or item > 1: - raise ValueError, 'Index out of range' if item == 0: return self.value - else: + elif item == 1: return self.deriv - - def __coerce__(self, other): - if _isDerivVar(other): - return self, other else: - return self, _DerivVar(other, []) + raise IndexError def __cmp__(self, other): - return cmp(self.value, other.value) + if isinstance(other, _DerivVar): + return cmp(self.value, other.value) + else: + return cmp(self.value, other) def __add__(self, other): - return _DerivVar(self.value + other.value, _mapderiv(lambda a,b: a+b, self.deriv, other.deriv)) - __radd__ = __add__ + if isinstance(other, _DerivVar): + return _DerivVar(self.value + other.value, self._mapderiv(lambda a,b: a+b, self.deriv, other.deriv)) + else: + return _DerivVar(self.value + other, self.deriv) + + def __radd__(self, other): + if isinstance(other, _DerivVar): + self.value += other.value + self.deriv = self._mapderiv(lambda a,b: a+b, self.deriv, other.deriv) + return self + else: + self.value += other + return self def __sub__(self, other): - return _DerivVar(self.value - other.value, _mapderiv(lambda a,b: a-b, self.deriv, other.deriv)) + if isinstance(other, _DerivVar): + return _DerivVar(self.value - other.value, self._mapderiv(lambda a,b: a-b, self.deriv, other.deriv)) + else: + return _DerivVar(self.value - other, self.deriv) - def __mul__(self, other): - return _DerivVar(self.value*other.value, - _mapderiv(lambda a,b: a+b, - map(lambda x,f=other.value:f*x, self.deriv), - map(lambda x,f=self.value:f*x, other.deriv))) + def __rsub__(self, other): + if isinstance(other, _DerivVar): + self.value -= other.value + self.deriv = self._mapderiv(lambda a,b: a-b, self.deriv, other.deriv) + return self + else: + self.value -= other + return self - __rmul__ = __mul__ + def __mul__(self, other): + if isinstance(other, _DerivVar): + return _DerivVar(self.value * other.value, self._mapderiv(lambda a,b: a+b, map(lambda x,f=self.value:f*x, other.deriv), map(lambda x,f=other.value:f*x, self.deriv))) + else: + return _DerivVar(self.value * other, map(lambda x,f=other:f*x, self.deriv)) def __div__(self, other): - if not other.value: - raise ZeroDivisionError, 'DerivVar division' - inv = 1./other.value - return _DerivVar(self.value*inv, - _mapderiv(lambda a,b: a-b, - map(lambda x,f=inv: f*x, self.deriv), - map(lambda x,f=self.value*inv*inv: f*x, - other.deriv))) - - def __rdiv__(self, other): - return other/self - - def __pow__(self, other, z=None): - if z is not None: - raise TypeError, 'DerivVar does not support ternary pow()' - val1 = pow(self.value, other.value-1) - val = val1*self.value - deriv1 = map(lambda x,f=val1*other.value: f*x, self.deriv) - if _isDerivVar(other) and len(other.deriv) > 0: - deriv2 = map(lambda x, f=val*numpy.log(self.value): f*x, - other.deriv) - return _DerivVar(val,_mapderiv(lambda a,b: a+b, deriv1, deriv2)) + if isinstance(other, _DerivVar): + inv = 1./other.value + return _DerivVar(self.value * inv, self._mapderiv(lambda a,b: a-b, map(lambda x,f=inv: f*x, self.deriv), map(lambda x,f=self.value*inv*inv: f*x, other.deriv))) else: - return _DerivVar(val,deriv1) + inv = 1./value + return _DerivVar(self.value * inv, map(lambda x,f=inv:f*x, self.deriv)) + + def __pow__(self, other): + val1 = pow(self.value, other-1) + deriv1 = map(lambda x,f=val1*other: f*x, self.deriv) + return _DerivVar(val1*self.value, deriv1) + + def __abs__(self): + absvalue = abs(self.value) + return _DerivVar(absvalue, map(lambda a, d=self.value/absvalue: d*a, self.deriv)) - def __rpow__(self, other): - return pow(other, self) - # ---- -# SEQUENCE PROCESSING -# ------------------- +# HELPERS +# ------- -def digest(sequence, enzyme, miscleavage=0, allowMods=False, strict=True): - """Digest seuence by specified enzyme. - sequence: (sequence) mspy sequence object - enzyme: (str) enzyme name - must be defined in mspy.enzymes - miscleavage: (int) number of allowed misscleavages - allowMods: (bool) do not care about modifications in cleavage site - strict: (bool) do not cleave even if variable modification is in cleavage site - """ - - # check sequence object - if not isinstance(sequence, objects.sequence): - raise TypeError, "Cannot digest non-sequence object!" - elif not sequence.chain: - return [] - - # get enzyme - if enzyme in blocks.enzymes: - enzyme = blocks.enzymes[enzyme] - expression = re.compile(enzyme.expression+'$') - else: - raise KeyError, 'Unknown enzyme! -> ' + enzyme - - # get digest indices - slices = [] # from | to | miscl - lastIndex = 0 - peptide = '' - for x, aa in enumerate(sequence.chain): - - # check expression - peptide += aa - if expression.search(peptide): - - # skip not allowed modifications - if not allowMods and sequence.ismodified(x-1, strict) and not enzyme.modsBefore: - continue - elif not allowMods and sequence.ismodified(x, strict) and not enzyme.modsAfter: - continue - else: - slices.append((lastIndex, x, 0)) - lastIndex = x +def findIndex(points, x, dim=1): + """Get nearest lower index for selected point.""" - # add last peptide - slices.append((lastIndex, x+1, 0)) + lo = 0 + hi = len(points) - # add indices for partials - indices = len(slices) - for x in range(indices): - for y in range(1, miscleavage+1): - if x+y < indices: - slices.append((slices[x][0], slices[x+y][1], y)) + # 1D array + if dim == 1: + while lo < hi: + mid = (lo + hi) / 2 + if x < points[mid]: + hi = mid else: - break - - # get peptides slices from protein - peptides = [] - for indices in slices: - - CHECK_FORCE_QUIT() - - # get peptide - peptide = sequence[indices[0]:indices[1]] - peptide.miscleavages = indices[2] - - # add terminal groups - if indices[0] != 0: - peptide.nTermFormula = enzyme.nTermFormula - if indices[1] != len(sequence.chain): - peptide.cTermFormula = enzyme.cTermFormula - - peptides.append(peptide) - - return peptides -# ---- - - -def fragment(sequence, serie, index=None): - """Generate list of neutral peptide fragments from given peptide. - sequence: (sequence) mspy sequence object - serie: (str) fragment serie name - must be defined in mspy.fragments - index: (int) fragment index - """ - - # check sequence object - if not isinstance(sequence, objects.sequence): - raise TypeError, "Cannot fragment non-sequence object!" - - frags = [] - length = len(sequence.chain) - - # get serie definition - if serie in blocks.fragments: - serie = blocks.fragments[serie] - else: - raise KeyError, 'Unknown fragment type! -> ' + serie - - # N-terminal fragments - if serie.terminus == 'N': - if index != None: - frag = sequence[:index] - frag.cTermFormula = serie.cTermFormula - frag.lossFormula = serie.lossFormula - frag.fragmentSerie = serie.name - frag.fragmentIndex = index - frags.append(frag) - else: - for x in range(length): - - CHECK_FORCE_QUIT() - - frag = sequence[:x+1] - frag.cTermFormula = serie.cTermFormula - frag.lossFormula = serie.lossFormula - frag.fragmentSerie = serie.name - frag.fragmentIndex = (x+1) - frags.append(frag) - - # C-terminal fragments - elif serie.terminus == 'C': - if index != None: - frag = sequence[length-index:] - frag.nTermFormula = serie.nTermFormula - frag.lossFormula = serie.lossFormula - frag.fragmentSerie = serie.name - frag.fragmentIndex = index - frags.append(frag) - else: - for x in range(length): - - CHECK_FORCE_QUIT() - - frag = sequence[length-(x+1):] - frag.nTermFormula = serie.nTermFormula - frag.lossFormula = serie.lossFormula - frag.fragmentSerie = serie.name - frag.fragmentIndex = (x+1) - frags.append(frag) - - # singlet fragments - elif serie.terminus == 'S': - if index != None: - frag = sequence[index-1:index] - frag.nTermFormula = serie.nTermFormula - frag.cTermFormula = serie.cTermFormula - frag.lossFormula = serie.lossFormula - frag.fragmentSerie = serie.name - frag.fragmentIndex = index - frags.append(frag) - else: - for x in range(length): - - CHECK_FORCE_QUIT() - - frag = sequence[x:x+1] - frag.nTermFormula = serie.nTermFormula - frag.cTermFormula = serie.cTermFormula - frag.lossFormula = serie.lossFormula - frag.fragmentSerie = serie.name - frag.fragmentIndex = (x+1) - frags.append(frag) - - # internal fragments - elif serie.terminus == 'I': - if index != None: - raise ValueError, 'No index allowed for this serie! -> ' + serie.name - else: - for x in range(1,length-1): - for y in range(2,length-x): - - CHECK_FORCE_QUIT() - - frag = sequence[x:x+y] - frag.nTermFormula = serie.nTermFormula - frag.cTermFormula = serie.cTermFormula - frag.lossFormula = serie.lossFormula - frag.fragmentSerie = serie.name - frags.append(frag) - else: - raise ValueError, 'Unknown fragment terminus! -> ' + serie.terminus - - # check fragment specifity - if serie.specifity: - for x in range(len(frags)): - frags[x].fragmentFiltered = True - for aa in serie.specifity: - if aa in frags[x].chain: - frags[x].fragmentFiltered = False - break - - # filter nonsense fragments - if frags and serie.terminus == 'N': - if serie.nTermFilter and (index==None or index==1): - frags[0].fragmentFiltered = True - if serie.cTermFilter and (index==None or index==len(sequence.chain)): - frags[-1].fragmentFiltered = True - elif frags and serie.terminus == 'C': - if serie.nTermFilter and (index==None or index==len(sequence.chain)): - frags[-1].fragmentFiltered = True - if serie.cTermFilter and (index==None or index==1): - frags[0].fragmentFiltered = True - elif frags and serie.terminus == 'S': - if serie.nTermFilter and (index==None or index==1): - frags[0].fragmentFiltered = True - if serie.cTermFilter and (index==None or index==len(sequence.chain)): - frags[-1].fragmentFiltered = True + lo = mid + 1 + # 2D array + if dim == 2: + while lo < hi: + mid = (lo + hi) / 2 + if x < points[mid][0]: + hi = mid + else: + lo = mid + 1 - return frags + return lo # ---- - -# HELPERS -# ------- - -def _interpolateLine(p1, p2, x=None, y=None): +def interpolateLine(p1, p2, x=None, y=None): """Get line interpolated X or Y value.""" # check points @@ -1773,40 +1651,6 @@ # ---- -def _getIndex1D(points, x): - """Get nearest index for selected point.""" - - lo = 0 - hi = len(points) - - while lo < hi: - mid = (lo + hi) / 2 - if x < points[mid]: - hi = mid - else: - lo = mid + 1 - - return lo -# ---- - - -def _getIndex2D(points, x): - """Get nearest index for selected point.""" - - lo = 0 - hi = len(points) - - while lo < hi: - mid = (lo + hi) / 2 - if x < points[mid][0]: - hi = mid - else: - lo = mid + 1 - - return lo -# ---- - - # PATTERN LOOKUP TABLE # -------------------- @@ -1815,10 +1659,11 @@ """Print pattern lookup table.""" for mass in range(0, highmass, step): + formula = averagine(mass, composition=composition) pattern = '' - for isotope in averagine(mass, composition=composition, threshold=0.001): - pattern += '%.3f, ' % isotope + for mz, abundance in formula.pattern(fwhm=0.1, threshold=0.001): + pattern += '%.3f, ' % abundance if table == 'tuple': print '(%s), #%d' % (pattern[:-2], mass) diff -Nru mmass-3.12.1/mspy/proteo.py mmass-4.0.0/mspy/proteo.py --- mmass-3.12.1/mspy/proteo.py 1970-01-01 00:00:00.000000000 +0000 +++ mmass-4.0.0/mspy/proteo.py 2011-11-28 11:19:48.000000000 +0000 @@ -0,0 +1,438 @@ +# ------------------------------------------------------------------------- +# Copyright (C) 2005-2011 Martin Strohalm + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# Complete text of GNU GPL can be found in the file LICENSE.TXT in the +# main directory of the program +# ------------------------------------------------------------------------- + +# load libs +import re +import itertools + +# load stopper +from stopper import CHECK_FORCE_QUIT + +# register essential objects and modules +import objects +import blocks + + +# SEQUENCE DIGESTION +# ------------------ + +def digest(sequence, enzyme, miscleavage=0, allowMods=False, strict=True): + """Digest seuence by specified enzyme. + sequence: (sequence) mspy sequence object + enzyme: (str) enzyme name - must be defined in mspy.enzymes + miscleavage: (int) number of allowed misscleavages + allowMods: (bool) do not care about modifications in cleavage site + strict: (bool) do not cleave even if variable modification is in cleavage site + """ + + # check sequence object + if not isinstance(sequence, objects.sequence): + raise TypeError, "Cannot digest non-sequence object!" + + # check cyclic peptides + if sequence.chainType != 'aminoacids': + raise TypeError, 'Digest function is not supported for non-amino sequences!' + + # check cyclic peptides + if sequence.cyclic: + raise TypeError, 'Digest function is not supported for cyclic peptides!' + + # check sequence + if not sequence.chain: + return [] + + # get enzyme + if enzyme in blocks.enzymes: + enzyme = blocks.enzymes[enzyme] + expression = re.compile(enzyme.expression+'$') + else: + raise KeyError, 'Unknown enzyme! -> ' + enzyme + + # get digest indices + slices = [] # from | to | miscl + lastIndex = 0 + peptide = '' + for x, aa in enumerate(sequence): + + # check expression + peptide += aa + if expression.search(peptide): + + # skip not allowed modifications + if not allowMods and sequence.ismodified(x-1, strict) and not enzyme.modsBefore: + continue + elif not allowMods and sequence.ismodified(x, strict) and not enzyme.modsAfter: + continue + else: + slices.append((lastIndex, x, 0)) + lastIndex = x + + # add last peptide + slices.append((lastIndex, x+1, 0)) + + # add indices for partials + indices = len(slices) + for x in range(indices): + for y in range(1, miscleavage+1): + if x+y < indices: + slices.append((slices[x][0], slices[x+y][1], y)) + else: + break + + # get peptides slices from protein + peptides = [] + for indices in slices: + + CHECK_FORCE_QUIT() + + # get peptide + peptide = sequence[indices[0]:indices[1]] + peptide.miscleavages = indices[2] + + # add terminal groups + if indices[0] != 0: + peptide.nTermFormula = enzyme.nTermFormula + if indices[1] != len(sequence): + peptide.cTermFormula = enzyme.cTermFormula + + peptides.append(peptide) + + return peptides +# ---- + + +def coverage(ranges, length, trueIndexes=False): + """Calculate sequence coverage. + ranges: (list of mspy.sequence or list of user ranges (start,stop)) + length: (int) parent sequence length + """ + + # check data + if not ranges: + return 0. + + # make a blank sequence + blank = length*[0] + + # list of ranges + for r in ranges: + if trueIndexes: + for x in range(r[0], r[1]): + blank[x]=(1) + else: + for x in range(r[0]-1, r[1]): + blank[x]=(1) + + # get sequence coverage + return 100.0*blank.count(1)/length +# ---- + + + +# SEQUENCE FRAGMENTATION +# ---------------------- + +def fragment(sequence, series, scrambling=False): + """Generate list of neutral peptide fragments from given peptide. + sequence: (sequence) mspy sequence object + series: (list) list of fragment serie names - must be defined in mspy.fragments + scrambling: (int) allow sequence scrambling + """ + + frags = [] + scramblingFilter = ('M') + + # check sequence object + if not isinstance(sequence, objects.sequence): + raise TypeError, "Cannot fragment non-sequence object!" + + # generate fragments for linear peptide + if not sequence.cyclic: + for serie in series: + frags += fragmentSerie(sequence, serie) + + # generate fragments for cyclic peptide + else: + for peptide in sequence.linearized(): + for serie in series: + frags += fragmentSerie(peptide, serie, cyclicParent=True) + + # generate scrambling fragments + if scrambling: + buff = [] + for frag in frags: + if frag.fragmentSerie == 'b' and len(frag) > 3: + for peptide in frag.linearized(): + for serie in series: + if not serie in scramblingFilter: + buff += fragmentSerie(peptide, serie, cyclicParent=sequence.cyclic) + + frags += buff + + # remove same fragments + buff = [] + have = [] + for frag in frags: + frhash = [frag.fragmentSerie] + frag.indexes() + if frag.fragmentSerie == 'M': + frhash.sort() + if not frhash in have: + buff.append(frag) + have.append(frhash) + + frags = buff + + return frags +# ---- + + +def fragmentSerie(sequence, serie, cyclicParent=False): + """Generate list of neutral peptide fragments from given peptide. + sequence: (sequence) mspy sequence object + serie: (str) fragment serie name - must be defined in mspy.fragments + """ + + # check sequence object + if not isinstance(sequence, objects.sequence): + raise TypeError, "Cannot fragment non-sequence object!" + + # check cyclic peptides + if sequence.cyclic: + raise TypeError, 'Direct fragmentation of cyclic peptides is not supported!' + + frags = [] + length = len(sequence) + + # get serie definition + serie = blocks.fragments[serie] + + # molecular ion + if serie.terminus == 'M': + frag = sequence[:] + frag.fragmentSerie = serie.name + frags.append(frag) + + # N-terminal fragments + elif serie.terminus == 'N': + for x in range(length): + frag = sequence[:x+1] + frag.fragmentSerie = serie.name + frag.fragmentIndex = (x+1) + frag.cTermFormula = serie.cTermFormula + frags.append(frag) + + CHECK_FORCE_QUIT() + + # C-terminal fragments + elif serie.terminus == 'C': + for x in range(length): + frag = sequence[length-(x+1):] + frag.fragmentSerie = serie.name + frag.fragmentIndex = (x+1) + frag.nTermFormula = serie.nTermFormula + frags.append(frag) + + CHECK_FORCE_QUIT() + + # singlet fragments + elif serie.terminus == 'S': + for x in range(length): + frag = sequence[x:x+1] + frag.fragmentSerie = serie.name + frag.fragmentIndex = (x+1) + frag.nTermFormula = serie.nTermFormula + frag.cTermFormula = serie.cTermFormula + frags.append(frag) + + CHECK_FORCE_QUIT() + + # internal fragments + elif serie.terminus == 'I': + for x in range(1,length-1): + for y in range(2,length-x): + frag = sequence[x:x+y] + frag.fragmentSerie = serie.name + frag.nTermFormula = serie.nTermFormula + frag.cTermFormula = serie.cTermFormula + frags.append(frag) + + CHECK_FORCE_QUIT() + + # correct termini for cyclic peptides + if cyclicParent: + for frag in frags: + if serie.terminus == 'M': + frag.nTermFormula = '' + frag.cTermFormula = '' + elif serie.terminus == 'N': + frag.nTermFormula = 'H' + elif serie.terminus == 'C': + frag.cTermFormula = 'H-1' + + # remove nonsense terminal fragments + if serie.terminus == 'N': + if frags and serie.nTermFilter: + del frags[0] + if frags and serie.cTermFilter: + del frags[-1] + elif serie.terminus == 'C': + if frags and serie.nTermFilter: + del frags[-1] + if frags and serie.cTermFilter: + del frags[0] + elif serie.terminus == 'S': + if frags and serie.nTermFilter: + del frags[0] + if frags and serie.cTermFilter: + del frags[-1] + + return frags +# ---- + + +def fragmentLosses(fragments, losses=[], defined=False, limit=1, filterIn={}, filterOut={}): + """Apply specified neutral losses to fragments. + fragments: (list) list of sequence fragments + losses: (list) list of neutral losses + defined: (bool) use monomer-defined neutral losses + limit: (int) max length of loss combination + filterIn: (dic) allowed series for specified losses + filterOut: (dic) not allowed series for specified losses + """ + + # make losses combinations + combinations = [] + for x in range(1, min(len(losses), limit) + 1): + for c in itertools.combinations(losses, x): + combinations.append(list(c)) + + # generate fragments + buff = [] + for frag in fragments: + + CHECK_FORCE_QUIT() + + # get monomer-defined losses to check specifity + definedLosses = [] + for monomer in frag: + definedLosses += blocks.monomers[monomer].losses + + # append new combinations with monomer-defined losses + lossesToApply = combinations[:] + if defined: + for monomer in frag: + for item in ([[]] + lossesToApply[:]): + for loss in blocks.monomers[monomer].losses: + newItem = item + [loss] + newItem.sort() + + if not [loss] in lossesToApply: + lossesToApply.append([loss]) + if len(newItem) <= limit and not newItem in lossesToApply: + lossesToApply.append(newItem) + + + # make fragment + for combination in lossesToApply: + newFrag = frag.duplicate() + skip = False + + # apply losses + for loss in combination: + newFrag.fragmentLosses.append(loss) + + # check neutral gains + if loss in frag.fragmentGains: + skip = True + break + + # check fragment type filter + if (loss in filterOut and frag.fragmentSerie in filterOut[loss]) \ + or (loss in filterIn and not frag.fragmentSerie in filterIn[loss]): + skip = True + break + + # check fragment composition + if not newFrag.isvalid(): + skip = True + break + + # filter non-specific losses + if not loss in definedLosses: + newFrag.fragmentFiltered = True + + # store fragment + if not skip: + buff.append(newFrag) + + return buff +# ---- + + +def fragmentGains(fragments, gains=[], filterIn={'H2O':['b'], 'CO':['b', 'c', 'break']}, filterOut={}): + """Apply specified neutral gains to fragments. + fragments: (list) list of sequence fragments + gains: (list) list of neutral gains + filterIn: (dic) allowed series for specified gains + filterOut: (dic) not allowed series for specified gains + """ + + # generate fragments + buff = [] + for frag in fragments: + + CHECK_FORCE_QUIT() + + # is parent cyclic? + cyclicParent = False + for item in frag.history: + if 'break' in item: + cyclicParent = True + break + + # apply gains + for gain in gains: + + # check neutral losses + if gain in frag.fragmentLosses: + continue + + # check fragment type filters + if (gain in filterOut and frag.fragmentSerie in filterOut[gain]) \ + or (gain in filterIn and not frag.fragmentSerie in filterIn[gain]): + continue + + # check break (cyclic parent) + if gain in filterIn and 'break' in filterIn[gain] and not cyclicParent: + continue + + # make fragment + newFrag = frag.duplicate() + newFrag.fragmentGains.append(gain) + + # check fragment composition + if not newFrag.isvalid(): + continue + + # store fragment + buff.append(newFrag) + + return buff +# ---- + + + \ No newline at end of file diff -Nru mmass-3.12.1/setup.py mmass-4.0.0/setup.py --- mmass-3.12.1/setup.py 2011-05-02 18:43:09.000000000 +0000 +++ mmass-4.0.0/setup.py 2011-12-01 16:33:06.000000000 +0000 @@ -13,7 +13,7 @@ # list additional files additionalFiles = [ ("configs",[ - "configs/aminoacids.xml", + "configs/monomers.xml", "configs/compounds.xml", "configs/config.xml", "configs/enzymes.xml", @@ -68,7 +68,8 @@ "gui/images/mac/icon_doc_mzxml.icns", "gui/images/mac/icon_doc_mzml.icns", "gui/images/mac/icon_doc_fid.icns", - "configs" + "configs", + "User Guide.pdf" ] # py2app options