ST-TURN-IIL blue|255,0,255|absolute|20.0|95.0|below|66.0
-GAMMA-TURN-CLASSIC red|0,255,255|20.0|95.0|below|66.0
+GAMMA-TURN-CLASSIC lightGray|0,255,255|20.0|95.0|below|66.0
BETA-TURN-IR 9a6a94
BETA-TURN-IL d6a6ca
BETA-BULGE 1dc451
<mapID target="uniprotfetcher" url="html/features/uniprotsequencefetcher.html" />
+ <mapID target="urllinks" url="html/webServices/urllinks.html" />
+ <mapID target="linksprefs" url="html/features/Preferences.html#links" />
+
<mapID target="backIcon" url="icons/back.png" />
<mapID target="forwardIcon" url="icons/forward.png" />
<mapID target="homeIcon" url="icons/Home.png" />
<tocitem text="Chimera Viewer" target="chimera" />
</tocitem>
<tocitem text="Viewing RNA structures" target="varna" expand="false"/>
+ <tocitem text="Opening URLs from Jalview" target="urllinks" expand="true">
+ <tocitem text="Configuring URL Links" target="urllinkspref" />
+ </tocitem>
<tocitem text="VAMSAS Data Exchange" target="vamsas">
<!-- what can Jalview share with other apps -->
<!-- what other apps exist -->
and displaying structure information.
</li>
<li>The <a href="#connections"><strong>"Connections"</strong>
- Preferences</a> tab allows you to change the links made from Jalview
- to your default web browser.
+ Preferences</a> tab allows you to configure Jalview's internet
+ settings and specify your default web browser.
+ </li>
+ <li>The <a href="#links"><strong>"Links"</strong>
+ Preferences</a> tab shows the currently configured <em>URL
+ Links</em> shown in the <strong>Link</strong> submenu in the Sequence
+ ID popup menu.
</li>
<li>The <a href="#output"><strong>"Output"</strong>
Preferences</a> tab contains settings affecting the export of
Preferences tab</strong></a>
</p>
<p>
- <em>URL Link From Sequence ID</em><br> These definitions are
- used to generate URLs from a sequence's ID or database cross
- references. Read more about <a
- href="../webServices/urllinks.html#urllinks">configuring
- URL links here</a>.
- </p>
- <p>
<em>Default Browser (Unix)</em><br> Its difficult in Java to
detect the default web browser for Unix users. If Jalview can't find
your default web browser, enter the name or full path to your web
statement</a> for more information.
</p>
<p>
+ <a name="links"><strong>The "Links" Preferences
+ tab</strong></a>
+ </p>
+ <p>
+ This panel shows a table, and two sections - <em>Edit</em> and <em>Filter</em>.
+ The table shows the available URL link definitions (consisting of a
+ database, Name, and URL template string), a checkbox <em>In
+ Menu</em> which indicates if the link is enabled, and <em>Double
+ Click</em> which marks the link that will be opened if a sequence's ID
+ is double clicked. The table can be sorted by clicking on the column headers.
+ </p>
+ <p><em>Edit Links</em><br /> This section contains three buttons,
+ <em>New</em>, <em>Edit</em> and <em>Delete</em>, which allow you to
+ create, modify and remove user-defined URL links from the Sequence
+ ID's links submenu.
+ </p>
+ <p>
+ <em>Filter</em><br /> The <em>Filter text</em> box allows you to
+ quickly show rows in the table containing a particular text string.
+ The <em>Custom only</em> button limits the entries in the table to
+ just those you have configured yourself <em>via</em> the <em>Edit
+ Links</em> buttons. Press <em>Show all</em> to clear any filters.
+ <p>
+ <a href="../webServices/urllinks.html#urllinks">Read more about configuring
+ URL links.</a>
+ </p>
+ <p>
<a name="output"><strong>Output Preferences tab</strong></a>
</p>
<p>
and PDB file association (if available). The Jalview id/start-end
option is ignored if Modeller output is selected.
<p>
- <a name="editing"><strong>Editing Preferences tab</strong></a>
+ <a name="editing"><strong>e"Editinge" Preferences tab</strong></a>
</p>
<p>There are currently three options available which can be
selected / deselected.</p>
</head>
<body>
<p>
- <p>
<strong>Opening URLs from Jalview</strong><br> Both the applet
and the desktop application are able to open URLs as 'popups' in
- your web browser. <br> Double-clicking on the ID of a sequence
- will open the first URL that can be generated from its sequence ID.
+ your web browser.</p>
+ <p> Double-clicking on the ID of a sequence
+ will open whichever URL is selected for 'popups' in the <strong>"Links"</strong> tab of the <a
+ href="../features/preferences.html#links">Jalview desktop
+ preferences</a>.
This is by default the EMBL-EBI site, but you can easily configure your own <a
href="#urllinks">sequence URL links</a>.
</p>
<p>
- Other links for a sequence either derived from any other configured
+ Other links for a sequence, either derived from any other configured
URL links, or imported from the sequence's annotation, are accessed
by right clicking to open the sequence pop-up menu, and selecting
from the <em>Links</em> submenu.
</p>
<p>
<strong><a name="urllinks">Configuring URL Links</a></strong> <br>URL
- links are defined in the "Connections" tab of the <a
- href="../features/preferences.html">Jalview desktop
+ links are defined in the "Links" tab of the <a
+ href="../features/preferences.html#links">Jalview desktop
preferences</a>, or specified as <a
href="http://www.jalview.org/examples/appletParameters.html#parameters">applet
- parameters</a>. <br> By default the item "EMBL-EBI Search" is added
- to this link menu. This link will show a web page in your default
- browser with the selected sequence id as part of the URL.<br>
- In the preferences dialog box, click <strong>new</strong> to add a
- new link, and <strong>edit</strong> to modify an existing link, or <strong>delete</strong>
- to remove it.<br> You can name the link, this will be displayed
- on a new menu item under the "Link" menu when you right
- click on a sequence id. <br> The URL string must contain a
- token that can be replaced with a sequence ID or DB accession ID. The simplest token is
- "$SEQUENCE_ID$", which will be replaced by the chosen
- sequence id when you click on it.
+ parameters</a>.</p>
+ <p>
+ <em>Default Link Settings</em><br /> The "EMBL-EBI Search"
+ link is the default link shown in the "Link" submenu, and
+ opened when double-clicking on a sequence ID. When clicked, this
+ link will show a web page in your default browser with the selected
+ sequence ID as part of the URL.
+ </p>
+ <p>
+ <em>Adding additional links</em><br /> You can configure your own
+ links via the Jalview <a href="../features/preferences.html#links"><strong>Preferences</strong></a>
+ dialog. Jalview also provides persistent URLs for many common
+ bioinformatics databases. These links are downloaded by Jalview from
+ the <em>identifiers.org</em> website, and the names and URLs are not
+ user editable.
</p>
<p>
- eg.<br> UniRef100 =
- http://www.ebi.uniprot.org/uniprot-srv/uniRefView.do?proteinAc=$SEQUENCE_ID$&library=uniref100<br>
- Swissprot = http://www.expasy.org/uniprot/$SEQUENCE_ID$ <br> <br>
+ <em>Creating your own URL link</em> URL links are specified as a
+ template containing special tokens that Jalview will replace with
+ the Sequence ID or Database Accession of the sequence when you
+ double click on its ID or open it's <strong>Link</strong> submenu.
+ Link URL templates must contain at least one token.
+ </p>
+ <em>eg.</em><pre> UniRef100 =
+ http://www.ebi.uniprot.org/uniprot-srv/uniRefView.do?proteinAc=$SEQUENCE_ID$&library=uniref100<br/>
+ Swissprot = http://www.expasy.org/uniprot/$SEQUENCE_ID$ <br> </pre>
+ <p>
Links will also be made for any database cross references associated
with the sequence where the database name exactly matches a URL link
name. In this case, the $DB_ACCESSION$ string will be replaced with
<p>
<strong>Regular Expression Substitution</strong><br> A url may
contain a string of the form $SEQUENCE_ID=/<em>regular
- expression</em>/=$ or $DB_ACCESSION=/<em>regular expression</em>/=$.
- In this case, the regular expression will be
- applied to the full sequence ID or DB accession ID string and the resulting match will
+ expression</em>/=$ or $DB_ACCESSION=/<em>regular expression</em>/=$. In
+ this case, the regular expression will be applied to the full
+ sequence ID or DB accession ID string and the resulting match will
be inserted into the URL. Groups of parentheses can be used to
specify which regions of the regular expression will be used to
generate the URL:
+
<ul>
<li>Each top level parenthesis will yield a URL containing the
text matched within that parenthesis.</li>
<li>Regions matching sub-parentheses within a top-level
parenthesis will be concatenated to form the text inserted into
the URL for the top-level parenthesis.</li>
- <em>Please Note:
- <ul>
- <li>The regular expressions supported by Jalview are those
- provided by the <a href="http://www.javaregex.com">Stevesoft
- javaregex package</a>.
- </li>
- <li>Some characters must be escaped when specifying them as
- a match within a regular expression.</li>
- </ul> <br> Many Thanks to Bernd Brandt of the Free University of
- Amsterdam for testing this new regular-expression expansion
- feature!
- </em>
- <em>
</ul>
- </p>
- </p>
+ <em>Please Note:</em>
+ <ul>
+ <li>The regular expressions supported by Jalview are those
+ provided by the <a href="http://www.javaregex.com">Stevesoft
+ javaregex package</a>.
+ </li>
+ <li>Some characters must be escaped when specifying them as a
+ match within a regular expression.</li>
+ </ul> <br> Many Thanks to Bernd Brandt of the Free University of
+ Amsterdam for testing the regular-expression expansion feature!
</body>
</html>
label.view_flanking_regions = Show sequence data either side of the subsequences involved in this alignment
label.structures_manager = Structures Manager
label.nickname = Nickname:
-label.url = URL:
+label.url = URL
+label.url\: = URL:
label.input_file_url = Enter URL or Input File
label.select_feature = Select feature
label.name = Name
label.vamsas_document_import_failed = Vamsas Document Import Failed
label.couldnt_locate = Couldn't locate {0}
label.url_not_found = URL not found
-label.no_link_selected = No link selected
label.new_sequence_url_link = New sequence URL link
label.cannot_edit_annotations_in_wrapped_view = Cannot edit annotations in wrapped view
label.wrapped_view_no_edit = Wrapped view - no edit
label.standard_databases = Standard Databases
label.fetch_embl_uniprot = Fetch from EMBL/EMBLCDS or Uniprot/PDB and any selected DAS sources
label.reset_min_max_colours_to_defaults = Reset min and max colours to defaults from user preferences.
-label.align_structures_using_linked_alignment_views = Align structures using {0} linked alignment views
+label.align_structures_using_linked_alignment_views = Superpose structures using {0} selected alignment view(s)
label.connect_to_session = Connect to session {0}
label.threshold_feature_display_by_score = Threshold the feature display by score.
label.threshold_feature_no_threshold = No Threshold
label.right_click_to_edit_currently_selected_parameter = Right click to edit currently selected parameter.
label.let_jmol_manage_structure_colours = Let Jmol manage structure colours
label.let_chimera_manage_structure_colours = Let Chimera manage structure colours
+label.fetch_chimera_attributes = Fetch Chimera attributes
+label.fetch_chimera_attributes_tip = Copy Chimera attribute to Jalview feature
label.marks_leaves_tree_not_associated_with_sequence = Marks leaves of tree not associated with a sequence
label.index_web_services_menu_by_host_site = Index web services in menu by the host site
label.option_want_informed_web_service_URL_cannot_be_accessed_jalview_when_starts_up = Check this option if you want to be informed<br>when a web service URL cannot be accessed by Jalview<br>when it starts up
label.pdb_file = PDB file
label.colour_with_jmol = Colour with Jmol
label.colour_with_chimera = Colour with Chimera
-label.align_structures = Align Structures
+label.superpose_structures = Superpose Structures
+error.superposition_failed = Superposition failed: {0}
+label.insufficient_residues = Not enough aligned residues ({0}) to perform superposition
label.jmol = Jmol
label.chimera = Chimera
+label.create_chimera_attributes = Write Jalview features
+label.create_chimera_attributes_tip = Set Chimera residue attributes for visible features
+label.attributes_set = {0} attribute values set on Chimera
label.sort_alignment_by_tree = Sort Alignment By Tree
label.mark_unlinked_leaves = Mark Unlinked Leaves
label.associate_leaves_with = Associate Leaves With
label.SEQUENCE_ID_for_DB_ACCESSION1 = Please review your URL links in the 'Connections' tab of the Preferences window:
label.SEQUENCE_ID_for_DB_ACCESSION2 = URL links using '$SEQUENCE_ID$' for DB accessions now use '$DB_ACCESSION$'.
label.do_not_display_again = Do not display this message again
+exception.url_cannot_have_miriam_id = {0} is a MIRIAM id and cannot be used as a custom url name
+exception.url_cannot_have_duplicate_id = {0} cannot be used as a label for more than one line
+label.filter = Filter text:
+action.customfilter = Custom only
+action.showall = Show All
+label.insert = Insert:
+action.seq_id = $SEQUENCE_ID$
+action.db_acc = $DB_ACCESSION$
+label.primary = Double Click
+label.inmenu = In Menu
+label.id = ID
+label.database = Database
+label.urltooltip = Only one url, which must use a sequence id, can be selected for the 'On Click' option
+label.edit_sequence_url_link = Edit sequence URL link
+warn.name_cannot_be_duplicate = User-defined URL names must be unique and cannot be MIRIAM ids
+label.invalid_name = Invalid Name !
label.output_seq_details = Output Sequence Details to list all database references
+label.urllinks = Links
label.view_flanking_regions = Mostrar los datos de la secuencia a ambos lados de las subsecuencias implicadas en este alineamiento
label.structures_manager = Administrar estructuras
label.nickname = Sobrenombre:
-label.url = URL:
+label.url\: = URL:
+label.url = URL
label.input_file_url = Introducir URL en el fichero de entrada
label.select_feature = Seleccionar caracterÃstica
label.name = Nombre
label.vamsas_document_import_failed = Fallo en la importación del documento Vamsas
label.couldnt_locate = No se pudo localizar {0}
label.url_not_found = URL no encontrada
-label.no_link_selected = Enlace no seleccionado
label.new_sequence_url_link = Enlace a una nueva secuencia URL
label.cannot_edit_annotations_in_wrapped_view = No se pueden editar anotaciones en vista envolvente
label.wrapped_view_no_edit = Vista envolvente - no editar
label.standard_databases = Bases de datos estándar
label.fetch_embl_uniprot = Recuperar de EMBL/EMBLCDS o Uniprot/PDB y de cualquier fuente DAS seleccionada
label.reset_min_max_colours_to_defaults = Reiniciar los colores min y max colours a los valores por defecto establecidos en las preferencias de usuario
-label.align_structures_using_linked_alignment_views = Alinear las estructuras utlizando las {0} vistas de alineamiento enlazadas
+label.align_structures_using_linked_alignment_views = Alinear las estructuras utilizando las {0} vista(s) de alineamiento enlazada(s)
label.connect_to_session = Conectar a la sesión {0}
label.threshold_feature_display_by_score = Filtrar la caracterÃstica mostrada por puntuación.
label.threshold_feature_no_threshold = Sin umbral
label.SEQUENCE_ID_for_DB_ACCESSION1 = Por favor, revise sus URLs en la pestaña 'Conexiones' de la ventana de Preferencias:
label.SEQUENCE_ID_for_DB_ACCESSION2 = URL enlaza usando '$SEQUENCE_ID$' para accesiones DB ahora usar '$DB_ACCESSION$'.
label.do_not_display_again = No mostrar este mensaje de nuevo
+exception.url_cannot_have_miriam_id = {0} es una id MIRIAM y no puede ser usada como nombre url personalizado
+exception.url_cannot_have_duplicate_id = {0} no puede ser usada como etiqueta en más de un enlace
+label.filter = Filtrar texto:
+action.customfilter = Sólo personalizado
+action.showall = Mostrar todo
+label.insert = Insertar:
+action.seq_id = $SEQUENCE_ID$
+action.db_acc = $DB_ACCESSION$
+label.primary = Doble clic
+label.inmenu = En Menú
+label.id = ID
+label.database = Base de datos
+label.urltooltip = Sólo una url, que debe usar una id de secuencia, puede ser seleccionada en la opción 'On Click'
+label.edit_sequence_url_link = Editar link de secuencia URL
+warn.name_cannot_be_duplicate = Los nombres URL definidos por el usuario deben ser únicos y no pueden ser ids de MIRIAM
+label.invalid_name = Nombre inválido !
label.output_seq_details = Seleccionar Detalles de la secuencia para ver todas
+label.urllinks = Enlaces
import jalview.datamodel.SequenceI;
import jalview.io.DataSourceType;
import jalview.io.StructureFile;
+import jalview.renderer.seqfeatures.FeatureColourFinder;
import jalview.structure.AtomSpec;
import jalview.structure.StructureListener;
import jalview.structure.StructureMapping;
showFeatures = true;
}
+ FeatureColourFinder finder = new FeatureColourFinder(fr);
+
PDBChain chain;
if (bysequence && pdb != null)
{
if (pos > 0)
{
pos = sequence[s].findIndex(pos);
- tmp.startCol = sr.getResidueBoxColour(sequence[s], pos);
- if (showFeatures)
- {
- tmp.startCol = fr.findFeatureColour(tmp.startCol,
- sequence[s], pos);
- }
+ tmp.startCol = sr.getResidueColour(sequence[s], pos,
+ finder);
}
pos = mapping[m].getSeqPos(tmp.at2.resNumber) - 1;
if (pos > 0)
{
pos = sequence[s].findIndex(pos);
- tmp.endCol = sr.getResidueBoxColour(sequence[s], pos);
- if (showFeatures)
- {
- tmp.endCol = fr.findFeatureColour(tmp.endCol,
- sequence[s], pos);
- }
+ tmp.endCol = sr
+ .getResidueColour(sequence[s], pos, finder);
}
-
}
}
}
import jalview.gui.SequenceRenderer;
import jalview.io.DataSourceType;
import jalview.io.StructureFile;
+import jalview.renderer.seqfeatures.FeatureColourFinder;
import jalview.structure.AtomSpec;
import jalview.structure.StructureListener;
import jalview.structure.StructureMapping;
showFeatures = true;
}
+ FeatureColourFinder finder = new FeatureColourFinder(fr);
PDBChain chain;
if (bysequence && pdb != null)
{
if (pos > 0)
{
pos = sequence[s].findIndex(pos);
- tmp.startCol = sr.getResidueBoxColour(sequence[s], pos);
- if (showFeatures)
- {
- tmp.startCol = fr.findFeatureColour(tmp.startCol,
- sequence[s], pos);
- }
+ tmp.startCol = sr.getResidueColour(sequence[s], pos,
+ finder);
}
pos = mapping[m].getSeqPos(tmp.at2.resNumber) - 1;
if (pos > 0)
{
pos = sequence[s].findIndex(pos);
- tmp.endCol = sr.getResidueBoxColour(sequence[s], pos);
- if (showFeatures)
- {
- tmp.endCol = fr.findFeatureColour(tmp.endCol,
- sequence[s], pos);
- }
+ tmp.endCol = sr
+ .getResidueColour(sequence[s], pos, finder);
}
}
public class PDBChain
{
+ public static final String RESNUM_FEATURE = "RESNUM";
+
/**
* SequenceFeature group for PDB File features added to sequences
*/
Residue tmpres = residues.lastElement();
Atom tmpat = tmpres.atoms.get(0);
// Make A new SequenceFeature for the current residue numbering
- SequenceFeature sf = new SequenceFeature("RESNUM", tmpat.resName
+ SequenceFeature sf = new SequenceFeature(RESNUM_FEATURE, tmpat.resName
+ ":" + tmpat.resNumIns + " " + pdbid + id, "", offset
+ count, offset + count, pdbid);
resFeatures.addElement(sf);
"list selection level residue", true);
if (chimeraReply != null)
{
+ /*
+ * expect 0, 1 or more lines of the format
+ * residue id #0:43.A type GLY
+ * where we are only interested in the atomspec #0.43.A
+ */
for (String inputLine : chimeraReply)
{
String[] inputLineParts = inputLine.split("\\s+");
*/
package jalview.analysis;
+import java.util.Arrays;
+import java.util.Hashtable;
+import java.util.List;
+
import jalview.datamodel.AlignedCodonFrame;
import jalview.datamodel.AlignmentAnnotation;
import jalview.datamodel.AlignmentI;
import jalview.util.MappingUtils;
import jalview.util.QuickSort;
-import java.util.Arrays;
-import java.util.Hashtable;
-import java.util.List;
-
/**
* Takes in a vector or array of sequences and column start and column end and
* returns a new Hashtable[] of size maxSeqLength, if Hashtable not supplied.
}
}
- public static final ProfilesI calculate(List<SequenceI> list,
- int start, int end)
+ public static final ProfilesI calculate(List<SequenceI> list, int start,
+ int end)
{
return calculate(list, start, end, false);
}
}
/**
+ * Derive the gap count annotation row.
+ *
+ * @param gaprow
+ * the annotation row to add annotations to
+ * @param profiles
+ * the source consensus data
+ * @param startCol
+ * start column (inclusive)
+ * @param endCol
+ * end column (exclusive)
+ */
+ public static void completeGapAnnot(AlignmentAnnotation gaprow,
+ ProfilesI profiles, int startCol, int endCol, long nseq)
+ {
+ if (gaprow == null || gaprow.annotations == null
+ || gaprow.annotations.length < endCol)
+ {
+ /*
+ * called with a bad alignment annotation row
+ * wait for it to be initialised properly
+ */
+ return;
+ }
+ // always set ranges again
+ gaprow.graphMax = nseq;
+ gaprow.graphMin = 0;
+ for (int i = startCol; i < endCol; i++)
+ {
+ ProfileI profile = profiles.get(i);
+ if (profile == null)
+ {
+ /*
+ * happens if sequences calculated over were
+ * shorter than alignment width
+ */
+ gaprow.annotations[i] = null;
+ return;
+ }
+
+ final int gapped = profile.getNonGapped();
+
+ String description = String.valueOf(gapped);
+
+ gaprow.annotations[i] = new Annotation(description, description,
+ '\0',
+ gapped);
+ }
+ }
+
+ /**
* Returns a tooltip showing either
* <ul>
* <li>the full profile (percentages of all residues present), if
* calculations
* @return
*/
- public static int[] extractProfile(ProfileI profile,
- boolean ignoreGaps)
+ public static int[] extractProfile(ProfileI profile, boolean ignoreGaps)
{
int[] rtnval = new int[64];
ResidueCount counts = profile.getCounts();
import jalview.util.DBRefUtils;
import jalview.util.MapList;
import jalview.util.MappingUtils;
+import jalview.util.RangeComparator;
import jalview.util.StringUtils;
import java.io.UnsupportedEncodingException;
* ranges are assembled in order. Other cases should not use this method,
* but instead construct an explicit mapping for CDS (e.g. EMBL parsing).
*/
- Collections.sort(result, new Comparator<int[]>()
- {
- @Override
- public int compare(int[] o1, int[] o2)
- {
- return Integer.compare(o1[0], o2[0]);
- }
- });
+ Collections.sort(result, new RangeComparator(true));
return result;
}
*/
package jalview.analysis;
-import jalview.datamodel.BinarySequence;
-import jalview.datamodel.BinarySequence.InvalidSequenceTypeException;
-import jalview.math.Matrix;
+import jalview.math.MatrixI;
import jalview.schemes.ResidueProperties;
import jalview.schemes.ScoreMatrix;
/**
* Performs Principal Component Analysis on given sequences
- *
- * @author $author$
- * @version $Revision$
*/
public class PCA implements Runnable
{
- Matrix m;
-
- Matrix symm;
+ boolean jvCalcMode = true;
- Matrix m2;
+ MatrixI symm;
double[] eigenvalue;
- Matrix eigenvector;
+ MatrixI eigenvector;
- StringBuffer details = new StringBuffer();
+ StringBuilder details = new StringBuilder(1024);
+
+ private String[] seqs;
+
+ private ScoreMatrix scoreMatrix;
/**
* Creates a new PCA object. By default, uses blosum62 matrix to generate
public PCA(String[] s, boolean nucleotides, String s_m)
{
+ this.seqs = s;
- BinarySequence[] bs = new BinarySequence[s.length];
- int ii = 0;
-
- while ((ii < s.length) && (s[ii] != null))
- {
- bs[ii] = new BinarySequence(s[ii], nucleotides);
- bs[ii].encode();
- ii++;
- }
-
- BinarySequence[] bs2 = new BinarySequence[s.length];
- ii = 0;
- ScoreMatrix smtrx = null;
+ scoreMatrix = null;
String sm = s_m;
if (sm != null)
{
- smtrx = ResidueProperties.getScoreMatrix(sm);
+ scoreMatrix = ResidueProperties.getScoreMatrix(sm);
}
- if (smtrx == null)
+ if (scoreMatrix == null)
{
// either we were given a non-existent score matrix or a scoremodel that
// isn't based on a pairwise symbol score matrix
- smtrx = ResidueProperties.getScoreMatrix(sm = (nucleotides ? "DNA"
- : "BLOSUM62"));
+ scoreMatrix = ResidueProperties
+ .getScoreMatrix(sm = (nucleotides ? "DNA" : "BLOSUM62"));
}
details.append("PCA calculation using " + sm
+ " sequence similarity matrix\n========\n\n");
- while ((ii < s.length) && (s[ii] != null))
- {
- bs2[ii] = new BinarySequence(s[ii], nucleotides);
- if (smtrx != null)
- {
- try
- {
- bs2[ii].matrixEncode(smtrx);
- } catch (InvalidSequenceTypeException x)
- {
- details.append("Unexpected mismatch of sequence type and score matrix. Calculation will not be valid!\n\n");
- }
- }
- ii++;
- }
-
- // System.out.println("Created binary encoding");
- // printMemory(rt);
- int count = 0;
-
- while ((count < bs.length) && (bs[count] != null))
- {
- count++;
- }
-
- double[][] seqmat = new double[count][bs[0].getDBinary().length];
- double[][] seqmat2 = new double[count][bs2[0].getDBinary().length];
- int i = 0;
-
- while (i < count)
- {
- seqmat[i] = bs[i].getDBinary();
- seqmat2[i] = bs2[i].getDBinary();
- i++;
- }
-
- // System.out.println("Created array");
- // printMemory(rt);
- // System.out.println(" --- Original matrix ---- ");
- m = new Matrix(seqmat);
- m2 = new Matrix(seqmat2);
-
- }
-
- /**
- * Returns the matrix used in PCA calculation
- *
- * @return java.math.Matrix object
- */
-
- public Matrix getM()
- {
- return m;
}
/**
*/
public double getEigenvalue(int i)
{
- return eigenvector.d[i];
+ return eigenvector.getD()[i];
}
/**
*/
public float[][] getComponents(int l, int n, int mm, float factor)
{
- float[][] out = new float[m.rows][3];
+ float[][] out = new float[getHeight()][3];
- for (int i = 0; i < m.rows; i++)
+ for (int i = 0; i < getHeight(); i++)
{
out[i][0] = (float) component(i, l) * factor;
out[i][1] = (float) component(i, n) * factor;
public double[] component(int n)
{
// n = index of eigenvector
- double[] out = new double[m.rows];
+ double[] out = new double[getHeight()];
- for (int i = 0; i < m.rows; i++)
+ for (int i = 0; i < out.length; i++)
{
out[i] = component(i, n);
}
{
double out = 0.0;
- for (int i = 0; i < symm.cols; i++)
+ for (int i = 0; i < symm.width(); i++)
{
- out += (symm.value[row][i] * eigenvector.value[i][n]);
+ out += (symm.getValue(row, i) * eigenvector.getValue(i, n));
}
- return out / eigenvector.d[n];
+ return out / eigenvector.getD()[n];
}
public String getDetails()
}
};
+ // long now = System.currentTimeMillis();
try
{
details.append("PCA Calculation Mode is "
+ (jvCalcMode ? "Jalview variant" : "Original SeqSpace")
+ "\n");
- Matrix mt = m.transpose();
- details.append(" --- OrigT * Orig ---- \n");
- if (!jvCalcMode)
- {
- eigenvector = mt.preMultiply(m); // standard seqspace comparison matrix
- }
- else
- {
- eigenvector = mt.preMultiply(m2); // jalview variation on seqsmace
- // method
- }
+ eigenvector = scoreMatrix.computePairwiseScores(seqs);
- eigenvector.print(ps);
+ details.append(" --- OrigT * Orig ---- \n");
+ eigenvector.print(ps, "%8.2f");
symm = eigenvector.copy();
details.append(" ---Tridiag transform matrix ---\n");
details.append(" --- D vector ---\n");
- eigenvector.printD(ps);
+ eigenvector.printD(ps, "%15.4e");
ps.println();
details.append("--- E vector ---\n");
- eigenvector.printE(ps);
+ eigenvector.printE(ps, "%15.4e");
ps.println();
// Now produce the diagonalization matrix
}
details.append(" --- New diagonalization matrix ---\n");
- eigenvector.print(ps);
+ eigenvector.print(ps, "%8.2f");
details.append(" --- Eigenvalues ---\n");
- eigenvector.printD(ps);
+ eigenvector.printD(ps, "%15.4e");
ps.println();
/*
* for (int seq=0;seq<symm.rows;seq++) { ps.print("\"Seq"+seq+"\""); for
*
* ps.print(","+component(seq, ev)); } ps.println(); }
*/
+ // System.out.println(("PCA.run() took "
+ // + (System.currentTimeMillis() - now) + "ms"));
}
- boolean jvCalcMode = true;
-
public void setJvCalcMode(boolean calcMode)
{
this.jvCalcMode = calcMode;
}
+
+ /**
+ * Answers the N dimensions of the NxN PCA matrix. This is the number of
+ * sequences involved in the pairwise score calculation.
+ *
+ * @return
+ */
+ public int getHeight()
+ {
+ // TODO can any of seqs[] be null?
+ return seqs.length;
+ }
}
import jalview.datamodel.SequenceI;
import jalview.renderer.ResidueShaderI;
import jalview.schemes.ColourSchemeI;
+import jalview.viewmodel.ViewportRanges;
import java.awt.Color;
import java.util.Hashtable;
public interface AlignViewportI extends ViewStyleI
{
- int getEndRes();
+ /**
+ * Get the ranges object containing details of the start and end sequences and
+ * residues
+ *
+ * @return
+ */
+ public ViewportRanges getRanges();
/**
* calculate the height for visible annotation, revalidating bounds where
AlignmentAnnotation getAlignmentConsensusAnnotation();
/**
+ * get the container for alignment gap annotation
+ *
+ * @return
+ */
+ AlignmentAnnotation getAlignmentGapAnnotation();
+
+ /**
* get the container for cDNA complement consensus annotation
*
* @return
import jalview.datamodel.SequenceI;
import java.awt.Color;
+import java.awt.Graphics;
import java.util.List;
import java.util.Map;
{
/**
- * compute the perceived colour for a given column position in sequenceI,
- * taking transparency and feature visibility into account.
+ * Computes the feature colour for a given sequence and column position,
+ * taking into account sequence feature locations, feature colour schemes,
+ * render ordering, feature and feature group visibility, and transparency.
+ * <p>
+ * The graphics argument should be provided if transparency is applied
+ * (getTransparency() < 1). With feature transparency, visible features are
+ * written to the graphics context and the composite colour may be read off
+ * from it. In this case, the returned feature colour is not the composite
+ * colour but that of the last feature drawn.
+ * <p>
+ * If no transparency applies, then the graphics argument may be null, and the
+ * returned colour is the one that would be drawn for the feature.
+ * <p>
+ * Returns null if there is no visible feature at the position.
+ * <p>
+ * This is provided to support rendering of feature colours other than on the
+ * sequence alignment, including by structure viewers and the overview window.
+ * Note this method takes no account of whether the sequence or column is
+ * hidden.
*
- * @param col
- * - background colour (due to alignment/group shading schemes, etc).
- * @param sequenceI
- * - sequence providing features
- * @param r
- * - column position
+ * @param sequence
+ * @param column
+ * @param g
* @return
*/
- Color findFeatureColour(Color col, SequenceI sequenceI, int r);
+ Color findFeatureColour(SequenceI sequence, int column, Graphics g);
/**
* trigger the feature discovery process for a newly created feature renderer.
*/
void setVisible(String featureType);
+ /**
+ * Sets the transparency value, between 0 (full transparency) and 1 (no
+ * transparency)
+ *
+ * @param value
+ */
+ void setTransparency(float value);
+
+ /**
+ * Returns the transparency value, between 0 (full transparency) and 1 (no
+ * transparency)
+ *
+ * @return
+ */
+ float getTransparency();
}
package jalview.api;
import jalview.datamodel.SequenceI;
+import jalview.renderer.seqfeatures.FeatureColourFinder;
import java.awt.Color;
public interface SequenceRenderer
{
- Color getResidueBoxColour(SequenceI sequenceI, int r);
-
- Color getResidueColour(SequenceI seq, int position, FeatureRenderer fr);
+ Color getResidueColour(SequenceI seq, int position,
+ FeatureColourFinder finder);
}
Menu menu1 = new Menu();
public APopupMenu(AlignmentPanel apanel, final SequenceI seq,
- Vector<String> links)
+ List<String> links)
{
// /////////////////////////////////////////////////////////
// If this is activated from the sequence panel, the user may want to
import jalview.util.MappingUtils;
import jalview.util.MessageManager;
import jalview.viewmodel.AlignmentViewport;
+import jalview.viewmodel.ViewportRanges;
import java.awt.BorderLayout;
import java.awt.Canvas;
@Override
public void keyPressed(KeyEvent evt)
{
+ ViewportRanges ranges = viewport.getRanges();
+
if (viewport.cursorMode
&& ((evt.getKeyCode() >= KeyEvent.VK_0 && evt.getKeyCode() <= KeyEvent.VK_9) || (evt
.getKeyCode() >= KeyEvent.VK_NUMPAD0 && evt
new String[] { (viewport.cursorMode ? "on" : "off") }));
if (viewport.cursorMode)
{
- alignPanel.seqPanel.seqCanvas.cursorX = viewport.startRes;
- alignPanel.seqPanel.seqCanvas.cursorY = viewport.startSeq;
+ alignPanel.seqPanel.seqCanvas.cursorX = ranges.getStartRes();
+ alignPanel.seqPanel.seqCanvas.cursorY = ranges.getStartSeq();
}
break;
}
else
{
- alignPanel.setScrollValues(viewport.startRes, viewport.startSeq
- - viewport.endSeq + viewport.startSeq);
+ alignPanel.setScrollValues(ranges.getStartRes(),
+ 2 * ranges.getStartSeq() - ranges.getEndSeq());
}
break;
}
else
{
- alignPanel.setScrollValues(viewport.startRes, viewport.startSeq
- + viewport.endSeq - viewport.startSeq);
+ alignPanel
+ .setScrollValues(ranges.getStartRes(), ranges.getEndSeq());
}
break;
seqs, 0, viewport.getAlignment().getWidth(),
viewport.getAlignment()));
- viewport.setEndSeq(viewport.getAlignment().getHeight());
+ viewport.getRanges().setEndSeq(viewport.getAlignment().getHeight());
viewport.getAlignment().getWidth();
viewport.firePropertyChange("alignment", null, viewport.getAlignment()
.getSequences());
void trimAlignment(boolean trimLeft)
{
+ AlignmentI al = viewport.getAlignment();
+ ViewportRanges ranges = viewport.getRanges();
ColumnSelection colSel = viewport.getColumnSelection();
int column;
}
else
{
- seqs = viewport.getAlignment().getSequencesArray();
+ seqs = al.getSequencesArray();
}
TrimRegionCommand trimRegion;
if (trimLeft)
{
trimRegion = new TrimRegionCommand("Remove Left", true, seqs,
- column, viewport.getAlignment());
- viewport.setStartRes(0);
+ column, al);
+ ranges.setStartRes(0);
}
else
{
trimRegion = new TrimRegionCommand("Remove Right", false, seqs,
- column, viewport.getAlignment());
+ column, al);
}
statusBar.setText(MessageManager.formatMessage(
.toString() }));
addHistoryItem(trimRegion);
- for (SequenceGroup sg : viewport.getAlignment().getGroups())
+ for (SequenceGroup sg : al.getGroups())
{
if ((trimLeft && !sg.adjustForRemoveLeft(column))
|| (!trimLeft && !sg.adjustForRemoveRight(column)))
{
- viewport.getAlignment().deleteGroup(sg);
+ al.deleteGroup(sg);
}
}
- viewport.firePropertyChange("alignment", null, viewport
- .getAlignment().getSequences());
+ viewport.firePropertyChange("alignment", null, al.getSequences());
}
}
public void removeGappedColumnMenuItem_actionPerformed()
{
- int start = 0, end = viewport.getAlignment().getWidth() - 1;
+ AlignmentI al = viewport.getAlignment();
+ ViewportRanges ranges = viewport.getRanges();
+ int start = 0;
+ int end = ranges.getAbsoluteAlignmentWidth() - 1;
SequenceI[] seqs;
if (viewport.getSelectionGroup() != null)
// This is to maintain viewport position on first residue
// of first sequence
- SequenceI seq = viewport.getAlignment().getSequenceAt(0);
- int startRes = seq.findPosition(viewport.startRes);
+ SequenceI seq = al.getSequenceAt(0);
+ int startRes = seq.findPosition(ranges.getStartRes());
// ShiftList shifts;
// viewport.getAlignment().removeGaps(shifts=new ShiftList());
// edit.alColumnChanges=shifts.getInverse();
// if (viewport.hasHiddenColumns)
// viewport.getColumnSelection().compensateForEdits(shifts);
- viewport.setStartRes(seq.findIndex(startRes) - 1);
- viewport.firePropertyChange("alignment", null, viewport.getAlignment()
- .getSequences());
+ ranges.setStartRes(seq.findIndex(startRes) - 1);
+ viewport.firePropertyChange("alignment", null, al.getSequences());
}
public void removeAllGapsMenuItem_actionPerformed()
{
- int start = 0, end = viewport.getAlignment().getWidth() - 1;
+ AlignmentI al = viewport.getAlignment();
+ ViewportRanges ranges = viewport.getRanges();
+ int start = 0;
+ int end = ranges.getAbsoluteAlignmentWidth() - 1;
SequenceI[] seqs;
if (viewport.getSelectionGroup() != null)
// This is to maintain viewport position on first residue
// of first sequence
- SequenceI seq = viewport.getAlignment().getSequenceAt(0);
- int startRes = seq.findPosition(viewport.startRes);
+ SequenceI seq = al.getSequenceAt(0);
+ int startRes = seq.findPosition(ranges.getStartRes());
addHistoryItem(new RemoveGapsCommand("Remove Gaps", seqs, start, end,
- viewport.getAlignment()));
+ al));
- viewport.setStartRes(seq.findIndex(startRes) - 1);
+ ranges.setStartRes(seq.findIndex(startRes) - 1);
- viewport.firePropertyChange("alignment", null, viewport.getAlignment()
- .getSequences());
+ viewport.firePropertyChange("alignment", null, al.getSequences());
}
import jalview.renderer.ResidueShader;
import jalview.schemes.ColourSchemeProperty;
import jalview.schemes.UserColourScheme;
-import jalview.structure.CommandListener;
import jalview.structure.SelectionSource;
import jalview.structure.StructureSelectionManager;
import jalview.structure.VamsasSource;
import jalview.viewmodel.AlignmentViewport;
+import jalview.viewmodel.ViewportRanges;
import java.awt.Font;
public class AlignViewport extends AlignmentViewport implements
- SelectionSource, VamsasSource, CommandListener
+ SelectionSource
{
boolean cursorMode = false;
calculator = new jalview.workers.AlignCalcManager();
this.applet = applet;
alignment = al;
+ ranges = new ViewportRanges(this.alignment);
// we always pad gaps
this.setPadGaps(true);
- this.startRes = 0;
- this.endRes = al.getWidth() - 1;
- this.startSeq = 0;
- this.endSeq = al.getHeight() - 1;
+
if (applet != null)
{
// get the width and height scaling factors if they were specified
public void resetSeqLimits(int height)
{
- setEndSeq(height / getCharHeight());
+ ranges.setEndSeq(height / getCharHeight());
}
public void setCurrentTree(NJTree tree)
import jalview.datamodel.SearchResultsI;
import jalview.datamodel.SequenceI;
import jalview.structure.StructureSelectionManager;
+import jalview.viewmodel.ViewportRanges;
import java.awt.BorderLayout;
import java.awt.Color;
AnnotationLabels alabels;
+ ViewportRanges vpRanges;
+
// this value is set false when selection area being dragged
boolean fastPaint = true;
{
alignFrame = null;
av = null;
+ vpRanges = null;
seqPanel = null;
seqPanelHolder = null;
sequenceHolderPanel = null;
alignFrame = af;
this.av = av;
+ vpRanges = av.getRanges();
seqPanel = new SeqPanel(av, this);
idPanel = new IdPanel(av, this);
scalePanel = new ScalePanel(av, this);
@Override
public void componentResized(ComponentEvent evt)
{
- setScrollValues(av.getStartRes(), av.getStartSeq());
+ setScrollValues(vpRanges.getStartRes(), vpRanges.getStartSeq());
if (getSize().height > 0
&& annotationPanelHolder.getSize().height > 0)
{
*/
if (centre)
{
- int offset = (av.getEndRes() - av.getStartRes() + 1) / 2 - 1;
+ int offset = (vpRanges.getEndRes() - vpRanges.getStartRes() + 1) / 2 - 1;
start = Math.max(start - offset, 0);
end = Math.min(end + offset, seq.getEnd() - 1);
}
// setScrollValues(start, seqIndex);
// }
// logic copied from jalview.gui.AlignmentPanel:
- if ((startv = av.getStartRes()) >= start)
+ if ((startv = vpRanges.getStartRes()) >= start)
{
/*
* Scroll left to make start of search results visible
*/
setScrollValues(start - 1, seqIndex);
}
- else if ((endv = av.getEndRes()) <= end)
+ else if ((endv = vpRanges.getEndRes()) <= end)
{
/*
* Scroll right to make end of search results visible
*/
setScrollValues(startv + 1 + end - endv, seqIndex);
}
- else if ((starts = av.getStartSeq()) > seqIndex)
+ else if ((starts = vpRanges.getStartSeq()) > seqIndex)
{
/*
* Scroll up to make start of search results visible
*/
- setScrollValues(av.getStartRes(), seqIndex);
+ setScrollValues(vpRanges.getStartRes(), seqIndex);
}
- else if ((ends = av.getEndSeq()) <= seqIndex)
+ else if ((ends = vpRanges.getEndSeq()) <= seqIndex)
{
/*
* Scroll down to make end of search results visible
*/
- setScrollValues(av.getStartRes(), starts + seqIndex - ends + 1);
+ setScrollValues(vpRanges.getStartRes(), starts + seqIndex - ends
+ + 1);
}
/*
* Else results are already visible - no need to scroll
{
int cwidth = seqPanel.seqCanvas
.getWrappedCanvasWidth(seqPanel.seqCanvas.getSize().width);
- if (res <= av.getStartRes() || res >= (av.getStartRes() + cwidth))
+ if (res <= vpRanges.getStartRes()
+ || res >= (vpRanges.getStartRes() + cwidth))
{
vscroll.setValue(res / cwidth);
- av.startRes = vscroll.getValue() * cwidth;
+ vpRanges.setStartRes(vscroll.getValue() * cwidth);
}
}
public void setWrapAlignment(boolean wrap)
{
- av.startSeq = 0;
- av.startRes = 0;
+ vpRanges.setStartSeq(0);
+ vpRanges.setStartRes(0);
scalePanelHolder.setVisible(!wrap);
hscroll.setVisible(!wrap);
{
x = 0;
}
- ;
+
hextent = seqPanel.seqCanvas.getSize().width / av.getCharWidth();
vextent = seqPanel.seqCanvas.getSize().height / av.getCharHeight();
x = 0;
}
- av.setStartSeq(y);
-
- int endSeq = y + vextent;
- if (endSeq > av.getAlignment().getHeight())
- {
- endSeq = av.getAlignment().getHeight();
- }
-
- av.setEndSeq(endSeq);
- av.setStartRes(x);
- av.setEndRes((x + (seqPanel.seqCanvas.getSize().width / av
+ vpRanges.setStartSeq(y);
+ vpRanges.setEndSeq(y + vextent);
+ vpRanges.setStartRes(x);
+ vpRanges.setEndRes((x + (seqPanel.seqCanvas.getSize().width / av
.getCharWidth())) - 1);
hscroll.setValues(x, hextent, 0, width);
@Override
public void adjustmentValueChanged(AdjustmentEvent evt)
{
- int oldX = av.getStartRes();
- int oldY = av.getStartSeq();
+ int oldX = vpRanges.getStartRes();
+ int oldY = vpRanges.getStartSeq();
if (evt == null || evt.getSource() == apvscroll)
{
if (evt == null || evt.getSource() == hscroll)
{
int x = hscroll.getValue();
- av.setStartRes(x);
- av.setEndRes(x + seqPanel.seqCanvas.getSize().width
+ vpRanges.setStartRes(x);
+ vpRanges.setEndRes(x + seqPanel.seqCanvas.getSize().width
/ av.getCharWidth() - 1);
}
{
int rowSize = seqPanel.seqCanvas
.getWrappedCanvasWidth(seqPanel.seqCanvas.getSize().width);
- av.setStartRes(vscroll.getValue() * rowSize);
- av.setEndRes((vscroll.getValue() + 1) * rowSize);
+ vpRanges.setStartRes(vscroll.getValue() * rowSize);
+ vpRanges.setEndRes((vscroll.getValue() + 1) * rowSize);
}
else
{
- av.setStartSeq(offy);
- av.setEndSeq(offy + seqPanel.seqCanvas.getSize().height
- / av.getCharHeight());
+ vpRanges.setStartSeq(offy);
+ vpRanges.setEndSeq(offy + seqPanel.seqCanvas.getSize().height
+ / av.getCharHeight() - 1);
}
}
overviewPanel.setBoxPosition();
}
- int scrollX = av.startRes - oldX;
- int scrollY = av.startSeq - oldY;
+ int scrollX = vpRanges.getStartRes() - oldX;
+ int scrollY = vpRanges.getStartSeq() - oldY;
if (av.getWrapAlignment() || !fastPaint || av.MAC)
{
{
// Make sure we're not trying to draw a panel
// larger than the visible window
- if (scrollX > av.endRes - av.startRes)
+ if (scrollX > vpRanges.getEndRes() - vpRanges.getStartRes())
{
- scrollX = av.endRes - av.startRes;
+ scrollX = vpRanges.getEndRes() - vpRanges.getStartRes();
}
- else if (scrollX < av.startRes - av.endRes)
+ else if (scrollX < vpRanges.getStartRes() - vpRanges.getEndRes())
{
- scrollX = av.startRes - av.endRes;
+ scrollX = vpRanges.getStartRes() - vpRanges.getEndRes();
}
idPanel.idCanvas.fastPaint(scrollY);
scalePanel.repaint();
if (av.isShowAnnotation())
{
- annotationPanel.fastPaint(av.getStartRes() - oldX);
+ annotationPanel.fastPaint(vpRanges.getStartRes() - oldX);
}
}
sendViewPosition();
private void sendViewPosition()
{
StructureSelectionManager.getStructureSelectionManager(av.applet)
- .sendViewPosition(this, av.startRes, av.endRes, av.startSeq,
- av.endSeq);
+ .sendViewPosition(this, vpRanges.getStartRes(),
+ vpRanges.getEndRes(), vpRanges.getStartSeq(),
+ vpRanges.getEndSeq());
}
/**
}
else
{
- setScrollValues(av.getStartRes(), av.getStartSeq());
+ setScrollValues(vpRanges.getStartRes(), vpRanges.getStartSeq());
}
seqPanel.seqCanvas.repaint();
av.calcPanelHeight());
f.height += dif;
ap.seqPanelHolder.setPreferredSize(f);
- ap.setScrollValues(av.getStartRes(), av.getStartSeq());
+ ap.setScrollValues(av.getRanges().getStartRes(), av.getRanges()
+ .getStartSeq());
ap.validate();
// ap.paintAlignment(true);
ap.addNotify();
}
}
- int column = evt.getX() / av.getCharWidth() + av.getStartRes();
+ int column = evt.getX() / av.getCharWidth()
+ + av.getRanges().getStartRes();
if (av.hasHiddenColumns())
{
gg.setColor(Color.white);
gg.fillRect(0, 0, getSize().width, getSize().height);
- drawComponent(gg, av.startRes, av.endRes + 1);
+ drawComponent(gg, av.getRanges().getStartRes(), av.getRanges()
+ .getEndRes() + 1);
g.drawImage(image, 0, 0, this);
}
gg.copyArea(0, 0, imgWidth, getSize().height,
-horizontal * av.getCharWidth(), 0);
- int sr = av.startRes, er = av.endRes + 1, transX = 0;
+ int sr = av.getRanges().getStartRes(), er = av.getRanges().getEndRes() + 1, transX = 0;
if (horizontal > 0) // scrollbar pulled right, image to the left
{
public jalview.api.FeatureRenderer getFeatureRenderer(
AlignmentViewPanel alignment)
{
- AlignmentPanel ap = (AlignmentPanel) alignment;
- if (appletJmolBinding.ap.av.isShowSequenceFeatures())
- {
- if (appletJmolBinding.fr == null)
- {
- appletJmolBinding.fr = new jalview.appletgui.FeatureRenderer(
- appletJmolBinding.ap.av);
- }
-
- appletJmolBinding.fr
- .transferSettings(appletJmolBinding.ap.seqPanel.seqCanvas
- .getFeatureRenderer());
- }
-
- return appletJmolBinding.fr;
+ return appletJmolBinding.ap.getFeatureRenderer();
}
@Override
@Override
public FeatureRenderer getFeatureRenderer(AlignmentViewPanel alignment)
{
- AlignmentPanel ap = (AlignmentPanel) alignment;
- if (ap.av.isShowSequenceFeatures())
+ AlignmentPanel alignPanel = (AlignmentPanel) alignment;
+ if (alignPanel.av.isShowSequenceFeatures())
{
- return ap.getFeatureRenderer();
+ return alignPanel.getFeatureRenderer();
}
else
{
if (dialog.accept)
{
- // This ensures that the last sequence
- // is refreshed and new features are rendered
- lastSeq = null;
lastFeatureAdded = name.getText().trim();
lastFeatureGroupAdded = source.getText().trim();
lastDescriptionAdded = description.getText().replace('\n', ' ');
public void adjustmentValueChanged(AdjustmentEvent evt)
{
fr.setTransparency((100 - transparency.getValue()) / 100f);
- ap.seqPanel.seqCanvas.repaint();
-
+ ap.paintAlignment(true);
}
class MyCheckbox extends Checkbox
package jalview.appletgui;
import jalview.datamodel.SequenceI;
+import jalview.viewmodel.ViewportRanges;
import java.awt.Color;
import java.awt.Font;
return;
}
+ ViewportRanges ranges = av.getRanges();
+
gg.copyArea(0, 0, getSize().width, imgHeight, 0,
-vertical * av.getCharHeight());
- int ss = av.startSeq, es = av.endSeq, transY = 0;
+ int ss = ranges.getStartSeq(), es = ranges.getEndSeq(), transY = 0;
if (vertical > 0) // scroll down
{
ss = es - vertical;
- if (ss < av.startSeq) // ie scrolling too fast, more than a page at a time
+ if (ss < ranges.getStartSeq()) // ie scrolling too fast, more than a page
+ // at a
+ // time
{
- ss = av.startSeq;
+ ss = ranges.getStartSeq();
}
else
{
- transY = imgHeight - vertical * av.getCharHeight();
+ transY = imgHeight - ((vertical + 1) * av.getCharHeight());
}
}
else if (vertical < 0)
{
es = ss - vertical;
- if (es > av.endSeq)
+ if (es > ranges.getEndSeq())
{
- es = av.endSeq;
+ es = ranges.getEndSeq();
}
}
gg.setFont(italic);
gg.fillRect(0, 0, getSize().width, getSize().height);
- drawIds(av.startSeq, av.endSeq);
+ drawIds(av.getRanges().getStartSeq(), av.getRanges().getEndSeq());
g.drawImage(image, 0, 0, this);
}
int cHeight = alheight * avcharHeight + hgap + annotationHeight;
- int rowSize = av.getEndRes() - av.getStartRes();
+ int rowSize = av.getRanges().getEndRes()
+ - av.getRanges().getStartRes();
// Draw the rest of the panels
- for (int ypos = hgap, row = av.startRes; (ypos <= getSize().height)
+ for (int ypos = hgap, row = av.getRanges().getStartRes(); (ypos <= getSize().height)
&& (row < maxwidth); ypos += cHeight, row += rowSize)
{
for (int i = starty; i < alheight; i++)
{
// Now draw the id strings
SequenceI seq;
- for (int i = starty; i < endy; i++)
+ for (int i = starty; i <= endy; i++)
{
seq = av.getAlignment().getSequenceAt(i);
*/
package jalview.appletgui;
-import static jalview.util.UrlConstants.EMBLEBI_STRING;
-import static jalview.util.UrlConstants.SRS_STRING;
-
import jalview.datamodel.Sequence;
import jalview.datamodel.SequenceFeature;
import jalview.datamodel.SequenceGroup;
import jalview.datamodel.SequenceI;
-import jalview.util.UrlLink;
+import jalview.urls.api.UrlProviderFactoryI;
+import jalview.urls.api.UrlProviderI;
+import jalview.urls.applet.AppletUrlProviderFactory;
import jalview.viewmodel.AlignmentViewport;
import java.awt.BorderLayout;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
+import java.util.HashMap;
import java.util.List;
-import java.util.Vector;
public class IdPanel extends Panel implements MouseListener,
MouseMotionListener
boolean mouseDragging = false;
- java.util.Vector links = new java.util.Vector();
+ UrlProviderI urlProvider = null;
public IdPanel(AlignViewport av, AlignmentPanel parent)
{
String label, url;
// TODO: add in group link parameter
+
+ // make a list of label,url pairs
+ HashMap<String, String> urlList = new HashMap<String, String>();
if (av.applet != null)
{
for (int i = 1; i < 10; i++)
label = av.applet.getParameter("linkLabel_" + i);
url = av.applet.getParameter("linkURL_" + i);
- if (label != null && url != null)
+ // only add non-null parameters
+ if (label != null)
{
- links.addElement(label + "|" + url);
+ urlList.put(label, url);
}
-
}
- }
- {
- // upgrade old SRS link
- int srsPos = links.indexOf(SRS_STRING);
- if (srsPos > -1)
+
+ if (!urlList.isEmpty())
{
- links.setElementAt(EMBLEBI_STRING, srsPos);
+ // set default as first entry in list
+ String defaultUrl = av.applet.getParameter("linkLabel_1");
+ UrlProviderFactoryI factory = new AppletUrlProviderFactory(
+ defaultUrl, urlList);
+ urlProvider = factory.createUrlProvider();
}
}
- if (links.size() < 1)
- {
- links = new java.util.Vector();
- links.addElement(EMBLEBI_STRING);
- }
}
Tooltip tooltip;
return;
}
- // DEFAULT LINK IS FIRST IN THE LINK LIST
+ // get the sequence details
int seq = alignPanel.seqPanel.findSeq(e);
SequenceI sq = av.getAlignment().getSequenceAt(seq);
if (sq == null)
}
String id = sq.getName();
- String target = null;
- String url = null;
- int i = 0;
- while (url == null && i < links.size())
- {
- // DEFAULT LINK IS FIRST IN THE LINK LIST
- // BUT IF ITS A REGEX AND DOES NOT MATCH THE NEXT ONE WILL BE TRIED
- url = links.elementAt(i++).toString();
- jalview.util.UrlLink urlLink = null;
- try
- {
- urlLink = new UrlLink(url);
- target = urlLink.getTarget();
- } catch (Exception foo)
- {
- System.err.println("Exception for URLLink '" + url + "'");
- foo.printStackTrace();
- url = null;
- continue;
- }
-
- if (urlLink.usesDBAccession())
- {
- // this URL requires an accession id, not the name of a sequence
- url = null;
- continue;
- }
-
- if (!urlLink.isValid())
- {
- System.err.println(urlLink.getInvalidMessage());
- url = null;
- continue;
- }
-
- String urls[] = urlLink.makeUrls(id, true);
- if (urls == null || urls[0] == null || urls[0].length() < 1)
- {
- url = null;
- continue;
- }
- // just take first URL made from regex
- url = urls[1];
- }
+ // get the default url with the sequence details filled in
+ String url = urlProvider.getPrimaryUrl(id);
+ String target = urlProvider.getPrimaryTarget(id);
try
{
-
alignPanel.alignFrame.showURL(url, target);
} catch (Exception ex)
{
return;
}
- if (mouseDragging && e.getY() < 0 && av.getStartSeq() > 0)
+ if (mouseDragging && e.getY() < 0 && av.getRanges().getStartSeq() > 0)
{
scrollThread = new ScrollThread(true);
}
if (mouseDragging && e.getY() >= getSize().height
- && av.getAlignment().getHeight() > av.getEndSeq())
+ && av.getAlignment().getHeight() > av.getRanges().getEndSeq())
{
scrollThread = new ScrollThread(false);
}
// build a new links menu based on the current links + any non-positional
// features
- Vector nlinks = new Vector();
- for (int l = 0, lSize = links.size(); l < lSize; l++)
- {
- nlinks.addElement(links.elementAt(l));
- }
+ List<String> nlinks = urlProvider.getLinksForMenu();
+
SequenceFeature sf[] = sq == null ? null : sq.getSequenceFeatures();
for (int sl = 0; sf != null && sl < sf.length; sl++)
{
{
for (int l = 0, lSize = sf[sl].links.size(); l < lSize; l++)
{
- nlinks.addElement(sf[sl].links.elementAt(l));
+ nlinks.add(sf[sl].links.elementAt(l));
}
}
}
int index = av.getAlignment().findIndex(list.get(0));
// do we need to scroll the panel?
- if (av.getStartSeq() > index || av.getEndSeq() < index)
+ if (av.getRanges().getStartSeq() > index
+ || av.getRanges().getEndSeq() < index)
{
- alignPanel.setScrollValues(av.getStartRes(), index);
+ alignPanel.setScrollValues(av.getRanges().getStartRes(), index);
}
}
if (alignPanel.scrollUp(up))
{
// scroll was ok, so add new sequence to selection
- int seq = av.getStartSeq();
+ int seq = av.getRanges().getStartSeq();
if (!up)
{
- seq = av.getEndSeq();
+ seq = av.getRanges().getEndSeq();
}
if (seq < lastid)
*/
package jalview.appletgui;
-import jalview.datamodel.AlignmentI;
+import jalview.datamodel.SequenceI;
+import jalview.renderer.seqfeatures.FeatureColourFinder;
+import jalview.viewmodel.OverviewDimensions;
import java.awt.Color;
import java.awt.Dimension;
public class OverviewPanel extends Panel implements Runnable,
MouseMotionListener, MouseListener
{
- Image miniMe;
+ private OverviewDimensions od;
- Image offscreen;
+ private Image miniMe;
- AlignViewport av;
+ private Image offscreen;
- AlignmentPanel ap;
+ private AlignViewport av;
- float scalew = 1f;
+ private AlignmentPanel ap;
- float scaleh = 1f;
+ private boolean resizing = false;
- public int width, sequencesHeight;
-
- int graphHeight = 20;
-
- int boxX = -1, boxY = -1, boxWidth = -1, boxHeight = -1;
-
- boolean resizing = false;
+ // This is set true if the user resizes whilst
+ // the overview is being calculated
+ private boolean resizeAgain = false;
// Can set different properties in this seqCanvas than
// main visible SeqCanvas
- SequenceRenderer sr;
+ private SequenceRenderer sr;
- FeatureRenderer fr;
+ private FeatureRenderer fr;
- Frame nullFrame;
+ private Frame nullFrame;
- public OverviewPanel(AlignmentPanel ap)
+ public OverviewPanel(AlignmentPanel alPanel)
{
- this.av = ap.av;
- this.ap = ap;
+ this.av = alPanel.av;
+ this.ap = alPanel;
setLayout(null);
nullFrame = new Frame();
nullFrame.addNotify();
sr.forOverview = true;
fr = new FeatureRenderer(av);
- // scale the initial size of overviewpanel to shape of alignment
- float initialScale = (float) av.getAlignment().getWidth()
- / (float) av.getAlignment().getHeight();
-
- if (av.getSequenceConsensusHash() == null)
- {
- graphHeight = 0;
- }
-
- if (av.getAlignment().getWidth() > av.getAlignment().getHeight())
- {
- // wider
- width = 400;
- sequencesHeight = (int) (400f / initialScale);
- if (sequencesHeight < 40)
- {
- sequencesHeight = 40;
- }
- }
- else
- {
- // taller
- width = (int) (400f * initialScale);
- sequencesHeight = 300;
- if (width < 120)
- {
- width = 120;
- }
- }
+ od = new OverviewDimensions(av.getRanges(),
+ (av.isShowAnnotation() && av.getSequenceConsensusHash() != null));
- setSize(new Dimension(width, sequencesHeight + graphHeight));
+ setSize(new Dimension(od.getWidth(), od.getHeight()));
addComponentListener(new ComponentAdapter()
{
@Override
public void componentResized(ComponentEvent evt)
{
- if (getSize().width != width
- || getSize().height != sequencesHeight + graphHeight)
+ if ((getWidth() != od.getWidth())
+ || (getHeight() != (od.getHeight())))
{
updateOverviewImage();
}
@Override
public void mousePressed(MouseEvent evt)
{
- boxX = evt.getX();
- boxY = evt.getY();
- checkValid();
+ mouseAction(evt);
}
@Override
public void mouseReleased(MouseEvent evt)
{
- boxX = evt.getX();
- boxY = evt.getY();
- checkValid();
+ mouseAction(evt);
}
@Override
public void mouseDragged(MouseEvent evt)
{
- boxX = evt.getX();
- boxY = evt.getY();
- checkValid();
+ mouseAction(evt);
}
- void checkValid()
+ private void mouseAction(MouseEvent evt)
{
- if (boxY < 0)
- {
- boxY = 0;
- }
-
- if (boxY > (sequencesHeight - boxHeight))
- {
- boxY = sequencesHeight - boxHeight + 1;
- }
-
- if (boxX < 0)
- {
- boxX = 0;
- }
-
- if (boxX > (width - boxWidth))
- {
- if (av.hasHiddenColumns())
- {
- // Try smallest possible box
- boxWidth = (int) ((av.endRes - av.startRes + 1) * av.getCharWidth() * scalew);
- }
- boxX = width - boxWidth;
- }
-
- int col = (int) (boxX / scalew / av.getCharWidth());
- int row = (int) (boxY / scaleh / av.getCharHeight());
-
- if (av.hasHiddenColumns())
- {
- if (!av.getColumnSelection().isVisible(col))
- {
- return;
- }
-
- col = av.getColumnSelection().findColumnPosition(col);
- }
-
- if (av.hasHiddenRows())
- {
- row = av.getAlignment().getHiddenSequences()
- .findIndexWithoutHiddenSeqs(row);
- }
-
- ap.setScrollValues(col, row);
+ od.updateViewportFromMouse(evt.getX(), evt.getY(), av.getAlignment()
+ .getHiddenSequences(), av.getColumnSelection(), av
+ .getRanges());
+ ap.setScrollValues(od.getScrollCol(), od.getScrollRow());
ap.paintAlignment(false);
}
/**
- * DOCUMENT ME!
+ * Updates the overview image when the related alignment panel is updated
*/
public void updateOverviewImage()
{
if ((getSize().width > 0) && (getSize().height > 0))
{
- width = getSize().width;
- sequencesHeight = getSize().height - graphHeight;
+ od.setWidth(getSize().width);
+ od.setHeight(getSize().height);
}
- setSize(new Dimension(width, sequencesHeight + graphHeight));
+ setSize(new Dimension(od.getWidth(), od.getHeight()));
Thread thread = new Thread(this);
thread.start();
repaint();
}
- // This is set true if the user resizes whilst
- // the overview is being calculated
- boolean resizeAgain = false;
-
@Override
public void run()
{
miniMe = null;
- int alwidth = av.getAlignment().getWidth();
- int alheight = av.getAlignment().getHeight()
- + av.getAlignment().getHiddenSequences().getSize();
if (av.isShowSequenceFeatures())
{
if (getSize().width > 0 && getSize().height > 0)
{
- width = getSize().width;
- sequencesHeight = getSize().height - graphHeight;
+ od.setWidth(getSize().width);
+ od.setHeight(getSize().height);
}
- setSize(new Dimension(width, sequencesHeight + graphHeight));
-
- int fullsizeWidth = alwidth * av.getCharWidth();
- int fullsizeHeight = alheight * av.getCharHeight();
+ setSize(new Dimension(od.getWidth(), od.getHeight()));
- scalew = (float) width / (float) fullsizeWidth;
- scaleh = (float) sequencesHeight / (float) fullsizeHeight;
-
- miniMe = nullFrame.createImage(width, sequencesHeight + graphHeight);
- offscreen = nullFrame.createImage(width, sequencesHeight + graphHeight);
+ miniMe = nullFrame.createImage(od.getWidth(), od.getHeight());
+ offscreen = nullFrame.createImage(od.getWidth(), od.getHeight());
Graphics mg = miniMe.getGraphics();
- float sampleCol = (float) alwidth / (float) width;
- float sampleRow = (float) alheight / (float) sequencesHeight;
-
- int lastcol = 0, lastrow = 0;
- int xstart = 0, ystart = 0;
- Color color = Color.yellow;
- int row, col, sameRow = 0, sameCol = 0;
- jalview.datamodel.SequenceI seq;
- final boolean hasHiddenRows = av.hasHiddenRows(), hasHiddenCols = av
- .hasHiddenColumns();
- boolean hiddenRow = false;
- AlignmentI alignment = av.getAlignment();
- for (row = 0; row <= sequencesHeight; row++)
- {
- if (resizeAgain)
- {
- break;
- }
- if ((int) (row * sampleRow) == lastrow)
- {
- sameRow++;
- continue;
- }
-
- hiddenRow = false;
- if (hasHiddenRows)
- {
- seq = alignment.getHiddenSequences().getHiddenSequence(lastrow);
- if (seq == null)
- {
- int index = alignment.getHiddenSequences()
- .findIndexWithoutHiddenSeqs(lastrow);
-
- seq = alignment.getSequenceAt(index);
- }
- else
- {
- hiddenRow = true;
- }
- }
- else
- {
- seq = alignment.getSequenceAt(lastrow);
- }
-
- for (col = 0; col < width; col++)
- {
- if ((int) (col * sampleCol) == lastcol
- && (int) (row * sampleRow) == lastrow)
- {
- sameCol++;
- continue;
- }
-
- lastcol = (int) (col * sampleCol);
-
- if (seq.getLength() > lastcol)
- {
- color = sr.getResidueBoxColour(seq, lastcol);
-
- if (av.isShowSequenceFeatures())
- {
- color = fr.findFeatureColour(color, seq, lastcol);
- }
- }
- else
- {
- color = Color.white; // White
- }
-
- if (hiddenRow
- || (hasHiddenCols && !av.getColumnSelection().isVisible(
- lastcol)))
- {
- color = color.darker().darker();
- }
- mg.setColor(color);
- if (sameCol == 1 && sameRow == 1)
- {
- mg.drawLine(xstart, ystart, xstart, ystart);
- }
- else
- {
- mg.fillRect(xstart, ystart, sameCol, sameRow);
- }
+ int alwidth = av.getAlignment().getWidth();
+ int alheight = av.getAlignment().getAbsoluteHeight();
+ float sampleCol = alwidth / (float) od.getWidth();
+ float sampleRow = alheight / (float) od.getSequencesHeight();
- xstart = col;
- sameCol = 1;
- }
- lastrow = (int) (row * sampleRow);
- ystart = row;
- sameRow = 1;
- }
+ buildImage(sampleRow, sampleCol, mg);
- if (av.getAlignmentConservationAnnotation() != null)
+ // check for conservation annotation to make sure overview works for DNA too
+ if (av.isShowAnnotation()
+ && (av.getAlignmentConservationAnnotation() != null))
{
- for (col = 0; col < width; col++)
+ for (int col = 0; col < od.getWidth() && !resizeAgain; col++)
{
- if (resizeAgain)
- {
- break;
- }
- lastcol = (int) (col * sampleCol);
- {
- mg.translate(col, sequencesHeight);
- ap.annotationPanel.renderer.drawGraph(mg,
- av.getAlignmentConservationAnnotation(),
- av.getAlignmentConservationAnnotation().annotations,
- (int) (sampleCol) + 1, graphHeight,
- (int) (col * sampleCol), (int) (col * sampleCol) + 1);
- mg.translate(-col, -sequencesHeight);
- }
+ mg.translate(col, od.getSequencesHeight());
+ ap.annotationPanel.renderer.drawGraph(mg,
+ av.getAlignmentConservationAnnotation(),
+ av.getAlignmentConservationAnnotation().annotations,
+ (int) (sampleCol) + 1, od.getGraphHeight(),
+ (int) (col * sampleCol), (int) (col * sampleCol) + 1);
+ mg.translate(-col, -od.getSequencesHeight());
}
}
System.gc();
}
}
- public void setBoxPosition()
+ /*
+ * Build the overview panel image
+ */
+ private void buildImage(float sampleRow, float sampleCol, Graphics mg)
{
- int fullsizeWidth = av.getAlignment().getWidth() * av.getCharWidth();
- int fullsizeHeight = (av.getAlignment().getHeight() + av.getAlignment()
- .getHiddenSequences().getSize())
- * av.getCharHeight();
-
- int startRes = av.getStartRes();
- int endRes = av.getEndRes();
+ int lastcol = 0;
+ int lastrow = 0;
+ int xstart = 0;
+ int ystart = 0;
+ Color color = Color.yellow;
+ int sameRow = 0;
+ int sameCol = 0;
- if (av.hasHiddenColumns())
- {
- startRes = av.getColumnSelection().adjustForHiddenColumns(startRes);
- endRes = av.getColumnSelection().adjustForHiddenColumns(endRes);
- }
+ SequenceI seq = null;
+ FeatureColourFinder finder = new FeatureColourFinder(fr);
- int startSeq = av.startSeq;
- int endSeq = av.endSeq;
+ final boolean hasHiddenCols = av.hasHiddenColumns();
+ boolean hiddenRow = false;
- if (av.hasHiddenRows())
+ for (int row = 0; row <= od.getSequencesHeight() && !resizeAgain; row++)
{
- startSeq = av.getAlignment().getHiddenSequences()
- .adjustForHiddenSeqs(startSeq);
-
- endSeq = av.getAlignment().getHiddenSequences()
- .adjustForHiddenSeqs(endSeq);
+ if ((int) (row * sampleRow) == lastrow)
+ {
+ sameRow++;
+ }
+ else
+ {
+ // get the sequence which would be at alignment index 'lastrow' if no
+ // columns were hidden, and determine whether it is hidden or not
+ hiddenRow = av.getAlignment().isHidden(lastrow);
+ seq = av.getAlignment().getSequenceAtAbsoluteIndex(lastrow);
+ for (int col = 0; col < od.getWidth(); col++)
+ {
+ if ((int) (col * sampleCol) == lastcol
+ && (int) (row * sampleRow) == lastrow)
+ {
+ sameCol++;
+ }
+ else
+ {
+ lastcol = (int) (col * sampleCol);
+
+ color = getColumnColourFromSequence(seq, hiddenRow,
+ hasHiddenCols, lastcol, finder);
+
+ mg.setColor(color);
+ if (sameCol == 1 && sameRow == 1)
+ {
+ mg.drawLine(xstart, ystart, xstart, ystart);
+ }
+ else
+ {
+ mg.fillRect(xstart, ystart, sameCol, sameRow);
+ }
+
+ xstart = col;
+ sameCol = 1;
+ }
+ }
+ lastrow = (int) (row * sampleRow);
+ ystart = row;
+ sameRow = 1;
+ }
}
+ }
- scalew = (float) width / (float) fullsizeWidth;
- scaleh = (float) sequencesHeight / (float) fullsizeHeight;
-
- boxX = (int) (startRes * av.getCharWidth() * scalew);
- boxY = (int) (startSeq * av.getCharHeight() * scaleh);
-
- if (av.hasHiddenColumns())
+ /*
+ * Find the colour of a sequence at a specified column position
+ */
+ private Color getColumnColourFromSequence(
+ jalview.datamodel.SequenceI seq, boolean hiddenRow,
+ boolean hasHiddenCols, int lastcol, FeatureColourFinder finder)
+ {
+ Color color = Color.white;
+ if (seq.getLength() > lastcol)
{
- boxWidth = (int) ((endRes - startRes + 1) * av.getCharWidth() * scalew);
+ color = sr.getResidueColour(seq, lastcol, finder);
}
- else
+
+ if (hiddenRow
+ || (hasHiddenCols && !av.getColumnSelection()
+ .isVisible(lastcol)))
{
- boxWidth = (int) ((endRes - startRes + 1) * av.getCharWidth() * scalew);
+ color = color.darker().darker();
}
+ return color;
+ }
- boxHeight = (int) ((endSeq - startSeq) * av.getCharHeight() * scaleh);
-
+ /**
+ * Update the overview panel box when the associated alignment panel is
+ * changed
+ *
+ */
+ public void setBoxPosition()
+ {
+ od.setBoxPosition(av.getAlignment()
+ .getHiddenSequences(), av.getColumnSelection(), av.getRanges());
repaint();
}
{
og.drawImage(miniMe, 0, 0, this);
og.setColor(Color.red);
- og.drawRect(boxX, boxY, boxWidth, boxHeight);
- og.drawRect(boxX + 1, boxY + 1, boxWidth - 2, boxHeight - 2);
+ od.drawBox(og);
g.drawImage(offscreen, 0, 0, this);
}
}
@Override
public void mousePressed(MouseEvent evt)
{
- int x = (evt.getX() / av.getCharWidth()) + av.getStartRes();
+ int x = (evt.getX() / av.getCharWidth()) + av.getRanges().getStartRes();
final int res;
if (av.hasHiddenColumns())
{
mouseDragging = false;
- int res = (evt.getX() / av.getCharWidth()) + av.getStartRes();
+ int res = (evt.getX() / av.getCharWidth())
+ + av.getRanges().getStartRes();
if (res > av.getAlignment().getWidth())
{
mouseDragging = true;
ColumnSelection cs = av.getColumnSelection();
- int res = (evt.getX() / av.getCharWidth()) + av.getStartRes();
+ int res = (evt.getX() / av.getCharWidth())
+ + av.getRanges().getStartRes();
res = Math.max(0, res);
res = cs.adjustForHiddenColumns(res);
res = Math.min(res, av.getAlignment().getWidth() - 1);
return;
}
- int res = (evt.getX() / av.getCharWidth()) + av.getStartRes();
+ int res = (evt.getX() / av.getCharWidth())
+ + av.getRanges().getStartRes();
res = av.getColumnSelection().adjustForHiddenColumns(res);
@Override
public void paint(Graphics g)
{
- drawScale(g, av.getStartRes(), av.getEndRes(), getSize().width,
+ drawScale(g, av.getRanges().getStartRes(), av.getRanges().getEndRes(),
+ getSize().width,
getSize().height);
}
import jalview.renderer.ScaleRenderer;
import jalview.renderer.ScaleRenderer.ScaleMark;
import jalview.viewmodel.AlignmentViewport;
+import jalview.viewmodel.ViewportRanges;
import java.awt.Color;
import java.awt.FontMetrics;
return;
}
+ ViewportRanges ranges = av.getRanges();
+
updateViewport();
// Its possible on certain browsers that the call to fastpaint
// is faster than it can paint, so this check here catches
// this possibility
- if (lastsr + horizontal != av.startRes)
+ if (lastsr + horizontal != ranges.getStartRes())
{
- horizontal = av.startRes - lastsr;
+ horizontal = ranges.getStartRes() - lastsr;
}
- lastsr = av.startRes;
+ lastsr = ranges.getStartRes();
fastPaint = true;
gg.copyArea(horizontal * avcharWidth, vertical * avcharHeight, imgWidth
imgHeight - vertical * avcharHeight, -horizontal * avcharWidth,
-vertical * avcharHeight);
- int sr = av.startRes, er = av.endRes, ss = av.startSeq, es = av.endSeq, transX = 0, transY = 0;
+ int sr = ranges.getStartRes(), er = ranges.getEndRes(), ss = ranges
+ .getStartSeq(), es = ranges
+ .getEndSeq(), transX = 0, transY = 0;
if (horizontal > 0) // scrollbar pulled right, image to the left
{
else if (vertical > 0) // scroll down
{
ss = es - vertical;
- if (ss < av.startSeq) // ie scrolling too fast, more than a page at a time
+ if (ss < ranges.getStartSeq()) // ie scrolling too fast, more than a page
+ // at a
+ // time
{
- ss = av.startSeq;
+ ss = ranges.getStartSeq();
}
else
{
- transY = imgHeight - vertical * avcharHeight;
+ transY = imgHeight - ((vertical + 1) * avcharHeight);
}
}
else if (vertical < 0)
{
es = ss - vertical;
- if (es > av.endSeq)
+ if (es > ranges.getEndSeq())
{
- es = av.endSeq;
+ es = ranges.getEndSeq();
}
}
gg.setColor(Color.white);
gg.fillRect(0, 0, imgWidth, imgHeight);
+ ViewportRanges ranges = av.getRanges();
+
if (av.getWrapAlignment())
{
- drawWrappedPanel(gg, imgWidth, imgHeight, av.startRes);
+ drawWrappedPanel(gg, imgWidth, imgHeight, ranges.getStartRes());
}
else
{
- drawPanel(gg, av.startRes, av.endRes, av.startSeq, av.endSeq, 0);
+ drawPanel(gg, ranges.getStartRes(), ranges.getEndRes(),
+ ranges.getStartSeq(), ranges.getEndSeq(), 0);
}
g.drawImage(img, 0, 0, this);
av.setWrappedWidth(cWidth);
- av.endRes = av.startRes + cWidth;
+ av.getRanges().setEndRes(av.getRanges().getStartRes() + cWidth);
int endx;
int ypos = hgap;
// / First draw the sequences
// ///////////////////////////
- for (int i = startSeq; i < endSeq; i++)
+ for (int i = startSeq; i <= endSeq; i++)
{
nextSeq = av.getAlignment().getSequenceAt(i);
if (av.isShowSequenceFeatures())
{
fr.drawSequence(g, nextSeq, startRes, endRes, offset
- + ((i - startSeq) * avcharHeight));
+ + ((i - startSeq) * avcharHeight), false);
}
// / Highlight search Results once all sequences have been drawn
int bottom = -1;
int alHeight = av.getAlignment().getHeight() - 1;
- for (i = startSeq; i < endSeq; i++)
+ for (i = startSeq; i <= endSeq; i++)
{
sx = (group.getStartRes() - startRes) * avcharWidth;
sy = offset + ((i - startSeq) * avcharHeight);
import jalview.util.MappingUtils;
import jalview.util.MessageManager;
import jalview.viewmodel.AlignmentViewport;
+import jalview.viewmodel.ViewportRanges;
import java.awt.BorderLayout;
import java.awt.Font;
}
else
{
- while (seqCanvas.cursorY < av.startSeq)
+ ViewportRanges ranges = av.getRanges();
+ while (seqCanvas.cursorY < ranges.getStartSeq())
{
ap.scrollUp(true);
}
- while (seqCanvas.cursorY + 1 > av.endSeq)
+ while (seqCanvas.cursorY + 1 > ranges.getEndSeq())
{
ap.scrollUp(false);
}
while (seqCanvas.cursorX < av.getColumnSelection()
- .adjustForHiddenColumns(av.startRes))
+ .adjustForHiddenColumns(ranges.getStartRes()))
{
if (!ap.scrollRight(false))
}
}
while (seqCanvas.cursorX > av.getColumnSelection()
- .adjustForHiddenColumns(av.endRes))
+ .adjustForHiddenColumns(ranges.getEndRes()))
{
if (!ap.scrollRight(true))
{
}
wrappedBlock = y / cHeight;
- wrappedBlock += av.getStartRes() / cwidth;
+ wrappedBlock += av.getRanges().getStartRes() / cwidth;
res = wrappedBlock * cwidth + x / av.getCharWidth();
}
else
{
- res = (x / av.getCharWidth()) + av.getStartRes();
+ res = (x / av.getCharWidth()) + av.getRanges().getStartRes();
}
if (av.hasHiddenColumns())
}
else
{
- seq = Math.min((y / av.getCharHeight()) + av.getStartSeq(), av
+ seq = Math.min((y / av.getCharHeight())
+ + av.getRanges().getStartSeq(),
+ av
.getAlignment().getHeight() - 1);
if (seq < 0)
{
stretchGroup = av.getSelectionGroup();
- if (stretchGroup == null)
+ if (stretchGroup == null || !stretchGroup.contains(sequence, res))
{
stretchGroup = av.getAlignment().findGroup(sequence, res);
- av.setSelectionGroup(stretchGroup);
- }
-
- if (stretchGroup == null
- || !stretchGroup.getSequences(null).contains(sequence)
- || stretchGroup.getStartRes() > res
- || stretchGroup.getEndRes() < res)
- {
- stretchGroup = null;
-
- SequenceGroup[] allGroups = av.getAlignment().findAllGroups(sequence);
-
- if (allGroups != null)
+ if (stretchGroup != null)
{
- for (int i = 0; i < allGroups.length; i++)
- {
- if (allGroups[i].getStartRes() <= res
- && allGroups[i].getEndRes() >= res)
- {
- stretchGroup = allGroups[i];
- break;
- }
- }
+ // only update the current selection if the popup menu has a group to
+ // focus on
+ av.setSelectionGroup(stretchGroup);
}
- av.setSelectionGroup(stretchGroup);
}
// DETECT RIGHT MOUSE BUTTON IN AWT
oldSeq = -1;
}
- if (res > av.endRes || res < av.startRes || y < av.startSeq
- || y > av.endSeq)
+ if (res > av.getRanges().getEndRes()
+ || res < av.getRanges().getStartRes()
+ || y < av.getRanges().getStartSeq()
+ || y > av.getRanges().getEndSeq())
{
mouseExited(evt);
}
if (evt != null)
{
- if (mouseDragging && evt.getY() < 0 && av.getStartSeq() > 0)
+ if (mouseDragging && evt.getY() < 0
+ && av.getRanges().getStartSeq() > 0)
{
running = ap.scrollUp(true);
}
if (mouseDragging && evt.getY() >= getSize().height
- && av.getAlignment().getHeight() > av.getEndSeq())
+ && av.getAlignment().getHeight() > av.getRanges()
+ .getEndSeq())
{
running = ap.scrollUp(false);
}
public void scrollTo(int row, int column)
{
- row = row < 0 ? ap.av.startSeq : row;
- column = column < 0 ? ap.av.startRes : column;
+ row = row < 0 ? ap.av.getRanges().getStartSeq() : row;
+ column = column < 0 ? ap.av.getRanges().getStartRes() : column;
ap.scrollTo(column, column, row, true, true);
}
public void scrollToRow(int row)
{
- row = row < 0 ? ap.av.startSeq : row;
- ap.scrollTo(ap.av.startRes, ap.av.startRes, row, true, true);
+ row = row < 0 ? ap.av.getRanges().getStartSeq() : row;
+ ap.scrollTo(ap.av.getRanges().getStartRes(), ap.av.getRanges()
+ .getStartRes(), row, true, true);
}
/**
public void scrollToColumn(int column)
{
- column = column < 0 ? ap.av.startRes : column;
- ap.scrollTo(column, column, ap.av.startSeq, true, true);
+ column = column < 0 ? ap.av.getRanges().getStartRes() : column;
+ ap.scrollTo(column, column, ap.av.getRanges().getStartSeq(), true, true);
}
/**
*/
package jalview.appletgui;
-import jalview.api.FeatureRenderer;
import jalview.datamodel.SequenceGroup;
import jalview.datamodel.SequenceI;
import jalview.renderer.ResidueShaderI;
+import jalview.renderer.seqfeatures.FeatureColourFinder;
import java.awt.Color;
import java.awt.Font;
this.renderGaps = renderGaps;
}
- @Override
- public Color getResidueBoxColour(SequenceI seq, int i)
+ protected Color getResidueBoxColour(SequenceI seq, int i)
{
allGroups = av.getAlignment().findAllGroups(seq);
*
* @param seq
* @param position
- * @param fr
+ * @param finder
* @return
*/
@Override
public Color getResidueColour(final SequenceI seq, int position,
- FeatureRenderer fr)
+ FeatureColourFinder finder)
{
// TODO replace 8 or so code duplications with calls to this method
// (refactored as needed)
Color col = getResidueBoxColour(seq, position);
- if (fr != null)
+ if (finder != null)
{
- col = fr.findFeatureColour(col, seq, position);
+ col = finder.findFeatureColour(col, seq, position);
}
return col;
}
import jalview.datamodel.PDBEntry;
import jalview.gui.UserDefinedColours;
+import jalview.schemes.ColourSchemeLoader;
import jalview.schemes.ColourSchemes;
import jalview.schemes.UserColourScheme;
import jalview.structure.StructureImportSettings;
+import jalview.urls.IdOrgSettings;
import jalview.util.ColorUtils;
import jalview.ws.dbsources.das.api.DasSourceRegistryI;
import jalview.ws.dbsources.das.datamodel.DasSourceRegistry;
* <li>SORT_ALIGNMENT (No sort|Id|Pairwise Identity)</li>
* <li>SEQUENCE_LINKS list of name|URL pairs for opening a url with
* $SEQUENCE_ID$</li>
+ * <li>STORED_LINKS list of name|url pairs which user has entered but are not
+ * currently used
+ * <li>DEFAULT_LINK name of single url to be used when user double clicks a
+ * sequence id (must be in SEQUENCE_LINKS or STORED_LINKS)
* <li>GROUP_LINKS list of name|URL[|<separator>] tuples - see
* jalview.utils.GroupURLLink for more info</li>
* <li>DAS_REGISTRY_URL the registry to query</li>
* <li>STRUCTURE_DISPLAY choose from JMOL (default) or CHIMERA for 3D structure
* display</li>
* <li>CHIMERA_PATH specify full path to Chimera program (if non-standard)</li>
+ * <li>ID_ORG_HOSTURL location of jalview service providing identifiers.org urls
+ * </li>
*
* </ul>
* Deprecated settings:
public static final String DAS_ACTIVE_SOURCE = "DAS_ACTIVE_SOURCE";
+ /**
+ * Sifts settings
+ */
public static final String DEFAULT_SIFTS_DOWNLOAD_DIR = System
.getProperty("user.home")
+ File.separatorChar
private final static String DEFAULT_FAIL_SAFE_PID_THRESHOLD = "30";
/**
+ * Identifiers.org download settings
+ */
+ private static final String ID_ORG_FILE = System.getProperty("user.home")
+ + File.separatorChar + ".identifiers.org.ids.json";
+
+ /**
* Allowed values are PDB or mmCIF
*/
private final static String PDB_DOWNLOAD_FORMAT = PDBEntry.Type.MMCIF
"sifts_cache_threshold_in_days",
DEFAULT_CACHE_THRESHOLD_IN_DAYS));
+ IdOrgSettings.setUrl(getDefault("ID_ORG_HOSTURL",
+ "http://www.jalview.org/services/identifiers"));
+ IdOrgSettings.setDownloadLocation(ID_ORG_FILE);
+
System.out
.println("Jalview Version: " + codeVersion + codeInstallation);
String file = st.nextToken();
try
{
- UserColourScheme ucs = ColourSchemes.loadColourScheme(file);
+ UserColourScheme ucs = ColourSchemeLoader.loadColourScheme(file);
if (ucs != null)
{
if (coloursFound.length() > 0)
return AlignmentUtils.getSequencesByName(this);
}
- /**
- * DOCUMENT ME!
- *
- * @param i
- * DOCUMENT ME!
- *
- * @return DOCUMENT ME!
- */
+
@Override
public SequenceI getSequenceAt(int i)
{
return null;
}
+ @Override
+ public SequenceI getSequenceAtAbsoluteIndex(int i)
+ {
+ SequenceI seq = null;
+ if (getHiddenSequences().getSize() > 0)
+ {
+ seq = getHiddenSequences().getHiddenSequence(i);
+ if (seq == null)
+ {
+ // didn't find the sequence in the hidden sequences, get it from the
+ // alignment
+ int index = getHiddenSequences().findIndexWithoutHiddenSeqs(i);
+ seq = getSequenceAt(index);
+ }
+ }
+ else
+ {
+ seq = getSequenceAt(i);
+ }
+ return seq;
+ }
+
/**
* Adds a sequence to the alignment. Recalculates maxLength and size. Note
* this currently does not recalculate whether or not the alignment is
}
}
- /**
- * DOCUMENT ME!
- *
- * @param s
- * DOCUMENT ME!
- */
@Override
public void deleteSequence(SequenceI s)
{
- deleteSequence(findIndex(s));
+ synchronized (sequences)
+ {
+ deleteSequence(findIndex(s));
+ }
}
- /**
- * DOCUMENT ME!
- *
- * @param i
- * DOCUMENT ME!
- */
@Override
public void deleteSequence(int i)
{
- if (i > -1 && i < getHeight())
+ synchronized (sequences)
{
- synchronized (sequences)
+ if (i > -1 && i < getHeight())
{
sequences.remove(i);
hiddenSequences.adjustHeightSequenceDeleted(i);
}
}
+ @Override
+ public void deleteHiddenSequence(int i)
+ {
+ synchronized (sequences)
+ {
+ if (i > -1 && i < getHeight())
+ {
+ sequences.remove(i);
+ }
+ }
+ }
+
/*
* (non-Javadoc)
*
return -1;
}
- /**
- * DOCUMENT ME!
- *
- * @return DOCUMENT ME!
- */
+
@Override
public int getHeight()
{
return sequences.size();
}
- /**
- * DOCUMENT ME!
- *
- * @return DOCUMENT ME!
- */
+ @Override
+ public int getAbsoluteHeight()
+ {
+ return sequences.size() + getHiddenSequences().getSize();
+ }
+
@Override
public int getWidth()
{
return true;
}
+ @Override
+ public boolean isHidden(int alignmentIndex)
+ {
+ return (getHiddenSequences().getHiddenSequence(alignmentIndex) != null);
+ }
+
/**
* Delete all annotations, including auto-calculated if the flag is set true.
* Returns true if at least one annotation was deleted, else false.
*/
private Map<Integer, Annotation> sequenceMapping;
- /** DOCUMENT ME!! */
+ /**
+ * lower range for quantitative data
+ */
public float graphMin;
- /** DOCUMENT ME!! */
+ /**
+ * Upper range for quantitative data
+ */
public float graphMax;
/**
public interface AlignmentI extends AnnotatedCollectionI
{
/**
- * Calculates the number of sequences in an alignment
+ * Calculates the number of sequences in an alignment, excluding hidden
+ * sequences
*
* @return Number of sequences in alignment
*/
int getHeight();
/**
+ * Calculates the number of sequences in an alignment, including hidden
+ * sequences
+ *
+ * @return Number of sequences in alignment
+ */
+ int getAbsoluteHeight();
+
+ /**
*
* Calculates the maximum width of the alignment, including gaps.
*
boolean isAligned(boolean includeHidden);
/**
+ * Answers if the sequence at alignmentIndex is hidden
+ *
+ * @param alignmentIndex
+ * the index to check
+ * @return true if the sequence is hidden
+ */
+ boolean isHidden(int alignmentIndex);
+
+ /**
* Gets sequences as a Synchronized collection
*
* @return All sequences in alignment.
SequenceI getSequenceAt(int i);
/**
+ * Find a specific sequence in this alignment.
+ *
+ * @param i
+ * Index of required sequence in full alignment, i.e. if all columns
+ * were visible
+ *
+ * @return SequenceI at given index.
+ */
+ SequenceI getSequenceAtAbsoluteIndex(int i);
+
+ /**
* Returns a map of lists of sequences keyed by sequence name.
*
* @return
SequenceI replaceSequenceAt(int i, SequenceI seq);
/**
- * Deletes a sequence from the alignment
+ * Deletes a sequence from the alignment. Updates hidden sequences to account
+ * for the removed sequence. Do NOT use this method to delete sequences which
+ * are just hidden.
*
* @param s
* Sequence to be deleted.
void deleteSequence(SequenceI s);
/**
- * Deletes a sequence from the alignment.
+ * Deletes a sequence from the alignment. Updates hidden sequences to account
+ * for the removed sequence. Do NOT use this method to delete sequences which
+ * are just hidden.
*
* @param i
* Index of sequence to be deleted.
void deleteSequence(int i);
/**
+ * Deletes a sequence in the alignment which has been hidden.
+ *
+ * @param i
+ * Index of sequence to be deleted
+ */
+ void deleteHiddenSequence(int i);
+
+ /**
* Finds sequence in alignment using sequence name as query.
*
* @param name
/**
* Returns the first group (in the order in which groups were added) that
- * includes the given sequence and aligned position (base 0), or null if none
- * found
+ * includes the given sequence instance and aligned position (base 0), or null
+ * if none found
*
* @param seq
+ * - must be contained in the alignment (not a dataset sequence)
* @param position
*
* @return
* @return
*/
public int[] getVisibleStartAndEndIndex(List<int[]> hiddenCols);
+
}
{
int nores = (isNa) ? ResidueProperties.maxNucleotideIndex
: ResidueProperties.maxProteinIndex;
- // Set all matrix to 0
+
dbinary = new double[getSequence().length * nores];
- for (int i = 0; i < dbinary.length; i++)
- {
- dbinary[i] = 0.0;
- }
return nores;
}
private void matrixEncode(final int[] aaIndex, final int[][] matrix)
{
- // Set all matrix to 0
- // dbinary = new double[getSequence().length * 21];
-
int nores = initMatrixGetNoRes();
- // for (int i = 0; i < dbinary.length; i++) {
- // dbinary[i] = 0.0;
- // }
for (int i = 0, iSize = getSequence().length; i < iSize; i++)
{
int aanum = nores - 1;
* left-most visible column will always be returned.
*
* @param hiddenColumn
- * int
- * @return int
+ * the column index in the full alignment including hidden columns
+ * @return the position of the column in the visible alignment
*/
public int findColumnPosition(int hiddenColumn)
{
result -= region[1] + 1 - region[0];
}
} while ((hiddenColumn > region[1]) && (index < hiddenColumns.size()));
- if (hiddenColumn > region[0] && hiddenColumn < region[1])
- {
- return region[0] + hiddenColumn - result;
+
+ if (hiddenColumn >= region[0] && hiddenColumn <= region[1])
+ {
+ // Here the hidden column is within a region, so
+ // we want to return the position of region[0]-1, adjusted for any
+ // earlier hidden columns.
+ // Calculate the difference between the actual hidden col position
+ // and region[0]-1, and then subtract from result to convert result from
+ // the adjusted hiddenColumn value to the adjusted region[0]-1 value
+
+ // However, if the region begins at 0 we cannot return region[0]-1
+ // just return 0
+ if (region[0] == 0)
+ {
+ return 0;
+ }
+ else
+ {
+ return result - (hiddenColumn - region[0] + 1);
+ }
}
}
return result; // return the shifted position after removing hidden columns.
}
/**
+ * Find the visible column which is a given visible number of columns to the
+ * left of another visible column. i.e. for a startColumn x, the column which
+ * is distance 1 away will be column x-1.
+ *
+ * @param visibleDistance
+ * the number of visible columns to offset by
+ * @param startColumn
+ * the column to start from
+ * @return the position of the column in the visible alignment
+ */
+ public int subtractVisibleColumns(int visibleDistance, int startColumn)
+ {
+ int distance = visibleDistance;
+
+ // in case startColumn is in a hidden region, move it to the left
+ int start = adjustForHiddenColumns(findColumnPosition(startColumn));
+
+ // get index of hidden region to left of start
+ int index = getHiddenIndexLeft(start);
+ if (index == -1)
+ {
+ // no hidden regions to left of startColumn
+ return start - distance;
+ }
+
+ // walk backwards through the alignment subtracting the counts of visible
+ // columns from distance
+ int[] region;
+ int gap = 0;
+ int nextstart = start;
+
+ while ((index > -1) && (distance - gap > 0))
+ {
+ // subtract the gap to right of region from distance
+ distance -= gap;
+ start = nextstart;
+
+ // calculate the next gap
+ region = hiddenColumns.get(index);
+ gap = start - region[1];
+
+ // set start to just to left of current region
+ nextstart = region[0] - 1;
+ index--;
+ }
+
+ if (distance - gap > 0)
+ {
+ // fell out of loop because there are no more hidden regions
+ distance -= gap;
+ return nextstart - distance;
+ }
+ return start - distance;
+
+ }
+
+ /**
* Use this method to determine where the next hiddenRegion starts
*
* @param hiddenRegion
}
+ /**
+ * This method returns the index of the hidden region to the left of a column
+ * position. If the column is in a hidden region it returns the index of the
+ * region to the left. If there is no hidden region to the left it returns -1.
+ *
+ * @param pos
+ * int
+ */
+ private int getHiddenIndexLeft(int pos)
+ {
+ if (hiddenColumns != null)
+ {
+ int index = hiddenColumns.size() - 1;
+ do
+ {
+ int[] region = hiddenColumns.elementAt(index);
+ if (pos > region[1])
+ {
+ return index;
+ }
+
+ index--;
+ } while (index > -1);
+ }
+
+ return -1;
+
+ }
+
public void hideSelectedColumns()
{
synchronized (selection)
hiddenSequences = new SequenceI[alignment.getHeight()];
}
- int alignmentIndex = alignment.findIndex(sequence);
- alignmentIndex = adjustForHiddenSeqs(alignmentIndex);
+ int absAlignmentIndex = alignment.findIndex(sequence);
+ int alignmentIndex = adjustForHiddenSeqs(absAlignmentIndex);
if (hiddenSequences[alignmentIndex] != null)
{
hiddenSequences[alignmentIndex] = sequence;
- alignment.deleteSequence(sequence);
+ alignment.deleteHiddenSequence(absAlignmentIndex);
}
public List<SequenceI> showAll(
return hiddenSequences == null ? null : hiddenSequences[alignmentIndex];
}
+ /**
+ * Convert absolute alignment index to visible alignment index
+ *
+ * @param alignmentIndex
+ * @return
+ */
public int findIndexWithoutHiddenSeqs(int alignmentIndex)
{
if (hiddenSequences == null)
}
int index = 0;
int hiddenSeqs = 0;
+ int diff = 0;
if (hiddenSequences.length <= alignmentIndex)
{
+ // if the alignmentIndex runs past the end of hidden sequences
+ // and therefore actually past the end of the alignment
+ // store the difference to add back on at the end, so that behaviour
+ // is consistent with hidden columns behaviour (used by overview panel)
+ diff = alignmentIndex - hiddenSequences.length + 1;
alignmentIndex = hiddenSequences.length - 1;
}
index++;
}
- return (alignmentIndex - hiddenSeqs);
+ return (alignmentIndex - hiddenSeqs + diff);
+ }
+
+ /**
+ * Find the visible row which is a given visible number of rows above another
+ * visible row. i.e. for a startRow x, the row which is distance 1 away will
+ * be row x-1.
+ *
+ * @param visibleDistance
+ * the number of visible rows to offset by
+ * @param startRow
+ * the row to start from
+ * @return the position of the row in the visible alignment
+ */
+ public int subtractVisibleRows(int visibleDistance, int startRow)
+ {
+ // walk upwards through the alignment
+ // count all the non-null sequences until we have visibleDistance counted
+ // then return the next visible sequence
+ if (hiddenSequences == null)
+ {
+ return startRow - visibleDistance;
+ }
+
+ int index = startRow;
+ int count = 0;
+ while ((index > -1) && (count < visibleDistance))
+ {
+ if (hiddenSequences[index] == null)
+ {
+ // count visible sequences
+ count++;
+ }
+ index--;
+ }
+ return index;
}
+ /**
+ * Convert alignment index from visible alignment to absolute alignment
+ *
+ * @param alignmentIndex
+ * @return
+ */
public int adjustForHiddenSeqs(int alignmentIndex)
{
if (hiddenSequences == null)
}
@Override
- public synchronized void addSequenceFeature(SequenceFeature sf)
+ public synchronized boolean addSequenceFeature(SequenceFeature sf)
{
if (sequenceFeatures == null && datasetSequence != null)
{
- datasetSequence.addSequenceFeature(sf);
- return;
+ return datasetSequence.addSequenceFeature(sf);
}
if (sequenceFeatures == null)
{
{
if (sequenceFeatures[i].equals(sf))
{
- return;
+ return false;
}
}
temp[sequenceFeatures.length] = sf;
sequenceFeatures = temp;
+ return true;
}
@Override
}
return false;
}
+
+ /**
+ * @param seq
+ * @return true if seq is a member of the group
+ */
+
+ public boolean contains(SequenceI seq1)
+ {
+ return sequences.contains(seq1);
+ }
+
+ /**
+ * @param seq
+ * @param apos
+ * @return true if startRes<=apos and endRes>=apos and seq is in the group
+ */
+ public boolean contains(SequenceI seq, int apos)
+ {
+ return (startRes <= apos && endRes >= apos) && sequences.contains(seq);
+ }
}
*/
public void addDBRef(DBRefEntry entry);
- public void addSequenceFeature(SequenceFeature sf);
+ /**
+ * Adds the given sequence feature and returns true, or returns false if it is
+ * already present on the sequence
+ *
+ * @param sf
+ * @return
+ */
+ public boolean addSequenceFeature(SequenceFeature sf);
public void deleteFeature(SequenceFeature sf);
/*
* Copied to Jalview September 2016.
* Only the members of this class required for SparseIntArray were copied.
- * Method binarySearch(short[] array, int size, short value) added to support
+ * Change Log:
+ * Sep 2016: Method binarySearch(short[] array, int size, short value) added to support
* SparseShortArray.
+ * Jan 2017: EMPTY_DOUBLES added
*/
class ContainerHelpers
{
static final int[] EMPTY_INTS = new int[0];
+ static final double[] EMPTY_DOUBLES = new double[0];
+
static final long[] EMPTY_LONGS = new long[0];
static final Object[] EMPTY_OBJECTS = new Object[0];
--- /dev/null
+package jalview.ext.android;
+
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * SparseDoubleArray map integers to doubles. Unlike a normal array of integers,
+ * there can be gaps in the indices. It is intended to be more memory efficient
+ * than using a HashMap to map Integer to Double, both because it avoids
+ * auto-boxing keys and values and its data structure doesn't rely on an extra
+ * entry object for each mapping.
+ *
+ * <p>
+ * Note that this container keeps its mappings in an array data structure, using
+ * a binary search to find keys. The implementation is not intended to be
+ * appropriate for data structures that may contain large numbers of items. It
+ * is generally slower than a traditional HashMap, since lookups require a
+ * binary search and adds and removes require inserting and deleting entries in
+ * the array. For containers holding up to hundreds of items, the performance
+ * difference is not significant, less than 50%.
+ * </p>
+ *
+ * <p>
+ * It is possible to iterate over the items in this container using
+ * {@link #keyAt(int)} and {@link #valueAt(int)}. Iterating over the keys using
+ * <code>keyAt(int)</code> with ascending values of the index will return the
+ * keys in ascending order, or the values corresponding to the keys in ascending
+ * order in the case of <code>valueAt(int)<code>.
+ * </p>
+ */
+
+/*
+ * Change log:
+ * Jan 2017 cloned from SparseIntArray for Jalview to support SparseMatrix
+ * - SparseDoubleArray(double[]) constructor added
+ * - multiply() added for more efficient multiply (or divide) of a value
+ */
+public class SparseDoubleArray implements Cloneable
+{
+ private int[] mKeys;
+
+ private double[] mValues;
+
+ private int mSize;
+
+ /**
+ * Creates a new SparseDoubleArray containing no mappings.
+ */
+ public SparseDoubleArray()
+ {
+ this(10);
+ }
+
+ /**
+ * Creates a new SparseDoubleArray containing no mappings that will not
+ * require any additional memory allocation to store the specified number of
+ * mappings. If you supply an initial capacity of 0, the sparse array will be
+ * initialized with a light-weight representation not requiring any additional
+ * array allocations.
+ */
+ public SparseDoubleArray(int initialCapacity)
+ {
+ if (initialCapacity == 0)
+ {
+ mKeys = ContainerHelpers.EMPTY_INTS;
+ mValues = ContainerHelpers.EMPTY_DOUBLES;
+ }
+ else
+ {
+ initialCapacity = idealDoubleArraySize(initialCapacity);
+ mKeys = new int[initialCapacity];
+ mValues = new double[initialCapacity];
+ }
+ mSize = 0;
+ }
+
+ /**
+ * Constructor given an array of double values; stores the non-zero values
+ *
+ * @param row
+ */
+ public SparseDoubleArray(double[] row)
+ {
+ this();
+ for (int i = 0; i < row.length; i++)
+ {
+ if (row[i] != 0d)
+ {
+ put(i, row[i]);
+ }
+ }
+ }
+
+ @Override
+ public SparseDoubleArray clone()
+ {
+ SparseDoubleArray clone = null;
+ try
+ {
+ clone = (SparseDoubleArray) super.clone();
+ clone.mKeys = mKeys.clone();
+ clone.mValues = mValues.clone();
+ } catch (CloneNotSupportedException cnse)
+ {
+ /* ignore */
+ }
+ return clone;
+ }
+
+ /**
+ * Gets the value mapped from the specified key, or <code>0</code> if no such
+ * mapping has been made.
+ */
+ public double get(int key)
+ {
+ return get(key, 0d);
+ }
+
+ /**
+ * Gets the int mapped from the specified key, or the specified value if no
+ * such mapping has been made.
+ */
+ public double get(int key, double valueIfKeyNotFound)
+ {
+ int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
+ if (i < 0)
+ {
+ return valueIfKeyNotFound;
+ }
+ else
+ {
+ return mValues[i];
+ }
+ }
+
+ /**
+ * Removes the mapping from the specified key, if there was any.
+ */
+ public void delete(int key)
+ {
+ int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
+ if (i >= 0)
+ {
+ removeAt(i);
+ }
+ }
+
+ /**
+ * Removes the mapping at the given index.
+ */
+ public void removeAt(int index)
+ {
+ System.arraycopy(mKeys, index + 1, mKeys, index, mSize - (index + 1));
+ System.arraycopy(mValues, index + 1, mValues, index, mSize
+ - (index + 1));
+ mSize--;
+ }
+
+ /**
+ * Adds a mapping from the specified key to the specified value, replacing the
+ * previous mapping from the specified key if there was one.
+ */
+ public void put(int key, double value)
+ {
+ int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
+ if (i >= 0)
+ {
+ mValues[i] = value;
+ }
+ else
+ {
+ i = ~i;
+ if (mSize >= mKeys.length)
+ {
+ int n = idealDoubleArraySize(mSize + 1);
+ int[] nkeys = new int[n];
+ double[] nvalues = new double[n];
+ // Log.e("SparseDoubleArray", "grow " + mKeys.length + " to " + n);
+ System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
+ System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
+ mKeys = nkeys;
+ mValues = nvalues;
+ }
+ if (mSize - i != 0)
+ {
+ // Log.e("SparseDoubleArray", "move " + (mSize - i));
+ System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i);
+ System.arraycopy(mValues, i, mValues, i + 1, mSize - i);
+ }
+ mKeys[i] = key;
+ mValues[i] = value;
+ mSize++;
+ }
+ }
+
+ /**
+ * Returns the number of key-value mappings that this SparseDoubleArray
+ * currently stores.
+ */
+ public int size()
+ {
+ return mSize;
+ }
+
+ /**
+ * Given an index in the range <code>0...size()-1</code>, returns the key from
+ * the <code>index</code>th key-value mapping that this SparseDoubleArray
+ * stores.
+ *
+ * <p>
+ * The keys corresponding to indices in ascending order are guaranteed to be
+ * in ascending order, e.g., <code>keyAt(0)</code> will return the smallest
+ * key and <code>keyAt(size()-1)</code> will return the largest key.
+ * </p>
+ */
+ public int keyAt(int index)
+ {
+ return mKeys[index];
+ }
+
+ /**
+ * Given an index in the range <code>0...size()-1</code>, returns the value
+ * from the <code>index</code>th key-value mapping that this SparseDoubleArray
+ * stores.
+ *
+ * <p>
+ * The values corresponding to indices in ascending order are guaranteed to be
+ * associated with keys in ascending order, e.g., <code>valueAt(0)</code> will
+ * return the value associated with the smallest key and
+ * <code>valueAt(size()-1)</code> will return the value associated with the
+ * largest key.
+ * </p>
+ */
+ public double valueAt(int index)
+ {
+ return mValues[index];
+ }
+
+ /**
+ * Returns the index for which {@link #keyAt} would return the specified key,
+ * or a negative number if the specified key is not mapped.
+ */
+ public int indexOfKey(int key)
+ {
+ return ContainerHelpers.binarySearch(mKeys, mSize, key);
+ }
+
+ /**
+ * Returns an index for which {@link #valueAt} would return the specified key,
+ * or a negative number if no keys map to the specified value. Beware that
+ * this is a linear search, unlike lookups by key, and that multiple keys can
+ * map to the same value and this will find only one of them.
+ */
+ public int indexOfValue(double value)
+ {
+ for (int i = 0; i < mSize; i++)
+ {
+ if (mValues[i] == value)
+ {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Removes all key-value mappings from this SparseDoubleArray.
+ */
+ public void clear()
+ {
+ mSize = 0;
+ }
+
+ /**
+ * Puts a key/value pair into the array, optimizing for the case where the key
+ * is greater than all existing keys in the array.
+ */
+ public void append(int key, double value)
+ {
+ if (mSize != 0 && key <= mKeys[mSize - 1])
+ {
+ put(key, value);
+ return;
+ }
+ int pos = mSize;
+ if (pos >= mKeys.length)
+ {
+ int n = idealDoubleArraySize(pos + 1);
+ int[] nkeys = new int[n];
+ double[] nvalues = new double[n];
+ // Log.e("SparseDoubleArray", "grow " + mKeys.length + " to " + n);
+ System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
+ System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
+ mKeys = nkeys;
+ mValues = nvalues;
+ }
+ mKeys[pos] = key;
+ mValues[pos] = value;
+ mSize = pos + 1;
+ }
+
+ /**
+ * Created by analogy with
+ * com.android.internal.util.ArrayUtils#idealLongArraySize
+ *
+ * @param i
+ * @return
+ */
+ public static int idealDoubleArraySize(int need)
+ {
+ return idealByteArraySize(need * 8) / 8;
+ }
+
+ /**
+ * Inlined here by copying from com.android.internal.util.ArrayUtils
+ *
+ * @param i
+ * @return
+ */
+ public static int idealByteArraySize(int need)
+ {
+ for (int i = 4; i < 32; i++)
+ {
+ if (need <= (1 << i) - 12)
+ {
+ return (1 << i) - 12;
+ }
+ }
+
+ return need;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>
+ * This implementation composes a string by iterating over its mappings.
+ */
+ @Override
+ public String toString()
+ {
+ if (size() <= 0)
+ {
+ return "{}";
+ }
+ StringBuilder buffer = new StringBuilder(mSize * 28);
+ buffer.append('{');
+ for (int i = 0; i < mSize; i++)
+ {
+ if (i > 0)
+ {
+ buffer.append(", ");
+ }
+ int key = keyAt(i);
+ buffer.append(key);
+ buffer.append('=');
+ double value = valueAt(i);
+ buffer.append(value);
+ }
+ buffer.append('}');
+ return buffer.toString();
+ }
+
+ /**
+ * Method (copied from put) added for Jalview to efficiently increment a key's
+ * value if present, else add it with the given value. This avoids a double
+ * binary search (once to get the value, again to put the updated value).
+ *
+ * @param key
+ * @oparam toAdd
+ * @return the new value for the key
+ */
+ public double add(int key, double toAdd)
+ {
+ double newValue = toAdd;
+ int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
+ if (i >= 0)
+ {
+ mValues[i] += toAdd;
+ newValue = mValues[i];
+ }
+ else
+ {
+ i = ~i;
+ if (mSize >= mKeys.length)
+ {
+ int n = idealDoubleArraySize(mSize + 1);
+ int[] nkeys = new int[n];
+ double[] nvalues = new double[n];
+ System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
+ System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
+ mKeys = nkeys;
+ mValues = nvalues;
+ }
+ if (mSize - i != 0)
+ {
+ System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i);
+ System.arraycopy(mValues, i, mValues, i + 1, mSize - i);
+ }
+ mKeys[i] = key;
+ mValues[i] = toAdd;
+ mSize++;
+ }
+ return newValue;
+ }
+
+ /**
+ * Method added for Jalview to efficiently multiply a key's value if present,
+ * else do nothing. This avoids a double binary search (once to get the value,
+ * again to put the updated value).
+ *
+ * @param key
+ * @oparam toAdd
+ * @return the new value for the key
+ */
+ public double divide(int key, double divisor)
+ {
+ double newValue = 0d;
+ if (divisor == 0d)
+ {
+ return newValue;
+ }
+ int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
+ if (i >= 0)
+ {
+ mValues[i] /= divisor;
+ newValue = mValues[i];
+ }
+ return newValue;
+ }
+}
import jalview.util.Comparison;
import jalview.util.DBRefUtils;
import jalview.util.MapList;
+import jalview.util.RangeComparator;
import java.io.IOException;
import java.net.MalformedURLException;
}
/**
- * A comparator to sort ranges into ascending start position order
- */
- private class RangeSorter implements Comparator<int[]>
- {
- boolean forwards;
-
- RangeSorter(boolean forward)
- {
- forwards = forward;
- }
-
- @Override
- public int compare(int[] o1, int[] o2)
- {
- return (forwards ? 1 : -1) * Integer.compare(o1[0], o2[0]);
- }
-
- }
-
- /**
* Default constructor (to use rest.ensembl.org)
*/
public EnsemblSeqProxy()
* a final sort is needed since Ensembl returns CDS sorted within source
* (havana / ensembl_havana)
*/
- Collections.sort(regions, new RangeSorter(direction == 1));
+ Collections.sort(regions, new RangeComparator(direction == 1));
List<int[]> to = Arrays.asList(new int[] { start,
start + mappedLength - 1 });
*/
package jalview.ext.jmol;
+import jalview.api.AlignmentViewPanel;
import jalview.api.FeatureRenderer;
import jalview.api.SequenceRenderer;
import jalview.datamodel.AlignmentI;
import jalview.structure.StructureMappingcommandSet;
import jalview.structure.StructureSelectionManager;
import jalview.structures.models.AAStructureBindingModel;
+import jalview.util.MessageManager;
import java.awt.Color;
import java.awt.Container;
import java.net.URL;
import java.security.AccessControlException;
import java.util.ArrayList;
+import java.util.BitSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
}
/**
- * Construct and send a command to align structures against a reference
- * structure, based on one or more sequence alignments
- *
- * @param _alignment
- * an array of alignments to process
- * @param _refStructure
- * an array of corresponding reference structures (index into pdb
- * file array); if a negative value is passed, the first PDB file
- * mapped to an alignment sequence is used as the reference for
- * superposition
- * @param _hiddenCols
- * an array of corresponding hidden columns for each alignment
+ * {@inheritDoc}
*/
@Override
- public void superposeStructures(AlignmentI[] _alignment,
+ public String superposeStructures(AlignmentI[] _alignment,
int[] _refStructure, ColumnSelection[] _hiddenCols)
{
while (viewer.isScriptExecuting())
String[] files = getPdbFile();
if (!waitForFileLoad(files))
{
- return;
+ return null;
}
StringBuilder selectioncom = new StringBuilder(256);
nSeconds = " " + (2.0 / files.length) + " ";
// if (nSeconds).substring(0,5)+" ";
}
+
// see JAL-1345 - should really automatically turn off the animation for
// large numbers of structures, but Jmol doesn't seem to allow that.
// nSeconds = " ";
}
/*
- * 'matched' array will hold 'true' for visible alignment columns where
+ * 'matched' bit j will be set for visible alignment columns j where
* all sequences have a residue with a mapping to the PDB structure
*/
- // TODO could use a BitSet for matched
- boolean matched[] = new boolean[alignment.getWidth()];
- for (int m = 0; m < matched.length; m++)
+ BitSet matched = new BitSet();
+ for (int m = 0; m < alignment.getWidth(); m++)
{
- matched[m] = (hiddenCols != null) ? hiddenCols.isVisible(m) : true;
+ if (hiddenCols == null || hiddenCols.isVisible(m))
+ {
+ matched.set(m);
+ }
}
SuperposeData[] structures = new SuperposeData[files.length];
}
String[] selcom = new String[files.length];
- int nmatched = 0;
- for (boolean b : matched)
- {
- if (b)
- {
- nmatched++;
- }
- }
+ int nmatched = matched.cardinality();
if (nmatched < 4)
{
- // TODO: bail out here because superposition illdefined?
+ return (MessageManager.formatMessage(
+"label.insufficient_residues",
+ nmatched));
}
/*
boolean run = false;
StringBuilder molsel = new StringBuilder();
molsel.append("{");
- for (int r = 0; r < matched.length; r++)
+
+ int nextColumnMatch = matched.nextSetBit(0);
+ while (nextColumnMatch != -1)
{
- if (matched[r])
+ int pdbResNo = structures[pdbfnum].pdbResNo[nextColumnMatch];
+ if (lpos != pdbResNo - 1)
{
- int pdbResNo = structures[pdbfnum].pdbResNo[r];
- if (lpos != pdbResNo - 1)
+ // discontinuity
+ if (lpos != -1)
{
- // discontinuity
- if (lpos != -1)
- {
- molsel.append(lpos);
- molsel.append(chainCd);
- molsel.append("|");
- }
- run = false;
+ molsel.append(lpos);
+ molsel.append(chainCd);
+ molsel.append("|");
}
- else
+ run = false;
+ }
+ else
+ {
+ // continuous run - and lpos >-1
+ if (!run)
{
- // continuous run - and lpos >-1
- if (!run)
- {
- // at the beginning, so add dash
- molsel.append(lpos);
- molsel.append("-");
- }
- run = true;
+ // at the beginning, so add dash
+ molsel.append(lpos);
+ molsel.append("-");
}
- lpos = pdbResNo;
+ run = true;
}
+ lpos = pdbResNo;
+ nextColumnMatch = matched.nextSetBit(nextColumnMatch + 1);
}
/*
* add final selection phrase
+ selectioncom.toString() + "); cartoons; ");
// evalStateCommand("select *; backbone; select "+selcom.toString()+"; cartoons; center "+selcom.toString());
}
+
+ return null;
}
public void evalStateCommand(String command)
/**
* @param files
* @param sr
- * @param fr
- * @param alignment
+ * @param viewPanel
* @return
*/
@Override
protected StructureMappingcommandSet[] getColourBySequenceCommands(
- String[] files, SequenceRenderer sr, FeatureRenderer fr,
- AlignmentI alignment)
+ String[] files, SequenceRenderer sr, AlignmentViewPanel viewPanel)
{
return JmolCommands.getColourBySequenceCommand(getSsm(), files,
- getSequence(), sr, fr, alignment);
+ getSequence(), sr, viewPanel);
}
/**
*/
package jalview.ext.jmol;
+import jalview.api.AlignViewportI;
+import jalview.api.AlignmentViewPanel;
import jalview.api.FeatureRenderer;
import jalview.api.SequenceRenderer;
import jalview.datamodel.AlignmentI;
+import jalview.datamodel.ColumnSelection;
import jalview.datamodel.SequenceI;
+import jalview.renderer.seqfeatures.FeatureColourFinder;
import jalview.structure.StructureMapping;
import jalview.structure.StructureMappingcommandSet;
import jalview.structure.StructureSelectionManager;
import java.awt.Color;
import java.util.ArrayList;
+import java.util.List;
/**
* Routines for generating Jmol commands for Jalview/Jmol binding another
*/
public static StructureMappingcommandSet[] getColourBySequenceCommand(
StructureSelectionManager ssm, String[] files,
- SequenceI[][] sequence, SequenceRenderer sr, FeatureRenderer fr,
- AlignmentI alignment)
+ SequenceI[][] sequence, SequenceRenderer sr,
+ AlignmentViewPanel viewPanel)
{
-
- ArrayList<StructureMappingcommandSet> cset = new ArrayList<StructureMappingcommandSet>();
+ FeatureRenderer fr = viewPanel.getFeatureRenderer();
+ FeatureColourFinder finder = new FeatureColourFinder(fr);
+ AlignViewportI viewport = viewPanel.getAlignViewport();
+ ColumnSelection cs = viewport.getColumnSelection();
+ AlignmentI al = viewport.getAlignment();
+ List<StructureMappingcommandSet> cset = new ArrayList<StructureMappingcommandSet>();
for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
{
for (int sp, m = 0; m < mapping.length; m++)
{
if (mapping[m].getSequence() == sequence[pdbfnum][s]
- && (sp = alignment.findIndex(sequence[pdbfnum][s])) > -1)
+ && (sp = al.findIndex(sequence[pdbfnum][s])) > -1)
{
- SequenceI asp = alignment.getSequenceAt(sp);
+ SequenceI asp = al.getSequenceAt(sp);
for (int r = 0; r < asp.getLength(); r++)
{
// no mapping to gaps in sequence
lastPos = pos;
- Color col = sr.getResidueBoxColour(sequence[pdbfnum][s], r);
+ Color col = sr.getResidueColour(sequence[pdbfnum][s], r,
+ finder);
- if (fr != null)
+ /*
+ * shade hidden regions darker
+ */
+ if (!cs.isVisible(r))
{
- col = fr.findFeatureColour(col, sequence[pdbfnum][s], r);
+ // col = ColorUtils.darkerThan(col);
+ col = Color.GRAY;
}
+
String newSelcom = (mapping[m].getChain() != " " ? ":"
+ mapping[m].getChain() : "")
+ "/"
--- /dev/null
+package jalview.ext.rbvi.chimera;
+
+import jalview.util.RangeComparator;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * A class to model a Chimera atomspec pattern, for example
+ *
+ * <pre>
+ * #0:15.A,28.A,54.A,63.A,70-72.A,83-84.A,97-98.A|#1:2.A,6.A,11.A,13-14.A,70.A,82.A,96-97.A
+ * </pre>
+ *
+ * where
+ * <ul>
+ * <li>#0 is a model number</li>
+ * <li>15 or 70-72 is a residue number, or range of residue numbers</li>
+ * <li>.A is a chain identifier</li>
+ * <li>residue ranges are separated by comma</li>
+ * <li>atomspecs for distinct models are separated by | (or)</li>
+ * </ul>
+ *
+ * <pre>
+ * @see http://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/midas/frameatom_spec.html
+ * </pre>
+ */
+public class AtomSpecModel
+{
+ private Map<Integer, Map<String, List<int[]>>> atomSpec;
+
+ /**
+ * Constructor
+ */
+ public AtomSpecModel()
+ {
+ atomSpec = new TreeMap<Integer, Map<String, List<int[]>>>();
+ }
+
+ /**
+ * Adds one contiguous range to this atom spec
+ *
+ * @param model
+ * @param startPos
+ * @param endPos
+ * @param chain
+ */
+ public void addRange(int model, int startPos, int endPos, String chain)
+ {
+ /*
+ * Get/initialize map of data for the colour and model
+ */
+ Map<String, List<int[]>> modelData = atomSpec.get(model);
+ if (modelData == null)
+ {
+ atomSpec.put(model, modelData = new TreeMap<String, List<int[]>>());
+ }
+
+ /*
+ * Get/initialize map of data for colour, model and chain
+ */
+ List<int[]> chainData = modelData.get(chain);
+ if (chainData == null)
+ {
+ chainData = new ArrayList<int[]>();
+ modelData.put(chain, chainData);
+ }
+
+ /*
+ * Add the start/end positions
+ */
+ chainData.add(new int[] { startPos, endPos });
+ // TODO add intelligently, using a RangeList class
+ }
+
+ /**
+ * Returns the range(s) formatted as a Chimera atomspec
+ *
+ * @return
+ */
+ public String getAtomSpec()
+ {
+ StringBuilder sb = new StringBuilder(128);
+ boolean firstModel = true;
+ for (Integer model : atomSpec.keySet())
+ {
+ if (!firstModel)
+ {
+ sb.append("|");
+ }
+ firstModel = false;
+ sb.append("#").append(model).append(":");
+
+ boolean firstPositionForModel = true;
+ final Map<String, List<int[]>> modelData = atomSpec.get(model);
+
+ for (String chain : modelData.keySet())
+ {
+ chain = chain.trim();
+
+ List<int[]> rangeList = modelData.get(chain);
+
+ /*
+ * sort ranges into ascending start position order
+ */
+ Collections.sort(rangeList, new RangeComparator(true));
+
+ int start = rangeList.isEmpty() ? 0 : rangeList.get(0)[0];
+ int end = rangeList.isEmpty() ? 0 : rangeList.get(0)[1];
+
+ Iterator<int[]> iterator = rangeList.iterator();
+ while (iterator.hasNext())
+ {
+ int[] range = iterator.next();
+ if (range[0] <= end + 1)
+ {
+ /*
+ * range overlaps or is contiguous with the last one
+ * - so just extend the end position, and carry on
+ * (unless this is the last in the list)
+ */
+ end = Math.max(end, range[1]);
+ }
+ else
+ {
+ /*
+ * we have a break so append the last range
+ */
+ appendRange(sb, start, end, chain, firstPositionForModel);
+ firstPositionForModel = false;
+ start = range[0];
+ end = range[1];
+ }
+ }
+
+ /*
+ * and append the last range
+ */
+ if (!rangeList.isEmpty())
+ {
+ appendRange(sb, start, end, chain, firstPositionForModel);
+ firstPositionForModel = false;
+ }
+ }
+ }
+ return sb.toString();
+ }
+
+ /**
+ * @param sb
+ * @param start
+ * @param end
+ * @param chain
+ * @param firstPositionForModel
+ */
+ protected void appendRange(StringBuilder sb, int start, int end,
+ String chain, boolean firstPositionForModel)
+ {
+ if (!firstPositionForModel)
+ {
+ sb.append(",");
+ }
+ if (end == start)
+ {
+ sb.append(start);
+ }
+ else
+ {
+ sb.append(start).append("-").append(end);
+ }
+ if (chain.length() > 0)
+ {
+ sb.append(".").append(chain);
+ }
+ }
+}
*/
package jalview.ext.rbvi.chimera;
+import jalview.api.AlignViewportI;
+import jalview.api.AlignmentViewPanel;
import jalview.api.FeatureRenderer;
import jalview.api.SequenceRenderer;
import jalview.datamodel.AlignmentI;
+import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.SequenceFeature;
import jalview.datamodel.SequenceI;
+import jalview.renderer.seqfeatures.FeatureColourFinder;
import jalview.structure.StructureMapping;
import jalview.structure.StructureMappingcommandSet;
import jalview.structure.StructureSelectionManager;
import java.awt.Color;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
-import java.util.SortedMap;
-import java.util.TreeMap;
/**
* Routines for generating Chimera commands for Jalview/Chimera binding
public class ChimeraCommands
{
+ public static final String NAMESPACE_PREFIX = "jv_";
+
/**
- * utility to construct the commands to colour chains by the given alignment
- * for passing to Chimera
- *
- * @returns Object[] { Object[] { <model being coloured>,
+ * Constructs Chimera commands to colour residues as per the Jalview alignment
*
+ * @param ssm
+ * @param files
+ * @param sequence
+ * @param sr
+ * @param fr
+ * @param viewPanel
+ * @return
*/
public static StructureMappingcommandSet[] getColourBySequenceCommand(
StructureSelectionManager ssm, String[] files,
- SequenceI[][] sequence, SequenceRenderer sr, FeatureRenderer fr,
- AlignmentI alignment)
+ SequenceI[][] sequence, SequenceRenderer sr,
+ AlignmentViewPanel viewPanel)
{
- Map<Color, SortedMap<Integer, Map<String, List<int[]>>>> colourMap = buildColoursMap(
- ssm, files, sequence, sr, fr, alignment);
+ Map<Object, AtomSpecModel> colourMap = buildColoursMap(ssm, files,
+ sequence, sr, viewPanel);
List<String> colourCommands = buildColourCommands(colourMap);
StructureMappingcommandSet cs = new StructureMappingcommandSet(
ChimeraCommands.class, null,
- colourCommands.toArray(new String[0]));
+ colourCommands.toArray(new String[colourCommands.size()]));
return new StructureMappingcommandSet[] { cs };
}
* 'color' commands (one per distinct colour used). The format of each command
* is
*
- * <blockquote> color colorname #modelnumber:range.chain e.g. color #00ff00
- * #0:2.B,4.B,9-12.B|#1:1.A,2-6.A,...
- *
- * @see http
- * ://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/midas/frameatom_spec
- * .html </pre>
+ * <pre>
+ * <blockquote>
+ * color colorname #modelnumber:range.chain
+ * e.g. color #00ff00 #0:2.B,4.B,9-12.B|#1:1.A,2-6.A,...
+ * </blockquote>
+ * </pre>
*
* @param colourMap
* @return
*/
protected static List<String> buildColourCommands(
- Map<Color, SortedMap<Integer, Map<String, List<int[]>>>> colourMap)
+ Map<Object, AtomSpecModel> colourMap)
{
/*
* This version concatenates all commands into a single String (semi-colon
List<String> commands = new ArrayList<String>();
StringBuilder sb = new StringBuilder(256);
boolean firstColour = true;
- for (Color colour : colourMap.keySet())
+ for (Object key : colourMap.keySet())
{
+ Color colour = (Color) key;
String colourCode = ColorUtils.toTkCode(colour);
if (!firstColour)
{
}
sb.append("color ").append(colourCode).append(" ");
firstColour = false;
- boolean firstModelForColour = true;
- final Map<Integer, Map<String, List<int[]>>> colourData = colourMap
- .get(colour);
- for (Integer model : colourData.keySet())
+ final AtomSpecModel colourData = colourMap.get(colour);
+ sb.append(colourData.getAtomSpec());
+ }
+ commands.add(sb.toString());
+ return commands;
+ }
+
+ /**
+ * Traverses a map of { modelNumber, {chain, {list of from-to ranges} } } and
+ * builds a Chimera format atom spec
+ *
+ * @param modelAndChainRanges
+ */
+ protected static String getAtomSpec(
+ Map<Integer, Map<String, List<int[]>>> modelAndChainRanges)
+ {
+ StringBuilder sb = new StringBuilder(128);
+ boolean firstModelForColour = true;
+ for (Integer model : modelAndChainRanges.keySet())
+ {
+ boolean firstPositionForModel = true;
+ if (!firstModelForColour)
{
- boolean firstPositionForModel = true;
- if (!firstModelForColour)
- {
- sb.append("|");
- }
- firstModelForColour = false;
- sb.append("#").append(model).append(":");
+ sb.append("|");
+ }
+ firstModelForColour = false;
+ sb.append("#").append(model).append(":");
- final Map<String, List<int[]>> modelData = colourData.get(model);
- for (String chain : modelData.keySet())
+ final Map<String, List<int[]>> modelData = modelAndChainRanges
+ .get(model);
+ for (String chain : modelData.keySet())
+ {
+ boolean hasChain = !"".equals(chain.trim());
+ for (int[] range : modelData.get(chain))
{
- boolean hasChain = !"".equals(chain.trim());
- for (int[] range : modelData.get(chain))
+ if (!firstPositionForModel)
{
- if (!firstPositionForModel)
- {
- sb.append(",");
- }
- if (range[0] == range[1])
- {
- sb.append(range[0]);
- }
- else
- {
- sb.append(range[0]).append("-").append(range[1]);
- }
- if (hasChain)
- {
- sb.append(".").append(chain);
- }
- firstPositionForModel = false;
+ sb.append(",");
}
+ if (range[0] == range[1])
+ {
+ sb.append(range[0]);
+ }
+ else
+ {
+ sb.append(range[0]).append("-").append(range[1]);
+ }
+ if (hasChain)
+ {
+ sb.append(".").append(chain);
+ }
+ firstPositionForModel = false;
}
}
}
- commands.add(sb.toString());
- return commands;
+ return sb.toString();
}
/**
* <pre>
- * Build a data structure which maps contiguous subsequences for each colour.
- * This generates a data structure from which we can easily generate the
- * Chimera command for colour by sequence.
+ * Build a data structure which records contiguous subsequences for each colour.
+ * From this we can easily generate the Chimera command for colour by sequence.
* Color
* Model number
* Chain
* Ordering is by order of addition (for colours and positions), natural ordering (for models and chains)
* </pre>
*/
- protected static Map<Color, SortedMap<Integer, Map<String, List<int[]>>>> buildColoursMap(
+ protected static Map<Object, AtomSpecModel> buildColoursMap(
StructureSelectionManager ssm, String[] files,
- SequenceI[][] sequence, SequenceRenderer sr, FeatureRenderer fr,
- AlignmentI alignment)
+ SequenceI[][] sequence, SequenceRenderer sr,
+ AlignmentViewPanel viewPanel)
{
- Map<Color, SortedMap<Integer, Map<String, List<int[]>>>> colourMap = new LinkedHashMap<Color, SortedMap<Integer, Map<String, List<int[]>>>>();
+ FeatureRenderer fr = viewPanel.getFeatureRenderer();
+ FeatureColourFinder finder = new FeatureColourFinder(fr);
+ AlignViewportI viewport = viewPanel.getAlignViewport();
+ ColumnSelection cs = viewport.getColumnSelection();
+ AlignmentI al = viewport.getAlignment();
+ Map<Object, AtomSpecModel> colourMap = new LinkedHashMap<Object, AtomSpecModel>();
Color lastColour = null;
+
for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
{
StructureMapping[] mapping = ssm.getMapping(files[pdbfnum]);
{
final SequenceI seq = sequence[pdbfnum][s];
if (mapping[m].getSequence() == seq
- && (sp = alignment.findIndex(seq)) > -1)
+ && (sp = al.findIndex(seq)) > -1)
{
- SequenceI asp = alignment.getSequenceAt(sp);
+ SequenceI asp = al.getSequenceAt(sp);
for (int r = 0; r < asp.getLength(); r++)
{
// no mapping to gaps in sequence
continue;
}
- Color colour = sr.getResidueColour(seq, r, fr);
+ Color colour = sr.getResidueColour(seq, r, finder);
+
+ /*
+ * darker colour for hidden regions
+ */
+ if (!cs.isVisible(r))
+ {
+ // colour = ColorUtils.darkerThan(colour);
+ colour = Color.GRAY;
+ }
+
final String chain = mapping[m].getChain();
/*
// final colour range
if (lastColour != null)
{
- addColourRange(colourMap, lastColour, pdbfnum, startPos,
- lastPos, lastChain);
+ addColourRange(colourMap, lastColour, pdbfnum, startPos, lastPos,
+ lastChain);
}
// break;
}
/**
* Helper method to add one contiguous colour range to the colour map.
*
- * @param colourMap
- * @param colour
+ * @param map
+ * @param key
* @param model
* @param startPos
* @param endPos
* @param chain
*/
- protected static void addColourRange(
- Map<Color, SortedMap<Integer, Map<String, List<int[]>>>> colourMap,
- Color colour, int model, int startPos, int endPos, String chain)
+ protected static void addColourRange(Map<Object, AtomSpecModel> map,
+ Object key, int model, int startPos, int endPos, String chain)
{
/*
* Get/initialize map of data for the colour
*/
- SortedMap<Integer, Map<String, List<int[]>>> colourData = colourMap
- .get(colour);
- if (colourData == null)
+ AtomSpecModel atomSpec = map.get(key);
+ if (atomSpec == null)
{
- colourMap
- .put(colour,
- colourData = new TreeMap<Integer, Map<String, List<int[]>>>());
+ atomSpec = new AtomSpecModel();
+ map.put(key, atomSpec);
}
- /*
- * Get/initialize map of data for the colour and model
- */
- Map<String, List<int[]>> modelData = colourData.get(model);
- if (modelData == null)
+ atomSpec.addRange(model, startPos, endPos, chain);
+ }
+
+ /**
+ * Constructs and returns Chimera commands to set attributes on residues
+ * corresponding to features in Jalview. Attribute names are the Jalview
+ * feature type, with a "jv_" prefix.
+ *
+ * @param ssm
+ * @param files
+ * @param seqs
+ * @param viewPanel
+ * @return
+ */
+ public static StructureMappingcommandSet getSetAttributeCommandsForFeatures(
+ StructureSelectionManager ssm, String[] files,
+ SequenceI[][] seqs, AlignmentViewPanel viewPanel)
+ {
+ Map<String, Map<Object, AtomSpecModel>> featureMap = buildFeaturesMap(
+ ssm, files, seqs, viewPanel);
+
+ List<String> commands = buildSetAttributeCommands(featureMap);
+
+ StructureMappingcommandSet cs = new StructureMappingcommandSet(
+ ChimeraCommands.class, null,
+ commands.toArray(new String[commands.size()]));
+
+ return cs;
+ }
+
+ /**
+ * <pre>
+ * Helper method to build a map of
+ * { featureType, { feature value, AtomSpecModel } }
+ * </pre>
+ *
+ * @param ssm
+ * @param files
+ * @param seqs
+ * @param viewPanel
+ * @return
+ */
+ protected static Map<String, Map<Object, AtomSpecModel>> buildFeaturesMap(
+ StructureSelectionManager ssm, String[] files,
+ SequenceI[][] seqs, AlignmentViewPanel viewPanel)
+ {
+ Map<String, Map<Object, AtomSpecModel>> theMap = new LinkedHashMap<String, Map<Object, AtomSpecModel>>();
+
+ FeatureRenderer fr = viewPanel.getFeatureRenderer();
+ if (fr == null)
{
- colourData.put(model, modelData = new TreeMap<String, List<int[]>>());
+ return theMap;
}
- /*
- * Get/initialize map of data for colour, model and chain
- */
- List<int[]> chainData = modelData.get(chain);
- if (chainData == null)
+ List<String> visibleFeatures = fr.getDisplayedFeatureTypes();
+ if (visibleFeatures.isEmpty())
{
- modelData.put(chain, chainData = new ArrayList<int[]>());
+ return theMap;
}
+ AlignmentI alignment = viewPanel.getAlignment();
+ for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
+ {
+ StructureMapping[] mapping = ssm.getMapping(files[pdbfnum]);
+
+ if (mapping == null || mapping.length < 1)
+ {
+ continue;
+ }
+
+ for (int seqNo = 0; seqNo < seqs[pdbfnum].length; seqNo++)
+ {
+ for (int m = 0; m < mapping.length; m++)
+ {
+ final SequenceI seq = seqs[pdbfnum][seqNo];
+ int sp = alignment.findIndex(seq);
+ if (mapping[m].getSequence() == seq && sp > -1)
+ {
+ /*
+ * found a sequence with a mapping to a structure;
+ * now scan its features
+ */
+ SequenceI asp = alignment.getSequenceAt(sp);
+
+ scanSequenceFeatures(visibleFeatures, mapping[m], asp, theMap,
+ pdbfnum);
+ }
+ }
+ }
+ }
+ return theMap;
+ }
+
+ /**
+ * Inspect features on the sequence; for each feature that is visible,
+ * determine its mapped ranges in the structure (if any) according to the
+ * given mapping, and add them to the map
+ *
+ * @param visibleFeatures
+ * @param mapping
+ * @param seq
+ * @param theMap
+ * @param modelNumber
+ */
+ protected static void scanSequenceFeatures(List<String> visibleFeatures,
+ StructureMapping mapping, SequenceI seq,
+ Map<String, Map<Object, AtomSpecModel>> theMap, int modelNumber)
+ {
+ SequenceFeature[] sfs = seq.getSequenceFeatures();
+ if (sfs == null)
+ {
+ return;
+ }
+
+ for (SequenceFeature sf : sfs)
+ {
+ String type = sf.getType();
+
+ /*
+ * Only copy visible features, don't copy any which originated
+ * from Chimera, and suppress uninteresting ones (e.g. RESNUM)
+ */
+ boolean isFromViewer = JalviewChimeraBinding.CHIMERA_FEATURE_GROUP
+ .equals(sf.getFeatureGroup());
+ if (isFromViewer || !visibleFeatures.contains(type))
+ {
+ continue;
+ }
+ List<int[]> mappedRanges = mapping.getPDBResNumRanges(sf.getBegin(),
+ sf.getEnd());
+
+ if (!mappedRanges.isEmpty())
+ {
+ String value = sf.getDescription();
+ if (value == null || value.length() == 0)
+ {
+ value = type;
+ }
+ float score = sf.getScore();
+ if (score != 0f && !Float.isNaN(score))
+ {
+ value = Float.toString(score);
+ }
+ Map<Object, AtomSpecModel> featureValues = theMap.get(type);
+ if (featureValues == null)
+ {
+ featureValues = new HashMap<Object, AtomSpecModel>();
+ theMap.put(type, featureValues);
+ }
+ for (int[] range : mappedRanges)
+ {
+ addColourRange(featureValues, value, modelNumber, range[0], range[1],
+ mapping.getChain());
+ }
+ }
+ }
+ }
+
+ /**
+ * Traverse the map of features/values/models/chains/positions to construct a
+ * list of 'setattr' commands (one per distinct feature type and value).
+ * <p>
+ * The format of each command is
+ *
+ * <pre>
+ * <blockquote> setattr r <featureName> " " #modelnumber:range.chain
+ * e.g. setattr r jv:chain <value> #0:2.B,4.B,9-12.B|#1:1.A,2-6.A,...
+ * </blockquote>
+ * </pre>
+ *
+ * @param featureMap
+ * @return
+ */
+ protected static List<String> buildSetAttributeCommands(
+ Map<String, Map<Object, AtomSpecModel>> featureMap)
+ {
+ List<String> commands = new ArrayList<String>();
+ for (String featureType : featureMap.keySet())
+ {
+ String attributeName = makeAttributeName(featureType);
+
+ /*
+ * clear down existing attributes for this feature
+ */
+ // 'problem' - sets attribute to None on all residues - overkill?
+ // commands.add("~setattr r " + attributeName + " :*");
+
+ Map<Object, AtomSpecModel> values = featureMap.get(featureType);
+ for (Object value : values.keySet())
+ {
+ /*
+ * for each distinct value recorded for this feature type,
+ * add a command to set the attribute on the mapped residues
+ * Put values in single quotes, encoding any embedded single quotes
+ */
+ StringBuilder sb = new StringBuilder(128);
+ String featureValue = value.toString();
+ featureValue = featureValue.replaceAll("\\'", "'");
+ sb.append("setattr r ").append(attributeName).append(" '")
+ .append(featureValue).append("' ");
+ sb.append(values.get(value).getAtomSpec());
+ commands.add(sb.toString());
+ }
+ }
+
+ return commands;
+ }
+
+ /**
+ * Makes a prefixed and valid Chimera attribute name. A jv_ prefix is applied
+ * for a 'Jalview' namespace, and any non-alphanumeric character is converted
+ * to an underscore.
+ *
+ * @param featureType
+ * @return <pre>
+ * @see https://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/midas/setattr.html
+ * </pre>
+ */
+ protected static String makeAttributeName(String featureType)
+ {
+ StringBuilder sb = new StringBuilder();
+ if (featureType != null)
+ {
+ for (char c : featureType.toCharArray())
+ {
+ sb.append(Character.isLetterOrDigit(c) ? c : '_');
+ }
+ }
+ String attName = NAMESPACE_PREFIX + sb.toString();
+
/*
- * Add the start/end positions
+ * Chimera treats an attribute name ending in 'color' as colour-valued;
+ * Jalview doesn't, so prevent this by appending an underscore
*/
- chainData.add(new int[] { startPos, endPos });
+ if (attName.toUpperCase().endsWith("COLOR"))
+ {
+ attName += "_";
+ }
+
+ return attName;
}
}
}
/**
- * Handler a ModelChanged notification from Chimera
+ * Handle a ModelChanged notification from Chimera
*
* @param substring
*/
package jalview.ext.rbvi.chimera;
import jalview.api.AlignmentViewPanel;
-import jalview.api.FeatureRenderer;
import jalview.api.SequenceRenderer;
import jalview.api.structures.JalviewStructureDisplayI;
import jalview.bin.Cache;
import jalview.datamodel.AlignmentI;
import jalview.datamodel.ColumnSelection;
import jalview.datamodel.PDBEntry;
+import jalview.datamodel.SearchResultMatchI;
+import jalview.datamodel.SearchResultsI;
+import jalview.datamodel.SequenceFeature;
import jalview.datamodel.SequenceI;
import jalview.httpserver.AbstractRequestHandler;
import jalview.io.DataSourceType;
import jalview.util.MessageManager;
import java.awt.Color;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
import java.net.BindException;
import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.Collections;
import java.util.Hashtable;
import java.util.LinkedHashMap;
import java.util.List;
public abstract class JalviewChimeraBinding extends AAStructureBindingModel
{
+ public static final String CHIMERA_FEATURE_GROUP = "Chimera";
+
// Chimera clause to exclude alternate locations in atom selection
private static final String NO_ALTLOCS = "&~@.B-Z&~@.2-9";
*/
private Map<String, List<ChimeraModel>> chimeraMaps = new LinkedHashMap<String, List<ChimeraModel>>();
- /*
- * the default or current model displayed if the model cannot be identified
- * from the selection message
- */
- private int frameNo = 0;
-
- private String lastCommand;
-
String lastHighlightCommand;
/*
{
getSsm().addStructureViewerListener(this);
// ssm.addSelectionListener(this);
- FeatureRenderer fr = getFeatureRenderer(null);
- if (fr != null)
- {
- fr.featuresAdded();
- }
refreshGUI();
}
return true;
chimeraListener.shutdown();
chimeraListener = null;
}
- lastCommand = null;
viewer = null;
if (chimeraMonitor != null)
}
/**
- * Construct and send a command to align structures against a reference
- * structure, based on one or more sequence alignments
- *
- * @param _alignment
- * an array of alignments to process
- * @param _refStructure
- * an array of corresponding reference structures (index into pdb
- * file array); if a negative value is passed, the first PDB file
- * mapped to an alignment sequence is used as the reference for
- * superposition
- * @param _hiddenCols
- * an array of corresponding hidden columns for each alignment
+ * {@inheritDoc}
*/
@Override
- public void superposeStructures(AlignmentI[] _alignment,
+ public String superposeStructures(AlignmentI[] _alignment,
int[] _refStructure, ColumnSelection[] _hiddenCols)
{
StringBuilder allComs = new StringBuilder(128);
if (!waitForFileLoad(files))
{
- return;
+ return null;
}
refreshPdbEntries();
}
/*
- * 'matched' array will hold 'true' for visible alignment columns where
+ * 'matched' bit i will be set for visible alignment columns i where
* all sequences have a residue with a mapping to the PDB structure
*/
- boolean matched[] = new boolean[alignment.getWidth()];
- for (int m = 0; m < matched.length; m++)
+ BitSet matched = new BitSet();
+ for (int m = 0; m < alignment.getWidth(); m++)
{
- matched[m] = (hiddenCols != null) ? hiddenCols.isVisible(m) : true;
+ if (hiddenCols == null || hiddenCols.isVisible(m))
+ {
+ matched.set(m);
+ }
}
SuperposeData[] structures = new SuperposeData[files.length];
refStructure = candidateRefStructure;
}
- int nmatched = 0;
- for (boolean b : matched)
- {
- if (b)
- {
- nmatched++;
- }
- }
+ int nmatched = matched.cardinality();
if (nmatched < 4)
{
- // TODO: bail out here because superposition illdefined?
+ return MessageManager.formatMessage("label.insufficient_residues",
+ nmatched);
}
/*
int lpos = -1;
boolean run = false;
StringBuilder molsel = new StringBuilder();
- for (int r = 0; r < matched.length; r++)
+
+ int nextColumnMatch = matched.nextSetBit(0);
+ while (nextColumnMatch != -1)
{
- if (matched[r])
+ int pdbResNum = structures[pdbfnum].pdbResNo[nextColumnMatch];
+ if (lpos != pdbResNum - 1)
{
- int pdbResNum = structures[pdbfnum].pdbResNo[r];
- if (lpos != pdbResNum - 1)
+ /*
+ * discontiguous - append last residue now
+ */
+ if (lpos != -1)
{
- /*
- * discontiguous - append last residue now
- */
- if (lpos != -1)
- {
- molsel.append(String.valueOf(lpos));
- molsel.append(chainCd);
- molsel.append(",");
- }
- run = false;
+ molsel.append(String.valueOf(lpos));
+ molsel.append(chainCd);
+ molsel.append(",");
}
- else
+ run = false;
+ }
+ else
+ {
+ /*
+ * extending a contiguous run
+ */
+ if (!run)
{
/*
- * extending a contiguous run
+ * start the range selection
*/
- if (!run)
- {
- /*
- * start the range selection
- */
- molsel.append(String.valueOf(lpos));
- molsel.append("-");
- }
- run = true;
+ molsel.append(String.valueOf(lpos));
+ molsel.append("-");
}
- lpos = pdbResNum;
+ run = true;
}
+ lpos = pdbResNum;
+ nextColumnMatch = matched.nextSetBit(nextColumnMatch + 1);
}
/*
.append(";" + command.toString());
}
}
+
+ String error = null;
if (selectioncom.length() > 0)
{
// TODO: visually distinguish regions that were superposed
}
allComs.append("; ~display all; chain @CA|P; ribbon ")
.append(selectioncom.toString()).append("; focus");
- sendChimeraCommand(allComs.toString(), false);
+ List<String> chimeraReplies = sendChimeraCommand(allComs.toString(),
+ true);
+ for (String reply : chimeraReplies)
+ {
+ if (reply.toLowerCase().contains("unequal numbers of atoms"))
+ {
+ error = reply;
+ }
+ }
}
-
+ return error;
}
/**
}
/**
- * Send a command to Chimera, and optionally log any responses.
+ * Send a command to Chimera, and optionally log and return any responses.
+ * <p>
+ * Does nothing, and returns null, if the command is the same as the last one
+ * sent [why?].
*
* @param command
- * @param logResponse
+ * @param getResponse
*/
- public void sendChimeraCommand(final String command, boolean logResponse)
+ public List<String> sendChimeraCommand(final String command,
+ boolean getResponse)
{
if (viewer == null)
{
// ? thread running after viewer shut down
- return;
+ return null;
}
+ List<String> reply = null;
viewerCommandHistory(false);
- if (lastCommand == null || !lastCommand.equals(command))
+ if (true /*lastCommand == null || !lastCommand.equals(command)*/)
{
// trim command or it may never find a match in the replyLog!!
List<String> lastReply = viewer.sendChimeraCommand(command.trim(),
- logResponse);
- if (logResponse && debug)
+ getResponse);
+ if (getResponse)
{
- log("Response from command ('" + command + "') was:\n" + lastReply);
+ reply = lastReply;
+ if (debug)
+ {
+ log("Response from command ('" + command + "') was:\n"
+ + lastReply);
+ }
}
}
viewerCommandHistory(true);
- lastCommand = command;
+
+ return reply;
}
/**
/**
* @param files
* @param sr
- * @param fr
- * @param alignment
+ * @param viewPanel
* @return
*/
@Override
protected StructureMappingcommandSet[] getColourBySequenceCommands(
- String[] files, SequenceRenderer sr, FeatureRenderer fr,
- AlignmentI alignment)
+ String[] files, SequenceRenderer sr, AlignmentViewPanel viewPanel)
{
return ChimeraCommands.getColourBySequenceCommand(getSsm(), files,
- getSequence(), sr, fr, alignment);
+ getSequence(), sr, viewPanel);
}
/**
*/
private int _modelFileNameMap[];
+
// ////////////////////////////////
// /StructureListener
@Override
* Parse model number, residue and chain for each selected position,
* formatted as #0:123.A or #1.2:87.B (#model.submodel:residue.chain)
*/
+ List<AtomSpec> atomSpecs = convertStructureResiduesToAlignment(selection);
+
+ /*
+ * Broadcast the selection (which may be empty, if the user just cleared all
+ * selections)
+ */
+ getSsm().mouseOverStructure(atomSpecs);
+ }
+
+ /**
+ * Converts a list of Chimera atomspecs to a list of AtomSpec representing the
+ * corresponding residues (if any) in Jalview
+ *
+ * @param structureSelection
+ * @return
+ */
+ protected List<AtomSpec> convertStructureResiduesToAlignment(
+ List<String> structureSelection)
+ {
List<AtomSpec> atomSpecs = new ArrayList<AtomSpec>();
- for (String atomSpec : selection)
+ for (String atomSpec : structureSelection)
{
- int colonPos = atomSpec.indexOf(":");
- if (colonPos == -1)
- {
- continue; // malformed
- }
-
- int hashPos = atomSpec.indexOf("#");
- String modelSubmodel = atomSpec.substring(hashPos + 1, colonPos);
- int dotPos = modelSubmodel.indexOf(".");
- int modelId = 0;
try
{
- modelId = Integer.valueOf(dotPos == -1 ? modelSubmodel
- : modelSubmodel.substring(0, dotPos));
- } catch (NumberFormatException e)
+ AtomSpec spec = AtomSpec.fromChimeraAtomspec(atomSpec);
+ String pdbfilename = getPdbFileForModel(spec.getModelNumber());
+ spec.setPdbFile(pdbfilename);
+ atomSpecs.add(spec);
+ } catch (IllegalArgumentException e)
{
- // ignore, default to model 0
+ System.err.println("Failed to parse atomspec: " + atomSpec);
}
+ }
+ return atomSpecs;
+ }
- String residueChain = atomSpec.substring(colonPos + 1);
- dotPos = residueChain.indexOf(".");
- int pdbResNum = Integer.parseInt(dotPos == -1 ? residueChain
- : residueChain.substring(0, dotPos));
-
- String chainId = dotPos == -1 ? "" : residueChain
- .substring(dotPos + 1);
-
- /*
- * Work out the pdbfilename from the model number
- */
- String pdbfilename = modelFileNames[frameNo];
- findfileloop: for (String pdbfile : this.chimeraMaps.keySet())
+ /**
+ * @param modelId
+ * @return
+ */
+ protected String getPdbFileForModel(int modelId)
+ {
+ /*
+ * Work out the pdbfilename from the model number
+ */
+ String pdbfilename = modelFileNames[0];
+ findfileloop: for (String pdbfile : this.chimeraMaps.keySet())
+ {
+ for (ChimeraModel cm : chimeraMaps.get(pdbfile))
{
- for (ChimeraModel cm : chimeraMaps.get(pdbfile))
+ if (cm.getModelNumber() == modelId)
{
- if (cm.getModelNumber() == modelId)
- {
- pdbfilename = pdbfile;
- break findfileloop;
- }
+ pdbfilename = pdbfile;
+ break findfileloop;
}
}
- atomSpecs.add(new AtomSpec(pdbfilename, chainId, pdbResNum, 0));
}
-
- /*
- * Broadcast the selection (which may be empty, if the user just cleared all
- * selections)
- */
- getSsm().mouseOverStructure(atomSpecs);
+ return pdbfilename;
}
private void log(String message)
}
/**
+ * Returns a list of chains mapped in this viewer. Note this list is not
+ * currently scoped per structure.
+ *
+ * @return
+ */
+ @Override
+ public List<String> getChainNames()
+ {
+ return chainNames;
+ }
+
+ /**
* Send a 'focus' command to Chimera to recentre the visible display
*/
public void focusView()
}
}
+ /**
+ * Constructs and send commands to Chimera to set attributes on residues for
+ * features visible in Jalview
+ *
+ * @param avp
+ * @return
+ */
+ public int sendFeaturesToViewer(AlignmentViewPanel avp)
+ {
+ // TODO refactor as required to pull up to an interface
+ AlignmentI alignment = avp.getAlignment();
- @Override
- public List<String> getChainNames()
+ String[] files = getPdbFile();
+ if (files == null)
+ {
+ return 0;
+ }
+
+ StructureMappingcommandSet commandSet = ChimeraCommands
+ .getSetAttributeCommandsForFeatures(getSsm(), files,
+ getSequence(), avp);
+ String[] commands = commandSet.commands;
+ if (commands.length > 10)
+ {
+ sendCommandsByFile(commands);
+ }
+ else
+ {
+ for (String command : commands)
+ {
+ sendAsynchronousCommand(command, null);
+ }
+ }
+ return commands.length;
+ }
+
+ /**
+ * Write commands to a temporary file, and send a command to Chimera to open
+ * the file as a commands script. For use when sending a large number of
+ * separate commands would overload the REST interface mechanism.
+ *
+ * @param commands
+ */
+ protected void sendCommandsByFile(String[] commands)
{
- return chainNames;
+ try
+ {
+ File tmp = File.createTempFile("chim", ".com");
+ tmp.deleteOnExit();
+ PrintWriter out = new PrintWriter(new FileOutputStream(tmp));
+ for (String command : commands)
+ {
+ out.println(command);
+ }
+ out.flush();
+ out.close();
+ String path = tmp.getAbsolutePath();
+ sendAsynchronousCommand("open cmd:" + path, null);
+ } catch (IOException e)
+ {
+ System.err
+ .println("Sending commands to Chimera via file failed with "
+ + e.getMessage());
+ }
}
+ /**
+ * Get Chimera residues which have the named attribute, find the mapped
+ * positions in the Jalview sequence(s), and set as sequence features
+ *
+ * @param attName
+ * @param alignmentPanel
+ */
+ public void copyStructureAttributesToFeatures(String attName,
+ AlignmentViewPanel alignmentPanel)
+ {
+ // todo pull up to AAStructureBindingModel (and interface?)
+
+ /*
+ * ask Chimera to list residues with the attribute, reporting its value
+ */
+ // this alternative command
+ // list residues spec ':*/attName' attr attName
+ // doesn't report 'None' values (which is good), but
+ // fails for 'average.bfactor' (which is bad):
+
+ String cmd = "list residues attr '" + attName + "'";
+ List<String> residues = sendChimeraCommand(cmd, true);
+
+ boolean featureAdded = createFeaturesForAttributes(attName, residues);
+ if (featureAdded)
+ {
+ alignmentPanel.getFeatureRenderer().featuresAdded();
+ }
+ }
+
+ /**
+ * Create features in Jalview for the given attribute name and structure
+ * residues.
+ *
+ * <pre>
+ * The residue list should be 0, 1 or more reply lines of the format:
+ * residue id #0:5.A isHelix -155.000836316 index 5
+ * or
+ * residue id #0:6.A isHelix None
+ * </pre>
+ *
+ * @param attName
+ * @param residues
+ * @return
+ */
+ protected boolean createFeaturesForAttributes(String attName,
+ List<String> residues)
+ {
+ boolean featureAdded = false;
+ String featureGroup = getViewerFeatureGroup();
+
+ for (String residue : residues)
+ {
+ AtomSpec spec = null;
+ String[] tokens = residue.split(" ");
+ if (tokens.length < 5)
+ {
+ continue;
+ }
+ String atomSpec = tokens[2];
+ String attValue = tokens[4];
+
+ /*
+ * ignore 'None' (e.g. for phi) or 'False' (e.g. for isHelix)
+ */
+ if ("None".equalsIgnoreCase(attValue)
+ || "False".equalsIgnoreCase(attValue))
+ {
+ continue;
+ }
+
+ try
+ {
+ spec = AtomSpec.fromChimeraAtomspec(atomSpec);
+ } catch (IllegalArgumentException e)
+ {
+ System.err.println("Problem parsing atomspec " + atomSpec);
+ continue;
+ }
+
+ String chainId = spec.getChain();
+ String description = attValue;
+ float score = Float.NaN;
+ try
+ {
+ score = Float.valueOf(attValue);
+ description = chainId;
+ } catch (NumberFormatException e)
+ {
+ // was not a float value
+ }
+
+ String pdbFile = getPdbFileForModel(spec.getModelNumber());
+ spec.setPdbFile(pdbFile);
+
+ List<AtomSpec> atoms = Collections.singletonList(spec);
+
+ /*
+ * locate the mapped position in the alignment (if any)
+ */
+ SearchResultsI sr = getSsm()
+ .findAlignmentPositionsForStructurePositions(atoms);
+
+ /*
+ * expect one matched alignment position, or none
+ * (if the structure position is not mapped)
+ */
+ for (SearchResultMatchI m : sr.getResults())
+ {
+ SequenceI seq = m.getSequence();
+ int start = m.getStart();
+ int end = m.getEnd();
+ SequenceFeature sf = new SequenceFeature(attName, description,
+ start, end, score, featureGroup);
+ // todo: should SequenceFeature have an explicit property for chain?
+ // note: repeating the action shouldn't duplicate features
+ featureAdded |= seq.addSequenceFeature(sf);
+ }
+ }
+ return featureAdded;
+ }
+
+ /**
+ * Answers the feature group name to apply to features created in Jalview from
+ * Chimera attributes
+ *
+ * @return
+ */
+ protected String getViewerFeatureGroup()
+ {
+ // todo pull up to interface
+ return CHIMERA_FEATURE_GROUP;
+ }
+
+
public Hashtable<String, String> getChainFile()
{
return chainFile;
*/
package jalview.ext.varna;
-import jalview.api.FeatureRenderer;
import jalview.api.SequenceRenderer;
import jalview.datamodel.AlignmentI;
import jalview.datamodel.SequenceI;
+import jalview.renderer.seqfeatures.FeatureColourFinder;
import jalview.structure.StructureMapping;
import jalview.structure.StructureSelectionManager;
*/
public static String[] getColourBySequenceCommand(
StructureSelectionManager ssm, String[] files,
- SequenceI[][] sequence, SequenceRenderer sr, FeatureRenderer fr,
+ SequenceI[][] sequence, SequenceRenderer sr,
+ FeatureColourFinder finder,
AlignmentI alignment)
{
ArrayList<String> str = new ArrayList<String>();
StructureMapping[] mapping = ssm.getMapping(files[pdbfnum]);
if (mapping == null || mapping.length < 1)
+ {
continue;
+ }
int lastPos = -1;
for (int s = 0; s < sequence[pdbfnum].length; s++)
int pos = mapping[m].getPDBResNum(asp.findPosition(r));
if (pos < 1 || pos == lastPos)
+ {
continue;
+ }
lastPos = pos;
- Color col = sr.getResidueBoxColour(sequence[pdbfnum][s], r);
+ Color col = sr.getResidueColour(sequence[pdbfnum][s], r,
+ finder);
- if (fr != null)
- col = fr.findFeatureColour(col, sequence[pdbfnum][s], r);
String newSelcom = (mapping[m].getChain() != " " ? ":"
+ mapping[m].getChain() : "")
+ "/"
import jalview.schemes.TCoffeeColourScheme;
import jalview.util.MessageManager;
import jalview.viewmodel.AlignmentViewport;
+import jalview.viewmodel.ViewportRanges;
import jalview.ws.DBRefFetcher;
import jalview.ws.DBRefFetcher.FetchFinishedListenerI;
import jalview.ws.jws1.Discoverer;
AlignViewport viewport;
+ ViewportRanges vpRanges;
+
public AlignViewControllerI avc;
List<AlignmentPanel> alignPanels = new ArrayList<AlignmentPanel>();
progressBar = new ProgressBar(this.statusPanel, this.statusBar);
}
+ vpRanges = viewport.getRanges();
avc = new jalview.controller.AlignViewController(this, viewport,
alignPanel);
if (viewport.getAlignmentConservationAnnotation() == null)
new String[] { (viewport.cursorMode ? "on" : "off") }));
if (viewport.cursorMode)
{
- alignPanel.getSeqPanel().seqCanvas.cursorX = viewport.startRes;
- alignPanel.getSeqPanel().seqCanvas.cursorY = viewport.startSeq;
+ alignPanel.getSeqPanel().seqCanvas.cursorX = vpRanges
+ .getStartRes();
+ alignPanel.getSeqPanel().seqCanvas.cursorY = vpRanges
+ .getStartSeq();
}
alignPanel.getSeqPanel().seqCanvas.repaint();
break;
}
else
{
- alignPanel.setScrollValues(viewport.startRes, viewport.startSeq
- - viewport.endSeq + viewport.startSeq);
+ alignPanel.setScrollValues(vpRanges.getStartRes(),
+ 2 * vpRanges.getStartSeq() - vpRanges.getEndSeq());
}
break;
case KeyEvent.VK_PAGE_DOWN:
}
else
{
- alignPanel.setScrollValues(viewport.startRes, viewport.startSeq
- + viewport.endSeq - viewport.startSeq);
+ alignPanel.setScrollValues(vpRanges.getStartRes(),
+ vpRanges.getEndSeq());
}
break;
}
{
// propagate alignment changed.
- viewport.setEndSeq(alignment.getHeight());
+ vpRanges.setEndSeq(alignment.getHeight());
if (annotationAdded)
{
// Duplicate sequence annotation in all views.
{
trimRegion = new TrimRegionCommand("Remove Left", true, seqs,
column, viewport.getAlignment());
- viewport.setStartRes(0);
+ vpRanges.setStartRes(0);
}
else
{
// This is to maintain viewport position on first residue
// of first sequence
SequenceI seq = viewport.getAlignment().getSequenceAt(0);
- int startRes = seq.findPosition(viewport.startRes);
+ int startRes = seq.findPosition(vpRanges.getStartRes());
// ShiftList shifts;
// viewport.getAlignment().removeGaps(shifts=new ShiftList());
// edit.alColumnChanges=shifts.getInverse();
// if (viewport.hasHiddenColumns)
// viewport.getColumnSelection().compensateForEdits(shifts);
- viewport.setStartRes(seq.findIndex(startRes) - 1);
+ vpRanges.setStartRes(seq.findIndex(startRes) - 1);
viewport.firePropertyChange("alignment", null, viewport.getAlignment()
.getSequences());
// This is to maintain viewport position on first residue
// of first sequence
SequenceI seq = viewport.getAlignment().getSequenceAt(0);
- int startRes = seq.findPosition(viewport.startRes);
+ int startRes = seq.findPosition(vpRanges.getStartRes());
addHistoryItem(new RemoveGapsCommand("Remove Gaps", seqs, start, end,
viewport.getAlignment()));
- viewport.setStartRes(seq.findIndex(startRes) - 1);
+ vpRanges.setStartRes(seq.findIndex(startRes) - 1);
viewport.firePropertyChange("alignment", null, viewport.getAlignment()
.getSequences());
import jalview.schemes.ColourSchemeProperty;
import jalview.schemes.ResidueColourScheme;
import jalview.schemes.UserColourScheme;
-import jalview.structure.CommandListener;
import jalview.structure.SelectionSource;
import jalview.structure.StructureSelectionManager;
import jalview.structure.VamsasSource;
import jalview.util.MessageManager;
import jalview.viewmodel.AlignmentViewport;
+import jalview.viewmodel.ViewportRanges;
import jalview.ws.params.AutoCalcSetting;
import java.awt.Container;
* @version $Revision: 1.141 $
*/
public class AlignViewport extends AlignmentViewport implements
- SelectionSource, CommandListener
+ SelectionSource
{
Font font;
void init()
{
- this.startRes = 0;
- this.endRes = alignment.getWidth() - 1;
- this.startSeq = 0;
- this.endSeq = alignment.getHeight() - 1;
+ ranges = new ViewportRanges(this.alignment);
applyViewProperties();
String fontName = Cache.getDefault("FONT_NAME", "SansSerif");
super.setViewStyle(settingsForView);
setFont(new Font(viewStyle.getFontName(), viewStyle.getFontStyle(),
viewStyle.getFontSize()), false);
- if (residueShading != null)
- {
- residueShading.setConservationApplied(settingsForView
- .isConservationColourSelected());
- }
}
/**
}
}
- setEndSeq(getAlignment().getHeight());
+ ranges.setEndSeq(getAlignment().getHeight());
firePropertyChange("alignment", null, getAlignment().getSequences());
}
import jalview.structure.StructureSelectionManager;
import jalview.util.MessageManager;
import jalview.util.Platform;
+import jalview.viewmodel.ViewportRanges;
import java.awt.BorderLayout;
import java.awt.Color;
{
public AlignViewport av;
+ ViewportRanges vpRanges;
+
OverviewPanel overviewPanel;
private SeqPanel seqPanel;
// this value is set false when selection area being dragged
boolean fastPaint = true;
- int hextent = 0;
+ private int hextent = 0;
- int vextent = 0;
+ private int vextent = 0;
/*
* Flag set while scrolling to follow complementary cDNA/protein scroll. When
{
alignFrame = af;
this.av = av;
+ vpRanges = av.getRanges();
setSeqPanel(new SeqPanel(av, this));
setIdPanel(new IdPanel(av, this));
*/
if (centre)
{
- int offset = (av.getEndRes() - av.getStartRes() + 1) / 2 - 1;
+ int offset = (vpRanges.getEndRes() - vpRanges.getStartRes() + 1) / 2 - 1;
start = Math.max(start - offset, 0);
end = end + offset - 1;
}
// + av.getStartSeq() + ", ends=" + av.getEndSeq());
if (!av.getWrapAlignment())
{
- if ((startv = av.getStartRes()) >= start)
+ if ((startv = vpRanges.getStartRes()) >= start)
{
/*
* Scroll left to make start of search results visible
// setScrollValues(start - 1, seqIndex); // plus one residue
setScrollValues(start, seqIndex);
}
- else if ((endv = av.getEndRes()) <= end)
+ else if ((endv = vpRanges.getEndRes()) <= end)
{
/*
* Scroll right to make end of search results visible
// setScrollValues(startv + 1 + end - endv, seqIndex); // plus one
setScrollValues(startv + end - endv, seqIndex);
}
- else if ((starts = av.getStartSeq()) > seqIndex)
+ else if ((starts = vpRanges.getStartSeq()) > seqIndex)
{
/*
* Scroll up to make start of search results visible
*/
- setScrollValues(av.getStartRes(), seqIndex);
+ setScrollValues(vpRanges.getStartRes(), seqIndex);
}
- else if ((ends = av.getEndSeq()) <= seqIndex)
+ else if ((ends = vpRanges.getEndSeq()) <= seqIndex)
{
/*
* Scroll down to make end of search results visible
*/
- setScrollValues(av.getStartRes(), starts + seqIndex - ends + 1);
+ setScrollValues(vpRanges.getStartRes(), starts + seqIndex - ends
+ + 1);
}
/*
* Else results are already visible - no need to scroll
{
int cwidth = getSeqPanel().seqCanvas
.getWrappedCanvasWidth(getSeqPanel().seqCanvas.getWidth());
- if (res < av.getStartRes() || res >= (av.getStartRes() + cwidth))
+ if (res < vpRanges.getStartRes()
+ || res >= (vpRanges.getStartRes() + cwidth))
{
vscroll.setValue((res / cwidth));
- av.startRes = vscroll.getValue() * cwidth;
+ vpRanges.setStartRes(vscroll.getValue() * cwidth);
}
}
fontChanged();
setAnnotationVisible(av.isShowAnnotation());
boolean wrap = av.getWrapAlignment();
- av.startSeq = 0;
+ vpRanges.setStartSeq(0);
scalePanelHolder.setVisible(!wrap);
hscroll.setVisible(!wrap);
idwidthAdjuster.setVisible(!wrap);
*/
public void setScrollValues(int x, int y)
{
- // System.err.println("Scroll " + this.av.viewName + " to " + x + "," + y);
if (av == null || av.getAlignment() == null)
{
return;
if (av.hasHiddenColumns())
{
+ // reset the width to exclude hidden columns
width = av.getColumnSelection().findColumnPosition(width);
}
- av.setEndRes((x + (getSeqPanel().seqCanvas.getWidth() / av
- .getCharWidth())) - 1);
-
hextent = getSeqPanel().seqCanvas.getWidth() / av.getCharWidth();
vextent = getSeqPanel().seqCanvas.getHeight() / av.getCharHeight();
x = 0;
}
+ // update endRes after x has (possibly) been adjusted
+ vpRanges.setEndRes((x + (getSeqPanel().seqCanvas.getWidth() / av
+ .getCharWidth())) - 1);
+
/*
* each scroll adjustment triggers adjustmentValueChanged, which resets the
* 'do not scroll complement' flag; ensure it is the same for both
@Override
public void adjustmentValueChanged(AdjustmentEvent evt)
{
- int oldX = av.getStartRes();
- int oldY = av.getStartSeq();
+ int oldX = vpRanges.getStartRes();
+ int oldY = vpRanges.getStartSeq();
if (evt.getSource() == hscroll)
{
int x = hscroll.getValue();
- av.setStartRes(x);
- av.setEndRes((x + (getSeqPanel().seqCanvas.getWidth() / av
+ vpRanges.setStartRes(x);
+ vpRanges.setEndRes((x + (getSeqPanel().seqCanvas.getWidth() / av
.getCharWidth())) - 1);
}
{
int rowSize = getSeqPanel().seqCanvas
.getWrappedCanvasWidth(getSeqPanel().seqCanvas.getWidth());
- av.setStartRes(offy * rowSize);
- av.setEndRes((offy + 1) * rowSize);
+ vpRanges.setStartRes(offy * rowSize);
+ vpRanges.setEndRes((offy + 1) * rowSize);
}
else
{
@Override
public void run()
{
- setScrollValues(av.getStartRes(), av.getStartSeq());
+ setScrollValues(vpRanges.getStartRes(),
+ vpRanges.getStartSeq());
}
});
}
}
else
{
- av.setStartSeq(offy);
- av.setEndSeq(offy
- + (getSeqPanel().seqCanvas.getHeight() / av.getCharHeight()));
+ vpRanges.setStartSeq(offy);
+ vpRanges.setEndSeq(offy
+ + (getSeqPanel().seqCanvas.getHeight() / av.getCharHeight())
+ - 1);
}
}
overviewPanel.setBoxPosition();
}
- int scrollX = av.startRes - oldX;
- int scrollY = av.startSeq - oldY;
+ int scrollX = vpRanges.getStartRes() - oldX;
+ int scrollY = vpRanges.getStartSeq() - oldY;
if (av.getWrapAlignment() || !fastPaint)
{
{
// Make sure we're not trying to draw a panel
// larger than the visible window
- if (scrollX > av.endRes - av.startRes)
+ if (scrollX > vpRanges.getEndRes() - vpRanges.getStartRes())
{
- scrollX = av.endRes - av.startRes;
+ scrollX = vpRanges.getEndRes() - vpRanges.getStartRes();
}
- else if (scrollX < av.startRes - av.endRes)
+ else if (scrollX < vpRanges.getStartRes() - vpRanges.getEndRes())
{
- scrollX = av.startRes - av.endRes;
+ scrollX = vpRanges.getStartRes() - vpRanges.getEndRes();
}
if (scrollX != 0 || scrollY != 0)
}
else
{
- setScrollValues(av.getStartRes(), av.getStartSeq());
+ setScrollValues(vpRanges.getStartRes(), vpRanges.getStartSeq());
}
}
import javax.swing.JColorChooser;
import javax.swing.JMenuItem;
-import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.Scrollable;
return;
}
- int column = (evt.getX() / av.getCharWidth()) + av.getStartRes();
+ int column = (evt.getX() / av.getCharWidth())
+ + av.getRanges().getStartRes();
if (av.hasHiddenColumns())
{
return;
}
}
- imgWidth = (av.endRes - av.startRes + 1) * av.getCharWidth();
+ imgWidth = (av.getRanges().getEndRes() - av.getRanges().getStartRes() + 1)
+ * av.getCharWidth();
if (imgWidth < 1)
{
return;
imageFresh = true;
}
- drawComponent(gg, av.startRes, av.endRes + 1);
+ drawComponent(gg, av.getRanges().getStartRes(), av.getRanges()
+ .getEndRes() + 1);
imageFresh = false;
g.drawImage(image, 0, 0, this);
}
gg.copyArea(0, 0, imgWidth, getHeight(),
-horizontal * av.getCharWidth(), 0);
long mtime = System.currentTimeMillis();
- int sr = av.startRes;
- int er = av.endRes + 1;
+ int sr = av.getRanges().getStartRes();
+ int er = av.getRanges().getEndRes() + 1;
int transX = 0;
if (horizontal > 0) // scrollbar pulled right, image to the left
import jalview.schemes.AnnotationColourGradient;
import jalview.util.MessageManager;
+import java.awt.event.FocusAdapter;
+import java.awt.event.FocusEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Vector;
{
this.av = av;
this.ap = ap;
+ thresholdValue.addFocusListener(new FocusAdapter()
+ {
+ @Override
+ public void focusLost(FocusEvent e)
+ {
+ thresholdValue_actionPerformed();
+ }
+ });
}
public AnnotationRowFilter()
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JInternalFrame;
-import javax.swing.JMenu;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.SwingUtilities;
{
super.initMenus();
- viewerActionMenu = new JMenu(MessageManager.getString("label.jmol"));
+ viewerActionMenu.setText(MessageManager.getString("label.jmol"));
viewerColour
.setText(MessageManager.getString("label.colour_with_jmol"));
{
private AppJmol appJmolWindow;
- private FeatureRenderer fr = null;
-
public AppJmolBinding(AppJmol appJmol, StructureSelectionManager sSm,
PDBEntry[] pdbentry, SequenceI[][] sequenceIs, DataSourceType protocol)
{
}
@Override
- public FeatureRenderer getFeatureRenderer(AlignmentViewPanel alignment)
- {
- AlignmentPanel ap = (alignment == null) ? appJmolWindow
- .getAlignmentPanel() : (AlignmentPanel) alignment;
- if (ap.av.isShowSequenceFeatures())
- {
- if (fr == null)
- {
- fr = (jalview.gui.FeatureRenderer) ap.cloneFeatureRenderer();
- }
- else
- {
- ap.updateFeatureRenderer(fr);
- }
- }
-
- return fr;
- }
-
- @Override
public SequenceRenderer getSequenceRenderer(AlignmentViewPanel alignment)
{
return new SequenceRenderer(((AlignmentPanel) alignment).av);
{
return appJmolWindow;
}
+
+ @Override
+ public jalview.api.FeatureRenderer getFeatureRenderer(
+ AlignmentViewPanel alignment)
+ {
+ AlignmentPanel ap = (alignment == null) ? appJmolWindow
+ .getAlignmentPanel() : (AlignmentPanel) alignment;
+ if (ap.av.isShowSequenceFeatures())
+ {
+ return ap.av.getAlignPanel().getSeqPanel().seqCanvas.fr;
+ }
+
+ return null;
+ }
}
*/
package jalview.gui;
+import jalview.api.FeatureRenderer;
import jalview.bin.Cache;
import jalview.datamodel.AlignmentI;
import jalview.datamodel.PDBEntry;
import jalview.datamodel.SequenceI;
+import jalview.ext.rbvi.chimera.ChimeraCommands;
import jalview.ext.rbvi.chimera.JalviewChimeraBinding;
import jalview.gui.StructureViewer.ViewerType;
import jalview.io.DataSourceType;
import jalview.ws.dbsources.Pdb;
import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.Random;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JInternalFrame;
+import javax.swing.JMenu;
+import javax.swing.JMenuItem;
import javax.swing.event.InternalFrameAdapter;
import javax.swing.event.InternalFrameEvent;
{
private JalviewChimeraBinding jmb;
- private boolean allChainsSelected = false;
-
private IProgressIndicator progressBar = null;
/*
private Random random = new Random();
+ private int myWidth = 500;
+
+ private int myHeight = 150;
+
/**
* Initialise menu options.
*/
helpItem.setText(MessageManager.getString("label.chimera_help"));
savemenu.setVisible(false); // not yet implemented
viewMenu.add(fitToWindow);
+
+ JMenuItem writeFeatures = new JMenuItem(
+ MessageManager.getString("label.create_chimera_attributes"));
+ writeFeatures.setToolTipText(MessageManager
+ .getString("label.create_chimera_attributes_tip"));
+ writeFeatures.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ sendFeaturesToChimera();
+ }
+ });
+ viewerActionMenu.add(writeFeatures);
+
+ final JMenu fetchAttributes = new JMenu(
+ MessageManager.getString("label.fetch_chimera_attributes"));
+ fetchAttributes.setToolTipText(MessageManager
+ .getString("label.fetch_chimera_attributes_tip"));
+ fetchAttributes.addMouseListener(new MouseAdapter()
+ {
+
+ @Override
+ public void mouseEntered(MouseEvent e)
+ {
+ buildAttributesMenu(fetchAttributes);
+ }
+ });
+ viewerActionMenu.add(fetchAttributes);
+
+ }
+
+ /**
+ * Query Chimera for its residue attribute names and add them as items off the
+ * attributes menu
+ *
+ * @param attributesMenu
+ */
+ protected void buildAttributesMenu(JMenu attributesMenu)
+ {
+ List<String> atts = jmb.sendChimeraCommand("list resattr", true);
+ if (atts == null)
+ {
+ return;
+ }
+ attributesMenu.removeAll();
+ Collections.sort(atts);
+ for (String att : atts)
+ {
+ final String attName = att.split(" ")[1];
+
+ /*
+ * ignore 'jv_*' attributes, as these are Jalview features that have
+ * been transferred to residue attributes in Chimera!
+ */
+ if (!attName.startsWith(ChimeraCommands.NAMESPACE_PREFIX))
+ {
+ JMenuItem menuItem = new JMenuItem(attName);
+ menuItem.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ getChimeraAttributes(attName);
+ }
+ });
+ attributesMenu.add(menuItem);
+ }
+ }
+ }
+
+ /**
+ * Read residues in Chimera with the given attribute name, and set as features
+ * on the corresponding sequence positions (if any)
+ *
+ * @param attName
+ */
+ protected void getChimeraAttributes(String attName)
+ {
+ jmb.copyStructureAttributesToFeatures(attName, getAlignmentPanel());
+ }
+
+ /**
+ * Send a command to Chimera to create residue attributes for Jalview features
+ * <p>
+ * The syntax is: setattr r <attName> <attValue> <atomSpec>
+ * <p>
+ * For example: setattr r jv:chain "Ferredoxin-1, Chloroplastic" #0:94.A
+ */
+ protected void sendFeaturesToChimera()
+ {
+ int count = jmb.sendFeaturesToViewer(getAlignmentPanel());
+ statusBar.setText(MessageManager.formatMessage("label.attributes_set",
+ count));
}
/**
SequenceI[][] seqs)
{
createProgressBar();
- // FIXME extractChains needs pdbentries to match IDs to PDBEntry(s) on seqs
jmb = new JalviewChimeraBindingModel(this,
ap.getStructureSelectionManager(), pdbentrys, seqs, null);
addAlignmentPanel(ap);
useAlignmentPanelForSuperposition(ap);
}
jmb.setColourBySequence(true);
- setSize(400, 400); // probably should be a configurable/dynamic default here
+ setSize(myWidth, myHeight);
initMenus();
addingStructures = false;
void initChimera()
{
jmb.setFinishedInit(false);
- jalview.gui.Desktop.addInternalFrame(this,
+ Desktop.addInternalFrame(this,
jmb.getViewerTitle(getViewerName(), true), getBounds().width,
getBounds().height);
+ chimeraSessionFile);
}
}
- jmb.setFinishedInit(true);
jmb.startChimeraListener();
}
-
/**
* Show only the selected chain(s) in the viewer
*/
if (files.length() > 0)
{
+ jmb.setFinishedInit(false);
if (!addingStructures)
{
try
}
}
}
+
jmb.refreshGUI();
jmb.setFinishedInit(true);
jmb.setLoadingFromArchive(false);
+ /*
+ * ensure that any newly discovered features (e.g. RESNUM)
+ * are added to any open feature settings dialog
+ */
+ FeatureRenderer fr = getBinding().getFeatureRenderer(null);
+ if (fr != null)
+ {
+ fr.featuresAdded();
+ }
+
// refresh the sequence colours for the new structure(s)
for (AlignmentPanel ap : _colourwith)
{
{
BrowserLauncher
.openURL("https://www.cgl.ucsf.edu/chimera/docs/UsersGuide");
- } catch (Exception ex)
+ } catch (IOException ex)
{
}
}
{
return "Chimera";
}
+
+ /**
+ * Sends commands to align structures according to associated alignment(s).
+ *
+ * @return
+ */
+ @Override
+ protected String alignStructs_withAllAlignPanels()
+ {
+ String reply = super.alignStructs_withAllAlignPanels();
+ if (reply != null)
+ {
+ statusBar.setText("Superposition failed: " + reply);
+ }
+ return reply;
+ }
}
import jalview.bin.Cache;
import jalview.datamodel.AnnotatedCollectionI;
import jalview.schemes.ColourSchemeI;
+import jalview.schemes.ColourSchemeLoader;
import jalview.schemes.ColourSchemes;
import jalview.schemes.ResidueColourScheme;
import jalview.schemes.UserColourScheme;
{
try
{
- UserColourScheme ucs = ColourSchemes.loadColourScheme(file);
+ UserColourScheme ucs = ColourSchemeLoader.loadColourScheme(file);
if (ucs != null
&& ColourSchemes.getInstance().nameExists(ucs.getName()))
{
pane12.add(nametf, BorderLayout.EAST);
panel.add(pane12, BorderLayout.NORTH);
pane12 = new JPanel(new BorderLayout());
- pane12.add(new JLabel(MessageManager.getString("label.url")),
+ pane12.add(new JLabel(MessageManager.getString("label.url:")),
BorderLayout.NORTH);
pane12.add(seqs, BorderLayout.SOUTH);
pane12.add(urltf, BorderLayout.EAST);
*/
package jalview.gui;
-import static jalview.util.UrlConstants.EMBLEBI_STRING;
import static jalview.util.UrlConstants.SEQUENCE_ID;
import jalview.api.AlignViewportI;
import jalview.jbgui.GSplitFrame;
import jalview.jbgui.GStructureViewer;
import jalview.structure.StructureSelectionManager;
+import jalview.urls.IdOrgSettings;
import jalview.util.ImageMaker;
import jalview.util.MessageManager;
import jalview.util.Platform;
+import jalview.util.UrlConstants;
import jalview.viewmodel.AlignmentViewport;
import jalview.ws.params.ParamManager;
+import jalview.ws.utils.UrlDownloadClient;
import java.awt.BorderLayout;
import java.awt.Color;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
+import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Hashtable;
showNews.setVisible(false);
+ getIdentifiersOrgData();
+
checkURLLinks();
this.addWindowListener(new WindowAdapter()
});
}
+ public void getIdentifiersOrgData()
+ {
+ // Thread off the identifiers fetcher
+ addDialogThread(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ Cache.log.debug("Downloading data from identifiers.org");
+ UrlDownloadClient client = new UrlDownloadClient();
+ try
+ {
+ client.download(IdOrgSettings.getUrl(),
+ IdOrgSettings.getDownloadLocation());
+ } catch (IOException e)
+ {
+ Cache.log.debug("Exception downloading identifiers.org data"
+ + e.getMessage());
+ }
+ }
+ });
+ }
+
@Override
protected void showNews_actionPerformed(ActionEvent e)
{
{
// check what the actual links are - if it's just the default don't
// bother with the warning
- Vector<String> links = Preferences.sequenceURLLinks;
+ List<String> links = Preferences.sequenceUrlLinks
+ .getLinksForMenu();
// only need to check links if there is one with a
// SEQUENCE_ID which is not the default EMBL_EBI link
while (li.hasNext())
{
String link = li.next();
- if (link.contains(SEQUENCE_ID) && !link.equals(EMBLEBI_STRING))
+ if (link.contains(SEQUENCE_ID)
+ && !link.equals(UrlConstants.DEFAULT_STRING))
{
check = true;
int barPos = link.indexOf("|");
import javax.swing.JColorChooser;
import javax.swing.JComboBox;
import javax.swing.JLabel;
-import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
* @version $Revision$
*/
public class FeatureRenderer extends
- jalview.renderer.seqfeatures.FeatureRenderer implements
- jalview.api.FeatureRenderer
+ jalview.renderer.seqfeatures.FeatureRenderer
{
Color resBoxColour;
if (reply == JvOptionPane.OK_OPTION && name.getText().length() > 0)
{
- // This ensures that the last sequence
- // is refreshed and new features are rendered
- lastSeq = null;
lastFeatureAdded = name.getText().trim();
lastFeatureGroupAdded = source.getText().trim();
lastDescriptionAdded = description.getText().replaceAll("\n", " ");
package jalview.gui;
import jalview.datamodel.SequenceI;
+import jalview.viewmodel.ViewportRanges;
import java.awt.BorderLayout;
import java.awt.Color;
return;
}
+ ViewportRanges ranges = av.getRanges();
+
gg.copyArea(0, 0, getWidth(), imgHeight, 0,
-vertical * av.getCharHeight());
- int ss = av.startSeq;
- int es = av.endSeq;
+ int ss = ranges.getStartSeq();
+ int es = ranges.getEndSeq();
int transY = 0;
if (vertical > 0) // scroll down
{
ss = es - vertical;
- if (ss < av.startSeq)
+ if (ss < ranges.getStartSeq())
{ // ie scrolling too fast, more than a page at a time
- ss = av.startSeq;
+ ss = ranges.getStartSeq();
}
else
{
- transY = imgHeight - (vertical * av.getCharHeight());
+ transY = imgHeight - ((vertical + 1) * av.getCharHeight());
}
}
- else if (vertical < 0)
+ else if (vertical < 0) // scroll up
{
es = ss - vertical;
- if (es > av.endSeq)
+ if (es > ranges.getEndSeq())
{
- es = av.endSeq;
+ es = ranges.getEndSeq();
}
}
gg.setColor(Color.white);
gg.fillRect(0, 0, getWidth(), imgHeight);
- drawIds(av.getStartSeq(), av.endSeq);
+ drawIds(av.getRanges().getStartSeq(), av.getRanges().getEndSeq());
g.drawImage(image, 0, 0, this);
}
int cHeight = alheight * av.getCharHeight() + hgap + annotationHeight;
- int rowSize = av.getEndRes() - av.getStartRes();
+ int rowSize = av.getRanges().getEndRes()
+ - av.getRanges().getStartRes();
// Draw the rest of the panels
- for (int ypos = hgap, row = av.startRes; (ypos <= getHeight())
+ for (int ypos = hgap, row = av.getRanges().getStartRes(); (ypos <= getHeight())
&& (row < maxwidth); ypos += cHeight, row += rowSize)
{
for (int i = starty; i < alheight; i++)
SequenceI sequence;
// Now draw the id strings
- for (int i = starty; i < endy; i++)
+ for (int i = starty; i <= endy; i++)
{
sequence = av.getAlignment().getSequenceAt(i);
import jalview.io.SequenceAnnotationReport;
import jalview.util.MessageManager;
import jalview.util.Platform;
-import jalview.util.UrlLink;
import jalview.viewmodel.AlignmentViewport;
import java.awt.BorderLayout;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.util.List;
-import java.util.Vector;
-import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.ToolTipManager;
return;
}
- Vector links = Preferences.sequenceURLLinks;
- if (links == null || links.size() < 1)
- {
- return;
- }
-
int seq = alignPanel.getSeqPanel().findSeq(e);
- String url = null;
- int i = 0;
String id = av.getAlignment().getSequenceAt(seq).getName();
- while (url == null && i < links.size())
- {
- // DEFAULT LINK IS FIRST IN THE LINK LIST
- // BUT IF ITS A REGEX AND DOES NOT MATCH THE NEXT ONE WILL BE TRIED
- url = links.elementAt(i++).toString();
- jalview.util.UrlLink urlLink = null;
- try
- {
- urlLink = new UrlLink(url);
- } catch (Exception foo)
- {
- jalview.bin.Cache.log.error("Exception for URLLink '" + url + "'",
- foo);
- url = null;
- continue;
- }
+ String url = Preferences.sequenceUrlLinks.getPrimaryUrl(id);
- if (urlLink.usesDBAccession())
- {
- // this URL requires an accession id, not the name of a sequence
- url = null;
- continue;
- }
-
- if (!urlLink.isValid())
- {
- jalview.bin.Cache.log.error(urlLink.getInvalidMessage());
- url = null;
- continue;
- }
-
- String urls[] = urlLink.makeUrls(id, true);
- if (urls == null || urls[0] == null || urls[0].length() < 4)
- {
- url = null;
- continue;
- }
- // just take first URL made from regex
- url = urls[1];
- }
try
{
jalview.util.BrowserLauncher.openURL(url);
return;
}
- if (mouseDragging && (e.getY() < 0) && (av.getStartSeq() > 0))
+ if (mouseDragging && (e.getY() < 0)
+ && (av.getRanges().getStartSeq() > 0))
{
scrollThread = new ScrollThread(true);
}
if (mouseDragging && (e.getY() >= getHeight())
- && (av.getAlignment().getHeight() > av.getEndSeq()))
+ && (av.getAlignment().getHeight() > av.getRanges().getEndSeq()))
{
scrollThread = new ScrollThread(false);
}
Sequence sq = (Sequence) av.getAlignment().getSequenceAt(seq2);
// build a new links menu based on the current links + any non-positional
// features
- Vector<String> nlinks = new Vector<String>(Preferences.sequenceURLLinks);
+ List<String> nlinks = Preferences.sequenceUrlLinks.getLinksForMenu();
SequenceFeature sfs[] = sq == null ? null : sq.getSequenceFeatures();
if (sfs != null)
{
{
for (int l = 0, lSize = sf.links.size(); l < lSize; l++)
{
- nlinks.addElement(sf.links.elementAt(l));
+ nlinks.add(sf.links.elementAt(l));
}
}
}
int index = av.getAlignment().findIndex(list.get(0));
// do we need to scroll the panel?
- if ((av.getStartSeq() > index) || (av.getEndSeq() < index))
+ if ((av.getRanges().getStartSeq() > index)
+ || (av.getRanges().getEndSeq() < index))
{
- alignPanel.setScrollValues(av.getStartRes(), index);
+ alignPanel.setScrollValues(av.getRanges().getStartRes(), index);
}
}
if (alignPanel.scrollUp(up))
{
// scroll was ok, so add new sequence to selection
- int seq = av.getStartSeq();
+ int seq = av.getRanges().getStartSeq();
if (!up)
{
- seq = av.getEndSeq();
+ seq = av.getRanges().getEndSeq();
}
if (seq < lastid)
import jalview.util.StringUtils;
import jalview.util.jarInputStreamProvider;
import jalview.viewmodel.AlignmentViewport;
+import jalview.viewmodel.ViewportRanges;
import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
import jalview.viewmodel.seqfeatures.FeaturesDisplayed;
import jalview.ws.jws2.Jws2Discoverer;
List<UserColourScheme> userColours = new ArrayList<UserColourScheme>();
AlignViewport av = ap.av;
+ ViewportRanges vpRanges = av.getRanges();
JalviewModel object = new JalviewModel();
object.setVamsasModel(new jalview.schemabinding.version2.VamsasModel());
view.setWidth(size.width);
view.setHeight(size.height);
- view.setStartRes(av.startRes);
- view.setStartSeq(av.startSeq);
+ view.setStartRes(vpRanges.getStartRes());
+ view.setStartSeq(vpRanges.getStartSeq());
if (av.getGlobalColourScheme() instanceof jalview.schemes.UserColourScheme)
{
af.viewport.setThresholdTextColour(view.getTextColThreshold());
af.viewport.setShowUnconserved(view.hasShowUnconserved() ? view
.isShowUnconserved() : false);
- af.viewport.setStartRes(view.getStartRes());
- af.viewport.setStartSeq(view.getStartSeq());
+ af.viewport.getRanges().setStartRes(view.getStartRes());
+ af.viewport.getRanges().setStartSeq(view.getStartSeq());
af.alignPanel.updateLayout();
ColourSchemeI cs = null;
// apply colourschemes
af.setBounds(view.getXpos(), view.getYpos(), view.getWidth(),
view.getHeight());
- af.viewport.setStartRes(view.getStartRes());
- af.viewport.setStartSeq(view.getStartSeq());
+ af.viewport.getRanges().setStartRes(view.getStartRes());
+ af.viewport.getRanges().setStartSeq(view.getStartSeq());
af.viewport.setShowAnnotation(view.getShowAnnotation());
af.viewport.setAbovePIDThreshold(view.getPidSelected());
af.viewport.setColourText(view.getShowColourText());
import jalview.io.DataSourceType;
import jalview.structure.StructureSelectionManager;
+import javax.swing.SwingUtilities;
+
public class JalviewChimeraBindingModel extends JalviewChimeraBinding
{
private ChimeraViewFrame cvf;
- private FeatureRenderer fr = null;
-
-
public JalviewChimeraBindingModel(ChimeraViewFrame chimeraViewFrame,
StructureSelectionManager ssm, PDBEntry[] pdbentry,
SequenceI[][] sequenceIs, DataSourceType protocol)
: (AlignmentPanel) alignment;
if (ap.av.isShowSequenceFeatures())
{
- if (fr == null)
- {
- fr = (jalview.gui.FeatureRenderer) ap.cloneFeatureRenderer();
- }
- else
- {
- ap.updateFeatureRenderer(fr);
- }
+ return ap.getSeqPanel().seqCanvas.fr;
}
- return fr;
+ return null;
}
@Override
protected void sendAsynchronousCommand(final String command,
final String progressMsg)
{
- Thread thread = new Thread(new Runnable()
+ final long handle = progressMsg == null ? 0 : cvf
+ .startProgressBar(progressMsg);
+ SwingUtilities.invokeLater(new Runnable()
{
-
@Override
public void run()
{
- long stm = cvf.startProgressBar(progressMsg);
try
{
sendChimeraCommand(command, false);
} finally
{
- cvf.stopProgressBar(null, stm);
+ if (progressMsg != null)
+ {
+ cvf.stopProgressBar(null, handle);
+ }
}
}
});
- thread.start();
-
}
@Override
*/
package jalview.gui;
+import jalview.datamodel.SequenceI;
import jalview.renderer.AnnotationRenderer;
+import jalview.renderer.seqfeatures.FeatureColourFinder;
+import jalview.viewmodel.OverviewDimensions;
import java.awt.Color;
import java.awt.Dimension;
import javax.swing.JPanel;
/**
- * DOCUMENT ME!
+ * Panel displaying an overview of the full alignment, with an interactive box
+ * representing the viewport onto the alignment.
*
* @author $author$
* @version $Revision$
*/
public class OverviewPanel extends JPanel implements Runnable
{
- BufferedImage miniMe;
+ private static final Color TRANS_GREY = new Color(100, 100, 100, 25);
- AlignViewport av;
+ private final AnnotationRenderer renderer = new AnnotationRenderer();
- AlignmentPanel ap;
+ private OverviewDimensions od;
- final AnnotationRenderer renderer = new AnnotationRenderer();
+ private BufferedImage miniMe;
- float scalew = 1f;
-
- float scaleh = 1f;
-
- int width;
-
- int sequencesHeight;
-
- int graphHeight = 20;
-
- int boxX = -1;
+ private BufferedImage lastMiniMe = null;
- int boxY = -1;
+ private AlignViewport av;
- int boxWidth = -1;
+ private AlignmentPanel ap;
- int boxHeight = -1;
+ //
+ private boolean resizing = false;
- boolean resizing = false;
+ // This is set true if the user resizes whilst
+ // the overview is being calculated
+ private boolean resizeAgain = false;
// Can set different properties in this seqCanvas than
// main visible SeqCanvas
- SequenceRenderer sr;
+ private SequenceRenderer sr;
jalview.renderer.seqfeatures.FeatureRenderer fr;
/**
* Creates a new OverviewPanel object.
*
- * @param ap
- * DOCUMENT ME!
+ * @param alPanel
+ * The alignment panel which is shown in the overview panel
*/
- public OverviewPanel(AlignmentPanel ap)
+ public OverviewPanel(AlignmentPanel alPanel)
{
- this.av = ap.av;
- this.ap = ap;
+ this.av = alPanel.av;
+ this.ap = alPanel;
setLayout(null);
sr = new SequenceRenderer(av);
sr.forOverview = true;
fr = new FeatureRenderer(ap);
- // scale the initial size of overviewpanel to shape of alignment
- float initialScale = (float) av.getAlignment().getWidth()
- / (float) av.getAlignment().getHeight();
-
- if (av.getAlignmentConservationAnnotation() == null)
- {
- graphHeight = 0;
- }
-
- if (av.getAlignment().getWidth() > av.getAlignment().getHeight())
- {
- // wider
- width = 400;
- sequencesHeight = (int) (400f / initialScale);
- if (sequencesHeight < 40)
- {
- sequencesHeight = 40;
- }
- }
- else
- {
- // taller
- width = (int) (400f * initialScale);
- sequencesHeight = 300;
-
- if (width < 120)
- {
- width = 120;
- }
- }
+ od = new OverviewDimensions(av.getRanges(),
+ (av.isShowAnnotation() && av
+ .getAlignmentConservationAnnotation() != null));
addComponentListener(new ComponentAdapter()
{
@Override
public void componentResized(ComponentEvent evt)
{
- if ((getWidth() != width)
- || (getHeight() != (sequencesHeight + graphHeight)))
+ if ((getWidth() != od.getWidth())
+ || (getHeight() != (od.getHeight())))
{
updateOverviewImage();
}
{
if (!av.getWrapAlignment())
{
- // TODO: feature: jv2.5 detect shift drag and update selection from
- // it.
- boxX = evt.getX();
- boxY = evt.getY();
- checkValid();
+ od.updateViewportFromMouse(evt.getX(), evt.getY(), av
+ .getAlignment().getHiddenSequences(), av
+ .getColumnSelection(), av.getRanges());
+ ap.setScrollValues(od.getScrollCol(), od.getScrollRow());
}
}
});
{
if (!av.getWrapAlignment())
{
- boxX = evt.getX();
- boxY = evt.getY();
- checkValid();
+ od.updateViewportFromMouse(evt.getX(), evt.getY(), av
+ .getAlignment().getHiddenSequences(), av
+ .getColumnSelection(), av.getRanges());
+ ap.setScrollValues(od.getScrollCol(), od.getScrollRow());
}
}
});
}
/**
- * DOCUMENT ME!
- */
- void checkValid()
- {
- if (boxY < 0)
- {
- boxY = 0;
- }
-
- if (boxY > (sequencesHeight - boxHeight))
- {
- boxY = sequencesHeight - boxHeight + 1;
- }
-
- if (boxX < 0)
- {
- boxX = 0;
- }
-
- if (boxX > (width - boxWidth))
- {
- if (av.hasHiddenColumns())
- {
- // Try smallest possible box
- boxWidth = (int) ((av.endRes - av.startRes + 1) * av.getCharWidth() * scalew);
- }
- boxX = width - boxWidth;
- }
-
- int col = (int) (boxX / scalew / av.getCharWidth());
- int row = (int) (boxY / scaleh / av.getCharHeight());
-
- if (av.hasHiddenColumns())
- {
- if (!av.getColumnSelection().isVisible(col))
- {
- return;
- }
-
- col = av.getColumnSelection().findColumnPosition(col);
- }
-
- if (av.hasHiddenRows())
- {
- row = av.getAlignment().getHiddenSequences()
- .findIndexWithoutHiddenSeqs(row);
- }
-
- ap.setScrollValues(col, row);
-
- }
-
- /**
- * DOCUMENT ME!
+ * Updates the overview image when the related alignment panel is updated
*/
public void updateOverviewImage()
{
if ((getWidth() > 0) && (getHeight() > 0))
{
- width = getWidth();
- sequencesHeight = getHeight() - graphHeight;
+ od.setWidth(getWidth());
+ od.setHeight(getHeight());
}
- setPreferredSize(new Dimension(width, sequencesHeight + graphHeight));
+ setPreferredSize(new Dimension(od.getWidth(), od.getHeight()));
Thread thread = new Thread(this);
thread.start();
repaint();
}
- // This is set true if the user resizes whilst
- // the overview is being calculated
- boolean resizeAgain = false;
-
- /**
- * DOCUMENT ME!
- */
@Override
public void run()
{
fr.transferSettings(ap.getSeqPanel().seqCanvas.getFeatureRenderer());
}
- int alwidth = av.getAlignment().getWidth();
- int alheight = av.getAlignment().getHeight()
- + av.getAlignment().getHiddenSequences().getSize();
-
- setPreferredSize(new Dimension(width, sequencesHeight + graphHeight));
-
- int fullsizeWidth = alwidth * av.getCharWidth();
- int fullsizeHeight = alheight * av.getCharHeight();
+ // why do we need to set preferred size again? was set in
+ // updateOverviewImage
+ setPreferredSize(new Dimension(od.getWidth(), od.getHeight()));
- scalew = (float) width / (float) fullsizeWidth;
- scaleh = (float) sequencesHeight / (float) fullsizeHeight;
-
- miniMe = new BufferedImage(width, sequencesHeight + graphHeight,
+ miniMe = new BufferedImage(od.getWidth(), od.getHeight(),
BufferedImage.TYPE_INT_RGB);
Graphics mg = miniMe.getGraphics();
mg.setColor(Color.orange);
- mg.fillRect(0, 0, width, miniMe.getHeight());
-
- float sampleCol = (float) alwidth / (float) width;
- float sampleRow = (float) alheight / (float) sequencesHeight;
+ mg.fillRect(0, 0, od.getWidth(), miniMe.getHeight());
- int lastcol = -1, lastrow = -1;
- int color = Color.white.getRGB();
- int row, col;
- jalview.datamodel.SequenceI seq;
- final boolean hasHiddenRows = av.hasHiddenRows(), hasHiddenCols = av
- .hasHiddenColumns();
- boolean hiddenRow = false;
- // get hidden row and hidden column map once at beginning.
- // clone featureRenderer settings to avoid race conditions... if state is
- // updated just need to refresh again
- for (row = 0; row < sequencesHeight; row++)
- {
- if (resizeAgain)
- {
- break;
- }
- if ((int) (row * sampleRow) == lastrow)
- {
- // No need to recalculate the colours,
- // Just copy from the row above
- for (col = 0; col < width; col++)
- {
- if (resizeAgain)
- {
- break;
- }
- miniMe.setRGB(col, row, miniMe.getRGB(col, row - 1));
- }
- continue;
- }
-
- lastrow = (int) (row * sampleRow);
-
- hiddenRow = false;
- if (hasHiddenRows)
- {
- seq = av.getAlignment().getHiddenSequences()
- .getHiddenSequence(lastrow);
- if (seq == null)
- {
- int index = av.getAlignment().getHiddenSequences()
- .findIndexWithoutHiddenSeqs(lastrow);
-
- seq = av.getAlignment().getSequenceAt(index);
- }
- else
- {
- hiddenRow = true;
- }
- }
- else
- {
- seq = av.getAlignment().getSequenceAt(lastrow);
- }
-
- if (seq == null)
- {
- System.out.println(lastrow + " null");
- continue;
- }
-
- for (col = 0; col < width; col++)
- {
- if (resizeAgain)
- {
- break;
- }
- if ((int) (col * sampleCol) == lastcol
- && (int) (row * sampleRow) == lastrow)
- {
- miniMe.setRGB(col, row, color);
- continue;
- }
-
- lastcol = (int) (col * sampleCol);
-
- if (seq.getLength() > lastcol)
- {
- color = sr.getResidueBoxColour(seq, lastcol).getRGB();
-
- if (av.isShowSequenceFeatures())
- {
- color = fr.findFeatureColour(color, seq, lastcol);
- }
- }
- else
- {
- color = -1; // White
- }
+ // calculate sampleCol and sampleRow
+ // alignment width is max number of residues/bases
+ // alignment height is number of sequences
+ int alwidth = av.getAlignment().getWidth();
+ int alheight = av.getAlignment().getAbsoluteHeight();
- if (hiddenRow
- || (hasHiddenCols && !av.getColumnSelection().isVisible(
- lastcol)))
- {
- color = new Color(color).darker().darker().getRGB();
- }
+ // sampleCol or sampleRow is the width/height allocated to each residue
+ // in particular, sometimes we may need more than one row/col of the
+ // BufferedImage allocated
+ // sampleCol is how much of a residue to assign to each pixel
+ // sampleRow is how many sequences to assign to each pixel
+ float sampleCol = alwidth / (float) od.getWidth();
+ float sampleRow = alheight / (float) od.getSequencesHeight();
- miniMe.setRGB(col, row, color);
+ buildImage(sampleRow, sampleCol);
- }
- }
-
- if (av.getAlignmentConservationAnnotation() != null)
+ // check for conservation annotation to make sure overview works for DNA too
+ if (av.isShowAnnotation()
+ && (av.getAlignmentConservationAnnotation() != null))
{
renderer.updateFromAlignViewport(av);
- for (col = 0; col < width; col++)
+ for (int col = 0; col < od.getWidth() && !resizeAgain; col++)
{
- if (resizeAgain)
- {
- break;
- }
- lastcol = (int) (col * sampleCol);
- {
- mg.translate(col, sequencesHeight);
- renderer.drawGraph(mg, av.getAlignmentConservationAnnotation(),
- av.getAlignmentConservationAnnotation().annotations,
- (int) (sampleCol) + 1, graphHeight,
- (int) (col * sampleCol), (int) (col * sampleCol) + 1);
- mg.translate(-col, -sequencesHeight);
- }
+ mg.translate(col, od.getSequencesHeight());
+ renderer.drawGraph(mg, av.getAlignmentConservationAnnotation(),
+ av.getAlignmentConservationAnnotation().annotations,
+ (int) (sampleCol) + 1, od.getGraphHeight(),
+ (int) (col * sampleCol), (int) (col * sampleCol) + 1);
+ mg.translate(-col, -od.getSequencesHeight());
+
}
}
System.gc();
setBoxPosition();
}
- /**
- * DOCUMENT ME!
+ /*
+ * Build the overview panel image
*/
- public void setBoxPosition()
+ private void buildImage(float sampleRow, float sampleCol)
{
- int fullsizeWidth = av.getAlignment().getWidth() * av.getCharWidth();
- int fullsizeHeight = (av.getAlignment().getHeight() + av.getAlignment()
- .getHiddenSequences().getSize())
- * av.getCharHeight();
+ int lastcol = -1;
+ int lastrow = -1;
+ int rgbColour = Color.white.getRGB();
- int startRes = av.getStartRes();
- int endRes = av.getEndRes();
+ SequenceI seq = null;
+ FeatureColourFinder finder = new FeatureColourFinder(fr);
- if (av.hasHiddenColumns())
+ final boolean hasHiddenCols = av.hasHiddenColumns();
+ boolean hiddenRow = false;
+ // get hidden row and hidden column map once at beginning.
+ // clone featureRenderer settings to avoid race conditions... if state is
+ // updated just need to refresh again
+ for (int row = 0; row < od.getSequencesHeight() && !resizeAgain; row++)
{
- startRes = av.getColumnSelection().adjustForHiddenColumns(startRes);
- endRes = av.getColumnSelection().adjustForHiddenColumns(endRes);
- }
+ boolean doCopy = true;
+ int currentrow = (int) (row * sampleRow);
+ if (currentrow != lastrow)
+ {
+ doCopy = false;
- int startSeq = av.startSeq;
- int endSeq = av.endSeq;
+ lastrow = currentrow;
- if (av.hasHiddenRows())
- {
- startSeq = av.getAlignment().getHiddenSequences()
- .adjustForHiddenSeqs(startSeq);
+ // get the sequence which would be at alignment index 'lastrow' if no
+ // rows were hidden, and determine whether it is hidden or not
+ hiddenRow = av.getAlignment().isHidden(lastrow);
+ seq = av.getAlignment().getSequenceAtAbsoluteIndex(lastrow);
+ }
- endSeq = av.getAlignment().getHiddenSequences()
- .adjustForHiddenSeqs(endSeq);
+ for (int col = 0; col < od.getWidth() && !resizeAgain; col++)
+ {
+ if (doCopy)
+ {
+ rgbColour = miniMe.getRGB(col, row - 1);
+ }
+ else if ((int) (col * sampleCol) != lastcol
+ || (int) (row * sampleRow) != lastrow)
+ {
+ lastcol = (int) (col * sampleCol);
+ rgbColour = getColumnColourFromSequence(seq, hiddenRow,
+ hasHiddenCols, lastcol, finder);
+ }
+ // else we just use the color we already have , so don't need to set it
+ miniMe.setRGB(col, row, rgbColour);
+ }
}
+ }
- scalew = (float) width / (float) fullsizeWidth;
- scaleh = (float) sequencesHeight / (float) fullsizeHeight;
-
- boxX = (int) (startRes * av.getCharWidth() * scalew);
- boxY = (int) (startSeq * av.getCharHeight() * scaleh);
+ /*
+ * Find the colour of a sequence at a specified column position
+ */
+ private int getColumnColourFromSequence(
+ jalview.datamodel.SequenceI seq,
+ boolean hiddenRow, boolean hasHiddenCols, int lastcol,
+ FeatureColourFinder finder)
+ {
+ Color color = Color.white;
- if (av.hasHiddenColumns())
+ if ((seq != null) && (seq.getLength() > lastcol))
{
- boxWidth = (int) ((endRes - startRes + 1) * av.getCharWidth() * scalew);
+ color = sr.getResidueColour(seq, lastcol, finder);
}
- else
+
+ if (hiddenRow
+ || (hasHiddenCols && !av.getColumnSelection()
+ .isVisible(lastcol)))
{
- boxWidth = (int) ((endRes - startRes + 1) * av.getCharWidth() * scalew);
+ color = color.darker().darker();
}
- boxHeight = (int) ((endSeq - startSeq) * av.getCharHeight() * scaleh);
-
- repaint();
+ return color.getRGB();
}
- private BufferedImage lastMiniMe = null;
-
/**
- * DOCUMENT ME!
+ * Update the overview panel box when the associated alignment panel is
+ * changed
*
- * @param g
- * DOCUMENT ME!
*/
+ public void setBoxPosition()
+ {
+ od.setBoxPosition(av.getAlignment()
+ .getHiddenSequences(), av.getColumnSelection(), av.getRanges());
+ repaint();
+ }
+
+
@Override
public void paintComponent(Graphics g)
{
{
g.drawImage(lastMiniMe, 0, 0, getWidth(), getHeight(), this);
}
- g.setColor(new Color(100, 100, 100, 25));
+ g.setColor(TRANS_GREY);
g.fillRect(0, 0, getWidth(), getHeight());
}
else if (lastMiniMe != null)
g.drawImage(lastMiniMe, 0, 0, this);
if (lastMiniMe != miniMe)
{
- g.setColor(new Color(100, 100, 100, 25));
+ g.setColor(TRANS_GREY);
g.fillRect(0, 0, getWidth(), getHeight());
}
}
- // TODO: render selected regions
+
g.setColor(Color.red);
- g.drawRect(boxX, boxY, boxWidth, boxHeight);
- g.drawRect(boxX + 1, boxY + 1, boxWidth - 2, boxHeight - 2);
+ od.drawBox(g);
}
}
*/
package jalview.gui;
-import static jalview.util.UrlConstants.DB_ACCESSION;
-import static jalview.util.UrlConstants.EMBLEBI_STRING;
-import static jalview.util.UrlConstants.SEQUENCE_ID;
-import static jalview.util.UrlConstants.SRS_STRING;
-
import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder;
import jalview.bin.Cache;
import jalview.gui.Help.HelpId;
import jalview.schemes.ColourSchemeI;
import jalview.schemes.ColourSchemes;
import jalview.schemes.ResidueColourScheme;
+import jalview.urls.UrlLinkTableModel;
+import jalview.urls.api.UrlProviderFactoryI;
+import jalview.urls.api.UrlProviderI;
+import jalview.urls.desktop.DesktopUrlProviderFactory;
import jalview.util.MessageManager;
import jalview.util.Platform;
+import jalview.util.UrlConstants;
import jalview.ws.sifts.SiftsSettings;
import java.awt.BorderLayout;
import java.awt.Color;
+import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
-import java.util.StringTokenizer;
-import java.util.Vector;
import javax.help.HelpSetException;
import javax.swing.JColorChooser;
import javax.swing.JFileChooser;
import javax.swing.JInternalFrame;
import javax.swing.JPanel;
+import javax.swing.ListSelectionModel;
+import javax.swing.RowFilter;
+import javax.swing.RowSorter;
+import javax.swing.SortOrder;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import javax.swing.table.TableCellRenderer;
+import javax.swing.table.TableColumn;
+import javax.swing.table.TableModel;
+import javax.swing.table.TableRowSorter;
import ext.edu.ucsf.rbvi.strucviz2.StructureManager;
* Holds name and link separated with | character. Sequence ID must be
* $SEQUENCE_ID$ or $SEQUENCE_ID=/.possible | chars ./=$
*/
- public static Vector<String> sequenceURLLinks;
+ public static UrlProviderI sequenceUrlLinks;
+
+ public static UrlLinkTableModel dataModel;
/**
* Holds name and link separated with | character. Sequence IDS and Sequences
public static List<String> groupURLLinks;
static
{
- String string = Cache.getDefault("SEQUENCE_LINKS", EMBLEBI_STRING);
- sequenceURLLinks = new Vector<String>();
-
- try
+ // get links selected to be in the menu (SEQUENCE_LINKS)
+ // and links entered by the user but not selected (STORED_LINKS)
+ String inMenuString = Cache.getDefault("SEQUENCE_LINKS", "");
+ String notInMenuString = Cache.getDefault("STORED_LINKS", "");
+ String defaultUrl = Cache.getDefault("DEFAULT_URL",
+ UrlConstants.DEFAULT_LABEL);
+
+ // if both links lists are empty, add the DEFAULT_URL link
+ // otherwise we assume the default link is in one of the lists
+ if (inMenuString.isEmpty() && notInMenuString.isEmpty())
{
- StringTokenizer st = new StringTokenizer(string, "|");
- while (st.hasMoreElements())
- {
- String name = st.nextToken();
- String url = st.nextToken();
- // check for '|' within a regex
- int rxstart = url.indexOf("$" + DB_ACCESSION + "$");
- if (rxstart == -1)
- {
- rxstart = url.indexOf("$" + SEQUENCE_ID + "$");
- }
- while (rxstart == -1 && url.indexOf("/=$") == -1)
- {
- url = url + "|" + st.nextToken();
- }
- sequenceURLLinks.addElement(name + "|" + url);
- }
- } catch (Exception ex)
- {
- System.out.println(ex + "\nError parsing sequence links");
- }
- {
- // upgrade old SRS link
- int srsPos = sequenceURLLinks.indexOf(SRS_STRING);
- if (srsPos > -1)
- {
- sequenceURLLinks.setElementAt(EMBLEBI_STRING, srsPos);
- }
+ inMenuString = UrlConstants.DEFAULT_STRING;
}
+ UrlProviderFactoryI factory = new DesktopUrlProviderFactory(defaultUrl,
+ inMenuString, notInMenuString);
+ sequenceUrlLinks = factory.createUrlProvider();
+ dataModel = new UrlLinkTableModel(sequenceUrlLinks);
/**
* TODO: reformulate groupURL encoding so two or more can be stored in the
groupURLLinks = new ArrayList<String>();
}
- Vector<String> nameLinks, urlLinks;
-
JInternalFrame frame;
DasSourceBrowser dasSource;
/*
* Set Connections tab defaults
*/
- nameLinks = new Vector<String>();
- urlLinks = new Vector<String>();
- for (int i = 0; i < sequenceURLLinks.size(); i++)
+
+ // set up sorting
+ linkUrlTable.setModel(dataModel);
+ final TableRowSorter<TableModel> sorter = new TableRowSorter<>(
+ linkUrlTable.getModel());
+ linkUrlTable.setRowSorter(sorter);
+ List<RowSorter.SortKey> sortKeys = new ArrayList<>();
+
+ UrlLinkTableModel m = (UrlLinkTableModel) linkUrlTable.getModel();
+ sortKeys.add(new RowSorter.SortKey(m.getPrimaryColumn(),
+ SortOrder.DESCENDING));
+ sortKeys.add(new RowSorter.SortKey(m.getSelectedColumn(),
+ SortOrder.DESCENDING));
+ sortKeys.add(new RowSorter.SortKey(m.getNameColumn(),
+ SortOrder.ASCENDING));
+
+ sorter.setSortKeys(sortKeys);
+ sorter.sort();
+
+ // set up filtering
+ ActionListener onReset;
+ onReset = new ActionListener()
{
- String link = sequenceURLLinks.elementAt(i).toString();
- nameLinks.addElement(link.substring(0, link.indexOf("|")));
- urlLinks.addElement(link.substring(link.indexOf("|") + 1));
- }
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ filterTB.setText("");
+ sorter.setRowFilter(RowFilter.regexFilter(""));
+ }
+
+ };
+ doReset.addActionListener(onReset);
+
+ // filter to display only custom urls
+ final RowFilter<TableModel, Object> customUrlFilter = new RowFilter<TableModel, Object>()
+ {
+ @Override
+ public boolean include(
+ Entry<? extends TableModel, ? extends Object> entry)
+ {
+ return ((UrlLinkTableModel) entry.getModel()).isUserEntry(entry);
+ }
+ };
+
+ final TableRowSorter<TableModel> customSorter = new TableRowSorter<>(
+ linkUrlTable.getModel());
+ customSorter.setRowFilter(customUrlFilter);
+
+ ActionListener onCustomOnly;
+ onCustomOnly = new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ filterTB.setText("");
+ sorter.setRowFilter(customUrlFilter);
+ }
+ };
+ userOnly.addActionListener(onCustomOnly);
+
+ filterTB.getDocument().addDocumentListener(new DocumentListener()
+ {
+ String caseInsensitiveFlag = "(?i)";
- updateLinkData();
+ @Override
+ public void changedUpdate(DocumentEvent e)
+ {
+ sorter.setRowFilter(RowFilter.regexFilter(caseInsensitiveFlag
+ + filterTB.getText()));
+ }
+
+ @Override
+ public void removeUpdate(DocumentEvent e)
+ {
+ sorter.setRowFilter(RowFilter.regexFilter(caseInsensitiveFlag
+ + filterTB.getText()));
+ }
+
+ @Override
+ public void insertUpdate(DocumentEvent e)
+ {
+ sorter.setRowFilter(RowFilter.regexFilter(caseInsensitiveFlag
+ + filterTB.getText()));
+ }
+ });
+
+ // set up list selection functionality
+ linkUrlTable.getSelectionModel().addListSelectionListener(
+ new UrlListSelectionHandler());
+
+ // set up radio buttons
+ int onClickCol = ((UrlLinkTableModel) linkUrlTable.getModel())
+ .getPrimaryColumn();
+ String onClickName = linkUrlTable.getColumnName(onClickCol);
+ linkUrlTable.getColumn(onClickName).setCellRenderer(
+ new RadioButtonRenderer());
+ linkUrlTable.getColumn(onClickName)
+ .setCellEditor(new RadioButtonEditor());
+
+ // get boolean columns and resize those to min possible
+ for (int column = 0; column < linkUrlTable.getColumnCount(); column++)
+ {
+ if (linkUrlTable.getModel().getColumnClass(column)
+ .equals(Boolean.class))
+ {
+ TableColumn tableColumn = linkUrlTable.getColumnModel().getColumn(
+ column);
+ int preferredWidth = tableColumn.getMinWidth();
+
+ TableCellRenderer cellRenderer = linkUrlTable.getCellRenderer(0,
+ column);
+ Component c = linkUrlTable.prepareRenderer(cellRenderer, 0, column);
+ int cwidth = c.getPreferredSize().width
+ + linkUrlTable.getIntercellSpacing().width;
+ preferredWidth = Math.max(preferredWidth, cwidth);
+
+ tableColumn.setPreferredWidth(preferredWidth);
+ }
+ }
useProxy.setSelected(Cache.getDefault("USE_PROXY", false));
- proxyServerTB.setEnabled(useProxy.isSelected());
- proxyPortTB.setEnabled(useProxy.isSelected());
+ useProxy_actionPerformed(); // make sure useProxy is correctly initialised
proxyServerTB.setText(Cache.getDefault("PROXY_SERVER", ""));
proxyPortTB.setText(Cache.getDefault("PROXY_PORT", ""));
jalview.util.BrowserLauncher.resetBrowser();
- if (nameLinks.size() > 0)
+ // save user-defined and selected links
+ String menuLinks = sequenceUrlLinks.writeUrlsAsString(true);
+ if (menuLinks.isEmpty())
+ {
+ Cache.applicationProperties.remove("SEQUENCE_LINKS");
+ }
+ else
{
- StringBuffer links = new StringBuffer();
- sequenceURLLinks = new Vector<String>();
- for (int i = 0; i < nameLinks.size(); i++)
- {
- sequenceURLLinks.addElement(nameLinks.elementAt(i) + "|"
- + urlLinks.elementAt(i));
- links.append(sequenceURLLinks.elementAt(i).toString());
- links.append("|");
- }
- // remove last "|"
- links.setLength(links.length() - 1);
Cache.applicationProperties.setProperty("SEQUENCE_LINKS",
- links.toString());
+ menuLinks.toString());
+ }
+
+ String nonMenuLinks = sequenceUrlLinks.writeUrlsAsString(false);
+ if (nonMenuLinks.isEmpty())
+ {
+ Cache.applicationProperties.remove("STORED_LINKS");
}
else
{
- Cache.applicationProperties.remove("SEQUENCE_LINKS");
- sequenceURLLinks.clear();
+ Cache.applicationProperties.setProperty("STORED_LINKS",
+ nonMenuLinks.toString());
}
+ Cache.applicationProperties.setProperty("DEFAULT_URL",
+ sequenceUrlLinks.getPrimaryUrlId());
+
Cache.applicationProperties.setProperty("USE_PROXY",
Boolean.toString(useProxy.isSelected()));
@Override
public void newLink_actionPerformed(ActionEvent e)
{
-
GSequenceLink link = new GSequenceLink();
boolean valid = false;
while (!valid)
{
if (link.checkValid())
{
- nameLinks.addElement(link.getName());
- urlLinks.addElement(link.getURL());
- updateLinkData();
- valid = true;
+ if (((UrlLinkTableModel) linkUrlTable.getModel())
+ .isUniqueName(link.getName()))
+ {
+ ((UrlLinkTableModel) linkUrlTable.getModel()).insertRow(
+ link.getName(), link.getURL());
+ valid = true;
+ }
+ else
+ {
+ link.notifyDuplicate();
+ continue;
+ }
}
}
else
{
GSequenceLink link = new GSequenceLink();
- int index = linkNameList.getSelectedIndex();
+ int index = linkUrlTable.getSelectedRow();
if (index == -1)
{
- JvOptionPane.showInternalMessageDialog(Desktop.desktop,
- MessageManager.getString("label.no_link_selected"),
- MessageManager.getString("label.no_link_selected"),
- JvOptionPane.WARNING_MESSAGE);
+ // button no longer enabled if row is not selected
+ Cache.log.debug("Edit with no row selected in linkUrlTable");
return;
}
- link.setName(nameLinks.elementAt(index).toString());
- link.setURL(urlLinks.elementAt(index).toString());
+ int nameCol = ((UrlLinkTableModel) linkUrlTable.getModel())
+ .getNameColumn();
+ int urlCol = ((UrlLinkTableModel) linkUrlTable.getModel())
+ .getUrlColumn();
+ String oldName = linkUrlTable.getValueAt(index, nameCol).toString();
+ link.setName(oldName);
+ link.setURL(linkUrlTable.getValueAt(index, urlCol).toString());
boolean valid = false;
while (!valid)
{
-
if (JvOptionPane.showInternalConfirmDialog(Desktop.desktop, link,
- MessageManager.getString("label.new_sequence_url_link"),
+ MessageManager.getString("label.edit_sequence_url_link"),
JvOptionPane.OK_CANCEL_OPTION, -1, null) == JvOptionPane.OK_OPTION)
{
if (link.checkValid())
{
- nameLinks.setElementAt(link.getName(), index);
- urlLinks.setElementAt(link.getURL(), index);
- updateLinkData();
- valid = true;
+ if ((oldName.equals(link.getName()))
+ || (((UrlLinkTableModel) linkUrlTable.getModel())
+ .isUniqueName(link.getName())))
+ {
+ linkUrlTable.setValueAt(link.getName(), index, nameCol);
+ linkUrlTable.setValueAt(link.getURL(), index, urlCol);
+ valid = true;
+ }
+ else
+ {
+ link.notifyDuplicate();
+ continue;
+ }
}
}
-
else
{
break;
@Override
public void deleteLink_actionPerformed(ActionEvent e)
{
- int index = linkNameList.getSelectedIndex();
+ int index = linkUrlTable.getSelectedRow();
+ int modelIndex = -1;
if (index == -1)
{
- JvOptionPane.showInternalMessageDialog(Desktop.desktop,
- MessageManager.getString("label.no_link_selected"),
- MessageManager.getString("label.no_link_selected"),
- JvOptionPane.WARNING_MESSAGE);
+ // button no longer enabled if row is not selected
+ Cache.log.debug("Delete with no row selected in linkUrlTable");
return;
}
- nameLinks.removeElementAt(index);
- urlLinks.removeElementAt(index);
- updateLinkData();
- }
+ else
+ {
+ modelIndex = linkUrlTable.convertRowIndexToModel(index);
+ }
- void updateLinkData()
- {
- linkNameList.setListData(nameLinks);
- linkURLList.setListData(urlLinks);
+ // make sure we use the model index to delete, and not the table index
+ ((UrlLinkTableModel) linkUrlTable.getModel()).removeRow(modelIndex);
}
+
@Override
public void defaultBrowser_mouseClicked(MouseEvent e)
{
return name.hashCode() + code.hashCode();
}
}
+
+ private class UrlListSelectionHandler implements ListSelectionListener
+ {
+
+ @Override
+ public void valueChanged(ListSelectionEvent e)
+ {
+ ListSelectionModel lsm = (ListSelectionModel) e.getSource();
+
+ int index = lsm.getMinSelectionIndex();
+ if (index == -1)
+ {
+ // no selection, so disable delete/edit buttons
+ editLink.setEnabled(false);
+ deleteLink.setEnabled(false);
+ return;
+ }
+ int modelIndex = linkUrlTable.convertRowIndexToModel(index);
+
+ // enable/disable edit and delete link buttons
+ if (((UrlLinkTableModel) linkUrlTable.getModel())
+ .isRowDeletable(modelIndex))
+ {
+ deleteLink.setEnabled(true);
+ }
+ else
+ {
+ deleteLink.setEnabled(false);
+ }
+
+ if (((UrlLinkTableModel) linkUrlTable.getModel())
+ .isRowEditable(modelIndex))
+ {
+ editLink.setEnabled(true);
+ }
+ else
+ {
+ editLink.setEnabled(false);
+ }
+ }
+}
}
@Override
public void mousePressed(MouseEvent evt)
{
- int x = (evt.getX() / av.getCharWidth()) + av.getStartRes();
+ int x = (evt.getX() / av.getCharWidth()) + av.getRanges().getStartRes();
final int res;
if (av.hasHiddenColumns())
{
mouseDragging = false;
- int res = (evt.getX() / av.getCharWidth()) + av.getStartRes();
+ int res = (evt.getX() / av.getCharWidth())
+ + av.getRanges().getStartRes();
if (av.hasHiddenColumns())
{
mouseDragging = true;
ColumnSelection cs = av.getColumnSelection();
- int res = (evt.getX() / av.getCharWidth()) + av.getStartRes();
+ int res = (evt.getX() / av.getCharWidth())
+ + av.getRanges().getStartRes();
res = Math.max(0, res);
res = cs.adjustForHiddenColumns(res);
res = Math.min(res, av.getAlignment().getWidth() - 1);
return;
}
- int res = (evt.getX() / av.getCharWidth()) + av.getStartRes();
+ int res = (evt.getX() / av.getCharWidth())
+ + av.getRanges().getStartRes();
res = av.getColumnSelection().adjustForHiddenColumns(res);
@Override
public void paintComponent(Graphics g)
{
- drawScale(g, av.getStartRes(), av.getEndRes(), getWidth(), getHeight());
+ drawScale(g, av.getRanges().getStartRes(), av.getRanges().getEndRes(),
+ getWidth(), getHeight());
}
// scalewidth will normally be screenwidth,
import jalview.datamodel.SequenceI;
import jalview.renderer.ScaleRenderer;
import jalview.renderer.ScaleRenderer.ScaleMark;
+import jalview.viewmodel.ViewportRanges;
import java.awt.BasicStroke;
import java.awt.BorderLayout;
gg.copyArea(horizontal * charWidth, vertical * charHeight, imgWidth,
imgHeight, -horizontal * charWidth, -vertical * charHeight);
- int sr = av.startRes;
- int er = av.endRes;
- int ss = av.startSeq;
- int es = av.endSeq;
+ ViewportRanges ranges = av.getRanges();
+ int sr = ranges.getStartRes();
+ int er = ranges.getEndRes();
+ int ss = ranges.getStartSeq();
+ int es = ranges.getEndSeq();
int transX = 0;
int transY = 0;
{
ss = es - vertical;
- if (ss < av.startSeq)
+ if (ss < ranges.getStartSeq())
{ // ie scrolling too fast, more than a page at a time
- ss = av.startSeq;
+ ss = ranges.getStartSeq();
}
else
{
- transY = imgHeight - (vertical * charHeight);
+ transY = imgHeight - ((vertical + 1) * charHeight);
}
}
else if (vertical < 0)
{
es = ss - vertical;
- if (es > av.endSeq)
+ if (es > ranges.getEndSeq())
{
- es = av.endSeq;
+ es = ranges.getEndSeq();
}
}
gg.setColor(Color.white);
gg.fillRect(0, 0, imgWidth, imgHeight);
+ ViewportRanges ranges = av.getRanges();
if (av.getWrapAlignment())
{
- drawWrappedPanel(gg, getWidth(), getHeight(), av.startRes);
+ drawWrappedPanel(gg, getWidth(), getHeight(), ranges.getStartRes());
}
else
{
- drawPanel(gg, av.startRes, av.endRes, av.startSeq, av.endSeq, 0);
+ drawPanel(gg, ranges.getStartRes(), ranges.getEndRes(),
+ ranges.getStartSeq(), ranges.getEndSeq(), 0);
}
g.drawImage(lcimg, 0, 0, this);
av.setWrappedWidth(cWidth);
- av.endRes = av.startRes + cWidth;
+ av.getRanges().setEndRes(av.getRanges().getStartRes() + cWidth);
int endx;
int ypos = hgap;
// / First draw the sequences
// ///////////////////////////
- for (int i = startSeq; i < endSeq; i++)
+ for (int i = startSeq; i <= endSeq; i++)
{
nextSeq = av.getAlignment().getSequenceAt(i);
if (nextSeq == null)
if (av.isShowSequenceFeatures())
{
fr.drawSequence(g, nextSeq, startRes, endRes, offset
- + ((i - startSeq) * charHeight));
+ + ((i - startSeq) * charHeight), false);
}
// / Highlight search Results once all sequences have been drawn
int top = -1;
int bottom = -1;
- for (i = startSeq; i < endSeq; i++)
+ for (i = startSeq; i <= endSeq; i++)
{
sx = (group.getStartRes() - startRes) * charWidth;
sy = offset + ((i - startSeq) * charHeight);
}
wrappedBlock = y / cHeight;
- wrappedBlock += av.getStartRes() / cwidth;
+ wrappedBlock += av.getRanges().getStartRes() / cwidth;
res = wrappedBlock * cwidth + x / av.getCharWidth();
// right-hand gutter
x = seqCanvas.getX() + seqCanvas.getWidth();
}
- res = (x / av.getCharWidth()) + av.getStartRes();
- if (res > av.getEndRes())
+ res = (x / av.getCharWidth()) + av.getRanges().getStartRes();
+ if (res > av.getRanges().getEndRes())
{
// moused off right
- res = av.getEndRes();
+ res = av.getRanges().getEndRes();
}
}
}
else
{
- seq = Math.min((y / av.getCharHeight()) + av.getStartSeq(), av
+ seq = Math.min((y / av.getCharHeight())
+ + av.getRanges().getStartSeq(),
+ av
.getAlignment().getHeight() - 1);
}
}
else
{
- while (seqCanvas.cursorY < av.startSeq)
+ while (seqCanvas.cursorY < av.getRanges().getStartSeq())
{
ap.scrollUp(true);
}
- while (seqCanvas.cursorY + 1 > av.endSeq)
+ while (seqCanvas.cursorY + 1 > av.getRanges().getEndSeq())
{
ap.scrollUp(false);
}
if (!av.getWrapAlignment())
{
while (seqCanvas.cursorX < av.getColumnSelection()
- .adjustForHiddenColumns(av.startRes))
+ .adjustForHiddenColumns(av.getRanges().getStartRes()))
{
if (!ap.scrollRight(false))
{
}
}
while (seqCanvas.cursorX > av.getColumnSelection()
- .adjustForHiddenColumns(av.endRes))
+ .adjustForHiddenColumns(av.getRanges().getEndRes()))
{
if (!ap.scrollRight(true))
{
stretchGroup = av.getSelectionGroup();
- if (stretchGroup == null)
+ if (stretchGroup == null || !stretchGroup.contains(sequence, res))
{
stretchGroup = av.getAlignment().findGroup(sequence, res);
- av.setSelectionGroup(stretchGroup);
- }
- if (stretchGroup == null
- || !stretchGroup.getSequences(null).contains(sequence)
- || (stretchGroup.getStartRes() > res)
- || (stretchGroup.getEndRes() < res))
- {
- stretchGroup = null;
-
- SequenceGroup[] allGroups = av.getAlignment().findAllGroups(sequence);
-
- if (allGroups != null)
+ if (stretchGroup != null)
{
- for (int i = 0; i < allGroups.length; i++)
- {
- if ((allGroups[i].getStartRes() <= res)
- && (allGroups[i].getEndRes() >= res))
- {
- stretchGroup = allGroups[i];
- break;
- }
- }
+ // only update the current selection if the popup menu has a group to
+ // focus on
+ av.setSelectionGroup(stretchGroup);
}
-
- av.setSelectionGroup(stretchGroup);
}
if (evt.isPopupTrigger()) // Mac: mousePressed
SliderPanel.setPIDSliderSource(ap, av.getResidueShading(),
ap.getViewName());
}
+ // TODO: stretchGroup will always be not null. Is this a merge error ?
if ((stretchGroup != null) && (stretchGroup.getEndRes() == res))
{
// Edit end res position of selected group
changeStartRes = true;
}
- if (res < av.getStartRes())
+ if (res < av.getRanges().getStartRes())
{
- res = av.getStartRes();
+ res = av.getRanges().getStartRes();
}
if (changeEndRes)
{
if (evt != null)
{
- if (mouseDragging && (evt.getY() < 0) && (av.getStartSeq() > 0))
+ if (mouseDragging && (evt.getY() < 0)
+ && (av.getRanges().getStartSeq() > 0))
{
running = ap.scrollUp(true);
}
if (mouseDragging && (evt.getY() >= getHeight())
- && (av.getAlignment().getHeight() > av.getEndSeq()))
+ && (av.getAlignment().getHeight() > av.getRanges()
+ .getEndSeq()))
{
running = ap.scrollUp(false);
}
*/
package jalview.gui;
-import jalview.api.FeatureRenderer;
import jalview.datamodel.SequenceGroup;
import jalview.datamodel.SequenceI;
import jalview.renderer.ResidueShaderI;
+import jalview.renderer.seqfeatures.FeatureColourFinder;
import jalview.util.Comparison;
import java.awt.Color;
boolean forOverview = false;
/**
- * Creates a new SequenceRenderer object.
+ * Creates a new SequenceRenderer object
*
- * @param av
- * DOCUMENT ME!
+ * @param viewport
*/
- public SequenceRenderer(AlignViewport av)
+ public SequenceRenderer(AlignViewport viewport)
{
- this.av = av;
+ this.av = viewport;
}
/**
this.renderGaps = renderGaps;
}
- @Override
- public Color getResidueBoxColour(SequenceI seq, int i)
+ protected Color getResidueBoxColour(SequenceI seq, int i)
{
// rate limiting step when rendering overview for lots of groups
allGroups = av.getAlignment().findAllGroups(seq);
*
* @param seq
* @param position
- * @param fr
+ * @param finder
* @return
*/
@Override
public Color getResidueColour(final SequenceI seq, int position,
- FeatureRenderer fr)
+ FeatureColourFinder finder)
{
- // TODO replace 8 or so code duplications with calls to this method
- // (refactored as needed)
Color col = getResidueBoxColour(seq, position);
- if (fr != null)
+ if (finder != null)
{
- col = fr.findFeatureColour(col, seq, position);
+ col = finder.findFeatureColour(col, seq, position);
}
return col;
}
protected boolean allChainsSelected = false;
+ protected JMenu viewSelectionMenu;
+
/**
* Default constructor
*/
@Override
public void itemStateChanged(ItemEvent e)
{
- alignStructs.setEnabled(_alignwith.size() > 0);
+ alignStructs.setEnabled(!_alignwith.isEmpty());
alignStructs.setToolTipText(MessageManager.formatMessage(
"label.align_structures_using_linked_alignment_views",
- new String[] { String.valueOf(_alignwith.size()) }));
+ _alignwith.size()));
}
};
- JMenu alpanels = new ViewSelectionMenu(
+ viewSelectionMenu = new ViewSelectionMenu(
MessageManager.getString("label.superpose_with"), this,
_alignwith, handler);
handler.itemStateChanged(null);
- viewerActionMenu.add(alpanels);
+ viewerActionMenu.add(viewSelectionMenu, 0);
viewerActionMenu.addMenuListener(new MenuListener()
{
@Override
public void setJalviewColourScheme(ColourSchemeI cs) {
getBinding().setJalviewColourScheme(cs);
}
+
+ /**
+ * Sends commands to the structure viewer to superimpose structures based on
+ * currently associated alignments. May optionally return an error message for
+ * the operation.
+ */
@Override
- protected void alignStructs_actionPerformed(ActionEvent actionEvent)
+ protected String alignStructs_actionPerformed(
+ ActionEvent actionEvent)
{
- alignStructs_withAllAlignPanels();
+ return alignStructs_withAllAlignPanels();
}
- protected void alignStructs_withAllAlignPanels()
+
+ protected String alignStructs_withAllAlignPanels()
{
if (getAlignmentPanel() == null)
{
- return;
+ return null;
}
if (_alignwith.size() == 0)
_alignwith.add(getAlignmentPanel());
}
+ String reply = null;
try
{
AlignmentI[] als = new Alignment[_alignwith.size()];
alm[a] = -1;
alc[a++] = ap.av.getColumnSelection();
}
- getBinding().superposeStructures(als, alm, alc);
+ reply = getBinding().superposeStructures(als, alm, alc);
+ if (reply != null)
+ {
+ String text = MessageManager.formatMessage(
+ "error.superposition_failed", reply);
+ statusBar.setText(text);
+ }
} catch (Exception e)
{
StringBuffer sp = new StringBuffer();
Cache.log.info("Couldn't align structures with the " + sp.toString()
+ "associated alignment panels.", e);
}
+ return reply;
}
+
@Override
public void background_actionPerformed(ActionEvent actionEvent)
{
}
protected abstract String getViewerName();
+
+ /**
+ * Configures the title and menu items of the viewer panel.
+ */
public void updateTitleAndMenus()
{
AAStructureBindingModel binding = getBinding();
setChainMenuItems(binding.getChainNames());
this.setTitle(binding.getViewerTitle(getViewerName(), true));
- if (binding.getPdbFile().length > 1 && binding.getSequence().length > 1)
+
+ /*
+ * enable 'Superpose with' if more than one mapped structure
+ */
+ viewSelectionMenu.setEnabled(false);
+ if (getBinding().getPdbFile().length > 1
+ && getBinding().getSequence().length > 1)
{
- viewerActionMenu.setVisible(true);
+ viewSelectionMenu.setEnabled(true);
}
+
+ /*
+ * Show action menu if it has any enabled items
+ */
+ viewerActionMenu.setVisible(false);
+ for (int i = 0; i < viewerActionMenu.getItemCount(); i++)
+ {
+ if (viewerActionMenu.getItem(i).isEnabled())
+ {
+ viewerActionMenu.setVisible(true);
+ break;
+ }
+ }
+
if (!binding.isLoadingFromArchive())
{
seqColour_actionPerformed(null);
public void run()
{
PrinterJob printJob = PrinterJob.getPrinterJob();
- PageFormat pf = printJob.pageDialog(printJob.defaultPage());
+ PageFormat defaultPage = printJob.defaultPage();
+ PageFormat pf = printJob.pageDialog(defaultPage);
+
+ if (defaultPage == pf)
+ {
+ /*
+ * user cancelled
+ */
+ return;
+ }
printJob.setPrintable(this, pf);
import jalview.schemabinding.version2.Colour;
import jalview.schemabinding.version2.JalviewUserColours;
import jalview.schemes.ColourSchemeI;
+import jalview.schemes.ColourSchemeLoader;
import jalview.schemes.ColourSchemes;
import jalview.schemes.ResidueProperties;
import jalview.schemes.UserColourScheme;
File choice = chooser.getSelectedFile();
Cache.setProperty(LAST_DIRECTORY, choice.getParent());
- UserColourScheme ucs = ColourSchemes.loadColourScheme(choice
+ UserColourScheme ucs = ColourSchemeLoader.loadColourScheme(choice
.getAbsolutePath());
Color[] colors = ucs.getColours();
schemeName.setText(ucs.getSchemeName());
{
colours = colours.substring(0, colours.indexOf("|"));
}
- ret = ColourSchemes.loadColourScheme(colours);
+ ret = ColourSchemeLoader.loadColourScheme(colours);
}
if (ret == null)
JTextField urltf = new JTextField(url, 40);
JPanel panel = new JPanel(new BorderLayout());
JPanel pane12 = new JPanel(new BorderLayout());
- pane12.add(new JLabel(MessageManager.getString("label.url")),
+ pane12.add(new JLabel(MessageManager.getString("label.url:")),
BorderLayout.CENTER);
pane12.add(urltf, BorderLayout.EAST);
panel.add(pane12, BorderLayout.NORTH);
new Thread(new Runnable()
{
+ @Override
public void run()
{
// force a refresh.
new Thread(new Runnable()
{
+ @Override
public void run()
{
progressBar.setVisible(true);
new Thread(new Runnable()
{
+ @Override
public void run()
{
long ct = System.currentTimeMillis();
new Thread(new Runnable()
{
+ @Override
public void run()
{
updateWsMenuConfig(false);
import jalview.json.binding.biojson.v1.SequenceFeaturesPojo;
import jalview.json.binding.biojson.v1.SequenceGrpPojo;
import jalview.json.binding.biojson.v1.SequencePojo;
+import jalview.renderer.seqfeatures.FeatureColourFinder;
import jalview.schemes.JalviewColourScheme;
import jalview.schemes.ResidueColourScheme;
import jalview.util.ColorUtils;
return sequenceFeaturesPojo;
}
+ FeatureColourFinder finder = new FeatureColourFinder(fr);
+
for (SequenceI seq : sqs)
{
SequenceI dataSetSequence = seq.getDatasetSequence();
String.valueOf(seq.hashCode()));
String featureColour = (fr == null) ? null : jalview.util.Format
- .getHexString(fr.findFeatureColour(Color.white, seq,
+ .getHexString(finder.findFeatureColour(Color.white, seq,
seq.findIndex(sf.getBegin())));
jsonFeature.setXstart(seq.findIndex(sf.getBegin()) - 1);
jsonFeature.setXend(seq.findIndex(sf.getEnd()));
import java.awt.Color;
+import MCview.PDBChain;
+
public class PDBFeatureSettings extends FeatureSettingsAdapter
{
// TODO find one central place to define feature names
private static final String FEATURE_INSERTION = "INSERTION";
- private static final String FEATURE_RES_NUM = "RESNUM";
+ private static final String FEATURE_RES_NUM = PDBChain.RESNUM_FEATURE;
@Override
public boolean isFeatureDisplayed(String type)
ArrayList<String[]> ccomands = new ArrayList<String[]>();
ArrayList<String> pdbfn = new ArrayList<String>();
StructureMappingcommandSet[] colcommands = JmolCommands
- .getColourBySequenceCommand(ssm, modelSet, sequence, sr, fr,
- ((AlignmentViewPanel) source).getAlignment());
+ .getColourBySequenceCommand(ssm, modelSet, sequence, sr,
+ (AlignmentViewPanel) source);
if (colcommands == null)
{
return;
return _listenerfn;
}
+ @Override
public void finalize() throws Throwable
{
jvlite = null;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
+import javax.swing.AbstractCellEditor;
import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.DefaultListCellRenderer;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
-import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
+import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.SwingConstants;
import javax.swing.border.TitledBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
-import javax.swing.event.ListSelectionEvent;
-import javax.swing.event.ListSelectionListener;
+import javax.swing.table.TableCellEditor;
+import javax.swing.table.TableCellRenderer;
/**
* Base class for the Preferences panel.
/*
* Connections tab components
*/
- protected JList linkURLList = new JList();
+ protected JTable linkUrlTable = new JTable();
+
+ protected JButton editLink = new JButton();
+
+ protected JButton deleteLink = new JButton();
+
+ protected JTextField filterTB = new JTextField();
+
+ protected JButton doReset = new JButton();
+
+ protected JButton userOnly = new JButton();
+
+ protected JLabel portLabel = new JLabel();
+
+ protected JLabel serverLabel = new JLabel();
protected JTextField proxyServerTB = new JTextField();
protected JTextField defaultBrowser = new JTextField();
- protected JList linkNameList = new JList();
-
protected JCheckBox useProxy = new JCheckBox();
protected JCheckBox usagestats = new JCheckBox();
tabbedPane.add(initConnectionsTab(),
MessageManager.getString("label.connections"));
+ tabbedPane.add(initLinksTab(),
+ MessageManager.getString("label.urllinks"));
+
tabbedPane.add(initOutputTab(),
MessageManager.getString("label.output"));
{
JPanel connectTab = new JPanel();
connectTab.setLayout(new GridBagLayout());
- JLabel serverLabel = new JLabel();
- serverLabel.setText(MessageManager.getString("label.address"));
- serverLabel.setHorizontalAlignment(SwingConstants.RIGHT);
- serverLabel.setFont(LABEL_FONT);
- proxyServerTB.setFont(LABEL_FONT);
- proxyPortTB.setFont(LABEL_FONT);
- JLabel portLabel = new JLabel();
- portLabel.setFont(LABEL_FONT);
- portLabel.setHorizontalAlignment(SwingConstants.RIGHT);
- portLabel.setText(MessageManager.getString("label.port"));
+
+ // Label for browser text box
JLabel browserLabel = new JLabel();
- browserLabel.setFont(new java.awt.Font("SansSerif", 0, 11));
+ browserLabel.setFont(LABEL_FONT);
browserLabel.setHorizontalAlignment(SwingConstants.TRAILING);
browserLabel.setText(MessageManager
.getString("label.default_browser_unix"));
defaultBrowser.setFont(LABEL_FONT);
defaultBrowser.setText("");
- usagestats.setText(MessageManager
- .getString("label.send_usage_statistics"));
- usagestats.setFont(LABEL_FONT);
- usagestats.setHorizontalAlignment(SwingConstants.RIGHT);
- usagestats.setHorizontalTextPosition(SwingConstants.LEADING);
- questionnaire.setText(MessageManager
- .getString("label.check_for_questionnaires"));
- questionnaire.setFont(LABEL_FONT);
- questionnaire.setHorizontalAlignment(SwingConstants.RIGHT);
- questionnaire.setHorizontalTextPosition(SwingConstants.LEADING);
- versioncheck.setText(MessageManager
- .getString("label.check_for_latest_version"));
- versioncheck.setFont(LABEL_FONT);
- versioncheck.setHorizontalAlignment(SwingConstants.RIGHT);
- versioncheck.setHorizontalTextPosition(SwingConstants.LEADING);
+
+ defaultBrowser.addMouseListener(new MouseAdapter()
+ {
+ @Override
+ public void mouseClicked(MouseEvent e)
+ {
+ if (e.getClickCount() > 1)
+ {
+ defaultBrowser_mouseClicked(e);
+ }
+ }
+ });
+
+ JPanel proxyPanel = initConnTabProxyPanel();
+ initConnTabCheckboxes();
+
+ // Add default Browser text box
+ connectTab.add(browserLabel, new GridBagConstraints(0, 0, 1, 1, 0.0,
+ 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE,
+ new Insets(10, 0, 5, 5), 5, 1));
+ defaultBrowser.setFont(LABEL_FONT);
+ defaultBrowser.setText("");
+
+ connectTab.add(defaultBrowser, new GridBagConstraints(1, 0, 1, 1, 1.0,
+ 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
+ new Insets(10, 0, 5, 10), 30, 1));
+
+ // Add proxy server panel
+ connectTab.add(proxyPanel, new GridBagConstraints(0, 1, 2, 1, 1.0, 0.0,
+ GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
+ new Insets(10, 0, 5, 12), 4, 10));
+
+ // Add usage stats, version check and questionnaire checkboxes
+ connectTab.add(usagestats, new GridBagConstraints(0, 2, 1, 1, 1.0, 0.0,
+ GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL,
+ new Insets(0, 2, 5, 5), 70, 1));
+ connectTab.add(questionnaire, new GridBagConstraints(1, 2, 1, 1, 1.0,
+ 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL,
+ new Insets(0, 2, 5, 10), 70, 1));
+ connectTab.add(versioncheck, new GridBagConstraints(0, 3, 1, 1, 1.0,
+ 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL,
+ new Insets(0, 2, 5, 5), 70, 1));
+
+ // Add padding so the panel doesn't look ridiculous
+ JPanel spacePanel = new JPanel();
+ connectTab.add(spacePanel, new GridBagConstraints(0, 4, 1, 1, 1.0, 1.0,
+ GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(0,
+ 0, 0, 5), 70, 1));
+
+ return connectTab;
+ }
+
+ /**
+ * Initialises the Links tabbed panel.
+ *
+ * @return
+ */
+ private JPanel initLinksTab()
+ {
+ JPanel linkTab = new JPanel();
+ linkTab.setLayout(new GridBagLayout());
+
+ // Set up table for Url links
+ linkUrlTable.setFillsViewportHeight(true);
+ linkUrlTable.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
+ linkUrlTable.setAutoCreateRowSorter(true);
+ linkUrlTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+
+ // adjust row height so radio buttons actually fit
+ // don't do this in the renderer, it causes the awt thread to activate
+ // constantly
+ JRadioButton temp = new JRadioButton();
+ linkUrlTable.setRowHeight(temp.getMinimumSize().height);
+
+ // Table in scrollpane so that the table is given a scrollbar
+ JScrollPane linkScrollPane = new JScrollPane(linkUrlTable);
+ linkScrollPane.setBorder(null);
+
+ // Panel for links functionality
+ JPanel linkPanel = new JPanel(new GridBagLayout());
+ linkPanel.setBorder(new TitledBorder(MessageManager
+ .getString("label.url_linkfrom_sequence_id")));
+
+ // Put the Url links panel together
+
+ // Buttons go at top right, resizing only resizes the blank space vertically
+ JPanel buttonPanel = initLinkTabUrlButtons();
+ GridBagConstraints linkConstraints1 = new GridBagConstraints();
+ linkConstraints1.insets = new Insets(0, 0, 5, 0);
+ linkConstraints1.gridx = 0;
+ linkConstraints1.gridy = 0;
+ linkConstraints1.weightx = 1.0;
+ linkConstraints1.fill = GridBagConstraints.HORIZONTAL;
+ linkTab.add(buttonPanel, linkConstraints1);
+
+ // Links table goes at top left, resizing resizes the table
+ GridBagConstraints linkConstraints2 = new GridBagConstraints();
+ linkConstraints2.insets = new Insets(0, 0, 5, 5);
+ linkConstraints2.gridx = 0;
+ linkConstraints2.gridy = 1;
+ linkConstraints2.weightx = 1.0;
+ linkConstraints2.weighty = 1.0;
+ linkConstraints2.fill = GridBagConstraints.BOTH;
+ linkTab.add(linkScrollPane, linkConstraints2);
+
+ // Filter box and buttons goes at bottom left, resizing resizes the text box
+ JPanel filterPanel = initLinkTabFilterPanel();
+ GridBagConstraints linkConstraints3 = new GridBagConstraints();
+ linkConstraints3.insets = new Insets(0, 0, 0, 5);
+ linkConstraints3.gridx = 0;
+ linkConstraints3.gridy = 2;
+ linkConstraints3.weightx = 1.0;
+ linkConstraints3.fill = GridBagConstraints.HORIZONTAL;
+ linkTab.add(filterPanel, linkConstraints3);
+
+ return linkTab;
+ }
+
+ private JPanel initLinkTabFilterPanel()
+ {
+ // Filter textbox and reset button
+ JLabel filterLabel = new JLabel(
+ MessageManager.getString("label.filter"));
+ filterLabel.setFont(LABEL_FONT);
+ filterLabel.setHorizontalAlignment(SwingConstants.RIGHT);
+ filterLabel.setHorizontalTextPosition(SwingConstants.LEADING);
+
+ filterTB.setFont(LABEL_FONT);
+ filterTB.setText("");
+
+ doReset.setText(MessageManager.getString("action.showall"));
+ userOnly.setText(MessageManager.getString("action.customfilter"));
+
+ // Panel for filter functionality
+ JPanel filterPanel = new JPanel(new GridBagLayout());
+ filterPanel.setBorder(new TitledBorder("Filter"));
+ GridBagConstraints gbc = new GridBagConstraints();
+ gbc.gridx = 0;
+ gbc.gridy = 0;
+ gbc.fill = GridBagConstraints.NONE;
+ gbc.anchor = GridBagConstraints.WEST;
+
+ filterPanel.add(filterLabel, gbc);
+
+ GridBagConstraints gbc1 = new GridBagConstraints();
+ gbc1.gridx = 1;
+ gbc1.gridwidth = 2;
+ gbc1.fill = GridBagConstraints.HORIZONTAL;
+ gbc1.anchor = GridBagConstraints.WEST;
+ gbc1.weightx = 1.0;
+ filterPanel.add(filterTB, gbc1);
+
+ GridBagConstraints gbc2 = new GridBagConstraints();
+ gbc2.gridx = 3;
+ gbc2.fill = GridBagConstraints.NONE;
+ gbc2.anchor = GridBagConstraints.WEST;
+ filterPanel.add(doReset, gbc2);
+
+ GridBagConstraints gbc3 = new GridBagConstraints();
+ gbc3.gridx = 4;
+ gbc3.fill = GridBagConstraints.NONE;
+ gbc3.anchor = GridBagConstraints.WEST;
+ filterPanel.add(userOnly, gbc3);
+
+ return filterPanel;
+ }
+
+ private JPanel initLinkTabUrlButtons()
+ {
+ // Buttons for new / edit / delete Url links
JButton newLink = new JButton();
newLink.setText(MessageManager.getString("action.new"));
+
+ editLink.setText(MessageManager.getString("action.edit"));
+
+ deleteLink.setText(MessageManager.getString("action.delete"));
+
+ // no current selection, so initially disable delete/edit buttons
+ editLink.setEnabled(false);
+ deleteLink.setEnabled(false);
+
newLink.addActionListener(new java.awt.event.ActionListener()
{
@Override
newLink_actionPerformed(e);
}
});
- JButton editLink = new JButton();
+
editLink.setText(MessageManager.getString("action.edit"));
editLink.addActionListener(new java.awt.event.ActionListener()
{
editLink_actionPerformed(e);
}
});
- JButton deleteLink = new JButton();
+
deleteLink.setText(MessageManager.getString("action.delete"));
deleteLink.addActionListener(new java.awt.event.ActionListener()
{
}
});
- linkURLList.addListSelectionListener(new ListSelectionListener()
- {
- @Override
- public void valueChanged(ListSelectionEvent e)
- {
- int index = linkURLList.getSelectedIndex();
- linkNameList.setSelectedIndex(index);
- }
- });
+ JPanel buttonPanel = new JPanel(new GridBagLayout());
+ buttonPanel.setBorder(new TitledBorder("Edit links"));
+ GridBagConstraints gbc = new GridBagConstraints();
+ gbc.gridx = 0;
+ gbc.gridy = 0;
+ gbc.fill = GridBagConstraints.NONE;
+ buttonPanel.add(newLink, gbc);
+
+ GridBagConstraints gbc1 = new GridBagConstraints();
+ gbc1.gridx = 1;
+ gbc1.gridy = 0;
+ gbc1.fill = GridBagConstraints.NONE;
+ buttonPanel.add(editLink, gbc1);
+
+ GridBagConstraints gbc2 = new GridBagConstraints();
+ gbc2.gridx = 2;
+ gbc2.gridy = 0;
+ gbc2.fill = GridBagConstraints.NONE;
+ buttonPanel.add(deleteLink, gbc2);
+
+ GridBagConstraints gbc3 = new GridBagConstraints();
+ gbc3.gridx = 3;
+ gbc3.gridy = 0;
+ gbc3.fill = GridBagConstraints.HORIZONTAL;
+ gbc3.weightx = 1.0;
+ JPanel spacePanel = new JPanel();
+ spacePanel.setBorder(null);
+ buttonPanel.add(spacePanel, gbc3);
+
+ return buttonPanel;
+ }
- linkNameList.addListSelectionListener(new ListSelectionListener()
- {
- @Override
- public void valueChanged(ListSelectionEvent e)
- {
- int index = linkNameList.getSelectedIndex();
- linkURLList.setSelectedIndex(index);
- }
- });
+ /**
+ * Initialises the proxy server panel in the Connections tab
+ *
+ * @return the proxy server panel
+ */
+ private JPanel initConnTabProxyPanel()
+ {
+ // Label for server text box
+ serverLabel.setText(MessageManager.getString("label.address"));
+ serverLabel.setHorizontalAlignment(SwingConstants.RIGHT);
+ serverLabel.setFont(LABEL_FONT);
- JScrollPane linkScrollPane = new JScrollPane();
- linkScrollPane.setBorder(null);
- JPanel linkPanel = new JPanel();
- linkPanel.setBorder(new TitledBorder(MessageManager
- .getString("label.url_linkfrom_sequence_id")));
- linkPanel.setLayout(new BorderLayout());
- GridLayout gridLayout1 = new GridLayout();
- JPanel editLinkButtons = new JPanel();
- editLinkButtons.setLayout(gridLayout1);
- gridLayout1.setRows(3);
- linkNameList.setFont(LABEL_FONT);
- linkNameList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
- BorderLayout borderLayout3 = new BorderLayout();
- JPanel linkPanel2 = new JPanel();
- linkPanel2.setLayout(borderLayout3);
- linkURLList.setFont(LABEL_FONT);
- linkURLList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+ // Proxy server and port text boxes
+ proxyServerTB.setFont(LABEL_FONT);
+ proxyPortTB.setFont(LABEL_FONT);
- defaultBrowser.addMouseListener(new MouseAdapter()
- {
- @Override
- public void mouseClicked(MouseEvent e)
- {
- if (e.getClickCount() > 1)
- {
- defaultBrowser_mouseClicked(e);
- }
- }
- });
+ // Label for Port text box
+ portLabel.setFont(LABEL_FONT);
+ portLabel.setHorizontalAlignment(SwingConstants.RIGHT);
+ portLabel.setText(MessageManager.getString("label.port"));
+
+ // Use proxy server checkbox
useProxy.setFont(LABEL_FONT);
useProxy.setHorizontalAlignment(SwingConstants.RIGHT);
useProxy.setHorizontalTextPosition(SwingConstants.LEADING);
useProxy_actionPerformed();
}
});
- linkPanel.add(editLinkButtons, BorderLayout.EAST);
- editLinkButtons.add(newLink, null);
- editLinkButtons.add(editLink, null);
- editLinkButtons.add(deleteLink, null);
- linkPanel.add(linkScrollPane, BorderLayout.CENTER);
- linkScrollPane.getViewport().add(linkPanel2, null);
- linkPanel2.add(linkURLList, BorderLayout.CENTER);
- linkPanel2.add(linkNameList, BorderLayout.WEST);
- JPanel jPanel1 = new JPanel();
+
+ // Make proxy server panel
+ JPanel proxyPanel = new JPanel();
TitledBorder titledBorder1 = new TitledBorder(
MessageManager.getString("label.proxy_server"));
- jPanel1.setBorder(titledBorder1);
- jPanel1.setLayout(new GridBagLayout());
- jPanel1.add(serverLabel, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0,
- GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0,
- 2, 4, 0), 5, 0));
- jPanel1.add(portLabel, new GridBagConstraints(2, 1, 1, 1, 0.0, 0.0,
- GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0,
- 0, 4, 0), 11, 6));
- connectTab.add(linkPanel, new GridBagConstraints(0, 0, 2, 1, 1.0, 1.0,
- GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(
- 16, 0, 0, 12), 359, -17));
- connectTab.add(jPanel1, new GridBagConstraints(0, 2, 2, 1, 1.0, 1.0,
- GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(
- 21, 0, 35, 12), 4, 6));
- connectTab.add(browserLabel, new GridBagConstraints(0, 1, 1, 1, 0.0,
+ proxyPanel.setBorder(titledBorder1);
+ proxyPanel.setLayout(new GridBagLayout());
+ proxyPanel.add(serverLabel, new GridBagConstraints(0, 1, 1, 1, 0.0,
0.0, GridBagConstraints.WEST, GridBagConstraints.NONE,
- new Insets(16, 0, 0, 0), 5, 1));
- jPanel1.add(useProxy, new GridBagConstraints(0, 0, 2, 1, 0.0, 0.0,
+ new Insets(0, 2, 2, 0), 5, 0));
+ proxyPanel.add(portLabel, new GridBagConstraints(2, 1, 1, 1, 0.0, 0.0,
+ GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0,
+ 0, 2, 0), 11, 0));
+ proxyPanel.add(useProxy, new GridBagConstraints(0, 0, 2, 1, 0.0, 0.0,
GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0,
2, 5, 185), 2, -4));
- jPanel1.add(proxyPortTB, new GridBagConstraints(3, 1, 1, 1, 1.0, 0.0,
- GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL,
- new Insets(0, 2, 4, 2), 54, 1));
- jPanel1.add(proxyServerTB, new GridBagConstraints(1, 1, 1, 1, 1.0, 0.0,
- GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL,
- new Insets(0, 2, 4, 0), 263, 1));
- connectTab.add(defaultBrowser, new GridBagConstraints(1, 1, 1, 1, 1.0,
- 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL,
- new Insets(15, 0, 0, 15), 307, 1));
- connectTab.add(usagestats, new GridBagConstraints(0, 4, 1, 1, 1.0, 0.0,
- GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL,
- new Insets(0, 2, 4, 2), 70, 1));
- connectTab.add(questionnaire, new GridBagConstraints(1, 4, 1, 1, 1.0,
+ proxyPanel.add(proxyPortTB, new GridBagConstraints(3, 1, 1, 1, 1.0,
0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL,
- new Insets(0, 2, 4, 2), 70, 1));
- connectTab.add(versioncheck, new GridBagConstraints(0, 5, 1, 1, 1.0,
+ new Insets(0, 2, 2, 2), 54, 1));
+ proxyPanel.add(proxyServerTB, new GridBagConstraints(1, 1, 1, 1, 1.0,
0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL,
- new Insets(0, 2, 4, 2), 70, 1));
- return connectTab;
+ new Insets(0, 2, 2, 0), 263, 1));
+
+ return proxyPanel;
+ }
+
+ /**
+ * Initialises the checkboxes in the Connections tab
+ */
+ private void initConnTabCheckboxes()
+ {
+ // Usage stats checkbox label
+ usagestats.setText(MessageManager
+ .getString("label.send_usage_statistics"));
+ usagestats.setFont(LABEL_FONT);
+ usagestats.setHorizontalAlignment(SwingConstants.RIGHT);
+ usagestats.setHorizontalTextPosition(SwingConstants.LEADING);
+
+ // Questionnaire checkbox label
+ questionnaire.setText(MessageManager
+ .getString("label.check_for_questionnaires"));
+ questionnaire.setFont(LABEL_FONT);
+ questionnaire.setHorizontalAlignment(SwingConstants.RIGHT);
+ questionnaire.setHorizontalTextPosition(SwingConstants.LEADING);
+
+ // Check for latest version checkbox label
+ versioncheck.setText(MessageManager
+ .getString("label.check_for_latest_version"));
+ versioncheck.setFont(LABEL_FONT);
+ versioncheck.setHorizontalAlignment(SwingConstants.RIGHT);
+ versioncheck.setHorizontalTextPosition(SwingConstants.LEADING);
}
/**
public void useProxy_actionPerformed()
{
- proxyServerTB.setEnabled(useProxy.isSelected());
- proxyPortTB.setEnabled(useProxy.isSelected());
+ boolean enabled = useProxy.isSelected();
+ portLabel.setEnabled(enabled);
+ serverLabel.setEnabled(enabled);
+ proxyServerTB.setEnabled(enabled);
+ proxyPortTB.setEnabled(enabled);
+ }
+
+ /**
+ * Customer renderer for JTable: supports column of radio buttons
+ */
+ public class RadioButtonRenderer extends JRadioButton implements
+ TableCellRenderer
+ {
+ public RadioButtonRenderer()
+ {
+ setHorizontalAlignment(CENTER);
+ setToolTipText(MessageManager.getString("label.urltooltip"));
+ }
+
+ @Override
+ public Component getTableCellRendererComponent(JTable table,
+ Object value, boolean isSelected, boolean hasFocus, int row,
+ int column)
+ {
+ setSelected((boolean) value);
+
+ // set colours to match rest of table
+ if (isSelected)
+ {
+ setBackground(table.getSelectionBackground());
+ setForeground(table.getSelectionForeground());
+ }
+ else
+ {
+ setBackground(table.getBackground());
+ setForeground(table.getForeground());
+ }
+ return this;
+ }
}
+ /**
+ * Customer cell editor for JTable: supports column of radio buttons in
+ * conjunction with renderer
+ */
+ public class RadioButtonEditor extends AbstractCellEditor implements
+ TableCellEditor
+ {
+ private JRadioButton button = new JRadioButton();
+
+ public RadioButtonEditor()
+ {
+ button.setHorizontalAlignment(SwingConstants.CENTER);
+ this.button.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ fireEditingStopped();
+ }
+ });
+ }
+
+ @Override
+ public Component getTableCellEditorComponent(JTable table,
+ Object value, boolean isSelected, int row, int column)
+ {
+ button.setSelected((boolean) value);
+ return button;
+ }
+
+ @Override
+ public Object getCellEditorValue()
+ {
+ return button.isSelected();
+ }
+
+ }
}
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
-import java.awt.Panel;
import java.awt.Rectangle;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.BorderFactory;
+import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
-public class GSequenceLink extends Panel
+public class GSequenceLink extends JPanel
{
+
+ JTextField nameTB = new JTextField();
+
+ JTextField urlTB = new JTextField();
+
+ JButton insertSeq = new JButton();
+
+ JButton insertDBAcc = new JButton();
+
+ JLabel insert = new JLabel();
+
+ JLabel jLabel1 = new JLabel();
+
+ JLabel jLabel2 = new JLabel();
+
+ JLabel jLabel3 = new JLabel();
+
+ JLabel jLabel4 = new JLabel();
+
+ JLabel jLabel5 = new JLabel();
+
+ JLabel jLabel6 = new JLabel();
+
+ JPanel jPanel1 = new JPanel();
+
+ GridBagLayout gridBagLayout1 = new GridBagLayout();
+
public GSequenceLink()
{
try
urlTB_keyTyped(e);
}
});
+
+ insertSeq.setLocation(77, 75);
+ insertSeq.setSize(141, 24);
+ insertSeq.setText(MessageManager.getString("action.seq_id"));
+ insertSeq.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ insertSeq_action(e);
+ }
+ });
+
+ insertDBAcc.setLocation(210, 75);
+ insertDBAcc.setSize(141, 24);
+ insertDBAcc.setText(MessageManager.getString("action.db_acc"));
+ insertDBAcc.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ insertDBAcc_action(e);
+ }
+ });
+
+ insert.setText(MessageManager.getString("label.insert"));
+ insert.setFont(JvSwingUtils.getLabelFont());
+ insert.setHorizontalAlignment(SwingConstants.RIGHT);
+ insert.setBounds(17, 78, 58, 16);
+
jLabel1.setFont(JvSwingUtils.getLabelFont());
jLabel1.setHorizontalAlignment(SwingConstants.TRAILING);
jLabel1.setText(MessageManager.getString("label.link_name"));
jLabel1.setBounds(new Rectangle(4, 10, 71, 24));
jLabel2.setFont(JvSwingUtils.getLabelFont());
jLabel2.setHorizontalAlignment(SwingConstants.TRAILING);
- jLabel2.setText(MessageManager.getString("label.url"));
+ jLabel2.setText(MessageManager.getString("label.url:"));
jLabel2.setBounds(new Rectangle(17, 37, 54, 27));
jLabel3.setFont(new java.awt.Font("Verdana", Font.ITALIC, 11));
jLabel3.setText(MessageManager.getString("label.use_sequence_id_1"));
- jLabel3.setBounds(new Rectangle(21, 72, 351, 15));
+ jLabel3.setBounds(new Rectangle(21, 102, 351, 15));
jLabel4.setFont(new java.awt.Font("Verdana", Font.ITALIC, 11));
jLabel4.setText(MessageManager.getString("label.use_sequence_id_2"));
- jLabel4.setBounds(new Rectangle(21, 88, 351, 15));
+ jLabel4.setBounds(new Rectangle(21, 118, 351, 15));
jLabel5.setFont(new java.awt.Font("Verdana", Font.ITALIC, 11));
jLabel5.setText(MessageManager.getString("label.use_sequence_id_3"));
- jLabel5.setBounds(new Rectangle(21, 106, 351, 15));
+ jLabel5.setBounds(new Rectangle(21, 136, 351, 15));
String lastLabel = MessageManager.getString("label.use_sequence_id_4");
if (lastLabel.length() > 0)
// e.g. Spanish version has longer text
jLabel6.setFont(new java.awt.Font("Verdana", Font.ITALIC, 11));
jLabel6.setText(lastLabel);
- jLabel6.setBounds(new Rectangle(21, 122, 351, 15));
+ jLabel6.setBounds(new Rectangle(21, 152, 351, 15));
}
jPanel1.setBorder(BorderFactory.createEtchedBorder());
jPanel1.add(jLabel1);
jPanel1.add(nameTB);
jPanel1.add(urlTB);
+ jPanel1.add(insertSeq);
+ jPanel1.add(insertDBAcc);
+ jPanel1.add(insert);
jPanel1.add(jLabel2);
jPanel1.add(jLabel3);
jPanel1.add(jLabel4);
jPanel1.add(jLabel5);
- int height = 130;
+ int height = 160;
if (lastLabel.length() > 0)
{
jPanel1.add(jLabel6);
- height = 146;
+ height = 176;
}
this.add(jPanel1, new GridBagConstraints(0, 0, 1, 1, 1.0, 1.0,
return false;
}
- JTextField nameTB = new JTextField();
-
- JTextField urlTB = new JTextField();
-
- JLabel jLabel1 = new JLabel();
-
- JLabel jLabel2 = new JLabel();
-
- JLabel jLabel3 = new JLabel();
-
- JLabel jLabel4 = new JLabel();
-
- JLabel jLabel5 = new JLabel();
-
- JLabel jLabel6 = new JLabel();
-
- JPanel jPanel1 = new JPanel();
-
- GridBagLayout gridBagLayout1 = new GridBagLayout();
+ public void notifyDuplicate()
+ {
+ JvOptionPane.showInternalMessageDialog(jalview.gui.Desktop.desktop,
+ MessageManager.getString("warn.name_cannot_be_duplicate"),
+ MessageManager.getString("label.invalid_name"),
+ JvOptionPane.WARNING_MESSAGE);
+ }
public void nameTB_keyTyped(KeyEvent e)
{
// }
}
+
+ public void insertSeq_action(ActionEvent e)
+ {
+ insertIntoUrl(insertSeq.getText());
+ }
+
+ public void insertDBAcc_action(ActionEvent e)
+ {
+ insertIntoUrl(insertDBAcc.getText());
+ }
+
+ private void insertIntoUrl(String insertion)
+ {
+ int pos = urlTB.getCaretPosition();
+ String text = urlTB.getText();
+ String newText = text.substring(0, pos) + insertion
+ + text.substring(pos);
+ urlTB.setText(newText);
+ }
}
}
});
alignStructs = new JMenuItem();
- alignStructs
- .setText(MessageManager.getString("label.align_structures"));
+ alignStructs.setText(MessageManager
+ .getString("label.superpose_structures"));
alignStructs.addActionListener(new ActionListener()
{
@Override
}
});
- viewerActionMenu = new JMenu();
+ viewerActionMenu = new JMenu(); // text set in sub-classes
viewerActionMenu.setVisible(false);
viewerActionMenu.add(alignStructs);
colourMenu = new JMenu();
{
}
- protected void alignStructs_actionPerformed(ActionEvent actionEvent)
- {
- }
+ protected abstract String alignStructs_actionPerformed(
+ ActionEvent actionEvent);
public void pdbFile_actionPerformed(ActionEvent actionEvent)
{
/**
* A class to model rectangular matrices of double values and operations on them
*/
-public class Matrix
+public class Matrix implements MatrixI
{
/*
* the cell values in row-major order
*/
- public double[][] value;
+ private double[][] value;
/*
* the number of rows
*/
- public int rows;
+ protected int rows;
/*
* the number of columns
*/
- public int cols;
+ protected int cols;
- /** DOCUMENT ME!! */
- public double[] d; // Diagonal
+ protected double[] d; // Diagonal
- /** DOCUMENT ME!! */
- public double[] e; // off diagonal
+ protected double[] e; // off diagonal
/**
* maximum number of iterations for tqli
*
*/
- int maxIter = 45; // fudge - add 15 iterations, just in case
+ private static final int maxIter = 45; // fudge - add 15 iterations, just in
+ // case
/**
+ * Default constructor
+ */
+ public Matrix()
+ {
+
+ }
+
+ /**
* Creates a new Matrix object. For example
*
* <pre>
}
/**
- * Returns a new matrix which is the transposes of this one
+ * Returns a new matrix which is the transpose of this one
*
* @return DOCUMENT ME!
*/
- public Matrix transpose()
+ @Override
+ public MatrixI transpose()
{
double[][] out = new double[cols][rows];
*
* @param ps
* DOCUMENT ME!
+ * @param format
*/
- public void print(PrintStream ps)
+ @Override
+ public void print(PrintStream ps, String format)
{
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
- Format.print(ps, "%8.2f", value[i][j]);
+ Format.print(ps, format, getValue(i, j));
}
ps.println();
* if the number of columns in the pre-multiplier is not equal to
* the number of rows in the multiplicand (this)
*/
- public Matrix preMultiply(Matrix in)
+ @Override
+ public MatrixI preMultiply(MatrixI in)
{
- if (in.cols != this.rows)
+ if (in.width() != rows)
{
throw new IllegalArgumentException("Can't pre-multiply " + this.rows
- + " rows by " + in.cols + " columns");
+ + " rows by " + in.width() + " columns");
}
- double[][] tmp = new double[in.rows][this.cols];
+ double[][] tmp = new double[in.height()][this.cols];
- for (int i = 0; i < in.rows; i++)
+ for (int i = 0; i < in.height(); i++)
{
for (int j = 0; j < this.cols; j++)
{
- tmp[i][j] = 0.0;
-
- for (int k = 0; k < in.cols; k++)
+ /*
+ * result[i][j] is the vector product of
+ * in.row[i] and this.column[j]
+ */
+ for (int k = 0; k < in.width(); k++)
{
- tmp[i][j] += (in.value[i][k] * this.value[k][j]);
+ tmp[i][j] += (in.getValue(i, k) * this.value[k][j]);
}
}
}
* number of columns in the multiplicand (this)
* @see #preMultiply(Matrix)
*/
- public Matrix postMultiply(Matrix in)
+ @Override
+ public MatrixI postMultiply(MatrixI in)
{
- if (in.rows != this.cols)
+ if (in.height() != this.cols)
{
throw new IllegalArgumentException("Can't post-multiply " + this.cols
- + " columns by " + in.rows + " rows");
+ + " columns by " + in.height() + " rows");
}
return in.preMultiply(this);
}
*
* @return
*/
- public Matrix copy()
+ @Override
+ public MatrixI copy()
{
double[][] newmat = new double[rows][cols];
/**
* DOCUMENT ME!
*/
+ @Override
public void tred()
{
int n = rows;
- int l;
int k;
int j;
int i;
for (i = n; i >= 2; i--)
{
- l = i - 1;
+ final int l = i - 1;
h = 0.0;
scale = 0.0;
{
for (k = 1; k <= l; k++)
{
- scale += Math.abs(value[i - 1][k - 1]);
+ double v = Math.abs(getValue(i - 1, k - 1));
+ scale += v;
}
if (scale == 0.0)
{
- e[i - 1] = value[i - 1][l - 1];
+ e[i - 1] = getValue(i - 1, l - 1);
}
else
{
for (k = 1; k <= l; k++)
{
- value[i - 1][k - 1] /= scale;
- h += (value[i - 1][k - 1] * value[i - 1][k - 1]);
+ double v = divideValue(i - 1, k - 1, scale);
+ h += v * v;
}
- f = value[i - 1][l - 1];
+ f = getValue(i - 1, l - 1);
if (f > 0)
{
e[i - 1] = scale * g;
h -= (f * g);
- value[i - 1][l - 1] = f - g;
+ setValue(i - 1, l - 1, f - g);
f = 0.0;
for (j = 1; j <= l; j++)
{
- value[j - 1][i - 1] = value[i - 1][j - 1] / h;
+ double val = getValue(i - 1, j - 1) / h;
+ setValue(j - 1, i - 1, val);
g = 0.0;
for (k = 1; k <= j; k++)
{
- g += (value[j - 1][k - 1] * value[i - 1][k - 1]);
+ g += (getValue(j - 1, k - 1) * getValue(i - 1, k - 1));
}
for (k = j + 1; k <= l; k++)
{
- g += (value[k - 1][j - 1] * value[i - 1][k - 1]);
+ g += (getValue(k - 1, j - 1) * getValue(i - 1, k - 1));
}
e[j - 1] = g / h;
- f += (e[j - 1] * value[i - 1][j - 1]);
+ f += (e[j - 1] * getValue(i - 1, j - 1));
}
hh = f / (h + h);
for (j = 1; j <= l; j++)
{
- f = value[i - 1][j - 1];
+ f = getValue(i - 1, j - 1);
g = e[j - 1] - (hh * f);
e[j - 1] = g;
for (k = 1; k <= j; k++)
{
- value[j - 1][k - 1] -= ((f * e[k - 1]) + (g * value[i - 1][k - 1]));
+ double val = (f * e[k - 1]) + (g * getValue(i - 1, k - 1));
+ addValue(j - 1, k - 1, -val);
}
}
}
}
else
{
- e[i - 1] = value[i - 1][l - 1];
+ e[i - 1] = getValue(i - 1, l - 1);
}
d[i - 1] = h;
for (i = 1; i <= n; i++)
{
- l = i - 1;
+ final int l = i - 1;
if (d[i - 1] != 0.0)
{
for (k = 1; k <= l; k++)
{
- g += (value[i - 1][k - 1] * value[k - 1][j - 1]);
+ g += (getValue(i - 1, k - 1) * getValue(k - 1, j - 1));
}
for (k = 1; k <= l; k++)
{
- value[k - 1][j - 1] -= (g * value[k - 1][i - 1]);
+ addValue(k - 1, j - 1, -(g * getValue(k - 1, i - 1)));
}
}
}
- d[i - 1] = value[i - 1][i - 1];
- value[i - 1][i - 1] = 1.0;
+ d[i - 1] = getValue(i - 1, i - 1);
+ setValue(i - 1, i - 1, 1.0);
for (j = 1; j <= l; j++)
{
- value[j - 1][i - 1] = 0.0;
- value[i - 1][j - 1] = 0.0;
+ setValue(j - 1, i - 1, 0.0);
+ setValue(i - 1, j - 1, 0.0);
}
}
}
/**
+ * Adds f to the value at [i, j] and returns the new value
+ *
+ * @param i
+ * @param j
+ * @param f
+ */
+ protected double addValue(int i, int j, double f)
+ {
+ double v = value[i][j] + f;
+ value[i][j] = v;
+ return v;
+ }
+
+ /**
+ * Divides the value at [i, j] by divisor and returns the new value. If d is
+ * zero, returns the unchanged value.
+ *
+ * @param i
+ * @param j
+ * @param divisor
+ * @return
+ */
+ protected double divideValue(int i, int j, double divisor)
+ {
+ if (divisor == 0d)
+ {
+ return getValue(i, j);
+ }
+ double v = value[i][j];
+ v = v / divisor;
+ value[i][j] = v;
+ return v;
+ }
+
+ /**
* DOCUMENT ME!
*/
+ @Override
public void tqli() throws Exception
{
int n = rows;
double s;
double r;
double p;
- ;
double g;
double f;
for (k = 1; k <= n; k++)
{
- f = value[k - 1][i];
- value[k - 1][i] = (s * value[k - 1][i - 1]) + (c * f);
- value[k - 1][i - 1] = (c * value[k - 1][i - 1]) - (s * f);
+ f = getValue(k - 1, i);
+ setValue(k - 1, i, (s * getValue(k - 1, i - 1)) + (c * f));
+ setValue(k - 1, i - 1, (c * getValue(k - 1, i - 1)) - (s * f));
}
}
}
}
+ @Override
+ public double getValue(int i, int j)
+ {
+ return value[i][j];
+ }
+
+ public void setValue(int i, int j, double val)
+ {
+ value[i][j] = val;
+ }
+
/**
* DOCUMENT ME!
*/
}
/**
- * DOCUMENT ME!
+ * Answers the first argument with the sign of the second argument
*
* @param a
- * DOCUMENT ME!
* @param b
- * DOCUMENT ME!
*
- * @return DOCUMENT ME!
+ * @return
*/
- public double sign(double a, double b)
+ static double sign(double a, double b)
{
if (b < 0)
{
*
* @param ps
* DOCUMENT ME!
+ * @param format
*/
- public void printD(PrintStream ps)
+ @Override
+ public void printD(PrintStream ps, String format)
{
for (int j = 0; j < rows; j++)
{
- Format.print(ps, "%15.4e", d[j]);
+ Format.print(ps, format, d[j]);
}
}
*
* @param ps
* DOCUMENT ME!
+ * @param format TODO
*/
- public void printE(PrintStream ps)
+ @Override
+ public void printE(PrintStream ps, String format)
{
for (int j = 0; j < rows; j++)
{
- Format.print(ps, "%15.4e", e[j]);
+ Format.print(ps, format, e[j]);
}
}
+
+ @Override
+ public double[] getD()
+ {
+ return d;
+ }
+
+ @Override
+ public double[] getE()
+ {
+ return e;
+ }
+
+ @Override
+ public int height() {
+ return rows;
+ }
+
+ @Override
+ public int width()
+ {
+ return cols;
+ }
+
+ @Override
+ public double[] getRow(int i)
+ {
+ double[] row = new double[cols];
+ System.arraycopy(value[i], 0, row, 0, cols);
+ return row;
+ }
}
--- /dev/null
+package jalview.math;
+
+import java.io.PrintStream;
+
+public interface MatrixI
+{
+ /**
+ * Answers the number of columns
+ *
+ * @return
+ */
+ int width();
+
+ /**
+ * Answers the number of rows
+ *
+ * @return
+ */
+ int height();
+
+ /**
+ * Answers the value at row i, column j
+ *
+ * @param i
+ * @param j
+ * @return
+ */
+ double getValue(int i, int j);
+
+ /**
+ * Answers a copy of the values in the i'th row
+ *
+ * @return
+ */
+ double[] getRow(int i);
+
+ MatrixI copy();
+
+ MatrixI transpose();
+
+ MatrixI preMultiply(MatrixI m);
+
+ MatrixI postMultiply(MatrixI m);
+
+ double[] getD();
+
+ double[] getE();
+
+ void print(PrintStream ps, String format);
+
+ void printD(PrintStream ps, String format);
+
+ void printE(PrintStream ps, String format);
+
+ void tqli() throws Exception;
+
+ void tred();
+
+}
--- /dev/null
+package jalview.math;
+
+import jalview.ext.android.SparseDoubleArray;
+
+/**
+ * A variant of Matrix intended for use for sparse (mostly zero) matrices. This
+ * class uses a SparseDoubleArray to hold each row of the matrix. The sparse
+ * array only stores non-zero values. This gives a smaller memory footprint, and
+ * fewer matrix calculation operations, for mostly zero matrices.
+ *
+ * @author gmcarstairs
+ */
+public class SparseMatrix extends Matrix
+{
+ /*
+ * we choose columns for the sparse arrays as this allows
+ * optimisation of the preMultiply() method used in PCA.run()
+ */
+ SparseDoubleArray[] sparseColumns;
+
+ /**
+ * Constructor given data in [row][column] order
+ *
+ * @param v
+ */
+ public SparseMatrix(double[][] v)
+ {
+ rows = v.length;
+ if (rows > 0) {
+ cols = v[0].length;
+ }
+ sparseColumns = new SparseDoubleArray[cols];
+
+ /*
+ * transpose v[row][col] into [col][row] order
+ */
+ for (int col = 0; col < cols; col++)
+ {
+ SparseDoubleArray sparseColumn = new SparseDoubleArray();
+ sparseColumns[col] = sparseColumn;
+ for (int row = 0; row < rows; row++)
+ {
+ double value = v[row][col];
+ if (value != 0d)
+ {
+ sparseColumn.put(row, value);
+ }
+ }
+ }
+ }
+
+ /**
+ * Answers the value at row i, column j
+ */
+ @Override
+ public double getValue(int i, int j)
+ {
+ return sparseColumns[j].get(i);
+ }
+
+ /**
+ * Sets the value at row i, column j to val
+ */
+ @Override
+ public void setValue(int i, int j, double val)
+ {
+ if (val == 0d)
+ {
+ sparseColumns[j].delete(i);
+ }
+ else
+ {
+ sparseColumns[j].put(i, val);
+ }
+ }
+
+ @Override
+ public double[] getColumn(int i)
+ {
+ double[] col = new double[height()];
+
+ SparseDoubleArray vals = sparseColumns[i];
+ for (int nonZero = 0; nonZero < vals.size(); nonZero++)
+ {
+ col[vals.keyAt(nonZero)] = vals.valueAt(nonZero);
+ }
+ return col;
+ }
+
+ @Override
+ public MatrixI copy()
+ {
+ double[][] vals = new double[height()][width()];
+ for (int i = 0; i < height(); i++)
+ {
+ vals[i] = getRow(i);
+ }
+ return new SparseMatrix(vals);
+ }
+
+ @Override
+ public MatrixI transpose()
+ {
+ double[][] out = new double[cols][rows];
+
+ /*
+ * for each column...
+ */
+ for (int i = 0; i < cols; i++)
+ {
+ /*
+ * put non-zero values into the corresponding row
+ * of the transposed matrix
+ */
+ SparseDoubleArray vals = sparseColumns[i];
+ for (int nonZero = 0; nonZero < vals.size(); nonZero++)
+ {
+ out[i][vals.keyAt(nonZero)] = vals.valueAt(nonZero);
+ }
+ }
+
+ return new SparseMatrix(out);
+ }
+
+ /**
+ * Answers a new matrix which is the product in.this. If the product contains
+ * less than 20% non-zero values, it is returned as a SparseMatrix, else as a
+ * Matrix.
+ * <p>
+ * This method is optimised for the sparse arrays which store column values
+ * for a SparseMatrix. Note that postMultiply is not so optimised. That would
+ * require redundantly also storing sparse arrays for the rows, which has not
+ * been done. Currently only preMultiply is used in Jalview.
+ */
+ @Override
+ public MatrixI preMultiply(MatrixI in)
+ {
+ if (in.width() != rows)
+ {
+ throw new IllegalArgumentException("Can't pre-multiply " + this.rows
+ + " rows by " + in.width() + " columns");
+ }
+ double[][] tmp = new double[in.height()][this.cols];
+
+ long count = 0L;
+ for (int i = 0; i < in.height(); i++)
+ {
+ for (int j = 0; j < this.cols; j++)
+ {
+ /*
+ * result[i][j] is the vector product of
+ * in.row[i] and this.column[j]
+ * we only need to use non-zero values from the column
+ */
+ SparseDoubleArray vals = sparseColumns[j];
+ boolean added = false;
+ for (int nonZero = 0; nonZero < vals.size(); nonZero++)
+ {
+ int myRow = vals.keyAt(nonZero);
+ double myValue = vals.valueAt(nonZero);
+ tmp[i][j] += (in.getValue(i, myRow) * myValue);
+ added = true;
+ }
+ if (added && tmp[i][j] != 0d)
+ {
+ count++; // non-zero entry in product
+ }
+ }
+ }
+
+ /*
+ * heuristic rule - if product is more than 80% zero
+ * then construct a SparseMatrix, else a Matrix
+ */
+ if (count * 5 < in.height() * cols)
+ {
+ return new SparseMatrix(tmp);
+ }
+ else
+ {
+ return new Matrix(tmp);
+ }
+ }
+
+ @Override
+ protected double divideValue(int i, int j, double divisor)
+ {
+ if (divisor == 0d)
+ {
+ return getValue(i, j);
+ }
+ double v = sparseColumns[j].divide(i, divisor);
+ return v;
+ }
+
+ @Override
+ protected double addValue(int i, int j, double addend)
+ {
+ double v = sparseColumns[j].add(i, addend);
+ return v;
+ }
+
+ /**
+ * Returns the fraction of the whole matrix size that is actually modelled in
+ * sparse arrays (normally, the non-zero values)
+ *
+ * @return
+ */
+ public float getFillRatio()
+ {
+ long count = 0L;
+ for (SparseDoubleArray col : sparseColumns)
+ {
+ count += col.size();
+ }
+ return count / (float) (height() * width());
+ }
+}
public void updateFromAlignViewport(AlignViewportI av)
{
charWidth = av.getCharWidth();
- endRes = av.getEndRes();
+ endRes = av.getRanges().getEndRes();
charHeight = av.getCharHeight();
hasHiddenColumns = av.hasHiddenColumns();
validCharWidth = av.isValidCharWidth();
private boolean conservationColouring;
/*
- * the phsyico-chemical property conservation scores for columns, with values
+ * the physico-chemical property conservation scores for columns, with values
* 0-9, '+' (all properties conserved), '*' (residue fully conserved) or '-' (gap)
* (may be null if colour by conservation is not selected)
*/
--- /dev/null
+package jalview.renderer.seqfeatures;
+
+import jalview.api.FeatureRenderer;
+import jalview.api.FeaturesDisplayedI;
+import jalview.datamodel.SequenceI;
+import jalview.viewmodel.seqfeatures.FeatureRendererModel;
+
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.image.BufferedImage;
+
+/**
+ * A helper class to find feature colour using an associated FeatureRenderer
+ *
+ * @author gmcarstairs
+ *
+ */
+public class FeatureColourFinder
+{
+ /*
+ * the class we delegate feature finding to
+ */
+ private FeatureRenderer featureRenderer;
+
+ /*
+ * a 1-pixel image on which features can be drawn, for the case where
+ * transparency allows 'see-through' of multiple feature colours
+ */
+ private BufferedImage offscreenImage;
+
+ /**
+ * Constructor
+ *
+ * @param fr
+ */
+ public FeatureColourFinder(FeatureRenderer fr)
+ {
+ featureRenderer = fr;
+ offscreenImage = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
+ }
+
+ /**
+ * Answers the feature colour to show for the given sequence and column
+ * position. This delegates to the FeatureRenderer to find the colour, which
+ * will depend on feature location, visibility, ordering, colour scheme, and
+ * whether or not transparency is applied. For feature rendering with
+ * transparency, this class provides a dummy 'offscreen' graphics context
+ * where multiple feature colours can be overlaid and the combined colour read
+ * back.
+ * <p>
+ * This method is not thread-safe when transparency is applied, since a shared
+ * BufferedImage would be used by all threads to hold the composite colour at
+ * a position. Each thread should use a separate instance of this class.
+ *
+ * @param defaultColour
+ * @param seq
+ * @param column
+ * alignment column position (base zero)
+ * @return
+ */
+ public Color findFeatureColour(Color defaultColour, SequenceI seq,
+ int column)
+ {
+ if (noFeaturesDisplayed())
+ {
+ return defaultColour;
+ }
+
+ Graphics g = null;
+
+ /*
+ * if transparency applies, provide a notional 1x1 graphics context
+ * that has been primed with the default colour
+ */
+ if (featureRenderer.getTransparency() != 1f)
+ {
+ g = offscreenImage.getGraphics();
+ if (defaultColour != null)
+ {
+ offscreenImage.setRGB(0, 0, defaultColour.getRGB());
+ }
+ }
+
+ Color c = featureRenderer.findFeatureColour(seq, column, g);
+ if (c == null)
+ {
+ return defaultColour;
+ }
+
+ if (g != null)
+ {
+ c = new Color(offscreenImage.getRGB(0, 0));
+ }
+ return c;
+ }
+
+ /**
+ * Answers true if feature display is turned off, or there are no features
+ * configured to be visible
+ *
+ * @return
+ */
+ boolean noFeaturesDisplayed()
+ {
+ if (featureRenderer == null
+ || !featureRenderer.getViewport().isShowSequenceFeatures())
+ {
+ return true;
+ }
+
+ if (!((FeatureRendererModel) featureRenderer).hasRenderOrder())
+ {
+ return true;
+ }
+
+ FeaturesDisplayedI displayed = featureRenderer.getFeaturesDisplayed();
+ if (displayed == null || displayed.getVisibleFeatureCount() == 0)
+ {
+ return true;
+ }
+
+ return false;
+ }
+}
import jalview.api.AlignViewportI;
import jalview.datamodel.SequenceFeature;
import jalview.datamodel.SequenceI;
+import jalview.util.Comparison;
import jalview.viewmodel.seqfeatures.FeatureRendererModel;
import java.awt.AlphaComposite;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
-import java.awt.image.BufferedImage;
public class FeatureRenderer extends FeatureRendererModel
{
-
- FontMetrics fm;
-
- int charOffset;
-
- boolean offscreenRender = false;
-
- protected SequenceI lastSeq;
-
- char s;
-
- int i;
-
- int av_charHeight, av_charWidth;
-
- boolean av_validCharWidth, av_isShowSeqFeatureHeight;
-
- private Integer currentColour;
+ private static final AlphaComposite NO_TRANSPARENCY = AlphaComposite
+ .getInstance(AlphaComposite.SRC_OVER, 1.0f);
/**
* Constructor given a viewport
this.av = viewport;
}
- protected void updateAvConfig()
+ /**
+ * Renders the sequence using the given feature colour between the given start
+ * and end columns. Returns true if at least one column is drawn, else false
+ * (the feature range does not overlap the start and end positions).
+ *
+ * @param g
+ * @param seq
+ * @param featureStart
+ * @param featureEnd
+ * @param featureColour
+ * @param start
+ * @param end
+ * @param y1
+ * @param colourOnly
+ * @return
+ */
+ boolean renderFeature(Graphics g, SequenceI seq, int featureStart,
+ int featureEnd, Color featureColour, int start, int end, int y1,
+ boolean colourOnly)
{
- av_charHeight = av.getCharHeight();
- av_charWidth = av.getCharWidth();
- av_validCharWidth = av.isValidCharWidth();
- av_isShowSeqFeatureHeight = av.isShowSequenceFeaturesHeight();
- }
+ int charHeight = av.getCharHeight();
+ int charWidth = av.getCharWidth();
+ boolean validCharWidth = av.isValidCharWidth();
- void renderFeature(Graphics g, SequenceI seq, int fstart, int fend,
- Color featureColour, int start, int end, int y1)
- {
- updateAvConfig();
- if (((fstart <= end) && (fend >= start)))
+ if (featureStart > end || featureEnd < start)
{
- if (fstart < start)
- { // fix for if the feature we have starts before the sequence start,
- fstart = start; // but the feature end is still valid!!
- }
-
- if (fend >= end)
- {
- fend = end;
- }
- int pady = (y1 + av_charHeight) - av_charHeight / 5;
- for (i = fstart; i <= fend; i++)
- {
- s = seq.getCharAt(i);
-
- if (jalview.util.Comparison.isGap(s))
- {
- continue;
- }
-
- g.setColor(featureColour);
-
- g.fillRect((i - start) * av_charWidth, y1, av_charWidth,
- av_charHeight);
-
- if (offscreenRender || !av_validCharWidth)
- {
- continue;
- }
-
- g.setColor(Color.white);
- charOffset = (av_charWidth - fm.charWidth(s)) / 2;
- g.drawString(String.valueOf(s), charOffset
- + (av_charWidth * (i - start)), pady);
+ return false;
+ }
- }
+ if (featureStart < start)
+ {
+ featureStart = start;
}
- }
+ if (featureEnd >= end)
+ {
+ featureEnd = end;
+ }
+ int pady = (y1 + charHeight) - charHeight / 5;
- void renderScoreFeature(Graphics g, SequenceI seq, int fstart, int fend,
- Color featureColour, int start, int end, int y1, byte[] bs)
- {
- updateAvConfig();
- if (((fstart <= end) && (fend >= start)))
+ FontMetrics fm = g.getFontMetrics();
+ for (int i = featureStart; i <= featureEnd; i++)
{
- if (fstart < start)
- { // fix for if the feature we have starts before the sequence start,
- fstart = start; // but the feature end is still valid!!
- }
+ char s = seq.getCharAt(i);
- if (fend >= end)
- {
- fend = end;
- }
- int pady = (y1 + av_charHeight) - av_charHeight / 5;
- int ystrt = 0, yend = av_charHeight;
- if (bs[0] != 0)
- {
- // signed - zero is always middle of residue line.
- if (bs[1] < 128)
- {
- yend = av_charHeight * (128 - bs[1]) / 512;
- ystrt = av_charHeight - yend / 2;
- }
- else
- {
- ystrt = av_charHeight / 2;
- yend = av_charHeight * (bs[1] - 128) / 512;
- }
- }
- else
+ if (Comparison.isGap(s))
{
- yend = av_charHeight * bs[1] / 255;
- ystrt = av_charHeight - yend;
-
+ continue;
}
- for (i = fstart; i <= fend; i++)
- {
- s = seq.getCharAt(i);
-
- if (jalview.util.Comparison.isGap(s))
- {
- continue;
- }
- g.setColor(featureColour);
- int x = (i - start) * av_charWidth;
- g.drawRect(x, y1, av_charWidth, av_charHeight);
- g.fillRect(x, y1 + ystrt, av_charWidth, yend);
+ g.setColor(featureColour);
- if (offscreenRender || !av_validCharWidth)
- {
- continue;
- }
+ g.fillRect((i - start) * charWidth, y1, charWidth,
+ charHeight);
- g.setColor(Color.black);
- charOffset = (av_charWidth - fm.charWidth(s)) / 2;
- g.drawString(String.valueOf(s), charOffset
- + (av_charWidth * (i - start)), pady);
+ if (colourOnly || !validCharWidth)
+ {
+ continue;
}
- }
- }
-
- BufferedImage offscreenImage;
- @Override
- public Color findFeatureColour(Color initialCol, SequenceI seq, int res)
- {
- return new Color(findFeatureColour(initialCol.getRGB(), seq, res));
+ g.setColor(Color.white);
+ int charOffset = (charWidth - fm.charWidth(s)) / 2;
+ g.drawString(String.valueOf(s), charOffset
+ + (charWidth * (i - start)), pady);
+ }
+ return true;
}
/**
- * This is used by Structure Viewers and the Overview Window to get the
- * feature colour of the rendered sequence, returned as an RGB value
+ * Renders the sequence using the given SCORE feature colour between the given
+ * start and end columns. Returns true if at least one column is drawn, else
+ * false (the feature range does not overlap the start and end positions).
*
- * @param defaultColour
+ * @param g
* @param seq
- * @param column
+ * @param fstart
+ * @param fend
+ * @param featureColour
+ * @param start
+ * @param end
+ * @param y1
+ * @param bs
+ * @param colourOnly
* @return
*/
- public synchronized int findFeatureColour(int defaultColour,
- final SequenceI seq, int column)
+ boolean renderScoreFeature(Graphics g, SequenceI seq, int fstart,
+ int fend, Color featureColour, int start, int end, int y1,
+ byte[] bs, boolean colourOnly)
{
- if (!av.isShowSequenceFeatures())
+ if (fstart > end || fend < start)
{
- return defaultColour;
+ return false;
}
- SequenceFeature[] sequenceFeatures = seq.getSequenceFeatures();
- if (seq != lastSeq)
+ if (fstart < start)
+ { // fix for if the feature we have starts before the sequence start,
+ fstart = start; // but the feature end is still valid!!
+ }
+
+ if (fend >= end)
+ {
+ fend = end;
+ }
+ int charHeight = av.getCharHeight();
+ int pady = (y1 + charHeight) - charHeight / 5;
+ int ystrt = 0, yend = charHeight;
+ if (bs[0] != 0)
{
- lastSeq = seq;
- lastSequenceFeatures = sequenceFeatures;
- if (lastSequenceFeatures != null)
+ // signed - zero is always middle of residue line.
+ if (bs[1] < 128)
{
- sfSize = lastSequenceFeatures.length;
+ yend = charHeight * (128 - bs[1]) / 512;
+ ystrt = charHeight - yend / 2;
+ }
+ else
+ {
+ ystrt = charHeight / 2;
+ yend = charHeight * (bs[1] - 128) / 512;
}
}
else
{
- if (lastSequenceFeatures != sequenceFeatures)
+ yend = charHeight * bs[1] / 255;
+ ystrt = charHeight - yend;
+
+ }
+
+ FontMetrics fm = g.getFontMetrics();
+ int charWidth = av.getCharWidth();
+
+ for (int i = fstart; i <= fend; i++)
+ {
+ char s = seq.getCharAt(i);
+
+ if (Comparison.isGap(s))
{
- lastSequenceFeatures = sequenceFeatures;
- if (lastSequenceFeatures != null)
- {
- sfSize = lastSequenceFeatures.length;
- }
+ continue;
}
+
+ g.setColor(featureColour);
+ int x = (i - start) * charWidth;
+ g.drawRect(x, y1, charWidth, charHeight);
+ g.fillRect(x, y1 + ystrt, charWidth, yend);
+
+ if (colourOnly || !av.isValidCharWidth())
+ {
+ continue;
+ }
+
+ g.setColor(Color.black);
+ int charOffset = (charWidth - fm.charWidth(s)) / 2;
+ g.drawString(String.valueOf(s), charOffset
+ + (charWidth * (i - start)), pady);
}
+ return true;
+ }
- if (lastSequenceFeatures == null || sfSize == 0)
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Color findFeatureColour(SequenceI seq, int column, Graphics g)
+ {
+ if (!av.isShowSequenceFeatures())
{
- return defaultColour;
+ return null;
}
- if (jalview.util.Comparison.isGap(lastSeq.getCharAt(column)))
+ SequenceFeature[] sequenceFeatures = seq.getSequenceFeatures();
+
+ if (sequenceFeatures == null || sequenceFeatures.length == 0)
{
- return Color.white.getRGB();
+ return null;
}
- // Only bother making an offscreen image if transparency is applied
- if (transparency != 1.0f && offscreenImage == null)
+ if (Comparison.isGap(seq.getCharAt(column)))
{
- offscreenImage = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
+ return Color.white;
}
- currentColour = null;
- // TODO: non-threadsafe - each rendering thread needs its own instance of
- // the feature renderer - or this should be synchronized.
- offscreenRender = true;
-
- if (offscreenImage != null)
+ Color renderedColour = null;
+ if (transparency == 1.0f)
{
- offscreenImage.setRGB(0, 0, defaultColour);
- drawSequence(offscreenImage.getGraphics(), lastSeq, column, column, 0);
-
- return offscreenImage.getRGB(0, 0);
+ /*
+ * simple case - just find the topmost rendered visible feature colour
+ */
+ renderedColour = findFeatureColour(seq, seq.findPosition(column));
}
else
{
- drawSequence(null, lastSeq, lastSeq.findPosition(column), -1, -1);
-
- if (currentColour == null)
- {
- return defaultColour;
- }
- else
- {
- return currentColour.intValue();
- }
+ /*
+ * transparency case - draw all visible features in render order to
+ * build up a composite colour on the graphics context
+ */
+ renderedColour = drawSequence(g, seq, column, column, 0, true);
}
-
+ return renderedColour;
}
- private volatile SequenceFeature[] lastSequenceFeatures;
-
- int sfSize;
-
- int sfindex;
-
- int spos;
-
- int epos;
-
/**
- * Draws the sequence on the graphics context, or just determines the colour
- * that would be drawn (if flag offscreenrender is true).
+ * Draws the sequence features on the graphics context, or just determines the
+ * colour that would be drawn (if flag colourOnly is true). Returns the last
+ * colour drawn (which may not be the effective colour if transparency
+ * applies), or null if no feature is drawn in the range given.
*
* @param g
+ * the graphics context to draw on (may be null if colourOnly==true)
* @param seq
* @param start
- * start column (or sequence position in offscreenrender mode)
+ * start column
* @param end
- * end column (not used in offscreenrender mode)
+ * end column
* @param y1
* vertical offset at which to draw on the graphics
+ * @param colourOnly
+ * if true, only do enough to determine the colour for the position,
+ * do not draw the character
+ * @return
*/
- public synchronized void drawSequence(Graphics g, final SequenceI seq,
- int start, int end, int y1)
+ public synchronized Color drawSequence(final Graphics g,
+ final SequenceI seq, int start, int end, int y1,
+ boolean colourOnly)
{
SequenceFeature[] sequenceFeatures = seq.getSequenceFeatures();
if (sequenceFeatures == null || sequenceFeatures.length == 0)
{
- return;
- }
-
- if (g != null)
- {
- fm = g.getFontMetrics();
+ return null;
}
updateFeatures();
- if (lastSeq == null || seq != lastSeq
- || sequenceFeatures != lastSequenceFeatures)
- {
- lastSeq = seq;
- lastSequenceFeatures = sequenceFeatures;
- }
-
- if (transparency != 1 && g != null)
+ if (transparency != 1f && g != null)
{
Graphics2D g2 = (Graphics2D) g;
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
transparency));
}
- if (!offscreenRender)
- {
- spos = lastSeq.findPosition(start);
- epos = lastSeq.findPosition(end);
- }
+ int startPos = seq.findPosition(start);
+ int endPos = seq.findPosition(end);
+
+ int sfSize = sequenceFeatures.length;
+ Color drawnColour = null;
- sfSize = lastSequenceFeatures.length;
+ /*
+ * iterate over features in ordering of their rendering (last is on top)
+ */
for (int renderIndex = 0; renderIndex < renderOrder.length; renderIndex++)
{
String type = renderOrder[renderIndex];
// loop through all features in sequence to find
// current feature to render
- for (sfindex = 0; sfindex < sfSize; sfindex++)
+ for (int sfindex = 0; sfindex < sfSize; sfindex++)
{
- final SequenceFeature sequenceFeature = lastSequenceFeatures[sfindex];
+ final SequenceFeature sequenceFeature = sequenceFeatures[sfindex];
if (!sequenceFeature.type.equals(type))
{
continue;
}
+ /*
+ * a feature type may be flagged as shown but the group
+ * an instance of it belongs to may be hidden
+ */
if (featureGroupNotShown(sequenceFeature))
{
continue;
}
/*
- * check feature overlaps the visible part of the alignment,
- * unless doing offscreenRender (to the Overview window or a
- * structure viewer) which is not limited
+ * check feature overlaps the target range
+ * TODO: efficient retrieval of features overlapping a range
*/
- if (!offscreenRender
- && (sequenceFeature.getBegin() > epos || sequenceFeature
- .getEnd() < spos))
+ if (sequenceFeature.getBegin() > endPos
+ || sequenceFeature.getEnd() < startPos)
{
continue;
}
Color featureColour = getColour(sequenceFeature);
boolean isContactFeature = sequenceFeature.isContactFeature();
- if (offscreenRender && offscreenImage == null)
- {
- /*
- * offscreen mode with no image (image is only needed if transparency
- * is applied to feature colours) - just check feature is rendered at
- * the requested position (start == sequence position in this mode)
- */
- boolean featureIsAtPosition = sequenceFeature.begin <= start
- && sequenceFeature.end >= start;
- if (isContactFeature)
- {
- featureIsAtPosition = sequenceFeature.begin == start
- || sequenceFeature.end == start;
- }
- if (featureIsAtPosition)
- {
- // this is passed out to the overview and other sequence renderers
- // (e.g. molecule viewer) to get displayed colour for rendered
- // sequence
- currentColour = new Integer(featureColour.getRGB());
- // used to be retreived from av.featuresDisplayed
- // currentColour = av.featuresDisplayed
- // .get(sequenceFeatures[sfindex].type);
-
- }
- }
- else if (isContactFeature)
+ if (isContactFeature)
{
- renderFeature(g, seq, seq.findIndex(sequenceFeature.begin) - 1,
+ boolean drawn = renderFeature(g, seq,
+ seq.findIndex(sequenceFeature.begin) - 1,
seq.findIndex(sequenceFeature.begin) - 1, featureColour,
- start, end, y1);
- renderFeature(g, seq, seq.findIndex(sequenceFeature.end) - 1,
+ start, end, y1, colourOnly);
+ drawn |= renderFeature(g, seq,
+ seq.findIndex(sequenceFeature.end) - 1,
seq.findIndex(sequenceFeature.end) - 1, featureColour,
- start, end, y1);
-
+ start, end, y1, colourOnly);
+ if (drawn)
+ {
+ drawnColour = featureColour;
+ }
}
else if (showFeature(sequenceFeature))
{
- if (av_isShowSeqFeatureHeight
+ if (av.isShowSequenceFeaturesHeight()
&& !Float.isNaN(sequenceFeature.score))
{
- renderScoreFeature(g, seq,
+ boolean drawn = renderScoreFeature(g, seq,
seq.findIndex(sequenceFeature.begin) - 1,
- seq.findIndex(sequenceFeature.end) - 1,
- featureColour, start, end, y1,
- normaliseScore(sequenceFeature));
+ seq.findIndex(sequenceFeature.end) - 1, featureColour,
+ start, end, y1, normaliseScore(sequenceFeature),
+ colourOnly);
+ if (drawn)
+ {
+ drawnColour = featureColour;
+ }
}
else
{
- renderFeature(g, seq, seq.findIndex(sequenceFeature.begin) - 1,
- seq.findIndex(sequenceFeature.end) - 1,
- featureColour, start, end, y1);
+ boolean drawn = renderFeature(g, seq,
+ seq.findIndex(sequenceFeature.begin) - 1,
+ seq.findIndex(sequenceFeature.end) - 1, featureColour,
+ start, end, y1, colourOnly);
+ if (drawn)
+ {
+ drawnColour = featureColour;
+ }
}
}
}
if (transparency != 1.0f && g != null)
{
+ /*
+ * reset transparency
+ */
Graphics2D g2 = (Graphics2D) g;
- g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
- 1.0f));
+ g2.setComposite(NO_TRANSPARENCY);
}
+
+ return drawnColour;
}
/**
@Override
public void featuresAdded()
{
- lastSeq = null;
findAllFeatures();
}
+
+ /**
+ * Returns the sequence feature colour rendered at the given sequence
+ * position, or null if none found. The feature of highest render order (i.e.
+ * on top) is found, subject to both feature type and feature group being
+ * visible, and its colour returned.
+ *
+ * @param seq
+ * @param pos
+ * @return
+ */
+ Color findFeatureColour(SequenceI seq, int pos)
+ {
+ SequenceFeature[] sequenceFeatures = seq.getSequenceFeatures();
+ if (sequenceFeatures == null || sequenceFeatures.length == 0)
+ {
+ return null;
+ }
+
+ /*
+ * check for new feature added while processing
+ */
+ updateFeatures();
+
+ /*
+ * inspect features in reverse renderOrder (the last in the array is
+ * displayed on top) until we find one that is rendered at the position
+ */
+ for (int renderIndex = renderOrder.length - 1; renderIndex >= 0; renderIndex--)
+ {
+ String type = renderOrder[renderIndex];
+ if (!showFeatureOfType(type))
+ {
+ continue;
+ }
+
+ for (int sfindex = 0; sfindex < sequenceFeatures.length; sfindex++)
+ {
+ SequenceFeature sequenceFeature = sequenceFeatures[sfindex];
+ if (!sequenceFeature.type.equals(type))
+ {
+ continue;
+ }
+
+ if (featureGroupNotShown(sequenceFeature))
+ {
+ continue;
+ }
+
+ /*
+ * check the column position is within the feature range
+ * (or is one of the two contact positions for a contact feature)
+ */
+ boolean featureIsAtPosition = sequenceFeature.begin <= pos
+ && sequenceFeature.end >= pos;
+ if (sequenceFeature.isContactFeature())
+ {
+ featureIsAtPosition = sequenceFeature.begin == pos
+ || sequenceFeature.end == pos;
+ }
+ if (featureIsAtPosition)
+ {
+ return getColour(sequenceFeature);
+ }
+ }
+ }
+
+ /*
+ * no displayed feature found at position
+ */
+ return null;
+ }
}
--- /dev/null
+package jalview.schemes;
+
+import jalview.binding.JalviewUserColours;
+
+import java.awt.Color;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStreamReader;
+
+import org.exolab.castor.xml.Unmarshaller;
+
+public class ColourSchemeLoader
+{
+
+ /**
+ * Loads a user defined colour scheme from file. The file should contain a
+ * definition of residue colours in XML format as defined in
+ * JalviewUserColours.xsd.
+ *
+ * @param filePath
+ *
+ * @return
+ */
+ public static UserColourScheme loadColourScheme(String filePath)
+ {
+ UserColourScheme ucs = null;
+ Color[] newColours = null;
+ File file = new File(filePath);
+ try
+ {
+ InputStreamReader in = new InputStreamReader(
+ new FileInputStream(file), "UTF-8");
+
+ jalview.schemabinding.version2.JalviewUserColours jucs = new jalview.schemabinding.version2.JalviewUserColours();
+
+ org.exolab.castor.xml.Unmarshaller unmar = new org.exolab.castor.xml.Unmarshaller(
+ jucs);
+ jucs = (jalview.schemabinding.version2.JalviewUserColours) unmar
+ .unmarshal(in);
+
+ /*
+ * non-case-sensitive colours are for 20 amino acid codes,
+ * B, Z, X and Gap
+ * optionally, lower-case alternatives for all except Gap
+ */
+ newColours = new Color[24];
+ Color[] lowerCase = new Color[23];
+ boolean caseSensitive = false;
+
+ String name;
+ int index;
+ for (int i = 0; i < jucs.getColourCount(); i++)
+ {
+ name = jucs.getColour(i).getName();
+ if (ResidueProperties.aa3Hash.containsKey(name))
+ {
+ index = ResidueProperties.aa3Hash.get(name).intValue();
+ }
+ else
+ {
+ index = ResidueProperties.aaIndex[name.charAt(0)];
+ }
+ if (index == -1)
+ {
+ continue;
+ }
+
+ Color color = new Color(Integer.parseInt(jucs.getColour(i)
+ .getRGB(), 16));
+ if (name.toLowerCase().equals(name))
+ {
+ caseSensitive = true;
+ lowerCase[index] = color;
+ }
+ else
+ {
+ newColours[index] = color;
+ }
+ }
+
+ /*
+ * instantiate the colour scheme
+ */
+ ucs = new UserColourScheme(newColours);
+ ucs.setName(jucs.getSchemeName());
+ if (caseSensitive)
+ {
+ ucs.setLowerCaseColours(lowerCase);
+ }
+ } catch (Exception ex)
+ {
+ // Could be old Jalview Archive format
+ try
+ {
+ InputStreamReader in = new InputStreamReader(new FileInputStream(
+ file), "UTF-8");
+
+ jalview.binding.JalviewUserColours jucs = new jalview.binding.JalviewUserColours();
+
+ jucs = JalviewUserColours.unmarshal(in);
+
+ newColours = new Color[jucs.getColourCount()];
+
+ for (int i = 0; i < 24; i++)
+ {
+ newColours[i] = new Color(Integer.parseInt(jucs.getColour(i)
+ .getRGB(), 16));
+ }
+ ucs = new UserColourScheme(newColours);
+ ucs.setName(jucs.getSchemeName());
+ } catch (Exception ex2)
+ {
+ ex2.printStackTrace();
+ }
+
+ if (newColours == null)
+ {
+ System.out.println("Error loading User ColourFile\n" + ex);
+ }
+ }
+
+ return ucs;
+ }
+
+}
package jalview.schemes;
-import jalview.binding.JalviewUserColours;
import jalview.datamodel.AnnotatedCollectionI;
import jalview.datamodel.SequenceCollectionI;
import jalview.datamodel.SequenceI;
-import java.awt.Color;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.InputStreamReader;
import java.util.LinkedHashMap;
import java.util.Map;
}
return false;
}
-
- /**
- * Loads a user defined colour scheme from file. The file should contain a
- * definition of residue colours in XML format as defined in
- * JalviewUserColours.xsd.
- *
- * @param filePath
- *
- * @return
- */
- public static UserColourScheme loadColourScheme(String filePath)
- {
- UserColourScheme ucs = null;
- Color[] newColours = null;
- File file = new File(filePath);
- try
- {
- InputStreamReader in = new InputStreamReader(
- new FileInputStream(file), "UTF-8");
-
- jalview.schemabinding.version2.JalviewUserColours jucs = new jalview.schemabinding.version2.JalviewUserColours();
-
- org.exolab.castor.xml.Unmarshaller unmar = new org.exolab.castor.xml.Unmarshaller(
- jucs);
- jucs = (jalview.schemabinding.version2.JalviewUserColours) unmar
- .unmarshal(in);
-
- /*
- * non-case-sensitive colours are for 20 amino acid codes,
- * B, Z, X and Gap
- * optionally, lower-case alternatives for all except Gap
- */
- newColours = new Color[24];
- Color[] lowerCase = new Color[23];
- boolean caseSensitive = false;
-
- String name;
- int index;
- for (int i = 0; i < jucs.getColourCount(); i++)
- {
- name = jucs.getColour(i).getName();
- if (ResidueProperties.aa3Hash.containsKey(name))
- {
- index = ResidueProperties.aa3Hash.get(name).intValue();
- }
- else
- {
- index = ResidueProperties.aaIndex[name.charAt(0)];
- }
- if (index == -1)
- {
- continue;
- }
-
- Color color = new Color(Integer.parseInt(jucs.getColour(i)
- .getRGB(), 16));
- if (name.toLowerCase().equals(name))
- {
- caseSensitive = true;
- lowerCase[index] = color;
- }
- else
- {
- newColours[index] = color;
- }
- }
-
- /*
- * instantiate the colour scheme
- */
- ucs = new UserColourScheme(newColours);
- ucs.setName(jucs.getSchemeName());
- if (caseSensitive)
- {
- ucs.setLowerCaseColours(lowerCase);
- }
- } catch (Exception ex)
- {
- // Could be old Jalview Archive format
- try
- {
- InputStreamReader in = new InputStreamReader(new FileInputStream(
- file), "UTF-8");
-
- jalview.binding.JalviewUserColours jucs = new jalview.binding.JalviewUserColours();
-
- jucs = JalviewUserColours.unmarshal(in);
-
- newColours = new Color[jucs.getColourCount()];
-
- for (int i = 0; i < 24; i++)
- {
- newColours[i] = new Color(Integer.parseInt(jucs.getColour(i)
- .getRGB(), 16));
- }
- ucs = new UserColourScheme(newColours);
- ucs.setName(jucs.getSchemeName());
- } catch (Exception ex2)
- {
- ex2.printStackTrace();
- }
-
- if (newColours == null)
- {
- System.out.println("Error loading User ColourFile\n" + ex);
- }
- }
-
- return ucs;
- }
}
-3, 3, 0, -1, -4 },
{ -2, -2, 1, 6, -3, 0, 2, -1, -1, -3, -4, -1, -3, -3, -1, 0, -1, -4,
-3, -3, 4, 1, -1, -4 },
- { 0, 3, -3, -3, 9, -3, -4, -3, -3, -1, -1, -3, -1, -2, -3, -1, -1,
+ { 0, -3, -3, -3, 9, -3, -4, -3, -3, -1, -1, -3, -1, -2, -3, -1, -1,
-2, -2, -1, -3, -3, -2, -4 },
{ -1, 1, 0, 0, -3, 5, 2, -2, 0, -3, -2, 1, 0, -3, -1, 0, -1, -2, -1,
-2, 0, 3, -1, -4 },
package jalview.schemes;
import jalview.analysis.scoremodels.PairwiseSeqScoreModel;
-import jalview.api.analysis.ScoreModelI;
+import jalview.math.Matrix;
+import jalview.math.MatrixI;
-public class ScoreMatrix extends PairwiseSeqScoreModel implements
- ScoreModelI
+public class ScoreMatrix extends PairwiseSeqScoreModel
{
String name;
}
/**
+ * Answers the score for substituting first char in A1 with first char in A2
*
* @param A1
* @param A2
- * @return score for substituting first char in A1 with first char in A2
+ * @return
*/
public int getPairwiseScore(String A1, String A2)
{
return getPairwiseScore(A1.charAt(0), A2.charAt(0));
}
+ @Override
public int getPairwiseScore(char c, char d)
{
- int pog = 0;
+ int score = 0;
try
{
: ResidueProperties.nucleotideIndex[c];
int b = (type == 0) ? ResidueProperties.aaIndex[d]
: ResidueProperties.nucleotideIndex[d];
-
- pog = matrix[a][b];
+ score = matrix[a][b];
} catch (Exception e)
{
// System.out.println("Unknown residue in " + A1 + " " + A2);
}
- return pog;
+ return score;
}
/**
* pretty print the matrix
*/
+ @Override
public String toString()
{
return outputMatrix(false);
}
return sb.toString();
}
+
+ /**
+ * Computes an NxN matrix where N is the number of sequences, and entry [i, j]
+ * is sequence[i] pairwise multiplied with sequence[j], as a sum of scores
+ * computed using the current score matrix. For example
+ * <ul>
+ * <li>Sequences:</li>
+ * <li>FKL</li>
+ * <li>R-D</li>
+ * <li>QIA</li>
+ * <li>GWC</li>
+ * <li>Score matrix is BLOSUM62</li>
+ * <li>Gaps treated same as X (unknown)</li>
+ * <li>product [0, 0] = F.F + K.K + L.L = 6 + 5 + 4 = 15</li>
+ * <li>product [1, 1] = R.R + -.- + D.D = 5 + -1 + 6 = 10</li>
+ * <li>product [2, 2] = Q.Q + I.I + A.A = 5 + 4 + 4 = 13</li>
+ * <li>product [3, 3] = G.G + W.W + C.C = 6 + 11 + 9 = 26</li>
+ * <li>product[0, 1] = F.R + K.- + L.D = -3 + -1 + -3 = -8
+ * <li>and so on</li>
+ * </ul>
+ */
+ public MatrixI computePairwiseScores(String[] seqs)
+ {
+ double[][] values = new double[seqs.length][];
+ for (int row = 0; row < seqs.length; row++)
+ {
+ values[row] = new double[seqs.length];
+ for (int col = 0; col < seqs.length; col++)
+ {
+ int total = 0;
+ int width = Math.min(seqs[row].length(), seqs[col].length());
+ for (int i = 0; i < width; i++)
+ {
+ char c1 = seqs[row].charAt(i);
+ char c2 = seqs[col].charAt(i);
+ int score = getPairwiseScore(c1, c2);
+ total += score;
+ }
+ values[row][col] = total;
+ }
+ }
+ return new Matrix(values);
+ }
}
*/
public class AtomSpec
{
- // TODO clarify do we want pdbFile here, or pdbId?
- // compare highlightAtom in 2.8.2 for JalviewJmolBinding and
- // javascript.MouseOverStructureListener
+ int modelNo;
+
private String pdbFile;
private String chain;
private int atomIndex;
/**
+ * Parses a Chimera atomspec e.g. #1:12.A to construct an AtomSpec model (with
+ * null pdb file name)
+ *
+ * @param spec
+ * @return
+ * @throw IllegalArgumentException if the spec cannot be parsed, or represents
+ * more than one residue
+ */
+ public static AtomSpec fromChimeraAtomspec(String spec)
+ {
+ int colonPos = spec.indexOf(":");
+ if (colonPos == -1)
+ {
+ throw new IllegalArgumentException(spec);
+ }
+
+ int hashPos = spec.indexOf("#");
+ if (hashPos == -1 && colonPos != 0)
+ {
+ // # is missing but something precedes : - reject
+ throw new IllegalArgumentException(spec);
+ }
+
+ String modelSubmodel = spec.substring(hashPos + 1, colonPos);
+ int dotPos = modelSubmodel.indexOf(".");
+ int modelId = 0;
+ try
+ {
+ modelId = Integer.valueOf(dotPos == -1 ? modelSubmodel
+ : modelSubmodel.substring(0, dotPos));
+ } catch (NumberFormatException e)
+ {
+ // ignore, default to model 0
+ }
+
+ String residueChain = spec.substring(colonPos + 1);
+ dotPos = residueChain.indexOf(".");
+ int resNum = 0;
+ try
+ {
+ resNum = Integer.parseInt(dotPos == -1 ? residueChain
+ : residueChain.substring(0, dotPos));
+ } catch (NumberFormatException e)
+ {
+ // could be a range e.g. #1:4-7.B
+ throw new IllegalArgumentException(spec);
+ }
+
+ String chainId = dotPos == -1 ? "" : residueChain.substring(dotPos + 1);
+
+ return new AtomSpec(modelId, chainId, resNum, 0);
+ }
+
+ /**
* Constructor
*
* @param pdbFile
this.atomIndex = atomNo;
}
+ /**
+ * Constructor
+ *
+ * @param modelId
+ * @param chainId
+ * @param resNo
+ * @param atomNo
+ */
+ public AtomSpec(int modelId, String chainId, int resNo, int atomNo)
+ {
+ this.modelNo = modelId;
+ this.chain = chainId;
+ this.pdbResNum = resNo;
+ this.atomIndex = atomNo;
+ }
+
public String getPdbFile()
{
return pdbFile;
return atomIndex;
}
+ public int getModelNumber()
+ {
+ return modelNo;
+ }
+
+ public void setPdbFile(String file)
+ {
+ pdbFile = file;
+ }
+
@Override
public String toString()
{
import jalview.datamodel.AlignmentAnnotation;
import jalview.datamodel.SequenceI;
+import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
public class StructureMapping
{
// and atomNo
HashMap<Integer, int[]> mapping;
+ /**
+ * Constructor
+ *
+ * @param seq
+ * @param pdbfile
+ * @param pdbid
+ * @param chain
+ * @param mapping
+ * a map from sequence to two values, { resNo, atomNo } in the
+ * structure
+ * @param mappingDetails
+ */
public StructureMapping(SequenceI seq, String pdbfile, String pdbid,
String chain, HashMap<Integer, int[]> mapping,
String mappingDetails)
}
/**
+ * Returns a (possibly empty) list of [start, end] residue positions in the
+ * mapped structure, corresponding to the given range of sequence positions
+ *
+ * @param fromSeqPos
+ * @param toSeqPos
+ * @return
+ */
+ public List<int[]> getPDBResNumRanges(int fromSeqPos, int toSeqPos)
+ {
+ List<int[]> result = new ArrayList<int[]>();
+ int startRes = -1;
+ int endRes = -1;
+
+ for (int i = fromSeqPos; i <= toSeqPos; i++)
+ {
+ int resNo = getPDBResNum(i);
+ if (resNo == UNASSIGNED_VALUE)
+ {
+ continue; // no mapping from this sequence position
+ }
+ if (startRes == -1)
+ {
+ startRes = resNo;
+ endRes = resNo;
+ }
+ if (resNo >= startRes && resNo <= endRes)
+ {
+ // within the current range - no change
+ continue;
+ }
+ if (resNo == startRes - 1)
+ {
+ // extend beginning of current range
+ startRes--;
+ continue;
+ }
+ if (resNo == endRes + 1)
+ {
+ // extend end of current range
+ endRes++;
+ continue;
+ }
+
+ /*
+ * resNo is not within or contiguous with last range,
+ * so write out the last range
+ */
+ result.add(new int[] { startRes, endRes });
+ startRes = resNo;
+ endRes = resNo;
+ }
+
+ /*
+ * and add the last range
+ */
+ if (startRes != -1)
+ {
+ result.add(new int[] { startRes, endRes });
+ }
+
+ return result;
+ }
+
+ /**
*
* @param pdbResNum
* @return -1 or the corresponding sequence position for a pdb residue number
return pdb;
}
- private boolean isCIFFile(String filename)
+ public void addStructureMapping(StructureMapping sm)
{
- String fileExt = filename.substring(filename.lastIndexOf(".") + 1,
- filename.length());
- return "cif".equalsIgnoreCase(fileExt);
+ mappings.add(sm);
}
/**
return;
}
+ SearchResultsI results = findAlignmentPositionsForStructurePositions(atoms);
+ for (Object li : listeners)
+ {
+ if (li instanceof SequenceListener)
+ {
+ ((SequenceListener) li).highlightSequence(results);
+ }
+ }
+ }
+
+ /**
+ * Constructs a SearchResults object holding regions (if any) in the Jalview
+ * alignment which have a mapping to the structure viewer positions in the
+ * supplied list
+ *
+ * @param atoms
+ * @return
+ */
+ public SearchResultsI findAlignmentPositionsForStructurePositions(
+ List<AtomSpec> atoms)
+ {
SearchResultsI results = new SearchResults();
for (AtomSpec atom : atoms)
{
}
}
}
- for (Object li : listeners)
- {
- if (li instanceof SequenceListener)
- {
- ((SequenceListener) li).highlightSequence(results);
- }
- }
+ return results;
}
/**
package jalview.structures.models;
import jalview.api.AlignmentViewPanel;
-import jalview.api.FeatureRenderer;
import jalview.api.SequenceRenderer;
import jalview.api.StructureSelectionManagerProvider;
import jalview.api.structures.JalviewStructureDisplayI;
import java.awt.Color;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.BitSet;
import java.util.List;
/**
* the sequence alignment which is the basis of structure
* superposition
* @param matched
- * an array of booleans, indexed by alignment column, where true
- * indicates that every structure has a mapped residue present in the
- * column (so the column can participate in structure alignment)
+ * a BitSet, where bit j is set to indicate that every structure has
+ * a mapped residue present in column j (so the column can
+ * participate in structure alignment)
* @param structures
* an array of data beans corresponding to pdb file index
* @return
*/
protected int findSuperposableResidues(AlignmentI alignment,
- boolean[] matched, SuperposeData[] structures)
+ BitSet matched, SuperposeData[] structures)
{
int refStructure = -1;
String[] files = getPdbFile();
{
refStructure = pdbfnum;
}
- for (int r = 0; r < matched.length; r++)
+ for (int r = 0; r < alignment.getWidth(); r++)
{
- if (!matched[r])
+ if (!matched.get(r))
{
continue;
}
int pos = getMappedPosition(theSequence, r, mapping);
if (pos < 1 || pos == lastPos)
{
- matched[r] = false;
+ matched.clear(r);
continue;
}
lastPos = pos;
public abstract void setJalviewColourScheme(ColourSchemeI cs);
- public abstract void superposeStructures(AlignmentI[] als, int[] alm,
- ColumnSelection[] alc);
-
- public abstract void setBackgroundColour(Color col);
-
- protected abstract StructureMappingcommandSet[] getColourBySequenceCommands(
- String[] files, SequenceRenderer sr, FeatureRenderer fr,
- AlignmentI alignment);
-
/**
- * returns the current featureRenderer that should be used to colour the
- * structures
- *
- * @param alignment
+ * Constructs and sends a command to align structures against a reference
+ * structure, based on one or more sequence alignments. May optionally return
+ * an error or warning message for the alignment command.
*
+ * @param alignments
+ * an array of alignments to process
+ * @param structureIndices
+ * an array of corresponding reference structures (index into pdb
+ * file array); if a negative value is passed, the first PDB file
+ * mapped to an alignment sequence is used as the reference for
+ * superposition
+ * @param hiddenCols
+ * an array of corresponding hidden columns for each alignment
* @return
*/
- public abstract FeatureRenderer getFeatureRenderer(AlignmentViewPanel alignment);
+ public abstract String superposeStructures(AlignmentI[] alignments, int[] structureIndices,
+ ColumnSelection[] hiddenCols);
+
+ public abstract void setBackgroundColour(Color col);
+
+ protected abstract StructureMappingcommandSet[] getColourBySequenceCommands(
+ String[] files, SequenceRenderer sr, AlignmentViewPanel avp);
/**
* returns the current sequenceRenderer that should be used to colour the
*/
public void colourBySequence(AlignmentViewPanel alignmentv)
{
- boolean showFeatures = alignmentv.getAlignViewport()
- .isShowSequenceFeatures();
if (!colourBySequence || !isLoadingFinished())
{
return;
SequenceRenderer sr = getSequenceRenderer(alignmentv);
- FeatureRenderer fr = null;
- if (showFeatures)
- {
- fr = getFeatureRenderer(alignmentv);
- }
- AlignmentI alignment = alignmentv.getAlignment();
-
StructureMappingcommandSet[] colourBySequenceCommands = getColourBySequenceCommands(
- files, sr, fr, alignment);
+ files, sr, alignmentv);
colourBySequence(colourBySequenceCommands);
}
{
return fileLoadingError != null && fileLoadingError.length() > 0;
}
+
+ public abstract jalview.api.FeatureRenderer getFeatureRenderer(
+ AlignmentViewPanel alignment);
}
--- /dev/null
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview 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.
+ *
+ * Jalview 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+
+package jalview.urls;
+
+import static jalview.util.UrlConstants.DB_ACCESSION;
+import static jalview.util.UrlConstants.DELIM;
+import static jalview.util.UrlConstants.SEP;
+import static jalview.util.UrlConstants.SEQUENCE_ID;
+
+import jalview.util.MessageManager;
+import jalview.util.UrlConstants;
+import jalview.util.UrlLink;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.StringTokenizer;
+
+/**
+ *
+ * Implements the UrlProviderI interface for a UrlProvider object which serves
+ * custom URLs defined by the user
+ *
+ * @author $author$
+ * @version $Revision$
+ */
+public class CustomUrlProvider extends UrlProviderImpl
+{
+ // Default sequence URL link label for SRS
+ private static final String SRS_LABEL = "SRS";
+
+ // map of string ids to urlLinks (selected)
+ private HashMap<String, UrlLink> selectedUrls;
+
+ // map of string ids to urlLinks (not selected)
+ private HashMap<String, UrlLink> nonselectedUrls;
+
+ /**
+ * Construct UrlProvider for custom (user-entered) URLs
+ *
+ * @param inMenuUrlList
+ * list of URLs set to be displayed in menu, in form stored in Cache.
+ * i.e. SEP delimited string
+ * @param storedUrlList
+ * list of custom URLs entered by user but not currently displayed in
+ * menu, in form stored in Cache
+ */
+ public CustomUrlProvider(String inMenuUrlList, String storedUrlList)
+ {
+ try
+ {
+ selectedUrls = parseUrlStrings(inMenuUrlList);
+ nonselectedUrls = parseUrlStrings(storedUrlList);
+ } catch (Exception ex)
+ {
+ System.out
+ .println(ex.getMessage() + "\nError parsing sequence links");
+ }
+ }
+
+ /**
+ * Construct UrlProvider for custom (user-entered) URLs
+ *
+ * @param urlList
+ * list of URLs to be displayed in menu, as (label,url) pairs
+ * @param storedUrlList
+ * list of custom URLs entered by user but not currently displayed in
+ * menu, as (label,url) pairs
+ */
+ public CustomUrlProvider(Map<String, String> inMenuUrlList,
+ Map<String, String> storedUrlList)
+ {
+ try
+ {
+ selectedUrls = parseUrlList(inMenuUrlList);
+ nonselectedUrls = parseUrlList(storedUrlList);
+ } catch (Exception ex)
+ {
+ System.out
+ .println(ex.getMessage() + "\nError parsing sequence links");
+ }
+ }
+
+ private HashMap<String, UrlLink> parseUrlStrings(String urlStrings)
+ {
+ // cachedUrlList is in form <label>|<url>|<label>|<url>...
+ // parse cachedUrlList into labels (used as id) and url links
+ HashMap<String, UrlLink> urls = new HashMap<String, UrlLink>();
+
+ StringTokenizer st = new StringTokenizer(urlStrings, SEP);
+ while (st.hasMoreElements())
+ {
+ String name = st.nextToken();
+
+ if (!isMiriamId(name))
+ {
+ // this one of our custom urls
+ String url = st.nextToken();
+ // check for '|' within a regex
+ int rxstart = url.indexOf(DELIM + DB_ACCESSION + DELIM);
+ if (rxstart == -1)
+ {
+ rxstart = url.indexOf(DELIM + SEQUENCE_ID + DELIM);
+ }
+ while (rxstart == -1 && url.indexOf("/=" + DELIM) == -1
+ && st.hasMoreTokens())
+ {
+ url = url + SEP + st.nextToken();
+ }
+ urls.put(name, new UrlLink(name, url, name));
+ }
+ }
+ upgradeOldLinks(urls);
+ return urls;
+ }
+
+ private HashMap<String, UrlLink> parseUrlList(Map<String, String> urlList)
+ {
+ HashMap<String, UrlLink> urls = new HashMap<String, UrlLink>();
+ if (urlList == null)
+ {
+ return urls;
+ }
+
+ Iterator<Map.Entry<String, String>> it = urlList.entrySet().iterator();
+ while (it.hasNext())
+ {
+ Map.Entry<String, String> pair = it.next();
+ urls.put(pair.getKey(),
+ new UrlLink(pair.getKey(), pair.getValue(),
+ pair.getKey()));
+ }
+ upgradeOldLinks(urls);
+ return urls;
+ }
+
+ /*
+ * Upgrade any legacy links which may have been left lying around
+ */
+ private void upgradeOldLinks(HashMap<String, UrlLink> urls)
+ {
+ // upgrade old SRS link
+ if (urls.containsKey(SRS_LABEL))
+ {
+ urls.remove(SRS_LABEL);
+ UrlLink link = new UrlLink(UrlConstants.DEFAULT_STRING);
+ link.setLabel(UrlConstants.DEFAULT_LABEL);
+ urls.put(UrlConstants.DEFAULT_LABEL, link);
+ }
+ }
+
+ @Override
+ public List<String> getLinksForMenu()
+ {
+ List<String> links = new ArrayList<String>();
+ Iterator<Map.Entry<String, UrlLink>> it = selectedUrls.entrySet()
+ .iterator();
+ while (it.hasNext())
+ {
+ Map.Entry<String, UrlLink> pair = it.next();
+ links.add(pair.getValue().toString());
+ }
+ return links;
+ }
+
+ @Override
+ public List<UrlLinkDisplay> getLinksForTable()
+ {
+ ArrayList<UrlLinkDisplay> displayLinks = new ArrayList<UrlLinkDisplay>();
+ displayLinks = getLinksForTable(selectedUrls, true);
+ displayLinks.addAll(getLinksForTable(nonselectedUrls, false));
+ return displayLinks;
+ }
+
+ private ArrayList<UrlLinkDisplay> getLinksForTable(
+ HashMap<String, UrlLink> urlList, boolean selected)
+ {
+ return super.getLinksForTable(urlList, null, selected);
+ }
+
+ @Override
+ public boolean setPrimaryUrl(String id)
+ {
+ if (selectedUrls.containsKey(id))
+ {
+ primaryUrl = id;
+ }
+ else if (nonselectedUrls.containsKey(id))
+ {
+ primaryUrl = id;
+ }
+ else
+ {
+ primaryUrl = null;
+ }
+
+ return (primaryUrl != null);
+ }
+
+ @Override
+ public String writeUrlsAsString(boolean selected)
+ {
+ StringBuffer links = new StringBuffer();
+ HashMap<String, UrlLink> urls;
+ if (selected)
+ {
+ urls = selectedUrls;
+ }
+ else
+ {
+ urls = nonselectedUrls;
+ }
+ if (urls.size() > 0)
+ {
+ for (Entry<String, UrlLink> entry : urls.entrySet())
+ {
+ links.append(entry.getValue().toString());
+ links.append(SEP);
+ }
+
+ // remove last SEP
+ links.setLength(links.length() - 1);
+ }
+ else
+ {
+ urls.clear();
+ }
+ return links.toString();
+ }
+
+ @Override
+ public String getPrimaryUrl(String seqid)
+ {
+ String result = super.getPrimaryUrl(seqid, selectedUrls);
+ if (result == null)
+ {
+ result = super.getPrimaryUrl(seqid, nonselectedUrls);
+ }
+ return result;
+ }
+
+ @Override
+ public String getPrimaryUrlId()
+ {
+ return primaryUrl;
+ }
+
+ @Override
+ public String getPrimaryTarget(String seqid)
+ {
+ return selectedUrls.get(primaryUrl).getTarget();
+ }
+
+ @Override
+ public void setUrlData(List<UrlLinkDisplay> links)
+ {
+ HashMap<String, UrlLink> unselurls = new HashMap<String, UrlLink>();
+ HashMap<String, UrlLink> selurls = new HashMap<String, UrlLink>();
+
+ Iterator<UrlLinkDisplay> it = links.iterator();
+ while (it.hasNext())
+ {
+ UrlLinkDisplay link = it.next();
+
+ // MIRIAM ids will be handled by a different UrlProvider class
+ if (!isMiriamId(link.getId()))
+ {
+ // don't allow duplicate key names as entries will be overwritten
+ if (unselurls.containsKey(link.getId())
+ || selurls.containsKey(link.getId()))
+ {
+ throw new IllegalArgumentException(MessageManager.formatMessage(
+ "exception.url_cannot_have_duplicate_id", link.getId()));
+ }
+ if (link.getIsSelected())
+ {
+ selurls.put(link.getId(),
+ new UrlLink(link.getDescription(), link.getUrl(), link.getDescription()));
+ }
+ else
+ {
+ unselurls
+ .put(link.getId(),
+ new UrlLink(link.getDescription(), link.getUrl(), link
+ .getDescription()));
+ }
+ // sort out primary and selected ids
+ if (link.getIsPrimary())
+ {
+ setPrimaryUrl(link.getId());
+ }
+ }
+
+ }
+ nonselectedUrls = unselurls;
+ selectedUrls = selurls;
+ }
+
+ @Override
+ public String choosePrimaryUrl()
+ {
+ // unilaterally set the primary id to the EMBL_EBI link
+ if ((!nonselectedUrls.containsKey(UrlConstants.DEFAULT_LABEL))
+ && (!selectedUrls.containsKey(UrlConstants.DEFAULT_LABEL)))
+ {
+ UrlLink link = new UrlLink(UrlConstants.DEFAULT_STRING);
+ link.setLabel(UrlConstants.DEFAULT_LABEL);
+ selectedUrls.put(UrlConstants.DEFAULT_LABEL, link);
+ }
+ primaryUrl = UrlConstants.DEFAULT_LABEL;
+ return UrlConstants.DEFAULT_LABEL;
+ }
+
+ @Override
+ public boolean contains(String id)
+ {
+ return (selectedUrls.containsKey(id) || nonselectedUrls.containsKey(id));
+ }
+
+}
--- /dev/null
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview 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.
+ *
+ * Jalview 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+
+package jalview.urls;
+
+/**
+ * Holds settings for identifiers.org e.g. url, download location
+ *
+ * @author $author$
+ * @version $Revision$
+ */
+public class IdOrgSettings
+{
+ private static String url;
+
+ private static String location;
+
+ public static void setUrl(String seturl)
+ {
+ url = seturl;
+ }
+
+ public static void setDownloadLocation(String setloc)
+ {
+ location = setloc;
+ }
+
+ public static String getUrl()
+ {
+ return url;
+ }
+
+ public static String getDownloadLocation()
+ {
+ return location;
+ }
+}
--- /dev/null
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview 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.
+ *
+ * Jalview 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+
+package jalview.urls;
+
+import static jalview.util.UrlConstants.DB_ACCESSION;
+import static jalview.util.UrlConstants.DELIM;
+import static jalview.util.UrlConstants.SEP;
+
+import jalview.util.UrlLink;
+
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.StringTokenizer;
+
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+import org.json.simple.parser.JSONParser;
+import org.json.simple.parser.ParseException;
+
+/**
+ *
+ * Implements the UrlProviderI interface for a UrlProvider object which serves
+ * URLs from identifiers.org
+ *
+ * @author $author$
+ * @version $Revision$
+ */
+public class IdentifiersUrlProvider extends UrlProviderImpl
+{
+
+ private static final String LOCAL_KEY = "Local";
+
+ private static final String ID_ORG_KEY = "identifiers.org";
+
+ // map of string ids to urls
+ private HashMap<String, UrlLink> urls;
+
+ // list of selected urls
+ private ArrayList<String> selectedUrls;
+
+ public IdentifiersUrlProvider(String cachedUrlList)
+ {
+ urls = readIdentifiers(IdOrgSettings.getDownloadLocation());
+ selectedUrls = new ArrayList<String>();
+ checkSelectionMatchesUrls(cachedUrlList);
+ }
+
+ /**
+ * Read data from an identifiers.org download file
+ *
+ * @param idFileName
+ * name of identifiers.org download file
+ * @return hashmap of identifiers.org data, keyed by MIRIAM id
+ */
+ private HashMap<String, UrlLink> readIdentifiers(
+ String idFileName)
+ {
+ JSONParser parser = new JSONParser();
+
+ // identifiers.org data
+ HashMap<String, UrlLink> idData = new HashMap<String, UrlLink>();
+
+ try
+ {
+ FileReader reader = new FileReader(idFileName);
+ String key = "";
+ JSONObject obj = (JSONObject) parser.parse(reader);
+ if (obj.containsKey(ID_ORG_KEY))
+ {
+ key = ID_ORG_KEY;
+ }
+ else if (obj.containsKey(LOCAL_KEY))
+ {
+ key = LOCAL_KEY;
+ }
+ else
+ {
+ System.out
+ .println("Unexpected key returned from identifiers jalview service");
+ return idData;
+ }
+
+ JSONArray jsonarray = (JSONArray) obj.get(key);
+
+ // loop over each entry in JSON array and build HashMap entry
+ for (int i = 0; i < jsonarray.size(); i++)
+ {
+ JSONObject item = (JSONObject) jsonarray.get(i);
+
+ String url = (String) item.get("url") + "/" + DELIM + DB_ACCESSION
+ + DELIM;
+ UrlLink link = new UrlLink((String) item.get("name"), url,
+ (String) item.get("prefix"));
+ idData.put((String) item.get("id"), link);
+ }
+ } catch (FileNotFoundException e)
+ {
+ e.printStackTrace();
+ idData.clear();
+ } catch (IOException e)
+ {
+ e.printStackTrace();
+ idData.clear();
+ } catch (ParseException e)
+ {
+ e.printStackTrace();
+ idData.clear();
+ }
+ return idData;
+ }
+
+ private void checkSelectionMatchesUrls(String cachedUrlList)
+ {
+ StringTokenizer st = new StringTokenizer(cachedUrlList, SEP);
+ while (st.hasMoreElements())
+ {
+ String id = st.nextToken();
+
+ if (isMiriamId(id))
+ {
+ // this is an identifiers.org MIRIAM id
+ if (urls.containsKey(id))
+ {
+ selectedUrls.add(id);
+ }
+ }
+ }
+
+ // reset defaultUrl in case it is no longer selected
+ setPrimaryUrl(primaryUrl);
+ }
+
+ @Override
+ public boolean setPrimaryUrl(String id)
+ {
+ if (urls.containsKey(id))
+ {
+ primaryUrl = id;
+ }
+ else
+ {
+ primaryUrl = null;
+ }
+
+ return urls.containsKey(id);
+ }
+
+ @Override
+ public String writeUrlsAsString(boolean selected)
+ {
+ if (!selected)
+ {
+ return ""; // we don't cache unselected identifiers.org urls
+ }
+
+ StringBuffer links = new StringBuffer();
+ if (!selectedUrls.isEmpty())
+ {
+ for (String k : selectedUrls)
+ {
+ links.append(k);
+ links.append(SEP);
+ }
+ // remove last SEP
+ links.setLength(links.length() - 1);
+ }
+ return links.toString();
+ }
+
+ @Override
+ public List<String> getLinksForMenu()
+ {
+ List<String> links = new ArrayList<String>();
+ for (String key : selectedUrls)
+ {
+ links.add(urls.get(key).toStringWithTarget());
+ }
+ return links;
+ }
+
+ @Override
+ public List<UrlLinkDisplay> getLinksForTable()
+ {
+ return super.getLinksForTable(urls, selectedUrls, false);
+ }
+
+ @Override
+ public void setUrlData(List<UrlLinkDisplay> links)
+ {
+ selectedUrls = new ArrayList<String>();
+
+ Iterator<UrlLinkDisplay> it = links.iterator();
+ while (it.hasNext())
+ {
+ UrlLinkDisplay link = it.next();
+
+ // Handle links with MIRIAM ids only
+ if (isMiriamId(link.getId()))
+ {
+ // select/deselect links accordingly and set default url
+ if (urls.containsKey(link.getId()))
+ {
+ if (link.getIsSelected())
+ {
+ selectedUrls.add(link.getId());
+ }
+ if (link.getIsPrimary())
+ {
+ setPrimaryUrl(link.getId());
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ public String getPrimaryUrl(String seqid)
+ {
+ return super.getPrimaryUrl(seqid, urls);
+ }
+
+ @Override
+ public String getPrimaryUrlId()
+ {
+ return primaryUrl;
+ }
+
+ @Override
+ public String getPrimaryTarget(String seqid)
+ {
+ return null;
+ }
+
+ @Override
+ public String choosePrimaryUrl()
+ {
+ return null;
+ }
+
+ @Override
+ public boolean contains(String id)
+ {
+ return (urls.containsKey(id));
+ }
+}
--- /dev/null
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview 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.
+ *
+ * Jalview 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+
+package jalview.urls;
+
+import jalview.util.MessageManager;
+import jalview.util.UrlLink;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * UrlLink table row definition
+ *
+ * @author $author$
+ * @version $Revision$
+ */
+
+public class UrlLinkDisplay
+{
+ private String id; // id is not supplied to display, but used to identify
+ // entries when saved
+
+ private boolean isPrimary;
+
+ private boolean isSelected;
+
+ private UrlLink link;
+
+ // Headers for columns in table
+ private final static List<String> colNames = new ArrayList<String>()
+ {
+ {
+ add(MessageManager.formatMessage("label.database"));
+ add(MessageManager.formatMessage("label.name"));
+ add(MessageManager.formatMessage("label.url"));
+ add(MessageManager.formatMessage("label.inmenu"));
+ add(MessageManager.formatMessage("label.primary"));
+ add(MessageManager.formatMessage("label.id"));
+ }
+ };
+
+ // column positions
+ public final static int DATABASE = 0;
+
+ public final static int NAME = 1;
+
+ public final static int URL = 2;
+
+ public final static int SELECTED = 3;
+
+ public final static int PRIMARY = 4;
+
+ public final static int ID = 5;
+
+ public UrlLinkDisplay(String rowId, UrlLink rowLink,
+ boolean rowSelected, boolean rowDefault)
+ {
+ id = rowId;
+ isPrimary = rowDefault;
+ isSelected = rowSelected;
+
+ link = rowLink;
+ }
+
+ // getters/setters
+ public String getId()
+ {
+ return id;
+ }
+
+ public String getDescription()
+ {
+ return link.getLabel();
+ }
+
+ public String getDBName()
+ {
+ return link.getTarget();
+ }
+
+ public String getUrl()
+ {
+ return link.getUrlWithToken();
+ }
+
+ public boolean getIsPrimary()
+ {
+ return isPrimary;
+ }
+
+ public boolean getIsSelected()
+ {
+ return isSelected;
+ }
+
+ public void setDBName(String name)
+ {
+ link.setTarget(name);
+ }
+
+ public void setUrl(String rowUrl)
+ {
+ link = new UrlLink(getDescription(), rowUrl, getDBName());
+ }
+
+ public void setDescription(String desc)
+ {
+ link.setLabel(desc);
+ }
+
+ public void setIsDefault(boolean rowDefault)
+ {
+ isPrimary = rowDefault;
+ }
+
+ public void setIsSelected(boolean rowSelected)
+ {
+ isSelected = rowSelected;
+ }
+
+ public Object getValue(int index)
+ {
+ switch (index)
+ {
+ case ID:
+ return id;
+ case URL:
+ return getUrl();
+ case PRIMARY:
+ return isPrimary;
+ case SELECTED:
+ return isSelected;
+ case NAME:
+ return getDescription();
+ case DATABASE:
+ return getDBName();
+ default:
+ return null;
+ }
+ }
+
+ public void setValue(int index, Object value)
+ {
+ switch (index)
+ {
+ case ID:
+ id = (String) value;
+ break;
+ case URL:
+ setUrl((String) value);
+ break;
+ case PRIMARY:
+ isPrimary = (boolean) value;
+ break;
+ case SELECTED:
+ isSelected = (boolean) value;
+ break;
+ case NAME:
+ setDescription((String) value);
+ case DATABASE:
+ setDBName((String) value);
+ break;
+ default:
+ // do nothing
+ }
+ }
+
+ /**
+ * Identify editable columns
+ *
+ * @param index
+ * index of column
+ * @return whether column can be edited in table
+ */
+ public boolean isEditable(int index)
+ {
+ if (index == PRIMARY)
+ {
+ // primary link must not be a $DB_ACCESSION$ link
+ // so only allow editing if it is not
+ return (!link.usesDBAccession());
+ }
+ else if (index == SELECTED)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Get list of column names to display in UI
+ *
+ * @return column names
+ */
+ public static List<String> getDisplayColumnNames()
+ {
+ // Display names between DESCRIPTION and ID (excludes ID)
+ return colNames.subList(DATABASE, ID);
+ }
+}
--- /dev/null
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview 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.
+ *
+ * Jalview 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+
+package jalview.urls;
+
+import jalview.bin.Cache;
+import jalview.urls.api.UrlProviderI;
+import jalview.util.UrlLink;
+
+import java.util.Iterator;
+import java.util.List;
+
+import javax.swing.RowFilter.Entry;
+import javax.swing.event.TableModelEvent;
+import javax.swing.event.TableModelListener;
+import javax.swing.table.AbstractTableModel;
+import javax.swing.table.TableModel;
+
+/**
+ * TableModel for UrlLinks table
+ *
+ * @author $author$
+ * @version $Revision$
+ */
+
+public class UrlLinkTableModel extends AbstractTableModel
+{
+ // local storage of data
+ private List<UrlLinkDisplay> data;
+
+ // supplier of url data
+ private UrlProviderI dataProvider;
+
+ // list of columns to display in table in correct order
+ private List<String> displayColumns;
+
+ // row in table which is currently the primary
+ private int primaryRow;
+
+ /**
+ * UrlLinkTableModel constructor
+ *
+ * @param baseData
+ * base data set to be presented in table
+ * @param entryNames
+ * keys of entries in baseData's nested hashmap. Should match order
+ * in displayColNames
+ * @param displayColNames
+ * names of columns to display in order.
+ * @param keyColName
+ * name of column corresponding to keys in baseData
+ */
+ public UrlLinkTableModel(UrlProviderI baseData)
+ {
+ dataProvider = baseData;
+ data = baseData.getLinksForTable();
+ displayColumns = UrlLinkDisplay.getDisplayColumnNames();
+
+ // find the primary row
+ primaryRow = 0;
+ Iterator<UrlLinkDisplay> it = data.iterator();
+ while (it.hasNext())
+ {
+ if (it.next().getIsPrimary())
+ {
+ break;
+ }
+ else
+ {
+ primaryRow++;
+ }
+ }
+
+ // set up listener which updates data source when table changes
+ this.addTableModelListener(new TableModelListener()
+ {
+ @Override
+ public void tableChanged(TableModelEvent e)
+ {
+ try
+ {
+ // update the UrlProvider from data list
+ dataProvider.setUrlData(data);
+ } catch (IllegalArgumentException ex)
+ {
+ Cache.log.error(ex.getMessage());
+ }
+ }
+ });
+
+ }
+
+ @Override
+ public int getRowCount()
+ {
+ if (data == null)
+ {
+ return 0;
+ }
+ else
+ {
+ return data.size();
+ }
+ }
+
+ @Override
+ public int getColumnCount()
+ {
+ return displayColumns.size();
+ }
+
+ @Override
+ public Object getValueAt(int rowIndex, int columnIndex)
+ {
+ return data.get(rowIndex).getValue(columnIndex);
+ }
+
+ @Override
+ public boolean isCellEditable(int rowIndex, int columnIndex)
+ {
+ return data.get(rowIndex).isEditable(columnIndex);
+ }
+
+ /**
+ * Determine if a row is editable indirectly (rather than directly in table as
+ * in isCellEditable)
+ *
+ * @param rowIndex
+ * @return true if row can be edited indirectly
+ */
+ public boolean isRowEditable(int rowIndex)
+ {
+ // to edit, row must be a user entered row
+ return (dataProvider.isUserEntry(data.get(rowIndex).getId()));
+ }
+
+ /**
+ * Determine if a row is deletable
+ *
+ * @param rowIndex
+ * the row to be tested
+ * @return true if row can be deleted
+ */
+ public boolean isRowDeletable(int rowIndex)
+ {
+ // to delete, row must be a user entered row, and not the default row
+ return (dataProvider.isUserEntry(data.get(rowIndex).getId()) && !data
+ .get(rowIndex).getIsPrimary());
+ }
+
+ @Override
+ public void setValueAt(Object aValue, int rowIndex, int columnIndex)
+ {
+ if (columnIndex == UrlLinkDisplay.PRIMARY)
+ {
+ // Default url column: exactly one row must always be true
+ if (rowIndex != primaryRow)
+ {
+ // selected row is not currently the default
+ // set the current default to false
+ data.get(primaryRow).setValue(columnIndex, false);
+ fireTableRowsUpdated(primaryRow, primaryRow);
+
+ // set the default to be the selected row
+ primaryRow = rowIndex;
+ data.get(rowIndex).setValue(columnIndex, aValue);
+
+ fireTableRowsUpdated(rowIndex, rowIndex);
+ }
+ }
+ else
+ {
+ data.get(rowIndex).setValue(columnIndex, aValue);
+ fireTableRowsUpdated(rowIndex, rowIndex);
+ }
+ }
+
+ @Override
+ public Class<?> getColumnClass(int columnIndex)
+ {
+ return getValueAt(0, columnIndex).getClass();
+ }
+
+ @Override
+ public String getColumnName(int columnIndex)
+ {
+ return displayColumns.get(columnIndex);
+ }
+
+ public void removeRow(int rowIndex)
+ {
+ // remove the row from data
+ data.remove(rowIndex);
+
+ // update default row
+ if (primaryRow > rowIndex)
+ {
+ primaryRow--;
+ }
+
+ // fire update which will update data source
+ fireTableRowsDeleted(rowIndex, rowIndex);
+ }
+
+ public int insertRow(String name, String url)
+ {
+ // add a row to the data
+ UrlLink link = new UrlLink(name, url, name);
+ UrlLinkDisplay u = new UrlLinkDisplay(name, link, true, false);
+ int index = data.size();
+ data.add(u);
+
+ // fire update which will update data source
+ fireTableRowsInserted(index, index);
+ return index;
+ }
+
+ public int getPrimaryColumn()
+ {
+ return UrlLinkDisplay.PRIMARY;
+ }
+
+ public int getNameColumn()
+ {
+ return UrlLinkDisplay.NAME;
+ }
+
+ public int getDatabaseColumn()
+ {
+ return UrlLinkDisplay.DATABASE;
+ }
+
+ public int getIdColumn()
+ {
+ return UrlLinkDisplay.ID;
+ }
+
+ public int getUrlColumn()
+ {
+ return UrlLinkDisplay.URL;
+ }
+
+ public int getSelectedColumn()
+ {
+ return UrlLinkDisplay.SELECTED;
+ }
+
+ public boolean isUserEntry(
+ Entry<? extends TableModel, ? extends Object> entry)
+ {
+ return dataProvider
+ .isUserEntry(entry.getStringValue(UrlLinkDisplay.ID));
+ }
+
+ public boolean isUniqueName(String name)
+ {
+ return !dataProvider.contains(name);
+ }
+}
--- /dev/null
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview 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.
+ *
+ * Jalview 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.urls;
+
+import static jalview.util.UrlConstants.SEP;
+
+import jalview.urls.api.UrlProviderI;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Vector;
+
+/**
+ *
+ * Implements the UrlProviderI interface for a composite UrlProvider object
+ *
+ * @author $author$
+ * @version $Revision$
+ */
+public class UrlProvider implements UrlProviderI
+{
+ // List of actual URL link providers
+ private List<UrlProviderI> providers;
+
+ // Specific reference to custom URL link provider
+ private UrlProviderI customProvider;
+
+ /**
+ * Constructor for UrlProvider composite
+ *
+ * @param defaultUrlString
+ * id of default url
+ * @param allProviders
+ * list of UrlProviders this provider gives access to
+ */
+ public UrlProvider(String defaultUrlString,
+ List<UrlProviderI> allProviders)
+ {
+ providers = allProviders;
+
+ customProvider = findCustomProvider();
+
+ // check that the defaultUrl still exists
+ if (!contains(defaultUrlString))
+ {
+ // if the defaultUrl can't be found in any of the providers
+ // set up a custom default url
+ choosePrimaryUrl();
+ }
+ else
+ {
+ setPrimaryUrl(defaultUrlString);
+ }
+ }
+
+ /*
+ * Store ref to custom url provider
+ */
+ private UrlProviderI findCustomProvider()
+ {
+ for (UrlProviderI p : providers)
+ {
+ if (p instanceof CustomUrlProvider)
+ {
+ return p;
+ }
+ }
+
+ System.out
+ .println("Error initialising UrlProvider - no custom url provider");
+ return null;
+ }
+
+ @Override
+ public boolean setPrimaryUrl(String id)
+ {
+ boolean outcome = false;
+ for (UrlProviderI p : providers)
+ {
+ if (p.setPrimaryUrl(id))
+ {
+ outcome = true;
+ }
+ }
+ if (!outcome)
+ {
+ throw new IllegalArgumentException();
+ }
+ return outcome;
+ }
+
+ @Override
+ public boolean contains(String id)
+ {
+ boolean outcome = false;
+ for (UrlProviderI p : providers)
+ {
+ if (p.contains(id))
+ {
+ outcome = true;
+ }
+ }
+ return outcome;
+ }
+
+ @Override
+ public String writeUrlsAsString(boolean selected)
+ {
+ String result = "";
+ for (UrlProviderI p : providers)
+ {
+ String next = p.writeUrlsAsString(selected);
+ if (!next.isEmpty())
+ {
+ result += next;
+ result += SEP;
+ }
+ }
+ // remove last sep
+ if (!result.isEmpty())
+ {
+ result = result.substring(0, result.length() - 1);
+ }
+ return result;
+ }
+
+ @Override
+ public Vector<String> getLinksForMenu()
+ {
+ Vector<String> fullLinks = new Vector<String>();
+ for (UrlProviderI p : providers)
+ {
+ List<String> links = p.getLinksForMenu();
+ if (links != null)
+ {
+ // will obliterate links with same keys from different providers
+ // must have checks in place to prevent user from duplicating ids
+ fullLinks.addAll(links);
+ }
+ }
+ return fullLinks;
+ }
+
+ @Override
+ public List<UrlLinkDisplay> getLinksForTable()
+ {
+ ArrayList<UrlLinkDisplay> displayLinks = new ArrayList<UrlLinkDisplay>();
+ for (UrlProviderI p : providers)
+ {
+ displayLinks.addAll(p.getLinksForTable());
+ }
+ return displayLinks;
+ }
+
+ @Override
+ public void setUrlData(List<UrlLinkDisplay> links)
+ {
+ for (UrlProviderI p : providers)
+ {
+ p.setUrlData(links);
+ }
+ }
+
+ @Override
+ public String getPrimaryUrl(String seqid)
+ {
+ String link = null;
+ for (UrlProviderI p : providers)
+ {
+ if (p.getPrimaryUrl(seqid) == null)
+ {
+ continue;
+ }
+ else
+ {
+ link = p.getPrimaryUrl(seqid);
+ break;
+ }
+ }
+ return link;
+ }
+
+ @Override
+ public String getPrimaryUrlId()
+ {
+ String id = null;
+ for (UrlProviderI p : providers)
+ {
+ if (p.getPrimaryUrlId() == null)
+ {
+ continue;
+ }
+ else
+ {
+ id = p.getPrimaryUrlId();
+ break;
+ }
+ }
+ return id;
+ }
+
+ @Override
+ public String getPrimaryTarget(String seqid)
+ {
+ String target = null;
+ for (UrlProviderI p : providers)
+ {
+ if (p.getPrimaryTarget(seqid) == null)
+ {
+ continue;
+ }
+ else
+ {
+ target = p.getPrimaryTarget(seqid);
+ break;
+ }
+ }
+ return target;
+ }
+
+ @Override
+ public String choosePrimaryUrl()
+ {
+ // choose a custom url default
+ return customProvider.choosePrimaryUrl();
+ }
+
+ @Override
+ public boolean isUserEntry(String id)
+ {
+ return customProvider.isUserEntry(id);
+ }
+}
--- /dev/null
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview 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.
+ *
+ * Jalview 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.urls;
+
+import jalview.urls.api.UrlProviderI;
+import jalview.util.UrlLink;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.regex.Pattern;
+
+/**
+ * Leaf node of UrlProvider composite
+ *
+ * @author $author$
+ * @version $Revision$
+ */
+
+public abstract class UrlProviderImpl implements UrlProviderI
+{
+ // minimum length of substitution in url link string
+ protected static final int MIN_SUBST_LENGTH = 4;
+
+ private static final Pattern MIRIAM_PATTERN = Pattern
+ .compile("^MIR:\\d{8}$");
+
+ protected String primaryUrl;
+
+ protected String getPrimaryUrl(String seqid, HashMap<String, UrlLink> urls)
+ {
+ if (seqid.length() < MIN_SUBST_LENGTH)
+ {
+ return null;
+ }
+ else if (primaryUrl == null)
+ {
+ return null;
+ }
+ else if (!urls.containsKey(primaryUrl))
+ {
+ return null;
+ }
+ else
+ {
+ String url = null;
+ UrlLink urlLink = urls.get(primaryUrl);
+ String[] primaryUrls = urlLink.makeUrls(seqid, true);
+ if (primaryUrls == null || primaryUrls[0] == null
+ || primaryUrls[0].length() < MIN_SUBST_LENGTH)
+ {
+ url = null;
+ }
+ else
+ {
+ // just take first URL made from regex
+ url = primaryUrls[1];
+ }
+ return url;
+ }
+ }
+
+ @Override
+ public List<UrlLinkDisplay> getLinksForTable()
+ {
+ return null;
+ }
+
+ protected ArrayList<UrlLinkDisplay> getLinksForTable(
+ HashMap<String, UrlLink> urls, ArrayList<String> selectedUrls,
+ boolean selected)
+ {
+ ArrayList<UrlLinkDisplay> displayLinks = new ArrayList<UrlLinkDisplay>();
+ for (Entry<String, UrlLink> entry : urls.entrySet())
+ {
+ String key = entry.getKey();
+ boolean isPrimary = (key.equals(primaryUrl));
+ boolean isSelected;
+ if (selectedUrls != null)
+ {
+ isSelected = selectedUrls.contains(key);
+ }
+ else
+ {
+ isSelected = selected;
+ }
+ displayLinks.add(new UrlLinkDisplay(key, entry.getValue(),
+ isSelected, isPrimary));
+ }
+ return displayLinks;
+ }
+
+ protected boolean isMiriamId(String id)
+ {
+ return MIRIAM_PATTERN.matcher(id).matches();
+ }
+
+ @Override
+ public boolean isUserEntry(String id)
+ {
+ return !isMiriamId(id);
+ }
+}
+
--- /dev/null
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview 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.
+ *
+ * Jalview 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.urls.api;
+
+
+/**
+ * Interface to UrlProvider factories
+ *
+ * @author $author$
+ * @version $Revision$
+ */
+public interface UrlProviderFactoryI
+{
+ public UrlProviderI createUrlProvider();
+
+}
--- /dev/null
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview 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.
+ *
+ * Jalview 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.urls.api;
+
+import jalview.urls.UrlLinkDisplay;
+
+import java.util.List;
+
+/**
+ * Methods for providing consistent access to up-to-date URLs
+ *
+ * @author $author$
+ * @version $Revision$
+ */
+public interface UrlProviderI
+{
+
+ /**
+ * Get names and urls in the UrlProvider as strings for display
+ *
+ */
+ List<String> getLinksForMenu();
+
+ /**
+ * Get names and urls as strings for display
+ *
+ */
+ List<UrlLinkDisplay> getLinksForTable();
+
+ /**
+ * Set names and urls from display settings
+ */
+ void setUrlData(List<UrlLinkDisplay> links);
+
+ /**
+ * Get the link for the primary URL
+ *
+ * @seqid sequence id for which to build link
+ * @return link for the primary URL
+ */
+ String getPrimaryUrl(String seqid);
+
+ /**
+ * Get the primary URL id
+ *
+ * @return id for primary URL
+ */
+ String getPrimaryUrlId();
+
+ /**
+ * Get the target of the link for the primary URL
+ *
+ * @seqid sequence id for which to build link
+ * @return target of link for the primary URL
+ */
+ String getPrimaryTarget(String seqid);
+
+ /**
+ * Set the primary URL: if only one URL can be used, this URL is the one which
+ * should be chosen, e.g. provides the URL to be used on double-click of a
+ * sequence id
+ *
+ * @param id
+ * the id of the URL to set as primary
+ * @return true if setting is successful
+ * @throws IllegalArgumentException
+ * if id does not exist as a url in the UrlProvider
+ */
+ boolean setPrimaryUrl(String id) throws IllegalArgumentException;
+
+ /**
+ * Test if UrlProvider contains a url
+ *
+ * @param id
+ * to test for
+ * @return true of UrlProvider contains this id, false otherwise
+ */
+ boolean contains(String id);
+
+ /**
+ * Write out all URLs as a string suitable for serialising
+ *
+ * @return string representation of available URLs
+ */
+ String writeUrlsAsString(boolean selected);
+
+ /**
+ * Choose the primary URL in the event of the selected primary being
+ * unavailable
+ *
+ * @return id of chosen primary url
+ */
+ String choosePrimaryUrl();
+
+ /**
+ * Determine if id is for a user-defined URL
+ */
+ boolean isUserEntry(String id);
+}
--- /dev/null
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview 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.
+ *
+ * Jalview 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.urls.applet;
+
+import jalview.urls.CustomUrlProvider;
+import jalview.urls.UrlProvider;
+import jalview.urls.api.UrlProviderFactoryI;
+import jalview.urls.api.UrlProviderI;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * UrlProvider factory for applet code
+ *
+ * @author $author$
+ * @version $Revision$
+ */
+
+public class AppletUrlProviderFactory implements UrlProviderFactoryI
+{
+ private String provDefaultUrl;
+
+ private Map<String, String> provUrlList;
+
+ public AppletUrlProviderFactory(String defaultUrlString,
+ Map<String, String> urlList)
+ {
+ provDefaultUrl = defaultUrlString;
+ provUrlList = urlList;
+ }
+
+ @Override
+ public UrlProviderI createUrlProvider()
+ {
+ // create all the UrlProviders we need
+ List<UrlProviderI> providers = new ArrayList<UrlProviderI>();
+ UrlProviderI customProvider = new CustomUrlProvider(provUrlList, null);
+ providers.add(customProvider);
+
+ UrlProviderI prov = new UrlProvider(provDefaultUrl, providers);
+ return prov;
+ }
+
+}
--- /dev/null
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview 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.
+ *
+ * Jalview 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.urls.desktop;
+
+import jalview.urls.CustomUrlProvider;
+import jalview.urls.IdentifiersUrlProvider;
+import jalview.urls.UrlProvider;
+import jalview.urls.api.UrlProviderFactoryI;
+import jalview.urls.api.UrlProviderI;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * UrlProvider factory for desktop code
+ *
+ * @author $author$
+ * @version $Revision$
+ */
+
+public class DesktopUrlProviderFactory implements UrlProviderFactoryI
+{
+
+ private String provDefaultUrl;
+
+ private String menuUrlList;
+
+ private String nonMenuUrlList;
+
+ public DesktopUrlProviderFactory(String defaultUrlString,
+ String cachedUrlList, String userUrlList)
+ {
+ provDefaultUrl = defaultUrlString;
+ menuUrlList = cachedUrlList;
+ nonMenuUrlList = userUrlList;
+ }
+
+ @Override
+ public UrlProviderI createUrlProvider()
+ {
+ // create all the UrlProviders we need
+ List<UrlProviderI> providers = new ArrayList<UrlProviderI>();
+
+ UrlProviderI idProvider = new IdentifiersUrlProvider(menuUrlList);
+ UrlProviderI customProvider = new CustomUrlProvider(menuUrlList,
+ nonMenuUrlList);
+ providers.add(idProvider);
+ providers.add(customProvider);
+
+ return new UrlProvider(provDefaultUrl, providers);
+ }
+
+}
--- /dev/null
+package jalview.util;
+
+import java.util.Comparator;
+
+/**
+ * A comparator to order [from, to] ranges into ascending or descending order of
+ * their start position
+ */
+public class RangeComparator implements Comparator<int[]>
+{
+ boolean forwards;
+
+ public RangeComparator(boolean forward)
+ {
+ forwards = forward;
+ }
+
+ @Override
+ public int compare(int[] o1, int[] o2)
+ {
+ int compared = Integer.compare(o1[0], o2[0]);
+ return forwards ? compared : -compared;
+ }
+
+}
\ No newline at end of file
public static final String SEQUENCE_ID = "SEQUENCE_ID";
/*
- * Default sequence URL link string for EMBL-EBI search
+ * Separator character used in Url links
+ */
+ public static final String SEP = "|";
+
+ /*
+ * Delimiter character used in Url links
*/
- public static final String EMBLEBI_STRING = "EMBL-EBI Search|http://www.ebi.ac.uk/ebisearch/search.ebi?db=allebi&query=$SEQUENCE_ID$";
+ public static final String DELIM = "$";
/*
- * Default sequence URL link string for SRS
+ * Default sequence URL link label for EMBL-EBI search
+ */
+ public static final String DEFAULT_LABEL = "EMBL-EBI Search";
+
+ /*
+ * Default sequence URL link string for EMBL-EBI search
*/
- public static final String SRS_STRING = "SRS|http://srs.ebi.ac.uk/srsbin/cgi-bin/wgetz?-newId+(([uniprot-all:$SEQUENCE_ID$]))+-view+SwissEntry";
+ public static final String DEFAULT_STRING = DEFAULT_LABEL
+ + "|http://www.ebi.ac.uk/ebisearch/search.ebi?db=allebi&query=$SEQUENCE_ID$";
/*
* not instantiable
package jalview.util;
import static jalview.util.UrlConstants.DB_ACCESSION;
+import static jalview.util.UrlConstants.DELIM;
+import static jalview.util.UrlConstants.SEP;
import static jalview.util.UrlConstants.SEQUENCE_ID;
import jalview.datamodel.DBRefEntry;
* documentation todo.
*/
- // Internal constants
- private static final String SEP = "|";
+ private static final String EQUALS = "=";
- private static final String DELIM = "$";
+ private static final String SPACE = " ";
private String urlSuffix;
private String label;
+ private String dbname;
+
private String regexReplace;
private boolean dynamic = false;
dynamic = true;
usesDBaccession = true;
- sep = parseTargetAndLabel(sep, psqid, link);
+ sep = parseLabel(sep, psqid, link);
- parseUrl(link, DB_ACCESSION, psqid, sep);
+ int endOfRegex = parseUrl(link, DB_ACCESSION, psqid, sep);
+ parseTarget(link, sep, endOfRegex);
}
else if (nsqid > -1)
{
dynamic = true;
- sep = parseTargetAndLabel(sep, nsqid, link);
+ sep = parseLabel(sep, nsqid, link);
+
+ int endOfRegex = parseUrl(link, SEQUENCE_ID, nsqid, sep);
- parseUrl(link, SEQUENCE_ID, nsqid, sep);
+ parseTarget(link, sep, endOfRegex);
}
else
{
- target = link.substring(0, sep);
- sep = link.lastIndexOf(SEP);
- label = link.substring(0, sep);
- urlPrefix = link.substring(sep + 1).trim();
+ label = link.substring(0, sep).trim();
+
+ // if there's a third element in the url link string
+ // it is the target name, otherwise target=label
+ int lastsep = link.lastIndexOf(SEP);
+ if (lastsep != sep)
+ {
+ urlPrefix = link.substring(sep + 1, lastsep).trim();
+ target = link.substring(lastsep + 1).trim();
+ }
+ else
+ {
+ urlPrefix = link.substring(sep + 1).trim();
+ target = label;
+ }
+
regexReplace = null; // implies we trim any prefix if necessary //
urlSuffix = null;
}
}
/**
+ * Alternative constructor for separate name, link and description
+ *
+ * @param name
+ * The string used to match the link to a DB reference id
+ * @param url
+ * The url to link to
+ * @param desc
+ * The description of the associated target DB
+ */
+ public UrlLink(String name, String url, String desc)
+ {
+ this(name + SEP + url + SEP + desc);
+ }
+
+ /**
* @return the url_suffix
*/
- public String getUrl_suffix()
+ public String getUrlSuffix()
{
return urlSuffix;
}
/**
* @return the url_prefix
*/
- public String getUrl_prefix()
+ public String getUrlPrefix()
{
return urlPrefix;
}
return label;
}
+ public String getUrlWithToken()
+ {
+ String var = (usesDBaccession ? DB_ACCESSION : SEQUENCE_ID);
+
+ return urlPrefix
+ + (dynamic ? (DELIM + var + ((regexReplace != null) ? EQUALS
+ + regexReplace + EQUALS + DELIM : DELIM)) : "")
+ + ((urlSuffix == null) ? "" : urlSuffix);
+ }
+
/**
* @return the regexReplace
*/
}
/**
+ * Set the target
+ *
+ * @param desc
+ */
+ public void setTarget(String desc)
+ {
+ target = desc;
+ }
+
+ /**
* return one or more URL strings by applying regex to the given idstring
*
* @param idstring
+ rg.stringMatched(s) + "'");
}
// try to collate subgroup matches
- Vector subs = new Vector();
+ Vector<String> subs = new Vector<String>();
// have to loop through submatches, collating them at top level
// match
int s = 0; // 1;
String[] res = new String[subs.size()];
for (int r = 0, rs = subs.size(); r < rs; r++)
{
- res[r] = (String) subs.elementAt(r);
+ res[r] = subs.elementAt(r);
}
subs.removeAllElements();
return res;
@Override
public String toString()
{
- String var = (usesDBaccession ? DB_ACCESSION : SEQUENCE_ID);
+ return label + SEP + getUrlWithToken();
+ }
- return label
- + SEP
- + urlPrefix
- + (dynamic ? (DELIM + var + ((regexReplace != null) ? "="
- + regexReplace + "=" + DELIM : DELIM)) : "")
- + ((urlSuffix == null) ? "" : urlSuffix);
+ /**
+ * @return delimited string containing label, url and target
+ */
+ public String toStringWithTarget()
+ {
+ return label + SEP + getUrlWithToken() + SEP + target;
}
/**
+ * Parse the label from the link string
*
* @param firstSep
* Location of first occurrence of separator in link string
* Link string containing database name and url
* @return Position of last separator symbol prior to any regex symbols
*/
- protected int parseTargetAndLabel(int firstSep, int psqid, String link)
+ protected int parseLabel(int firstSep, int psqid, String link)
{
int p = firstSep;
int sep = firstSep;
// Assuming that the URL itself does not contain any SEP symbols
// sep now contains last pipe symbol position prior to any regex symbols
label = link.substring(0, sep);
- if (label.indexOf(SEP) > -1)
- {
- // SEP terminated database name / www target at start of Label
- target = label.substring(0, label.indexOf(SEP));
- }
- else if (label.indexOf(" ") > 2)
+
+ return sep;
+ }
+
+ /**
+ * Parse the target from the link string
+ *
+ * @param link
+ * Link string containing database name and url
+ * @param sep
+ * Location of first separator symbol
+ * @param endOfRegex
+ * Location of end of any regular expression in link string
+ */
+ protected void parseTarget(String link, int sep, int endOfRegex)
+ {
+ int lastsep = link.lastIndexOf(SEP);
+
+ if ((lastsep != sep) && (lastsep > endOfRegex))
{
- // space separated Label - matches database name
- target = label.substring(0, label.indexOf(" "));
+ // final element in link string is the target
+ target = link.substring(lastsep + 1).trim();
}
else
{
target = label;
}
- return sep;
+
+ if (target.indexOf(SEP) > -1)
+ {
+ // SEP terminated database name / www target at start of Label
+ target = target.substring(0, target.indexOf(SEP));
+ }
+ else if (target.indexOf(SPACE) > 2)
+ {
+ // space separated label - first word matches database name
+ target = target.substring(0, target.indexOf(SPACE));
+ }
}
/**
* Position of id or name in link string
* @param sep
* Position of separator in link string
+ * @return Location of end of any regex in link string
*/
- protected void parseUrl(String link, String varName, int sqidPos, int sep)
+ protected int parseUrl(String link, String varName, int sqidPos, int sep)
{
urlPrefix = link.substring(sep + 1, sqidPos).trim();
// verify format is really correct.
if (link.indexOf(DELIM + varName + DELIM) == sqidPos)
{
- urlSuffix = link.substring(sqidPos + startLength - 1);
+ int lastsep = link.lastIndexOf(SEP);
+ if (lastsep < sqidPos + startLength - 1)
+ {
+ // the last SEP character was before the regex, ignore
+ lastsep = link.length();
+ }
+ urlSuffix = link.substring(sqidPos + startLength - 1, lastsep)
+ .trim();
regexReplace = null;
}
else
+ link;
}
}
+
+ return p;
}
/**
*/
protected void createStaticLink(Map<String, List<String>> linkset)
{
- if (!linkset.containsKey(label + SEP + getUrl_prefix()))
+ if (!linkset.containsKey(label + SEP + getUrlPrefix()))
{
// Add a non-dynamic link
- linkset.put(label + SEP + getUrl_prefix(),
- Arrays.asList(target, label, null, getUrl_prefix()));
+ linkset.put(label + SEP + getUrlPrefix(),
+ Arrays.asList(target, label, null, getUrlPrefix()));
}
}
}
}
}
-
- private static void testUrls(UrlLink ul, String idstring, String[] urls)
- {
-
- if (urls == null)
- {
- System.out.println("Created NO urls.");
- }
- else
- {
- System.out.println("Created " + (urls.length / 2) + " Urls.");
- for (int uls = 0; uls < urls.length; uls += 2)
- {
- System.out.println("URL Replacement text : " + urls[uls]
- + " : URL : " + urls[uls + 1]);
- }
- }
- }
-
- public static void main(String argv[])
- {
- String[] links = new String[] {
- /*
- * "AlinkT|Target|http://foo.foo.soo/",
- * "myUrl1|http://$SEQUENCE_ID=/[0-9]+/=$.someserver.org/foo",
- * "myUrl2|http://$SEQUENCE_ID=/(([0-9]+).+([A-Za-z]+))/=$.someserver.org/foo"
- * ,
- * "myUrl3|http://$SEQUENCE_ID=/([0-9]+).+([A-Za-z]+)/=$.someserver.org/foo"
- * , "myUrl4|target|http://$SEQUENCE_ID$.someserver.org/foo|too",
- * "PF1|http://us.expasy.org/cgi-bin/niceprot.pl?$SEQUENCE_ID=/(?:PFAM:)?(.+)/=$"
- * ,
- * "PF2|http://us.expasy.org/cgi-bin/niceprot.pl?$SEQUENCE_ID=/(PFAM:)?(.+)/=$"
- * ,
- * "PF3|http://us.expasy.org/cgi-bin/niceprot.pl?$SEQUENCE_ID=/PFAM:(.+)/=$"
- * , "NOTFER|http://notfer.org/$SEQUENCE_ID=/(?<!\\s)(.+)/=$",
- */
- "NESTED|http://nested/$" + DB_ACCESSION
- + "=/^(?:Label:)?(?:(?:gi\\|(\\d+))|([^:]+))/=$/nested" };
- String[] idstrings = new String[] {
- /*
- * //"LGUL_human", //"QWIQW_123123", "uniprot|why_do+_12313_foo",
- * //"123123312", "123123 ABCDE foo", "PFAM:PF23943",
- */
- "Label:gi|9234|pdb|102L|A" };
- // TODO: test the setLabel method.
- for (int i = 0; i < links.length; i++)
- {
- UrlLink ul = new UrlLink(links[i]);
- if (ul.isValid())
- {
- System.out.println("\n\n\n");
- System.out.println("Link " + i + " " + links[i] + " : "
- + ul.toString());
- System.out.println(" pref : "
- + ul.getUrl_prefix()
- + "\n suf : "
- + ul.getUrl_suffix()
- + "\n : "
- + ((ul.getRegexReplace() != null) ? ul.getRegexReplace()
- : ""));
- for (int ids = 0; ids < idstrings.length; ids++)
- {
- System.out.println("ID String : " + idstrings[ids]
- + "\nWithout onlyIfMatches:");
- String[] urls = ul.makeUrls(idstrings[ids], false);
- testUrls(ul, idstrings[ids], urls);
- System.out.println("With onlyIfMatches set.");
- urls = ul.makeUrls(idstrings[ids], true);
- testUrls(ul, idstrings[ids], urls);
- }
- }
- else
- {
- System.err.println("Invalid URLLink : " + links[i] + " : "
- + ul.getInvalidMessage());
- }
- }
- }
}
*/
package jalview.viewmodel;
+import java.awt.Color;
+import java.beans.PropertyChangeSupport;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+
import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder;
import jalview.analysis.Conservation;
import jalview.api.AlignCalcManagerI;
import jalview.workers.ConsensusThread;
import jalview.workers.StrucConsensusThread;
-import java.awt.Color;
-import java.beans.PropertyChangeSupport;
-import java.util.ArrayDeque;
-import java.util.ArrayList;
-import java.util.BitSet;
-import java.util.Deque;
-import java.util.HashMap;
-import java.util.Hashtable;
-import java.util.List;
-import java.util.Map;
-
/**
* base class holding visualization and analysis attributes and common logic for
* an active alignment view displayed in the GUI
public abstract class AlignmentViewport implements AlignViewportI,
CommandListener, VamsasSource
{
+ protected ViewportRanges ranges;
+
protected ViewStyleI viewStyle = new ViewStyle();
/**
protected AlignmentAnnotation complementConsensus;
+ protected AlignmentAnnotation gapcounts;
+
protected AlignmentAnnotation strucConsensus;
protected AlignmentAnnotation conservation;
}
@Override
+ public AlignmentAnnotation getAlignmentGapAnnotation()
+ {
+ return gapcounts;
+ }
+
+ @Override
public AlignmentAnnotation getComplementConsensusAnnotation()
{
return complementConsensus;
public void updateConsensus(final AlignmentViewPanel ap)
{
// see note in mantis : issue number 8585
- if (consensus == null || !autoCalculateConsensus)
+ if ((consensus == null || gapcounts == null) || !autoCalculateConsensus)
{
return;
}
*/
private boolean followHighlight = true;
- // TODO private with getters and setters?
- public int startRes;
-
- public int endRes;
-
- public int startSeq;
-
- public int endSeq;
-
/**
* Property change listener for changes in alignment
*
consensus = new AlignmentAnnotation("Consensus", "PID",
new Annotation[1], 0f, 100f, AlignmentAnnotation.BAR_GRAPH);
initConsensus(consensus);
+ gapcounts = new AlignmentAnnotation("Occupancy",
+ "Number of aligned positions",
+ new Annotation[1], 0f, alignment.getHeight(),
+ AlignmentAnnotation.BAR_GRAPH);
+ initGapCounts(gapcounts);
initComplementConsensus();
}
}
}
+ // these should be extracted from the view model - style and settings for
+ // derived annotation
+ private void initGapCounts(AlignmentAnnotation counts)
+ {
+ counts.hasText = false;
+ counts.autoCalculated = true;
+ counts.graph = AlignmentAnnotation.BAR_GRAPH;
+
+ if (showConsensus)
+ {
+ alignment.addAnnotation(counts);
+ }
+ }
+
private void initConservation()
{
if (showConservation)
public void setViewStyle(ViewStyleI settingsForView)
{
viewStyle = new ViewStyle(settingsForView);
+ if (residueShading != null)
+ {
+ residueShading.setConservationApplied(settingsForView
+ .isConservationColourSelected());
+ }
}
@Override
this.followHighlight = b;
}
- public int getStartRes()
- {
- return startRes;
- }
-
@Override
- public int getEndRes()
- {
- return endRes;
- }
-
- public int getStartSeq()
- {
- return startSeq;
- }
-
- public void setStartRes(int res)
+ public ViewportRanges getRanges()
{
- this.startRes = res;
- }
-
- public void setStartSeq(int seq)
- {
- this.startSeq = seq;
- }
-
- public void setEndRes(int res)
- {
- if (res > alignment.getWidth() - 1)
- {
- // log.System.out.println(" Corrected res from " + res + " to maximum " +
- // (alignment.getWidth()-1));
- res = alignment.getWidth() - 1;
- }
- if (res < 0)
- {
- res = 0;
- }
- this.endRes = res;
- }
-
- public void setEndSeq(int seq)
- {
- if (seq > alignment.getHeight())
- {
- seq = alignment.getHeight();
- }
- if (seq < 0)
- {
- seq = 0;
- }
- this.endSeq = seq;
- }
-
- public int getEndSeq()
- {
- return endSeq;
+ return ranges;
}
/**
* locate 'middle' column (true middle if an odd number visible, left of
* middle if an even number visible)
*/
- int middleColumn = getStartRes() + (getEndRes() - getStartRes()) / 2;
+ int middleColumn = ranges.getStartRes()
+ + (ranges.getEndRes() - ranges.getStartRes()) / 2;
final HiddenSequences hiddenSequences = getAlignment()
.getHiddenSequences();
*/
int lastSeq = alignment.getHeight() - 1;
List<AlignedCodonFrame> seqMappings = null;
- for (int seqNo = getStartSeq(); seqNo < lastSeq; seqNo++, seqOffset++)
+ for (int seqNo = ranges.getStartSeq(); seqNo < lastSeq; seqNo++, seqOffset++)
{
sequence = getAlignment().getSequenceAt(seqNo);
if (hiddenSequences != null && hiddenSequences.isHidden(sequence))
*/
private boolean selectionIsDefinedGroup = false;
-
@Override
public boolean isSelectionDefinedGroup()
{
--- /dev/null
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview 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.
+ *
+ * Jalview 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.viewmodel;
+
+import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenSequences;
+
+import java.awt.Graphics;
+
+public class OverviewDimensions
+{
+ // Default width and height values
+ private static final int DEFAULT_GRAPH_HEIGHT = 20;
+
+ private static final int MAX_WIDTH = 400;
+
+ private static final int MIN_WIDTH = 120;
+
+ private static final int MIN_SEQ_HEIGHT = 40;
+
+ private static final int MAX_SEQ_HEIGHT = 300;
+
+ // width of the overview panel
+ private int width;
+
+ // height of sequences part of the overview panel
+ private int sequencesHeight;
+
+ // height of the graphs part of the overview panel
+ private int graphHeight = DEFAULT_GRAPH_HEIGHT;
+
+ // dimensions of box outlining current extent of view in alignment panel
+ // location of left side of box
+ private int boxX = -1;
+
+ // location of bottom of box
+ private int boxY = -1;
+
+ // width of box
+ private int boxWidth = -1;
+
+ // height of box
+ private int boxHeight = -1;
+
+ // scroll position in viewport corresponding to boxX
+ private int scrollCol = -1;
+
+ // scroll position in viewport corresponding to boxY
+ private int scrollRow = -1;
+
+ /**
+ * Create an OverviewDimensions object
+ *
+ * @param ranges
+ * positional properties of the viewport
+ * @param showAnnotationPanel
+ * true if the annotation panel is to be shown, false otherwise
+ */
+ public OverviewDimensions(ViewportRanges ranges,
+ boolean showAnnotationPanel)
+ {
+ // scale the initial size of overviewpanel to shape of alignment
+ float initialScale = (float) ranges.getAbsoluteAlignmentWidth()
+ / (float) ranges.getAbsoluteAlignmentHeight();
+
+ if (!showAnnotationPanel)
+ {
+ graphHeight = 0;
+ }
+
+ if (ranges.getAbsoluteAlignmentWidth() > ranges
+ .getAbsoluteAlignmentHeight())
+ {
+ // wider
+ width = MAX_WIDTH;
+ sequencesHeight = Math.round(MAX_WIDTH / initialScale);
+ if (sequencesHeight < MIN_SEQ_HEIGHT)
+ {
+ sequencesHeight = MIN_SEQ_HEIGHT;
+ }
+ }
+ else
+ {
+ // taller
+ width = Math.round(MAX_WIDTH * initialScale);
+ sequencesHeight = MAX_SEQ_HEIGHT;
+
+ if (width < MIN_WIDTH)
+ {
+ width = MIN_WIDTH;
+ }
+ }
+ }
+
+ /**
+ * Check box dimensions and scroll positions and correct if necessary
+ *
+ * @param mousex
+ * x position in overview panel
+ * @param mousey
+ * y position in overview panel
+ * @param hiddenSeqs
+ * hidden sequences
+ * @param hiddenCols
+ * hidden columns
+ * @param ranges
+ * viewport position properties
+ */
+ public void updateViewportFromMouse(int mousex, int mousey,
+ HiddenSequences hiddenSeqs, ColumnSelection hiddenCols,
+ ViewportRanges ranges)
+ {
+ int x = mousex;
+ int y = mousey;
+
+ int alwidth = ranges.getAbsoluteAlignmentWidth();
+ int alheight = ranges.getAbsoluteAlignmentHeight();
+
+ if (x < 0)
+ {
+ x = 0;
+ }
+
+ if (y < 0)
+ {
+ y = 0;
+ }
+
+ //
+ // Convert x value to residue position
+ //
+
+ // need to determine where scrollCol should be, given x
+ // to do this also need to know width of viewport, and some hidden column
+ // correction
+
+ // convert x to residues - this is an absolute position
+ int xAsRes = Math.round((float) x * alwidth / width);
+
+ // get viewport width in residues
+ int vpwidth = ranges.getEndRes() - ranges.getStartRes() + 1;
+
+ // get where x should be when accounting for hidden cols
+ // if x is in a hidden col region, shift to left - but we still need
+ // absolute position
+ // so convert back after getting visible region position
+ int visXAsRes = hiddenCols.findColumnPosition(xAsRes);
+
+ // check in case we went off the edge of the alignment
+ int visAlignWidth = hiddenCols.findColumnPosition(alwidth - 1);
+ if (visXAsRes + vpwidth - 1 > visAlignWidth)
+ {
+ // went past the end of the alignment, adjust backwards
+
+ // if last position was before the end of the alignment, need to update
+ if ((scrollCol + vpwidth - 1) < visAlignWidth)
+ {
+ visXAsRes = hiddenCols.findColumnPosition(hiddenCols
+ .subtractVisibleColumns(vpwidth - 1, alwidth - 1));
+ }
+ else
+ {
+ visXAsRes = scrollCol;
+ }
+ }
+
+ //
+ // Convert y value to sequence position
+ //
+
+ // convert y to residues
+ int yAsSeq = Math.round((float) y * alheight / sequencesHeight);
+
+ // get viewport height in sequences
+ // add 1 because height includes both endSeq and startSeq
+ int vpheight = ranges.getEndSeq() - ranges.getStartSeq() + 1;
+
+ // get where y should be when accounting for hidden rows
+ // if y is in a hidden row region, shift up - but we still need absolute
+ // position,
+ // so convert back after getting visible region position
+ yAsSeq = hiddenSeqs.adjustForHiddenSeqs(hiddenSeqs
+ .findIndexWithoutHiddenSeqs(yAsSeq));
+
+ // check in case we went off the edge of the alignment
+ int visAlignHeight = hiddenSeqs.findIndexWithoutHiddenSeqs(alheight);
+ int visYAsRes = hiddenSeqs.findIndexWithoutHiddenSeqs(yAsSeq);
+ if (visYAsRes + vpheight - 1 > visAlignHeight)
+ {
+ // went past the end of the alignment, adjust backwards
+ if ((scrollRow + vpheight - 1) < visAlignHeight)
+ {
+ visYAsRes = hiddenSeqs.findIndexWithoutHiddenSeqs(hiddenSeqs
+ .subtractVisibleRows(vpheight - 1, alheight - 1));
+ }
+ else
+ {
+ visYAsRes = scrollRow;
+ }
+ }
+
+ // update scroll values
+ scrollCol = visXAsRes;
+ scrollRow = visYAsRes;
+
+ }
+
+ /**
+ * Update the overview panel box when the associated alignment panel is
+ * changed
+ *
+ * @param hiddenSeqs
+ * hidden sequences
+ * @param hiddenCols
+ * hidden columns
+ * @param ranges
+ * viewport position properties
+ */
+ public void setBoxPosition(HiddenSequences hiddenSeqs,
+ ColumnSelection hiddenCols, ViewportRanges ranges)
+ {
+ int alwidth = ranges.getAbsoluteAlignmentWidth();
+ int alheight = ranges.getAbsoluteAlignmentHeight();
+
+ // work with absolute values of startRes and endRes
+ int startRes = hiddenCols.adjustForHiddenColumns(ranges.getStartRes());
+ int endRes = hiddenCols.adjustForHiddenColumns(ranges.getEndRes());
+
+ // work with absolute values of startSeq and endSeq
+ int startSeq = hiddenSeqs.adjustForHiddenSeqs(ranges.getStartSeq());
+ int endSeq = hiddenSeqs.adjustForHiddenSeqs(ranges.getEndSeq());
+
+ // boxX, boxY is the x,y location equivalent to startRes, startSeq
+ boxX = Math.round((float) startRes * width / alwidth);
+ boxY = Math.round((float) startSeq * sequencesHeight / alheight);
+
+ // boxWidth is the width in residues translated to pixels
+ // since the box includes both the start and end residues, add 1 to the
+ // difference
+ boxWidth = Math
+ .round((float) (endRes - startRes + 1) * width / alwidth);
+ // boxHeight is the height in sequences translated to pixels
+ boxHeight = Math.round((float) (endSeq - startSeq + 1)
+ * sequencesHeight
+ / alheight);
+ }
+
+ /**
+ * Draw the overview panel's viewport box on a graphics object
+ *
+ * @param g
+ * the graphics object to draw on
+ */
+ public void drawBox(Graphics g)
+ {
+ g.drawRect(boxX, boxY, boxWidth, boxHeight);
+ g.drawRect(boxX + 1, boxY + 1, boxWidth - 2, boxHeight - 2);
+ }
+
+ public int getScrollCol()
+ {
+ return scrollCol;
+ }
+
+ public int getScrollRow()
+ {
+ return scrollRow;
+ }
+
+ // TODO should be removed, when unit test has mock Graphics object available
+ // to check boxX/boxY
+ public int getBoxX()
+ {
+ return boxX;
+ }
+
+ // TODO should be removed, when unit test has mock Graphics object available
+ // to check boxX/boxY
+ public int getBoxY()
+ {
+ return boxY;
+ }
+
+ // TODO should be removed, when unit test has mock Graphics object available
+ public int getBoxWidth()
+ {
+ return boxWidth;
+ }
+
+ // TODO should be removed, when unit test has mock Graphics object available
+ public int getBoxHeight()
+ {
+ return boxHeight;
+ }
+
+ public void setWidth(int w)
+ {
+ width = w;
+ }
+
+ public void setHeight(int h)
+ {
+ sequencesHeight = h - graphHeight;
+ }
+
+ public int getWidth()
+ {
+ return width;
+ }
+
+ public int getHeight()
+ {
+ return sequencesHeight + graphHeight;
+ }
+
+ public int getSequencesHeight()
+ {
+ return sequencesHeight;
+ }
+
+ public int getGraphHeight()
+ {
+ return graphHeight;
+ }
+}
public class PCAModel
{
+ /*
+ * Jalview 2.10.1 treated gaps as X (peptide) or N (nucleotide)
+ * for pairwise scoring; 2.10.2 uses gap score (last column) in
+ * score matrix (JAL-2397)
+ * Set this flag to true (via Groovy) for 2.10.1 behaviour
+ */
+ private static boolean scoreGapAsAny = false;
public PCAModel(AlignmentView seqstrings2, SequenceI[] seqs2,
boolean nucleotide2)
public void run()
{
-
- pca = new PCA(seqstrings.getSequenceStrings(' '), nucleotide,
+ char gapChar = scoreGapAsAny ? (nucleotide ? 'N' : 'X') : ' ';
+ String[] sequenceStrings = seqstrings.getSequenceStrings(gapChar);
+ pca = new PCA(sequenceStrings, nucleotide,
score_matrix);
pca.setJvCalcMode(jvCalcMode);
pca.run();
ii++;
}
- double[][] comps = new double[ii][ii];
-
- for (int i = 0; i < ii; i++)
- {
- if (pca.getEigenvalue(i) > 1e-4)
- {
- comps[i] = pca.component(i);
- }
- }
-
- top = pca.getM().rows - 1;
+ int height = pca.getHeight();
+ // top = pca.getM().height() - 1;
+ top = height - 1;
points = new Vector<SequencePoint>();
float[][] scores = pca.getComponents(top - 1, top - 2, top - 3, 100);
- for (int i = 0; i < pca.getM().rows; i++)
+ for (int i = 0; i < height; i++)
{
SequencePoint sp = new SequencePoint(seqs[i], scores[i]);
points.addElement(sp);
}
-
}
public void updateRc(RotatableCanvasI rc)
{
- rc.setPoints(points, pca.getM().rows);
+ rc.setPoints(points, pca.getHeight());
}
public boolean isNucleotide()
// note: actual indices for components are dim1-1, etc (patch for JAL-1123)
float[][] scores = pca.getComponents(dim1 - 1, dim2 - 1, dim3 - 1, 100);
- for (int i = 0; i < pca.getM().rows; i++)
+ for (int i = 0; i < pca.getHeight(); i++)
{
- ((SequencePoint) points.elementAt(i)).coord = scores[i];
+ points.elementAt(i).coord = scores[i];
}
}
--- /dev/null
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview 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.
+ *
+ * Jalview 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.viewmodel;
+
+public abstract class ViewportProperties
+{
+
+}
--- /dev/null
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview 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.
+ *
+ * Jalview 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.viewmodel;
+
+import jalview.datamodel.AlignmentI;
+
+/**
+ * Embryonic class which: Supplies and updates viewport properties relating to
+ * position such as: start and end residues and sequences; ideally will serve
+ * hidden columns/rows too. Intention also to support calculations for
+ * positioning, scrolling etc. such as finding the middle of the viewport,
+ * checking for scrolls off screen
+ */
+public class ViewportRanges extends ViewportProperties
+{
+ // start residue of viewport
+ private int startRes;
+
+ // end residue of viewport
+ private int endRes;
+
+ // start sequence of viewport
+ private int startSeq;
+
+ // end sequence of viewport
+ private int endSeq;
+
+ // alignment
+ private AlignmentI al;
+
+ /**
+ * Constructor
+ *
+ * @param alignment
+ * the viewport's alignment
+ */
+ public ViewportRanges(AlignmentI alignment)
+ {
+ // initial values of viewport settings
+ this.startRes = 0;
+ this.endRes = alignment.getWidth() - 1;
+ this.startSeq = 0;
+ this.endSeq = alignment.getHeight() - 1;
+ this.al = alignment;
+ }
+
+ /**
+ * Get alignment width in cols, including hidden cols
+ */
+ public int getAbsoluteAlignmentWidth()
+ {
+ return al.getWidth();
+ }
+
+ /**
+ * Get alignment height in rows, including hidden rows
+ */
+ public int getAbsoluteAlignmentHeight()
+ {
+ return al.getHeight() + al.getHiddenSequences().getSize();
+ }
+
+ /**
+ * Set first residue visible in the viewport
+ *
+ * @param res
+ * residue position
+ */
+ public void setStartRes(int res)
+ {
+ if (res > al.getWidth() - 1)
+ {
+ res = al.getWidth() - 1;
+ }
+ else if (res < 0)
+ {
+ res = 0;
+ }
+ this.startRes = res;
+ }
+
+ /**
+ * Set last residue visible in the viewport
+ *
+ * @param res
+ * residue position
+ */
+ public void setEndRes(int res)
+ {
+ if (res >= al.getWidth())
+ {
+ res = al.getWidth() - 1;
+ }
+ else if (res < 0)
+ {
+ res = 0;
+ }
+ this.endRes = res;
+ }
+
+ /**
+ * Set the first sequence visible in the viewport
+ *
+ * @param seq
+ * sequence position
+ */
+ public void setStartSeq(int seq)
+ {
+ if (seq > al.getHeight() - 1)
+ {
+ seq = al.getHeight() - 1;
+ }
+ else if (seq < 0)
+ {
+ seq = 0;
+ }
+ this.startSeq = seq;
+ }
+
+ /**
+ * Set the last sequence visible in the viewport
+ *
+ * @param seq
+ * sequence position
+ */
+ public void setEndSeq(int seq)
+ {
+ if (seq >= al.getHeight())
+ {
+ seq = al.getHeight() - 1;
+ }
+ else if (seq < 0)
+ {
+ seq = 0;
+ }
+ this.endSeq = seq;
+ }
+
+ /**
+ * Get start residue of viewport
+ */
+ public int getStartRes()
+ {
+ return startRes;
+ }
+
+ /**
+ * Get end residue of viewport
+ */
+ public int getEndRes()
+ {
+ return endRes;
+ }
+
+ /**
+ * Get start sequence of viewport
+ */
+ public int getStartSeq()
+ {
+ return startSeq;
+ }
+
+ /**
+ * Get end sequence of viewport
+ */
+ public int getEndSeq()
+ {
+ return endSeq;
+ }
+}
}
/**
- * calculate the render colour for a specific feature using current feature
- * settings.
+ * Returns the configured colour for a particular feature instance. This
+ * includes calculation of 'colour by label', or of a graduated score colour,
+ * if applicable. It does not take into account feature visibility or colour
+ * transparency.
*
* @param feature
- * @return render colour for the given feature
+ * @return
*/
public Color getColour(SequenceFeature feature)
{
featureColours.put(featureType, col);
}
+ @Override
public void setTransparency(float value)
{
transparency = value;
}
+ @Override
public float getTransparency()
{
return transparency;
* @return list of groups
*/
@Override
- public List getGroups(boolean visible)
+ public List<String> getGroups(boolean visible)
{
if (featureGroups != null)
{
try
{
AlignmentAnnotation consensus = getConsensusAnnotation();
- if (consensus == null || calcMan.isPending(this))
+ AlignmentAnnotation gap = getGapAnnotation();
+ if ((consensus == null && gap == null) || calcMan.isPending(this))
{
calcMan.workerComplete(this);
return;
{
AlignmentAnnotation consensus = getConsensusAnnotation();
consensus.annotations = new Annotation[aWidth];
+ AlignmentAnnotation gap = getGapAnnotation();
+ if (gap != null)
+ {
+ gap.annotations = new Annotation[aWidth];
+ }
}
/**
SequenceI[] aseqs = getSequences();
int width = alignment.getWidth();
- ProfilesI hconsensus = AAFrequency.calculate(aseqs, width, 0,
- width, true);
+ ProfilesI hconsensus = AAFrequency.calculate(aseqs, width, 0, width,
+ true);
alignViewport.setSequenceConsensusHash(hconsensus);
setColourSchemeConsensus(hconsensus);
}
/**
+ * Get the Gap annotation for the alignment
+ *
+ * @return
+ */
+ protected AlignmentAnnotation getGapAnnotation()
+ {
+ return alignViewport.getAlignmentGapAnnotation();
+ }
+
+ /**
* update the consensus annotation from the sequence profile data using
* current visualization settings.
*/
&& hconsensus != null)
{
deriveConsensus(consensus, hconsensus);
+ AlignmentAnnotation gap = getGapAnnotation();
+ if (gap != null)
+ {
+ deriveGap(gap, hconsensus);
+ }
}
}
long nseq = getSequences().length;
AAFrequency.completeConsensus(consensusAnnotation, hconsensus,
- hconsensus.getStartColumn(),
- hconsensus.getEndColumn() + 1,
+ hconsensus.getStartColumn(), hconsensus.getEndColumn() + 1,
alignViewport.isIgnoreGapsConsensus(),
alignViewport.isShowSequenceLogo(), nseq);
}
/**
+ * Convert the computed consensus data into a gap annotation row for display.
+ *
+ * @param gapAnnotation
+ * the annotation to be populated
+ * @param hconsensus
+ * the computed consensus data
+ */
+ protected void deriveGap(AlignmentAnnotation gapAnnotation,
+ ProfilesI hconsensus)
+ {
+ long nseq = getSequences().length;
+ AAFrequency.completeGapAnnot(gapAnnotation, hconsensus,
+ hconsensus.getStartColumn(), hconsensus.getEndColumn() + 1,
+ nseq);
+ }
+
+ /**
* Get the consensus data stored on the viewport.
*
* @return
{
calcMan.notifyStart(this); // updatingConservation = true;
- while (!calcMan.notifyWorking(this))
+ while ((calcMan != null) && (!calcMan.notifyWorking(this)))
{
try
{
ex.printStackTrace();
}
}
- if (alignViewport.isClosed())
+ if ((alignViewport == null) || (calcMan == null)
+ || (alignViewport.isClosed()))
{
abortAndDestroy();
return;
}
calcMan.workerComplete(this);
+ if ((alignViewport == null) || (calcMan == null)
+ || (alignViewport.isClosed()))
+ {
+ abortAndDestroy();
+ return;
+ }
if (ap != null)
{
ap.paintAlignment(true);
}
af.getFeatureRenderer().featuresAdded();
- int start = af.getViewport().getStartSeq();
- int end = af.getViewport().getEndSeq();
+ int start = af.getViewport().getRanges().getStartSeq();
+ int end = af.getViewport().getRanges().getEndSeq();
int index;
for (index = start; index < end; index++)
{
public class SiftsClient implements SiftsClientI
{
+ /*
+ * for use in mocking out file fetch for tests only
+ * - reset to null after testing!
+ */
+ private static File mockSiftsFile;
+
private Entry siftsEntry;
private StructureFile pdb;
*/
public static File getSiftsFile(String pdbId) throws SiftsException
{
+ /*
+ * return mocked file if it has been set
+ */
+ if (mockSiftsFile != null)
+ {
+ return mockSiftsFile;
+ }
+
String siftsFileName = SiftsSettings.getSiftDownloadDirectory()
+ pdbId.toLowerCase() + ".xml.gz";
File siftsFile = new File(siftsFileName);
return siftsEntry.getDbVersion();
}
+ public static void setMockSiftsFile(File file)
+ {
+ mockSiftsFile = file;
+ }
+
}
--- /dev/null
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview 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.
+ *
+ * Jalview 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+
+package jalview.ws.utils;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.net.URL;
+import java.nio.channels.Channels;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+
+public class UrlDownloadClient
+{
+ public UrlDownloadClient()
+ {
+
+ }
+
+ /**
+ * Download and save a file from a URL
+ *
+ * @param urlstring
+ * url to download from, as string
+ * @param outfile
+ * the name of file to save the URLs to
+ * @throws IOException
+ */
+ public void download(String urlstring, String outfile) throws IOException
+ {
+ FileOutputStream fos = null;
+ ReadableByteChannel rbc = null;
+ Path temp = null;
+ try
+ {
+ temp = Files.createTempFile(".jalview_", ".tmp");
+
+ URL url = new URL(urlstring);
+ rbc = Channels.newChannel(url.openStream());
+ fos = new FileOutputStream(temp.toString());
+ fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
+
+ // copy tempfile to outfile once our download completes
+ // incase something goes wrong
+ Files.copy(temp, Paths.get(outfile),
+ StandardCopyOption.REPLACE_EXISTING);
+ } catch (IOException e)
+ {
+ throw e;
+ } finally
+ {
+ try
+ {
+ if (fos != null)
+ {
+ fos.close();
+ }
+ } catch (IOException e)
+ {
+ System.out
+ .println("Exception while closing download file output stream: "
+ + e.getMessage());
+ }
+ try
+ {
+ if (rbc != null)
+ {
+ rbc.close();
+ }
+ } catch (IOException e)
+ {
+ System.out.println("Exception while closing download channel: "
+ + e.getMessage());
+ }
+ try
+ {
+ if (temp != null)
+ {
+ Files.deleteIfExists(temp);
+ }
+ } catch (IOException e)
+ {
+ System.out.println("Exception while deleting download temp file: "
+ + e.getMessage());
+ }
+ }
+ }
+}
import static org.testng.AssertJUnit.assertSame;
import static org.testng.AssertJUnit.assertTrue;
+import jalview.analysis.AlignmentGenerator;
import jalview.datamodel.AlignedCodonFrame.SequenceToSequenceMapping;
import jalview.gui.JvOptionPane;
import jalview.io.DataSourceType;
assertNull(a.findGroup(seq2, 8));
}
+ @Test(groups = { "Functional" })
+ public void testDeleteSequenceByIndex()
+ {
+ // create random alignment
+ AlignmentGenerator gen = new AlignmentGenerator(false);
+ AlignmentI a = gen.generate(20, 15, 123, 5, 5);
+
+ // delete sequence 10, alignment reduced by 1
+ int height = a.getAbsoluteHeight();
+ a.deleteSequence(10);
+ assertEquals(a.getAbsoluteHeight(), height - 1);
+
+ // try to delete -ve index, nothing happens
+ a.deleteSequence(-1);
+ assertEquals(a.getAbsoluteHeight(), height - 1);
+
+ // try to delete beyond end of alignment, nothing happens
+ a.deleteSequence(14);
+ assertEquals(a.getAbsoluteHeight(), height - 1);
+ }
+
+ @Test(groups = { "Functional" })
+ public void testDeleteSequenceBySeq()
+ {
+ // create random alignment
+ AlignmentGenerator gen = new AlignmentGenerator(false);
+ AlignmentI a = gen.generate(20, 15, 123, 5, 5);
+
+ // delete sequence 10, alignment reduced by 1
+ int height = a.getAbsoluteHeight();
+ SequenceI seq = a.getSequenceAt(10);
+ a.deleteSequence(seq);
+ assertEquals(a.getAbsoluteHeight(), height - 1);
+
+ // try to delete non-existent sequence, nothing happens
+ seq = new Sequence("cds", "GCCTCGGAT");
+ assertEquals(a.getAbsoluteHeight(), height - 1);
+ }
+
+ @Test(groups = { "Functional" })
+ public void testDeleteHiddenSequence()
+ {
+ // create random alignment
+ AlignmentGenerator gen = new AlignmentGenerator(false);
+ AlignmentI a = gen.generate(20, 15, 123, 5, 5);
+
+ // delete a sequence which is hidden, check it is NOT removed from hidden
+ // sequences
+ int height = a.getAbsoluteHeight();
+ SequenceI seq = a.getSequenceAt(2);
+ a.getHiddenSequences().hideSequence(seq);
+ assertEquals(a.getHiddenSequences().getSize(), 1);
+ a.deleteSequence(2);
+ assertEquals(a.getAbsoluteHeight(), height - 1);
+ assertEquals(a.getHiddenSequences().getSize(), 1);
+
+ // delete a sequence which is not hidden, check hiddenSequences are not
+ // affected
+ a.deleteSequence(10);
+ assertEquals(a.getAbsoluteHeight(), height - 2);
+ assertEquals(a.getHiddenSequences().getSize(), 1);
+ }
+
}
cs.hideColumns(4, 4);
assertEquals(4, cs.findColumnPosition(5));
+ // hiding column 4 moves column 4 to position 3
+ assertEquals(3, cs.findColumnPosition(4));
+
// hiding columns 1 and 2 moves column 5 to column 2
cs.hideColumns(1, 2);
assertEquals(2, cs.findColumnPosition(5));
+
+ // check with > 1 hidden column regions
+ // where some columns are in the hidden regions
+ ColumnSelection cs2 = new ColumnSelection();
+ cs2.hideColumns(5, 10);
+ cs2.hideColumns(20, 27);
+ cs2.hideColumns(40, 44);
+
+ // hiding columns 5-10 and 20-27 moves column 8 to column 4
+ assertEquals(4, cs2.findColumnPosition(8));
+
+ // and moves column 24 to 13
+ assertEquals(13, cs2.findColumnPosition(24));
+
+ // and moves column 28 to 14
+ assertEquals(14, cs2.findColumnPosition(28));
+
+ // and moves column 40 to 25
+ assertEquals(25, cs2.findColumnPosition(40));
+
+ // check when hidden columns start at 0 that the visible column
+ // is returned as 0
+ ColumnSelection cs3 = new ColumnSelection();
+ cs3.hideColumns(0, 4);
+ assertEquals(0, cs3.findColumnPosition(2));
+
+ }
+
+ /**
+ * Test the method that finds the visible column position a given distance
+ * before another column
+ */
+ @Test(groups = { "Functional" })
+ public void testFindColumnNToLeft()
+ {
+ ColumnSelection cs = new ColumnSelection();
+
+ // test that without hidden columns, findColumnNToLeft returns
+ // position n to left of provided position
+ int pos = cs.subtractVisibleColumns(3, 10);
+ assertEquals(7, pos);
+
+ // 0 returns same position
+ pos = cs.subtractVisibleColumns(0, 10);
+ assertEquals(10, pos);
+
+ // overflow to left returns negative number
+ pos = cs.subtractVisibleColumns(3, 0);
+ assertEquals(-3, pos);
+
+ // test that with hidden columns to left of result column
+ // behaviour is the same as above
+ cs.hideColumns(1, 3);
+
+ // position n to left of provided position
+ pos = cs.subtractVisibleColumns(3, 10);
+ assertEquals(7, pos);
+
+ // 0 returns same position
+ pos = cs.subtractVisibleColumns(0, 10);
+ assertEquals(10, pos);
+
+ // test with one set of hidden columns between start and required position
+ cs.hideColumns(12, 15);
+ pos = cs.subtractVisibleColumns(8, 17);
+ assertEquals(5, pos);
+
+ // test with two sets of hidden columns between start and required position
+ cs.hideColumns(20, 21);
+ pos = cs.subtractVisibleColumns(8, 23);
+ assertEquals(9, pos);
+
+ // repeat last 2 tests with no hidden columns to left of required position
+ cs.revealAllHiddenColumns();
+
+ // test with one set of hidden columns between start and required position
+ cs.hideColumns(12, 15);
+ pos = cs.subtractVisibleColumns(8, 17);
+ assertEquals(5, pos);
+
+ // test with two sets of hidden columns between start and required position
+ cs.hideColumns(20, 21);
+ pos = cs.subtractVisibleColumns(8, 23);
+ assertEquals(9, pos);
+
}
/**
JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
}
- static int SEQ_COUNT = 10;
+ static int SEQ_COUNT = 25;
SequenceI[] seqs;
seqs = new SequenceI[SEQ_COUNT];
for (int i = 0; i < SEQ_COUNT; i++)
{
- // sequence lengths are 1, 2, ... 10
- seqs[i] = new Sequence("Seq" + i, "abcdefghijk".substring(0, i + 1));
+ // sequence lengths are 1, 2, ... 25
+ seqs[i] = new Sequence("Seq" + i,
+ "abcdefghijklmnopqrstuvwxy".substring(0, i + 1));
}
}
/*
* alignment is now seq0/2/3/4/7/8/9
*/
- assertEquals(7, al.getHeight());
+ assertEquals(SEQ_COUNT - 3, al.getHeight());
assertEquals(0, hs.adjustForHiddenSeqs(0));
assertEquals(2, hs.adjustForHiddenSeqs(1));
assertEquals(3, hs.adjustForHiddenSeqs(2));
/*
* alignment is now seq0/2/3/4/7/8/9
*/
- assertEquals(7, al.getHeight());
+ assertEquals(SEQ_COUNT - 3, al.getHeight());
assertEquals(0, hs.findIndexWithoutHiddenSeqs(0));
assertEquals(0, hs.findIndexWithoutHiddenSeqs(1));
assertEquals(1, hs.findIndexWithoutHiddenSeqs(2));
}
/**
+ * Test the method that finds the visible row position a given distance before
+ * another row
+ */
+ @Test(groups = { "Functional" })
+ public void testFindIndexNFromRow()
+ {
+ AlignmentI al = new Alignment(seqs);
+ HiddenSequences hs = new HiddenSequences(al);
+
+ // test that without hidden rows, findIndexNFromRow returns
+ // position n above provided position
+ int pos = hs.subtractVisibleRows(3, 10);
+ assertEquals(7, pos);
+
+ // 0 returns same position
+ pos = hs.subtractVisibleRows(0, 10);
+ assertEquals(10, pos);
+
+ // overflow to top returns negative number
+ pos = hs.subtractVisibleRows(3, 0);
+ assertEquals(-3, pos);
+
+ // test that with hidden rows above result row
+ // behaviour is the same as above
+ hs.hideSequence(seqs[1]);
+ hs.hideSequence(seqs[2]);
+ hs.hideSequence(seqs[3]);
+
+ // position n above provided position
+ pos = hs.subtractVisibleRows(3, 10);
+ assertEquals(7, pos);
+
+ // 0 returns same position
+ pos = hs.subtractVisibleRows(0, 10);
+ assertEquals(10, pos);
+
+ // test with one set of hidden rows between start and required position
+ hs.hideSequence(seqs[12]);
+ hs.hideSequence(seqs[13]);
+ hs.hideSequence(seqs[14]);
+ hs.hideSequence(seqs[15]);
+ pos = hs.subtractVisibleRows(8, 17);
+ assertEquals(5, pos);
+
+ // test with two sets of hidden rows between start and required position
+ hs.hideSequence(seqs[20]);
+ hs.hideSequence(seqs[21]);
+ pos = hs.subtractVisibleRows(8, 23);
+ assertEquals(9, pos);
+
+ // repeat last 2 tests with no hidden columns to left of required position
+ hs.showAll(null);
+
+ // test with one set of hidden rows between start and required position
+ hs.hideSequence(seqs[12]);
+ hs.hideSequence(seqs[13]);
+ hs.hideSequence(seqs[14]);
+ hs.hideSequence(seqs[15]);
+ pos = hs.subtractVisibleRows(8, 17);
+ assertEquals(5, pos);
+
+ // test with two sets of hidden rows between start and required position
+ hs.hideSequence(seqs[20]);
+ hs.hideSequence(seqs[21]);
+ pos = hs.subtractVisibleRows(8, 23);
+ assertEquals(9, pos);
+
+ }
+
+ /**
* Test the method that reconstructs (sort of) the full alignment including
* hidden sequences
*/
assertTrue(al.getSequences().contains(seqs[1]));
HiddenSequences hs = al.getHiddenSequences();
assertEquals(0, hs.getSize());
- assertEquals(10, al.getHeight());
+ assertEquals(SEQ_COUNT, al.getHeight());
/*
* hide the second sequence in the alignment
assertTrue(hs.isHidden(seqs[1]));
assertFalse(al.getSequences().contains(seqs[1]));
assertEquals(1, hs.getSize());
- assertEquals(9, al.getHeight());
+ assertEquals(SEQ_COUNT - 1, al.getHeight());
assertSame(seqs[2], al.getSequenceAt(1));
/*
assertFalse(al.getSequences().contains(seqs[1]));
assertFalse(al.getSequences().contains(seqs[2]));
assertEquals(2, hs.getSize());
- assertEquals(8, al.getHeight());
+ assertEquals(SEQ_COUNT - 2, al.getHeight());
/*
* perform 'reveal' on what is now the second sequence in the alignment
assertTrue(revealed.contains(seqs[1]));
assertTrue(revealed.contains(seqs[2]));
assertEquals(0, hs.getSize());
- assertEquals(10, al.getHeight());
+ assertEquals(SEQ_COUNT, al.getHeight());
+ }
+
+ /**
+ * Test the method that adds a sequence to the hidden sequences and deletes it
+ * from the alignment, and its converse, where the first hidden sequences are
+ * at the bottom of the alignment (JAL-2437)
+ */
+ @Test(groups = "Functional")
+ public void testHideShowLastSequences()
+ {
+ AlignmentI al = new Alignment(seqs);
+ assertTrue(al.getSequences().contains(seqs[1]));
+ HiddenSequences hs = al.getHiddenSequences();
+ assertEquals(0, hs.getSize());
+ assertEquals(SEQ_COUNT, al.getHeight());
+
+ /*
+ * hide the last sequence in the alignment
+ */
+ hs.hideSequence(seqs[SEQ_COUNT - 1]);
+ assertFalse(hs.isHidden(seqs[SEQ_COUNT - 2]));
+ assertTrue(hs.isHidden(seqs[SEQ_COUNT - 1]));
+ assertFalse(al.getSequences().contains(seqs[SEQ_COUNT - 1]));
+ assertEquals(1, hs.getSize());
+ assertEquals(SEQ_COUNT - 1, al.getHeight());
+
+ /*
+ * hide the third last sequence in the alignment
+ */
+ hs.hideSequence(seqs[SEQ_COUNT - 3]);
+ assertFalse(hs.isHidden(seqs[SEQ_COUNT - 2]));
+ assertTrue(hs.isHidden(seqs[SEQ_COUNT - 3]));
+ assertFalse(al.getSequences().contains(seqs[SEQ_COUNT - 3]));
+ assertEquals(2, hs.getSize());
+ assertEquals(SEQ_COUNT - 2, al.getHeight());
+
+ /*
+ * reveal all the sequences, which should be reinstated in the same order as they started in
+ */
+ hs.showAll(null);
+ assertFalse(hs.isHidden(seqs[SEQ_COUNT - 3]));
+ assertFalse(hs.isHidden(seqs[SEQ_COUNT - 1]));
+ assertEquals(seqs[SEQ_COUNT - 3], al.getSequences().get(SEQ_COUNT - 3));
+ assertEquals(seqs[SEQ_COUNT - 2], al.getSequences().get(SEQ_COUNT - 2));
+ assertEquals(seqs[SEQ_COUNT - 1], al.getSequences().get(SEQ_COUNT - 1));
+ assertEquals(0, hs.getSize());
+ assertEquals(SEQ_COUNT, al.getHeight());
}
@Test(groups = "Functional")
public class SequenceGroupTest
{
- @Test
+ @Test(groups={"Functional"})
public void testAddSequence()
{
SequenceGroup sg = new SequenceGroup();
assertTrue(sg.getSequences().contains(seq3));
}
- @Test
+ @Test(groups={"Functional"})
public void testAddOrRemove()
{
SequenceGroup sg = new SequenceGroup();
assertFalse(sg.getSequences().contains(seq1));
}
- @Test
+ @Test(groups={"Functional"})
public void testGetColourScheme()
{
SequenceGroup sg = new SequenceGroup();
assertSame(scheme, sg.getColourScheme());
}
- @Test
+ @Test(groups={"Functional"})
public void testSetContext()
{
SequenceGroup sg1 = new SequenceGroup();
assertNull(sg3.getContext());
}
}
+
+ @Test(groups = { "Functional" })
+ public void testContains()
+ {
+ /*
+ * essentially the same tests as AlignmentI.findGroup
+ * but from a particular group's perspective
+ */
+
+ SequenceI seq1 = new Sequence("seq1", "ABCDEF---GHI");
+ SequenceI seq2 = new Sequence("seq2", "---JKLMNO---");
+ AlignmentI a = new Alignment(new SequenceI[] { seq1, seq2 });
+ /*
+ * add a group consisting of just "DEF"
+ */
+ SequenceGroup sg1 = new SequenceGroup();
+ sg1.addSequence(seq1, false);
+ sg1.setStartRes(3);
+ sg1.setEndRes(5);
+
+ /*
+ * test sequence membership
+ */
+ assertTrue(sg1.contains(seq1));
+ assertFalse(sg1.contains(seq2));
+
+ /*
+ * test sequence+position
+ */
+
+ assertFalse(sg1.contains(seq1, 2)); // position not in group
+ assertFalse(sg1.contains(seq1, 6)); // position not in group
+ assertFalse(sg1.contains(seq2, 5)); // sequence not in group
+ assertTrue(sg1.contains(seq1, 3)); // yes
+ assertTrue(sg1.contains(seq1, 4));
+ assertTrue(sg1.contains(seq1, 5));
+
+ /*
+ * add a group consisting of
+ * EF--
+ * KLMN
+ */
+ SequenceGroup sg2 = new SequenceGroup();
+ sg2.addSequence(seq1, false);
+ sg2.addSequence(seq2, false);
+ sg2.setStartRes(4);
+ sg2.setEndRes(7);
+ a.addGroup(sg2);
+
+ /*
+ * if a residue is in more than one group, method returns
+ * the first found (in order groups were added)
+ */
+ assertTrue(sg2.contains(seq1, 4));
+ assertTrue(sg2.contains(seq1, 5));
+
+ /*
+ * seq2 only belongs to the second group
+ */
+ assertTrue(sg2.contains(seq2, 4));
+ assertTrue(sg2.contains(seq2, 5));
+ assertTrue(sg2.contains(seq2, 6));
+ assertTrue(sg2.contains(seq2, 7));
+ assertFalse(sg2.contains(seq2, 3));
+ assertFalse(sg2.contains(seq2, 8));
+ sg2.setEndRes(8);
+ assertTrue(sg2.contains(seq2, 8));
+ sg2.deleteSequence(seq2, false);
+ assertFalse(sg2.contains(seq2));
+
+ }
}
--- /dev/null
+package jalview.ext.android;
+
+import static org.testng.Assert.assertEquals;
+
+import org.testng.annotations.Test;
+
+public class SparseDoubleArrayTest
+{
+
+ @Test
+ public void testConstructor()
+ {
+ double[] d = new double[] { 0d, 0d, 1.2d, 0d, 0d, 3.4d };
+ SparseDoubleArray s = new SparseDoubleArray(d);
+ for (int i = 0; i < d.length; i++)
+ {
+ assertEquals(s.get(i), d[i], "At [" + i + "]");
+ }
+ }
+
+ @Test
+ public void testAdd()
+ {
+ double[] d = new double[] { 0d, 0d, 1.2d, 0d, 0d, 3.4d };
+ SparseDoubleArray s = new SparseDoubleArray(d);
+ // add to zero (absent)
+ s.add(0, 3.2d);
+ assertEquals(s.get(0), 3.2d);
+ // add to non-zero
+ s.add(0, 2.5d);
+ assertEquals(s.get(0), 5.7d);
+ // add negative value
+ s.add(2, -5.3d);
+ assertEquals(s.get(2), -4.1d);
+ // add to unset value
+ s.add(12, 9.8d);
+ assertEquals(s.get(12), 9.8d);
+ }
+
+ @Test
+ public void testDivide()
+ {
+ double delta = 1.0e-10;
+ double[] d = new double[] { 0d, 2.4d, 1.2d, 0d, -4.8d, -3.6d };
+ SparseDoubleArray s = new SparseDoubleArray(d);
+ assertEquals(s.divide(0, 1d), 0d); // no such entry
+ assertEquals(s.divide(2, 0d), 0d); // zero divisor
+ assertEquals(s.divide(1, 2d), 1.2d, delta); // + / +
+ assertEquals(s.divide(2, -2d), -0.6d, delta); // + / -
+ assertEquals(s.divide(4, 3d), -1.6d, delta); // - / +
+ assertEquals(s.divide(5, -3d), 1.2d, delta); // - / -
+ }
+}
// need some mappings!
StructureMappingcommandSet[] commands = JmolCommands
- .getColourBySequenceCommand(ssm, files, seqs, sr, null, al);
+ .getColourBySequenceCommand(ssm, files, seqs, sr, af.alignPanel);
}
}
import jalview.api.structures.JalviewStructureDisplayI;
import jalview.bin.Cache;
+import jalview.bin.Jalview;
import jalview.datamodel.SequenceI;
import jalview.gui.AlignFrame;
import jalview.gui.JvOptionPane;
@BeforeClass(alwaysRun = true)
public static void setUpBeforeClass() throws Exception
{
- jalview.bin.Jalview.main(new String[] {
- "-noquestionnaire -nonews -props",
+ Jalview.main(new String[] { "-noquestionnaire", "-nonews", "-props",
"test/jalview/ext/rbvi/chimera/testProps.jvprops" });
}
--- /dev/null
+HEADER ELECTRON TRANSPORT 26-APR-15 4ZHO
+TITLE THE CRYSTAL STRUCTURE OF ARABIDOPSIS FERREDOXIN 2 WITH 2FE-2S CLUSTER
+COMPND MOL_ID: 1;
+COMPND 2 MOLECULE: FERREDOXIN-2, CHLOROPLASTIC;
+COMPND 3 CHAIN: A, B;
+COMPND 4 SYNONYM: ATFD2;
+COMPND 5 ENGINEERED: YES
+SOURCE MOL_ID: 1;
+SOURCE 2 ORGANISM_SCIENTIFIC: ARABIDOPSIS THALIANA;
+SOURCE 3 ORGANISM_COMMON: MOUSE-EAR CRESS;
+SOURCE 4 ORGANISM_TAXID: 3702;
+SOURCE 5 GENE: FD2, PETF, PETF1, AT1G60950, T7P1.9;
+SOURCE 6 EXPRESSION_SYSTEM: ESCHERICHIA COLI BL21(DE3);
+SOURCE 7 EXPRESSION_SYSTEM_TAXID: 469008
+KEYWDS FERREDOXIN 2FE-2S CLUSTER ELECTRON TRANSFER CHLOROPLAST, ELECTRON
+KEYWDS 2 TRANSPORT
+EXPDTA X-RAY DIFFRACTION
+AUTHOR R.GRINTER,I.JOSTS,A.W.ROSZAK,R.J.COGDELL,D.WALKER
+REVDAT 2 09-NOV-16 4ZHO 1 JRNL
+REVDAT 1 31-AUG-16 4ZHO 0
+JRNL AUTH R.GRINTER,I.JOSTS,K.MOSBAHI,A.W.ROSZAK,R.J.COGDELL,
+JRNL AUTH 2 A.M.BONVIN,J.J.MILNER,S.M.KELLY,O.BYRON,B.O.SMITH,D.WALKER
+JRNL TITL STRUCTURE OF THE BACTERIAL PLANT-FERREDOXIN RECEPTOR FUSA.
+JRNL REF NAT COMMUN V. 7 13308 2016
+JRNL REFN ESSN 2041-1723
+JRNL PMID 27796364
+JRNL DOI 10.1038/NCOMMS13308
+REMARK 2
+REMARK 2 RESOLUTION. 2.34 ANGSTROMS.
+REMARK 3
+REMARK 3 REFINEMENT.
+REMARK 3 PROGRAM : REFMAC 5.8.0049
+REMARK 3 AUTHORS : MURSHUDOV,VAGIN,DODSON
+REMARK 3
+REMARK 3 REFINEMENT TARGET : MAXIMUM LIKELIHOOD
+REMARK 3
+REMARK 3 DATA USED IN REFINEMENT.
+REMARK 3 RESOLUTION RANGE HIGH (ANGSTROMS) : 2.34
+REMARK 3 RESOLUTION RANGE LOW (ANGSTROMS) : 60.73
+REMARK 3 DATA CUTOFF (SIGMA(F)) : NULL
+REMARK 3 COMPLETENESS FOR RANGE (%) : 99.5
+REMARK 3 NUMBER OF REFLECTIONS : 12221
+REMARK 3
+REMARK 3 FIT TO DATA USED IN REFINEMENT.
+REMARK 3 CROSS-VALIDATION METHOD : THROUGHOUT
+REMARK 3 FREE R VALUE TEST SET SELECTION : RANDOM
+REMARK 3 R VALUE (WORKING + TEST SET) : 0.198
+REMARK 3 R VALUE (WORKING SET) : 0.197
+REMARK 3 FREE R VALUE : 0.216
+REMARK 3 FREE R VALUE TEST SET SIZE (%) : 4.900
+REMARK 3 FREE R VALUE TEST SET COUNT : 627
+REMARK 3
+REMARK 3 FIT IN THE HIGHEST RESOLUTION BIN.
+REMARK 3 TOTAL NUMBER OF BINS USED : 20
+REMARK 3 BIN RESOLUTION RANGE HIGH (A) : 2.34
+REMARK 3 BIN RESOLUTION RANGE LOW (A) : 2.40
+REMARK 3 REFLECTION IN BIN (WORKING SET) : 864
+REMARK 3 BIN COMPLETENESS (WORKING+TEST) (%) : 98.58
+REMARK 3 BIN R VALUE (WORKING SET) : 0.2390
+REMARK 3 BIN FREE R VALUE SET COUNT : 39
+REMARK 3 BIN FREE R VALUE : 0.3090
+REMARK 3
+REMARK 3 NUMBER OF NON-HYDROGEN ATOMS USED IN REFINEMENT.
+REMARK 3 PROTEIN ATOMS : 1440
+REMARK 3 NUCLEIC ACID ATOMS : 0
+REMARK 3 HETEROGEN ATOMS : 10
+REMARK 3 SOLVENT ATOMS : 38
+REMARK 3
+REMARK 3 B VALUES.
+REMARK 3 FROM WILSON PLOT (A**2) : NULL
+REMARK 3 MEAN B VALUE (OVERALL, A**2) : 59.55
+REMARK 3 OVERALL ANISOTROPIC B VALUE.
+REMARK 3 B11 (A**2) : 2.75000
+REMARK 3 B22 (A**2) : 2.75000
+REMARK 3 B33 (A**2) : -5.50000
+REMARK 3 B12 (A**2) : 0.00000
+REMARK 3 B13 (A**2) : 0.00000
+REMARK 3 B23 (A**2) : 0.00000
+REMARK 3
+REMARK 3 ESTIMATED OVERALL COORDINATE ERROR.
+REMARK 3 ESU BASED ON R VALUE (A): 0.229
+REMARK 3 ESU BASED ON FREE R VALUE (A): 0.180
+REMARK 3 ESU BASED ON MAXIMUM LIKELIHOOD (A): 0.136
+REMARK 3 ESU FOR B VALUES BASED ON MAXIMUM LIKELIHOOD (A**2): 12.808
+REMARK 3
+REMARK 3 CORRELATION COEFFICIENTS.
+REMARK 3 CORRELATION COEFFICIENT FO-FC : 0.949
+REMARK 3 CORRELATION COEFFICIENT FO-FC FREE : 0.952
+REMARK 3
+REMARK 3 RMS DEVIATIONS FROM IDEAL VALUES COUNT RMS WEIGHT
+REMARK 3 BOND LENGTHS REFINED ATOMS (A): 1468 ; 0.017 ; 0.019
+REMARK 3 BOND LENGTHS OTHERS (A): 1296 ; 0.001 ; 0.020
+REMARK 3 BOND ANGLES REFINED ATOMS (DEGREES): 1990 ; 1.933 ; 1.975
+REMARK 3 BOND ANGLES OTHERS (DEGREES): 3026 ; 0.912 ; 3.000
+REMARK 3 TORSION ANGLES, PERIOD 1 (DEGREES): 192 ; 7.288 ; 5.000
+REMARK 3 TORSION ANGLES, PERIOD 2 (DEGREES): 66 ;34.298 ;26.970
+REMARK 3 TORSION ANGLES, PERIOD 3 (DEGREES): 234 ;14.918 ;15.000
+REMARK 3 TORSION ANGLES, PERIOD 4 (DEGREES): 2 ; 5.922 ;15.000
+REMARK 3 CHIRAL-CENTER RESTRAINTS (A**3): 230 ; 0.115 ; 0.200
+REMARK 3 GENERAL PLANES REFINED ATOMS (A): 1682 ; 0.007 ; 0.020
+REMARK 3 GENERAL PLANES OTHERS (A): 276 ; 0.001 ; 0.020
+REMARK 3 NON-BONDED CONTACTS REFINED ATOMS (A): NULL ; NULL ; NULL
+REMARK 3 NON-BONDED CONTACTS OTHERS (A): NULL ; NULL ; NULL
+REMARK 3 NON-BONDED TORSION REFINED ATOMS (A): NULL ; NULL ; NULL
+REMARK 3 NON-BONDED TORSION OTHERS (A): NULL ; NULL ; NULL
+REMARK 3 H-BOND (X...Y) REFINED ATOMS (A): NULL ; NULL ; NULL
+REMARK 3 H-BOND (X...Y) OTHERS (A): NULL ; NULL ; NULL
+REMARK 3 POTENTIAL METAL-ION REFINED ATOMS (A): NULL ; NULL ; NULL
+REMARK 3 POTENTIAL METAL-ION OTHERS (A): NULL ; NULL ; NULL
+REMARK 3 SYMMETRY VDW REFINED ATOMS (A): NULL ; NULL ; NULL
+REMARK 3 SYMMETRY VDW OTHERS (A): NULL ; NULL ; NULL
+REMARK 3 SYMMETRY H-BOND REFINED ATOMS (A): NULL ; NULL ; NULL
+REMARK 3 SYMMETRY H-BOND OTHERS (A): NULL ; NULL ; NULL
+REMARK 3 SYMMETRY METAL-ION REFINED ATOMS (A): NULL ; NULL ; NULL
+REMARK 3 SYMMETRY METAL-ION OTHERS (A): NULL ; NULL ; NULL
+REMARK 3
+REMARK 3 ISOTROPIC THERMAL FACTOR RESTRAINTS. COUNT RMS WEIGHT
+REMARK 3 MAIN-CHAIN BOND REFINED ATOMS (A**2): 774 ; 3.602 ; 4.642
+REMARK 3 MAIN-CHAIN BOND OTHER ATOMS (A**2): 773 ; 3.584 ; 4.636
+REMARK 3 MAIN-CHAIN ANGLE REFINED ATOMS (A**2): 964 ; 4.741 ; 6.949
+REMARK 3 MAIN-CHAIN ANGLE OTHER ATOMS (A**2): 965 ; 4.738 ; 6.957
+REMARK 3 SIDE-CHAIN BOND REFINED ATOMS (A**2): 694 ; 5.685 ; 5.263
+REMARK 3 SIDE-CHAIN BOND OTHER ATOMS (A**2): 691 ; 5.624 ; 5.277
+REMARK 3 SIDE-CHAIN ANGLE REFINED ATOMS (A**2): NULL ; NULL ; NULL
+REMARK 3 SIDE-CHAIN ANGLE OTHER ATOMS (A**2): 1021 ; 8.298 ; 7.648
+REMARK 3 LONG RANGE B REFINED ATOMS (A**2): 1582 ; 9.824 ;37.488
+REMARK 3 LONG RANGE B OTHER ATOMS (A**2): 1580 ; 9.825 ;37.492
+REMARK 3
+REMARK 3 ANISOTROPIC THERMAL FACTOR RESTRAINTS. COUNT RMS WEIGHT
+REMARK 3 RIGID-BOND RESTRAINTS (A**2): NULL ; NULL ; NULL
+REMARK 3 SPHERICITY; FREE ATOMS (A**2): NULL ; NULL ; NULL
+REMARK 3 SPHERICITY; BONDED ATOMS (A**2): NULL ; NULL ; NULL
+REMARK 3
+REMARK 3 NCS RESTRAINTS STATISTICS
+REMARK 3 NUMBER OF DIFFERENT NCS GROUPS : NULL
+REMARK 3
+REMARK 3 TLS DETAILS
+REMARK 3 NUMBER OF TLS GROUPS : 2
+REMARK 3
+REMARK 3 TLS GROUP : 1
+REMARK 3 NUMBER OF COMPONENTS GROUP : 1
+REMARK 3 COMPONENTS C SSSEQI TO C SSSEQI
+REMARK 3 RESIDUE RANGE : A 2 A 118
+REMARK 3 ORIGIN FOR THE GROUP (A): -11.9068 -7.9134 -35.1151
+REMARK 3 T TENSOR
+REMARK 3 T11: 0.0724 T22: 0.0486
+REMARK 3 T33: 0.0466 T12: -0.0255
+REMARK 3 T13: 0.0362 T23: -0.0257
+REMARK 3 L TENSOR
+REMARK 3 L11: 3.9618 L22: 2.5662
+REMARK 3 L33: 3.5301 L12: -0.2237
+REMARK 3 L13: -2.4244 L23: -0.7777
+REMARK 3 S TENSOR
+REMARK 3 S11: -0.1452 S12: 0.2312 S13: 0.0678
+REMARK 3 S21: 0.1082 S22: 0.0201 S23: 0.1702
+REMARK 3 S31: 0.1983 S32: -0.3971 S33: 0.1251
+REMARK 3
+REMARK 3 TLS GROUP : 2
+REMARK 3 NUMBER OF COMPONENTS GROUP : 1
+REMARK 3 COMPONENTS C SSSEQI TO C SSSEQI
+REMARK 3 RESIDUE RANGE : B 2 B 122
+REMARK 3 ORIGIN FOR THE GROUP (A): -27.4515 -16.6414 -12.3927
+REMARK 3 T TENSOR
+REMARK 3 T11: 0.0153 T22: 0.0305
+REMARK 3 T33: 0.0110 T12: 0.0014
+REMARK 3 T13: 0.0124 T23: -0.0038
+REMARK 3 L TENSOR
+REMARK 3 L11: 2.2921 L22: 2.7795
+REMARK 3 L33: 6.4597 L12: 0.0122
+REMARK 3 L13: 0.2226 L23: -0.5396
+REMARK 3 S TENSOR
+REMARK 3 S11: 0.0678 S12: -0.2191 S13: 0.0982
+REMARK 3 S21: 0.1361 S22: 0.0490 S23: 0.0984
+REMARK 3 S31: -0.1717 S32: -0.0459 S33: -0.1168
+REMARK 3
+REMARK 3 BULK SOLVENT MODELLING.
+REMARK 3 METHOD USED : MASK
+REMARK 3 PARAMETERS FOR MASK CALCULATION
+REMARK 3 VDW PROBE RADIUS : 1.20
+REMARK 3 ION PROBE RADIUS : 0.80
+REMARK 3 SHRINKAGE RADIUS : 0.80
+REMARK 3
+REMARK 3 OTHER REFINEMENT REMARKS: HYDROGENS HAVE BEEN ADDED IN THE RIDING
+REMARK 3 POSITIONS
+REMARK 4
+REMARK 4 4ZHO COMPLIES WITH FORMAT V. 3.30, 13-JUL-11
+REMARK 100
+REMARK 100 THIS ENTRY HAS BEEN PROCESSED BY PDBE ON 27-APR-15.
+REMARK 100 THE DEPOSITION ID IS D_1000209256.
+REMARK 200
+REMARK 200 EXPERIMENTAL DETAILS
+REMARK 200 EXPERIMENT TYPE : X-RAY DIFFRACTION
+REMARK 200 DATE OF DATA COLLECTION : 21-JUL-14
+REMARK 200 TEMPERATURE (KELVIN) : 100
+REMARK 200 PH : 8.5
+REMARK 200 NUMBER OF CRYSTALS USED : NULL
+REMARK 200
+REMARK 200 SYNCHROTRON (Y/N) : Y
+REMARK 200 RADIATION SOURCE : DIAMOND
+REMARK 200 BEAMLINE : I02
+REMARK 200 X-RAY GENERATOR MODEL : NULL
+REMARK 200 MONOCHROMATIC OR LAUE (M/L) : M
+REMARK 200 WAVELENGTH OR RANGE (A) : 1.74
+REMARK 200 MONOCHROMATOR : SILICON CRYSTAL
+REMARK 200 OPTICS : NULL
+REMARK 200
+REMARK 200 DETECTOR TYPE : PIXEL
+REMARK 200 DETECTOR MANUFACTURER : PSI PILATUS 6M
+REMARK 200 INTENSITY-INTEGRATION SOFTWARE : XDS
+REMARK 200 DATA SCALING SOFTWARE : AIMLESS
+REMARK 200
+REMARK 200 NUMBER OF UNIQUE REFLECTIONS : 12894
+REMARK 200 RESOLUTION RANGE HIGH (A) : 2.340
+REMARK 200 RESOLUTION RANGE LOW (A) : 60.730
+REMARK 200 REJECTION CRITERIA (SIGMA(I)) : NULL
+REMARK 200
+REMARK 200 OVERALL.
+REMARK 200 COMPLETENESS FOR RANGE (%) : 99.4
+REMARK 200 DATA REDUNDANCY : 12.30
+REMARK 200 R MERGE (I) : 0.06600
+REMARK 200 R SYM (I) : NULL
+REMARK 200 <I/SIGMA(I)> FOR THE DATA SET : 23.2000
+REMARK 200
+REMARK 200 IN THE HIGHEST RESOLUTION SHELL.
+REMARK 200 HIGHEST RESOLUTION SHELL, RANGE HIGH (A) : 2.34
+REMARK 200 HIGHEST RESOLUTION SHELL, RANGE LOW (A) : 2.40
+REMARK 200 COMPLETENESS FOR SHELL (%) : 98.4
+REMARK 200 DATA REDUNDANCY IN SHELL : 11.80
+REMARK 200 R MERGE FOR SHELL (I) : 0.59800
+REMARK 200 R SYM FOR SHELL (I) : NULL
+REMARK 200 <I/SIGMA(I)> FOR SHELL : 4.200
+REMARK 200
+REMARK 200 DIFFRACTION PROTOCOL: SINGLE WAVELENGTH
+REMARK 200 METHOD USED TO DETERMINE THE STRUCTURE: NULL
+REMARK 200 SOFTWARE USED: PHASER
+REMARK 200 STARTING MODEL: NULL
+REMARK 200
+REMARK 200 REMARK: THIN PLATES, DEEP RED BROWN COLOUR DUE TO 2FE-2S IRON
+REMARK 200 SULPHUR CLUSTER
+REMARK 280
+REMARK 280 CRYSTAL
+REMARK 280 SOLVENT CONTENT, VS (%): 64.33
+REMARK 280 MATTHEWS COEFFICIENT, VM (ANGSTROMS**3/DA): 3.45
+REMARK 280
+REMARK 280 CRYSTALLIZATION CONDITIONS: 0.2 M MGCL2, 0.1 M TRIS, 20 % PEG
+REMARK 280 8000, PH 8.5, VAPOR DIFFUSION, SITTING DROP, TEMPERATURE 294K
+REMARK 290
+REMARK 290 CRYSTALLOGRAPHIC SYMMETRY
+REMARK 290 SYMMETRY OPERATORS FOR SPACE GROUP: P 42 21 2
+REMARK 290
+REMARK 290 SYMOP SYMMETRY
+REMARK 290 NNNMMM OPERATOR
+REMARK 290 1555 X,Y,Z
+REMARK 290 2555 -X,-Y,Z
+REMARK 290 3555 -Y+1/2,X+1/2,Z+1/2
+REMARK 290 4555 Y+1/2,-X+1/2,Z+1/2
+REMARK 290 5555 -X+1/2,Y+1/2,-Z+1/2
+REMARK 290 6555 X+1/2,-Y+1/2,-Z+1/2
+REMARK 290 7555 Y,X,-Z
+REMARK 290 8555 -Y,-X,-Z
+REMARK 290
+REMARK 290 WHERE NNN -> OPERATOR NUMBER
+REMARK 290 MMM -> TRANSLATION VECTOR
+REMARK 290
+REMARK 290 CRYSTALLOGRAPHIC SYMMETRY TRANSFORMATIONS
+REMARK 290 THE FOLLOWING TRANSFORMATIONS OPERATE ON THE ATOM/HETATM
+REMARK 290 RECORDS IN THIS ENTRY TO PRODUCE CRYSTALLOGRAPHICALLY
+REMARK 290 RELATED MOLECULES.
+REMARK 290 SMTRY1 1 1.000000 0.000000 0.000000 0.00000
+REMARK 290 SMTRY2 1 0.000000 1.000000 0.000000 0.00000
+REMARK 290 SMTRY3 1 0.000000 0.000000 1.000000 0.00000
+REMARK 290 SMTRY1 2 -1.000000 0.000000 0.000000 0.00000
+REMARK 290 SMTRY2 2 0.000000 -1.000000 0.000000 0.00000
+REMARK 290 SMTRY3 2 0.000000 0.000000 1.000000 0.00000
+REMARK 290 SMTRY1 3 0.000000 -1.000000 0.000000 30.36500
+REMARK 290 SMTRY2 3 1.000000 0.000000 0.000000 30.36500
+REMARK 290 SMTRY3 3 0.000000 0.000000 1.000000 77.36500
+REMARK 290 SMTRY1 4 0.000000 1.000000 0.000000 30.36500
+REMARK 290 SMTRY2 4 -1.000000 0.000000 0.000000 30.36500
+REMARK 290 SMTRY3 4 0.000000 0.000000 1.000000 77.36500
+REMARK 290 SMTRY1 5 -1.000000 0.000000 0.000000 30.36500
+REMARK 290 SMTRY2 5 0.000000 1.000000 0.000000 30.36500
+REMARK 290 SMTRY3 5 0.000000 0.000000 -1.000000 77.36500
+REMARK 290 SMTRY1 6 1.000000 0.000000 0.000000 30.36500
+REMARK 290 SMTRY2 6 0.000000 -1.000000 0.000000 30.36500
+REMARK 290 SMTRY3 6 0.000000 0.000000 -1.000000 77.36500
+REMARK 290 SMTRY1 7 0.000000 1.000000 0.000000 0.00000
+REMARK 290 SMTRY2 7 1.000000 0.000000 0.000000 0.00000
+REMARK 290 SMTRY3 7 0.000000 0.000000 -1.000000 0.00000
+REMARK 290 SMTRY1 8 0.000000 -1.000000 0.000000 0.00000
+REMARK 290 SMTRY2 8 -1.000000 0.000000 0.000000 0.00000
+REMARK 290 SMTRY3 8 0.000000 0.000000 -1.000000 0.00000
+REMARK 290
+REMARK 290 REMARK: NULL
+REMARK 300
+REMARK 300 BIOMOLECULE: 1, 2
+REMARK 300 SEE REMARK 350 FOR THE AUTHOR PROVIDED AND/OR PROGRAM
+REMARK 300 GENERATED ASSEMBLY INFORMATION FOR THE STRUCTURE IN
+REMARK 300 THIS ENTRY. THE REMARK MAY ALSO PROVIDE INFORMATION ON
+REMARK 300 BURIED SURFACE AREA.
+REMARK 350
+REMARK 350 COORDINATES FOR A COMPLETE MULTIMER REPRESENTING THE KNOWN
+REMARK 350 BIOLOGICALLY SIGNIFICANT OLIGOMERIZATION STATE OF THE
+REMARK 350 MOLECULE CAN BE GENERATED BY APPLYING BIOMT TRANSFORMATIONS
+REMARK 350 GIVEN BELOW. BOTH NON-CRYSTALLOGRAPHIC AND
+REMARK 350 CRYSTALLOGRAPHIC OPERATIONS ARE GIVEN.
+REMARK 350
+REMARK 350 BIOMOLECULE: 1
+REMARK 350 AUTHOR DETERMINED BIOLOGICAL UNIT: MONOMERIC
+REMARK 350 APPLY THE FOLLOWING TO CHAINS: A
+REMARK 350 BIOMT1 1 1.000000 0.000000 0.000000 0.00000
+REMARK 350 BIOMT2 1 0.000000 1.000000 0.000000 0.00000
+REMARK 350 BIOMT3 1 0.000000 0.000000 1.000000 0.00000
+REMARK 350
+REMARK 350 BIOMOLECULE: 2
+REMARK 350 AUTHOR DETERMINED BIOLOGICAL UNIT: MONOMERIC
+REMARK 350 APPLY THE FOLLOWING TO CHAINS: B
+REMARK 350 BIOMT1 1 1.000000 0.000000 0.000000 0.00000
+REMARK 350 BIOMT2 1 0.000000 1.000000 0.000000 0.00000
+REMARK 350 BIOMT3 1 0.000000 0.000000 1.000000 0.00000
+REMARK 375
+REMARK 375 SPECIAL POSITION
+REMARK 375 THE FOLLOWING ATOMS ARE FOUND TO BE WITHIN 0.15 ANGSTROMS
+REMARK 375 OF A SYMMETRY RELATED ATOM AND ARE ASSUMED TO BE ON SPECIAL
+REMARK 375 POSITIONS.
+REMARK 375
+REMARK 375 ATOM RES CSSEQI
+REMARK 375 HOH B 319 LIES ON A SPECIAL POSITION.
+REMARK 465
+REMARK 465 MISSING RESIDUES
+REMARK 465 THE FOLLOWING RESIDUES WERE NOT LOCATED IN THE
+REMARK 465 EXPERIMENT. (M=MODEL NUMBER; RES=RESIDUE NAME; C=CHAIN
+REMARK 465 IDENTIFIER; SSSEQ=SEQUENCE NUMBER; I=INSERTION CODE.)
+REMARK 465
+REMARK 465 M RES C SSSEQI
+REMARK 465 MET A 1
+REMARK 465 GLU A 99
+REMARK 465 HIS A 100
+REMARK 465 HIS A 101
+REMARK 465 HIS A 102
+REMARK 465 HIS A 103
+REMARK 465 HIS A 104
+REMARK 465 HIS A 105
+REMARK 465 MET B 1
+REMARK 465 GLU B 99
+REMARK 465 HIS B 100
+REMARK 465 HIS B 101
+REMARK 465 HIS B 102
+REMARK 465 HIS B 103
+REMARK 465 HIS B 104
+REMARK 465 HIS B 105
+REMARK 470
+REMARK 470 MISSING ATOM
+REMARK 470 THE FOLLOWING RESIDUES HAVE MISSING ATOMS (M=MODEL NUMBER;
+REMARK 470 RES=RESIDUE NAME; C=CHAIN IDENTIFIER; SSEQ=SEQUENCE NUMBER;
+REMARK 470 I=INSERTION CODE):
+REMARK 470 M RES CSSEQI ATOMS
+REMARK 470 LEU A 98 CG CD1 CD2
+REMARK 470 LEU B 98 CG CD1 CD2
+REMARK 500
+REMARK 500 GEOMETRY AND STEREOCHEMISTRY
+REMARK 500 SUBTOPIC: TORSION ANGLES
+REMARK 500
+REMARK 500 TORSION ANGLES OUTSIDE THE EXPECTED RAMACHANDRAN REGIONS:
+REMARK 500 (M=MODEL NUMBER; RES=RESIDUE NAME; C=CHAIN IDENTIFIER;
+REMARK 500 SSEQ=SEQUENCE NUMBER; I=INSERTION CODE).
+REMARK 500
+REMARK 500 STANDARD TABLE:
+REMARK 500 FORMAT:(10X,I3,1X,A3,1X,A1,I4,A1,4X,F7.2,3X,F7.2)
+REMARK 500
+REMARK 500 EXPECTED VALUES: GJ KLEYWEGT AND TA JONES (1996). PHI/PSI-
+REMARK 500 CHOLOGY: RAMACHANDRAN REVISITED. STRUCTURE 4, 1395 - 1400
+REMARK 500
+REMARK 500 M RES CSSEQI PSI PHI
+REMARK 500 SER A 39 -64.23 -146.55
+REMARK 500 MET A 97 -67.17 -99.01
+REMARK 500 SER B 39 -78.49 -140.11
+REMARK 500 SER B 63 -12.80 -148.10
+REMARK 500
+REMARK 500 REMARK: NULL
+REMARK 620
+REMARK 620 METAL COORDINATION
+REMARK 620 (M=MODEL NUMBER; RES=RESIDUE NAME; C=CHAIN IDENTIFIER;
+REMARK 620 SSEQ=SEQUENCE NUMBER; I=INSERTION CODE):
+REMARK 620
+REMARK 620 COORDINATION ANGLES FOR: M RES CSSEQI METAL
+REMARK 620 FES A 201 FE1
+REMARK 620 N RES CSSEQI ATOM
+REMARK 620 1 CYS A 40 SG
+REMARK 620 2 FES A 201 S1 124.8
+REMARK 620 3 FES A 201 S2 100.1 99.4
+REMARK 620 4 CYS A 45 SG 105.3 110.0 117.8
+REMARK 620 N 1 2 3
+REMARK 620
+REMARK 620 COORDINATION ANGLES FOR: M RES CSSEQI METAL
+REMARK 620 FES A 201 FE2
+REMARK 620 N RES CSSEQI ATOM
+REMARK 620 1 CYS A 48 SG
+REMARK 620 2 FES A 201 S1 114.4
+REMARK 620 3 FES A 201 S2 108.9 101.7
+REMARK 620 4 CYS A 78 SG 105.9 122.0 102.7
+REMARK 620 N 1 2 3
+REMARK 620
+REMARK 620 COORDINATION ANGLES FOR: M RES CSSEQI METAL
+REMARK 620 FES B 201 FE1
+REMARK 620 N RES CSSEQI ATOM
+REMARK 620 1 CYS B 40 SG
+REMARK 620 2 FES B 201 S1 119.9
+REMARK 620 3 FES B 201 S2 102.0 97.8
+REMARK 620 4 CYS B 45 SG 109.5 108.1 119.7
+REMARK 620 N 1 2 3
+REMARK 620
+REMARK 620 COORDINATION ANGLES FOR: M RES CSSEQI METAL
+REMARK 620 FES B 201 FE2
+REMARK 620 N RES CSSEQI ATOM
+REMARK 620 1 CYS B 48 SG
+REMARK 620 2 FES B 201 S1 111.1
+REMARK 620 3 FES B 201 S2 115.5 99.1
+REMARK 620 4 CYS B 78 SG 110.9 117.2 102.5
+REMARK 620 N 1 2 3
+REMARK 800
+REMARK 800 SITE
+REMARK 800 SITE_IDENTIFIER: AC1
+REMARK 800 EVIDENCE_CODE: SOFTWARE
+REMARK 800 SITE_DESCRIPTION: binding site for residue FES A 201
+REMARK 800
+REMARK 800 SITE_IDENTIFIER: AC2
+REMARK 800 EVIDENCE_CODE: SOFTWARE
+REMARK 800 SITE_DESCRIPTION: binding site for residue CL A 202
+REMARK 800
+REMARK 800 SITE_IDENTIFIER: AC3
+REMARK 800 EVIDENCE_CODE: SOFTWARE
+REMARK 800 SITE_DESCRIPTION: binding site for residue FES B 201
+REMARK 800
+REMARK 800 SITE_IDENTIFIER: AC4
+REMARK 800 EVIDENCE_CODE: SOFTWARE
+REMARK 800 SITE_DESCRIPTION: binding site for residue CL B 202
+DBREF 4ZHO A 1 94 UNP P16972 FER2_ARATH 52 145
+DBREF 4ZHO B 1 94 UNP P16972 FER2_ARATH 52 145
+SEQADV 4ZHO ALA A 95 UNP P16972 EXPRESSION TAG
+SEQADV 4ZHO ILE A 96 UNP P16972 EXPRESSION TAG
+SEQADV 4ZHO MET A 97 UNP P16972 EXPRESSION TAG
+SEQADV 4ZHO LEU A 98 UNP P16972 EXPRESSION TAG
+SEQADV 4ZHO GLU A 99 UNP P16972 EXPRESSION TAG
+SEQADV 4ZHO HIS A 100 UNP P16972 EXPRESSION TAG
+SEQADV 4ZHO HIS A 101 UNP P16972 EXPRESSION TAG
+SEQADV 4ZHO HIS A 102 UNP P16972 EXPRESSION TAG
+SEQADV 4ZHO HIS A 103 UNP P16972 EXPRESSION TAG
+SEQADV 4ZHO HIS A 104 UNP P16972 EXPRESSION TAG
+SEQADV 4ZHO HIS A 105 UNP P16972 EXPRESSION TAG
+SEQADV 4ZHO ALA B 95 UNP P16972 EXPRESSION TAG
+SEQADV 4ZHO ILE B 96 UNP P16972 EXPRESSION TAG
+SEQADV 4ZHO MET B 97 UNP P16972 EXPRESSION TAG
+SEQADV 4ZHO LEU B 98 UNP P16972 EXPRESSION TAG
+SEQADV 4ZHO GLU B 99 UNP P16972 EXPRESSION TAG
+SEQADV 4ZHO HIS B 100 UNP P16972 EXPRESSION TAG
+SEQADV 4ZHO HIS B 101 UNP P16972 EXPRESSION TAG
+SEQADV 4ZHO HIS B 102 UNP P16972 EXPRESSION TAG
+SEQADV 4ZHO HIS B 103 UNP P16972 EXPRESSION TAG
+SEQADV 4ZHO HIS B 104 UNP P16972 EXPRESSION TAG
+SEQADV 4ZHO HIS B 105 UNP P16972 EXPRESSION TAG
+SEQRES 1 A 105 MET ALA THR TYR LYS VAL LYS PHE ILE THR PRO GLU GLY
+SEQRES 2 A 105 GLU LEU GLU VAL GLU CYS ASP ASP ASP VAL TYR VAL LEU
+SEQRES 3 A 105 ASP ALA ALA GLU GLU ALA GLY ILE ASP LEU PRO TYR SER
+SEQRES 4 A 105 CYS ARG ALA GLY SER CYS SER SER CYS ALA GLY LYS VAL
+SEQRES 5 A 105 VAL SER GLY SER VAL ASP GLN SER ASP GLN SER PHE LEU
+SEQRES 6 A 105 ASP ASP GLU GLN ILE GLY GLU GLY PHE VAL LEU THR CYS
+SEQRES 7 A 105 ALA ALA TYR PRO THR SER ASP VAL THR ILE GLU THR HIS
+SEQRES 8 A 105 LYS GLU GLU ALA ILE MET LEU GLU HIS HIS HIS HIS HIS
+SEQRES 9 A 105 HIS
+SEQRES 1 B 105 MET ALA THR TYR LYS VAL LYS PHE ILE THR PRO GLU GLY
+SEQRES 2 B 105 GLU LEU GLU VAL GLU CYS ASP ASP ASP VAL TYR VAL LEU
+SEQRES 3 B 105 ASP ALA ALA GLU GLU ALA GLY ILE ASP LEU PRO TYR SER
+SEQRES 4 B 105 CYS ARG ALA GLY SER CYS SER SER CYS ALA GLY LYS VAL
+SEQRES 5 B 105 VAL SER GLY SER VAL ASP GLN SER ASP GLN SER PHE LEU
+SEQRES 6 B 105 ASP ASP GLU GLN ILE GLY GLU GLY PHE VAL LEU THR CYS
+SEQRES 7 B 105 ALA ALA TYR PRO THR SER ASP VAL THR ILE GLU THR HIS
+SEQRES 8 B 105 LYS GLU GLU ALA ILE MET LEU GLU HIS HIS HIS HIS HIS
+SEQRES 9 B 105 HIS
+HET FES A 201 4
+HET CL A 202 1
+HET FES B 201 4
+HET CL B 202 1
+HETNAM FES FE2/S2 (INORGANIC) CLUSTER
+HETNAM CL CHLORIDE ION
+FORMUL 3 FES 2(FE2 S2)
+FORMUL 4 CL 2(CL 1-)
+FORMUL 7 HOH *38(H2 O)
+HELIX 1 AA1 TYR A 24 ALA A 32 1 9
+HELIX 2 AA2 ASP A 66 GLU A 72 1 7
+HELIX 3 AA3 CYS A 78 ALA A 80 5 3
+HELIX 4 AA5 TYR B 24 ALA B 32 1 9
+HELIX 5 AA6 ASP B 66 GLU B 72 1 7
+HELIX 6 AA7 CYS B 78 ALA B 80 5 3
+HELIX 7 AA8 LYS B 92 MET B 97 5 6
+SHEET 1 AA1 5 GLU A 14 ASP A 20 0
+SHEET 2 AA1 5 THR A 3 ILE A 9 -1 N PHE A 8 O LEU A 15
+SHEET 3 AA1 5 VAL A 86 GLU A 89 1 O ILE A 88 N LYS A 7
+SHEET 4 AA1 5 ALA A 49 SER A 54 -1 N SER A 54 O THR A 87
+SHEET 5 AA1 5 PHE A 74 LEU A 76 -1 O VAL A 75 N GLY A 50
+SHEET 1 AA2 2 VAL A 57 ASP A 58 0
+SHEET 2 AA2 2 TYR A 81 PRO A 82 -1 O TYR A 81 N ASP A 58
+SHEET 1 AA3 5 GLY B 13 ASP B 20 0
+SHEET 2 AA3 5 THR B 3 THR B 10 -1 N PHE B 8 O LEU B 15
+SHEET 3 AA3 5 VAL B 86 GLU B 89 1 O ILE B 88 N LYS B 7
+SHEET 4 AA3 5 ALA B 49 SER B 54 -1 N LYS B 51 O GLU B 89
+SHEET 5 AA3 5 PHE B 74 LEU B 76 -1 O VAL B 75 N GLY B 50
+SHEET 1 AA4 2 VAL B 57 ASP B 58 0
+SHEET 2 AA4 2 TYR B 81 PRO B 82 -1 O TYR B 81 N ASP B 58
+LINK SG CYS A 40 FE1 FES A 201 1555 1555 2.33
+LINK SG CYS A 45 FE1 FES A 201 1555 1555 2.28
+LINK SG CYS A 48 FE2 FES A 201 1555 1555 2.28
+LINK SG CYS A 78 FE2 FES A 201 1555 1555 2.34
+LINK SG CYS B 40 FE1 FES B 201 1555 1555 2.22
+LINK SG CYS B 45 FE1 FES B 201 1555 1555 2.25
+LINK SG CYS B 48 FE2 FES B 201 1555 1555 2.18
+LINK SG CYS B 78 FE2 FES B 201 1555 1555 2.36
+SITE 1 AC1 8 SER A 39 CYS A 40 ARG A 41 GLY A 43
+SITE 2 AC1 8 SER A 44 CYS A 45 CYS A 48 CYS A 78
+SITE 1 AC2 2 SER A 84 ASP A 85
+SITE 1 AC3 8 SER B 39 CYS B 40 ARG B 41 GLY B 43
+SITE 2 AC3 8 SER B 44 CYS B 45 CYS B 48 CYS B 78
+SITE 1 AC4 2 SER B 84 ASP B 85
+CRYST1 60.730 60.730 154.730 90.00 90.00 90.00 P 42 21 2 16
+ORIGX1 1.000000 0.000000 0.000000 0.00000
+ORIGX2 0.000000 1.000000 0.000000 0.00000
+ORIGX3 0.000000 0.000000 1.000000 0.00000
+SCALE1 0.016466 0.000000 0.000000 0.00000
+SCALE2 0.000000 0.016466 0.000000 0.00000
+SCALE3 0.000000 0.000000 0.006463 0.00000
+ATOM 1 N ALA A 2 -1.257 -15.807 -48.124 1.00 50.77 N
+ANISOU 1 N ALA A 2 7787 5804 5698 -219 1819 -481 N
+ATOM 2 CA ALA A 2 -1.523 -14.339 -48.197 1.00 50.70 C
+ANISOU 2 CA ALA A 2 7568 6034 5660 -183 1548 -344 C
+ATOM 3 C ALA A 2 -1.438 -13.722 -46.830 1.00 45.70 C
+ANISOU 3 C ALA A 2 6785 5347 5230 -97 1396 -189 C
+ATOM 4 O ALA A 2 -1.809 -14.345 -45.825 1.00 44.98 O
+ANISOU 4 O ALA A 2 6732 5134 5221 -136 1414 -240 O
+ATOM 5 CB ALA A 2 -2.903 -14.040 -48.848 1.00 48.96 C
+ANISOU 5 CB ALA A 2 7316 6077 5207 -370 1390 -508 C
+ATOM 6 N THR A 3 -1.069 -12.455 -46.833 1.00 45.54 N
+ANISOU 6 N THR A 3 6600 5431 5271 -1 1249 -16 N
+ATOM 7 CA THR A 3 -0.949 -11.641 -45.631 1.00 47.35 C
+ANISOU 7 CA THR A 3 6681 5636 5674 60 1092 109 C
+ATOM 8 C THR A 3 -1.689 -10.384 -45.941 1.00 43.11 C
+ANISOU 8 C THR A 3 6022 5274 5083 31 915 145 C
+ATOM 9 O THR A 3 -1.531 -9.803 -47.012 1.00 41.92 O
+ANISOU 9 O THR A 3 5843 5236 4848 63 924 210 O
+ATOM 10 CB THR A 3 0.543 -11.321 -45.328 1.00 50.05 C
+ANISOU 10 CB THR A 3 6935 5888 6195 216 1141 301 C
+ATOM 11 OG1 THR A 3 1.229 -12.551 -45.036 1.00 50.95 O
+ANISOU 11 OG1 THR A 3 7151 5846 6362 283 1328 306 O
+ATOM 12 CG2 THR A 3 0.673 -10.438 -44.115 1.00 54.46 C
+ANISOU 12 CG2 THR A 3 7341 6448 6902 242 968 390 C
+ATOM 13 N TYR A 4 -2.484 -9.944 -44.989 1.00 46.99 N
+ANISOU 13 N TYR A 4 6443 5784 5625 -9 776 123 N
+ATOM 14 CA TYR A 4 -3.347 -8.768 -45.177 1.00 48.43 C
+ANISOU 14 CA TYR A 4 6510 6116 5775 -19 632 167 C
+ATOM 15 C TYR A 4 -3.023 -7.694 -44.144 1.00 47.22 C
+ANISOU 15 C TYR A 4 6246 5881 5813 46 540 272 C
+ATOM 16 O TYR A 4 -2.521 -7.988 -43.069 1.00 48.33 O
+ANISOU 16 O TYR A 4 6396 5904 6063 58 537 263 O
+ATOM 17 CB TYR A 4 -4.801 -9.196 -45.059 1.00 47.01 C
+ANISOU 17 CB TYR A 4 6341 6049 5468 -146 570 20 C
+ATOM 18 CG TYR A 4 -5.208 -10.134 -46.157 1.00 43.84 C
+ANISOU 18 CG TYR A 4 6035 5763 4857 -258 645 -122 C
+ATOM 19 CD1 TYR A 4 -5.280 -9.700 -47.461 1.00 48.21 C
+ANISOU 19 CD1 TYR A 4 6559 6515 5243 -243 630 -80 C
+ATOM 20 CD2 TYR A 4 -5.473 -11.470 -45.898 1.00 48.38 C
+ANISOU 20 CD2 TYR A 4 6743 6241 5397 -383 752 -303 C
+ATOM 21 CE1 TYR A 4 -5.629 -10.561 -48.480 1.00 48.93 C
+ANISOU 21 CE1 TYR A 4 6746 6739 5104 -368 694 -244 C
+ATOM 22 CE2 TYR A 4 -5.802 -12.362 -46.923 1.00 48.52 C
+ANISOU 22 CE2 TYR A 4 6868 6342 5221 -522 844 -480 C
+ATOM 23 CZ TYR A 4 -5.914 -11.892 -48.199 1.00 48.26 C
+ANISOU 23 CZ TYR A 4 6798 6543 4992 -526 799 -466 C
+ATOM 24 OH TYR A 4 -6.226 -12.778 -49.220 1.00 52.35 O
+ANISOU 24 OH TYR A 4 7434 7172 5284 -686 885 -675 O
+ATOM 25 N LYS A 5 -3.307 -6.453 -44.489 1.00 47.90 N
+ANISOU 25 N LYS A 5 6234 6036 5930 90 478 373 N
+ATOM 26 CA LYS A 5 -3.126 -5.320 -43.582 1.00 49.46 C
+ANISOU 26 CA LYS A 5 6343 6138 6309 126 414 439 C
+ATOM 27 C LYS A 5 -4.415 -5.114 -42.819 1.00 44.72 C
+ANISOU 27 C LYS A 5 5725 5576 5688 87 334 362 C
+ATOM 28 O LYS A 5 -5.464 -4.904 -43.423 1.00 45.76 O
+ANISOU 28 O LYS A 5 5820 5852 5714 87 308 374 O
+ATOM 29 CB LYS A 5 -2.776 -4.038 -44.357 1.00 51.93 C
+ANISOU 29 CB LYS A 5 6573 6454 6702 205 443 602 C
+ATOM 30 CG LYS A 5 -1.497 -4.126 -45.113 1.00 62.94 C
+ANISOU 30 CG LYS A 5 7967 7811 8137 249 542 698 C
+ATOM 31 CD LYS A 5 -0.351 -4.665 -44.240 1.00 71.74 C
+ANISOU 31 CD LYS A 5 9078 8803 9377 228 553 662 C
+ATOM 32 CE LYS A 5 -0.083 -3.798 -43.025 1.00 78.38 C
+ANISOU 32 CE LYS A 5 9836 9541 10403 192 473 648 C
+ATOM 33 NZ LYS A 5 0.491 -2.513 -43.496 1.00 87.36 N
+ANISOU 33 NZ LYS A 5 10881 10609 11701 215 524 774 N
+ATOM 34 N VAL A 6 -4.356 -5.236 -41.505 1.00 40.33 N
+ANISOU 34 N VAL A 6 5186 4922 5213 58 297 290 N
+ATOM 35 CA VAL A 6 -5.506 -4.978 -40.686 1.00 43.48 C
+ANISOU 35 CA VAL A 6 5572 5340 5608 33 246 224 C
+ATOM 36 C VAL A 6 -5.286 -3.624 -40.015 1.00 44.26 C
+ANISOU 36 C VAL A 6 5616 5334 5865 73 225 265 C
+ATOM 37 O VAL A 6 -4.317 -3.413 -39.286 1.00 45.54 O
+ANISOU 37 O VAL A 6 5782 5395 6125 57 211 245 O
+ATOM 38 CB VAL A 6 -5.704 -6.072 -39.614 1.00 47.03 C
+ANISOU 38 CB VAL A 6 6100 5753 6016 -24 246 110 C
+ATOM 39 CG1 VAL A 6 -6.982 -5.808 -38.849 1.00 45.34 C
+ANISOU 39 CG1 VAL A 6 5866 5571 5789 -46 216 50 C
+ATOM 40 CG2 VAL A 6 -5.764 -7.451 -40.254 1.00 46.02 C
+ANISOU 40 CG2 VAL A 6 6052 5664 5769 -78 315 53 C
+ATOM 41 N LYS A 7 -6.163 -2.682 -40.330 1.00 45.38 N
+ANISOU 41 N LYS A 7 5700 5508 6034 123 235 327 N
+ATOM 42 CA LYS A 7 -6.143 -1.373 -39.740 1.00 45.98 C
+ANISOU 42 CA LYS A 7 5748 5450 6273 160 263 351 C
+ATOM 43 C LYS A 7 -7.143 -1.363 -38.592 1.00 47.81 C
+ANISOU 43 C LYS A 7 6003 5668 6491 143 248 245 C
+ATOM 44 O LYS A 7 -8.347 -1.536 -38.787 1.00 51.78 O
+ANISOU 44 O LYS A 7 6468 6287 6918 173 249 263 O
+ATOM 45 CB LYS A 7 -6.506 -0.347 -40.788 1.00 48.29 C
+ANISOU 45 CB LYS A 7 5968 5763 6617 264 329 520 C
+ATOM 46 CG LYS A 7 -6.637 1.070 -40.268 1.00 58.39 C
+ANISOU 46 CG LYS A 7 7234 6859 8090 316 413 556 C
+ATOM 47 CD LYS A 7 -6.631 2.026 -41.447 1.00 68.64 C
+ANISOU 47 CD LYS A 7 8467 8148 9461 441 515 776 C
+ATOM 48 CE LYS A 7 -6.930 3.448 -41.018 1.00 82.52 C
+ANISOU 48 CE LYS A 7 10225 9693 11435 515 651 833 C
+ATOM 49 NZ LYS A 7 -6.213 4.399 -41.926 1.00 90.34 N
+ANISOU 49 NZ LYS A 7 11188 10561 12575 587 785 1022 N
+ATOM 50 N PHE A 8 -6.640 -1.148 -37.392 1.00 43.94 N
+ANISOU 50 N PHE A 8 5567 5061 6068 93 233 136 N
+ATOM 51 CA PHE A 8 -7.513 -1.002 -36.238 1.00 50.30 C
+ANISOU 51 CA PHE A 8 6412 5840 6859 87 244 34 C
+ATOM 52 C PHE A 8 -7.808 0.440 -35.906 1.00 44.05 C
+ANISOU 52 C PHE A 8 5618 4900 6218 131 331 33 C
+ATOM 53 O PHE A 8 -6.905 1.228 -35.663 1.00 48.85 O
+ANISOU 53 O PHE A 8 6245 5366 6948 88 353 -5 O
+ATOM 54 CB PHE A 8 -6.843 -1.646 -35.018 1.00 45.89 C
+ANISOU 54 CB PHE A 8 5927 5267 6239 10 184 -93 C
+ATOM 55 CG PHE A 8 -6.679 -3.122 -35.144 1.00 46.40 C
+ANISOU 55 CG PHE A 8 6019 5437 6174 -10 148 -85 C
+ATOM 56 CD1 PHE A 8 -7.769 -3.967 -35.038 1.00 48.26 C
+ANISOU 56 CD1 PHE A 8 6277 5749 6311 -14 173 -106 C
+ATOM 57 CD2 PHE A 8 -5.438 -3.668 -35.354 1.00 44.91 C
+ANISOU 57 CD2 PHE A 8 5828 5253 5981 -27 113 -54 C
+ATOM 58 CE1 PHE A 8 -7.601 -5.339 -35.131 1.00 47.89 C
+ANISOU 58 CE1 PHE A 8 6276 5748 6170 -46 182 -111 C
+ATOM 59 CE2 PHE A 8 -5.279 -5.027 -35.445 1.00 45.32 C
+ANISOU 59 CE2 PHE A 8 5923 5360 5935 -28 125 -39 C
+ATOM 60 CZ PHE A 8 -6.356 -5.857 -35.342 1.00 47.01 C
+ANISOU 60 CZ PHE A 8 6184 5615 6059 -43 168 -74 C
+ATOM 61 N ILE A 9 -9.069 0.763 -35.795 1.00 45.19 N
+ANISOU 61 N ILE A 9 5739 5067 6363 208 395 63 N
+ATOM 62 CA ILE A 9 -9.459 2.100 -35.309 1.00 51.68 C
+ANISOU 62 CA ILE A 9 6584 5712 7339 270 525 51 C
+ATOM 63 C ILE A 9 -9.826 1.880 -33.879 1.00 50.92 C
+ANISOU 63 C ILE A 9 6580 5587 7179 217 529 -126 C
+ATOM 64 O ILE A 9 -10.824 1.229 -33.599 1.00 53.51 O
+ANISOU 64 O ILE A 9 6889 6036 7407 248 527 -124 O
+ATOM 65 CB ILE A 9 -10.635 2.697 -36.124 1.00 55.53 C
+ANISOU 65 CB ILE A 9 6967 6250 7879 433 624 240 C
+ATOM 66 CG1 ILE A 9 -10.204 2.918 -37.592 1.00 55.29 C
+ANISOU 66 CG1 ILE A 9 6852 6282 7873 497 619 438 C
+ATOM 67 CG2 ILE A 9 -11.137 4.018 -35.502 1.00 55.96 C
+ANISOU 67 CG2 ILE A 9 7065 6086 8109 523 808 232 C
+ATOM 68 CD1 ILE A 9 -11.385 2.981 -38.527 1.00 58.25 C
+ANISOU 68 CD1 ILE A 9 7085 6859 8188 645 639 641 C
+ATOM 69 N THR A 10 -8.967 2.329 -32.980 1.00 50.67 N
+ANISOU 69 N THR A 10 6641 5425 7186 121 526 -284 N
+ATOM 70 CA THR A 10 -9.185 2.107 -31.561 1.00 51.69 C
+ANISOU 70 CA THR A 10 6873 5558 7208 65 520 -464 C
+ATOM 71 C THR A 10 -9.612 3.432 -30.915 1.00 50.65 C
+ANISOU 71 C THR A 10 6822 5218 7204 89 689 -568 C
+ATOM 72 O THR A 10 -9.544 4.466 -31.525 1.00 57.26 O
+ANISOU 72 O THR A 10 7639 5887 8228 134 806 -501 O
+ATOM 73 CB THR A 10 -7.930 1.531 -30.864 1.00 50.80 C
+ANISOU 73 CB THR A 10 6804 5512 6986 -68 378 -588 C
+ATOM 74 OG1 THR A 10 -6.968 2.554 -30.671 1.00 53.43 O
+ANISOU 74 OG1 THR A 10 7157 5704 7440 -168 390 -696 O
+ATOM 75 CG2 THR A 10 -7.278 0.462 -31.693 1.00 50.38 C
+ANISOU 75 CG2 THR A 10 6674 5593 6874 -73 264 -466 C
+ATOM 76 N PRO A 11 -10.106 3.393 -29.679 1.00 56.03 N
+ANISOU 76 N PRO A 11 7607 5897 7785 72 733 -722 N
+ATOM 77 CA PRO A 11 -10.427 4.652 -28.979 1.00 58.93 C
+ANISOU 77 CA PRO A 11 8085 6039 8264 79 922 -863 C
+ATOM 78 C PRO A 11 -9.259 5.590 -28.772 1.00 63.22 C
+ANISOU 78 C PRO A 11 8697 6403 8918 -73 935 -1031 C
+ATOM 79 O PRO A 11 -9.508 6.756 -28.521 1.00 69.60 O
+ANISOU 79 O PRO A 11 9594 6966 9884 -65 1137 -1123 O
+ATOM 80 CB PRO A 11 -10.886 4.178 -27.593 1.00 59.38 C
+ANISOU 80 CB PRO A 11 8256 6185 8120 51 924 -1030 C
+ATOM 81 CG PRO A 11 -11.306 2.750 -27.777 1.00 55.35 C
+ANISOU 81 CG PRO A 11 7663 5915 7451 96 802 -896 C
+ATOM 82 CD PRO A 11 -10.443 2.207 -28.868 1.00 52.67 C
+ANISOU 82 CD PRO A 11 7215 5657 7140 56 649 -769 C
+ATOM 83 N GLU A 12 -8.030 5.041 -28.776 1.00 70.08 N
+ANISOU 83 N GLU A 12 9526 7398 9704 -217 738 -1080 N
+ATOM 84 CA GLU A 12 -6.732 5.771 -28.699 1.00 69.59 C
+ANISOU 84 CA GLU A 12 9470 7225 9747 -402 705 -1227 C
+ATOM 85 C GLU A 12 -6.252 6.249 -30.096 1.00 71.32 C
+ANISOU 85 C GLU A 12 9578 7319 10199 -369 757 -1033 C
+ATOM 86 O GLU A 12 -5.575 7.279 -30.200 1.00 82.47 O
+ANISOU 86 O GLU A 12 11009 8520 11805 -484 854 -1123 O
+ATOM 87 CB GLU A 12 -5.618 4.877 -28.105 1.00 80.51 C
+ANISOU 87 CB GLU A 12 10809 8855 10925 -546 460 -1320 C
+ATOM 88 CG GLU A 12 -5.569 4.624 -26.578 1.00 89.15 C
+ANISOU 88 CG GLU A 12 12010 10093 11769 -643 381 -1555 C
+ATOM 89 CD GLU A 12 -4.271 3.871 -26.137 1.00 96.47 C
+ANISOU 89 CD GLU A 12 12846 11289 12519 -771 133 -1597 C
+ATOM 90 OE1 GLU A 12 -3.440 4.458 -25.401 1.00 86.42 O
+ANISOU 90 OE1 GLU A 12 11584 10049 11202 -968 64 -1827 O
+ATOM 91 OE2 GLU A 12 -4.044 2.692 -26.542 1.00 87.89 O
+ANISOU 91 OE2 GLU A 12 11665 10388 11340 -678 12 -1398 O
+ATOM 92 N GLY A 13 -6.566 5.500 -31.160 1.00 63.49 N
+ANISOU 92 N GLY A 13 8479 6460 9184 -227 703 -780 N
+ATOM 93 CA GLY A 13 -6.219 5.913 -32.504 1.00 59.26 C
+ANISOU 93 CA GLY A 13 7850 5841 8826 -167 764 -575 C
+ATOM 94 C GLY A 13 -6.111 4.770 -33.479 1.00 56.21 C
+ANISOU 94 C GLY A 13 7353 5681 8322 -92 628 -378 C
+ATOM 95 O GLY A 13 -6.534 3.652 -33.197 1.00 53.58 O
+ANISOU 95 O GLY A 13 7018 5544 7795 -65 517 -379 O
+ATOM 96 N GLU A 14 -5.519 5.057 -34.631 1.00 54.33 N
+ANISOU 96 N GLU A 14 7036 5399 8206 -65 661 -215 N
+ATOM 97 CA GLU A 14 -5.492 4.115 -35.751 1.00 60.06 C
+ANISOU 97 CA GLU A 14 7674 6319 8826 19 577 -23 C
+ATOM 98 C GLU A 14 -4.126 3.540 -35.940 1.00 51.22 C
+ANISOU 98 C GLU A 14 6504 5271 7684 -88 464 -38 C
+ATOM 99 O GLU A 14 -3.198 4.277 -36.050 1.00 52.79 O
+ANISOU 99 O GLU A 14 6674 5338 8045 -172 512 -55 O
+ATOM 100 CB GLU A 14 -5.953 4.814 -37.053 1.00 67.15 C
+ANISOU 100 CB GLU A 14 8513 7162 9837 174 715 218 C
+ATOM 101 CG GLU A 14 -7.367 5.360 -36.842 1.00 82.24 C
+ANISOU 101 CG GLU A 14 10442 9031 11772 314 834 268 C
+ATOM 102 CD GLU A 14 -7.938 6.250 -37.944 1.00 92.51 C
+ANISOU 102 CD GLU A 14 11677 10275 13196 506 998 534 C
+ATOM 103 OE1 GLU A 14 -7.274 6.424 -38.992 1.00104.38 O
+ANISOU 103 OE1 GLU A 14 13129 11783 14748 536 1022 696 O
+ATOM 104 OE2 GLU A 14 -9.080 6.772 -37.742 1.00 86.19 O
+ANISOU 104 OE2 GLU A 14 10870 9437 12438 645 1116 601 O
+ATOM 105 N LEU A 15 -4.066 2.220 -36.076 1.00 51.18 N
+ANISOU 105 N LEU A 15 6481 5467 7497 -72 343 -11 N
+ATOM 106 CA LEU A 15 -2.856 1.402 -36.095 1.00 54.47 C
+ANISOU 106 CA LEU A 15 6850 5982 7861 -141 239 -15 C
+ATOM 107 C LEU A 15 -3.099 0.276 -37.078 1.00 53.30 C
+ANISOU 107 C LEU A 15 6690 5980 7581 -52 221 115 C
+ATOM 108 O LEU A 15 -4.183 -0.290 -37.098 1.00 48.80 O
+ANISOU 108 O LEU A 15 6160 5493 6889 1 217 115 O
+ATOM 109 CB LEU A 15 -2.708 0.632 -34.773 1.00 53.82 C
+ANISOU 109 CB LEU A 15 6808 6004 7634 -208 122 -164 C
+ATOM 110 CG LEU A 15 -2.570 1.415 -33.509 1.00 64.22 C
+ANISOU 110 CG LEU A 15 8165 7251 8981 -319 102 -355 C
+ATOM 111 CD1 LEU A 15 -2.755 0.471 -32.348 1.00 68.91 C
+ANISOU 111 CD1 LEU A 15 8813 8000 9367 -328 0 -448 C
+ATOM 112 CD2 LEU A 15 -1.203 2.057 -33.474 1.00 66.88 C
+ANISOU 112 CD2 LEU A 15 8412 7542 9455 -454 71 -403 C
+ATOM 113 N GLU A 16 -2.062 -0.144 -37.776 1.00 49.83 N
+ANISOU 113 N GLU A 16 6195 5579 7157 -55 214 200 N
+ATOM 114 CA GLU A 16 -2.191 -1.180 -38.784 1.00 52.00 C
+ANISOU 114 CA GLU A 16 6480 5971 7306 14 227 299 C
+ATOM 115 C GLU A 16 -1.165 -2.260 -38.528 1.00 44.99 C
+ANISOU 115 C GLU A 16 5581 5146 6365 -5 183 291 C
+ATOM 116 O GLU A 16 -0.027 -1.953 -38.247 1.00 41.15 O
+ANISOU 116 O GLU A 16 5017 4632 5983 -49 162 300 O
+ATOM 117 CB GLU A 16 -1.924 -0.519 -40.111 1.00 56.47 C
+ANISOU 117 CB GLU A 16 6996 6506 7952 73 320 454 C
+ATOM 118 CG GLU A 16 -2.598 -1.111 -41.299 1.00 64.79 C
+ANISOU 118 CG GLU A 16 8072 7693 8851 152 352 546 C
+ATOM 119 CD GLU A 16 -2.299 -0.276 -42.542 1.00 77.28 C
+ANISOU 119 CD GLU A 16 9604 9258 10500 229 453 725 C
+ATOM 120 OE1 GLU A 16 -1.932 -0.864 -43.609 1.00 78.06 O
+ANISOU 120 OE1 GLU A 16 9708 9456 10491 269 492 807 O
+ATOM 121 OE2 GLU A 16 -2.392 0.977 -42.427 1.00 67.17 O
+ANISOU 121 OE2 GLU A 16 8290 7846 9385 251 517 784 O
+ATOM 122 N VAL A 17 -1.538 -3.520 -38.672 1.00 44.95 N
+ANISOU 122 N VAL A 17 5642 5223 6212 27 187 284 N
+ATOM 123 CA VAL A 17 -0.578 -4.609 -38.466 1.00 43.94 C
+ANISOU 123 CA VAL A 17 5513 5132 6048 46 189 310 C
+ATOM 124 C VAL A 17 -0.754 -5.509 -39.643 1.00 44.55 C
+ANISOU 124 C VAL A 17 5652 5239 6033 92 285 360 C
+ATOM 125 O VAL A 17 -1.732 -5.387 -40.374 1.00 43.66 O
+ANISOU 125 O VAL A 17 5577 5162 5847 87 308 346 O
+ATOM 126 CB VAL A 17 -0.860 -5.372 -37.157 1.00 48.00 C
+ANISOU 126 CB VAL A 17 6081 5682 6472 37 134 232 C
+ATOM 127 CG1 VAL A 17 -0.799 -4.395 -35.985 1.00 48.79 C
+ANISOU 127 CG1 VAL A 17 6138 5776 6622 -25 37 146 C
+ATOM 128 CG2 VAL A 17 -2.229 -6.014 -37.217 1.00 46.07 C
+ANISOU 128 CG2 VAL A 17 5942 5449 6111 34 172 170 C
+ATOM 129 N GLU A 18 0.203 -6.379 -39.858 1.00 39.17 N
+ANISOU 129 N GLU A 18 4974 4558 5351 139 347 420 N
+ATOM 130 CA GLU A 18 0.027 -7.446 -40.834 1.00 45.65 C
+ANISOU 130 CA GLU A 18 5895 5385 6065 169 468 423 C
+ATOM 131 C GLU A 18 -0.549 -8.660 -40.120 1.00 42.91 C
+ANISOU 131 C GLU A 18 5658 5017 5628 157 500 342 C
+ATOM 132 O GLU A 18 -0.225 -8.908 -38.983 1.00 50.61 O
+ANISOU 132 O GLU A 18 6614 5981 6632 182 459 356 O
+ATOM 133 CB GLU A 18 1.373 -7.869 -41.404 1.00 49.05 C
+ANISOU 133 CB GLU A 18 6290 5791 6555 246 574 536 C
+ATOM 134 CG GLU A 18 1.849 -7.008 -42.535 1.00 63.96 C
+ANISOU 134 CG GLU A 18 8110 7691 8497 264 618 626 C
+ATOM 135 CD GLU A 18 3.316 -7.261 -42.867 1.00 75.06 C
+ANISOU 135 CD GLU A 18 9436 9075 10006 344 719 757 C
+ATOM 136 OE1 GLU A 18 3.833 -8.337 -42.508 1.00 68.87 O
+ANISOU 136 OE1 GLU A 18 8682 8270 9214 408 790 779 O
+ATOM 137 OE2 GLU A 18 3.953 -6.347 -43.437 1.00 86.26 O
+ANISOU 137 OE2 GLU A 18 10749 10492 11532 351 741 855 O
+ATOM 138 N CYS A 19 -1.403 -9.397 -40.824 1.00 42.18 N
+ANISOU 138 N CYS A 19 5675 4930 5420 110 580 258 N
+ATOM 139 CA CYS A 19 -2.100 -10.522 -40.319 1.00 42.40 C
+ANISOU 139 CA CYS A 19 5816 4913 5379 67 646 167 C
+ATOM 140 C CYS A 19 -2.196 -11.521 -41.439 1.00 43.87 C
+ANISOU 140 C CYS A 19 6123 5068 5477 29 804 99 C
+ATOM 141 O CYS A 19 -2.743 -11.212 -42.516 1.00 43.45 O
+ANISOU 141 O CYS A 19 6070 5112 5326 -37 790 39 O
+ATOM 142 CB CYS A 19 -3.524 -10.140 -39.826 1.00 45.74 C
+ANISOU 142 CB CYS A 19 6229 5397 5751 -23 551 67 C
+ATOM 143 SG CYS A 19 -4.342 -11.539 -39.028 1.00 48.02 S
+ANISOU 143 SG CYS A 19 6646 5607 5990 -86 658 -31 S
+ATOM 144 N ASP A 20 -1.642 -12.721 -41.204 1.00 45.23 N
+ANISOU 144 N ASP A 20 6401 5109 5674 79 970 112 N
+ATOM 145 CA ASP A 20 -1.719 -13.795 -42.164 1.00 47.07 C
+ANISOU 145 CA ASP A 20 6786 5262 5833 28 1168 13 C
+ATOM 146 C ASP A 20 -3.181 -14.220 -42.331 1.00 49.54 C
+ANISOU 146 C ASP A 20 7175 5613 6035 -157 1166 -185 C
+ATOM 147 O ASP A 20 -4.027 -14.046 -41.400 1.00 46.05 O
+ANISOU 147 O ASP A 20 6690 5197 5609 -209 1069 -212 O
+ATOM 148 CB ASP A 20 -0.895 -14.979 -41.694 1.00 49.71 C
+ANISOU 148 CB ASP A 20 7224 5411 6252 141 1380 87 C
+ATOM 149 CG ASP A 20 0.620 -14.723 -41.766 1.00 64.33 C
+ANISOU 149 CG ASP A 20 8980 7254 8207 325 1414 288 C
+ATOM 150 OD1 ASP A 20 1.122 -14.017 -42.690 1.00 70.08 O
+ANISOU 150 OD1 ASP A 20 9639 8062 8926 341 1382 324 O
+ATOM 151 OD2 ASP A 20 1.349 -15.271 -40.906 1.00 70.59 O
+ANISOU 151 OD2 ASP A 20 9755 7971 9092 465 1489 432 O
+ATOM 152 N ASP A 21 -3.481 -14.806 -43.487 1.00 48.95 N
+ANISOU 152 N ASP A 21 7206 5550 5840 -269 1280 -332 N
+ATOM 153 CA ASP A 21 -4.886 -15.213 -43.792 1.00 52.07 C
+ANISOU 153 CA ASP A 21 7641 6029 6111 -489 1264 -547 C
+ATOM 154 C ASP A 21 -5.466 -16.364 -42.961 1.00 52.45 C
+ANISOU 154 C ASP A 21 7805 5898 6224 -586 1412 -652 C
+ATOM 155 O ASP A 21 -6.664 -16.621 -43.076 1.00 52.58 O
+ANISOU 155 O ASP A 21 7815 5996 6165 -785 1384 -823 O
+ATOM 156 CB ASP A 21 -5.080 -15.591 -45.251 1.00 52.20 C
+ANISOU 156 CB ASP A 21 7744 6142 5948 -620 1342 -716 C
+ATOM 157 CG ASP A 21 -4.192 -16.744 -45.675 1.00 54.79 C
+ANISOU 157 CG ASP A 21 8277 6240 6300 -591 1630 -772 C
+ATOM 158 OD1 ASP A 21 -3.555 -17.399 -44.833 1.00 60.00 O
+ANISOU 158 OD1 ASP A 21 9012 6660 7124 -475 1787 -678 O
+ATOM 159 OD2 ASP A 21 -4.087 -16.978 -46.873 1.00 66.22 O
+ANISOU 159 OD2 ASP A 21 9812 7754 7595 -664 1713 -895 O
+ATOM 160 N ASP A 22 -4.630 -17.059 -42.198 1.00 51.20 N
+ANISOU 160 N ASP A 22 7738 5513 6200 -447 1580 -538 N
+ATOM 161 CA ASP A 22 -5.098 -18.073 -41.256 1.00 62.00 C
+ANISOU 161 CA ASP A 22 9213 6691 7651 -492 1741 -573 C
+ATOM 162 C ASP A 22 -4.625 -17.744 -39.835 1.00 59.08 C
+ANISOU 162 C ASP A 22 8764 6294 7388 -296 1668 -346 C
+ATOM 163 O ASP A 22 -4.377 -18.629 -39.062 1.00 56.04 O
+ANISOU 163 O ASP A 22 8478 5724 7088 -214 1851 -264 O
+ATOM 164 CB ASP A 22 -4.624 -19.475 -41.714 1.00 71.33 C
+ANISOU 164 CB ASP A 22 10621 7602 8879 -509 2084 -652 C
+ATOM 165 CG ASP A 22 -3.093 -19.576 -41.838 1.00 78.00 C
+ANISOU 165 CG ASP A 22 11493 8340 9802 -254 2204 -448 C
+ATOM 166 OD1 ASP A 22 -2.396 -18.536 -41.681 1.00 74.86 O
+ANISOU 166 OD1 ASP A 22 10926 8102 9414 -102 2002 -272 O
+ATOM 167 OD2 ASP A 22 -2.585 -20.697 -42.122 1.00 91.53 O
+ANISOU 167 OD2 ASP A 22 13392 9804 11580 -212 2520 -469 O
+ATOM 168 N VAL A 23 -4.476 -16.441 -39.535 1.00 58.45 N
+ANISOU 168 N VAL A 23 8509 6406 7294 -222 1411 -246 N
+ATOM 169 CA VAL A 23 -4.282 -15.937 -38.191 1.00 51.17 C
+ANISOU 169 CA VAL A 23 7497 5521 6421 -98 1292 -96 C
+ATOM 170 C VAL A 23 -5.446 -15.027 -37.852 1.00 51.90 C
+ANISOU 170 C VAL A 23 7486 5767 6465 -205 1102 -177 C
+ATOM 171 O VAL A 23 -5.900 -14.243 -38.695 1.00 52.44 O
+ANISOU 171 O VAL A 23 7471 5973 6479 -287 979 -252 O
+ATOM 172 CB VAL A 23 -2.914 -15.295 -38.008 1.00 53.75 C
+ANISOU 172 CB VAL A 23 7721 5902 6798 84 1203 86 C
+ATOM 173 CG1 VAL A 23 -2.782 -14.588 -36.643 1.00 51.64 C
+ANISOU 173 CG1 VAL A 23 7345 5733 6542 168 1034 192 C
+ATOM 174 CG2 VAL A 23 -1.872 -16.402 -38.166 1.00 52.89 C
+ANISOU 174 CG2 VAL A 23 7712 5629 6754 219 1438 196 C
+ATOM 175 N TYR A 24 -6.020 -15.271 -36.669 1.00 49.92 N
+ANISOU 175 N TYR A 24 7252 5485 6229 -201 1118 -157 N
+ATOM 176 CA TYR A 24 -7.105 -14.448 -36.120 1.00 49.53 C
+ANISOU 176 CA TYR A 24 7107 5561 6149 -269 973 -210 C
+ATOM 177 C TYR A 24 -6.598 -13.062 -35.859 1.00 47.90 C
+ANISOU 177 C TYR A 24 6775 5477 5946 -174 771 -133 C
+ATOM 178 O TYR A 24 -5.530 -12.835 -35.330 1.00 50.41 O
+ANISOU 178 O TYR A 24 7074 5788 6289 -48 730 -19 O
+ATOM 179 CB TYR A 24 -7.664 -14.995 -34.792 1.00 53.15 C
+ANISOU 179 CB TYR A 24 7622 5953 6617 -252 1058 -177 C
+ATOM 180 CG TYR A 24 -8.368 -16.349 -34.905 1.00 54.34 C
+ANISOU 180 CG TYR A 24 7898 5950 6796 -378 1291 -263 C
+ATOM 181 CD1 TYR A 24 -9.369 -16.572 -35.863 1.00 61.64 C
+ANISOU 181 CD1 TYR A 24 8804 6911 7703 -595 1316 -450 C
+ATOM 182 CD2 TYR A 24 -8.040 -17.385 -34.061 1.00 58.06 C
+ANISOU 182 CD2 TYR A 24 8497 6251 7312 -288 1491 -157 C
+ATOM 183 CE1 TYR A 24 -10.013 -17.808 -35.976 1.00 67.82 C
+ANISOU 183 CE1 TYR A 24 9699 7540 8526 -757 1542 -565 C
+ATOM 184 CE2 TYR A 24 -8.691 -18.634 -34.147 1.00 67.21 C
+ANISOU 184 CE2 TYR A 24 9786 7220 8531 -418 1749 -239 C
+ATOM 185 CZ TYR A 24 -9.672 -18.847 -35.099 1.00 67.30 C
+ANISOU 185 CZ TYR A 24 9783 7246 8539 -670 1777 -462 C
+ATOM 186 OH TYR A 24 -10.304 -20.070 -35.167 1.00 63.80 O
+ANISOU 186 OH TYR A 24 9466 6605 8170 -838 2041 -574 O
+ATOM 187 N VAL A 25 -7.413 -12.132 -36.241 1.00 46.10 N
+ANISOU 187 N VAL A 25 6451 5365 5699 -242 655 -197 N
+ATOM 188 CA VAL A 25 -7.117 -10.720 -36.104 1.00 50.13 C
+ANISOU 188 CA VAL A 25 6853 5957 6237 -176 500 -147 C
+ATOM 189 C VAL A 25 -6.622 -10.284 -34.725 1.00 49.08 C
+ANISOU 189 C VAL A 25 6716 5810 6120 -88 441 -91 C
+ATOM 190 O VAL A 25 -5.602 -9.548 -34.601 1.00 48.80 O
+ANISOU 190 O VAL A 25 6626 5791 6124 -25 355 -35 O
+ATOM 191 CB VAL A 25 -8.407 -10.000 -36.511 1.00 51.95 C
+ANISOU 191 CB VAL A 25 6992 6297 6447 -248 438 -209 C
+ATOM 192 CG1 VAL A 25 -8.482 -8.654 -35.889 1.00 65.37 C
+ANISOU 192 CG1 VAL A 25 8616 8025 8196 -180 340 -173 C
+ATOM 193 CG2 VAL A 25 -8.427 -9.935 -38.033 1.00 52.86 C
+ANISOU 193 CG2 VAL A 25 7066 6496 6519 -296 427 -223 C
+ATOM 194 N LEU A 26 -7.301 -10.753 -33.681 1.00 50.45 N
+ANISOU 194 N LEU A 26 6944 5968 6256 -94 493 -112 N
+ATOM 195 CA LEU A 26 -6.902 -10.450 -32.290 1.00 47.33 C
+ANISOU 195 CA LEU A 26 6562 5597 5822 -14 443 -70 C
+ATOM 196 C LEU A 26 -5.498 -10.894 -32.035 1.00 47.06 C
+ANISOU 196 C LEU A 26 6537 5561 5781 82 436 39 C
+ATOM 197 O LEU A 26 -4.721 -10.194 -31.377 1.00 55.96 O
+ANISOU 197 O LEU A 26 7607 6768 6888 128 318 66 O
+ATOM 198 CB LEU A 26 -7.807 -11.200 -31.306 1.00 53.55 C
+ANISOU 198 CB LEU A 26 7430 6361 6552 -20 551 -79 C
+ATOM 199 CG LEU A 26 -7.510 -11.161 -29.801 1.00 55.13 C
+ANISOU 199 CG LEU A 26 7674 6613 6658 70 531 -26 C
+ATOM 200 CD1 LEU A 26 -7.326 -9.720 -29.325 1.00 55.80 C
+ANISOU 200 CD1 LEU A 26 7695 6785 6722 71 376 -95 C
+ATOM 201 CD2 LEU A 26 -8.666 -11.852 -29.032 1.00 61.83 C
+ANISOU 201 CD2 LEU A 26 8600 7428 7463 52 674 -33 C
+ATOM 202 N ASP A 27 -5.136 -12.069 -32.524 1.00 48.10 N
+ANISOU 202 N ASP A 27 6734 5609 5931 111 571 103 N
+ATOM 203 CA ASP A 27 -3.762 -12.587 -32.305 1.00 48.67 C
+ANISOU 203 CA ASP A 27 6797 5686 6010 241 594 251 C
+ATOM 204 C ASP A 27 -2.701 -11.814 -33.061 1.00 52.00 C
+ANISOU 204 C ASP A 27 7102 6157 6495 255 488 280 C
+ATOM 205 O ASP A 27 -1.619 -11.648 -32.546 1.00 53.84 O
+ANISOU 205 O ASP A 27 7252 6477 6725 342 414 382 O
+ATOM 206 CB ASP A 27 -3.670 -14.036 -32.649 1.00 52.61 C
+ANISOU 206 CB ASP A 27 7412 6040 6537 286 816 319 C
+ATOM 207 CG ASP A 27 -4.541 -14.887 -31.735 1.00 63.74 C
+ANISOU 207 CG ASP A 27 8934 7380 7902 289 954 332 C
+ATOM 208 OD1 ASP A 27 -4.580 -14.630 -30.517 1.00 77.44 O
+ANISOU 208 OD1 ASP A 27 10653 9216 9555 357 885 392 O
+ATOM 209 OD2 ASP A 27 -5.228 -15.780 -32.232 1.00 66.17 O
+ANISOU 209 OD2 ASP A 27 9347 7539 8253 206 1139 268 O
+ATOM 210 N ALA A 28 -3.001 -11.313 -34.254 1.00 45.81 N
+ANISOU 210 N ALA A 28 6297 5346 5763 172 479 200 N
+ATOM 211 CA ALA A 28 -2.052 -10.414 -34.921 1.00 45.27 C
+ANISOU 211 CA ALA A 28 6113 5321 5765 182 389 237 C
+ATOM 212 C ALA A 28 -1.874 -9.098 -34.113 1.00 46.76 C
+ANISOU 212 C ALA A 28 6200 5596 5968 152 219 201 C
+ATOM 213 O ALA A 28 -0.782 -8.604 -33.981 1.00 48.55 O
+ANISOU 213 O ALA A 28 6321 5880 6246 174 142 256 O
+ATOM 214 CB ALA A 28 -2.542 -10.096 -36.327 1.00 48.41 C
+ANISOU 214 CB ALA A 28 6517 5691 6185 111 423 175 C
+ATOM 215 N ALA A 29 -2.956 -8.547 -33.566 1.00 46.59 N
+ANISOU 215 N ALA A 29 6211 5582 5908 92 177 97 N
+ATOM 216 CA ALA A 29 -2.882 -7.367 -32.726 1.00 45.37 C
+ANISOU 216 CA ALA A 29 6001 5476 5760 54 58 28 C
+ATOM 217 C ALA A 29 -2.026 -7.590 -31.506 1.00 45.22 C
+ANISOU 217 C ALA A 29 5953 5566 5662 94 -18 63 C
+ATOM 218 O ALA A 29 -1.157 -6.760 -31.212 1.00 50.70 O
+ANISOU 218 O ALA A 29 6546 6327 6390 54 -129 39 O
+ATOM 219 CB ALA A 29 -4.268 -6.959 -32.299 1.00 45.68 C
+ANISOU 219 CB ALA A 29 6100 5492 5763 13 76 -74 C
+ATOM 220 N GLU A 30 -2.244 -8.704 -30.827 1.00 46.60 N
+ANISOU 220 N GLU A 30 6205 5769 5730 169 45 128 N
+ATOM 221 CA GLU A 30 -1.476 -9.042 -29.636 1.00 54.76 C
+ANISOU 221 CA GLU A 30 7206 6952 6646 243 -23 204 C
+ATOM 222 C GLU A 30 -0.050 -9.331 -29.955 1.00 54.21 C
+ANISOU 222 C GLU A 30 7010 6960 6626 313 -60 346 C
+ATOM 223 O GLU A 30 0.832 -8.823 -29.288 1.00 59.88 O
+ANISOU 223 O GLU A 30 7604 7849 7298 302 -205 354 O
+ATOM 224 CB GLU A 30 -2.122 -10.183 -28.852 1.00 62.74 C
+ANISOU 224 CB GLU A 30 8340 7960 7538 332 92 277 C
+ATOM 225 CG GLU A 30 -3.470 -9.711 -28.236 1.00 72.73 C
+ANISOU 225 CG GLU A 30 9697 9198 8739 260 106 134 C
+ATOM 226 CD GLU A 30 -4.256 -10.812 -27.471 1.00 84.77 C
+ANISOU 226 CD GLU A 30 11347 10699 10163 332 254 206 C
+ATOM 227 OE1 GLU A 30 -4.358 -12.001 -27.950 1.00 80.99 O
+ANISOU 227 OE1 GLU A 30 10932 10104 9737 384 419 311 O
+ATOM 228 OE2 GLU A 30 -4.785 -10.463 -26.379 1.00 83.98 O
+ANISOU 228 OE2 GLU A 30 11293 10681 9934 331 227 148 O
+ATOM 229 N GLU A 31 0.205 -10.073 -31.022 1.00 59.74 N
+ANISOU 229 N GLU A 31 7727 7548 7422 373 72 443 N
+ATOM 230 CA GLU A 31 1.574 -10.229 -31.535 1.00 56.65 C
+ANISOU 230 CA GLU A 31 7199 7210 7113 445 65 582 C
+ATOM 231 C GLU A 31 2.251 -8.862 -31.829 1.00 60.42 C
+ANISOU 231 C GLU A 31 7517 7754 7685 328 -85 505 C
+ATOM 232 O GLU A 31 3.462 -8.797 -31.776 1.00 66.23 O
+ANISOU 232 O GLU A 31 8087 8613 8463 365 -148 610 O
+ATOM 233 CB GLU A 31 1.536 -11.120 -32.771 1.00 64.23 C
+ANISOU 233 CB GLU A 31 8243 7999 8160 503 266 648 C
+ATOM 234 CG GLU A 31 2.861 -11.443 -33.471 1.00 83.36 C
+ANISOU 234 CG GLU A 31 10552 10436 10682 606 328 807 C
+ATOM 235 CD GLU A 31 3.790 -12.366 -32.669 1.00102.53 C
+ANISOU 235 CD GLU A 31 12908 12976 13073 795 367 1027 C
+ATOM 236 OE1 GLU A 31 3.385 -12.888 -31.594 1.00113.60 O
+ANISOU 236 OE1 GLU A 31 14374 14434 14355 859 366 1071 O
+ATOM 237 OE2 GLU A 31 4.946 -12.569 -33.121 1.00102.50 O
+ANISOU 237 OE2 GLU A 31 12770 13016 13158 898 412 1182 O
+ATOM 238 N ALA A 32 1.502 -7.778 -32.127 1.00 57.02 N
+ANISOU 238 N ALA A 32 7120 7240 7301 193 -126 339 N
+ATOM 239 CA ALA A 32 2.120 -6.424 -32.410 1.00 59.13 C
+ANISOU 239 CA ALA A 32 7255 7519 7692 72 -224 265 C
+ATOM 240 C ALA A 32 2.224 -5.516 -31.195 1.00 56.89 C
+ANISOU 240 C ALA A 32 6920 7349 7346 -41 -378 124 C
+ATOM 241 O ALA A 32 2.754 -4.418 -31.279 1.00 65.02 O
+ANISOU 241 O ALA A 32 7847 8373 8484 -167 -445 38 O
+ATOM 242 CB ALA A 32 1.377 -5.676 -33.506 1.00 53.40 C
+ANISOU 242 CB ALA A 32 6588 6626 7076 11 -149 198 C
+ATOM 243 N GLY A 33 1.719 -5.987 -30.077 1.00 55.56 N
+ANISOU 243 N GLY A 33 6832 7274 7000 -3 -414 93 N
+ATOM 244 CA GLY A 33 1.778 -5.257 -28.849 1.00 58.15 C
+ANISOU 244 CA GLY A 33 7139 7738 7215 -106 -550 -56 C
+ATOM 245 C GLY A 33 0.546 -4.451 -28.568 1.00 60.01 C
+ANISOU 245 C GLY A 33 7520 7837 7440 -190 -508 -246 C
+ATOM 246 O GLY A 33 0.620 -3.573 -27.741 1.00 69.82 O
+ANISOU 246 O GLY A 33 8758 9139 8629 -310 -593 -418 O
+ATOM 247 N ILE A 34 -0.586 -4.759 -29.224 1.00 61.19 N
+ANISOU 247 N ILE A 34 7792 7820 7635 -130 -370 -221 N
+ATOM 248 CA ILE A 34 -1.840 -4.017 -29.038 1.00 58.99 C
+ANISOU 248 CA ILE A 34 7627 7418 7368 -177 -306 -363 C
+ATOM 249 C ILE A 34 -2.765 -4.786 -28.094 1.00 62.15 C
+ANISOU 249 C ILE A 34 8149 7876 7589 -107 -261 -367 C
+ATOM 250 O ILE A 34 -3.056 -5.947 -28.343 1.00 63.50 O
+ANISOU 250 O ILE A 34 8359 8045 7721 -13 -186 -239 O
+ATOM 251 CB ILE A 34 -2.577 -3.788 -30.390 1.00 61.05 C
+ANISOU 251 CB ILE A 34 7905 7506 7785 -156 -191 -318 C
+ATOM 252 CG1 ILE A 34 -1.701 -2.983 -31.385 1.00 65.68 C
+ANISOU 252 CG1 ILE A 34 8381 8020 8552 -209 -201 -287 C
+ATOM 253 CG2 ILE A 34 -3.890 -3.029 -30.184 1.00 63.01 C
+ANISOU 253 CG2 ILE A 34 8237 7650 8053 -172 -114 -425 C
+ATOM 254 CD1 ILE A 34 -2.244 -3.016 -32.822 1.00 63.49 C
+ANISOU 254 CD1 ILE A 34 8108 7640 8375 -155 -98 -187 C
+ATOM 255 N ASP A 35 -3.244 -4.141 -27.030 1.00 63.70 N
+ANISOU 255 N ASP A 35 8416 8102 7682 -158 -279 -520 N
+ATOM 256 CA ASP A 35 -4.088 -4.826 -26.025 1.00 71.88 C
+ANISOU 256 CA ASP A 35 9569 9207 8534 -87 -222 -516 C
+ATOM 257 C ASP A 35 -5.567 -4.529 -26.307 1.00 64.56 C
+ANISOU 257 C ASP A 35 8725 8121 7682 -77 -78 -569 C
+ATOM 258 O ASP A 35 -6.130 -3.476 -25.980 1.00 66.69 O
+ANISOU 258 O ASP A 35 9040 8315 7983 -127 -40 -715 O
+ATOM 259 CB ASP A 35 -3.667 -4.503 -24.557 1.00 81.85 C
+ANISOU 259 CB ASP A 35 10862 10660 9575 -127 -325 -633 C
+ATOM 260 CG ASP A 35 -2.375 -5.278 -24.107 1.00 93.06 C
+ANISOU 260 CG ASP A 35 12178 12327 10851 -75 -463 -497 C
+ATOM 261 OD1 ASP A 35 -2.081 -6.430 -24.567 1.00 87.57 O
+ANISOU 261 OD1 ASP A 35 11448 11645 10179 50 -418 -279 O
+ATOM 262 OD2 ASP A 35 -1.644 -4.712 -23.270 1.00100.07 O
+ANISOU 262 OD2 ASP A 35 13013 13406 11600 -161 -608 -613 O
+ATOM 263 N LEU A 36 -6.157 -5.471 -27.010 1.00 61.66 N
+ANISOU 263 N LEU A 36 8363 7702 7362 -15 12 -444 N
+ATOM 264 CA LEU A 36 -7.533 -5.410 -27.353 1.00 56.54 C
+ANISOU 264 CA LEU A 36 7746 6959 6776 -6 133 -460 C
+ATOM 265 C LEU A 36 -8.274 -6.365 -26.418 1.00 58.83 C
+ANISOU 265 C LEU A 36 8125 7301 6925 45 227 -424 C
+ATOM 266 O LEU A 36 -7.725 -7.349 -25.938 1.00 59.91 O
+ANISOU 266 O LEU A 36 8295 7514 6951 96 222 -330 O
+ATOM 267 CB LEU A 36 -7.736 -5.829 -28.796 1.00 54.45 C
+ANISOU 267 CB LEU A 36 7414 6631 6642 -9 169 -370 C
+ATOM 268 CG LEU A 36 -7.150 -4.979 -29.924 1.00 47.43 C
+ANISOU 268 CG LEU A 36 6437 5685 5896 -39 115 -362 C
+ATOM 269 CD1 LEU A 36 -7.661 -5.559 -31.235 1.00 51.84 C
+ANISOU 269 CD1 LEU A 36 6953 6228 6515 -36 168 -282 C
+ATOM 270 CD2 LEU A 36 -7.550 -3.538 -29.754 1.00 48.45 C
+ANISOU 270 CD2 LEU A 36 6559 5739 6109 -60 130 -458 C
+ATOM 271 N PRO A 37 -9.531 -6.066 -26.158 1.00 52.73 N
+ANISOU 271 N PRO A 37 7383 6483 6166 48 333 -477 N
+ATOM 272 CA PRO A 37 -10.189 -6.803 -25.130 1.00 48.70 C
+ANISOU 272 CA PRO A 37 6960 6021 5521 94 437 -451 C
+ATOM 273 C PRO A 37 -10.579 -8.210 -25.630 1.00 53.45 C
+ANISOU 273 C PRO A 37 7558 6591 6158 100 538 -324 C
+ATOM 274 O PRO A 37 -10.785 -8.477 -26.837 1.00 49.32 O
+ANISOU 274 O PRO A 37 6961 6008 5767 49 548 -299 O
+ATOM 275 CB PRO A 37 -11.382 -5.907 -24.791 1.00 51.49 C
+ANISOU 275 CB PRO A 37 7326 6326 5910 95 535 -549 C
+ATOM 276 CG PRO A 37 -11.712 -5.243 -26.095 1.00 57.15 C
+ANISOU 276 CG PRO A 37 7927 6960 6825 64 521 -547 C
+ATOM 277 CD PRO A 37 -10.372 -5.018 -26.760 1.00 53.71 C
+ANISOU 277 CD PRO A 37 7454 6520 6432 30 379 -538 C
+ATOM 278 N TYR A 38 -10.593 -9.140 -24.698 1.00 52.25 N
+ANISOU 278 N TYR A 38 7494 6481 5875 159 621 -244 N
+ATOM 279 CA TYR A 38 -11.096 -10.464 -24.975 1.00 58.41 C
+ANISOU 279 CA TYR A 38 8299 7189 6702 152 774 -141 C
+ATOM 280 C TYR A 38 -11.545 -11.071 -23.664 1.00 53.69 C
+ANISOU 280 C TYR A 38 7809 6629 5962 227 913 -70 C
+ATOM 281 O TYR A 38 -11.164 -10.607 -22.581 1.00 52.44 O
+ANISOU 281 O TYR A 38 7709 6589 5625 301 856 -82 O
+ATOM 282 CB TYR A 38 -9.996 -11.359 -25.594 1.00 54.60 C
+ANISOU 282 CB TYR A 38 7821 6673 6252 178 755 -32 C
+ATOM 283 CG TYR A 38 -8.783 -11.536 -24.706 1.00 57.28 C
+ANISOU 283 CG TYR A 38 8199 7128 6435 299 678 70 C
+ATOM 284 CD1 TYR A 38 -7.743 -10.603 -24.717 1.00 57.17 C
+ANISOU 284 CD1 TYR A 38 8115 7222 6383 300 480 19 C
+ATOM 285 CD2 TYR A 38 -8.679 -12.620 -23.830 1.00 58.87 C
+ANISOU 285 CD2 TYR A 38 8492 7349 6525 412 809 232 C
+ATOM 286 CE1 TYR A 38 -6.629 -10.752 -23.885 1.00 58.64 C
+ANISOU 286 CE1 TYR A 38 8295 7574 6409 396 383 113 C
+ATOM 287 CE2 TYR A 38 -7.565 -12.768 -22.985 1.00 62.26 C
+ANISOU 287 CE2 TYR A 38 8928 7946 6781 545 722 358 C
+ATOM 288 CZ TYR A 38 -6.548 -11.837 -23.032 1.00 65.34 C
+ANISOU 288 CZ TYR A 38 9221 8482 7122 529 494 291 C
+ATOM 289 OH TYR A 38 -5.464 -11.963 -22.208 1.00 72.76 O
+ANISOU 289 OH TYR A 38 10126 9640 7877 642 383 410 O
+ATOM 290 N SER A 39 -12.264 -12.176 -23.765 1.00 51.04 N
+ANISOU 290 N SER A 39 7503 6198 5691 202 1102 6 N
+ATOM 291 CA SER A 39 -12.527 -12.977 -22.556 1.00 52.70 C
+ANISOU 291 CA SER A 39 7828 6422 5770 296 1272 129 C
+ATOM 292 C SER A 39 -12.586 -14.475 -22.933 1.00 54.61 C
+ANISOU 292 C SER A 39 8121 6509 6118 281 1473 260 C
+ATOM 293 O SER A 39 -11.697 -15.196 -22.537 1.00 53.05 O
+ANISOU 293 O SER A 39 8000 6314 5842 404 1512 419 O
+ATOM 294 CB SER A 39 -13.752 -12.480 -21.786 1.00 50.63 C
+ANISOU 294 CB SER A 39 7578 6193 5466 287 1376 64 C
+ATOM 295 OG SER A 39 -14.134 -13.447 -20.804 1.00 57.92 O
+ANISOU 295 OG SER A 39 8608 7099 6297 364 1590 207 O
+ATOM 296 N CYS A 40 -13.549 -14.932 -23.748 1.00 56.78 N
+ANISOU 296 N CYS A 40 8345 6653 6573 127 1599 192 N
+ATOM 297 CA CYS A 40 -13.634 -16.380 -24.053 1.00 57.29 C
+ANISOU 297 CA CYS A 40 8484 6532 6749 80 1830 281 C
+ATOM 298 C CYS A 40 -12.645 -16.882 -25.075 1.00 62.77 C
+ANISOU 298 C CYS A 40 9192 7133 7523 67 1795 293 C
+ATOM 299 O CYS A 40 -12.278 -18.037 -25.022 1.00 51.88 O
+ANISOU 299 O CYS A 40 7920 5599 6191 114 1993 416 O
+ATOM 300 CB CYS A 40 -15.040 -16.831 -24.469 1.00 62.61 C
+ANISOU 300 CB CYS A 40 9100 7107 7580 -117 2004 185 C
+ATOM 301 SG CYS A 40 -15.521 -16.463 -26.163 1.00 58.56 S
+ANISOU 301 SG CYS A 40 8420 6610 7220 -350 1871 -25 S
+ATOM 302 N ARG A 41 -12.233 -16.028 -26.016 1.00 58.00 N
+ANISOU 302 N ARG A 41 8486 6605 6943 14 1575 175 N
+ATOM 303 CA ARG A 41 -11.317 -16.429 -27.087 1.00 58.21 C
+ANISOU 303 CA ARG A 41 8521 6552 7044 -1 1548 175 C
+ATOM 304 C ARG A 41 -11.821 -17.585 -27.916 1.00 57.79 C
+ANISOU 304 C ARG A 41 8520 6302 7133 -157 1766 115 C
+ATOM 305 O ARG A 41 -10.986 -18.264 -28.554 1.00 62.26 O
+ANISOU 305 O ARG A 41 9155 6747 7753 -132 1841 152 O
+ATOM 306 CB ARG A 41 -9.896 -16.763 -26.569 1.00 63.76 C
+ANISOU 306 CB ARG A 41 9289 7271 7664 206 1533 363 C
+ATOM 307 CG ARG A 41 -9.186 -15.605 -25.856 1.00 71.18 C
+ANISOU 307 CG ARG A 41 10160 8433 8450 322 1286 387 C
+ATOM 308 CD ARG A 41 -7.710 -15.932 -25.568 1.00 80.04 C
+ANISOU 308 CD ARG A 41 11287 9622 9501 504 1238 570 C
+ATOM 309 NE ARG A 41 -6.866 -15.741 -26.762 1.00 74.82 N
+ANISOU 309 NE ARG A 41 10554 8929 8944 472 1145 532 N
+ATOM 310 CZ ARG A 41 -6.356 -14.582 -27.159 1.00 78.00 C
+ANISOU 310 CZ ARG A 41 10841 9455 9338 432 915 438 C
+ATOM 311 NH1 ARG A 41 -6.552 -13.467 -26.465 1.00 81.90 N
+ANISOU 311 NH1 ARG A 41 11285 10102 9732 410 749 350 N
+ATOM 312 NH2 ARG A 41 -5.644 -14.532 -28.265 1.00 86.15 N
+ANISOU 312 NH2 ARG A 41 11819 10442 10471 411 877 426 N
+ATOM 313 N ALA A 42 -13.150 -17.769 -27.971 1.00 49.81 N
+ANISOU 313 N ALA A 42 7468 5266 6189 -330 1868 7 N
+ATOM 314 CA ALA A 42 -13.768 -18.969 -28.558 1.00 57.96 C
+ANISOU 314 CA ALA A 42 8557 6104 7358 -524 2112 -75 C
+ATOM 315 C ALA A 42 -14.982 -18.639 -29.396 1.00 57.37 C
+ANISOU 315 C ALA A 42 8326 6129 7343 -777 2047 -282 C
+ATOM 316 O ALA A 42 -15.740 -19.526 -29.769 1.00 64.20 O
+ANISOU 316 O ALA A 42 9200 6877 8312 -990 2234 -389 O
+ATOM 317 CB ALA A 42 -14.200 -19.960 -27.458 1.00 56.47 C
+ANISOU 317 CB ALA A 42 8492 5754 7210 -482 2407 58 C
+ATOM 318 N GLY A 43 -15.231 -17.380 -29.635 1.00 52.54 N
+ANISOU 318 N GLY A 43 7557 5735 6668 -759 1799 -332 N
+ATOM 319 CA GLY A 43 -16.309 -17.040 -30.539 1.00 57.00 C
+ANISOU 319 CA GLY A 43 7941 6441 7273 -969 1718 -492 C
+ATOM 320 C GLY A 43 -17.684 -17.010 -29.934 1.00 58.47 C
+ANISOU 320 C GLY A 43 8011 6695 7510 -1063 1807 -511 C
+ATOM 321 O GLY A 43 -18.693 -16.858 -30.667 1.00 64.87 O
+ANISOU 321 O GLY A 43 8633 7651 8361 -1255 1754 -633 O
+ATOM 322 N SER A 44 -17.753 -17.088 -28.605 1.00 57.15 N
+ANISOU 322 N SER A 44 7930 6459 7323 -922 1931 -379 N
+ATOM 323 CA SER A 44 -19.057 -17.205 -27.927 1.00 59.58 C
+ANISOU 323 CA SER A 44 8144 6800 7692 -1003 2076 -376 C
+ATOM 324 C SER A 44 -19.354 -16.159 -26.851 1.00 51.98 C
+ANISOU 324 C SER A 44 7145 5959 6646 -810 2021 -281 C
+ATOM 325 O SER A 44 -20.144 -16.385 -25.952 1.00 58.60 O
+ANISOU 325 O SER A 44 7978 6778 7507 -803 2197 -224 O
+ATOM 326 CB SER A 44 -19.181 -18.630 -27.398 1.00 63.12 C
+ANISOU 326 CB SER A 44 8744 7008 8228 -1080 2393 -327 C
+ATOM 327 OG SER A 44 -17.989 -18.942 -26.691 1.00 75.47 O
+ANISOU 327 OG SER A 44 10522 8441 9708 -852 2451 -164 O
+ATOM 328 N CYS A 45 -18.785 -14.973 -26.981 1.00 51.65 N
+ANISOU 328 N CYS A 45 7072 6035 6515 -668 1796 -279 N
+ATOM 329 CA CYS A 45 -19.057 -13.886 -26.059 1.00 48.70 C
+ANISOU 329 CA CYS A 45 6677 5758 6066 -505 1753 -233 C
+ATOM 330 C CYS A 45 -18.893 -12.526 -26.780 1.00 51.12 C
+ANISOU 330 C CYS A 45 6860 6197 6366 -453 1521 -288 C
+ATOM 331 O CYS A 45 -18.542 -12.469 -27.980 1.00 50.80 O
+ANISOU 331 O CYS A 45 6749 6191 6360 -532 1388 -341 O
+ATOM 332 CB CYS A 45 -18.171 -13.989 -24.805 1.00 50.90 C
+ANISOU 332 CB CYS A 45 7166 5974 6198 -316 1803 -126 C
+ATOM 333 SG CYS A 45 -16.566 -13.180 -24.911 1.00 53.21 S
+ANISOU 333 SG CYS A 45 7542 6307 6366 -170 1556 -124 S
+ATOM 334 N SER A 46 -19.167 -11.439 -26.041 1.00 49.49 N
+ANISOU 334 N SER A 46 6640 6051 6114 -315 1503 -272 N
+ATOM 335 CA SER A 46 -19.261 -10.117 -26.614 1.00 49.31 C
+ANISOU 335 CA SER A 46 6494 6118 6122 -255 1356 -304 C
+ATOM 336 C SER A 46 -17.941 -9.369 -26.532 1.00 51.44 C
+ANISOU 336 C SER A 46 6888 6345 6311 -146 1208 -320 C
+ATOM 337 O SER A 46 -17.854 -8.268 -27.057 1.00 46.10 O
+ANISOU 337 O SER A 46 6135 5703 5678 -96 1103 -340 O
+ATOM 338 CB SER A 46 -20.298 -9.307 -25.871 1.00 50.14 C
+ANISOU 338 CB SER A 46 6525 6274 6249 -163 1462 -287 C
+ATOM 339 OG SER A 46 -19.973 -9.287 -24.483 1.00 49.91 O
+ANISOU 339 OG SER A 46 6691 6179 6094 -53 1563 -278 O
+ATOM 340 N SER A 47 -16.939 -9.950 -25.880 1.00 47.00 N
+ANISOU 340 N SER A 47 6498 5716 5641 -106 1210 -297 N
+ATOM 341 CA SER A 47 -15.839 -9.148 -25.341 1.00 48.40 C
+ANISOU 341 CA SER A 47 6782 5891 5713 -1 1093 -321 C
+ATOM 342 C SER A 47 -14.884 -8.548 -26.378 1.00 50.48 C
+ANISOU 342 C SER A 47 6998 6152 6030 -15 913 -348 C
+ATOM 343 O SER A 47 -14.433 -7.391 -26.220 1.00 42.86 O
+ANISOU 343 O SER A 47 6043 5186 5055 37 827 -403 O
+ATOM 344 CB SER A 47 -15.052 -9.964 -24.335 1.00 48.69 C
+ANISOU 344 CB SER A 47 6981 5919 5599 58 1134 -259 C
+ATOM 345 OG SER A 47 -14.042 -9.148 -23.822 1.00 52.57 O
+ANISOU 345 OG SER A 47 7538 6457 5976 130 999 -303 O
+ATOM 346 N CYS A 48 -14.586 -9.312 -27.432 1.00 46.30 N
+ANISOU 346 N CYS A 48 6426 5606 5560 -94 881 -320 N
+ATOM 347 CA CYS A 48 -13.615 -8.899 -28.445 1.00 43.55 C
+ANISOU 347 CA CYS A 48 6042 5255 5251 -102 736 -325 C
+ATOM 348 C CYS A 48 -14.282 -8.264 -29.667 1.00 48.19 C
+ANISOU 348 C CYS A 48 6472 5897 5938 -148 687 -339 C
+ATOM 349 O CYS A 48 -13.664 -8.163 -30.727 1.00 52.68 O
+ANISOU 349 O CYS A 48 7001 6475 6538 -171 598 -328 O
+ATOM 350 CB CYS A 48 -12.855 -10.140 -28.938 1.00 45.20 C
+ANISOU 350 CB CYS A 48 6309 5413 5450 -145 755 -280 C
+ATOM 351 SG CYS A 48 -13.936 -11.252 -29.869 1.00 49.74 S
+ANISOU 351 SG CYS A 48 6821 5979 6098 -304 875 -312 S
+ATOM 352 N ALA A 49 -15.536 -7.842 -29.543 1.00 49.80 N
+ANISOU 352 N ALA A 49 6575 6158 6186 -145 751 -344 N
+ATOM 353 CA ALA A 49 -16.294 -7.449 -30.708 1.00 48.00 C
+ANISOU 353 CA ALA A 49 6167 6039 6032 -181 710 -321 C
+ATOM 354 C ALA A 49 -15.698 -6.209 -31.365 1.00 47.62 C
+ANISOU 354 C ALA A 49 6079 5983 6030 -94 608 -287 C
+ATOM 355 O ALA A 49 -15.183 -5.313 -30.693 1.00 45.45 O
+ANISOU 355 O ALA A 49 5885 5614 5769 -6 608 -304 O
+ATOM 356 CB ALA A 49 -17.720 -7.170 -30.327 1.00 44.89 C
+ANISOU 356 CB ALA A 49 5646 5725 5684 -164 808 -302 C
+ATOM 357 N GLY A 50 -15.818 -6.151 -32.678 1.00 48.69 N
+ANISOU 357 N GLY A 50 6091 6224 6184 -128 536 -244 N
+ATOM 358 CA GLY A 50 -15.449 -4.952 -33.442 1.00 49.68 C
+ANISOU 358 CA GLY A 50 6154 6355 6367 -31 471 -170 C
+ATOM 359 C GLY A 50 -16.413 -4.732 -34.592 1.00 50.54 C
+ANISOU 359 C GLY A 50 6054 6667 6481 -27 438 -81 C
+ATOM 360 O GLY A 50 -17.402 -5.446 -34.760 1.00 51.08 O
+ANISOU 360 O GLY A 50 6008 6888 6512 -119 451 -99 O
+ATOM 361 N LYS A 51 -16.125 -3.748 -35.412 1.00 53.55 N
+ANISOU 361 N LYS A 51 6371 7070 6904 74 397 23 N
+ATOM 362 CA LYS A 51 -16.949 -3.502 -36.568 1.00 53.87 C
+ANISOU 362 CA LYS A 51 6201 7352 6915 104 349 142 C
+ATOM 363 C LYS A 51 -16.099 -3.324 -37.812 1.00 52.01 C
+ANISOU 363 C LYS A 51 5967 7166 6626 116 266 208 C
+ATOM 364 O LYS A 51 -15.259 -2.429 -37.884 1.00 49.83 O
+ANISOU 364 O LYS A 51 5763 6736 6431 222 288 275 O
+ATOM 365 CB LYS A 51 -17.819 -2.272 -36.354 1.00 55.11 C
+ANISOU 365 CB LYS A 51 6228 7529 7182 289 432 285 C
+ATOM 366 CG LYS A 51 -19.060 -2.302 -37.241 1.00 69.25 C
+ANISOU 366 CG LYS A 51 7743 9649 8918 311 386 414 C
+ATOM 367 CD LYS A 51 -19.994 -1.116 -37.036 1.00 78.14 C
+ANISOU 367 CD LYS A 51 8713 10807 10169 534 496 599 C
+ATOM 368 CE LYS A 51 -19.697 -0.098 -38.130 1.00 91.14 C
+ANISOU 368 CE LYS A 51 10279 12512 11835 709 478 813 C
+ATOM 369 NZ LYS A 51 -20.322 1.238 -37.924 1.00 98.12 N
+ANISOU 369 NZ LYS A 51 11067 13328 12884 974 639 1022 N
+ATOM 370 N VAL A 52 -16.371 -4.149 -38.805 1.00 56.50 N
+ANISOU 370 N VAL A 52 6451 7958 7057 -1 184 184 N
+ATOM 371 CA VAL A 52 -15.743 -4.044 -40.096 1.00 53.02 C
+ANISOU 371 CA VAL A 52 5995 7623 6524 10 113 251 C
+ATOM 372 C VAL A 52 -16.271 -2.823 -40.812 1.00 55.66 C
+ANISOU 372 C VAL A 52 6153 8116 6878 198 104 478 C
+ATOM 373 O VAL A 52 -17.446 -2.763 -41.107 1.00 57.54 O
+ANISOU 373 O VAL A 52 6184 8614 7061 218 71 553 O
+ATOM 374 CB VAL A 52 -16.050 -5.263 -40.957 1.00 52.46 C
+ANISOU 374 CB VAL A 52 5882 7779 6271 -184 41 135 C
+ATOM 375 CG1 VAL A 52 -15.519 -5.033 -42.382 1.00 54.82 C
+ANISOU 375 CG1 VAL A 52 6153 8239 6436 -149 -26 221 C
+ATOM 376 CG2 VAL A 52 -15.383 -6.462 -40.332 1.00 50.36 C
+ANISOU 376 CG2 VAL A 52 5817 7306 6010 -339 95 -55 C
+ATOM 377 N VAL A 53 -15.394 -1.848 -41.054 1.00 54.66 N
+ANISOU 377 N VAL A 53 6097 7828 6843 341 150 599 N
+ATOM 378 CA VAL A 53 -15.763 -0.629 -41.772 1.00 62.36 C
+ANISOU 378 CA VAL A 53 6930 8905 7859 554 184 855 C
+ATOM 379 C VAL A 53 -15.275 -0.645 -43.240 1.00 58.73 C
+ANISOU 379 C VAL A 53 6429 8643 7241 577 116 972 C
+ATOM 380 O VAL A 53 -15.785 0.085 -44.048 1.00 58.59 O
+ANISOU 380 O VAL A 53 6253 8828 7179 741 116 1203 O
+ATOM 381 CB VAL A 53 -15.351 0.680 -41.005 1.00 65.49 C
+ANISOU 381 CB VAL A 53 7415 8968 8500 719 338 940 C
+ATOM 382 CG1 VAL A 53 -15.576 0.504 -39.522 1.00 72.86 C
+ANISOU 382 CG1 VAL A 53 8446 9701 9533 655 398 764 C
+ATOM 383 CG2 VAL A 53 -13.917 1.090 -41.248 1.00 68.64 C
+ANISOU 383 CG2 VAL A 53 7968 9134 8977 721 376 943 C
+ATOM 384 N SER A 54 -14.348 -1.525 -43.591 1.00 53.74 N
+ANISOU 384 N SER A 54 5935 7975 6509 426 68 825 N
+ATOM 385 CA SER A 54 -13.884 -1.675 -44.972 1.00 55.87 C
+ANISOU 385 CA SER A 54 6190 8441 6597 431 18 904 C
+ATOM 386 C SER A 54 -13.173 -3.046 -45.081 1.00 56.25 C
+ANISOU 386 C SER A 54 6394 8450 6527 213 -15 660 C
+ATOM 387 O SER A 54 -12.486 -3.512 -44.129 1.00 49.66 O
+ANISOU 387 O SER A 54 5714 7335 5817 133 33 511 O
+ATOM 388 CB SER A 54 -12.991 -0.455 -45.367 1.00 56.61 C
+ANISOU 388 CB SER A 54 6326 8357 6824 625 121 1123 C
+ATOM 389 OG SER A 54 -12.138 -0.710 -46.445 1.00 63.73 O
+ANISOU 389 OG SER A 54 7288 9336 7589 611 112 1159 O
+ATOM 390 N GLY A 55 -13.389 -3.710 -46.217 1.00 53.71 N
+ANISOU 390 N GLY A 55 6028 8423 5956 121 -89 620 N
+ATOM 391 CA GLY A 55 -12.890 -5.055 -46.464 1.00 54.03 C
+ANISOU 391 CA GLY A 55 6214 8444 5869 -87 -89 381 C
+ATOM 392 C GLY A 55 -13.780 -6.179 -45.936 1.00 56.10 C
+ANISOU 392 C GLY A 55 6459 8774 6082 -306 -121 151 C
+ATOM 393 O GLY A 55 -14.982 -5.983 -45.681 1.00 60.55 O
+ANISOU 393 O GLY A 55 6840 9527 6637 -318 -183 180 O
+ATOM 394 N SER A 56 -13.181 -7.362 -45.781 1.00 52.30 N
+ANISOU 394 N SER A 56 6161 8128 5583 -472 -54 -60 N
+ATOM 395 CA SER A 56 -13.909 -8.555 -45.414 1.00 56.19 C
+ANISOU 395 CA SER A 56 6669 8647 6032 -704 -41 -291 C
+ATOM 396 C SER A 56 -13.104 -9.443 -44.480 1.00 53.82 C
+ANISOU 396 C SER A 56 6589 7981 5876 -764 94 -420 C
+ATOM 397 O SER A 56 -11.877 -9.347 -44.370 1.00 54.78 O
+ANISOU 397 O SER A 56 6852 7882 6078 -658 162 -364 O
+ATOM 398 CB SER A 56 -14.330 -9.330 -46.692 1.00 60.27 C
+ANISOU 398 CB SER A 56 7153 9473 6272 -904 -92 -449 C
+ATOM 399 OG SER A 56 -13.185 -9.640 -47.492 1.00 64.49 O
+ANISOU 399 OG SER A 56 7867 9923 6713 -890 -21 -484 O
+ATOM 400 N VAL A 57 -13.818 -10.317 -43.788 1.00 57.62 N
+ANISOU 400 N VAL A 57 7081 8413 6396 -929 142 -574 N
+ATOM 401 CA VAL A 57 -13.221 -11.309 -42.892 1.00 53.60 C
+ANISOU 401 CA VAL A 57 6773 7581 6008 -986 293 -680 C
+ATOM 402 C VAL A 57 -13.972 -12.587 -43.112 1.00 55.21 C
+ANISOU 402 C VAL A 57 7008 7830 6138 -1256 368 -912 C
+ATOM 403 O VAL A 57 -15.069 -12.588 -43.684 1.00 53.95 O
+ANISOU 403 O VAL A 57 6676 7964 5858 -1404 275 -989 O
+ATOM 404 CB VAL A 57 -13.373 -10.956 -41.381 1.00 57.18 C
+ANISOU 404 CB VAL A 57 7224 7857 6644 -880 320 -596 C
+ATOM 405 CG1 VAL A 57 -12.463 -9.803 -41.015 1.00 52.19 C
+ANISOU 405 CG1 VAL A 57 6602 7118 6107 -653 277 -417 C
+ATOM 406 CG2 VAL A 57 -14.834 -10.627 -41.047 1.00 53.61 C
+ANISOU 406 CG2 VAL A 57 6573 7599 6197 -936 258 -594 C
+ATOM 407 N ASP A 58 -13.366 -13.666 -42.641 1.00 55.82 N
+ANISOU 407 N ASP A 58 7294 7617 6296 -1318 547 -1013 N
+ATOM 408 CA ASP A 58 -13.996 -14.957 -42.561 1.00 58.46 C
+ANISOU 408 CA ASP A 58 7701 7878 6631 -1574 687 -1233 C
+ATOM 409 C ASP A 58 -14.136 -15.223 -41.085 1.00 55.65 C
+ANISOU 409 C ASP A 58 7395 7287 6461 -1515 794 -1166 C
+ATOM 410 O ASP A 58 -13.156 -15.457 -40.418 1.00 55.05 O
+ANISOU 410 O ASP A 58 7478 6953 6484 -1367 903 -1074 O
+ATOM 411 CB ASP A 58 -13.103 -16.016 -43.188 1.00 65.76 C
+ANISOU 411 CB ASP A 58 8862 8605 7518 -1656 869 -1374 C
+ATOM 412 CG ASP A 58 -13.609 -17.451 -42.970 1.00 72.39 C
+ANISOU 412 CG ASP A 58 9833 9259 8413 -1919 1088 -1606 C
+ATOM 413 OD1 ASP A 58 -14.654 -17.719 -42.304 1.00 72.82 O
+ANISOU 413 OD1 ASP A 58 9792 9332 8542 -2058 1107 -1663 O
+ATOM 414 OD2 ASP A 58 -12.932 -18.339 -43.523 1.00 80.41 O
+ANISOU 414 OD2 ASP A 58 11056 10090 9406 -1990 1274 -1737 O
+ATOM 415 N GLN A 59 -15.358 -15.182 -40.586 1.00 59.22 N
+ANISOU 415 N GLN A 59 7695 7858 6947 -1623 763 -1198 N
+ATOM 416 CA GLN A 59 -15.612 -15.422 -39.174 1.00 62.73 C
+ANISOU 416 CA GLN A 59 8181 8107 7544 -1569 878 -1130 C
+ATOM 417 C GLN A 59 -16.694 -16.457 -38.993 1.00 65.10 C
+ANISOU 417 C GLN A 59 8454 8390 7889 -1842 1015 -1303 C
+ATOM 418 O GLN A 59 -17.576 -16.295 -38.154 1.00 66.15 O
+ANISOU 418 O GLN A 59 8471 8562 8101 -1853 1028 -1256 O
+ATOM 419 CB GLN A 59 -16.011 -14.137 -38.463 1.00 57.25 C
+ANISOU 419 CB GLN A 59 7325 7538 6889 -1378 738 -953 C
+ATOM 420 CG GLN A 59 -17.246 -13.434 -39.016 1.00 55.97 C
+ANISOU 420 CG GLN A 59 6886 7717 6661 -1449 585 -955 C
+ATOM 421 CD GLN A 59 -17.652 -12.296 -38.096 1.00 62.04 C
+ANISOU 421 CD GLN A 59 7537 8522 7511 -1245 528 -780 C
+ATOM 422 OE1 GLN A 59 -18.210 -11.269 -38.534 1.00 66.81 O
+ANISOU 422 OE1 GLN A 59 7938 9366 8079 -1159 394 -682 O
+ATOM 423 NE2 GLN A 59 -17.359 -12.461 -36.800 1.00 56.51 N
+ANISOU 423 NE2 GLN A 59 6972 7583 6913 -1150 646 -731 N
+ATOM 424 N SER A 60 -16.585 -17.512 -39.786 1.00 64.01 N
+ANISOU 424 N SER A 60 8432 8180 7707 -2067 1137 -1510 N
+ATOM 425 CA SER A 60 -17.358 -18.738 -39.660 1.00 71.88 C
+ANISOU 425 CA SER A 60 9472 9060 8776 -2367 1339 -1715 C
+ATOM 426 C SER A 60 -17.042 -19.592 -38.399 1.00 69.57 C
+ANISOU 426 C SER A 60 9386 8371 8673 -2297 1620 -1638 C
+ATOM 427 O SER A 60 -17.817 -20.492 -38.073 1.00 71.72 O
+ANISOU 427 O SER A 60 9674 8528 9048 -2526 1809 -1764 O
+ATOM 428 CB SER A 60 -17.104 -19.609 -40.916 1.00 74.82 C
+ANISOU 428 CB SER A 60 9970 9417 9042 -2615 1424 -1979 C
+ATOM 429 OG SER A 60 -15.720 -19.921 -40.981 1.00 69.57 O
+ANISOU 429 OG SER A 60 9563 8467 8400 -2430 1560 -1910 O
+ATOM 430 N ASP A 61 -15.919 -19.358 -37.720 1.00 66.51 N
+ANISOU 430 N ASP A 61 9149 7790 8330 -1996 1657 -1429 N
+ATOM 431 CA ASP A 61 -15.690 -19.995 -36.412 1.00 71.53 C
+ANISOU 431 CA ASP A 61 9937 8131 9109 -1878 1886 -1294 C
+ATOM 432 C ASP A 61 -16.401 -19.243 -35.270 1.00 70.72 C
+ANISOU 432 C ASP A 61 9687 8145 9037 -1762 1797 -1144 C
+ATOM 433 O ASP A 61 -16.415 -19.738 -34.176 1.00 76.22 O
+ANISOU 433 O ASP A 61 10486 8652 9822 -1683 1980 -1036 O
+ATOM 434 CB ASP A 61 -14.215 -20.094 -36.049 1.00 71.97 C
+ANISOU 434 CB ASP A 61 10185 7978 9182 -1596 1957 -1113 C
+ATOM 435 CG ASP A 61 -13.386 -20.780 -37.089 1.00 73.12 C
+ANISOU 435 CG ASP A 61 10490 7983 9309 -1651 2076 -1223 C
+ATOM 436 OD1 ASP A 61 -13.929 -21.468 -37.992 1.00 83.53 O
+ANISOU 436 OD1 ASP A 61 11838 9288 10611 -1938 2174 -1474 O
+ATOM 437 OD2 ASP A 61 -12.154 -20.643 -36.976 1.00 81.02 O
+ANISOU 437 OD2 ASP A 61 11586 8889 10308 -1407 2081 -1062 O
+ATOM 438 N GLN A 62 -16.979 -18.058 -35.515 1.00 72.21 N
+ANISOU 438 N GLN A 62 9647 8639 9149 -1733 1544 -1123 N
+ATOM 439 CA GLN A 62 -17.756 -17.359 -34.476 1.00 67.75 C
+ANISOU 439 CA GLN A 62 8946 8173 8619 -1633 1498 -1004 C
+ATOM 440 C GLN A 62 -19.164 -17.942 -34.377 1.00 73.09 C
+ANISOU 440 C GLN A 62 9484 8914 9371 -1894 1611 -1123 C
+ATOM 441 O GLN A 62 -19.705 -18.425 -35.366 1.00 70.89 O
+ANISOU 441 O GLN A 62 9116 8743 9073 -2166 1602 -1315 O
+ATOM 442 CB GLN A 62 -17.867 -15.838 -34.717 1.00 66.80 C
+ANISOU 442 CB GLN A 62 8639 8319 8422 -1477 1233 -915 C
+ATOM 443 CG GLN A 62 -19.034 -15.338 -35.614 1.00 67.21 C
+ANISOU 443 CG GLN A 62 8412 8696 8428 -1635 1083 -998 C
+ATOM 444 CD GLN A 62 -20.329 -14.964 -34.874 1.00 64.99 C
+ANISOU 444 CD GLN A 62 7928 8548 8214 -1649 1104 -947 C
+ATOM 445 OE1 GLN A 62 -20.304 -14.340 -33.806 1.00 71.34 O
+ANISOU 445 OE1 GLN A 62 8759 9285 9059 -1444 1131 -808 O
+ATOM 446 NE2 GLN A 62 -21.471 -15.281 -35.476 1.00 63.47 N
+ANISOU 446 NE2 GLN A 62 7516 8576 8024 -1892 1085 -1063 N
+ATOM 447 N SER A 63 -19.742 -17.884 -33.174 1.00 72.66 N
+ANISOU 447 N SER A 63 9406 8808 9392 -1819 1719 -1013 N
+ATOM 448 CA SER A 63 -21.142 -18.244 -32.958 1.00 72.40 C
+ANISOU 448 CA SER A 63 9193 8866 9449 -2039 1821 -1088 C
+ATOM 449 C SER A 63 -21.984 -17.121 -32.341 1.00 66.69 C
+ANISOU 449 C SER A 63 8251 8365 8723 -1899 1711 -963 C
+ATOM 450 O SER A 63 -23.178 -17.067 -32.599 1.00 77.64 O
+ANISOU 450 O SER A 63 9385 9960 10154 -2074 1693 -1026 O
+ATOM 451 CB SER A 63 -21.277 -19.527 -32.118 1.00 70.17 C
+ANISOU 451 CB SER A 63 9088 8272 9301 -2138 2157 -1089 C
+ATOM 452 OG SER A 63 -20.352 -19.523 -31.051 1.00 76.40 O
+ANISOU 452 OG SER A 63 10101 8853 10075 -1847 2253 -890 O
+ATOM 453 N PHE A 64 -21.393 -16.238 -31.540 1.00 58.38 N
+ANISOU 453 N PHE A 64 7282 7276 7622 -1597 1650 -796 N
+ATOM 454 CA PHE A 64 -22.194 -15.361 -30.713 1.00 54.39 C
+ANISOU 454 CA PHE A 64 6633 6895 7136 -1461 1643 -686 C
+ATOM 455 C PHE A 64 -23.087 -14.381 -31.501 1.00 58.70 C
+ANISOU 455 C PHE A 64 6865 7765 7673 -1486 1455 -693 C
+ATOM 456 O PHE A 64 -24.182 -14.086 -31.039 1.00 57.54 O
+ANISOU 456 O PHE A 64 6527 7742 7591 -1488 1516 -644 O
+ATOM 457 CB PHE A 64 -21.262 -14.595 -29.755 1.00 55.93 C
+ANISOU 457 CB PHE A 64 7010 6983 7257 -1156 1611 -549 C
+ATOM 458 CG PHE A 64 -21.972 -13.594 -28.871 1.00 56.33 C
+ANISOU 458 CG PHE A 64 6960 7132 7311 -994 1624 -455 C
+ATOM 459 CD1 PHE A 64 -22.478 -13.970 -27.623 1.00 51.74 C
+ANISOU 459 CD1 PHE A 64 6445 6457 6754 -951 1839 -390 C
+ATOM 460 CD2 PHE A 64 -22.149 -12.275 -29.292 1.00 59.73 C
+ANISOU 460 CD2 PHE A 64 7237 7734 7723 -872 1452 -423 C
+ATOM 461 CE1 PHE A 64 -23.090 -13.031 -26.810 1.00 57.92 C
+ANISOU 461 CE1 PHE A 64 7159 7319 7527 -791 1874 -316 C
+ATOM 462 CE2 PHE A 64 -22.810 -11.337 -28.484 1.00 60.57 C
+ANISOU 462 CE2 PHE A 64 7268 7898 7848 -710 1505 -344 C
+ATOM 463 CZ PHE A 64 -23.289 -11.715 -27.242 1.00 54.75 C
+ANISOU 463 CZ PHE A 64 6607 7070 7122 -674 1715 -302 C
+ATOM 464 N LEU A 65 -22.629 -13.842 -32.646 1.00 59.31 N
+ANISOU 464 N LEU A 65 6879 7987 7667 -1474 1243 -724 N
+ATOM 465 CA LEU A 65 -23.379 -12.775 -33.374 1.00 63.23 C
+ANISOU 465 CA LEU A 65 7079 8808 8137 -1426 1064 -668 C
+ATOM 466 C LEU A 65 -24.616 -13.283 -34.188 1.00 65.16 C
+ANISOU 466 C LEU A 65 7020 9342 8393 -1708 1030 -770 C
+ATOM 467 O LEU A 65 -24.516 -14.329 -34.834 1.00 64.66 O
+ANISOU 467 O LEU A 65 7003 9259 8302 -1976 1052 -946 O
+ATOM 468 CB LEU A 65 -22.421 -11.920 -34.276 1.00 63.03 C
+ANISOU 468 CB LEU A 65 7095 8842 8010 -1279 864 -623 C
+ATOM 469 CG LEU A 65 -21.294 -11.083 -33.600 1.00 62.01 C
+ANISOU 469 CG LEU A 65 7179 8506 7874 -1004 852 -518 C
+ATOM 470 CD1 LEU A 65 -20.274 -10.486 -34.575 1.00 60.47 C
+ANISOU 470 CD1 LEU A 65 7035 8338 7604 -917 691 -493 C
+ATOM 471 CD2 LEU A 65 -21.842 -9.965 -32.731 1.00 60.62 C
+ANISOU 471 CD2 LEU A 65 6923 8352 7758 -795 888 -391 C
+ATOM 472 N ASP A 66 -25.764 -12.554 -34.051 1.00 69.31 N
+ANISOU 472 N ASP A 66 7243 10123 8968 -1644 999 -661 N
+ATOM 473 CA ASP A 66 -27.047 -12.615 -34.848 1.00 72.82 C
+ANISOU 473 CA ASP A 66 7291 10968 9408 -1843 905 -692 C
+ATOM 474 C ASP A 66 -26.639 -12.271 -36.317 1.00 77.46 C
+ANISOU 474 C ASP A 66 7794 11812 9825 -1871 656 -723 C
+ATOM 475 O ASP A 66 -25.716 -11.438 -36.541 1.00 65.69 O
+ANISOU 475 O ASP A 66 6447 10241 8269 -1624 566 -617 O
+ATOM 476 CB ASP A 66 -28.090 -11.511 -34.364 1.00 77.64 C
+ANISOU 476 CB ASP A 66 7609 11789 10101 -1619 914 -476 C
+ATOM 477 CG ASP A 66 -29.226 -12.030 -33.407 1.00 93.62 C
+ANISOU 477 CG ASP A 66 9481 13808 12279 -1733 1126 -471 C
+ATOM 478 OD1 ASP A 66 -29.080 -13.108 -32.793 1.00106.10 O
+ANISOU 478 OD1 ASP A 66 11255 15134 13923 -1914 1308 -596 O
+ATOM 479 OD2 ASP A 66 -30.299 -11.343 -33.266 1.00 93.76 O
+ANISOU 479 OD2 ASP A 66 9173 14081 12368 -1624 1134 -319 O
+ATOM 480 N ASP A 67 -27.292 -12.872 -37.323 1.00 79.83 N
+ANISOU 480 N ASP A 67 7864 12428 10039 -2173 549 -870 N
+ATOM 481 CA ASP A 67 -26.991 -12.525 -38.711 1.00 83.48 C
+ANISOU 481 CA ASP A 67 8232 13188 10299 -2190 314 -888 C
+ATOM 482 C ASP A 67 -27.305 -11.060 -38.958 1.00 81.61 C
+ANISOU 482 C ASP A 67 7760 13217 10028 -1857 174 -603 C
+ATOM 483 O ASP A 67 -26.634 -10.428 -39.777 1.00 81.48 O
+ANISOU 483 O ASP A 67 7791 13288 9878 -1705 34 -521 O
+ATOM 484 CB ASP A 67 -27.780 -13.356 -39.743 1.00 99.82 C
+ANISOU 484 CB ASP A 67 10050 15632 12243 -2589 204 -1107 C
+ATOM 485 CG ASP A 67 -27.453 -14.842 -39.701 1.00102.82 C
+ANISOU 485 CG ASP A 67 10677 15732 12655 -2952 367 -1422 C
+ATOM 486 OD1 ASP A 67 -26.299 -15.215 -39.353 1.00102.93 O
+ANISOU 486 OD1 ASP A 67 11082 15321 12706 -2872 499 -1465 O
+ATOM 487 OD2 ASP A 67 -28.380 -15.622 -40.029 1.00 94.69 O
+ANISOU 487 OD2 ASP A 67 9430 14922 11623 -3321 370 -1619 O
+ATOM 488 N GLU A 68 -28.313 -10.508 -38.287 1.00 76.33 N
+ANISOU 488 N GLU A 68 6842 12669 9490 -1729 236 -436 N
+ATOM 489 CA GLU A 68 -28.488 -9.053 -38.331 1.00 87.60 C
+ANISOU 489 CA GLU A 68 8114 14233 10935 -1350 179 -137 C
+ATOM 490 C GLU A 68 -27.140 -8.357 -37.951 1.00 89.20 C
+ANISOU 490 C GLU A 68 8695 14033 11161 -1073 233 -65 C
+ATOM 491 O GLU A 68 -26.669 -7.443 -38.628 1.00 88.13 O
+ANISOU 491 O GLU A 68 8554 13978 10954 -862 128 85 O
+ATOM 492 CB GLU A 68 -29.608 -8.602 -37.395 1.00 95.60 C
+ANISOU 492 CB GLU A 68 8892 15305 12126 -1215 319 23 C
+ATOM 493 CG GLU A 68 -29.735 -7.087 -37.282 1.00104.83 C
+ANISOU 493 CG GLU A 68 9958 16515 13354 -793 334 332 C
+ATOM 494 CD GLU A 68 -30.926 -6.636 -36.439 1.00115.12 C
+ANISOU 494 CD GLU A 68 11001 17904 14832 -647 495 501 C
+ATOM 495 OE1 GLU A 68 -31.956 -7.348 -36.393 1.00115.20 O
+ANISOU 495 OE1 GLU A 68 10727 18166 14878 -878 505 440 O
+ATOM 496 OE2 GLU A 68 -30.828 -5.546 -35.827 1.00115.96 O
+ANISOU 496 OE2 GLU A 68 11189 17821 15050 -303 630 690 O
+ATOM 497 N GLN A 69 -26.519 -8.821 -36.871 1.00 84.99 N
+ANISOU 497 N GLN A 69 8479 13084 10727 -1087 401 -169 N
+ATOM 498 CA GLN A 69 -25.278 -8.246 -36.383 1.00 74.41 C
+ANISOU 498 CA GLN A 69 7470 11389 9412 -867 450 -126 C
+ATOM 499 C GLN A 69 -24.113 -8.417 -37.351 1.00 73.31 C
+ANISOU 499 C GLN A 69 7506 11209 9139 -912 323 -199 C
+ATOM 500 O GLN A 69 -23.352 -7.485 -37.533 1.00 68.06 O
+ANISOU 500 O GLN A 69 6940 10450 8469 -692 283 -80 O
+ATOM 501 CB GLN A 69 -24.929 -8.815 -34.993 1.00 71.55 C
+ANISOU 501 CB GLN A 69 7378 10660 9148 -886 645 -216 C
+ATOM 502 CG GLN A 69 -25.865 -8.310 -33.913 1.00 72.95 C
+ANISOU 502 CG GLN A 69 7442 10823 9452 -746 799 -105 C
+ATOM 503 CD GLN A 69 -25.579 -8.891 -32.535 1.00 72.43 C
+ANISOU 503 CD GLN A 69 7636 10439 9442 -758 996 -178 C
+ATOM 504 OE1 GLN A 69 -25.227 -10.079 -32.369 1.00 64.31 O
+ANISOU 504 OE1 GLN A 69 6765 9275 8394 -961 1053 -316 O
+ATOM 505 NE2 GLN A 69 -25.737 -8.050 -31.530 1.00 72.76 N
+ANISOU 505 NE2 GLN A 69 7734 10360 9548 -530 1119 -79 N
+ATOM 506 N ILE A 70 -23.969 -9.589 -37.964 1.00 78.29 N
+ANISOU 506 N ILE A 70 8181 11890 9673 -1199 285 -397 N
+ATOM 507 CA ILE A 70 -22.959 -9.783 -39.017 1.00 75.81 C
+ANISOU 507 CA ILE A 70 8009 11579 9215 -1247 178 -469 C
+ATOM 508 C ILE A 70 -23.247 -8.950 -40.279 1.00 80.31 C
+ANISOU 508 C ILE A 70 8337 12536 9640 -1154 -9 -332 C
+ATOM 509 O ILE A 70 -22.334 -8.336 -40.829 1.00 79.77 O
+ANISOU 509 O ILE A 70 8384 12414 9511 -993 -67 -242 O
+ATOM 510 CB ILE A 70 -22.818 -11.250 -39.409 1.00 73.74 C
+ANISOU 510 CB ILE A 70 7859 11274 8884 -1583 218 -732 C
+ATOM 511 CG1 ILE A 70 -22.302 -12.031 -38.193 1.00 70.17 C
+ANISOU 511 CG1 ILE A 70 7687 10403 8571 -1612 426 -812 C
+ATOM 512 CG2 ILE A 70 -21.890 -11.368 -40.629 1.00 69.89 C
+ANISOU 512 CG2 ILE A 70 7488 10843 8223 -1620 113 -800 C
+ATOM 513 CD1 ILE A 70 -22.178 -13.529 -38.421 1.00 73.86 C
+ANISOU 513 CD1 ILE A 70 8298 10742 9024 -1925 541 -1055 C
+ATOM 514 N GLY A 71 -24.501 -8.934 -40.720 1.00 80.29 N
+ANISOU 514 N GLY A 71 7989 12934 9582 -1249 -96 -298 N
+ATOM 515 CA GLY A 71 -24.945 -8.065 -41.782 1.00 84.25 C
+ANISOU 515 CA GLY A 71 8211 13855 9944 -1113 -267 -106 C
+ATOM 516 C GLY A 71 -24.627 -6.587 -41.543 1.00 90.55 C
+ANISOU 516 C GLY A 71 9018 14542 10843 -709 -231 194 C
+ATOM 517 O GLY A 71 -24.287 -5.858 -42.499 1.00 81.85 O
+ANISOU 517 O GLY A 71 7861 13613 9622 -547 -332 358 O
+ATOM 518 N GLU A 72 -24.732 -6.122 -40.290 1.00 85.84 N
+ANISOU 518 N GLU A 72 8502 13652 10461 -547 -67 267 N
+ATOM 519 CA GLU A 72 -24.363 -4.720 -39.956 1.00 84.90 C
+ANISOU 519 CA GLU A 72 8443 13349 10466 -189 11 507 C
+ATOM 520 C GLU A 72 -22.834 -4.496 -39.871 1.00 78.13 C
+ANISOU 520 C GLU A 72 7942 12117 9627 -119 45 456 C
+ATOM 521 O GLU A 72 -22.372 -3.347 -39.798 1.00 75.56 O
+ANISOU 521 O GLU A 72 7680 11635 9392 134 104 627 O
+ATOM 522 CB GLU A 72 -25.091 -4.227 -38.684 1.00 90.04 C
+ANISOU 522 CB GLU A 72 9044 13847 11319 -41 188 589 C
+ATOM 523 CG GLU A 72 -26.571 -3.883 -38.951 1.00104.52 C
+ANISOU 523 CG GLU A 72 10456 16088 13168 32 166 776 C
+ATOM 524 CD GLU A 72 -27.484 -3.868 -37.708 1.00115.41 C
+ANISOU 524 CD GLU A 72 11754 17371 14724 75 350 790 C
+ATOM 525 OE1 GLU A 72 -27.080 -4.369 -36.632 1.00119.16 O
+ANISOU 525 OE1 GLU A 72 12496 17503 15276 -13 480 617 O
+ATOM 526 OE2 GLU A 72 -28.638 -3.366 -37.807 1.00117.96 O
+ANISOU 526 OE2 GLU A 72 11730 17986 15102 210 373 993 O
+ATOM 527 N GLY A 73 -22.058 -5.585 -39.875 1.00 67.33 N
+ANISOU 527 N GLY A 73 6793 10600 8189 -345 28 226 N
+ATOM 528 CA GLY A 73 -20.599 -5.498 -39.918 1.00 67.28 C
+ANISOU 528 CA GLY A 73 7077 10299 8185 -298 44 183 C
+ATOM 529 C GLY A 73 -19.821 -5.908 -38.667 1.00 62.16 C
+ANISOU 529 C GLY A 73 6708 9260 7648 -326 164 53 C
+ATOM 530 O GLY A 73 -18.585 -5.771 -38.638 1.00 63.30 O
+ANISOU 530 O GLY A 73 7062 9181 7806 -276 171 35 O
+ATOM 531 N PHE A 74 -20.506 -6.407 -37.635 1.00 54.21 N
+ANISOU 531 N PHE A 74 5695 8188 6714 -400 259 -21 N
+ATOM 532 CA PHE A 74 -19.813 -6.733 -36.379 1.00 50.47 C
+ANISOU 532 CA PHE A 74 5476 7384 6317 -394 373 -110 C
+ATOM 533 C PHE A 74 -19.017 -7.976 -36.610 1.00 48.37 C
+ANISOU 533 C PHE A 74 5385 7015 5978 -577 371 -263 C
+ATOM 534 O PHE A 74 -19.389 -8.786 -37.447 1.00 48.97 O
+ANISOU 534 O PHE A 74 5379 7259 5968 -764 327 -353 O
+ATOM 535 CB PHE A 74 -20.762 -6.849 -35.179 1.00 51.93 C
+ANISOU 535 CB PHE A 74 5616 7527 6587 -388 503 -119 C
+ATOM 536 CG PHE A 74 -21.382 -5.561 -34.825 1.00 54.65 C
+ANISOU 536 CG PHE A 74 5836 7903 7023 -170 553 31 C
+ATOM 537 CD1 PHE A 74 -20.611 -4.556 -34.263 1.00 59.00 C
+ANISOU 537 CD1 PHE A 74 6552 8226 7638 12 602 74 C
+ATOM 538 CD2 PHE A 74 -22.705 -5.309 -35.097 1.00 62.03 C
+ANISOU 538 CD2 PHE A 74 6482 9097 7988 -145 562 133 C
+ATOM 539 CE1 PHE A 74 -21.141 -3.312 -33.970 1.00 61.30 C
+ANISOU 539 CE1 PHE A 74 6759 8497 8034 221 689 205 C
+ATOM 540 CE2 PHE A 74 -23.278 -4.074 -34.762 1.00 65.97 C
+ANISOU 540 CE2 PHE A 74 6870 9599 8593 96 649 300 C
+ATOM 541 CZ PHE A 74 -22.481 -3.064 -34.213 1.00 69.36 C
+ANISOU 541 CZ PHE A 74 7503 9751 9097 283 726 331 C
+ATOM 542 N VAL A 75 -17.889 -8.074 -35.901 1.00 48.27 N
+ANISOU 542 N VAL A 75 5608 6737 5995 -517 420 -290 N
+ATOM 543 CA VAL A 75 -16.947 -9.203 -35.999 1.00 47.38 C
+ANISOU 543 CA VAL A 75 5685 6480 5837 -632 453 -395 C
+ATOM 544 C VAL A 75 -16.430 -9.520 -34.615 1.00 49.15 C
+ANISOU 544 C VAL A 75 6091 6473 6108 -575 558 -404 C
+ATOM 545 O VAL A 75 -16.248 -8.629 -33.798 1.00 47.13 O
+ANISOU 545 O VAL A 75 5866 6148 5892 -428 559 -343 O
+ATOM 546 CB VAL A 75 -15.775 -8.834 -36.956 1.00 48.33 C
+ANISOU 546 CB VAL A 75 5867 6583 5911 -571 365 -359 C
+ATOM 547 CG1 VAL A 75 -15.079 -7.549 -36.507 1.00 49.98 C
+ANISOU 547 CG1 VAL A 75 6112 6686 6192 -372 333 -248 C
+ATOM 548 CG2 VAL A 75 -14.782 -9.929 -37.088 1.00 49.25 C
+ANISOU 548 CG2 VAL A 75 6167 6549 5995 -653 422 -442 C
+ATOM 549 N LEU A 76 -16.184 -10.794 -34.355 1.00 49.57 N
+ANISOU 549 N LEU A 76 6273 6411 6149 -688 660 -479 N
+ATOM 550 CA LEU A 76 -15.521 -11.198 -33.153 1.00 47.93 C
+ANISOU 550 CA LEU A 76 6243 6013 5953 -611 755 -452 C
+ATOM 551 C LEU A 76 -14.098 -11.431 -33.507 1.00 45.41 C
+ANISOU 551 C LEU A 76 6054 5590 5609 -559 721 -432 C
+ATOM 552 O LEU A 76 -13.751 -12.422 -34.211 1.00 46.04 O
+ANISOU 552 O LEU A 76 6200 5615 5676 -659 783 -486 O
+ATOM 553 CB LEU A 76 -16.177 -12.472 -32.551 1.00 49.85 C
+ANISOU 553 CB LEU A 76 6545 6174 6220 -737 935 -501 C
+ATOM 554 CG LEU A 76 -17.619 -12.228 -32.105 1.00 52.45 C
+ANISOU 554 CG LEU A 76 6721 6616 6591 -787 985 -507 C
+ATOM 555 CD1 LEU A 76 -18.258 -13.483 -31.561 1.00 56.78 C
+ANISOU 555 CD1 LEU A 76 7318 7068 7185 -930 1185 -551 C
+ATOM 556 CD2 LEU A 76 -17.640 -11.190 -31.039 1.00 52.12 C
+ANISOU 556 CD2 LEU A 76 6691 6565 6545 -599 972 -426 C
+ATOM 557 N THR A 77 -13.248 -10.565 -32.967 1.00 46.19 N
+ANISOU 557 N THR A 77 6193 5650 5705 -409 646 -365 N
+ATOM 558 CA THR A 77 -11.875 -10.505 -33.442 1.00 42.15 C
+ANISOU 558 CA THR A 77 5743 5084 5186 -350 586 -327 C
+ATOM 559 C THR A 77 -11.098 -11.716 -33.100 1.00 45.26 C
+ANISOU 559 C THR A 77 6277 5354 5565 -343 692 -303 C
+ATOM 560 O THR A 77 -10.095 -11.997 -33.772 1.00 50.56 O
+ANISOU 560 O THR A 77 6987 5982 6241 -320 686 -277 O
+ATOM 561 CB THR A 77 -11.139 -9.239 -32.928 1.00 47.57 C
+ANISOU 561 CB THR A 77 6417 5768 5889 -225 479 -279 C
+ATOM 562 OG1 THR A 77 -11.277 -9.041 -31.498 1.00 46.78 O
+ANISOU 562 OG1 THR A 77 6374 5641 5757 -165 507 -279 O
+ATOM 563 CG2 THR A 77 -11.677 -8.033 -33.637 1.00 44.69 C
+ANISOU 563 CG2 THR A 77 5923 5486 5568 -210 405 -272 C
+ATOM 564 N CYS A 78 -11.496 -12.435 -32.033 1.00 50.28 N
+ANISOU 564 N CYS A 78 6990 5924 6188 -338 814 -286 N
+ATOM 565 CA CYS A 78 -10.739 -13.646 -31.587 1.00 46.96 C
+ANISOU 565 CA CYS A 78 6711 5367 5761 -289 955 -214 C
+ATOM 566 C CYS A 78 -11.053 -14.787 -32.559 1.00 49.46 C
+ANISOU 566 C CYS A 78 7079 5587 6126 -435 1104 -293 C
+ATOM 567 O CYS A 78 -10.411 -15.828 -32.559 1.00 51.48 O
+ANISOU 567 O CYS A 78 7458 5693 6407 -405 1257 -244 O
+ATOM 568 CB CYS A 78 -11.178 -14.092 -30.182 1.00 53.40 C
+ANISOU 568 CB CYS A 78 7600 6145 6541 -234 1071 -151 C
+ATOM 569 SG CYS A 78 -12.881 -14.758 -30.242 1.00 51.94 S
+ANISOU 569 SG CYS A 78 7387 5928 6417 -420 1238 -249 S
+ATOM 570 N ALA A 79 -12.058 -14.598 -33.405 1.00 53.34 N
+ANISOU 570 N ALA A 79 7469 6170 6626 -598 1068 -418 N
+ATOM 571 CA ALA A 79 -12.515 -15.685 -34.236 1.00 55.83 C
+ANISOU 571 CA ALA A 79 7829 6416 6967 -787 1210 -543 C
+ATOM 572 C ALA A 79 -12.550 -15.316 -35.744 1.00 59.35 C
+ANISOU 572 C ALA A 79 8188 7002 7360 -894 1092 -650 C
+ATOM 573 O ALA A 79 -13.139 -16.061 -36.535 1.00 55.41 O
+ANISOU 573 O ALA A 79 7693 6513 6847 -1099 1172 -802 O
+ATOM 574 CB ALA A 79 -13.912 -16.109 -33.759 1.00 59.21 C
+ANISOU 574 CB ALA A 79 8205 6858 7433 -940 1313 -616 C
+ATOM 575 N ALA A 80 -11.913 -14.208 -36.131 1.00 51.54 N
+ANISOU 575 N ALA A 80 7126 6121 6335 -767 917 -576 N
+ATOM 576 CA ALA A 80 -12.025 -13.689 -37.496 1.00 52.60 C
+ANISOU 576 CA ALA A 80 7161 6426 6398 -833 799 -635 C
+ATOM 577 C ALA A 80 -10.641 -13.659 -38.187 1.00 52.00 C
+ANISOU 577 C ALA A 80 7168 6282 6305 -734 797 -581 C
+ATOM 578 O ALA A 80 -9.618 -13.161 -37.620 1.00 49.22 O
+ANISOU 578 O ALA A 80 6840 5858 6002 -561 760 -450 O
+ATOM 579 CB ALA A 80 -12.672 -12.314 -37.499 1.00 53.13 C
+ANISOU 579 CB ALA A 80 7044 6690 6453 -769 627 -571 C
+ATOM 580 N TYR A 81 -10.617 -14.269 -39.382 1.00 50.25 N
+ANISOU 580 N TYR A 81 6991 6091 6011 -860 853 -698 N
+ATOM 581 CA TYR A 81 -9.473 -14.232 -40.301 1.00 47.17 C
+ANISOU 581 CA TYR A 81 6664 5673 5582 -786 868 -665 C
+ATOM 582 C TYR A 81 -9.695 -13.111 -41.287 1.00 50.29 C
+ANISOU 582 C TYR A 81 6913 6311 5882 -771 694 -634 C
+ATOM 583 O TYR A 81 -10.787 -12.986 -41.832 1.00 51.07 O
+ANISOU 583 O TYR A 81 6906 6613 5885 -903 620 -722 O
+ATOM 584 CB TYR A 81 -9.426 -15.493 -41.146 1.00 51.08 C
+ANISOU 584 CB TYR A 81 7306 6080 6021 -943 1048 -833 C
+ATOM 585 CG TYR A 81 -9.189 -16.735 -40.354 1.00 58.36 C
+ANISOU 585 CG TYR A 81 8398 6724 7050 -954 1282 -854 C
+ATOM 586 CD1 TYR A 81 -8.089 -16.833 -39.537 1.00 55.81 C
+ANISOU 586 CD1 TYR A 81 8143 6231 6829 -740 1353 -672 C
+ATOM 587 CD2 TYR A 81 -10.088 -17.800 -40.389 1.00 63.94 C
+ANISOU 587 CD2 TYR A 81 9183 7347 7763 -1179 1441 -1042 C
+ATOM 588 CE1 TYR A 81 -7.853 -17.958 -38.801 1.00 58.92 C
+ANISOU 588 CE1 TYR A 81 8687 6381 7317 -708 1583 -641 C
+ATOM 589 CE2 TYR A 81 -9.854 -18.945 -39.642 1.00 66.35 C
+ANISOU 589 CE2 TYR A 81 9659 7359 8190 -1168 1700 -1029 C
+ATOM 590 CZ TYR A 81 -8.713 -19.009 -38.869 1.00 60.72 C
+ANISOU 590 CZ TYR A 81 9018 6485 7566 -910 1772 -810 C
+ATOM 591 OH TYR A 81 -8.409 -20.106 -38.119 1.00 67.42 O
+ANISOU 591 OH TYR A 81 10026 7058 8530 -846 2038 -740 O
+ATOM 592 N PRO A 82 -8.665 -12.297 -41.547 1.00 49.08 N
+ANISOU 592 N PRO A 82 6740 6152 5756 -609 636 -494 N
+ATOM 593 CA PRO A 82 -8.810 -11.345 -42.651 1.00 47.57 C
+ANISOU 593 CA PRO A 82 6433 6172 5466 -585 518 -444 C
+ATOM 594 C PRO A 82 -8.910 -12.091 -43.994 1.00 51.19 C
+ANISOU 594 C PRO A 82 6956 6741 5751 -719 580 -581 C
+ATOM 595 O PRO A 82 -8.241 -13.098 -44.143 1.00 50.40 O
+ANISOU 595 O PRO A 82 7018 6474 5657 -755 739 -662 O
+ATOM 596 CB PRO A 82 -7.518 -10.563 -42.588 1.00 45.77 C
+ANISOU 596 CB PRO A 82 6205 5851 5335 -407 504 -279 C
+ATOM 597 CG PRO A 82 -6.511 -11.495 -41.974 1.00 47.02 C
+ANISOU 597 CG PRO A 82 6497 5788 5579 -368 638 -280 C
+ATOM 598 CD PRO A 82 -7.288 -12.383 -41.033 1.00 48.95 C
+ANISOU 598 CD PRO A 82 6803 5951 5844 -460 702 -380 C
+ATOM 599 N THR A 83 -9.757 -11.627 -44.924 1.00 48.49 N
+ANISOU 599 N THR A 83 6489 6685 5247 -788 466 -606 N
+ATOM 600 CA THR A 83 -9.762 -12.153 -46.307 1.00 51.50 C
+ANISOU 600 CA THR A 83 6925 7231 5411 -907 499 -734 C
+ATOM 601 C THR A 83 -9.429 -11.095 -47.342 1.00 49.00 C
+ANISOU 601 C THR A 83 6517 7124 4975 -771 406 -571 C
+ATOM 602 O THR A 83 -9.557 -11.323 -48.533 1.00 50.94 O
+ANISOU 602 O THR A 83 6777 7584 4992 -851 400 -650 O
+ATOM 603 CB THR A 83 -11.157 -12.749 -46.647 1.00 56.46 C
+ANISOU 603 CB THR A 83 7475 8093 5884 -1158 444 -940 C
+ATOM 604 OG1 THR A 83 -12.178 -11.809 -46.291 1.00 57.08 O
+ANISOU 604 OG1 THR A 83 7322 8384 5979 -1111 275 -821 O
+ATOM 605 CG2 THR A 83 -11.377 -14.007 -45.846 1.00 57.41 C
+ANISOU 605 CG2 THR A 83 7729 7967 6115 -1324 602 -1126 C
+ATOM 606 N SER A 84 -9.123 -9.892 -46.868 1.00 49.80 N
+ANISOU 606 N SER A 84 6516 7183 5220 -575 335 -345 N
+ATOM 607 CA SER A 84 -8.642 -8.809 -47.689 1.00 51.09 C
+ANISOU 607 CA SER A 84 6609 7464 5339 -413 295 -145 C
+ATOM 608 C SER A 84 -8.017 -7.870 -46.668 1.00 49.54 C
+ANISOU 608 C SER A 84 6376 7040 5405 -251 294 24 C
+ATOM 609 O SER A 84 -8.128 -8.093 -45.490 1.00 47.99 O
+ANISOU 609 O SER A 84 6201 6679 5354 -276 298 -28 O
+ATOM 610 CB SER A 84 -9.795 -8.069 -48.389 1.00 56.08 C
+ANISOU 610 CB SER A 84 7050 8454 5800 -400 154 -60 C
+ATOM 611 OG SER A 84 -10.589 -7.330 -47.413 1.00 52.75 O
+ANISOU 611 OG SER A 84 6487 8017 5536 -337 76 32 O
+ATOM 612 N ASP A 85 -7.382 -6.806 -47.126 1.00 46.38 N
+ANISOU 612 N ASP A 85 5924 6639 5057 -96 299 222 N
+ATOM 613 CA ASP A 85 -6.983 -5.755 -46.253 1.00 49.05 C
+ANISOU 613 CA ASP A 85 6206 6797 5631 21 291 358 C
+ATOM 614 C ASP A 85 -8.286 -5.304 -45.638 1.00 50.62 C
+ANISOU 614 C ASP A 85 6295 7088 5849 14 202 357 C
+ATOM 615 O ASP A 85 -9.334 -5.212 -46.322 1.00 54.44 O
+ANISOU 615 O ASP A 85 6675 7839 6170 0 136 381 O
+ATOM 616 CB ASP A 85 -6.341 -4.609 -47.058 1.00 47.60 C
+ANISOU 616 CB ASP A 85 5967 6628 5489 170 330 579 C
+ATOM 617 CG ASP A 85 -4.900 -4.925 -47.559 1.00 52.73 C
+ANISOU 617 CG ASP A 85 6707 7157 6169 197 442 609 C
+ATOM 618 OD1 ASP A 85 -4.277 -5.936 -47.150 1.00 52.35 O
+ANISOU 618 OD1 ASP A 85 6760 6983 6148 128 494 481 O
+ATOM 619 OD2 ASP A 85 -4.368 -4.108 -48.369 1.00 56.01 O
+ANISOU 619 OD2 ASP A 85 7082 7598 6598 307 501 791 O
+ATOM 620 N VAL A 86 -8.255 -4.968 -44.377 1.00 45.98 N
+ANISOU 620 N VAL A 86 5710 6311 5446 32 200 343 N
+ATOM 621 CA VAL A 86 -9.522 -4.737 -43.682 1.00 45.59 C
+ANISOU 621 CA VAL A 86 5573 6331 5415 18 147 316 C
+ATOM 622 C VAL A 86 -9.338 -3.725 -42.597 1.00 43.07 C
+ANISOU 622 C VAL A 86 5245 5812 5305 107 169 375 C
+ATOM 623 O VAL A 86 -8.275 -3.619 -42.020 1.00 44.22 O
+ANISOU 623 O VAL A 86 5470 5760 5572 112 201 355 O
+ATOM 624 CB VAL A 86 -10.078 -6.072 -43.148 1.00 48.01 C
+ANISOU 624 CB VAL A 86 5939 6654 5647 -143 144 117 C
+ATOM 625 CG1 VAL A 86 -9.082 -6.710 -42.219 1.00 49.95 C
+ANISOU 625 CG1 VAL A 86 6328 6652 5997 -170 206 38 C
+ATOM 626 CG2 VAL A 86 -11.442 -5.939 -42.465 1.00 50.17 C
+ANISOU 626 CG2 VAL A 86 6107 7020 5936 -171 105 89 C
+ATOM 627 N THR A 87 -10.371 -2.925 -42.367 1.00 45.19 N
+ANISOU 627 N THR A 87 5406 6148 5615 181 159 451 N
+ATOM 628 CA THR A 87 -10.350 -1.923 -41.352 1.00 45.50 C
+ANISOU 628 CA THR A 87 5452 5991 5845 259 209 481 C
+ATOM 629 C THR A 87 -11.421 -2.288 -40.351 1.00 47.74 C
+ANISOU 629 C THR A 87 5716 6302 6122 213 199 378 C
+ATOM 630 O THR A 87 -12.526 -2.582 -40.730 1.00 47.10 O
+ANISOU 630 O THR A 87 5523 6431 5940 201 166 397 O
+ATOM 631 CB THR A 87 -10.656 -0.544 -41.917 1.00 50.80 C
+ANISOU 631 CB THR A 87 6025 6671 6605 425 268 690 C
+ATOM 632 OG1 THR A 87 -9.617 -0.209 -42.839 1.00 51.07 O
+ANISOU 632 OG1 THR A 87 6082 6667 6653 467 301 799 O
+ATOM 633 CG2 THR A 87 -10.675 0.502 -40.782 1.00 50.21 C
+ANISOU 633 CG2 THR A 87 5986 6346 6744 486 359 679 C
+ATOM 634 N ILE A 88 -11.062 -2.273 -39.075 1.00 47.12 N
+ANISOU 634 N ILE A 88 5735 6028 6137 183 227 271 N
+ATOM 635 CA ILE A 88 -11.915 -2.724 -38.016 1.00 47.67 C
+ANISOU 635 CA ILE A 88 5818 6102 6192 138 240 168 C
+ATOM 636 C ILE A 88 -11.927 -1.719 -36.867 1.00 42.11 C
+ANISOU 636 C ILE A 88 5161 5214 5622 206 309 145 C
+ATOM 637 O ILE A 88 -10.907 -1.494 -36.286 1.00 43.07 O
+ANISOU 637 O ILE A 88 5383 5181 5801 181 309 80 O
+ATOM 638 CB ILE A 88 -11.395 -4.068 -37.512 1.00 49.90 C
+ANISOU 638 CB ILE A 88 6214 6349 6396 13 220 34 C
+ATOM 639 CG1 ILE A 88 -11.587 -5.112 -38.628 1.00 49.65 C
+ANISOU 639 CG1 ILE A 88 6153 6480 6231 -76 191 16 C
+ATOM 640 CG2 ILE A 88 -12.108 -4.473 -36.212 1.00 51.61 C
+ANISOU 640 CG2 ILE A 88 6470 6528 6608 -19 261 -58 C
+ATOM 641 CD1 ILE A 88 -10.896 -6.432 -38.386 1.00 49.71 C
+ANISOU 641 CD1 ILE A 88 6291 6410 6186 -176 218 -87 C
+ATOM 642 N GLU A 89 -13.099 -1.193 -36.519 1.00 43.90 N
+ANISOU 642 N GLU A 89 5312 5478 5890 282 372 184 N
+ATOM 643 CA GLU A 89 -13.278 -0.421 -35.290 1.00 47.43 C
+ANISOU 643 CA GLU A 89 5831 5749 6437 331 467 118 C
+ATOM 644 C GLU A 89 -13.369 -1.368 -34.118 1.00 48.10 C
+ANISOU 644 C GLU A 89 6014 5828 6434 235 456 -33 C
+ATOM 645 O GLU A 89 -14.208 -2.238 -34.131 1.00 46.09 O
+ANISOU 645 O GLU A 89 5699 5711 6099 192 450 -38 O
+ATOM 646 CB GLU A 89 -14.570 0.378 -35.316 1.00 52.55 C
+ANISOU 646 CB GLU A 89 6361 6442 7161 470 572 230 C
+ATOM 647 CG GLU A 89 -14.633 1.492 -36.347 1.00 63.41 C
+ANISOU 647 CG GLU A 89 7637 7813 8643 621 629 431 C
+ATOM 648 CD GLU A 89 -15.842 2.407 -36.147 1.00 73.77 C
+ANISOU 648 CD GLU A 89 8843 9123 10063 800 777 562 C
+ATOM 649 OE1 GLU A 89 -16.733 2.070 -35.336 1.00 80.53 O
+ANISOU 649 OE1 GLU A 89 9673 10027 10895 795 819 497 O
+ATOM 650 OE2 GLU A 89 -15.887 3.472 -36.793 1.00 76.86 O
+ANISOU 650 OE2 GLU A 89 9175 9453 10575 962 875 747 O
+ATOM 651 N THR A 90 -12.531 -1.166 -33.102 1.00 44.70 N
+ANISOU 651 N THR A 90 5722 5248 6013 199 462 -150 N
+ATOM 652 CA THR A 90 -12.427 -2.084 -32.002 1.00 43.34 C
+ANISOU 652 CA THR A 90 5650 5087 5727 129 448 -262 C
+ATOM 653 C THR A 90 -13.337 -1.652 -30.827 1.00 47.39 C
+ANISOU 653 C THR A 90 6210 5556 6240 178 561 -329 C
+ATOM 654 O THR A 90 -13.940 -0.586 -30.855 1.00 46.89 O
+ANISOU 654 O THR A 90 6109 5423 6283 268 659 -299 O
+ATOM 655 CB THR A 90 -10.937 -2.167 -31.551 1.00 42.54 C
+ANISOU 655 CB THR A 90 5651 4917 5596 69 368 -337 C
+ATOM 656 OG1 THR A 90 -10.480 -0.884 -31.081 1.00 46.16 O
+ANISOU 656 OG1 THR A 90 6155 5238 6145 78 400 -410 O
+ATOM 657 CG2 THR A 90 -10.008 -2.601 -32.693 1.00 42.77 C
+ANISOU 657 CG2 THR A 90 5633 4980 5636 38 287 -260 C
+ATOM 658 N HIS A 91 -13.394 -2.452 -29.757 1.00 47.53 N
+ANISOU 658 N HIS A 91 6321 5601 6138 136 573 -409 N
+ATOM 659 CA HIS A 91 -14.121 -2.027 -28.523 1.00 50.54 C
+ANISOU 659 CA HIS A 91 6775 5936 6488 184 696 -488 C
+ATOM 660 C HIS A 91 -15.577 -1.689 -28.823 1.00 48.63 C
+ANISOU 660 C HIS A 91 6407 5732 6336 269 818 -403 C
+ATOM 661 O HIS A 91 -16.087 -0.683 -28.370 1.00 47.55 O
+ANISOU 661 O HIS A 91 6289 5503 6273 358 945 -426 O
+ATOM 662 CB HIS A 91 -13.449 -0.819 -27.839 1.00 53.09 C
+ANISOU 662 CB HIS A 91 7212 6116 6841 192 723 -613 C
+ATOM 663 CG HIS A 91 -12.037 -1.062 -27.377 1.00 53.84 C
+ANISOU 663 CG HIS A 91 7400 6222 6835 99 592 -706 C
+ATOM 664 ND1 HIS A 91 -10.998 -1.282 -28.245 1.00 52.95 N
+ANISOU 664 ND1 HIS A 91 7230 6124 6762 50 467 -650 N
+ATOM 665 CD2 HIS A 91 -11.494 -1.106 -26.132 1.00 56.62 C
+ANISOU 665 CD2 HIS A 91 7877 6601 7033 54 565 -841 C
+ATOM 666 CE1 HIS A 91 -9.869 -1.434 -27.568 1.00 52.38 C
+ANISOU 666 CE1 HIS A 91 7223 6088 6589 -18 367 -735 C
+ATOM 667 NE2 HIS A 91 -10.149 -1.348 -26.282 1.00 55.87 N
+ANISOU 667 NE2 HIS A 91 7774 6556 6899 -20 411 -852 N
+ATOM 668 N LYS A 92 -16.228 -2.521 -29.624 1.00 49.04 N
+ANISOU 668 N LYS A 92 6318 5927 6386 236 787 -308 N
+ATOM 669 CA LYS A 92 -17.650 -2.390 -29.844 1.00 50.58 C
+ANISOU 669 CA LYS A 92 6348 6224 6644 297 884 -219 C
+ATOM 670 C LYS A 92 -18.507 -3.326 -28.988 1.00 47.54 C
+ANISOU 670 C LYS A 92 5964 5904 6193 250 976 -250 C
+ATOM 671 O LYS A 92 -19.654 -3.503 -29.328 1.00 46.77 O
+ANISOU 671 O LYS A 92 5686 5937 6144 257 1030 -172 O
+ATOM 672 CB LYS A 92 -17.947 -2.701 -31.306 1.00 53.04 C
+ANISOU 672 CB LYS A 92 6468 6705 6979 263 785 -107 C
+ATOM 673 CG LYS A 92 -17.183 -1.817 -32.271 1.00 56.58 C
+ANISOU 673 CG LYS A 92 6898 7107 7489 325 715 -36 C
+ATOM 674 CD LYS A 92 -17.486 -0.352 -32.061 1.00 58.78 C
+ANISOU 674 CD LYS A 92 7167 7262 7905 494 841 28 C
+ATOM 675 CE LYS A 92 -18.585 0.113 -32.975 1.00 67.73 C
+ANISOU 675 CE LYS A 92 8061 8564 9107 618 876 223 C
+ATOM 676 NZ LYS A 92 -18.423 1.591 -33.141 1.00 70.69 N
+ANISOU 676 NZ LYS A 92 8453 8766 9637 795 997 324 N
+ATOM 677 N GLU A 93 -17.977 -3.940 -27.920 1.00 48.14 N
+ANISOU 677 N GLU A 93 6220 5912 6155 204 998 -342 N
+ATOM 678 CA GLU A 93 -18.834 -4.744 -26.990 1.00 51.58 C
+ANISOU 678 CA GLU A 93 6674 6388 6535 183 1133 -348 C
+ATOM 679 C GLU A 93 -20.133 -4.043 -26.630 1.00 53.52 C
+ANISOU 679 C GLU A 93 6808 6660 6864 287 1296 -305 C
+ATOM 680 O GLU A 93 -21.165 -4.650 -26.637 1.00 58.70 O
+ANISOU 680 O GLU A 93 7330 7419 7554 250 1380 -249 O
+ATOM 681 CB GLU A 93 -18.112 -5.078 -25.684 1.00 53.98 C
+ANISOU 681 CB GLU A 93 7203 6619 6686 189 1166 -429 C
+ATOM 682 CG GLU A 93 -18.999 -5.656 -24.586 1.00 58.34 C
+ANISOU 682 CG GLU A 93 7798 7194 7171 208 1345 -418 C
+ATOM 683 CD GLU A 93 -18.194 -6.346 -23.498 1.00 59.78 C
+ANISOU 683 CD GLU A 93 8187 7360 7166 207 1352 -449 C
+ATOM 684 OE1 GLU A 93 -17.556 -5.652 -22.668 1.00 64.37 O
+ANISOU 684 OE1 GLU A 93 8915 7917 7626 267 1330 -538 O
+ATOM 685 OE2 GLU A 93 -18.184 -7.597 -23.528 1.00 52.88 O
+ANISOU 685 OE2 GLU A 93 7321 6504 6265 142 1381 -382 O
+ATOM 686 N GLU A 94 -20.084 -2.768 -26.311 1.00 59.72 N
+ANISOU 686 N GLU A 94 7647 7342 7699 413 1362 -331 N
+ATOM 687 CA GLU A 94 -21.265 -2.097 -25.790 1.00 66.89 C
+ANISOU 687 CA GLU A 94 8483 8242 8687 544 1565 -289 C
+ATOM 688 C GLU A 94 -22.389 -2.061 -26.822 1.00 70.98 C
+ANISOU 688 C GLU A 94 8697 8926 9344 581 1575 -124 C
+ATOM 689 O GLU A 94 -23.572 -2.215 -26.481 1.00 76.40 O
+ANISOU 689 O GLU A 94 9243 9704 10081 626 1721 -54 O
+ATOM 690 CB GLU A 94 -20.887 -0.700 -25.315 1.00 74.24 C
+ANISOU 690 CB GLU A 94 9560 8986 9660 665 1660 -370 C
+ATOM 691 CG GLU A 94 -20.302 -0.701 -23.891 1.00 88.53 C
+ANISOU 691 CG GLU A 94 11642 10696 11297 640 1723 -551 C
+ATOM 692 CD GLU A 94 -21.356 -0.505 -22.760 1.00104.83 C
+ANISOU 692 CD GLU A 94 13759 12740 13331 745 1979 -573 C
+ATOM 693 OE1 GLU A 94 -20.982 0.024 -21.666 1.00102.89 O
+ANISOU 693 OE1 GLU A 94 13744 12388 12962 767 2076 -740 O
+ATOM 694 OE2 GLU A 94 -22.562 -0.867 -22.947 1.00106.29 O
+ANISOU 694 OE2 GLU A 94 13749 13029 13605 797 2092 -434 O
+ATOM 695 N ALA A 95 -22.007 -1.909 -28.091 1.00 68.41 N
+ANISOU 695 N ALA A 95 8255 8672 9065 556 1414 -53 N
+ATOM 696 CA ALA A 95 -22.956 -1.709 -29.182 1.00 66.09 C
+ANISOU 696 CA ALA A 95 7658 8583 8869 608 1388 116 C
+ATOM 697 C ALA A 95 -23.662 -2.996 -29.528 1.00 66.44 C
+ANISOU 697 C ALA A 95 7523 8851 8867 435 1328 127 C
+ATOM 698 O ALA A 95 -24.779 -2.940 -30.017 1.00 70.13 O
+ANISOU 698 O ALA A 95 7710 9533 9402 465 1352 251 O
+ATOM 699 CB ALA A 95 -22.245 -1.163 -30.422 1.00 66.10 C
+ANISOU 699 CB ALA A 95 7613 8606 8896 636 1238 189 C
+ATOM 700 N ILE A 96 -23.008 -4.142 -29.324 1.00 64.35 N
+ANISOU 700 N ILE A 96 7407 8544 8498 253 1257 4 N
+ATOM 701 CA ILE A 96 -23.650 -5.436 -29.582 1.00 69.19 C
+ANISOU 701 CA ILE A 96 7886 9314 9088 56 1244 -17 C
+ATOM 702 C ILE A 96 -24.290 -6.032 -28.311 1.00 75.00 C
+ANISOU 702 C ILE A 96 8682 9987 9825 30 1440 -50 C
+ATOM 703 O ILE A 96 -24.815 -7.127 -28.332 1.00 68.54 O
+ANISOU 703 O ILE A 96 7782 9246 9011 -142 1479 -77 O
+ATOM 704 CB ILE A 96 -22.743 -6.492 -30.279 1.00 69.26 C
+ANISOU 704 CB ILE A 96 7991 9314 9009 -136 1099 -110 C
+ATOM 705 CG1 ILE A 96 -21.443 -6.740 -29.528 1.00 72.23 C
+ANISOU 705 CG1 ILE A 96 8677 9458 9305 -123 1101 -195 C
+ATOM 706 CG2 ILE A 96 -22.463 -6.154 -31.716 1.00 67.05 C
+ANISOU 706 CG2 ILE A 96 7581 9181 8715 -151 922 -66 C
+ATOM 707 CD1 ILE A 96 -21.463 -8.031 -28.757 1.00 71.63 C
+ANISOU 707 CD1 ILE A 96 8723 9309 9184 -245 1210 -253 C
+ATOM 708 N MET A 97 -24.258 -5.310 -27.201 1.00 82.61 N
+ANISOU 708 N MET A 97 9796 10805 10784 194 1584 -55 N
+ATOM 709 CA MET A 97 -25.147 -5.636 -26.099 1.00 87.11 C
+ANISOU 709 CA MET A 97 10364 11365 11366 215 1801 -42 C
+ATOM 710 C MET A 97 -26.325 -4.668 -26.205 1.00 95.61 C
+ANISOU 710 C MET A 97 11196 12551 12577 376 1919 80 C
+ATOM 711 O MET A 97 -27.410 -5.101 -26.587 1.00 94.92 O
+ANISOU 711 O MET A 97 10826 12664 12575 303 1954 163 O
+ATOM 712 CB MET A 97 -24.435 -5.516 -24.761 1.00 78.92 C
+ANISOU 712 CB MET A 97 9648 10134 10203 296 1904 -129 C
+ATOM 713 CG MET A 97 -23.264 -6.468 -24.547 1.00 69.75 C
+ANISOU 713 CG MET A 97 8709 8888 8904 181 1804 -207 C
+ATOM 714 SD MET A 97 -22.432 -5.914 -23.038 1.00 73.23 S
+ANISOU 714 SD MET A 97 9478 9183 9162 316 1882 -298 S
+ATOM 715 CE MET A 97 -21.484 -7.324 -22.587 1.00 70.81 C
+ANISOU 715 CE MET A 97 9359 8848 8698 213 1836 -305 C
+ATOM 716 N LEU A 98 -26.060 -3.361 -25.977 1.00101.64 N
+ANISOU 716 N LEU A 98 12055 13191 13371 583 1974 95 N
+ATOM 717 CA LEU A 98 -27.090 -2.306 -25.727 1.00104.44 C
+ANISOU 717 CA LEU A 98 12260 13563 13858 803 2175 216 C
+ATOM 718 C LEU A 98 -27.843 -1.768 -26.965 1.00 99.32 C
+ANISOU 718 C LEU A 98 11253 13135 13349 890 2107 411 C
+ATOM 719 O LEU A 98 -27.308 -1.714 -28.071 1.00 91.78 O
+ANISOU 719 O LEU A 98 10232 12263 12378 839 1898 441 O
+ATOM 720 CB LEU A 98 -26.469 -1.140 -24.941 1.00 98.56 C
+ANISOU 720 CB LEU A 98 11797 12554 13097 977 2303 129 C
+TER 721 LEU A 98
+ATOM 722 N ALA B 2 -32.420 -24.500 -28.343 1.00 55.40 N
+ANISOU 722 N ALA B 2 8165 6777 6106 -670 -1057 -125 N
+ATOM 723 CA ALA B 2 -32.280 -23.018 -28.309 1.00 49.74 C
+ANISOU 723 CA ALA B 2 7221 6215 5463 -512 -965 -28 C
+ATOM 724 C ALA B 2 -30.968 -22.594 -27.656 1.00 49.10 C
+ANISOU 724 C ALA B 2 7123 6073 5460 -324 -756 -44 C
+ATOM 725 O ALA B 2 -30.475 -23.240 -26.699 1.00 48.76 O
+ANISOU 725 O ALA B 2 7101 5932 5490 -308 -687 -81 O
+ATOM 726 CB ALA B 2 -33.452 -22.398 -27.562 1.00 46.79 C
+ANISOU 726 CB ALA B 2 6548 6005 5225 -580 -1026 92 C
+ATOM 727 N THR B 3 -30.475 -21.450 -28.119 1.00 46.70 N
+ANISOU 727 N THR B 3 6765 5842 5136 -203 -668 1 N
+ATOM 728 CA THR B 3 -29.337 -20.783 -27.525 1.00 45.09 C
+ANISOU 728 CA THR B 3 6493 5632 5006 -79 -488 8 C
+ATOM 729 C THR B 3 -29.711 -19.332 -27.227 1.00 42.65 C
+ANISOU 729 C THR B 3 6022 5395 4786 -46 -461 119 C
+ATOM 730 O THR B 3 -30.163 -18.603 -28.102 1.00 49.78 O
+ANISOU 730 O THR B 3 6948 6349 5617 -31 -515 186 O
+ATOM 731 CB THR B 3 -28.152 -20.886 -28.525 1.00 48.51 C
+ANISOU 731 CB THR B 3 7083 6061 5285 14 -383 -53 C
+ATOM 732 OG1 THR B 3 -27.960 -22.272 -28.848 1.00 53.59 O
+ANISOU 732 OG1 THR B 3 7925 6609 5827 21 -421 -170 O
+ATOM 733 CG2 THR B 3 -26.865 -20.283 -27.959 1.00 46.16 C
+ANISOU 733 CG2 THR B 3 6683 5804 5049 105 -200 -45 C
+ATOM 734 N TYR B 4 -29.515 -18.935 -25.980 1.00 41.02 N
+ANISOU 734 N TYR B 4 5685 5178 4720 -22 -381 136 N
+ATOM 735 CA TYR B 4 -29.849 -17.616 -25.484 1.00 41.59 C
+ANISOU 735 CA TYR B 4 5649 5273 4878 26 -345 216 C
+ATOM 736 C TYR B 4 -28.595 -16.874 -25.182 1.00 37.08 C
+ANISOU 736 C TYR B 4 5099 4664 4323 55 -200 205 C
+ATOM 737 O TYR B 4 -27.552 -17.444 -25.084 1.00 42.67 O
+ANISOU 737 O TYR B 4 5829 5376 5007 49 -128 142 O
+ATOM 738 CB TYR B 4 -30.686 -17.729 -24.208 1.00 37.93 C
+ANISOU 738 CB TYR B 4 5032 4839 4538 12 -366 231 C
+ATOM 739 CG TYR B 4 -31.986 -18.470 -24.482 1.00 40.65 C
+ANISOU 739 CG TYR B 4 5310 5268 4864 -68 -514 257 C
+ATOM 740 CD1 TYR B 4 -32.953 -17.916 -25.304 1.00 41.09 C
+ANISOU 740 CD1 TYR B 4 5314 5421 4875 -38 -621 333 C
+ATOM 741 CD2 TYR B 4 -32.253 -19.691 -23.893 1.00 39.18 C
+ANISOU 741 CD2 TYR B 4 5113 5074 4699 -188 -554 219 C
+ATOM 742 CE1 TYR B 4 -34.139 -18.580 -25.546 1.00 44.88 C
+ANISOU 742 CE1 TYR B 4 5690 6029 5332 -146 -773 362 C
+ATOM 743 CE2 TYR B 4 -33.429 -20.383 -24.132 1.00 44.73 C
+ANISOU 743 CE2 TYR B 4 5750 5865 5377 -328 -695 249 C
+ATOM 744 CZ TYR B 4 -34.369 -19.827 -24.951 1.00 49.31 C
+ANISOU 744 CZ TYR B 4 6235 6582 5915 -317 -807 316 C
+ATOM 745 OH TYR B 4 -35.506 -20.526 -25.188 1.00 53.31 O
+ANISOU 745 OH TYR B 4 6643 7219 6390 -490 -962 347 O
+ATOM 746 N LYS B 5 -28.735 -15.589 -25.005 1.00 42.61 N
+ANISOU 746 N LYS B 5 5794 5333 5063 87 -164 270 N
+ATOM 747 CA LYS B 5 -27.647 -14.685 -24.656 1.00 46.72 C
+ANISOU 747 CA LYS B 5 6346 5805 5598 57 -42 270 C
+ATOM 748 C LYS B 5 -27.871 -14.311 -23.218 1.00 44.65 C
+ANISOU 748 C LYS B 5 6004 5508 5453 71 -18 246 C
+ATOM 749 O LYS B 5 -28.949 -13.910 -22.869 1.00 45.52 O
+ANISOU 749 O LYS B 5 6085 5600 5610 146 -64 281 O
+ATOM 750 CB LYS B 5 -27.735 -13.411 -25.451 1.00 51.37 C
+ANISOU 750 CB LYS B 5 7063 6323 6130 68 -27 364 C
+ATOM 751 CG LYS B 5 -27.674 -13.596 -26.941 1.00 58.63 C
+ANISOU 751 CG LYS B 5 8089 7285 6902 63 -56 410 C
+ATOM 752 CD LYS B 5 -26.289 -13.986 -27.387 1.00 70.28 C
+ANISOU 752 CD LYS B 5 9582 8829 8291 -17 60 365 C
+ATOM 753 CE LYS B 5 -26.281 -14.277 -28.899 1.00 79.59 C
+ANISOU 753 CE LYS B 5 10887 10066 9288 -6 42 396 C
+ATOM 754 NZ LYS B 5 -26.107 -13.052 -29.737 1.00 78.80 N
+ANISOU 754 NZ LYS B 5 10935 9919 9086 -50 88 523 N
+ATOM 755 N VAL B 6 -26.848 -14.482 -22.400 1.00 44.73 N
+ANISOU 755 N VAL B 6 5968 5536 5490 12 52 185 N
+ATOM 756 CA VAL B 6 -26.898 -14.160 -21.017 1.00 43.45 C
+ANISOU 756 CA VAL B 6 5755 5350 5403 9 75 149 C
+ATOM 757 C VAL B 6 -25.875 -13.071 -20.817 1.00 41.71 C
+ANISOU 757 C VAL B 6 5600 5078 5168 -88 150 141 C
+ATOM 758 O VAL B 6 -24.703 -13.264 -21.100 1.00 40.03 O
+ANISOU 758 O VAL B 6 5351 4944 4913 -178 196 125 O
+ATOM 759 CB VAL B 6 -26.496 -15.357 -20.132 1.00 43.61 C
+ANISOU 759 CB VAL B 6 5675 5449 5445 0 68 89 C
+ATOM 760 CG1 VAL B 6 -26.579 -14.975 -18.662 1.00 45.36 C
+ANISOU 760 CG1 VAL B 6 5860 5659 5714 -5 90 55 C
+ATOM 761 CG2 VAL B 6 -27.382 -16.547 -20.422 1.00 42.80 C
+ANISOU 761 CG2 VAL B 6 5551 5370 5340 37 -7 99 C
+ATOM 762 N LYS B 7 -26.334 -11.940 -20.314 1.00 40.23 N
+ANISOU 762 N LYS B 7 5512 4765 5007 -71 162 150 N
+ATOM 763 CA LYS B 7 -25.489 -10.806 -20.042 1.00 45.32 C
+ANISOU 763 CA LYS B 7 6277 5311 5631 -205 217 138 C
+ATOM 764 C LYS B 7 -25.268 -10.732 -18.545 1.00 45.32 C
+ANISOU 764 C LYS B 7 6243 5315 5660 -241 224 48 C
+ATOM 765 O LYS B 7 -26.230 -10.649 -17.762 1.00 42.09 O
+ANISOU 765 O LYS B 7 5848 4860 5282 -112 213 21 O
+ATOM 766 CB LYS B 7 -26.179 -9.567 -20.522 1.00 45.61 C
+ANISOU 766 CB LYS B 7 6527 5150 5652 -141 218 203 C
+ATOM 767 CG LYS B 7 -25.518 -8.255 -20.177 1.00 54.48 C
+ANISOU 767 CG LYS B 7 7863 6090 6747 -291 265 191 C
+ATOM 768 CD LYS B 7 -26.348 -7.148 -20.886 1.00 64.52 C
+ANISOU 768 CD LYS B 7 9392 7132 7990 -162 255 284 C
+ATOM 769 CE LYS B 7 -25.977 -5.744 -20.437 1.00 79.55 C
+ANISOU 769 CE LYS B 7 11603 8759 9861 -274 292 266 C
+ATOM 770 NZ LYS B 7 -26.138 -4.714 -21.507 1.00 86.71 N
+ANISOU 770 NZ LYS B 7 12802 9439 10702 -264 295 396 N
+ATOM 771 N PHE B 8 -24.001 -10.796 -18.153 1.00 44.26 N
+ANISOU 771 N PHE B 8 6044 5273 5500 -411 242 4 N
+ATOM 772 CA PHE B 8 -23.636 -10.739 -16.757 1.00 48.27 C
+ANISOU 772 CA PHE B 8 6521 5811 6006 -472 227 -80 C
+ATOM 773 C PHE B 8 -23.203 -9.366 -16.431 1.00 50.61 C
+ANISOU 773 C PHE B 8 7012 5952 6265 -641 245 -114 C
+ATOM 774 O PHE B 8 -22.332 -8.836 -17.115 1.00 51.85 O
+ANISOU 774 O PHE B 8 7205 6107 6388 -833 269 -77 O
+ATOM 775 CB PHE B 8 -22.495 -11.714 -16.458 1.00 46.54 C
+ANISOU 775 CB PHE B 8 6090 5823 5767 -542 208 -104 C
+ATOM 776 CG PHE B 8 -22.919 -13.133 -16.573 1.00 43.20 C
+ANISOU 776 CG PHE B 8 5543 5501 5370 -371 182 -85 C
+ATOM 777 CD1 PHE B 8 -23.753 -13.684 -15.611 1.00 45.99 C
+ANISOU 777 CD1 PHE B 8 5889 5839 5743 -264 152 -107 C
+ATOM 778 CD2 PHE B 8 -22.561 -13.888 -17.670 1.00 43.53 C
+ANISOU 778 CD2 PHE B 8 5511 5629 5397 -326 196 -45 C
+ATOM 779 CE1 PHE B 8 -24.172 -15.008 -15.719 1.00 45.51 C
+ANISOU 779 CE1 PHE B 8 5756 5836 5697 -151 123 -79 C
+ATOM 780 CE2 PHE B 8 -22.977 -15.203 -17.786 1.00 47.96 C
+ANISOU 780 CE2 PHE B 8 6024 6230 5968 -183 163 -39 C
+ATOM 781 CZ PHE B 8 -23.809 -15.751 -16.817 1.00 42.32 C
+ANISOU 781 CZ PHE B 8 5316 5479 5284 -113 120 -50 C
+ATOM 782 N ILE B 9 -23.818 -8.777 -15.407 1.00 50.12 N
+ANISOU 782 N ILE B 9 7095 5752 6194 -582 242 -186 N
+ATOM 783 CA ILE B 9 -23.293 -7.532 -14.841 1.00 52.49 C
+ANISOU 783 CA ILE B 9 7627 5881 6436 -773 243 -255 C
+ATOM 784 C ILE B 9 -22.569 -7.908 -13.581 1.00 53.51 C
+ANISOU 784 C ILE B 9 7645 6168 6518 -894 195 -352 C
+ATOM 785 O ILE B 9 -23.199 -8.276 -12.624 1.00 53.62 O
+ANISOU 785 O ILE B 9 7645 6206 6520 -744 190 -409 O
+ATOM 786 CB ILE B 9 -24.432 -6.583 -14.587 1.00 57.52 C
+ANISOU 786 CB ILE B 9 8544 6244 7065 -590 275 -283 C
+ATOM 787 CG1 ILE B 9 -25.188 -6.426 -15.903 1.00 59.96 C
+ANISOU 787 CG1 ILE B 9 8902 6461 7416 -426 296 -159 C
+ATOM 788 CG2 ILE B 9 -23.932 -5.267 -13.966 1.00 60.99 C
+ANISOU 788 CG2 ILE B 9 9309 6437 7425 -785 272 -375 C
+ATOM 789 CD1 ILE B 9 -26.172 -5.282 -15.905 1.00 63.59 C
+ANISOU 789 CD1 ILE B 9 9670 6630 7859 -227 324 -158 C
+ATOM 790 N THR B 10 -21.243 -7.928 -13.622 1.00 58.51 N
+ANISOU 790 N THR B 10 8157 6958 7116 -1157 160 -355 N
+ATOM 791 CA THR B 10 -20.440 -8.325 -12.483 1.00 58.08 C
+ANISOU 791 CA THR B 10 7958 7106 7001 -1275 86 -431 C
+ATOM 792 C THR B 10 -19.973 -7.044 -11.813 1.00 70.23 C
+ANISOU 792 C THR B 10 9748 8484 8451 -1550 48 -529 C
+ATOM 793 O THR B 10 -20.144 -5.958 -12.368 1.00 71.35 O
+ANISOU 793 O THR B 10 10161 8360 8588 -1655 87 -519 O
+ATOM 794 CB THR B 10 -19.189 -9.135 -12.876 1.00 58.06 C
+ANISOU 794 CB THR B 10 7627 7434 6998 -1387 54 -376 C
+ATOM 795 OG1 THR B 10 -18.233 -8.281 -13.503 1.00 67.21 O
+ANISOU 795 OG1 THR B 10 8801 8610 8125 -1697 67 -349 O
+ATOM 796 CG2 THR B 10 -19.528 -10.276 -13.818 1.00 59.69 C
+ANISOU 796 CG2 THR B 10 7661 7742 7275 -1147 101 -286 C
+ATOM 797 N PRO B 11 -19.376 -7.160 -10.620 1.00 72.85 N
+ANISOU 797 N PRO B 11 10022 8962 8697 -1676 -39 -622 N
+ATOM 798 CA PRO B 11 -18.837 -5.933 -10.022 1.00 82.51 C
+ANISOU 798 CA PRO B 11 11506 10030 9814 -1997 -96 -729 C
+ATOM 799 C PRO B 11 -17.740 -5.357 -10.913 1.00 82.13 C
+ANISOU 799 C PRO B 11 11402 10036 9765 -2359 -105 -662 C
+ATOM 800 O PRO B 11 -17.601 -4.166 -11.043 1.00 81.04 O
+ANISOU 800 O PRO B 11 11578 9634 9578 -2614 -104 -697 O
+ATOM 801 CB PRO B 11 -18.263 -6.417 -8.685 1.00 79.55 C
+ANISOU 801 CB PRO B 11 10990 9902 9333 -2070 -213 -819 C
+ATOM 802 CG PRO B 11 -19.024 -7.665 -8.373 1.00 77.41 C
+ANISOU 802 CG PRO B 11 10544 9762 9107 -1699 -182 -776 C
+ATOM 803 CD PRO B 11 -19.316 -8.308 -9.700 1.00 70.96 C
+ANISOU 803 CD PRO B 11 9555 8976 8429 -1526 -97 -639 C
+ATOM 804 N GLU B 12 -17.008 -6.230 -11.575 1.00 88.50 N
+ANISOU 804 N GLU B 12 11824 11180 10621 -2365 -98 -558 N
+ATOM 805 CA GLU B 12 -15.873 -5.804 -12.367 1.00 99.06 C
+ANISOU 805 CA GLU B 12 13027 12669 11940 -2715 -89 -484 C
+ATOM 806 C GLU B 12 -16.299 -5.351 -13.766 1.00 93.10 C
+ANISOU 806 C GLU B 12 12432 11697 11242 -2687 35 -371 C
+ATOM 807 O GLU B 12 -15.498 -4.776 -14.476 1.00 97.19 O
+ANISOU 807 O GLU B 12 12930 12268 11727 -3008 67 -299 O
+ATOM 808 CB GLU B 12 -14.832 -6.940 -12.446 1.00112.44 C
+ANISOU 808 CB GLU B 12 14216 14866 13638 -2694 -123 -425 C
+ATOM 809 CG GLU B 12 -14.678 -7.719 -11.130 1.00124.13 C
+ANISOU 809 CG GLU B 12 15529 16561 15070 -2562 -247 -503 C
+ATOM 810 CD GLU B 12 -13.339 -8.441 -10.973 1.00129.71 C
+ANISOU 810 CD GLU B 12 15773 17775 15735 -2649 -327 -459 C
+ATOM 811 OE1 GLU B 12 -12.591 -8.120 -10.015 1.00122.40 O
+ANISOU 811 OE1 GLU B 12 14767 17032 14705 -2906 -469 -526 O
+ATOM 812 OE2 GLU B 12 -13.042 -9.343 -11.788 1.00121.66 O
+ANISOU 812 OE2 GLU B 12 14470 16981 14772 -2441 -255 -362 O
+ATOM 813 N GLY B 13 -17.543 -5.608 -14.166 1.00 81.49 N
+ANISOU 813 N GLY B 13 11109 10009 9842 -2323 99 -344 N
+ATOM 814 CA GLY B 13 -18.037 -5.147 -15.451 1.00 73.28 C
+ANISOU 814 CA GLY B 13 10250 8758 8835 -2271 193 -234 C
+ATOM 815 C GLY B 13 -18.997 -6.122 -16.098 1.00 65.13 C
+ANISOU 815 C GLY B 13 9104 7761 7882 -1867 241 -172 C
+ATOM 816 O GLY B 13 -19.539 -6.995 -15.467 1.00 67.40 O
+ANISOU 816 O GLY B 13 9263 8138 8207 -1617 210 -222 O
+ATOM 817 N GLU B 14 -19.185 -5.957 -17.384 1.00 61.80 N
+ANISOU 817 N GLU B 14 8743 7270 7466 -1838 311 -57 N
+ATOM 818 CA GLU B 14 -20.256 -6.598 -18.125 1.00 63.32 C
+ANISOU 818 CA GLU B 14 8924 7423 7712 -1496 338 2 C
+ATOM 819 C GLU B 14 -19.671 -7.497 -19.189 1.00 56.31 C
+ANISOU 819 C GLU B 14 7774 6809 6810 -1480 388 83 C
+ATOM 820 O GLU B 14 -18.634 -7.194 -19.774 1.00 62.63 O
+ANISOU 820 O GLU B 14 8502 7742 7551 -1731 443 140 O
+ATOM 821 CB GLU B 14 -21.129 -5.544 -18.792 1.00 71.21 C
+ANISOU 821 CB GLU B 14 10284 8074 8699 -1428 362 71 C
+ATOM 822 CG GLU B 14 -22.416 -5.260 -18.043 1.00 86.78 C
+ANISOU 822 CG GLU B 14 12442 9819 10709 -1152 330 6 C
+ATOM 823 CD GLU B 14 -22.957 -3.842 -18.244 1.00101.03 C
+ANISOU 823 CD GLU B 14 14681 11229 12476 -1139 343 36 C
+ATOM 824 OE1 GLU B 14 -22.373 -2.917 -17.631 1.00107.53 O
+ANISOU 824 OE1 GLU B 14 15741 11869 13245 -1388 335 -29 O
+ATOM 825 OE2 GLU B 14 -23.973 -3.658 -18.983 1.00100.60 O
+ANISOU 825 OE2 GLU B 14 14745 11041 12435 -874 348 124 O
+ATOM 826 N LEU B 15 -20.365 -8.587 -19.454 1.00 56.17 N
+ANISOU 826 N LEU B 15 7631 6874 6835 -1191 377 86 N
+ATOM 827 CA LEU B 15 -20.023 -9.507 -20.528 1.00 55.27 C
+ANISOU 827 CA LEU B 15 7340 6967 6692 -1109 425 143 C
+ATOM 828 C LEU B 15 -21.290 -10.308 -20.860 1.00 53.66 C
+ANISOU 828 C LEU B 15 7166 6692 6529 -812 384 148 C
+ATOM 829 O LEU B 15 -22.039 -10.720 -19.940 1.00 50.69 O
+ANISOU 829 O LEU B 15 6774 6269 6216 -671 324 88 O
+ATOM 830 CB LEU B 15 -18.948 -10.454 -20.044 1.00 57.82 C
+ANISOU 830 CB LEU B 15 7356 7605 7007 -1128 426 93 C
+ATOM 831 CG LEU B 15 -18.440 -11.420 -21.099 1.00 63.30 C
+ANISOU 831 CG LEU B 15 7878 8524 7650 -1015 495 130 C
+ATOM 832 CD1 LEU B 15 -17.756 -10.666 -22.216 1.00 63.58 C
+ANISOU 832 CD1 LEU B 15 7943 8622 7594 -1222 602 221 C
+ATOM 833 CD2 LEU B 15 -17.443 -12.372 -20.490 1.00 65.97 C
+ANISOU 833 CD2 LEU B 15 7922 9161 7982 -958 487 79 C
+ATOM 834 N GLU B 16 -21.532 -10.510 -22.157 1.00 47.63 N
+ANISOU 834 N GLU B 16 6447 5937 5713 -745 415 221 N
+ATOM 835 CA GLU B 16 -22.664 -11.304 -22.654 1.00 45.67 C
+ANISOU 835 CA GLU B 16 6218 5656 5479 -515 358 230 C
+ATOM 836 C GLU B 16 -22.099 -12.584 -23.254 1.00 48.61 C
+ANISOU 836 C GLU B 16 6436 6232 5799 -443 384 205 C
+ATOM 837 O GLU B 16 -21.055 -12.553 -23.930 1.00 46.18 O
+ANISOU 837 O GLU B 16 6067 6070 5407 -536 474 229 O
+ATOM 838 CB GLU B 16 -23.451 -10.553 -23.698 1.00 48.11 C
+ANISOU 838 CB GLU B 16 6731 5809 5738 -476 346 328 C
+ATOM 839 CG GLU B 16 -24.832 -11.113 -24.032 1.00 53.37 C
+ANISOU 839 CG GLU B 16 7413 6439 6424 -265 251 343 C
+ATOM 840 CD GLU B 16 -25.747 -10.126 -24.829 1.00 57.72 C
+ANISOU 840 CD GLU B 16 8169 6829 6932 -188 209 453 C
+ATOM 841 OE1 GLU B 16 -26.936 -9.937 -24.446 1.00 69.98 O
+ANISOU 841 OE1 GLU B 16 9737 8308 8544 -25 134 464 O
+ATOM 842 OE2 GLU B 16 -25.279 -9.506 -25.809 1.00 71.51 O
+ANISOU 842 OE2 GLU B 16 10058 8536 8577 -278 255 541 O
+ATOM 843 N VAL B 17 -22.770 -13.706 -22.978 1.00 44.60 N
+ANISOU 843 N VAL B 17 5878 5736 5329 -281 315 156 N
+ATOM 844 CA VAL B 17 -22.304 -14.976 -23.436 1.00 46.75 C
+ANISOU 844 CA VAL B 17 6070 6143 5548 -182 330 114 C
+ATOM 845 C VAL B 17 -23.463 -15.746 -23.995 1.00 45.90 C
+ANISOU 845 C VAL B 17 6061 5952 5427 -66 243 110 C
+ATOM 846 O VAL B 17 -24.614 -15.485 -23.683 1.00 43.95 O
+ANISOU 846 O VAL B 17 5860 5598 5240 -49 164 134 O
+ATOM 847 CB VAL B 17 -21.605 -15.796 -22.302 1.00 47.60 C
+ANISOU 847 CB VAL B 17 6021 6360 5702 -132 323 46 C
+ATOM 848 CG1 VAL B 17 -20.698 -14.897 -21.492 1.00 51.12 C
+ANISOU 848 CG1 VAL B 17 6363 6888 6173 -288 361 47 C
+ATOM 849 CG2 VAL B 17 -22.618 -16.422 -21.353 1.00 49.09 C
+ANISOU 849 CG2 VAL B 17 6236 6442 5970 -53 227 18 C
+ATOM 850 N GLU B 18 -23.109 -16.745 -24.776 1.00 46.07 N
+ANISOU 850 N GLU B 18 6102 6043 5357 16 260 72 N
+ATOM 851 CA GLU B 18 -24.020 -17.745 -25.270 1.00 49.63 C
+ANISOU 851 CA GLU B 18 6660 6424 5772 95 165 41 C
+ATOM 852 C GLU B 18 -24.215 -18.851 -24.218 1.00 44.35 C
+ANISOU 852 C GLU B 18 5956 5714 5177 154 106 -15 C
+ATOM 853 O GLU B 18 -23.267 -19.284 -23.560 1.00 51.13 O
+ANISOU 853 O GLU B 18 6734 6641 6052 214 157 -53 O
+ATOM 854 CB GLU B 18 -23.469 -18.355 -26.555 1.00 50.78 C
+ANISOU 854 CB GLU B 18 6901 6634 5756 163 218 4 C
+ATOM 855 CG GLU B 18 -23.996 -17.686 -27.802 1.00 68.77 C
+ANISOU 855 CG GLU B 18 9305 8898 7926 113 200 68 C
+ATOM 856 CD GLU B 18 -23.835 -18.551 -29.075 1.00 88.05 C
+ANISOU 856 CD GLU B 18 11901 11375 10178 191 210 8 C
+ATOM 857 OE1 GLU B 18 -22.896 -19.410 -29.126 1.00 81.31 O
+ANISOU 857 OE1 GLU B 18 11040 10592 9262 305 301 -77 O
+ATOM 858 OE2 GLU B 18 -24.664 -18.355 -30.020 1.00 95.29 O
+ANISOU 858 OE2 GLU B 18 12955 12254 10995 158 122 45 O
+ATOM 859 N CYS B 19 -25.445 -19.302 -24.075 1.00 41.64 N
+ANISOU 859 N CYS B 19 5672 5279 4869 130 -6 -8 N
+ATOM 860 CA CYS B 19 -25.763 -20.344 -23.133 1.00 45.79 C
+ANISOU 860 CA CYS B 19 6202 5746 5449 144 -63 -39 C
+ATOM 861 C CYS B 19 -26.882 -21.159 -23.766 1.00 46.84 C
+ANISOU 861 C CYS B 19 6462 5798 5535 89 -183 -46 C
+ATOM 862 O CYS B 19 -27.984 -20.631 -23.986 1.00 45.31 O
+ANISOU 862 O CYS B 19 6227 5622 5365 10 -256 7 O
+ATOM 863 CB CYS B 19 -26.236 -19.742 -21.802 1.00 44.81 C
+ANISOU 863 CB CYS B 19 5955 5628 5442 93 -68 2 C
+ATOM 864 SG CYS B 19 -26.514 -21.029 -20.541 1.00 44.98 S
+ANISOU 864 SG CYS B 19 5996 5591 5503 93 -120 -8 S
+ATOM 865 N ASP B 20 -26.627 -22.429 -24.061 1.00 46.35 N
+ANISOU 865 N ASP B 20 6561 5651 5398 132 -213 -114 N
+ATOM 866 CA ASP B 20 -27.710 -23.303 -24.531 1.00 48.89 C
+ANISOU 866 CA ASP B 20 7032 5874 5668 19 -349 -130 C
+ATOM 867 C ASP B 20 -28.747 -23.474 -23.465 1.00 47.10 C
+ANISOU 867 C ASP B 20 6711 5635 5547 -116 -420 -68 C
+ATOM 868 O ASP B 20 -28.472 -23.214 -22.296 1.00 47.38 O
+ANISOU 868 O ASP B 20 6628 5699 5673 -83 -357 -35 O
+ATOM 869 CB ASP B 20 -27.195 -24.650 -25.016 1.00 49.61 C
+ANISOU 869 CB ASP B 20 7385 5821 5642 92 -366 -229 C
+ATOM 870 CG ASP B 20 -26.366 -24.538 -26.278 1.00 56.74 C
+ANISOU 870 CG ASP B 20 8391 6766 6398 224 -291 -299 C
+ATOM 871 OD1 ASP B 20 -26.482 -23.537 -27.079 1.00 61.65 O
+ANISOU 871 OD1 ASP B 20 8935 7508 6978 194 -270 -261 O
+ATOM 872 OD2 ASP B 20 -25.587 -25.487 -26.498 1.00 64.45 O
+ANISOU 872 OD2 ASP B 20 9551 7653 7283 379 -246 -389 O
+ATOM 873 N ASP B 21 -29.960 -23.866 -23.882 1.00 51.35 N
+ANISOU 873 N ASP B 21 7285 6165 6058 -283 -552 -48 N
+ATOM 874 CA ASP B 21 -31.093 -24.022 -22.958 1.00 47.36 C
+ANISOU 874 CA ASP B 21 6647 5708 5637 -444 -612 27 C
+ATOM 875 C ASP B 21 -30.985 -25.153 -21.926 1.00 47.41 C
+ANISOU 875 C ASP B 21 6767 5582 5664 -512 -610 28 C
+ATOM 876 O ASP B 21 -31.828 -25.247 -21.025 1.00 45.27 O
+ANISOU 876 O ASP B 21 6372 5373 5454 -650 -626 105 O
+ATOM 877 CB ASP B 21 -32.458 -24.057 -23.695 1.00 51.66 C
+ANISOU 877 CB ASP B 21 7134 6351 6143 -629 -764 67 C
+ATOM 878 CG ASP B 21 -32.657 -25.259 -24.632 1.00 61.29 C
+ANISOU 878 CG ASP B 21 8623 7436 7229 -779 -899 -7 C
+ATOM 879 OD1 ASP B 21 -31.869 -26.233 -24.690 1.00 60.99 O
+ANISOU 879 OD1 ASP B 21 8860 7188 7124 -738 -879 -93 O
+ATOM 880 OD2 ASP B 21 -33.671 -25.198 -25.362 1.00 76.44 O
+ANISOU 880 OD2 ASP B 21 10482 9466 9093 -935 -1042 19 O
+ATOM 881 N ASP B 22 -29.986 -26.019 -22.094 1.00 45.76 N
+ANISOU 881 N ASP B 22 6801 5197 5386 -402 -588 -47 N
+ATOM 882 CA ASP B 22 -29.698 -27.103 -21.184 1.00 49.94 C
+ANISOU 882 CA ASP B 22 7499 5560 5913 -408 -587 -39 C
+ATOM 883 C ASP B 22 -28.367 -26.870 -20.478 1.00 51.81 C
+ANISOU 883 C ASP B 22 7692 5815 6179 -156 -468 -51 C
+ATOM 884 O ASP B 22 -27.852 -27.770 -19.904 1.00 47.85 O
+ANISOU 884 O ASP B 22 7360 5171 5649 -76 -467 -52 O
+ATOM 885 CB ASP B 22 -29.681 -28.442 -21.915 1.00 54.09 C
+ANISOU 885 CB ASP B 22 8395 5838 6318 -461 -680 -116 C
+ATOM 886 CG ASP B 22 -28.657 -28.512 -23.084 1.00 63.91 C
+ANISOU 886 CG ASP B 22 9803 7027 7451 -230 -637 -239 C
+ATOM 887 OD1 ASP B 22 -28.251 -27.429 -23.607 1.00 56.77 O
+ANISOU 887 OD1 ASP B 22 8699 6311 6557 -118 -561 -247 O
+ATOM 888 OD2 ASP B 22 -28.283 -29.685 -23.476 1.00 60.29 O
+ANISOU 888 OD2 ASP B 22 9703 6324 6879 -163 -672 -325 O
+ATOM 889 N VAL B 23 -27.833 -25.644 -20.499 1.00 44.07 N
+ANISOU 889 N VAL B 23 6485 5013 5246 -45 -380 -50 N
+ATOM 890 CA VAL B 23 -26.611 -25.310 -19.757 1.00 47.28 C
+ANISOU 890 CA VAL B 23 6793 5491 5677 138 -286 -54 C
+ATOM 891 C VAL B 23 -26.941 -24.305 -18.663 1.00 46.19 C
+ANISOU 891 C VAL B 23 6430 5488 5630 71 -247 9 C
+ATOM 892 O VAL B 23 -27.644 -23.285 -18.881 1.00 39.27 O
+ANISOU 892 O VAL B 23 5415 4705 4798 -11 -238 32 O
+ATOM 893 CB VAL B 23 -25.523 -24.795 -20.707 1.00 50.38 C
+ANISOU 893 CB VAL B 23 7146 5975 6020 297 -208 -117 C
+ATOM 894 CG1 VAL B 23 -24.342 -24.208 -19.967 1.00 46.76 C
+ANISOU 894 CG1 VAL B 23 6507 5665 5593 423 -122 -109 C
+ATOM 895 CG2 VAL B 23 -25.132 -25.955 -21.653 1.00 50.32 C
+ANISOU 895 CG2 VAL B 23 7401 5823 5893 416 -228 -198 C
+ATOM 896 N TYR B 24 -26.524 -24.659 -17.451 1.00 44.23 N
+ANISOU 896 N TYR B 24 6178 5236 5390 119 -233 41 N
+ATOM 897 CA TYR B 24 -26.635 -23.726 -16.362 1.00 42.32 C
+ANISOU 897 CA TYR B 24 5758 5120 5199 83 -187 78 C
+ATOM 898 C TYR B 24 -25.823 -22.471 -16.675 1.00 41.44 C
+ANISOU 898 C TYR B 24 5501 5135 5109 147 -123 34 C
+ATOM 899 O TYR B 24 -24.735 -22.521 -17.198 1.00 44.52 O
+ANISOU 899 O TYR B 24 5887 5563 5465 255 -98 -5 O
+ATOM 900 CB TYR B 24 -26.178 -24.336 -15.052 1.00 44.23 C
+ANISOU 900 CB TYR B 24 6041 5350 5413 135 -194 117 C
+ATOM 901 CG TYR B 24 -27.087 -25.431 -14.497 1.00 46.96 C
+ANISOU 901 CG TYR B 24 6541 5568 5732 16 -244 192 C
+ATOM 902 CD1 TYR B 24 -28.468 -25.241 -14.364 1.00 44.56 C
+ANISOU 902 CD1 TYR B 24 6173 5299 5459 -181 -243 243 C
+ATOM 903 CD2 TYR B 24 -26.538 -26.649 -14.079 1.00 51.68 C
+ANISOU 903 CD2 TYR B 24 7347 6023 6266 106 -288 224 C
+ATOM 904 CE1 TYR B 24 -29.285 -26.242 -13.871 1.00 49.24 C
+ANISOU 904 CE1 TYR B 24 6889 5801 6017 -343 -281 325 C
+ATOM 905 CE2 TYR B 24 -27.342 -27.663 -13.564 1.00 49.44 C
+ANISOU 905 CE2 TYR B 24 7249 5591 5944 -40 -332 309 C
+ATOM 906 CZ TYR B 24 -28.691 -27.448 -13.430 1.00 51.30 C
+ANISOU 906 CZ TYR B 24 7400 5881 6209 -289 -324 362 C
+ATOM 907 OH TYR B 24 -29.429 -28.459 -12.887 1.00 52.12 O
+ANISOU 907 OH TYR B 24 7677 5862 6265 -476 -359 461 O
+ATOM 908 N VAL B 25 -26.397 -21.353 -16.303 1.00 42.58 N
+ANISOU 908 N VAL B 25 5534 5344 5298 74 -91 48 N
+ATOM 909 CA VAL B 25 -25.870 -19.977 -16.515 1.00 43.51 C
+ANISOU 909 CA VAL B 25 5561 5536 5435 77 -35 18 C
+ATOM 910 C VAL B 25 -24.479 -19.883 -15.914 1.00 45.47 C
+ANISOU 910 C VAL B 25 5750 5871 5655 125 -13 -11 C
+ATOM 911 O VAL B 25 -23.583 -19.234 -16.483 1.00 42.02 O
+ANISOU 911 O VAL B 25 5255 5505 5205 121 24 -37 O
+ATOM 912 CB VAL B 25 -27.014 -19.053 -15.974 1.00 47.07 C
+ANISOU 912 CB VAL B 25 5964 5993 5928 22 -14 42 C
+ATOM 913 CG1 VAL B 25 -26.658 -17.985 -14.979 1.00 51.34 C
+ANISOU 913 CG1 VAL B 25 6467 6569 6468 14 35 10 C
+ATOM 914 CG2 VAL B 25 -27.951 -18.612 -17.124 1.00 50.07 C
+ANISOU 914 CG2 VAL B 25 6347 6348 6328 11 -32 68 C
+ATOM 915 N LEU B 26 -24.262 -20.562 -14.781 1.00 42.91 N
+ANISOU 915 N LEU B 26 5432 5567 5305 159 -44 3 N
+ATOM 916 CA LEU B 26 -22.937 -20.508 -14.120 1.00 44.21 C
+ANISOU 916 CA LEU B 26 5508 5860 5427 214 -52 -16 C
+ATOM 917 C LEU B 26 -21.873 -21.156 -15.044 1.00 43.16 C
+ANISOU 917 C LEU B 26 5348 5786 5263 347 -46 -31 C
+ATOM 918 O LEU B 26 -20.782 -20.644 -15.204 1.00 41.77 O
+ANISOU 918 O LEU B 26 5032 5771 5066 355 -19 -54 O
+ATOM 919 CB LEU B 26 -22.973 -21.227 -12.757 1.00 43.87 C
+ANISOU 919 CB LEU B 26 5503 5824 5338 252 -103 21 C
+ATOM 920 CG LEU B 26 -21.633 -21.303 -12.009 1.00 51.12 C
+ANISOU 920 CG LEU B 26 6319 6909 6194 330 -147 15 C
+ATOM 921 CD1 LEU B 26 -20.989 -19.928 -11.865 1.00 47.47 C
+ANISOU 921 CD1 LEU B 26 5717 6587 5732 203 -127 -41 C
+ATOM 922 CD2 LEU B 26 -21.802 -21.989 -10.650 1.00 53.81 C
+ANISOU 922 CD2 LEU B 26 6734 7244 6465 368 -206 70 C
+ATOM 923 N ASP B 27 -22.221 -22.283 -15.633 1.00 44.33 N
+ANISOU 923 N ASP B 27 5638 5809 5394 443 -66 -21 N
+ATOM 924 CA ASP B 27 -21.332 -23.028 -16.510 1.00 46.01 C
+ANISOU 924 CA ASP B 27 5876 6049 5554 621 -47 -49 C
+ATOM 925 C ASP B 27 -20.956 -22.226 -17.766 1.00 49.22 C
+ANISOU 925 C ASP B 27 6200 6549 5953 583 32 -86 C
+ATOM 926 O ASP B 27 -19.802 -22.149 -18.106 1.00 50.44 O
+ANISOU 926 O ASP B 27 6223 6878 6063 680 86 -104 O
+ATOM 927 CB ASP B 27 -21.974 -24.337 -16.843 1.00 48.69 C
+ANISOU 927 CB ASP B 27 6461 6173 5864 695 -93 -45 C
+ATOM 928 CG ASP B 27 -22.021 -25.293 -15.605 1.00 61.91 C
+ANISOU 928 CG ASP B 27 8247 7761 7515 764 -163 12 C
+ATOM 929 OD1 ASP B 27 -21.027 -25.395 -14.870 1.00 72.00 O
+ANISOU 929 OD1 ASP B 27 9424 9171 8760 907 -177 30 O
+ATOM 930 OD2 ASP B 27 -23.034 -25.974 -15.376 1.00 65.76 O
+ANISOU 930 OD2 ASP B 27 8922 8059 8004 668 -211 51 O
+ATOM 931 N ALA B 28 -21.929 -21.573 -18.394 1.00 48.34 N
+ANISOU 931 N ALA B 28 6146 6346 5874 438 40 -82 N
+ATOM 932 CA ALA B 28 -21.708 -20.761 -19.556 1.00 48.04 C
+ANISOU 932 CA ALA B 28 6072 6368 5811 384 108 -93 C
+ATOM 933 C ALA B 28 -20.772 -19.641 -19.163 1.00 49.27 C
+ANISOU 933 C ALA B 28 6043 6698 5979 293 162 -84 C
+ATOM 934 O ALA B 28 -19.857 -19.319 -19.908 1.00 48.19 O
+ANISOU 934 O ALA B 28 5813 6707 5789 295 240 -88 O
+ATOM 935 CB ALA B 28 -23.039 -20.183 -20.056 1.00 52.12 C
+ANISOU 935 CB ALA B 28 6682 6758 6362 258 77 -68 C
+ATOM 936 N ALA B 29 -20.986 -19.058 -17.979 1.00 46.38 N
+ANISOU 936 N ALA B 29 5631 6327 5664 194 124 -74 N
+ATOM 937 CA ALA B 29 -20.076 -18.026 -17.489 1.00 48.20 C
+ANISOU 937 CA ALA B 29 5715 6706 5890 65 150 -79 C
+ATOM 938 C ALA B 29 -18.630 -18.516 -17.392 1.00 50.01 C
+ANISOU 938 C ALA B 29 5752 7184 6064 154 166 -86 C
+ATOM 939 O ALA B 29 -17.691 -17.860 -17.830 1.00 49.30 O
+ANISOU 939 O ALA B 29 5514 7276 5941 54 227 -80 O
+ATOM 940 CB ALA B 29 -20.518 -17.475 -16.122 1.00 48.24 C
+ANISOU 940 CB ALA B 29 5740 6659 5928 -29 96 -90 C
+ATOM 941 N GLU B 30 -18.455 -19.668 -16.787 1.00 50.74 N
+ANISOU 941 N GLU B 30 5842 7297 6140 344 111 -87 N
+ATOM 942 CA GLU B 30 -17.125 -20.211 -16.573 1.00 53.52 C
+ANISOU 942 CA GLU B 30 5996 7905 6434 495 109 -84 C
+ATOM 943 C GLU B 30 -16.487 -20.582 -17.882 1.00 55.58 C
+ANISOU 943 C GLU B 30 6200 8279 6639 634 213 -95 C
+ATOM 944 O GLU B 30 -15.310 -20.345 -18.062 1.00 53.30 O
+ANISOU 944 O GLU B 30 5662 8284 6302 650 267 -87 O
+ATOM 945 CB GLU B 30 -17.245 -21.433 -15.659 1.00 55.76 C
+ANISOU 945 CB GLU B 30 6364 8121 6701 708 18 -66 C
+ATOM 946 CG GLU B 30 -17.599 -20.966 -14.244 1.00 60.54 C
+ANISOU 946 CG GLU B 30 6973 8707 7322 564 -69 -52 C
+ATOM 947 CD GLU B 30 -17.847 -22.100 -13.266 1.00 67.44 C
+ANISOU 947 CD GLU B 30 7969 9491 8161 734 -157 -9 C
+ATOM 948 OE1 GLU B 30 -18.209 -23.248 -13.665 1.00 66.53 O
+ANISOU 948 OE1 GLU B 30 8035 9206 8037 915 -159 8 O
+ATOM 949 OE2 GLU B 30 -17.669 -21.807 -12.069 1.00 71.86 O
+ANISOU 949 OE2 GLU B 30 8471 10144 8689 666 -231 5 O
+ATOM 950 N GLU B 31 -17.279 -21.156 -18.796 1.00 55.65 N
+ANISOU 950 N GLU B 31 6432 8073 6637 723 241 -115 N
+ATOM 951 CA GLU B 31 -16.811 -21.477 -20.146 1.00 59.63 C
+ANISOU 951 CA GLU B 31 6942 8655 7058 853 350 -141 C
+ATOM 952 C GLU B 31 -16.291 -20.194 -20.865 1.00 55.72 C
+ANISOU 952 C GLU B 31 6283 8348 6540 632 457 -115 C
+ATOM 953 O GLU B 31 -15.355 -20.248 -21.599 1.00 58.65 O
+ANISOU 953 O GLU B 31 6505 8951 6826 714 569 -117 O
+ATOM 954 CB GLU B 31 -17.945 -22.145 -20.947 1.00 70.50 C
+ANISOU 954 CB GLU B 31 8629 9739 8417 905 329 -174 C
+ATOM 955 CG GLU B 31 -17.483 -23.157 -21.980 1.00 89.10 C
+ANISOU 955 CG GLU B 31 11093 12105 10654 1169 401 -233 C
+ATOM 956 CD GLU B 31 -16.540 -24.196 -21.373 1.00108.88 C
+ANISOU 956 CD GLU B 31 13534 14713 13120 1482 395 -248 C
+ATOM 957 OE1 GLU B 31 -16.868 -24.715 -20.275 1.00122.63 O
+ANISOU 957 OE1 GLU B 31 15352 16322 14918 1517 281 -221 O
+ATOM 958 OE2 GLU B 31 -15.461 -24.475 -21.968 1.00106.25 O
+ANISOU 958 OE2 GLU B 31 13067 14613 12689 1708 509 -276 O
+ATOM 959 N ALA B 32 -16.902 -19.037 -20.607 1.00 54.88 N
+ANISOU 959 N ALA B 32 6217 8134 6498 356 427 -85 N
+ATOM 960 CA ALA B 32 -16.492 -17.745 -21.179 1.00 59.73 C
+ANISOU 960 CA ALA B 32 6747 8857 7089 106 511 -44 C
+ATOM 961 C ALA B 32 -15.343 -17.016 -20.467 1.00 63.02 C
+ANISOU 961 C ALA B 32 6892 9546 7504 -75 520 -22 C
+ATOM 962 O ALA B 32 -14.998 -15.927 -20.905 1.00 63.67 O
+ANISOU 962 O ALA B 32 6934 9694 7561 -332 587 19 O
+ATOM 963 CB ALA B 32 -17.705 -16.806 -21.263 1.00 56.13 C
+ANISOU 963 CB ALA B 32 6511 8123 6691 -78 469 -20 C
+ATOM 964 N GLY B 33 -14.771 -17.574 -19.387 1.00 61.55 N
+ANISOU 964 N GLY B 33 6539 9514 7332 31 442 -42 N
+ATOM 965 CA GLY B 33 -13.600 -16.980 -18.707 1.00 63.73 C
+ANISOU 965 CA GLY B 33 6518 10110 7586 -146 423 -23 C
+ATOM 966 C GLY B 33 -13.895 -16.058 -17.525 1.00 66.50 C
+ANISOU 966 C GLY B 33 6927 10352 7985 -414 308 -38 C
+ATOM 967 O GLY B 33 -13.016 -15.338 -17.073 1.00 78.05 O
+ANISOU 967 O GLY B 33 8192 12044 9417 -656 282 -30 O
+ATOM 968 N ILE B 34 -15.129 -16.076 -17.028 1.00 67.68 N
+ANISOU 968 N ILE B 34 7348 10169 8195 -380 241 -66 N
+ATOM 969 CA ILE B 34 -15.538 -15.285 -15.866 1.00 69.74 C
+ANISOU 969 CA ILE B 34 7714 10302 8481 -573 147 -99 C
+ATOM 970 C ILE B 34 -15.518 -16.184 -14.636 1.00 64.98 C
+ANISOU 970 C ILE B 34 7061 9759 7866 -396 34 -118 C
+ATOM 971 O ILE B 34 -15.991 -17.333 -14.669 1.00 60.93 O
+ANISOU 971 O ILE B 34 6620 9161 7366 -127 24 -105 O
+ATOM 972 CB ILE B 34 -17.001 -14.806 -15.975 1.00 71.51 C
+ANISOU 972 CB ILE B 34 8249 10155 8763 -593 156 -112 C
+ATOM 973 CG1 ILE B 34 -17.270 -14.074 -17.281 1.00 80.00 C
+ANISOU 973 CG1 ILE B 34 9439 11114 9843 -696 254 -73 C
+ATOM 974 CG2 ILE B 34 -17.370 -13.876 -14.827 1.00 74.50 C
+ANISOU 974 CG2 ILE B 34 8756 10405 9144 -770 88 -161 C
+ATOM 975 CD1 ILE B 34 -18.763 -13.913 -17.553 1.00 74.26 C
+ANISOU 975 CD1 ILE B 34 8970 10076 9167 -610 251 -68 C
+ATOM 976 N ASP B 35 -15.021 -15.649 -13.537 1.00 61.68 N
+ANISOU 976 N ASP B 35 6562 9464 7408 -566 -59 -146 N
+ATOM 977 CA ASP B 35 -15.019 -16.414 -12.290 1.00 75.53 C
+ANISOU 977 CA ASP B 35 8296 11276 9122 -414 -177 -152 C
+ATOM 978 C ASP B 35 -16.098 -15.810 -11.437 1.00 67.96 C
+ANISOU 978 C ASP B 35 7599 10051 8171 -525 -210 -201 C
+ATOM 979 O ASP B 35 -16.004 -14.664 -11.028 1.00 71.36 O
+ANISOU 979 O ASP B 35 8091 10448 8572 -786 -232 -255 O
+ATOM 980 CB ASP B 35 -13.639 -16.434 -11.587 1.00 82.96 C
+ANISOU 980 CB ASP B 35 8931 12609 9978 -475 -282 -144 C
+ATOM 981 CG ASP B 35 -12.583 -17.205 -12.400 1.00 94.51 C
+ANISOU 981 CG ASP B 35 10096 14387 11425 -270 -232 -89 C
+ATOM 982 OD1 ASP B 35 -12.806 -18.403 -12.759 1.00 96.53 O
+ANISOU 982 OD1 ASP B 35 10403 14579 11694 79 -201 -57 O
+ATOM 983 OD2 ASP B 35 -11.544 -16.586 -12.714 1.00 99.59 O
+ANISOU 983 OD2 ASP B 35 10468 15337 12033 -469 -215 -78 O
+ATOM 984 N LEU B 36 -17.154 -16.583 -11.237 1.00 61.63 N
+ANISOU 984 N LEU B 36 6966 9051 7399 -328 -200 -183 N
+ATOM 985 CA LEU B 36 -18.261 -16.213 -10.383 1.00 56.78 C
+ANISOU 985 CA LEU B 36 6568 8229 6777 -371 -208 -218 C
+ATOM 986 C LEU B 36 -18.245 -17.129 -9.153 1.00 52.62 C
+ANISOU 986 C LEU B 36 6041 7780 6171 -238 -300 -192 C
+ATOM 987 O LEU B 36 -17.788 -18.261 -9.215 1.00 51.28 O
+ANISOU 987 O LEU B 36 5782 7714 5987 -45 -339 -130 O
+ATOM 988 CB LEU B 36 -19.602 -16.402 -11.121 1.00 60.32 C
+ANISOU 988 CB LEU B 36 7183 8425 7309 -276 -120 -195 C
+ATOM 989 CG LEU B 36 -19.852 -15.603 -12.408 1.00 57.54 C
+ANISOU 989 CG LEU B 36 6878 7960 7022 -360 -36 -197 C
+ATOM 990 CD1 LEU B 36 -21.213 -16.023 -13.015 1.00 57.02 C
+ANISOU 990 CD1 LEU B 36 6941 7702 7020 -235 11 -162 C
+ATOM 991 CD2 LEU B 36 -19.778 -14.120 -12.106 1.00 59.01 C
+ANISOU 991 CD2 LEU B 36 7159 8073 7187 -580 -26 -256 C
+ATOM 992 N PRO B 37 -18.782 -16.647 -8.045 1.00 49.77 N
+ANISOU 992 N PRO B 37 5814 7352 5742 -321 -326 -238 N
+ATOM 993 CA PRO B 37 -18.701 -17.404 -6.819 1.00 52.69 C
+ANISOU 993 CA PRO B 37 6200 7815 6003 -225 -415 -204 C
+ATOM 994 C PRO B 37 -19.633 -18.609 -6.877 1.00 53.75 C
+ANISOU 994 C PRO B 37 6445 7807 6169 -30 -373 -116 C
+ATOM 995 O PRO B 37 -20.659 -18.578 -7.575 1.00 52.82 O
+ANISOU 995 O PRO B 37 6420 7504 6142 -22 -275 -109 O
+ATOM 996 CB PRO B 37 -19.214 -16.410 -5.772 1.00 55.23 C
+ANISOU 996 CB PRO B 37 6682 8069 6232 -380 -415 -294 C
+ATOM 997 CG PRO B 37 -20.178 -15.544 -6.538 1.00 56.99 C
+ANISOU 997 CG PRO B 37 7035 8061 6556 -438 -287 -341 C
+ATOM 998 CD PRO B 37 -19.480 -15.359 -7.863 1.00 55.95 C
+ANISOU 998 CD PRO B 37 6768 7965 6526 -486 -269 -323 C
+ATOM 999 N TYR B 38 -19.264 -19.661 -6.164 1.00 51.10 N
+ANISOU 999 N TYR B 38 6105 7561 5748 112 -458 -39 N
+ATOM 1000 CA TYR B 38 -20.137 -20.809 -5.974 1.00 53.20 C
+ANISOU 1000 CA TYR B 38 6529 7673 6010 243 -434 55 C
+ATOM 1001 C TYR B 38 -19.656 -21.588 -4.747 1.00 54.18 C
+ANISOU 1001 C TYR B 38 6693 7909 5982 349 -548 134 C
+ATOM 1002 O TYR B 38 -18.582 -21.362 -4.322 1.00 49.82 O
+ANISOU 1002 O TYR B 38 6003 7570 5353 362 -654 116 O
+ATOM 1003 CB TYR B 38 -20.086 -21.734 -7.179 1.00 49.99 C
+ANISOU 1003 CB TYR B 38 6125 7167 5701 391 -407 104 C
+ATOM 1004 CG TYR B 38 -18.715 -22.275 -7.467 1.00 51.86 C
+ANISOU 1004 CG TYR B 38 6213 7579 5912 569 -486 127 C
+ATOM 1005 CD1 TYR B 38 -17.850 -21.585 -8.312 1.00 55.55 C
+ANISOU 1005 CD1 TYR B 38 6471 8204 6429 528 -464 64 C
+ATOM 1006 CD2 TYR B 38 -18.269 -23.505 -6.904 1.00 61.75 C
+ANISOU 1006 CD2 TYR B 38 7532 8850 7078 796 -577 225 C
+ATOM 1007 CE1 TYR B 38 -16.594 -22.086 -8.614 1.00 58.14 C
+ANISOU 1007 CE1 TYR B 38 6611 8752 6728 714 -515 89 C
+ATOM 1008 CE2 TYR B 38 -16.989 -24.012 -7.186 1.00 59.46 C
+ANISOU 1008 CE2 TYR B 38 7079 8753 6757 1025 -645 249 C
+ATOM 1009 CZ TYR B 38 -16.163 -23.294 -8.041 1.00 63.46 C
+ANISOU 1009 CZ TYR B 38 7329 9462 7319 985 -607 177 C
+ATOM 1010 OH TYR B 38 -14.891 -23.736 -8.343 1.00 72.30 O
+ANISOU 1010 OH TYR B 38 8229 10837 8402 1217 -652 201 O
+ATOM 1011 N SER B 39 -20.429 -22.569 -4.273 1.00 53.67 N
+ANISOU 1011 N SER B 39 6815 7706 5871 420 -534 237 N
+ATOM 1012 CA SER B 39 -19.980 -23.484 -3.243 1.00 53.24 C
+ANISOU 1012 CA SER B 39 6845 7718 5665 553 -645 347 C
+ATOM 1013 C SER B 39 -20.482 -24.911 -3.576 1.00 53.99 C
+ANISOU 1013 C SER B 39 7143 7585 5782 691 -631 477 C
+ATOM 1014 O SER B 39 -19.746 -25.715 -4.122 1.00 60.00 O
+ANISOU 1014 O SER B 39 7905 8323 6567 901 -692 520 O
+ATOM 1015 CB SER B 39 -20.438 -22.974 -1.880 1.00 54.47 C
+ANISOU 1015 CB SER B 39 7088 7945 5660 422 -647 339 C
+ATOM 1016 OG SER B 39 -19.961 -23.809 -0.856 1.00 58.10 O
+ANISOU 1016 OG SER B 39 7640 8485 5947 547 -768 457 O
+ATOM 1017 N CYS B 40 -21.745 -25.188 -3.303 1.00 53.52 N
+ANISOU 1017 N CYS B 40 7259 7360 5714 563 -542 532 N
+ATOM 1018 CA CYS B 40 -22.341 -26.502 -3.494 1.00 52.54 C
+ANISOU 1018 CA CYS B 40 7371 6999 5591 607 -533 661 C
+ATOM 1019 C CYS B 40 -22.554 -26.894 -4.990 1.00 54.29 C
+ANISOU 1019 C CYS B 40 7615 7039 5972 636 -494 621 C
+ATOM 1020 O CYS B 40 -22.599 -28.079 -5.354 1.00 56.18 O
+ANISOU 1020 O CYS B 40 8070 7067 6206 733 -528 702 O
+ATOM 1021 CB CYS B 40 -23.706 -26.493 -2.758 1.00 53.96 C
+ANISOU 1021 CB CYS B 40 7670 7122 5708 390 -431 727 C
+ATOM 1022 SG CYS B 40 -25.014 -25.506 -3.570 1.00 54.05 S
+ANISOU 1022 SG CYS B 40 7540 7122 5874 175 -270 621 S
+ATOM 1023 N ARG B 41 -22.745 -25.881 -5.830 1.00 55.21 N
+ANISOU 1023 N ARG B 41 7548 7218 6210 539 -423 498 N
+ATOM 1024 CA ARG B 41 -23.100 -26.036 -7.243 1.00 57.45 C
+ANISOU 1024 CA ARG B 41 7842 7361 6623 525 -377 449 C
+ATOM 1025 C ARG B 41 -24.289 -26.944 -7.426 1.00 53.39 C
+ANISOU 1025 C ARG B 41 7544 6624 6118 400 -351 531 C
+ATOM 1026 O ARG B 41 -24.325 -27.732 -8.363 1.00 57.10 O
+ANISOU 1026 O ARG B 41 8153 6914 6628 449 -373 531 O
+ATOM 1027 CB ARG B 41 -21.926 -26.568 -8.054 1.00 57.25 C
+ANISOU 1027 CB ARG B 41 7805 7331 6614 765 -433 421 C
+ATOM 1028 CG ARG B 41 -20.730 -25.656 -8.128 1.00 63.18 C
+ANISOU 1028 CG ARG B 41 8288 8346 7369 845 -452 341 C
+ATOM 1029 CD ARG B 41 -19.678 -26.364 -8.976 1.00 72.83 C
+ANISOU 1029 CD ARG B 41 9491 9584 8595 1112 -481 331 C
+ATOM 1030 NE ARG B 41 -20.005 -26.268 -10.416 1.00 66.24 N
+ANISOU 1030 NE ARG B 41 8672 8642 7853 1080 -399 256 N
+ATOM 1031 CZ ARG B 41 -19.501 -25.337 -11.206 1.00 60.12 C
+ANISOU 1031 CZ ARG B 41 7679 8033 7131 1040 -342 173 C
+ATOM 1032 NH1 ARG B 41 -18.683 -24.440 -10.693 1.00 58.08 N
+ANISOU 1032 NH1 ARG B 41 7175 8038 6852 995 -361 150 N
+ATOM 1033 NH2 ARG B 41 -19.820 -25.271 -12.489 1.00 59.63 N
+ANISOU 1033 NH2 ARG B 41 7655 7877 7124 1014 -273 118 N
+ATOM 1034 N ALA B 42 -25.254 -26.842 -6.528 1.00 50.75 N
+ANISOU 1034 N ALA B 42 7240 6313 5731 225 -301 598 N
+ATOM 1035 CA ALA B 42 -26.322 -27.854 -6.466 1.00 55.82 C
+ANISOU 1035 CA ALA B 42 8087 6773 6348 63 -286 714 C
+ATOM 1036 C ALA B 42 -27.689 -27.296 -6.092 1.00 53.85 C
+ANISOU 1036 C ALA B 42 7723 6630 6105 -178 -176 738 C
+ATOM 1037 O ALA B 42 -28.646 -28.060 -5.838 1.00 55.78 O
+ANISOU 1037 O ALA B 42 8091 6791 6308 -370 -150 854 O
+ATOM 1038 CB ALA B 42 -25.919 -28.950 -5.457 1.00 58.15 C
+ANISOU 1038 CB ALA B 42 8635 6960 6496 141 -354 856 C
+ATOM 1039 N GLY B 43 -27.766 -25.976 -6.007 1.00 52.94 N
+ANISOU 1039 N GLY B 43 7380 6706 6028 -168 -108 636 N
+ATOM 1040 CA GLY B 43 -29.019 -25.311 -5.704 1.00 57.58 C
+ANISOU 1040 CA GLY B 43 7828 7426 6621 -321 9 641 C
+ATOM 1041 C GLY B 43 -29.393 -25.157 -4.247 1.00 56.47 C
+ANISOU 1041 C GLY B 43 7699 7426 6330 -371 90 705 C
+ATOM 1042 O GLY B 43 -30.490 -24.676 -3.919 1.00 61.40 O
+ANISOU 1042 O GLY B 43 8200 8190 6936 -473 214 718 O
+ATOM 1043 N SER B 44 -28.507 -25.552 -3.359 1.00 57.15 N
+ANISOU 1043 N SER B 44 7922 7502 6288 -282 25 748 N
+ATOM 1044 CA SER B 44 -28.864 -25.573 -1.947 1.00 60.58 C
+ANISOU 1044 CA SER B 44 8415 8061 6539 -340 95 828 C
+ATOM 1045 C SER B 44 -28.070 -24.590 -1.083 1.00 55.02 C
+ANISOU 1045 C SER B 44 7667 7512 5724 -218 81 721 C
+ATOM 1046 O SER B 44 -27.939 -24.770 0.117 1.00 56.43 O
+ANISOU 1046 O SER B 44 7952 7776 5712 -219 84 785 O
+ATOM 1047 CB SER B 44 -28.724 -26.997 -1.455 1.00 64.11 C
+ANISOU 1047 CB SER B 44 9118 8363 6875 -384 27 1009 C
+ATOM 1048 OG SER B 44 -27.369 -27.403 -1.576 1.00 72.90 O
+ANISOU 1048 OG SER B 44 10341 9378 7978 -177 -128 997 O
+ATOM 1049 N CYS B 45 -27.538 -23.526 -1.680 1.00 50.30 N
+ANISOU 1049 N CYS B 45 6932 6949 5228 -137 60 559 N
+ATOM 1050 CA CYS B 45 -26.911 -22.490 -0.877 1.00 49.85 C
+ANISOU 1050 CA CYS B 45 6852 7028 5060 -85 47 441 C
+ATOM 1051 C CYS B 45 -27.172 -21.136 -1.520 1.00 51.33 C
+ANISOU 1051 C CYS B 45 6911 7228 5361 -83 119 279 C
+ATOM 1052 O CYS B 45 -27.967 -21.005 -2.440 1.00 55.12 O
+ANISOU 1052 O CYS B 45 7307 7650 5984 -106 191 278 O
+ATOM 1053 CB CYS B 45 -25.390 -22.791 -0.653 1.00 48.86 C
+ANISOU 1053 CB CYS B 45 6762 6928 4874 20 -134 439 C
+ATOM 1054 SG CYS B 45 -24.160 -22.368 -1.931 1.00 53.35 S
+ANISOU 1054 SG CYS B 45 7176 7476 5616 105 -244 330 S
+ATOM 1055 N SER B 46 -26.488 -20.125 -1.034 1.00 50.33 N
+ANISOU 1055 N SER B 46 6793 7170 5158 -63 86 148 N
+ATOM 1056 CA SER B 46 -26.687 -18.804 -1.525 1.00 53.49 C
+ANISOU 1056 CA SER B 46 7146 7540 5638 -62 151 0 C
+ATOM 1057 C SER B 46 -25.436 -18.250 -2.234 1.00 51.56 C
+ANISOU 1057 C SER B 46 6851 7262 5478 -77 28 -89 C
+ATOM 1058 O SER B 46 -25.397 -17.049 -2.580 1.00 51.57 O
+ANISOU 1058 O SER B 46 6861 7210 5522 -105 60 -215 O
+ATOM 1059 CB SER B 46 -27.077 -17.908 -0.321 1.00 54.94 C
+ANISOU 1059 CB SER B 46 7434 7804 5634 -60 242 -100 C
+ATOM 1060 OG SER B 46 -25.958 -17.693 0.515 1.00 59.45 O
+ANISOU 1060 OG SER B 46 8091 8449 6049 -97 114 -164 O
+ATOM 1061 N SER B 47 -24.417 -19.082 -2.465 1.00 50.22 N
+ANISOU 1061 N SER B 47 6631 7124 5322 -52 -104 -22 N
+ATOM 1062 CA SER B 47 -23.104 -18.545 -2.910 1.00 53.80 C
+ANISOU 1062 CA SER B 47 6993 7634 5811 -82 -216 -100 C
+ATOM 1063 C SER B 47 -23.102 -17.974 -4.299 1.00 49.57 C
+ANISOU 1063 C SER B 47 6378 7002 5454 -106 -173 -147 C
+ATOM 1064 O SER B 47 -22.409 -17.004 -4.556 1.00 47.90 O
+ANISOU 1064 O SER B 47 6131 6812 5254 -198 -204 -242 O
+ATOM 1065 CB SER B 47 -21.985 -19.587 -2.863 1.00 55.00 C
+ANISOU 1065 CB SER B 47 7072 7893 5931 4 -358 -10 C
+ATOM 1066 OG SER B 47 -21.799 -19.986 -1.539 1.00 67.17 O
+ANISOU 1066 OG SER B 47 8697 9542 7281 24 -428 35 O
+ATOM 1067 N CYS B 48 -23.836 -18.597 -5.210 1.00 47.83 N
+ANISOU 1067 N CYS B 48 6142 6677 5355 -48 -112 -75 N
+ATOM 1068 CA CYS B 48 -23.825 -18.180 -6.626 1.00 44.63 C
+ANISOU 1068 CA CYS B 48 5671 6187 5098 -57 -82 -102 C
+ATOM 1069 C CYS B 48 -25.021 -17.249 -6.959 1.00 50.82 C
+ANISOU 1069 C CYS B 48 6502 6866 5939 -77 30 -146 C
+ATOM 1070 O CYS B 48 -25.428 -17.128 -8.127 1.00 51.63 O
+ANISOU 1070 O CYS B 48 6573 6888 6154 -61 61 -130 O
+ATOM 1071 CB CYS B 48 -23.944 -19.426 -7.480 1.00 41.68 C
+ANISOU 1071 CB CYS B 48 5279 5758 4800 24 -100 -7 C
+ATOM 1072 SG CYS B 48 -25.514 -20.250 -7.174 1.00 47.58 S
+ANISOU 1072 SG CYS B 48 6110 6423 5543 17 -32 87 S
+ATOM 1073 N ALA B 49 -25.604 -16.621 -5.943 1.00 49.42 N
+ANISOU 1073 N ALA B 49 6406 6702 5668 -83 90 -197 N
+ATOM 1074 CA ALA B 49 -26.803 -15.852 -6.145 1.00 47.37 C
+ANISOU 1074 CA ALA B 49 6180 6371 5446 -34 205 -227 C
+ATOM 1075 C ALA B 49 -26.501 -14.656 -7.025 1.00 46.14 C
+ANISOU 1075 C ALA B 49 6068 6096 5364 -55 208 -304 C
+ATOM 1076 O ALA B 49 -25.486 -13.952 -6.837 1.00 47.19 O
+ANISOU 1076 O ALA B 49 6266 6210 5452 -154 153 -386 O
+ATOM 1077 CB ALA B 49 -27.369 -15.388 -4.811 1.00 48.90 C
+ANISOU 1077 CB ALA B 49 6469 6616 5493 -1 286 -284 C
+ATOM 1078 N GLY B 50 -27.414 -14.412 -7.959 1.00 46.35 N
+ANISOU 1078 N GLY B 50 6066 6052 5491 20 266 -269 N
+ATOM 1079 CA GLY B 50 -27.486 -13.112 -8.644 1.00 47.72 C
+ANISOU 1079 CA GLY B 50 6340 6080 5709 42 296 -328 C
+ATOM 1080 C GLY B 50 -28.933 -12.665 -8.683 1.00 52.51 C
+ANISOU 1080 C GLY B 50 6951 6666 6333 212 397 -314 C
+ATOM 1081 O GLY B 50 -29.796 -13.183 -7.949 1.00 51.98 O
+ANISOU 1081 O GLY B 50 6805 6723 6220 284 461 -282 O
+ATOM 1082 N LYS B 51 -29.194 -11.690 -9.542 1.00 56.73 N
+ANISOU 1082 N LYS B 51 7570 7061 6924 284 413 -325 N
+ATOM 1083 CA LYS B 51 -30.512 -11.104 -9.670 1.00 58.00 C
+ANISOU 1083 CA LYS B 51 7730 7209 7099 498 500 -309 C
+ATOM 1084 C LYS B 51 -30.801 -10.888 -11.160 1.00 51.95 C
+ANISOU 1084 C LYS B 51 6929 6374 6435 547 454 -226 C
+ATOM 1085 O LYS B 51 -30.004 -10.302 -11.879 1.00 52.34 O
+ANISOU 1085 O LYS B 51 7113 6268 6503 462 408 -238 O
+ATOM 1086 CB LYS B 51 -30.496 -9.813 -8.890 1.00 62.10 C
+ANISOU 1086 CB LYS B 51 8498 7573 7524 591 570 -437 C
+ATOM 1087 CG LYS B 51 -31.824 -9.123 -8.706 1.00 71.92 C
+ANISOU 1087 CG LYS B 51 9764 8816 8744 885 686 -447 C
+ATOM 1088 CD LYS B 51 -31.618 -8.015 -7.667 1.00 84.43 C
+ANISOU 1088 CD LYS B 51 11656 10230 10191 959 758 -609 C
+ATOM 1089 CE LYS B 51 -32.841 -7.727 -6.792 1.00 94.36 C
+ANISOU 1089 CE LYS B 51 12897 11600 11354 1256 917 -653 C
+ATOM 1090 NZ LYS B 51 -33.550 -6.484 -7.218 1.00 96.90 N
+ANISOU 1090 NZ LYS B 51 13408 11730 11677 1566 985 -687 N
+ATOM 1091 N VAL B 52 -31.914 -11.423 -11.620 1.00 50.92 N
+ANISOU 1091 N VAL B 52 6608 6386 6353 653 460 -133 N
+ATOM 1092 CA VAL B 52 -32.367 -11.250 -12.978 1.00 51.68 C
+ANISOU 1092 CA VAL B 52 6658 6458 6518 721 403 -47 C
+ATOM 1093 C VAL B 52 -32.869 -9.817 -13.125 1.00 55.73 C
+ANISOU 1093 C VAL B 52 7340 6819 7014 951 455 -71 C
+ATOM 1094 O VAL B 52 -33.750 -9.385 -12.411 1.00 58.68 O
+ANISOU 1094 O VAL B 52 7692 7253 7351 1160 545 -97 O
+ATOM 1095 CB VAL B 52 -33.490 -12.237 -13.328 1.00 54.96 C
+ANISOU 1095 CB VAL B 52 6806 7103 6972 744 375 55 C
+ATOM 1096 CG1 VAL B 52 -34.003 -12.011 -14.775 1.00 52.68 C
+ANISOU 1096 CG1 VAL B 52 6472 6811 6730 819 290 142 C
+ATOM 1097 CG2 VAL B 52 -33.016 -13.669 -13.135 1.00 50.23 C
+ANISOU 1097 CG2 VAL B 52 6115 6592 6375 524 325 77 C
+ATOM 1098 N VAL B 53 -32.237 -9.071 -14.009 1.00 58.89 N
+ANISOU 1098 N VAL B 53 7936 7012 7426 915 408 -62 N
+ATOM 1099 CA VAL B 53 -32.688 -7.736 -14.395 1.00 62.70 C
+ANISOU 1099 CA VAL B 53 8634 7295 7891 1137 434 -54 C
+ATOM 1100 C VAL B 53 -33.762 -7.758 -15.502 1.00 61.16 C
+ANISOU 1100 C VAL B 53 8295 7206 7737 1336 378 79 C
+ATOM 1101 O VAL B 53 -34.656 -6.932 -15.513 1.00 69.08 O
+ANISOU 1101 O VAL B 53 9355 8170 8723 1636 413 102 O
+ATOM 1102 CB VAL B 53 -31.492 -6.995 -14.961 1.00 67.39 C
+ANISOU 1102 CB VAL B 53 9512 7623 8467 954 398 -72 C
+ATOM 1103 CG1 VAL B 53 -31.901 -5.593 -15.416 1.00 75.74 C
+ANISOU 1103 CG1 VAL B 53 10871 8410 9495 1168 416 -46 C
+ATOM 1104 CG2 VAL B 53 -30.375 -6.982 -13.920 1.00 67.44 C
+ANISOU 1104 CG2 VAL B 53 9626 7572 8426 722 423 -198 C
+ATOM 1105 N SER B 54 -33.617 -8.645 -16.484 1.00 54.51 N
+ANISOU 1105 N SER B 54 7294 6485 6931 1182 280 163 N
+ATOM 1106 CA SER B 54 -34.604 -8.785 -17.528 1.00 57.42 C
+ANISOU 1106 CA SER B 54 7508 6990 7316 1325 196 285 C
+ATOM 1107 C SER B 54 -34.480 -10.128 -18.163 1.00 49.00 C
+ANISOU 1107 C SER B 54 6241 6104 6271 1103 103 329 C
+ATOM 1108 O SER B 54 -33.420 -10.732 -18.126 1.00 48.61 O
+ANISOU 1108 O SER B 54 6245 6001 6221 872 101 279 O
+ATOM 1109 CB SER B 54 -34.457 -7.676 -18.615 1.00 67.92 C
+ANISOU 1109 CB SER B 54 9097 8093 8615 1441 149 357 C
+ATOM 1110 OG SER B 54 -33.212 -7.732 -19.310 1.00 68.84 O
+ANISOU 1110 OG SER B 54 9383 8061 8712 1181 119 358 O
+ATOM 1111 N GLY B 55 -35.568 -10.582 -18.760 1.00 49.29 N
+ANISOU 1111 N GLY B 55 6054 6357 6315 1182 19 420 N
+ATOM 1112 CA GLY B 55 -35.709 -11.925 -19.288 1.00 50.10 C
+ANISOU 1112 CA GLY B 55 5974 6638 6423 971 -80 453 C
+ATOM 1113 C GLY B 55 -36.015 -12.954 -18.190 1.00 54.88 C
+ANISOU 1113 C GLY B 55 6384 7412 7052 843 -31 418 C
+ATOM 1114 O GLY B 55 -36.357 -12.606 -17.055 1.00 51.85 O
+ANISOU 1114 O GLY B 55 5948 7078 6673 954 81 384 O
+ATOM 1115 N SER B 56 -35.910 -14.235 -18.540 1.00 52.05 N
+ANISOU 1115 N SER B 56 5952 7132 6691 610 -114 429 N
+ATOM 1116 CA SER B 56 -36.309 -15.287 -17.628 1.00 53.81 C
+ANISOU 1116 CA SER B 56 6017 7504 6924 461 -86 428 C
+ATOM 1117 C SER B 56 -35.313 -16.444 -17.548 1.00 48.18 C
+ANISOU 1117 C SER B 56 5432 6672 6199 230 -112 379 C
+ATOM 1118 O SER B 56 -34.496 -16.695 -18.438 1.00 51.01 O
+ANISOU 1118 O SER B 56 5943 6898 6540 166 -175 352 O
+ATOM 1119 CB SER B 56 -37.721 -15.783 -17.988 1.00 54.48 C
+ANISOU 1119 CB SER B 56 5818 7872 7006 422 -173 525 C
+ATOM 1120 OG SER B 56 -37.776 -16.208 -19.330 1.00 61.00 O
+ANISOU 1120 OG SER B 56 6673 8698 7805 316 -335 559 O
+ATOM 1121 N VAL B 57 -35.377 -17.125 -16.430 1.00 52.89 N
+ANISOU 1121 N VAL B 57 5977 7324 6794 133 -50 372 N
+ATOM 1122 CA VAL B 57 -34.589 -18.335 -16.192 1.00 52.55 C
+ANISOU 1122 CA VAL B 57 6056 7179 6732 -51 -77 346 C
+ATOM 1123 C VAL B 57 -35.550 -19.389 -15.674 1.00 55.14 C
+ANISOU 1123 C VAL B 57 6247 7658 7045 -229 -95 418 C
+ATOM 1124 O VAL B 57 -36.603 -19.052 -15.133 1.00 53.51 O
+ANISOU 1124 O VAL B 57 5830 7660 6841 -192 -35 473 O
+ATOM 1125 CB VAL B 57 -33.487 -18.134 -15.162 1.00 52.68 C
+ANISOU 1125 CB VAL B 57 6199 7082 6734 -9 13 278 C
+ATOM 1126 CG1 VAL B 57 -32.429 -17.171 -15.703 1.00 51.20 C
+ANISOU 1126 CG1 VAL B 57 6147 6751 6553 92 24 213 C
+ATOM 1127 CG2 VAL B 57 -34.091 -17.723 -13.810 1.00 53.07 C
+ANISOU 1127 CG2 VAL B 57 6147 7252 6763 53 130 286 C
+ATOM 1128 N ASP B 58 -35.198 -20.651 -15.913 1.00 54.40 N
+ANISOU 1128 N ASP B 58 6283 7459 6926 -420 -174 422 N
+ATOM 1129 CA ASP B 58 -35.847 -21.810 -15.319 1.00 52.99 C
+ANISOU 1129 CA ASP B 58 6069 7345 6718 -650 -190 493 C
+ATOM 1130 C ASP B 58 -34.894 -22.245 -14.184 1.00 50.66 C
+ANISOU 1130 C ASP B 58 5942 6913 6390 -637 -113 472 C
+ATOM 1131 O ASP B 58 -33.754 -22.666 -14.424 1.00 47.29 O
+ANISOU 1131 O ASP B 58 5729 6287 5951 -598 -150 415 O
+ATOM 1132 CB ASP B 58 -36.003 -22.916 -16.375 1.00 56.52 C
+ANISOU 1132 CB ASP B 58 6638 7699 7137 -861 -345 501 C
+ATOM 1133 CG ASP B 58 -36.384 -24.259 -15.771 1.00 65.37 C
+ANISOU 1133 CG ASP B 58 7842 8781 8214 -1139 -373 568 C
+ATOM 1134 OD1 ASP B 58 -36.846 -24.290 -14.603 1.00 66.65 O
+ANISOU 1134 OD1 ASP B 58 7883 9073 8365 -1194 -270 640 O
+ATOM 1135 OD2 ASP B 58 -36.259 -25.280 -16.483 1.00 70.20 O
+ANISOU 1135 OD2 ASP B 58 8664 9224 8785 -1310 -494 551 O
+ATOM 1136 N GLN B 59 -35.324 -22.089 -12.942 1.00 54.05 N
+ANISOU 1136 N GLN B 59 6267 7475 6792 -640 -1 517 N
+ATOM 1137 CA GLN B 59 -34.515 -22.555 -11.829 1.00 56.53 C
+ANISOU 1137 CA GLN B 59 6742 7686 7049 -640 51 516 C
+ATOM 1138 C GLN B 59 -35.268 -23.486 -10.889 1.00 59.14 C
+ANISOU 1138 C GLN B 59 7050 8107 7313 -851 94 632 C
+ATOM 1139 O GLN B 59 -35.188 -23.390 -9.661 1.00 65.41 O
+ANISOU 1139 O GLN B 59 7848 8966 8035 -822 198 658 O
+ATOM 1140 CB GLN B 59 -33.848 -21.372 -11.086 1.00 52.52 C
+ANISOU 1140 CB GLN B 59 6227 7196 6529 -422 151 436 C
+ATOM 1141 CG GLN B 59 -34.803 -20.396 -10.480 1.00 52.17 C
+ANISOU 1141 CG GLN B 59 5988 7361 6471 -326 274 442 C
+ATOM 1142 CD GLN B 59 -34.109 -19.292 -9.719 1.00 53.41 C
+ANISOU 1142 CD GLN B 59 6218 7483 6592 -139 359 343 C
+ATOM 1143 OE1 GLN B 59 -33.067 -19.483 -9.016 1.00 53.43 O
+ANISOU 1143 OE1 GLN B 59 6375 7387 6535 -140 352 304 O
+ATOM 1144 NE2 GLN B 59 -34.697 -18.133 -9.795 1.00 52.42 N
+ANISOU 1144 NE2 GLN B 59 5992 7441 6483 26 432 304 N
+ATOM 1145 N SER B 60 -35.956 -24.435 -11.476 1.00 61.58 N
+ANISOU 1145 N SER B 60 7365 8407 7623 -1092 6 703 N
+ATOM 1146 CA SER B 60 -36.740 -25.363 -10.706 1.00 72.30 C
+ANISOU 1146 CA SER B 60 8709 9847 8911 -1360 39 834 C
+ATOM 1147 C SER B 60 -35.825 -26.402 -10.017 1.00 74.05 C
+ANISOU 1147 C SER B 60 9269 9808 9057 -1412 17 868 C
+ATOM 1148 O SER B 60 -36.221 -27.047 -9.059 1.00 79.84 O
+ANISOU 1148 O SER B 60 10049 10581 9705 -1588 76 985 O
+ATOM 1149 CB SER B 60 -37.836 -25.999 -11.579 1.00 70.49 C
+ANISOU 1149 CB SER B 60 8372 9709 8700 -1655 -64 902 C
+ATOM 1150 OG SER B 60 -37.380 -26.382 -12.862 1.00 66.63 O
+ANISOU 1150 OG SER B 60 8069 9001 8245 -1672 -224 825 O
+ATOM 1151 N ASP B 61 -34.586 -26.497 -10.469 1.00 73.32 N
+ANISOU 1151 N ASP B 61 9398 9476 8984 -1231 -57 775 N
+ATOM 1152 CA ASP B 61 -33.572 -27.336 -9.811 1.00 80.97 C
+ANISOU 1152 CA ASP B 61 10666 10220 9879 -1177 -83 802 C
+ATOM 1153 C ASP B 61 -32.954 -26.686 -8.541 1.00 78.11 C
+ANISOU 1153 C ASP B 61 10262 9960 9455 -993 15 795 C
+ATOM 1154 O ASP B 61 -32.067 -27.263 -7.927 1.00 77.14 O
+ANISOU 1154 O ASP B 61 10352 9697 9259 -910 -16 823 O
+ATOM 1155 CB ASP B 61 -32.442 -27.683 -10.824 1.00 80.12 C
+ANISOU 1155 CB ASP B 61 10771 9865 9803 -1012 -194 700 C
+ATOM 1156 CG ASP B 61 -32.957 -28.443 -12.071 1.00 80.27 C
+ANISOU 1156 CG ASP B 61 10914 9741 9842 -1194 -306 687 C
+ATOM 1157 OD1 ASP B 61 -34.142 -28.856 -12.081 1.00 92.44 O
+ANISOU 1157 OD1 ASP B 61 12396 11355 11371 -1491 -323 772 O
+ATOM 1158 OD2 ASP B 61 -32.182 -28.623 -13.047 1.00 76.90 O
+ANISOU 1158 OD2 ASP B 61 10638 9149 9429 -1052 -377 588 O
+ATOM 1159 N GLN B 62 -33.390 -25.476 -8.178 1.00 79.30 N
+ANISOU 1159 N GLN B 62 10161 10347 9623 -909 123 751 N
+ATOM 1160 CA GLN B 62 -32.867 -24.772 -7.012 1.00 68.13 C
+ANISOU 1160 CA GLN B 62 8730 9027 8129 -755 210 719 C
+ATOM 1161 C GLN B 62 -33.726 -25.126 -5.824 1.00 70.39 C
+ANISOU 1161 C GLN B 62 8983 9467 8294 -906 322 843 C
+ATOM 1162 O GLN B 62 -34.807 -25.613 -6.012 1.00 70.22 O
+ANISOU 1162 O GLN B 62 8868 9532 8279 -1119 351 940 O
+ATOM 1163 CB GLN B 62 -32.896 -23.248 -7.236 1.00 67.38 C
+ANISOU 1163 CB GLN B 62 8445 9063 8093 -577 276 593 C
+ATOM 1164 CG GLN B 62 -34.246 -22.561 -6.972 1.00 69.55 C
+ANISOU 1164 CG GLN B 62 8479 9582 8363 -600 408 617 C
+ATOM 1165 CD GLN B 62 -34.463 -22.057 -5.534 1.00 62.14 C
+ANISOU 1165 CD GLN B 62 7513 8808 7289 -536 557 618 C
+ATOM 1166 OE1 GLN B 62 -33.521 -21.731 -4.823 1.00 54.90 O
+ANISOU 1166 OE1 GLN B 62 6736 7827 6294 -429 553 551 O
+ATOM 1167 NE2 GLN B 62 -35.725 -21.958 -5.128 1.00 63.75 N
+ANISOU 1167 NE2 GLN B 62 7519 9253 7449 -599 689 690 N
+ATOM 1168 N SER B 63 -33.270 -24.812 -4.615 1.00 70.67 N
+ANISOU 1168 N SER B 63 9076 9569 8205 -808 389 839 N
+ATOM 1169 CA SER B 63 -34.035 -25.114 -3.403 1.00 75.26 C
+ANISOU 1169 CA SER B 63 9643 10319 8633 -940 519 961 C
+ATOM 1170 C SER B 63 -33.862 -24.131 -2.248 1.00 70.31 C
+ANISOU 1170 C SER B 63 8977 9863 7874 -780 639 888 C
+ATOM 1171 O SER B 63 -34.598 -24.210 -1.268 1.00 78.27 O
+ANISOU 1171 O SER B 63 9939 11060 8737 -863 783 973 O
+ATOM 1172 CB SER B 63 -33.622 -26.492 -2.865 1.00 78.05 C
+ANISOU 1172 CB SER B 63 10283 10493 8878 -1077 445 1110 C
+ATOM 1173 OG SER B 63 -32.682 -26.352 -1.790 1.00 90.02 O
+ANISOU 1173 OG SER B 63 11950 12004 10249 -923 435 1099 O
+ATOM 1174 N PHE B 64 -32.871 -23.255 -2.316 1.00 65.41 N
+ANISOU 1174 N PHE B 64 8394 9180 7277 -573 583 734 N
+ATOM 1175 CA PHE B 64 -32.513 -22.466 -1.160 1.00 66.55 C
+ANISOU 1175 CA PHE B 64 8587 9435 7264 -453 656 655 C
+ATOM 1176 C PHE B 64 -33.316 -21.199 -1.122 1.00 68.15 C
+ANISOU 1176 C PHE B 64 8618 9800 7476 -340 809 543 C
+ATOM 1177 O PHE B 64 -33.653 -20.718 -0.042 1.00 74.02 O
+ANISOU 1177 O PHE B 64 9375 10700 8049 -284 945 514 O
+ATOM 1178 CB PHE B 64 -31.016 -22.107 -1.193 1.00 68.74 C
+ANISOU 1178 CB PHE B 64 8990 9582 7543 -323 508 542 C
+ATOM 1179 CG PHE B 64 -30.513 -21.437 0.066 1.00 66.26 C
+ANISOU 1179 CG PHE B 64 8771 9370 7032 -245 537 461 C
+ATOM 1180 CD1 PHE B 64 -30.170 -22.204 1.194 1.00 72.14 C
+ANISOU 1180 CD1 PHE B 64 9675 10158 7576 -288 506 569 C
+ATOM 1181 CD2 PHE B 64 -30.367 -20.052 0.126 1.00 68.69 C
+ANISOU 1181 CD2 PHE B 64 9050 9711 7337 -137 581 279 C
+ATOM 1182 CE1 PHE B 64 -29.710 -21.588 2.347 1.00 71.63 C
+ANISOU 1182 CE1 PHE B 64 9709 10202 7302 -228 515 487 C
+ATOM 1183 CE2 PHE B 64 -29.898 -19.430 1.275 1.00 69.45 C
+ANISOU 1183 CE2 PHE B 64 9273 9885 7231 -91 592 184 C
+ATOM 1184 CZ PHE B 64 -29.571 -20.192 2.381 1.00 72.58 C
+ANISOU 1184 CZ PHE B 64 9799 10357 7420 -139 555 283 C
+ATOM 1185 N LEU B 65 -33.564 -20.610 -2.286 1.00 63.83 N
+ANISOU 1185 N LEU B 65 7937 9206 7106 -274 785 473 N
+ATOM 1186 CA LEU B 65 -34.355 -19.387 -2.350 1.00 66.16 C
+ANISOU 1186 CA LEU B 65 8089 9630 7419 -115 921 375 C
+ATOM 1187 C LEU B 65 -35.835 -19.702 -2.078 1.00 70.47 C
+ANISOU 1187 C LEU B 65 8411 10440 7921 -180 1083 494 C
+ATOM 1188 O LEU B 65 -36.350 -20.690 -2.636 1.00 62.63 O
+ANISOU 1188 O LEU B 65 7317 9477 7002 -379 1035 634 O
+ATOM 1189 CB LEU B 65 -34.235 -18.733 -3.729 1.00 59.60 C
+ANISOU 1189 CB LEU B 65 7191 8674 6779 -25 837 299 C
+ATOM 1190 CG LEU B 65 -32.861 -18.246 -4.188 1.00 57.76 C
+ANISOU 1190 CG LEU B 65 7120 8221 6602 27 700 183 C
+ATOM 1191 CD1 LEU B 65 -32.917 -17.582 -5.576 1.00 57.81 C
+ANISOU 1191 CD1 LEU B 65 7061 8127 6775 102 646 135 C
+ATOM 1192 CD2 LEU B 65 -32.327 -17.275 -3.169 1.00 54.39 C
+ANISOU 1192 CD2 LEU B 65 6839 7788 6036 131 752 49 C
+ATOM 1193 N ASP B 66 -36.487 -18.860 -1.244 1.00 74.89 N
+ANISOU 1193 N ASP B 66 8903 11198 8353 -19 1274 433 N
+ATOM 1194 CA ASP B 66 -37.951 -18.868 -1.031 1.00 83.97 C
+ANISOU 1194 CA ASP B 66 9768 12675 9461 -11 1464 525 C
+ATOM 1195 C ASP B 66 -38.674 -18.077 -2.147 1.00 89.05 C
+ANISOU 1195 C ASP B 66 10182 13382 10272 163 1465 482 C
+ATOM 1196 O ASP B 66 -38.020 -17.512 -3.028 1.00 82.08 O
+ANISOU 1196 O ASP B 66 9403 12261 9520 266 1329 383 O
+ATOM 1197 CB ASP B 66 -38.358 -18.435 0.427 1.00 96.74 C
+ANISOU 1197 CB ASP B 66 11411 14515 10828 108 1694 490 C
+ATOM 1198 CG ASP B 66 -37.950 -16.966 0.829 1.00101.11 C
+ANISOU 1198 CG ASP B 66 12141 14972 11304 434 1759 259 C
+ATOM 1199 OD1 ASP B 66 -37.822 -16.062 -0.014 1.00103.38 O
+ANISOU 1199 OD1 ASP B 66 12437 15111 11732 617 1698 145 O
+ATOM 1200 OD2 ASP B 66 -37.801 -16.698 2.048 1.00107.31 O
+ANISOU 1200 OD2 ASP B 66 13086 15829 11857 502 1880 192 O
+ATOM 1201 N ASP B 67 -40.005 -18.040 -2.158 1.00 86.95 N
+ANISOU 1201 N ASP B 67 9589 13450 9995 197 1609 569 N
+ATOM 1202 CA ASP B 67 -40.677 -17.431 -3.312 1.00 90.53 C
+ANISOU 1202 CA ASP B 67 9811 13977 10608 358 1567 559 C
+ATOM 1203 C ASP B 67 -40.717 -15.891 -3.254 1.00 86.24 C
+ANISOU 1203 C ASP B 67 9333 13386 10046 784 1662 390 C
+ATOM 1204 O ASP B 67 -40.642 -15.233 -4.281 1.00 81.53 O
+ANISOU 1204 O ASP B 67 8742 12650 9585 940 1557 340 O
+ATOM 1205 CB ASP B 67 -42.050 -18.071 -3.552 1.00102.24 C
+ANISOU 1205 CB ASP B 67 10878 15858 12109 201 1632 735 C
+ATOM 1206 CG ASP B 67 -41.961 -19.594 -3.777 1.00110.12 C
+ANISOU 1206 CG ASP B 67 11890 16814 13135 -260 1502 895 C
+ATOM 1207 OD1 ASP B 67 -41.291 -20.027 -4.737 1.00 98.84 O
+ANISOU 1207 OD1 ASP B 67 10618 15101 11835 -390 1286 884 O
+ATOM 1208 OD2 ASP B 67 -42.569 -20.364 -2.992 1.00123.31 O
+ANISOU 1208 OD2 ASP B 67 13438 18728 14684 -494 1624 1033 O
+ATOM 1209 N GLU B 68 -40.822 -15.309 -2.066 1.00 91.45 N
+ANISOU 1209 N GLU B 68 10086 14137 10521 974 1859 301 N
+ATOM 1210 CA GLU B 68 -40.562 -13.877 -1.887 1.00 92.79 C
+ANISOU 1210 CA GLU B 68 10476 14135 10644 1350 1926 105 C
+ATOM 1211 C GLU B 68 -39.357 -13.490 -2.763 1.00 88.95 C
+ANISOU 1211 C GLU B 68 10277 13221 10296 1308 1700 12 C
+ATOM 1212 O GLU B 68 -39.451 -12.586 -3.592 1.00 86.77 O
+ANISOU 1212 O GLU B 68 10035 12811 10122 1529 1655 -46 O
+ATOM 1213 CB GLU B 68 -40.252 -13.581 -0.409 1.00103.28 C
+ANISOU 1213 CB GLU B 68 12042 15476 11725 1425 2090 -9 C
+ATOM 1214 CG GLU B 68 -39.658 -12.210 -0.110 1.00110.78 C
+ANISOU 1214 CG GLU B 68 13356 16139 12594 1717 2114 -242 C
+ATOM 1215 CD GLU B 68 -40.711 -11.114 -0.156 1.00127.27 C
+ANISOU 1215 CD GLU B 68 15344 18364 14648 2164 2303 -314 C
+ATOM 1216 OE1 GLU B 68 -41.594 -11.091 0.736 1.00128.34 O
+ANISOU 1216 OE1 GLU B 68 15322 18834 14608 2332 2547 -306 O
+ATOM 1217 OE2 GLU B 68 -40.658 -10.276 -1.086 1.00135.31 O
+ANISOU 1217 OE2 GLU B 68 16444 19164 15804 2367 2214 -371 O
+ATOM 1218 N GLN B 69 -38.246 -14.206 -2.567 1.00 72.49 N
+ANISOU 1218 N GLN B 69 8389 10950 8204 1029 1565 15 N
+ATOM 1219 CA GLN B 69 -36.950 -13.911 -3.200 1.00 73.21 C
+ANISOU 1219 CA GLN B 69 8740 10685 8389 958 1373 -72 C
+ATOM 1220 C GLN B 69 -36.830 -14.132 -4.727 1.00 65.48 C
+ANISOU 1220 C GLN B 69 7666 9593 7621 882 1203 -2 C
+ATOM 1221 O GLN B 69 -36.176 -13.383 -5.439 1.00 63.34 O
+ANISOU 1221 O GLN B 69 7557 9080 7428 951 1109 -83 O
+ATOM 1222 CB GLN B 69 -35.889 -14.744 -2.517 1.00 75.50 C
+ANISOU 1222 CB GLN B 69 9196 10892 8596 710 1285 -63 C
+ATOM 1223 CG GLN B 69 -35.602 -14.267 -1.103 1.00 78.45 C
+ANISOU 1223 CG GLN B 69 9777 11287 8741 786 1396 -180 C
+ATOM 1224 CD GLN B 69 -34.680 -15.215 -0.356 1.00 80.20 C
+ANISOU 1224 CD GLN B 69 10125 11490 8855 555 1301 -133 C
+ATOM 1225 OE1 GLN B 69 -34.695 -16.439 -0.569 1.00 76.67 O
+ANISOU 1225 OE1 GLN B 69 9569 11099 8460 360 1233 26 O
+ATOM 1226 NE2 GLN B 69 -33.869 -14.655 0.531 1.00 79.87 N
+ANISOU 1226 NE2 GLN B 69 10337 11359 8650 578 1283 -273 N
+ATOM 1227 N ILE B 70 -37.462 -15.169 -5.220 1.00 61.39 N
+ANISOU 1227 N ILE B 70 6901 9247 7174 715 1163 150 N
+ATOM 1228 CA ILE B 70 -37.598 -15.345 -6.623 1.00 62.15 C
+ANISOU 1228 CA ILE B 70 6889 9291 7432 668 1022 213 C
+ATOM 1229 C ILE B 70 -38.394 -14.186 -7.226 1.00 73.71 C
+ANISOU 1229 C ILE B 70 8249 10811 8945 974 1070 184 C
+ATOM 1230 O ILE B 70 -37.990 -13.601 -8.254 1.00 73.86 O
+ANISOU 1230 O ILE B 70 8375 10629 9058 1051 959 151 O
+ATOM 1231 CB ILE B 70 -38.275 -16.689 -6.902 1.00 63.18 C
+ANISOU 1231 CB ILE B 70 6790 9618 7596 406 976 375 C
+ATOM 1232 CG1 ILE B 70 -37.310 -17.798 -6.413 1.00 66.78 C
+ANISOU 1232 CG1 ILE B 70 7440 9927 8005 147 902 402 C
+ATOM 1233 CG2 ILE B 70 -38.638 -16.782 -8.387 1.00 57.25 C
+ANISOU 1233 CG2 ILE B 70 5905 8860 6984 377 830 431 C
+ATOM 1234 CD1 ILE B 70 -37.651 -19.227 -6.791 1.00 70.61 C
+ANISOU 1234 CD1 ILE B 70 7840 10465 8522 -155 814 547 C
+ATOM 1235 N GLY B 71 -39.521 -13.852 -6.588 1.00 75.76 N
+ANISOU 1235 N GLY B 71 8304 11355 9126 1166 1244 206 N
+ATOM 1236 CA GLY B 71 -40.376 -12.761 -7.036 1.00 72.95 C
+ANISOU 1236 CA GLY B 71 7834 11088 8796 1528 1307 188 C
+ATOM 1237 C GLY B 71 -39.624 -11.447 -7.147 1.00 76.38 C
+ANISOU 1237 C GLY B 71 8635 11163 9222 1770 1297 33 C
+ATOM 1238 O GLY B 71 -39.883 -10.642 -8.039 1.00 79.14 O
+ANISOU 1238 O GLY B 71 9008 11417 9641 1993 1244 36 O
+ATOM 1239 N GLU B 72 -38.660 -11.230 -6.267 1.00 77.34 N
+ANISOU 1239 N GLU B 72 9065 11073 9246 1700 1332 -94 N
+ATOM 1240 CA GLU B 72 -37.776 -10.071 -6.409 1.00 82.72 C
+ANISOU 1240 CA GLU B 72 10132 11378 9918 1818 1290 -240 C
+ATOM 1241 C GLU B 72 -36.680 -10.326 -7.459 1.00 73.65 C
+ANISOU 1241 C GLU B 72 9106 9983 8893 1567 1086 -215 C
+ATOM 1242 O GLU B 72 -35.725 -9.562 -7.537 1.00 70.35 O
+ANISOU 1242 O GLU B 72 8999 9266 8462 1543 1035 -321 O
+ATOM 1243 CB GLU B 72 -37.154 -9.705 -5.053 1.00 94.77 C
+ANISOU 1243 CB GLU B 72 11940 12798 11270 1810 1386 -397 C
+ATOM 1244 CG GLU B 72 -38.118 -9.911 -3.884 1.00110.12 C
+ANISOU 1244 CG GLU B 72 13720 15060 13058 1957 1598 -397 C
+ATOM 1245 CD GLU B 72 -37.932 -8.936 -2.746 1.00125.11 C
+ANISOU 1245 CD GLU B 72 15946 16831 14757 2160 1737 -591 C
+ATOM 1246 OE1 GLU B 72 -38.918 -8.231 -2.409 1.00134.61 O
+ANISOU 1246 OE1 GLU B 72 17112 18158 15874 2531 1921 -638 O
+ATOM 1247 OE2 GLU B 72 -36.813 -8.896 -2.185 1.00125.40 O
+ANISOU 1247 OE2 GLU B 72 16271 16663 14709 1956 1661 -698 O
+ATOM 1248 N GLY B 73 -36.799 -11.410 -8.233 1.00 65.49 N
+ANISOU 1248 N GLY B 73 7839 9083 7962 1362 977 -81 N
+ATOM 1249 CA GLY B 73 -35.815 -11.747 -9.280 1.00 62.64 C
+ANISOU 1249 CA GLY B 73 7570 8528 7700 1152 805 -56 C
+ATOM 1250 C GLY B 73 -34.511 -12.432 -8.913 1.00 64.69 C
+ANISOU 1250 C GLY B 73 7964 8676 7938 882 732 -95 C
+ATOM 1251 O GLY B 73 -33.621 -12.552 -9.759 1.00 61.13 O
+ANISOU 1251 O GLY B 73 7598 8075 7554 753 615 -91 O
+ATOM 1252 N PHE B 74 -34.380 -12.937 -7.687 1.00 63.75 N
+ANISOU 1252 N PHE B 74 7851 8656 7716 805 798 -121 N
+ATOM 1253 CA PHE B 74 -33.146 -13.627 -7.305 1.00 53.01 C
+ANISOU 1253 CA PHE B 74 6598 7217 6322 587 711 -142 C
+ATOM 1254 C PHE B 74 -32.988 -14.972 -7.975 1.00 47.15 C
+ANISOU 1254 C PHE B 74 5729 6525 5658 405 605 -25 C
+ATOM 1255 O PHE B 74 -33.925 -15.691 -8.210 1.00 47.19 O
+ANISOU 1255 O PHE B 74 5555 6679 5693 369 619 77 O
+ATOM 1256 CB PHE B 74 -33.033 -13.757 -5.799 1.00 57.58 C
+ANISOU 1256 CB PHE B 74 7252 7883 6742 571 795 -193 C
+ATOM 1257 CG PHE B 74 -32.721 -12.455 -5.116 1.00 62.39 C
+ANISOU 1257 CG PHE B 74 8094 8364 7244 697 859 -353 C
+ATOM 1258 CD1 PHE B 74 -31.451 -11.886 -5.228 1.00 64.10 C
+ANISOU 1258 CD1 PHE B 74 8521 8379 7455 591 755 -452 C
+ATOM 1259 CD2 PHE B 74 -33.694 -11.780 -4.360 1.00 68.55 C
+ANISOU 1259 CD2 PHE B 74 8895 9233 7917 917 1026 -411 C
+ATOM 1260 CE1 PHE B 74 -31.155 -10.674 -4.606 1.00 68.98 C
+ANISOU 1260 CE1 PHE B 74 9402 8846 7962 659 796 -610 C
+ATOM 1261 CE2 PHE B 74 -33.400 -10.578 -3.721 1.00 69.76 C
+ANISOU 1261 CE2 PHE B 74 9331 9224 7950 1040 1082 -581 C
+ATOM 1262 CZ PHE B 74 -32.132 -10.015 -3.852 1.00 73.33 C
+ANISOU 1262 CZ PHE B 74 10030 9434 8398 891 957 -683 C
+ATOM 1263 N VAL B 75 -31.754 -15.313 -8.293 1.00 47.62 N
+ANISOU 1263 N VAL B 75 5890 6460 5740 284 497 -46 N
+ATOM 1264 CA VAL B 75 -31.467 -16.527 -9.040 1.00 46.67 C
+ANISOU 1264 CA VAL B 75 5712 6336 5685 155 395 39 C
+ATOM 1265 C VAL B 75 -30.245 -17.245 -8.471 1.00 44.46 C
+ANISOU 1265 C VAL B 75 5526 6018 5347 63 327 28 C
+ATOM 1266 O VAL B 75 -29.283 -16.611 -8.088 1.00 45.81 O
+ANISOU 1266 O VAL B 75 5789 6141 5474 68 309 -55 O
+ATOM 1267 CB VAL B 75 -31.345 -16.225 -10.573 1.00 48.40 C
+ANISOU 1267 CB VAL B 75 5921 6459 6009 172 323 45 C
+ATOM 1268 CG1 VAL B 75 -30.229 -15.219 -10.891 1.00 49.82 C
+ANISOU 1268 CG1 VAL B 75 6236 6497 6194 190 302 -42 C
+ATOM 1269 CG2 VAL B 75 -31.192 -17.513 -11.372 1.00 52.32 C
+ANISOU 1269 CG2 VAL B 75 6386 6945 6547 57 228 117 C
+ATOM 1270 N LEU B 76 -30.313 -18.572 -8.356 1.00 47.02 N
+ANISOU 1270 N LEU B 76 5836 6371 5658 -24 284 120 N
+ATOM 1271 CA LEU B 76 -29.121 -19.328 -8.132 1.00 46.01 C
+ANISOU 1271 CA LEU B 76 5797 6192 5492 -56 197 127 C
+ATOM 1272 C LEU B 76 -28.512 -19.742 -9.476 1.00 40.71 C
+ANISOU 1272 C LEU B 76 5131 5424 4910 -54 113 128 C
+ATOM 1273 O LEU B 76 -29.048 -20.600 -10.147 1.00 46.45 O
+ANISOU 1273 O LEU B 76 5862 6109 5676 -101 81 191 O
+ATOM 1274 CB LEU B 76 -29.384 -20.509 -7.221 1.00 47.02 C
+ANISOU 1274 CB LEU B 76 5975 6357 5531 -120 195 227 C
+ATOM 1275 CG LEU B 76 -30.003 -20.207 -5.836 1.00 48.21 C
+ANISOU 1275 CG LEU B 76 6126 6635 5556 -128 299 239 C
+ATOM 1276 CD1 LEU B 76 -30.102 -21.517 -5.059 1.00 49.81 C
+ANISOU 1276 CD1 LEU B 76 6416 6849 5659 -217 281 368 C
+ATOM 1277 CD2 LEU B 76 -29.254 -19.158 -5.030 1.00 49.77 C
+ANISOU 1277 CD2 LEU B 76 6382 6864 5663 -57 312 121 C
+ATOM 1278 N THR B 77 -27.369 -19.136 -9.812 1.00 41.43 N
+ANISOU 1278 N THR B 77 5232 5494 5012 -17 79 55 N
+ATOM 1279 CA THR B 77 -26.727 -19.284 -11.128 1.00 40.67 C
+ANISOU 1279 CA THR B 77 5128 5343 4981 1 33 43 C
+ATOM 1280 C THR B 77 -26.271 -20.689 -11.435 1.00 44.46 C
+ANISOU 1280 C THR B 77 5663 5781 5447 32 -31 92 C
+ATOM 1281 O THR B 77 -26.273 -21.097 -12.621 1.00 45.14 O
+ANISOU 1281 O THR B 77 5776 5802 5573 48 -54 93 O
+ATOM 1282 CB THR B 77 -25.599 -18.252 -11.327 1.00 45.56 C
+ANISOU 1282 CB THR B 77 5722 5989 5598 -3 32 -32 C
+ATOM 1283 OG1 THR B 77 -24.616 -18.284 -10.248 1.00 43.74 O
+ANISOU 1283 OG1 THR B 77 5481 5849 5287 -11 -5 -59 O
+ATOM 1284 CG2 THR B 77 -26.220 -16.863 -11.400 1.00 41.29 C
+ANISOU 1284 CG2 THR B 77 5203 5403 5080 -24 94 -78 C
+ATOM 1285 N CYS B 78 -25.967 -21.485 -10.393 1.00 45.27 N
+ANISOU 1285 N CYS B 78 5822 5901 5476 54 -62 136 N
+ATOM 1286 CA CYS B 78 -25.538 -22.878 -10.640 1.00 40.58 C
+ANISOU 1286 CA CYS B 78 5341 5220 4856 123 -127 189 C
+ATOM 1287 C CYS B 78 -26.708 -23.807 -10.971 1.00 41.12 C
+ANISOU 1287 C CYS B 78 5522 5162 4939 26 -135 258 C
+ATOM 1288 O CYS B 78 -26.504 -24.884 -11.423 1.00 43.05 O
+ANISOU 1288 O CYS B 78 5913 5275 5166 63 -188 285 O
+ATOM 1289 CB CYS B 78 -24.806 -23.414 -9.415 1.00 46.97 C
+ANISOU 1289 CB CYS B 78 6199 6078 5566 196 -175 233 C
+ATOM 1290 SG CYS B 78 -25.953 -23.849 -8.071 1.00 49.40 S
+ANISOU 1290 SG CYS B 78 6603 6375 5792 77 -143 334 S
+ATOM 1291 N ALA B 79 -27.946 -23.393 -10.780 1.00 44.78 N
+ANISOU 1291 N ALA B 79 5918 5669 5425 -101 -84 285 N
+ATOM 1292 CA ALA B 79 -29.075 -24.281 -11.005 1.00 47.60 C
+ANISOU 1292 CA ALA B 79 6343 5956 5784 -250 -101 364 C
+ATOM 1293 C ALA B 79 -30.185 -23.636 -11.871 1.00 49.22 C
+ANISOU 1293 C ALA B 79 6406 6233 6061 -337 -80 350 C
+ATOM 1294 O ALA B 79 -31.381 -24.008 -11.779 1.00 50.46 O
+ANISOU 1294 O ALA B 79 6514 6441 6216 -497 -73 423 O
+ATOM 1295 CB ALA B 79 -29.642 -24.689 -9.663 1.00 51.35 C
+ANISOU 1295 CB ALA B 79 6846 6483 6181 -345 -59 459 C
+ATOM 1296 N ALA B 80 -29.766 -22.691 -12.710 1.00 47.73 N
+ANISOU 1296 N ALA B 80 6146 6065 5924 -239 -75 270 N
+ATOM 1297 CA ALA B 80 -30.656 -21.820 -13.483 1.00 47.79 C
+ANISOU 1297 CA ALA B 80 6019 6149 5986 -255 -60 260 C
+ATOM 1298 C ALA B 80 -30.291 -21.968 -14.960 1.00 45.38 C
+ANISOU 1298 C ALA B 80 5782 5759 5701 -235 -129 220 C
+ATOM 1299 O ALA B 80 -29.179 -21.667 -15.325 1.00 42.72 O
+ANISOU 1299 O ALA B 80 5492 5381 5359 -133 -121 162 O
+ATOM 1300 CB ALA B 80 -30.480 -20.367 -13.042 1.00 44.94 C
+ANISOU 1300 CB ALA B 80 5565 5866 5641 -146 20 209 C
+ATOM 1301 N TYR B 81 -31.241 -22.453 -15.772 1.00 45.42 N
+ANISOU 1301 N TYR B 81 5782 5764 5709 -349 -198 253 N
+ATOM 1302 CA TYR B 81 -31.175 -22.431 -17.214 1.00 43.03 C
+ANISOU 1302 CA TYR B 81 5534 5415 5397 -340 -266 217 C
+ATOM 1303 C TYR B 81 -31.816 -21.180 -17.774 1.00 44.38 C
+ANISOU 1303 C TYR B 81 5553 5705 5604 -286 -255 229 C
+ATOM 1304 O TYR B 81 -32.869 -20.780 -17.277 1.00 44.18 O
+ANISOU 1304 O TYR B 81 5365 5812 5607 -312 -236 284 O
+ATOM 1305 CB TYR B 81 -31.969 -23.595 -17.812 1.00 42.89 C
+ANISOU 1305 CB TYR B 81 5610 5343 5342 -522 -376 244 C
+ATOM 1306 CG TYR B 81 -31.528 -24.936 -17.365 1.00 42.13 C
+ANISOU 1306 CG TYR B 81 5733 5076 5198 -585 -404 245 C
+ATOM 1307 CD1 TYR B 81 -30.314 -25.445 -17.790 1.00 44.66 C
+ANISOU 1307 CD1 TYR B 81 6255 5239 5473 -442 -407 173 C
+ATOM 1308 CD2 TYR B 81 -32.339 -25.734 -16.540 1.00 48.75 C
+ANISOU 1308 CD2 TYR B 81 6588 5909 6023 -781 -423 329 C
+ATOM 1309 CE1 TYR B 81 -29.894 -26.718 -17.417 1.00 43.35 C
+ANISOU 1309 CE1 TYR B 81 6335 4883 5252 -447 -440 177 C
+ATOM 1310 CE2 TYR B 81 -31.956 -27.041 -16.215 1.00 49.19 C
+ANISOU 1310 CE2 TYR B 81 6919 5750 6019 -844 -464 343 C
+ATOM 1311 CZ TYR B 81 -30.702 -27.516 -16.640 1.00 48.71 C
+ANISOU 1311 CZ TYR B 81 7087 5502 5916 -648 -475 264 C
+ATOM 1312 OH TYR B 81 -30.184 -28.775 -16.265 1.00 52.95 O
+ANISOU 1312 OH TYR B 81 7931 5800 6387 -626 -510 278 O
+ATOM 1313 N PRO B 82 -31.222 -20.582 -18.851 1.00 42.24 N
+ANISOU 1313 N PRO B 82 5338 5394 5317 -199 -264 189 N
+ATOM 1314 CA PRO B 82 -31.916 -19.427 -19.426 1.00 43.63 C
+ANISOU 1314 CA PRO B 82 5410 5655 5512 -135 -271 223 C
+ATOM 1315 C PRO B 82 -33.193 -19.929 -20.110 1.00 42.47 C
+ANISOU 1315 C PRO B 82 5186 5607 5344 -243 -390 277 C
+ATOM 1316 O PRO B 82 -33.182 -21.018 -20.729 1.00 43.18 O
+ANISOU 1316 O PRO B 82 5392 5637 5378 -371 -481 256 O
+ATOM 1317 CB PRO B 82 -30.922 -18.885 -20.482 1.00 44.26 C
+ANISOU 1317 CB PRO B 82 5608 5658 5550 -62 -258 186 C
+ATOM 1318 CG PRO B 82 -29.978 -19.997 -20.799 1.00 44.00 C
+ANISOU 1318 CG PRO B 82 5714 5541 5462 -94 -268 127 C
+ATOM 1319 CD PRO B 82 -30.010 -20.955 -19.610 1.00 43.22 C
+ANISOU 1319 CD PRO B 82 5616 5415 5388 -148 -264 126 C
+ATOM 1320 N THR B 83 -34.264 -19.156 -20.049 1.00 43.35 N
+ANISOU 1320 N THR B 83 5114 5871 5484 -188 -400 342 N
+ATOM 1321 CA THR B 83 -35.417 -19.426 -20.932 1.00 48.62 C
+ANISOU 1321 CA THR B 83 5669 6684 6117 -276 -540 401 C
+ATOM 1322 C THR B 83 -35.748 -18.249 -21.876 1.00 46.65 C
+ANISOU 1322 C THR B 83 5378 6497 5848 -103 -583 444 C
+ATOM 1323 O THR B 83 -36.739 -18.269 -22.580 1.00 52.22 O
+ANISOU 1323 O THR B 83 5955 7366 6519 -132 -710 507 O
+ATOM 1324 CB THR B 83 -36.648 -19.794 -20.074 1.00 51.91 C
+ANISOU 1324 CB THR B 83 5841 7312 6568 -382 -542 472 C
+ATOM 1325 OG1 THR B 83 -36.869 -18.747 -19.119 1.00 51.49 O
+ANISOU 1325 OG1 THR B 83 5651 7343 6568 -184 -407 493 O
+ATOM 1326 CG2 THR B 83 -36.374 -21.131 -19.339 1.00 48.25 C
+ANISOU 1326 CG2 THR B 83 5482 6756 6094 -602 -531 453 C
+ATOM 1327 N SER B 84 -34.922 -17.220 -21.872 1.00 49.15 N
+ANISOU 1327 N SER B 84 5810 6685 6177 63 -486 421 N
+ATOM 1328 CA SER B 84 -34.968 -16.169 -22.893 1.00 47.46 C
+ANISOU 1328 CA SER B 84 5660 6452 5920 210 -525 469 C
+ATOM 1329 C SER B 84 -33.560 -15.596 -22.849 1.00 44.74 C
+ANISOU 1329 C SER B 84 5522 5905 5571 249 -408 413 C
+ATOM 1330 O SER B 84 -32.757 -15.991 -21.985 1.00 42.92 O
+ANISOU 1330 O SER B 84 5325 5604 5377 186 -319 344 O
+ATOM 1331 CB SER B 84 -35.999 -15.072 -22.468 1.00 52.98 C
+ANISOU 1331 CB SER B 84 6195 7271 6664 424 -504 546 C
+ATOM 1332 OG SER B 84 -35.478 -14.259 -21.372 1.00 56.24 O
+ANISOU 1332 OG SER B 84 6673 7559 7133 543 -346 502 O
+ATOM 1333 N ASP B 85 -33.263 -14.621 -23.694 1.00 42.09 N
+ANISOU 1333 N ASP B 85 5315 5491 5184 344 -407 456 N
+ATOM 1334 CA ASP B 85 -32.096 -13.779 -23.472 1.00 44.39 C
+ANISOU 1334 CA ASP B 85 5767 5616 5481 363 -284 426 C
+ATOM 1335 C ASP B 85 -32.367 -13.068 -22.174 1.00 44.33 C
+ANISOU 1335 C ASP B 85 5710 5574 5557 461 -200 408 C
+ATOM 1336 O ASP B 85 -33.473 -12.654 -21.914 1.00 44.74 O
+ANISOU 1336 O ASP B 85 5658 5704 5635 607 -226 457 O
+ATOM 1337 CB ASP B 85 -31.910 -12.741 -24.580 1.00 50.33 C
+ANISOU 1337 CB ASP B 85 6690 6279 6153 434 -297 505 C
+ATOM 1338 CG ASP B 85 -31.692 -13.380 -25.963 1.00 53.63 C
+ANISOU 1338 CG ASP B 85 7180 6749 6447 352 -376 524 C
+ATOM 1339 OD1 ASP B 85 -31.204 -14.529 -26.022 1.00 47.82 O
+ANISOU 1339 OD1 ASP B 85 6425 6053 5688 233 -377 444 O
+ATOM 1340 OD2 ASP B 85 -32.060 -12.736 -26.984 1.00 54.69 O
+ANISOU 1340 OD2 ASP B 85 7411 6877 6491 428 -443 619 O
+ATOM 1341 N VAL B 86 -31.347 -12.922 -21.361 1.00 40.17 N
+ANISOU 1341 N VAL B 86 5253 4953 5056 392 -100 335 N
+ATOM 1342 CA VAL B 86 -31.545 -12.627 -20.001 1.00 40.95 C
+ANISOU 1342 CA VAL B 86 5304 5044 5208 443 -28 288 C
+ATOM 1343 C VAL B 86 -30.338 -11.876 -19.512 1.00 40.30 C
+ANISOU 1343 C VAL B 86 5380 4811 5117 374 55 227 C
+ATOM 1344 O VAL B 86 -29.225 -12.135 -19.945 1.00 43.19 O
+ANISOU 1344 O VAL B 86 5796 5158 5455 238 66 208 O
+ATOM 1345 CB VAL B 86 -31.795 -13.954 -19.226 1.00 47.21 C
+ANISOU 1345 CB VAL B 86 5933 5975 6029 355 -41 254 C
+ATOM 1346 CG1 VAL B 86 -30.588 -14.864 -19.281 1.00 53.03 C
+ANISOU 1346 CG1 VAL B 86 6718 6685 6745 209 -38 201 C
+ATOM 1347 CG2 VAL B 86 -32.149 -13.690 -17.770 1.00 54.18 C
+ANISOU 1347 CG2 VAL B 86 6757 6889 6939 415 40 215 C
+ATOM 1348 N THR B 87 -30.567 -10.923 -18.633 1.00 40.44 N
+ANISOU 1348 N THR B 87 5478 4736 5147 466 116 194 N
+ATOM 1349 CA THR B 87 -29.526 -10.137 -17.998 1.00 44.61 C
+ANISOU 1349 CA THR B 87 6175 5117 5656 367 180 122 C
+ATOM 1350 C THR B 87 -29.555 -10.459 -16.518 1.00 45.83 C
+ANISOU 1350 C THR B 87 6259 5336 5818 364 223 34 C
+ATOM 1351 O THR B 87 -30.627 -10.480 -15.920 1.00 50.57 O
+ANISOU 1351 O THR B 87 6782 6002 6428 521 248 34 O
+ATOM 1352 CB THR B 87 -29.811 -8.653 -18.240 1.00 48.52 C
+ANISOU 1352 CB THR B 87 6913 5392 6126 483 206 148 C
+ATOM 1353 OG1 THR B 87 -29.766 -8.415 -19.647 1.00 50.14 O
+ANISOU 1353 OG1 THR B 87 7196 5550 6304 478 160 251 O
+ATOM 1354 CG2 THR B 87 -28.775 -7.748 -17.578 1.00 51.37 C
+ANISOU 1354 CG2 THR B 87 7497 5567 6453 330 258 66 C
+ATOM 1355 N ILE B 88 -28.383 -10.757 -15.950 1.00 46.15 N
+ANISOU 1355 N ILE B 88 6302 5394 5839 188 231 -31 N
+ATOM 1356 CA ILE B 88 -28.248 -11.202 -14.561 1.00 48.38 C
+ANISOU 1356 CA ILE B 88 6524 5758 6100 163 252 -105 C
+ATOM 1357 C ILE B 88 -27.148 -10.356 -13.868 1.00 49.51 C
+ANISOU 1357 C ILE B 88 6821 5800 6187 17 267 -195 C
+ATOM 1358 O ILE B 88 -26.006 -10.333 -14.336 1.00 50.31 O
+ANISOU 1358 O ILE B 88 6922 5912 6279 -155 240 -192 O
+ATOM 1359 CB ILE B 88 -27.854 -12.697 -14.495 1.00 47.16 C
+ANISOU 1359 CB ILE B 88 6193 5770 5956 88 209 -84 C
+ATOM 1360 CG1 ILE B 88 -29.028 -13.550 -14.899 1.00 45.49 C
+ANISOU 1360 CG1 ILE B 88 5857 5647 5780 178 185 -12 C
+ATOM 1361 CG2 ILE B 88 -27.449 -13.095 -13.075 1.00 50.06 C
+ANISOU 1361 CG2 ILE B 88 6533 6211 6275 43 217 -145 C
+ATOM 1362 CD1 ILE B 88 -28.663 -14.921 -15.331 1.00 44.53 C
+ANISOU 1362 CD1 ILE B 88 5652 5603 5664 105 128 18 C
+ATOM 1363 N GLU B 89 -27.473 -9.703 -12.758 1.00 53.87 N
+ANISOU 1363 N GLU B 89 7496 6283 6689 72 309 -278 N
+ATOM 1364 CA GLU B 89 -26.437 -9.087 -11.897 1.00 55.06 C
+ANISOU 1364 CA GLU B 89 7788 6369 6762 -106 296 -383 C
+ATOM 1365 C GLU B 89 -25.875 -10.173 -10.991 1.00 50.59 C
+ANISOU 1365 C GLU B 89 7047 6015 6159 -183 255 -407 C
+ATOM 1366 O GLU B 89 -26.632 -10.952 -10.372 1.00 53.81 O
+ANISOU 1366 O GLU B 89 7350 6536 6558 -58 279 -389 O
+ATOM 1367 CB GLU B 89 -26.978 -7.962 -10.983 1.00 64.61 C
+ANISOU 1367 CB GLU B 89 9255 7398 7894 -8 353 -489 C
+ATOM 1368 CG GLU B 89 -27.906 -6.925 -11.597 1.00 75.35 C
+ANISOU 1368 CG GLU B 89 10817 8537 9275 195 408 -466 C
+ATOM 1369 CD GLU B 89 -28.548 -5.964 -10.562 1.00 82.40 C
+ANISOU 1369 CD GLU B 89 11968 9264 10073 373 485 -588 C
+ATOM 1370 OE1 GLU B 89 -29.068 -6.404 -9.504 1.00 81.15 O
+ANISOU 1370 OE1 GLU B 89 11720 9254 9857 488 538 -645 O
+ATOM 1371 OE2 GLU B 89 -28.574 -4.751 -10.836 1.00 78.16 O
+ANISOU 1371 OE2 GLU B 89 11754 8436 9505 415 502 -623 O
+ATOM 1372 N THR B 90 -24.559 -10.217 -10.878 1.00 51.58 N
+ANISOU 1372 N THR B 90 7135 6210 6250 -392 193 -434 N
+ATOM 1373 CA THR B 90 -23.886 -11.258 -10.104 1.00 50.76 C
+ANISOU 1373 CA THR B 90 6862 6321 6103 -439 132 -438 C
+ATOM 1374 C THR B 90 -23.428 -10.795 -8.698 1.00 54.51 C
+ANISOU 1374 C THR B 90 7442 6820 6450 -544 93 -549 C
+ATOM 1375 O THR B 90 -23.592 -9.656 -8.337 1.00 56.29 O
+ANISOU 1375 O THR B 90 7894 6876 6618 -596 118 -640 O
+ATOM 1376 CB THR B 90 -22.680 -11.779 -10.880 1.00 51.05 C
+ANISOU 1376 CB THR B 90 6727 6500 6170 -558 78 -385 C
+ATOM 1377 OG1 THR B 90 -21.707 -10.743 -11.014 1.00 54.51 O
+ANISOU 1377 OG1 THR B 90 7235 6905 6570 -789 55 -432 O
+ATOM 1378 CG2 THR B 90 -23.111 -12.265 -12.264 1.00 50.66 C
+ANISOU 1378 CG2 THR B 90 6610 6424 6212 -455 115 -293 C
+ATOM 1379 N HIS B 91 -22.903 -11.730 -7.904 1.00 57.41 N
+ANISOU 1379 N HIS B 91 7670 7387 6755 -556 26 -538 N
+ATOM 1380 CA HIS B 91 -22.350 -11.451 -6.562 1.00 53.16 C
+ANISOU 1380 CA HIS B 91 7206 6925 6066 -666 -42 -633 C
+ATOM 1381 C HIS B 91 -23.379 -10.865 -5.635 1.00 52.82 C
+ANISOU 1381 C HIS B 91 7383 6755 5930 -566 36 -720 C
+ATOM 1382 O HIS B 91 -23.140 -9.839 -5.055 1.00 57.23 O
+ANISOU 1382 O HIS B 91 8152 7207 6385 -681 21 -845 O
+ATOM 1383 CB HIS B 91 -21.120 -10.564 -6.646 1.00 52.81 C
+ANISOU 1383 CB HIS B 91 7193 6894 5976 -939 -126 -702 C
+ATOM 1384 CG HIS B 91 -19.981 -11.185 -7.409 1.00 56.19 C
+ANISOU 1384 CG HIS B 91 7349 7534 6464 -1027 -193 -617 C
+ATOM 1385 ND1 HIS B 91 -20.029 -11.423 -8.768 1.00 58.74 N
+ANISOU 1385 ND1 HIS B 91 7574 7829 6914 -972 -131 -528 N
+ATOM 1386 CD2 HIS B 91 -18.759 -11.596 -7.006 1.00 57.11 C
+ANISOU 1386 CD2 HIS B 91 7263 7919 6514 -1145 -312 -608 C
+ATOM 1387 CE1 HIS B 91 -18.883 -11.936 -9.173 1.00 56.30 C
+ANISOU 1387 CE1 HIS B 91 7023 7755 6612 -1044 -186 -477 C
+ATOM 1388 NE2 HIS B 91 -18.094 -12.046 -8.123 1.00 61.01 N
+ANISOU 1388 NE2 HIS B 91 7535 8546 7100 -1142 -299 -520 N
+ATOM 1389 N LYS B 92 -24.532 -11.528 -5.533 1.00 51.89 N
+ANISOU 1389 N LYS B 92 7218 6656 5842 -359 126 -655 N
+ATOM 1390 CA LYS B 92 -25.686 -11.045 -4.764 1.00 55.84 C
+ANISOU 1390 CA LYS B 92 7874 7083 6259 -208 243 -719 C
+ATOM 1391 C LYS B 92 -25.938 -11.835 -3.472 1.00 58.34 C
+ANISOU 1391 C LYS B 92 8162 7572 6430 -160 255 -708 C
+ATOM 1392 O LYS B 92 -26.959 -11.637 -2.823 1.00 58.98 O
+ANISOU 1392 O LYS B 92 8322 7655 6430 -18 378 -739 O
+ATOM 1393 CB LYS B 92 -26.964 -11.067 -5.656 1.00 58.46 C
+ANISOU 1393 CB LYS B 92 8144 7346 6720 -12 355 -640 C
+ATOM 1394 CG LYS B 92 -26.997 -9.991 -6.743 1.00 61.75 C
+ANISOU 1394 CG LYS B 92 8682 7550 7230 -3 369 -662 C
+ATOM 1395 CD LYS B 92 -26.411 -8.664 -6.237 1.00 67.88 C
+ANISOU 1395 CD LYS B 92 9757 8134 7899 -115 352 -813 C
+ATOM 1396 CE LYS B 92 -26.933 -7.436 -6.946 1.00 70.75 C
+ANISOU 1396 CE LYS B 92 10351 8225 8305 -10 414 -844 C
+ATOM 1397 NZ LYS B 92 -28.067 -6.929 -6.119 1.00 81.14 N
+ANISOU 1397 NZ LYS B 92 11822 9481 9525 253 540 -928 N
+ATOM 1398 N GLU B 93 -25.011 -12.712 -3.102 1.00 57.86 N
+ANISOU 1398 N GLU B 93 7989 7669 6322 -262 135 -655 N
+ATOM 1399 CA GLU B 93 -25.136 -13.464 -1.883 1.00 65.82 C
+ANISOU 1399 CA GLU B 93 9004 8833 7172 -230 128 -625 C
+ATOM 1400 C GLU B 93 -25.494 -12.505 -0.726 1.00 69.11 C
+ANISOU 1400 C GLU B 93 9655 9212 7388 -218 194 -777 C
+ATOM 1401 O GLU B 93 -26.466 -12.735 -0.015 1.00 63.37 O
+ANISOU 1401 O GLU B 93 8970 8546 6562 -93 320 -761 O
+ATOM 1402 CB GLU B 93 -23.834 -14.222 -1.595 1.00 65.64 C
+ANISOU 1402 CB GLU B 93 8876 8968 7096 -333 -46 -573 C
+ATOM 1403 CG GLU B 93 -23.788 -14.779 -0.175 1.00 79.13 C
+ANISOU 1403 CG GLU B 93 10652 10826 8585 -318 -84 -555 C
+ATOM 1404 CD GLU B 93 -22.987 -16.055 -0.039 1.00 76.96 C
+ANISOU 1404 CD GLU B 93 10243 10705 8292 -298 -222 -415 C
+ATOM 1405 OE1 GLU B 93 -21.780 -16.023 -0.371 1.00 79.66 O
+ANISOU 1405 OE1 GLU B 93 10469 11135 8663 -371 -367 -426 O
+ATOM 1406 OE2 GLU B 93 -23.601 -17.080 0.373 1.00 67.00 O
+ANISOU 1406 OE2 GLU B 93 8994 9478 6985 -203 -176 -287 O
+ATOM 1407 N GLU B 94 -24.725 -11.432 -0.566 1.00 69.03 N
+ANISOU 1407 N GLU B 94 9811 9108 7309 -360 117 -926 N
+ATOM 1408 CA GLU B 94 -24.928 -10.483 0.552 1.00 77.95 C
+ANISOU 1408 CA GLU B 94 11229 10170 8216 -366 159 -1102 C
+ATOM 1409 C GLU B 94 -26.428 -10.119 0.763 1.00 81.07 C
+ANISOU 1409 C GLU B 94 11734 10485 8584 -108 385 -1134 C
+ATOM 1410 O GLU B 94 -26.904 -10.013 1.908 1.00 85.54 O
+ANISOU 1410 O GLU B 94 12445 11120 8935 -23 471 -1211 O
+ATOM 1411 CB GLU B 94 -24.036 -9.252 0.313 1.00 87.19 C
+ANISOU 1411 CB GLU B 94 12594 11164 9368 -580 56 -1254 C
+ATOM 1412 CG GLU B 94 -24.432 -7.953 1.012 1.00106.45 C
+ANISOU 1412 CG GLU B 94 15427 13387 11633 -560 129 -1466 C
+ATOM 1413 CD GLU B 94 -23.735 -7.773 2.341 1.00110.68 C
+ANISOU 1413 CD GLU B 94 16139 14025 11889 -732 8 -1602 C
+ATOM 1414 OE1 GLU B 94 -22.649 -8.362 2.521 1.00117.37 O
+ANISOU 1414 OE1 GLU B 94 16802 15085 12706 -936 -180 -1543 O
+ATOM 1415 OE2 GLU B 94 -24.273 -7.047 3.196 1.00115.53 O
+ANISOU 1415 OE2 GLU B 94 17075 14520 12301 -644 98 -1769 O
+ATOM 1416 N ALA B 95 -27.170 -9.967 -0.337 1.00 78.47 N
+ANISOU 1416 N ALA B 95 11311 10048 8454 26 480 -1068 N
+ATOM 1417 CA ALA B 95 -28.574 -9.572 -0.290 1.00 77.65 C
+ANISOU 1417 CA ALA B 95 11250 9907 8344 296 683 -1084 C
+ATOM 1418 C ALA B 95 -29.499 -10.685 0.182 1.00 81.60 C
+ANISOU 1418 C ALA B 95 11531 10661 8809 409 797 -947 C
+ATOM 1419 O ALA B 95 -30.560 -10.398 0.728 1.00 86.75 O
+ANISOU 1419 O ALA B 95 12220 11380 9361 612 978 -982 O
+ATOM 1420 CB ALA B 95 -29.025 -9.052 -1.654 1.00 73.64 C
+ANISOU 1420 CB ALA B 95 10698 9230 8050 400 717 -1040 C
+ATOM 1421 N ILE B 96 -29.102 -11.941 -0.054 1.00 86.66 N
+ANISOU 1421 N ILE B 96 11957 11441 9527 280 698 -787 N
+ATOM 1422 CA ILE B 96 -29.871 -13.143 0.330 1.00 86.56 C
+ANISOU 1422 CA ILE B 96 11762 11641 9485 314 780 -627 C
+ATOM 1423 C ILE B 96 -29.477 -13.617 1.721 1.00 84.77 C
+ANISOU 1423 C ILE B 96 11641 11556 9011 242 759 -633 C
+ATOM 1424 O ILE B 96 -29.685 -14.761 2.056 1.00 83.12 O
+ANISOU 1424 O ILE B 96 11324 11491 8764 195 764 -478 O
+ATOM 1425 CB ILE B 96 -29.623 -14.323 -0.663 1.00 90.19 C
+ANISOU 1425 CB ILE B 96 12007 12122 10139 213 673 -451 C
+ATOM 1426 CG1 ILE B 96 -30.006 -13.941 -2.082 1.00 90.30 C
+ANISOU 1426 CG1 ILE B 96 11917 12018 10374 272 679 -433 C
+ATOM 1427 CG2 ILE B 96 -30.408 -15.587 -0.291 1.00 96.15 C
+ANISOU 1427 CG2 ILE B 96 12623 13049 10858 195 743 -278 C
+ATOM 1428 CD1 ILE B 96 -31.453 -13.513 -2.211 1.00 91.73 C
+ANISOU 1428 CD1 ILE B 96 12017 12259 10577 456 854 -422 C
+ATOM 1429 N MET B 97 -28.867 -12.760 2.519 1.00 96.04 N
+ANISOU 1429 N MET B 97 13305 12930 10255 212 718 -806 N
+ATOM 1430 CA MET B 97 -28.752 -13.030 3.959 1.00108.10 C
+ANISOU 1430 CA MET B 97 14968 14612 11491 186 733 -832 C
+ATOM 1431 C MET B 97 -29.333 -11.852 4.784 1.00112.54 C
+ANISOU 1431 C MET B 97 15786 15132 11839 327 893 -1037 C
+ATOM 1432 O MET B 97 -30.047 -12.090 5.759 1.00113.07 O
+ANISOU 1432 O MET B 97 15896 15370 11696 422 1051 -1023 O
+ATOM 1433 CB MET B 97 -27.301 -13.410 4.291 1.00103.41 C
+ANISOU 1433 CB MET B 97 14414 14054 10823 -6 483 -827 C
+ATOM 1434 CG MET B 97 -26.722 -14.327 3.206 1.00102.45 C
+ANISOU 1434 CG MET B 97 14057 13920 10946 -76 347 -664 C
+ATOM 1435 SD MET B 97 -25.246 -15.322 3.559 1.00117.34 S
+ANISOU 1435 SD MET B 97 15877 15943 12762 -203 84 -561 S
+ATOM 1436 CE MET B 97 -24.043 -14.027 3.907 1.00103.96 C
+ANISOU 1436 CE MET B 97 14327 14224 10946 -367 -80 -786 C
+ATOM 1437 N LEU B 98 -29.087 -10.604 4.344 1.00119.26 N
+ANISOU 1437 N LEU B 98 16822 15748 12742 354 871 -1217 N
+ATOM 1438 CA LEU B 98 -29.639 -9.356 4.952 1.00123.66 C
+ANISOU 1438 CA LEU B 98 17689 16180 13115 531 1024 -1437 C
+ATOM 1439 C LEU B 98 -30.866 -9.535 5.875 1.00124.53 C
+ANISOU 1439 C LEU B 98 17792 16500 13023 769 1286 -1430 C
+ATOM 1440 O LEU B 98 -32.001 -9.708 5.420 1.00113.44 O
+ANISOU 1440 O LEU B 98 16173 15192 11737 973 1471 -1329 O
+ATOM 1441 CB LEU B 98 -29.945 -8.322 3.862 1.00113.25 C
+ANISOU 1441 CB LEU B 98 16446 14588 11996 658 1065 -1512 C
+TER 1442 LEU B 98
+HETATM 1443 FE1 FES A 201 -15.271 -14.172 -26.506 1.00 44.84 FE
+ANISOU 1443 FE1 FES A 201 6513 5131 5392 -266 1479 -131 FE
+HETATM 1444 FE2 FES A 201 -13.886 -13.246 -28.774 1.00 43.12 FE
+ANISOU 1444 FE2 FES A 201 6178 4976 5230 -316 1145 -235 FE
+HETATM 1445 S1 FES A 201 -13.297 -13.107 -26.664 1.00 54.52 S
+ANISOU 1445 S1 FES A 201 7773 6436 6506 -96 1188 -102 S
+HETATM 1446 S2 FES A 201 -15.933 -14.020 -28.613 1.00 59.15 S
+ANISOU 1446 S2 FES A 201 8119 7001 7354 -510 1368 -300 S
+HETATM 1447 CL CL A 202 -7.271 -6.453 -50.333 1.00 66.75 CL
+ANISOU 1447 CL CL A 202 8476 9756 7127 -15 320 384 CL
+HETATM 1448 FE1 FES B 201 -24.764 -23.326 -3.870 1.00 41.78 FE
+ANISOU 1448 FE1 FES B 201 5702 5769 4400 126 -205 391 FE
+HETATM 1449 FE2 FES B 201 -25.332 -22.283 -6.421 1.00 37.10 FE
+ANISOU 1449 FE2 FES B 201 4925 5056 4113 76 -116 248 FE
+HETATM 1450 S1 FES B 201 -23.427 -22.583 -5.443 1.00 50.74 S
+ANISOU 1450 S1 FES B 201 6641 6936 5699 218 -266 253 S
+HETATM 1451 S2 FES B 201 -26.631 -22.784 -4.792 1.00 52.36 S
+ANISOU 1451 S2 FES B 201 6974 7030 5890 -29 -34 366 S
+HETATM 1452 CL CL B 202 -35.655 -14.036 -25.892 1.00 63.11 CL
+ANISOU 1452 CL CL B 202 7828 8449 7699 533 -737 677 CL
+HETATM 1453 O HOH A 301 -5.604 9.621 -30.726 1.00 71.67 O
+ANISOU 1453 O HOH A 301 9741 6570 10921 -503 1286 -1155 O
+HETATM 1454 O HOH A 302 -9.976 -2.053 -46.606 1.00 60.80 O
+ANISOU 1454 O HOH A 302 7211 8696 7192 404 154 904 O
+HETATM 1455 O HOH A 303 -25.242 -15.543 -37.047 1.00 85.19 O
+ANISOU 1455 O HOH A 303 9346 12270 10750 -2562 894 -1311 O
+HETATM 1456 O HOH A 304 -8.615 -1.310 -44.946 1.00 51.68 O
+ANISOU 1456 O HOH A 304 6188 7004 6442 421 264 856 O
+HETATM 1457 O HOH A 305 -6.495 -20.103 -36.227 1.00 66.33 O
+ANISOU 1457 O HOH A 305 9914 6783 8504 -320 2093 -239 O
+HETATM 1458 O HOH A 306 -15.756 -22.203 -33.220 1.00 75.41 O
+ANISOU 1458 O HOH A 306 10813 7895 9944 -1695 2618 -965 O
+HETATM 1459 O HOH A 307 -29.136 -5.336 -24.489 1.00 68.01 O
+ANISOU 1459 O HOH A 307 7381 9218 9240 419 2448 230 O
+HETATM 1460 O HOH A 308 -31.273 -2.568 -37.684 1.00 80.28 O
+ANISOU 1460 O HOH A 308 6166 13841 10493 472 476 1418 O
+HETATM 1461 O HOH A 309 -12.248 -4.951 -30.108 1.00 43.84 O
+ANISOU 1461 O HOH A 309 5908 5247 5501 5 448 -372 O
+HETATM 1462 O HOH A 310 1.254 -8.613 -35.928 1.00 55.59 O
+ANISOU 1462 O HOH A 310 7059 6744 7319 249 231 444 O
+HETATM 1463 O HOH A 311 -14.907 -5.701 -24.000 1.00 59.32 O
+ANISOU 1463 O HOH A 311 8290 7265 6981 168 940 -557 O
+HETATM 1464 O HOH A 312 -10.817 -7.018 -29.284 1.00 41.62 O
+ANISOU 1464 O HOH A 312 5784 4984 5045 -27 423 -341 O
+HETATM 1465 O HOH A 313 2.334 -6.045 -37.941 1.00 48.64 O
+ANISOU 1465 O HOH A 313 5952 5811 6716 139 202 488 O
+HETATM 1466 O HOH A 314 -15.179 -4.981 -27.668 1.00 53.48 O
+ANISOU 1466 O HOH A 314 7171 6503 6643 87 768 -437 O
+HETATM 1467 O HOH A 315 -0.012 -13.050 -38.710 1.00 53.80 O
+ANISOU 1467 O HOH A 315 7374 6131 6936 327 934 389 O
+HETATM 1468 O HOH A 316 -4.588 7.953 -34.979 1.00 55.02 O
+ANISOU 1468 O HOH A 316 7176 4879 8848 -164 1054 -241 O
+HETATM 1469 O HOH A 317 -7.401 1.030 -46.099 1.00 71.07 O
+ANISOU 1469 O HOH A 317 8592 9256 9152 695 478 1286 O
+HETATM 1470 O HOH B 301 -17.227 -5.370 -20.274 1.00 67.76 O
+ANISOU 1470 O HOH B 301 9358 8307 8078 -2373 512 237 O
+HETATM 1471 O HOH B 302 -16.773 -19.622 -11.270 1.00 63.07 O
+ANISOU 1471 O HOH B 302 7080 9333 7548 271 -261 -62 O
+HETATM 1472 O HOH B 303 -33.187 -25.431 -12.986 1.00 63.64 O
+ANISOU 1472 O HOH B 303 8214 8071 7895 -876 -197 526 O
+HETATM 1473 O HOH B 304 -33.633 -10.672 -27.113 1.00 59.09 O
+ANISOU 1473 O HOH B 304 8015 7375 7058 804 -526 819 O
+HETATM 1474 O HOH B 305 -29.987 -6.037 -4.511 1.00 66.34 O
+ANISOU 1474 O HOH B 305 10207 7566 7433 765 801 -1097 O
+HETATM 1475 O HOH B 306 -13.899 -20.518 -11.569 1.00 81.57 O
+ANISOU 1475 O HOH B 306 8854 12357 9778 587 -327 -7 O
+HETATM 1476 O HOH B 307 -22.312 -17.195 -9.418 1.00 47.15 O
+ANISOU 1476 O HOH B 307 5812 6486 5616 -124 -89 -163 O
+HETATM 1477 O HOH B 308 -34.144 -23.559 -20.590 1.00 51.64 O
+ANISOU 1477 O HOH B 308 6612 6627 6378 -778 -651 271 O
+HETATM 1478 O HOH B 309 -24.795 -27.082 -17.164 1.00 48.12 O
+ANISOU 1478 O HOH B 309 7064 5473 5745 466 -276 10 O
+HETATM 1479 O HOH B 310 -32.217 -13.054 4.356 1.00 88.41 O
+ANISOU 1479 O HOH B 310 12239 12424 8929 628 1337 -721 O
+HETATM 1480 O HOH B 311 -23.165 -14.400 -5.121 1.00 48.01 O
+ANISOU 1480 O HOH B 311 6333 6580 5329 -351 -63 -448 O
+HETATM 1481 O HOH B 312 -20.108 -19.770 -22.685 1.00 54.43 O
+ANISOU 1481 O HOH B 312 6815 7445 6419 397 344 -109 O
+HETATM 1482 O HOH B 313 -29.379 -10.101 -22.915 1.00 62.52 O
+ANISOU 1482 O HOH B 313 8624 7375 7757 322 17 426 O
+HETATM 1483 O HOH B 314 -23.815 -23.224 -24.077 1.00 46.69 O
+ANISOU 1483 O HOH B 314 6623 5782 5333 479 -2 -224 O
+HETATM 1484 O HOH B 315 -31.917 -9.402 -21.408 1.00 63.89 O
+ANISOU 1484 O HOH B 315 8654 7581 8038 758 -17 436 O
+HETATM 1485 O HOH B 316 -43.034 -22.451 -5.025 1.00 82.32 O
+ANISOU 1485 O HOH B 316 8131 13423 9723 -1213 1232 1263 O
+HETATM 1486 O HOH B 317 -13.942 -19.466 -15.267 1.00 82.69 O
+ANISOU 1486 O HOH B 317 8966 12435 10017 416 49 -55 O
+HETATM 1487 O HOH B 318 -23.364 -14.585 -8.816 1.00 50.88 O
+ANISOU 1487 O HOH B 318 6512 6761 6060 -288 14 -313 O
+HETATM 1488 O HOH B 319 -41.794 -18.985 0.026 0.50 60.91 O
+ANISOU 1488 O HOH B 319 5945 10874 6323 -9 2050 811 O
+HETATM 1489 O HOH B 320 -29.672 -24.828 -29.742 1.00 55.49 O
+ANISOU 1489 O HOH B 320 8618 6605 5859 -263 -781 -333 O
+HETATM 1490 O HOH B 321 -38.215 -20.833 -12.380 1.00 58.66 O
+ANISOU 1490 O HOH B 321 6197 8706 7384 -584 159 654 O
+CONECT 301 1443
+CONECT 333 1443
+CONECT 351 1444
+CONECT 569 1444
+CONECT 1022 1448
+CONECT 1054 1448
+CONECT 1072 1449
+CONECT 1290 1449
+CONECT 1443 301 333 1445 1446
+CONECT 1444 351 569 1445 1446
+CONECT 1445 1443 1444
+CONECT 1446 1443 1444
+CONECT 1448 1022 1054 1450 1451
+CONECT 1449 1072 1290 1450 1451
+CONECT 1450 1448 1449
+CONECT 1451 1448 1449
+MASTER 410 0 4 7 14 0 6 6 1488 2 16 18
+END
--- /dev/null
+package jalview.ext.rbvi.chimera;
+
+import static org.testng.Assert.assertEquals;
+
+import org.testng.annotations.Test;
+
+public class AtomSpecModelTest
+{
+ @Test(groups = "Functional")
+ public void testGetAtomSpec()
+ {
+ AtomSpecModel model = new AtomSpecModel();
+ assertEquals(model.getAtomSpec(), "");
+ model.addRange(1, 2, 4, "A");
+ assertEquals(model.getAtomSpec(), "#1:2-4.A");
+ model.addRange(1, 8, 8, "A");
+ assertEquals(model.getAtomSpec(), "#1:2-4.A,8.A");
+ model.addRange(1, 5, 7, "B");
+ assertEquals(model.getAtomSpec(), "#1:2-4.A,8.A,5-7.B");
+ model.addRange(1, 3, 5, "A");
+ assertEquals(model.getAtomSpec(), "#1:2-5.A,8.A,5-7.B");
+ model.addRange(0, 1, 4, "B");
+ assertEquals(model.getAtomSpec(), "#0:1-4.B|#1:2-5.A,8.A,5-7.B");
+ model.addRange(0, 5, 9, "C");
+ assertEquals(model.getAtomSpec(), "#0:1-4.B,5-9.C|#1:2-5.A,8.A,5-7.B");
+ model.addRange(1, 8, 10, "B");
+ assertEquals(model.getAtomSpec(), "#0:1-4.B,5-9.C|#1:2-5.A,8.A,5-10.B");
+ model.addRange(1, 8, 9, "B");
+ assertEquals(model.getAtomSpec(), "#0:1-4.B,5-9.C|#1:2-5.A,8.A,5-10.B");
+ model.addRange(0, 3, 10, "C"); // subsumes 5-9
+ assertEquals(model.getAtomSpec(), "#0:1-4.B,3-10.C|#1:2-5.A,8.A,5-10.B");
+ }
+
+}
*/
package jalview.ext.rbvi.chimera;
-import static org.testng.AssertJUnit.assertEquals;
-import static org.testng.AssertJUnit.assertTrue;
-
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceI;
+import jalview.gui.AlignFrame;
import jalview.gui.JvOptionPane;
+import jalview.gui.SequenceRenderer;
+import jalview.schemes.JalviewColourScheme;
+import jalview.structure.StructureMapping;
+import jalview.structure.StructureMappingcommandSet;
+import jalview.structure.StructureSelectionManager;
import java.awt.Color;
-import java.util.Arrays;
+import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
-import java.util.SortedMap;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
}
@Test(groups = { "Functional" })
- public void testAddColourRange()
- {
- Map<Color, SortedMap<Integer, Map<String, List<int[]>>>> map = new LinkedHashMap<Color, SortedMap<Integer, Map<String, List<int[]>>>>();
- ChimeraCommands.addColourRange(map, Color.pink, 1, 2, 4, "A");
- ChimeraCommands.addColourRange(map, Color.pink, 1, 8, 8, "A");
- ChimeraCommands.addColourRange(map, Color.pink, 1, 5, 7, "B");
- ChimeraCommands.addColourRange(map, Color.red, 1, 3, 5, "A");
- ChimeraCommands.addColourRange(map, Color.red, 0, 1, 4, "B");
- ChimeraCommands.addColourRange(map, Color.orange, 0, 5, 9, "C");
-
- // three colours mapped
- assertEquals(3, map.keySet().size());
-
- // Red has two models, Pink and Orange one each
- assertEquals(2, map.get(Color.red).keySet().size());
- assertEquals(1, map.get(Color.orange).keySet().size());
- assertEquals(1, map.get(Color.pink).keySet().size());
-
- // pink model 1 has two chains, red.0 / red.1 / orange.0 one each
- assertEquals(2, map.get(Color.pink).get(1).keySet().size());
- assertEquals(1, map.get(Color.red).get(0).keySet().size());
- assertEquals(1, map.get(Color.red).get(1).keySet().size());
- assertEquals(1, map.get(Color.orange).get(0).keySet().size());
-
- // inspect positions
- List<int[]> posList = map.get(Color.pink).get(1).get("A");
- assertEquals(2, posList.size());
- assertTrue(Arrays.equals(new int[] { 2, 4 }, posList.get(0)));
- assertTrue(Arrays.equals(new int[] { 8, 8 }, posList.get(1)));
-
- posList = map.get(Color.pink).get(1).get("B");
- assertEquals(1, posList.size());
- assertTrue(Arrays.equals(new int[] { 5, 7 }, posList.get(0)));
-
- posList = map.get(Color.red).get(0).get("B");
- assertEquals(1, posList.size());
- assertTrue(Arrays.equals(new int[] { 1, 4 }, posList.get(0)));
-
- posList = map.get(Color.red).get(1).get("A");
- assertEquals(1, posList.size());
- assertTrue(Arrays.equals(new int[] { 3, 5 }, posList.get(0)));
-
- posList = map.get(Color.orange).get(0).get("C");
- assertEquals(1, posList.size());
- assertTrue(Arrays.equals(new int[] { 5, 9 }, posList.get(0)));
- }
-
- @Test(groups = { "Functional" })
public void testBuildColourCommands()
{
- Map<Color, SortedMap<Integer, Map<String, List<int[]>>>> map = new LinkedHashMap<Color, SortedMap<Integer, Map<String, List<int[]>>>>();
+ Map<Object, AtomSpecModel> map = new LinkedHashMap<Object, AtomSpecModel>();
ChimeraCommands.addColourRange(map, Color.blue, 0, 2, 5, "A");
ChimeraCommands.addColourRange(map, Color.blue, 0, 7, 7, "B");
ChimeraCommands.addColourRange(map, Color.blue, 0, 9, 23, "A");
ChimeraCommands.addColourRange(map, Color.yellow, 1, 8, 8, "A");
ChimeraCommands.addColourRange(map, Color.yellow, 1, 3, 5, "A");
ChimeraCommands.addColourRange(map, Color.red, 0, 3, 5, "A");
+ ChimeraCommands.addColourRange(map, Color.red, 0, 6, 9, "A");
// Colours should appear in the Chimera command in the order in which
- // they were added; within colour, by model, by chain, and positions as
- // added
+ // they were added; within colour, by model, by chain, ranges in start order
String command = ChimeraCommands.buildColourCommands(map).get(0);
assertEquals(
- "color #0000ff #0:2-5.A,9-23.A,7.B|#1:1.A,4-7.B; color #ffff00 #1:8.A,3-5.A; color #ff0000 #0:3-5.A",
- command);
+ command,
+ "color #0000ff #0:2-5.A,9-23.A,7.B|#1:1.A,4-7.B; color #ffff00 #1:3-5.A,8.A; color #ff0000 #0:3-9.A");
+ }
+
+ @Test(groups = { "Functional" })
+ public void testBuildSetAttributeCommands()
+ {
+ /*
+ * make a map of { featureType, {featureValue, {residue range specification } } }
+ */
+ Map<String, Map<Object, AtomSpecModel>> featuresMap = new LinkedHashMap<String, Map<Object, AtomSpecModel>>();
+ Map<Object, AtomSpecModel> featureValues = new HashMap<Object, AtomSpecModel>();
+
+ /*
+ * start with just one feature/value...
+ */
+ featuresMap.put("chain", featureValues);
+ ChimeraCommands.addColourRange(featureValues, "X", 0, 8, 20, "A");
+
+ List<String> commands = ChimeraCommands
+ .buildSetAttributeCommands(featuresMap);
+ assertEquals(1, commands.size());
+
+ /*
+ * feature name gets a jv_ namespace prefix
+ * feature value is quoted in case it contains spaces
+ */
+ assertEquals(commands.get(0), "setattr r jv_chain 'X' #0:8-20.A");
+
+ // add same feature value, overlapping range
+ ChimeraCommands.addColourRange(featureValues, "X", 0, 3, 9, "A");
+ // same feature value, contiguous range
+ ChimeraCommands.addColourRange(featureValues, "X", 0, 21, 25, "A");
+ commands = ChimeraCommands.buildSetAttributeCommands(featuresMap);
+ assertEquals(1, commands.size());
+ assertEquals(commands.get(0), "setattr r jv_chain 'X' #0:3-25.A");
+
+ // same feature value and model, different chain
+ ChimeraCommands.addColourRange(featureValues, "X", 0, 21, 25, "B");
+ // same feature value and chain, different model
+ ChimeraCommands.addColourRange(featureValues, "X", 1, 26, 30, "A");
+ commands = ChimeraCommands.buildSetAttributeCommands(featuresMap);
+ assertEquals(1, commands.size());
+ assertEquals(commands.get(0),
+ "setattr r jv_chain 'X' #0:3-25.A,21-25.B|#1:26-30.A");
+
+ // same feature, different value
+ ChimeraCommands.addColourRange(featureValues, "Y", 0, 40, 50, "A");
+ commands = ChimeraCommands.buildSetAttributeCommands(featuresMap);
+ assertEquals(2, commands.size());
+ // commands are ordered by feature type but not by value
+ // so use contains to test for the expected command:
+ assertTrue(commands
+ .contains("setattr r jv_chain 'X' #0:3-25.A,21-25.B|#1:26-30.A"));
+ assertTrue(commands.contains("setattr r jv_chain 'Y' #0:40-50.A"));
+
+ featuresMap.clear();
+ featureValues.clear();
+ featuresMap.put("side-chain binding!", featureValues);
+ ChimeraCommands.addColourRange(featureValues,
+ "<html>metal <a href=\"http:a.b.c/x\"> 'ion!", 0, 7, 15,
+ "A");
+ // feature names are sanitised to change non-alphanumeric to underscore
+ // feature values are sanitised to encode single quote characters
+ commands = ChimeraCommands.buildSetAttributeCommands(featuresMap);
+ assertTrue(commands
+ .contains("setattr r jv_side_chain_binding_ '<html>metal <a href=\"http:a.b.c/x\"> 'ion!' #0:7-15.A"));
+ }
+
+ /**
+ * Tests for the method that prefixes and sanitises a feature name so it can
+ * be used as a valid, namespaced attribute name in Chimera
+ */
+ @Test(groups = { "Functional" })
+ public void testMakeAttributeName()
+ {
+ assertEquals(ChimeraCommands.makeAttributeName(null), "jv_");
+ assertEquals(ChimeraCommands.makeAttributeName(""), "jv_");
+ assertEquals(ChimeraCommands.makeAttributeName("helix"), "jv_helix");
+ assertEquals(ChimeraCommands.makeAttributeName("Hello World 24"),
+ "jv_Hello_World_24");
+ assertEquals(
+ ChimeraCommands.makeAttributeName("!this is-a_very*{odd(name"),
+ "jv__this_is_a_very__odd_name");
+ // name ending in color gets underscore appended
+ assertEquals(ChimeraCommands.makeAttributeName("helixColor"),
+ "jv_helixColor_");
+ }
+
+ @Test(groups = { "Functional" })
+ public void testGetColourBySequenceCommands_hiddenColumns()
+ {
+ /*
+ * load these sequences, coloured by Strand propensity,
+ * with columns 2-4 hidden
+ */
+ SequenceI seq1 = new Sequence("seq1", "MHRSQSSSGG");
+ SequenceI seq2 = new Sequence("seq2", "MVRSNGGSSS");
+ AlignmentI al = new Alignment(new SequenceI[] { seq1, seq2 });
+ AlignFrame af = new AlignFrame(al, 800, 500);
+ af.changeColour_actionPerformed(JalviewColourScheme.Strand.toString());
+ ColumnSelection cs = new ColumnSelection();
+ cs.addElement(2);
+ cs.addElement(3);
+ cs.addElement(4);
+ af.getViewport().setColumnSelection(cs);
+ af.hideSelColumns_actionPerformed(null);
+ SequenceRenderer sr = new SequenceRenderer(af.getViewport());
+ SequenceI[][] seqs = new SequenceI[][] { { seq1 }, { seq2 } };
+ String[] files = new String[] { "seq1.pdb", "seq2.pdb" };
+ StructureSelectionManager ssm = new StructureSelectionManager();
+
+ /*
+ * map residues 1-10 to residues 21-30 (atoms 105-150) in structures
+ */
+ HashMap<Integer, int[]> map = new HashMap<Integer, int[]>();
+ for (int pos = 1; pos <= seq1.getLength(); pos++)
+ {
+ map.put(pos, new int[] { 20 + pos, 5 * (20 + pos) });
+ }
+ StructureMapping sm1 = new StructureMapping(seq1, "seq1.pdb", "pdb1",
+ "A", map, null);
+ ssm.addStructureMapping(sm1);
+ StructureMapping sm2 = new StructureMapping(seq2, "seq2.pdb", "pdb2",
+ "B", map, null);
+ ssm.addStructureMapping(sm2);
+
+ StructureMappingcommandSet[] commands = ChimeraCommands
+ .getColourBySequenceCommand(ssm, files, seqs, sr, af.alignPanel);
+ assertEquals(1, commands.length);
+ assertEquals(1, commands[0].commands.length);
+ String theCommand = commands[0].commands[0];
+ // M colour is #82827d (see strand.html help page)
+ assertTrue(theCommand.contains("color #82827d #0:21.A|#1:21.B"));
+ // H colour is #60609f
+ assertTrue(theCommand.contains("color #60609f #0:22.A"));
+ // V colour is ##ffff00
+ assertTrue(theCommand.contains("color #ffff00 #1:22.B"));
+ // hidden columns are Gray (128, 128, 128)
+ assertTrue(theCommand.contains("color #808080 #0:23-25.A|#1:23-25.B"));
+ // S and G are both coloured #4949b6
+ assertTrue(theCommand.contains("color #4949b6 #0:26-30.A|#1:26-30.B"));
}
}
*/
package jalview.ext.rbvi.chimera;
-import static org.testng.AssertJUnit.assertEquals;
-import static org.testng.AssertJUnit.assertTrue;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+import jalview.api.FeatureRenderer;
import jalview.api.structures.JalviewStructureDisplayI;
import jalview.bin.Cache;
+import jalview.bin.Jalview;
+import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.PDBEntry;
+import jalview.datamodel.SequenceFeature;
import jalview.datamodel.SequenceI;
import jalview.gui.AlignFrame;
+import jalview.gui.Desktop;
import jalview.gui.JvOptionPane;
import jalview.gui.Preferences;
import jalview.gui.StructureViewer;
import jalview.gui.StructureViewer.ViewerType;
+import jalview.io.FileLoader;
+import jalview.structure.StructureMapping;
+import jalview.structure.StructureSelectionManager;
+import jalview.ws.sifts.SiftsClient;
+import jalview.ws.sifts.SiftsException;
+import jalview.ws.sifts.SiftsSettings;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import java.util.Vector;
import jalview.io.DataSourceType;
import org.testng.annotations.AfterClass;
+import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
}
+ private JalviewStructureDisplayI chimeraViewer;
+
/**
* @throws java.lang.Exception
*/
@BeforeClass(alwaysRun = true)
public static void setUpBeforeClass() throws Exception
{
- jalview.bin.Jalview.main(new String[] {
- "-noquestionnaire -nonews -props",
+ Jalview.main(new String[] { "-noquestionnaire", "-nonews", "-props",
"test/jalview/ext/rbvi/chimera/testProps.jvprops" });
+ Cache.setProperty(Preferences.STRUCTURE_DISPLAY,
+ ViewerType.CHIMERA.name());
+ Cache.setProperty("SHOW_ANNOTATIONS", "false");
+ Cache.setProperty(Preferences.STRUCT_FROM_PDB, "false");
+ Cache.setProperty(Preferences.STRUCTURE_DISPLAY,
+ ViewerType.CHIMERA.name());
+ Cache.setProperty("MAP_WITH_SIFTS", "true");
+ // TODO this should not be necessary!
+ SiftsSettings.setMapWithSifts(true);
}
/**
@AfterClass(alwaysRun = true)
public static void tearDownAfterClass() throws Exception
{
- jalview.gui.Desktop.instance.closeAll_actionPerformed(null);
+ Desktop.instance.closeAll_actionPerformed(null);
+ }
+
+ @AfterMethod(alwaysRun = true)
+ public void tearDownAfterTest() throws Exception
+ {
+ SiftsClient.setMockSiftsFile(null);
+ if (chimeraViewer != null)
+ {
+ chimeraViewer.closeViewer(true);
+ }
}
- @Test(groups = { "Functional" })
+ /**
+ * Load 1GAQ and view the first structure for which a PDB id is found. Note no
+ * network connection is needed - PDB file is read locally, SIFTS fetch fails
+ * so mapping falls back to Needleman-Wunsch - ok for this test.
+ */
+ // External as local install of Chimera required
+ @Test(groups = { "External" })
public void testSingleSeqViewChimera()
{
- Cache.setProperty(Preferences.STRUCTURE_DISPLAY,
- ViewerType.CHIMERA.name());
String inFile = "examples/1gaq.txt";
- AlignFrame af = new jalview.io.FileLoader().LoadFileWaitTillLoaded(
- inFile, DataSourceType.FILE);
- assertTrue("Didn't read input file " + inFile, af != null);
- for (SequenceI sq : af.getViewport().getAlignment().getSequences())
+ AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(inFile,
+ DataSourceType.FILE);
+ assertNotNull(af, "Failed to create AlignFrame");
+ SequenceI sq = af.getViewport().getAlignment().getSequenceAt(0);
+ assertEquals(sq.getName(), "1GAQ|A");
+ SequenceI dsq = sq.getDatasetSequence();
+ Vector<PDBEntry> pdbIds = dsq.getAllPDBEntries();
+ assertEquals(pdbIds.size(), 1);
+ PDBEntry pdbEntry = pdbIds.get(0);
+ assertEquals(pdbEntry.getId(), "1GAQ");
+ StructureViewer structureViewer = new StructureViewer(af.getViewport()
+ .getStructureSelectionManager());
+ chimeraViewer = structureViewer.viewStructures(pdbEntry,
+ new SequenceI[] { sq }, af.getCurrentView().getAlignPanel());
+ JalviewChimeraBinding binding = (JalviewChimeraBinding) chimeraViewer
+ .getBinding();
+
+ /*
+ * Wait for viewer load thread to complete
+ */
+ while (!binding.isFinishedInit())
{
- System.out.println("** sq=" + sq.getName());
- SequenceI dsq = sq.getDatasetSequence();
- while (dsq.getDatasetSequence() != null)
+ try
+ {
+ Thread.sleep(500);
+ } catch (InterruptedException e)
{
- dsq = dsq.getDatasetSequence();
}
- if (dsq.getAllPDBEntries() != null
- && dsq.getAllPDBEntries().size() > 0)
+ }
+
+ assertTrue(binding.isChimeraRunning(), "Failed to start Chimera");
+
+ assertEquals(chimeraViewer.getBinding().getPdbCount(), 1);
+ chimeraViewer.closeViewer(true);
+ chimeraViewer = null;
+ return;
+ }
+
+ /**
+ * Test for writing Jalview features as attributes on mapped residues in
+ * Chimera. Note this uses local copies of PDB and SIFTS file, no network
+ * connection required.
+ *
+ * @throws IOException
+ * @throws SiftsException
+ */
+ // External as this requires a local install of Chimera
+ @Test(groups = { "External" })
+ public void testTransferFeatures() throws IOException, SiftsException
+ {
+ String inFile = "examples/uniref50.fa";
+ AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(inFile,
+ DataSourceType.FILE);
+ assertNotNull(af, "Failed to create AlignFrame");
+ SequenceI sq = af.getViewport().getAlignment().findName("FER2_ARATH");
+ assertNotNull(sq, "Didn't find FER2_ARATH");
+
+ /*
+ * need a Uniprot dbref for SIFTS mapping to work!!
+ */
+ sq.addDBRef(new DBRefEntry("UNIPROT", "0", "P16972", null));
+
+ /*
+ * use local test PDB and SIFTS files
+ */
+ String pdbFilePath = new File(
+ "test/jalview/ext/rbvi/chimera/4zho.pdb").getPath();
+ PDBEntry pdbEntry = new PDBEntry("4ZHO", null, null, pdbFilePath);
+ String siftsFilePath = new File(
+ "test/jalview/ext/rbvi/chimera/4zho.xml.gz")
+ .getPath();
+ SiftsClient.setMockSiftsFile(new File(siftsFilePath));
+
+ StructureViewer structureViewer = new StructureViewer(af.getViewport()
+ .getStructureSelectionManager());
+ chimeraViewer = structureViewer.viewStructures(pdbEntry,
+ new SequenceI[] { sq }, af.getCurrentView().getAlignPanel());
+
+ JalviewChimeraBinding binding = (JalviewChimeraBinding) chimeraViewer
+ .getBinding();
+ do
+ {
+ try
+ {
+ Thread.sleep(500);
+ } catch (InterruptedException e)
+ {
+ }
+ } while (!binding.isFinishedInit());
+
+ assertTrue(binding.isChimeraRunning(), "Failed to launch Chimera");
+
+ assertEquals(binding.getPdbCount(), 1);
+
+ /*
+ * check mapping is (sequence) 53-145 to (structure) 2-94 A/B
+ * (or possibly 52-145 to 1-94 - see JAL-2319)
+ */
+ StructureSelectionManager ssm = binding.getSsm();
+ String pdbFile = binding.getPdbFile()[0];
+ StructureMapping[] mappings = ssm.getMapping(pdbFile);
+ assertTrue(mappings[0].getMappingDetailsOutput().contains("SIFTS"),
+ "Failed to perform SIFTS mapping");
+ assertEquals(mappings.length, 2);
+ assertEquals(mappings[0].getChain(), "A");
+ assertEquals(mappings[0].getPDBResNum(53), 2);
+ assertEquals(mappings[0].getPDBResNum(145), 94);
+ assertEquals(mappings[1].getChain(), "B");
+ assertEquals(mappings[1].getPDBResNum(53), 2);
+ assertEquals(mappings[1].getPDBResNum(145), 94);
+
+ /*
+ * now add some features to FER2_ARATH
+ */
+ // feature on a sequence region not mapped to structure:
+ sq.addSequenceFeature(new SequenceFeature("transit peptide",
+ "chloroplast", 1, 51, Float.NaN, null));
+ // feature on a region mapped to structure:
+ sq.addSequenceFeature(new SequenceFeature("domain",
+ "2Fe-2S ferredoxin-type", 55, 145, Float.NaN, null));
+ // on sparse positions of the sequence
+ sq.addSequenceFeature(new SequenceFeature("metal ion-binding site",
+ "Iron-Sulfur (2Fe-2S)", 91, 91, Float.NaN, null));
+ sq.addSequenceFeature(new SequenceFeature("metal ion-binding site",
+ "Iron-Sulfur (2Fe-2S)", 96, 96, Float.NaN, null));
+ // on a sequence region that is partially mapped to structure:
+ sq.addSequenceFeature(new SequenceFeature("helix", null, 50, 60,
+ Float.NaN, null));
+ // and again:
+ sq.addSequenceFeature(new SequenceFeature("chain", null, 50, 70,
+ Float.NaN, null));
+ // add numeric valued features - score is set as attribute value
+ sq.addSequenceFeature(new SequenceFeature("kd", "hydrophobicity", 62,
+ 62, -2.1f, null));
+ sq.addSequenceFeature(new SequenceFeature("kd", "hydrophobicity", 65,
+ 65, 3.6f, null));
+ sq.addSequenceFeature(new SequenceFeature("RESNUM", "ALA: 2 4zhoA",
+ 53, 53, Float.NaN, null));
+
+ /*
+ * set all features visible except for chain
+ */
+ af.setShowSeqFeatures(true);
+ FeatureRenderer fr = af.getFeatureRenderer();
+ fr.setVisible("transit peptide");
+ fr.setVisible("domain");
+ fr.setVisible("metal ion-binding site");
+ fr.setVisible("helix");
+ fr.setVisible("kd");
+ fr.setVisible("RESNUM");
+
+ /*
+ * 'perform' menu action to copy visible features to
+ * attributes in Chimera
+ */
+ // TODO rename and pull up method to binding interface
+ // once functionality is added for Jmol as well
+ binding.sendFeaturesToViewer(af.getViewport().getAlignPanel());
+
+ /*
+ * give Chimera time to open the commands file and execute it
+ */
+ try
+ {
+ Thread.sleep(1000);
+ } catch (InterruptedException e)
+ {
+ }
+
+ /*
+ * ask Chimera for its residue attribute names
+ */
+ List<String> reply = binding.sendChimeraCommand("list resattr", true);
+ // prefixed and sanitised attribute names for Jalview features:
+ assertTrue(reply.contains("resattr jv_domain"));
+ assertTrue(reply.contains("resattr jv_metal_ion_binding_site"));
+ assertTrue(reply.contains("resattr jv_helix"));
+ assertTrue(reply.contains("resattr jv_kd"));
+ assertTrue(reply.contains("resattr jv_RESNUM"));
+ // feature is not on a mapped region - no attribute created
+ assertFalse(reply.contains("resattr jv_transit_peptide"));
+ // feature is not visible - no attribute created
+ assertFalse(reply.contains("resattr jv_chain"));
+
+ /*
+ * ask Chimera for residues with an attribute
+ * 91 and 96 on sequence --> residues 40 and 45 on chains A and B
+ */
+ reply = binding.sendChimeraCommand(
+ "list resi att jv_metal_ion_binding_site", true);
+ assertEquals(reply.size(), 4);
+ assertTrue(reply
+ .contains("residue id #0:40.A jv_metal_ion_binding_site \"Iron-Sulfur (2Fe-2S)\" index 40"));
+ assertTrue(reply
+ .contains("residue id #0:45.A jv_metal_ion_binding_site \"Iron-Sulfur (2Fe-2S)\" index 45"));
+ assertTrue(reply
+ .contains("residue id #0:40.B jv_metal_ion_binding_site \"Iron-Sulfur (2Fe-2S)\" index 40"));
+ assertTrue(reply
+ .contains("residue id #0:45.B jv_metal_ion_binding_site \"Iron-Sulfur (2Fe-2S)\" index 45"));
+
+ /*
+ * check attributes with score values
+ * sequence positions 62 and 65 --> residues 11 and 14 on chains A and B
+ */
+ reply = binding.sendChimeraCommand("list resi att jv_kd", true);
+ assertEquals(reply.size(), 4);
+ assertTrue(reply.contains("residue id #0:11.A jv_kd -2.1 index 11"));
+ assertTrue(reply.contains("residue id #0:14.A jv_kd 3.6 index 14"));
+ assertTrue(reply.contains("residue id #0:11.B jv_kd -2.1 index 11"));
+ assertTrue(reply.contains("residue id #0:14.B jv_kd 3.6 index 14"));
+
+ /*
+ * list residues with positive kd score
+ */
+ reply = binding.sendChimeraCommand(
+ "list resi spec :*/jv_kd>0 attr jv_kd", true);
+ assertEquals(reply.size(), 2);
+ assertTrue(reply.contains("residue id #0:14.A jv_kd 3.6 index 14"));
+ assertTrue(reply.contains("residue id #0:14.B jv_kd 3.6 index 14"));
+
+ SiftsClient.setMockSiftsFile(null);
+ chimeraViewer.closeViewer(true);
+ chimeraViewer = null;
+ }
+
+ /**
+ * Test for creating Jalview features from attributes on mapped residues in
+ * Chimera. Note this uses local copies of PDB and SIFTS file, no network
+ * connection required.
+ *
+ * @throws IOException
+ * @throws SiftsException
+ */
+ // External as this requires a local install of Chimera
+ @Test(groups = { "External" })
+ public void testGetAttributes() throws IOException, SiftsException
+ {
+ String inFile = "examples/uniref50.fa";
+ AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(inFile,
+ DataSourceType.FILE);
+ assertNotNull(af, "Failed to create AlignFrame");
+ SequenceI fer2Arath = af.getViewport().getAlignment()
+ .findName("FER2_ARATH");
+ assertNotNull(fer2Arath, "Didn't find FER2_ARATH");
+
+ /*
+ * need a Uniprot dbref for SIFTS mapping to work!!
+ */
+ fer2Arath.addDBRef(new DBRefEntry("UNIPROT", "0", "P16972", null));
+
+ /*
+ * use local test PDB and SIFTS files
+ */
+ String pdbFilePath = new File(
+ "test/jalview/ext/rbvi/chimera/4zho.pdb").getPath();
+ PDBEntry pdbEntry = new PDBEntry("4ZHO", null, null, pdbFilePath);
+ String siftsFilePath = new File(
+ "test/jalview/ext/rbvi/chimera/4zho.xml.gz")
+ .getPath();
+ SiftsClient.setMockSiftsFile(new File(siftsFilePath));
+
+ StructureViewer structureViewer = new StructureViewer(af.getViewport()
+ .getStructureSelectionManager());
+ chimeraViewer = structureViewer.viewStructures(pdbEntry,
+ new SequenceI[] { fer2Arath }, af.getCurrentView()
+ .getAlignPanel());
+
+ JalviewChimeraBinding binding = (JalviewChimeraBinding) chimeraViewer
+ .getBinding();
+ do
+ {
+ try
+ {
+ Thread.sleep(500);
+ } catch (InterruptedException e)
{
- for (int q = 0; q < dsq.getAllPDBEntries().size(); q++)
- {
- final StructureViewer structureViewer = new StructureViewer(af
- .getViewport().getStructureSelectionManager());
- structureViewer.setViewerType(ViewerType.CHIMERA);
- JalviewStructureDisplayI chimeraViewer = structureViewer
- .viewStructures(dsq.getAllPDBEntries().elementAt(q),
- new SequenceI[] { sq }, af.getCurrentView()
- .getAlignPanel());
- /*
- * Wait for viewer load thread to complete
- */
- while (!chimeraViewer.getBinding().isFinishedInit())
- {
- try
- {
- Thread.sleep(500);
- } catch (InterruptedException e)
- {
- }
- }
- assertEquals(1, chimeraViewer.getBinding().getPdbCount());
- chimeraViewer.closeViewer(true);
- // todo: break here means only once through this loop?
- break;
- }
- break;
}
+ } while (!binding.isFinishedInit());
+
+ assertTrue(binding.isChimeraRunning(), "Failed to launch Chimera");
+
+ assertEquals(binding.getPdbCount(), 1);
+
+ /*
+ * 'perform' menu action to copy visible features to
+ * attributes in Chimera
+ */
+ // TODO rename and pull up method to binding interface
+ // once functionality is added for Jmol as well
+ binding.copyStructureAttributesToFeatures("isHelix", af.getViewport()
+ .getAlignPanel());
+
+ /*
+ * verify 22 residues have isHelix feature
+ * (may merge into ranges in future)
+ */
+ af.setShowSeqFeatures(true);
+ FeatureRenderer fr = af.getFeatureRenderer();
+ fr.setVisible("isHelix");
+ for (int res = 75; res <= 83; res++)
+ {
+ checkFeaturesAtRes(fer2Arath, fr, res, "isHelix");
}
+ for (int res = 117; res <= 123; res++)
+ {
+ checkFeaturesAtRes(fer2Arath, fr, res, "isHelix");
+ }
+ for (int res = 129; res <= 131; res++)
+ {
+ checkFeaturesAtRes(fer2Arath, fr, res, "isHelix");
+ }
+ for (int res = 143; res <= 145; res++)
+ {
+ checkFeaturesAtRes(fer2Arath, fr, res, "isHelix");
+ }
+
+ /*
+ * fetch a numeric valued attribute
+ */
+ binding.copyStructureAttributesToFeatures("phi", af.getViewport()
+ .getAlignPanel());
+ fr.setVisible("phi");
+ List<SequenceFeature> fs = fr.findFeaturesAtRes(fer2Arath, 54);
+ assertEquals(fs.size(), 3);
+ assertEquals(fs.get(0).getType(), "RESNUM");
+ assertEquals(fs.get(1).getType(), "phi");
+ assertEquals(fs.get(2).getType(), "phi");
+ assertEquals(fs.get(1).getDescription(), "A"); // chain
+ assertEquals(fs.get(2).getDescription(), "B");
+ assertEquals(fs.get(1).getScore(), -131.0713f, 0.001f);
+ assertEquals(fs.get(2).getScore(), -127.39512, 0.001f);
+
+ /*
+ * tear down - also in AfterMethod
+ */
+ SiftsClient.setMockSiftsFile(null);
+ chimeraViewer.closeViewer(true);
+ chimeraViewer = null;
+ }
+
+ /**
+ * Helper method to verify new feature at a sequence position
+ *
+ * @param seq
+ * @param fr
+ * @param res
+ * @param featureType
+ */
+ protected void checkFeaturesAtRes(SequenceI seq, FeatureRenderer fr,
+ int res, String featureType)
+ {
+ String where = "at position " + res;
+ List<SequenceFeature> fs = fr.findFeaturesAtRes(seq, res);
+ assertEquals(fs.size(), 2, where);
+ assertEquals(fs.get(0).getType(), "RESNUM", where);
+ SequenceFeature sf = fs.get(1);
+ assertEquals(sf.getType(), featureType, where);
+ assertEquals(sf.getFeatureGroup(), "Chimera", where);
+ assertEquals(sf.getDescription(), "True", where);
+ assertEquals(sf.getScore(), Float.NaN, where);
}
}
-#---JalviewX Properties File---
-#Fri Apr 25 09:54:25 BST 2014
-SCREEN_Y=768
-SCREEN_X=936
-SHOW_WSDISCOVERY_ERRORS=true
-LATEST_VERSION=2.8.0b1
-SHOW_CONSERVATION=true
+ANNOTATIONCOLOUR_MAX=ff0000
+ANNOTATIONCOLOUR_MIN=ffc800
+ANTI_ALIAS=false
+AUTHORFNAMES=Jim Procter, Andrew Waterhouse, Jan Engelhardt, Lauren Lui, Michele Clamp, James Cuff, Steve Searle, David Martin & Geoff Barton
+AUTHORS=J Procter, AM Waterhouse, LM Lui, J Engelhardt, G Barton, M Clamp, S Searle
+AUTO_CALC_CONSENSUS=true
+BLC_JVSUFFIX=true
+BUILD_DATE=01 November 2013
+CLUSTAL_JVSUFFIX=true
+DAS_ACTIVE_SOURCE=uniprot\t
+DAS_LOCAL_SOURCE=
+DAS_REGISTRY_URL=http\://www.ebi.ac.uk/das-srv/registry/das/
+DEFAULT_COLOUR=None
+DEFAULT_FILE_FORMAT=FASTA
+FASTA_JVSUFFIX=true
+FIGURE_AUTOIDWIDTH=false
+FIGURE_USERIDWIDTH=
+FONT_NAME=SansSerif
+FONT_SIZE=10
+FONT_STYLE=plain
+GAP_SYMBOL=-
+ID_ITALICS=true
+JALVIEW_NEWS_RSS_LASTMODIFIED=Apr 23, 2014 2\:53\:26 PM
+JALVIEW_RSS_WINDOW_SCREEN_HEIGHT=328
JALVIEW_RSS_WINDOW_SCREEN_WIDTH=550
+JALVIEW_RSS_WINDOW_SCREEN_X=0
+JALVIEW_RSS_WINDOW_SCREEN_Y=0
+JAVA_CONSOLE_SCREEN_HEIGHT=162
JAVA_CONSOLE_SCREEN_WIDTH=450
+JAVA_CONSOLE_SCREEN_X=830
+JAVA_CONSOLE_SCREEN_Y=475
+JWS2HOSTURLS=http\://www.compbio.dundee.ac.uk/jabaws
LAST_DIRECTORY=/Volumes/Data/Users/jimp/Documents/testing/Jalview/examples
-ID_ITALICS=true
-SORT_ALIGNMENT=No sort
-SHOW_IDENTITY=true
-WSMENU_BYHOST=false
-SEQUENCE_LINKS=EMBL-EBI Search|http\://www.ebi.ac.uk/ebisearch/search.ebi?db\=allebi&query\=$SEQUENCE_ID$
-SHOW_FULLSCREEN=false
-RECENT_URL=http\://www.jalview.org/examples/exampleFile_2_7.jar
-FONT_NAME=SansSerif
-BLC_JVSUFFIX=true
-VERSION_CHECK=false
-YEAR=2011
-SHOW_DBREFS_TOOLTIP=true
+LATEST_VERSION=2.8.0b1
MSF_JVSUFFIX=true
-SCREENGEOMETRY_HEIGHT=1600
-JAVA_CONSOLE_SCREEN_Y=475
-JAVA_CONSOLE_SCREEN_X=830
+NOQUESTIONNAIRES=true
+PAD_GAPS=false
PFAM_JVSUFFIX=true
+PILEUP_JVSUFFIX=true
PIR_JVSUFFIX=true
-STARTUP_FILE=http\://www.jalview.org/examples/exampleFile_2_3.jar
-JAVA_CONSOLE_SCREEN_HEIGHT=162
PIR_MODELLER=false
-GAP_SYMBOL=-
-SHOW_QUALITY=true
+RECENT_FILE=examples/uniref50.fa\t/Volumes/Data/Users/jimp/Documents/testing/Jalview/examples/RF00031_folded.stk\t/Volumes/Data/Users/jimp/bs_ig_mult.out
+RECENT_URL=http\://www.jalview.org/examples/exampleFile_2_7.jar
+RIGHT_ALIGN_IDS=false
+RSBS_SERVICES=|Multi-Harmony|Analysis|Sequence Harmony and Multi-Relief (Brandt et al. 2010)|hseparable,gapCharacter\='-',returns\='ANNOTATION'|?tool\=jalview|http\://zeus.few.vu.nl/programs/shmrwww/index.php?tool\=jalview&groups\=$PARTITION\:min\='2',minsize\='2',sep\=' '$&ali_file\=$ALIGNMENT\:format\='FASTA',writeasfile$
+SCREEN_HEIGHT=650
+SCREEN_WIDTH=900
+SCREEN_X=936
+SCREEN_Y=768
+SCREENGEOMETRY_HEIGHT=1600
+SCREENGEOMETRY_WIDTH=2560
+SEQUENCE_LINKS=EMBL-EBI Search|http\://www.ebi.ac.uk/ebisearch/search.ebi?db\=allebi&query\=$SEQUENCE_ID$
+SHOW_ANNOTATIONS=true
+SHOW_CONSENSUS_HISTOGRAM=true
+SHOW_CONSENSUS_LOGO=false
+SHOW_CONSERVATION=true
+SHOW_DBREFS_TOOLTIP=true
+SHOW_ENFIN_SERVICES=true
+SHOW_FULLSCREEN=false
+SHOW_GROUP_CONSENSUS=false
SHOW_GROUP_CONSERVATION=false
+SHOW_IDENTITY=true
+SHOW_JAVA_CONSOLE=false
+SHOW_JVSUFFIX=true
SHOW_JWS2_SERVICES=true
SHOW_NPFEATS_TOOLTIP=true
-FONT_STYLE=plain
-ANTI_ALIAS=false
-SORT_BY_TREE=false
-RSBS_SERVICES=|Multi-Harmony|Analysis|Sequence Harmony and Multi-Relief (Brandt et al. 2010)|hseparable,gapCharacter\='-',returns\='ANNOTATION'|?tool\=jalview|http\://zeus.few.vu.nl/programs/shmrwww/index.php?tool\=jalview&groups\=$PARTITION\:min\='2',minsize\='2',sep\=' '$&ali_file\=$ALIGNMENT\:format\='FASTA',writeasfile$
-AUTHORFNAMES=Jim Procter, Andrew Waterhouse, Jan Engelhardt, Lauren Lui, Michele Clamp, James Cuff, Steve Searle, David Martin & Geoff Barton
-JALVIEW_RSS_WINDOW_SCREEN_HEIGHT=328
-SHOW_GROUP_CONSENSUS=false
-SHOW_CONSENSUS_HISTOGRAM=true
SHOW_OVERVIEW=false
-AUTHORS=J Procter, AM Waterhouse, LM Lui, J Engelhardt, G Barton, M Clamp, S Searle
-FIGURE_AUTOIDWIDTH=false
-SCREEN_WIDTH=900
-ANNOTATIONCOLOUR_MIN=ffc800
+SHOW_QUALITY=true
SHOW_STARTUP_FILE=false
-RECENT_FILE=examples/uniref50.fa\t/Volumes/Data/Users/jimp/Documents/testing/Jalview/examples/RF00031_folded.stk\t/Volumes/Data/Users/jimp/bs_ig_mult.out
-DEFAULT_FILE_FORMAT=FASTA
-SHOW_JAVA_CONSOLE=false
-VERSION=2.8b1
-FIGURE_USERIDWIDTH=
-WSMENU_BYTYPE=false
-DEFAULT_COLOUR=None
-NOQUESTIONNAIRES=true
-JALVIEW_NEWS_RSS_LASTMODIFIED=Apr 23, 2014 2\:53\:26 PM
-BUILD_DATE=01 November 2013
-PILEUP_JVSUFFIX=true
-SHOW_CONSENSUS_LOGO=false
-SCREENGEOMETRY_WIDTH=2560
-SHOW_ANNOTATIONS=true
-JALVIEW_RSS_WINDOW_SCREEN_Y=0
-USAGESTATS=false
-JALVIEW_RSS_WINDOW_SCREEN_X=0
SHOW_UNCONSERVED=false
-SHOW_JVSUFFIX=true
-DAS_LOCAL_SOURCE=
-SCREEN_HEIGHT=650
-ANNOTATIONCOLOUR_MAX=ff0000
-AUTO_CALC_CONSENSUS=true
-FASTA_JVSUFFIX=true
-DAS_ACTIVE_SOURCE=uniprot\t
-JWS2HOSTURLS=http\://www.compbio.dundee.ac.uk/jabaws
-PAD_GAPS=false
-CLUSTAL_JVSUFFIX=true
-SHOW_ENFIN_SERVICES=true
-FONT_SIZE=10
-RIGHT_ALIGN_IDS=false
+SHOW_WSDISCOVERY_ERRORS=true
+SORT_ALIGNMENT=No sort
+SORT_BY_TREE=false
+STARTUP_FILE=
+USAGESTATS=false
USE_PROXY=false
+VERSION_CHECK=false
+VERSION=2.8b1
WRAP_ALIGNMENT=false
-#DAS_REGISTRY_URL=http\://www.dasregistry.org/das/ # retired 01/05/2015
-DAS_REGISTRY_URL=http\://www.ebi.ac.uk/das-srv/registry/das/
+WSMENU_BYHOST=false
+WSMENU_BYTYPE=false
+YEAR=2011
--- /dev/null
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview 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.
+ *
+ * Jalview 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.gui;
+
+import static org.testng.Assert.assertEquals;
+
+import jalview.bin.Cache;
+import jalview.bin.Jalview;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceI;
+import jalview.io.DataSourceType;
+import jalview.io.FileLoader;
+import jalview.viewmodel.ViewportRanges;
+
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+public class AlignmentPanelTest
+{
+ SequenceI seq1 = new Sequence(
+ "Seq1",
+ "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+ SequenceI seq2 = new Sequence(
+ "Seq2",
+ "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+ SequenceI seq3 = new Sequence(
+ "Seq3",
+ "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+ SequenceI seq4 = new Sequence(
+ "Seq4",
+ "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+ SequenceI seq5 = new Sequence(
+ "Seq5",
+ "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+ SequenceI seq6 = new Sequence(
+ "Seq6",
+ "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+ SequenceI seq7 = new Sequence(
+ "Seq7",
+ "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+ SequenceI seq8 = new Sequence(
+ "Seq8",
+ "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+ SequenceI seq9 = new Sequence(
+ "Seq9",
+ "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+ SequenceI seq10 = new Sequence(
+ "Seq10",
+ "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+ SequenceI seq11 = new Sequence(
+ "Seq11",
+ "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+ SequenceI seq12 = new Sequence(
+ "Seq12",
+ "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+ SequenceI seq13 = new Sequence(
+ "Seq13",
+ "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+ SequenceI seq14 = new Sequence(
+ "Seq14",
+ "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+ SequenceI seq15 = new Sequence(
+ "Seq15",
+ "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+ SequenceI seq16 = new Sequence(
+ "Seq16",
+ "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+ SequenceI seq17 = new Sequence(
+ "Seq17",
+ "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+ SequenceI seq18 = new Sequence(
+ "Seq18",
+ "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+ SequenceI seq19 = new Sequence(
+ "Seq19",
+ "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+ SequenceI seq20 = new Sequence(
+ "Seq20",
+ "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+ SequenceI seq21 = new Sequence(
+ "Seq21",
+ "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+ SequenceI seq22 = new Sequence(
+ "Seq22",
+ "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+ SequenceI seq23 = new Sequence(
+ "Seq23",
+ "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+ AlignFrame af;
+
+ @BeforeMethod(alwaysRun = true)
+ public void setUp()
+ {
+ Jalview.main(new String[] { "-nonews", "-props",
+ "test/jalview/testProps.jvprops" });
+
+ Cache.applicationProperties.setProperty("SHOW_IDENTITY",
+ Boolean.TRUE.toString());
+ af = new FileLoader().LoadFileWaitTillLoaded("examples/uniref50.fa",
+ DataSourceType.FILE);
+
+ /*
+ * wait for Consensus thread to complete
+ */
+ synchronized (this)
+ {
+ while (af.getViewport().getConsensusSeq() == null)
+ {
+ try
+ {
+ wait(50);
+ } catch (InterruptedException e)
+ {
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Test side effect that end residue is set correctly by setScrollValues, with
+ * or without hidden columns
+ */
+ @Test(groups = "Functional")
+ public void TestSetScrollValues()
+ {
+ ViewportRanges ranges = af.getViewport().getRanges();
+ af.alignPanel.setScrollValues(0, 0);
+
+ int oldres = ranges.getEndRes();
+ af.alignPanel.setScrollValues(-1, 5);
+
+ // setting -ve x value does not change residue
+ assertEquals(ranges.getEndRes(), oldres);
+
+ af.alignPanel.setScrollValues(0, 5);
+
+ // setting 0 as x value does not change residue
+ assertEquals(ranges.getEndRes(), oldres);
+
+ af.alignPanel.setScrollValues(5, 5);
+ // setting x value to 5 extends endRes by 5 residues
+ assertEquals(ranges.getEndRes(), oldres + 5);
+
+ // scroll to position after hidden columns sets endres to oldres (width) +
+ // position
+ int scrollpos = 60;
+ af.getViewport().hideColumns(30, 50);
+ af.alignPanel.setScrollValues(scrollpos, 5);
+ assertEquals(ranges.getEndRes(), oldres + scrollpos);
+
+ // scroll to position within hidden columns, still sets endres to oldres +
+ // position
+ // not sure if this is actually correct behaviour but this is what Jalview
+ // currently does
+ scrollpos = 40;
+ af.getViewport().showAllHiddenColumns();
+ af.getViewport().hideColumns(30, 50);
+ af.alignPanel.setScrollValues(scrollpos, 5);
+ assertEquals(ranges.getEndRes(), oldres + scrollpos);
+
+ // scroll to position within <width> distance of the end of the alignment
+ // endRes should be set to width of alignment - 1
+ scrollpos = 130;
+ af.getViewport().showAllHiddenColumns();
+ af.alignPanel.setScrollValues(scrollpos, 5);
+ assertEquals(ranges.getEndRes(), af.getViewport()
+ .getAlignment().getWidth() - 1);
+
+ // now hide some columns, and scroll to position within <width>
+ // distance of the end of the alignment
+ // endRes should be set to width of alignment - 1 - the number of hidden
+ // columns
+ af.getViewport().hideColumns(30, 50);
+ af.alignPanel.setScrollValues(scrollpos, 5);
+ assertEquals(ranges.getEndRes(), af.getViewport()
+ .getAlignment().getWidth() - 1 - 21); // 21 is the number of hidden
+ // columns
+ }
+}
types = AnnotationChooser.getAnnotationTypes(
parentPanel.getAlignment(), false);
- assertEquals("Not six annotation types", 6, types.size());
+ assertEquals("Not six annotation types", 7, types.size());
assertTrue("IUPRED missing", types.contains("IUPRED"));
assertTrue("JMol missing", types.contains("JMol"));
assertTrue("Beauty missing", types.contains("Beauty"));
assertTrue("Consensus missing", types.contains("Consensus"));
assertTrue("Quality missing", types.contains("Quality"));
assertTrue("Conservation missing", types.contains("Conservation"));
+ assertTrue("Occupancy missing", types.contains("Occupancy"));
}
/**
AlignmentAnnotation[] anns = parentPanel.getAlignment()
.getAlignmentAnnotation();
- assertTrue(anns[5].visible); // JMol for seq3
- assertTrue(anns[7].visible); // JMol for seq1
+ int autocalc = countAutocalc(anns);
+ assertTrue(anns[autocalc + 2].visible); // JMol for seq3
+ assertTrue(anns[autocalc + 4].visible); // JMol for seq1
setSelected(getTypeCheckbox("JMol"), true);
assertTrue(anns[0].visible); // Conservation
assertTrue(anns[1].visible); // Quality
assertTrue(anns[2].visible); // Consensus
- assertTrue(anns[3].visible); // IUPred for seq0
- assertTrue(anns[4].visible); // Beauty
- assertFalse(anns[5].visible); // JMol for seq3 - not selected but hidden
- assertTrue(anns[6].visible); // IUPRED for seq2
- assertFalse(anns[7].visible); // JMol for seq1 - selected and hidden
+ assertTrue(anns[3].visible); // Occupancy
+ assertTrue(anns[4].visible); // IUPred for seq0
+ assertTrue(anns[5].visible); // Beauty
+ assertFalse(anns[6].visible); // JMol for seq3 - not selected but hidden
+ assertTrue(anns[7].visible); // IUPRED for seq2
+ assertFalse(anns[8].visible); // JMol for seq1 - selected and hidden
}
/**
AlignmentAnnotation[] anns = parentPanel.getAlignment()
.getAlignmentAnnotation();
- assertTrue(anns[7].visible); // JMol for seq1
+ int autocalc = countAutocalc(anns);
+ assertTrue(anns[autocalc + 4].visible); // JMol for seq1
setSelected(getTypeCheckbox("JMol"), true);
assertTrue(anns[0].visible); // Conservation
assertTrue(anns[1].visible); // Quality
assertTrue(anns[2].visible); // Consensus
- assertTrue(anns[3].visible); // IUPred for seq0
- assertTrue(anns[4].visible); // Beauty
- assertTrue(anns[5].visible); // JMol for seq3 not in selection group
- assertTrue(anns[6].visible); // IUPRED for seq2
- assertFalse(anns[7].visible); // JMol for seq1 in selection group
+ assertTrue(anns[3].visible); // Occupancy
+ assertTrue(anns[4].visible); // IUPred for seq0
+ assertTrue(anns[5].visible); // Beauty
+ assertTrue(anns[6].visible); // JMol for seq3 not in selection group
+ assertTrue(anns[7].visible); // IUPRED for seq2
+ assertFalse(anns[8].visible); // JMol for seq1 in selection group
}
/**
// select JMol - all hidden
setSelected(typeCheckbox, true);
- assertFalse(anns[5].visible); // JMol for seq3
- assertFalse(anns[7].visible); // JMol for seq1
+ int autocalc = countAutocalc(anns);
+ assertFalse(anns[autocalc + 2].visible); // JMol for seq3
+ assertFalse(anns[autocalc + 4].visible); // JMol for seq1
// deselect JMol - all unhidden
setSelected(typeCheckbox, false);
- assertTrue(anns[0].visible); // Conservation
- assertTrue(anns[1].visible); // Quality
- assertTrue(anns[2].visible); // Consensus
- assertTrue(anns[3].visible); // IUPred for seq0
- assertTrue(anns[4].visible); // Beauty
- assertTrue(anns[5].visible); // JMol for seq3
- assertTrue(anns[6].visible); // IUPRED for seq2
- assertTrue(anns[7].visible); // JMol for seq1
+ for (AlignmentAnnotation ann : anns)
+ {
+ assertTrue(ann.visible);
+ }
+ }
+
+ /**
+ * Returns a count of autocalculated annotations in the set provided
+ *
+ * @param anns
+ * @return
+ */
+ private int countAutocalc(AlignmentAnnotation[] anns)
+ {
+ int count = 0;
+ for (AlignmentAnnotation ann : anns)
+ {
+ if (ann.autoCalculated)
+ {
+ count++;
+ }
+ }
+ return count;
}
/**
setSelected(allSequencesCheckbox, true);
setSelected(hideCheckbox, true);
setSelected(getTypeCheckbox("JMol"), true);
- assertFalse(anns[5].visible); // JMol for seq3
- assertFalse(anns[7].visible); // JMol for seq1
+ int autocalc = countAutocalc(anns);
+ assertFalse(anns[autocalc + 2].visible); // JMol for seq3
+ assertFalse(anns[autocalc + 4].visible); // JMol for seq1
// ...now show them...
setSelected(showCheckbox, true);
- assertTrue(anns[0].visible); // Conservation
- assertTrue(anns[1].visible); // Quality
- assertTrue(anns[2].visible); // Consensus
- assertTrue(anns[3].visible); // IUPred for seq0
- assertTrue(anns[4].visible); // Beauty
- assertTrue(anns[5].visible); // JMol for seq3
- assertTrue(anns[6].visible); // IUPRED for seq2
- assertTrue(anns[7].visible); // JMol for seq1
+ for (AlignmentAnnotation ann : anns)
+ {
+ assertTrue(ann.visible);
+ }
}
/**
setSelected(hideCheckbox, true);
setSelected(getTypeCheckbox("JMol"), true);
- assertTrue(anns[5].visible); // JMol for seq3
- assertFalse(anns[7].visible); // JMol for seq1
+ int autocalc = countAutocalc(anns);
+ assertTrue(anns[autocalc + 2].visible); // JMol for seq3
+ assertFalse(anns[autocalc + 4].visible); // JMol for seq1
// ...now show them...
setSelected(showCheckbox, true);
- assertTrue(anns[0].visible); // Conservation
- assertTrue(anns[1].visible); // Quality
- assertTrue(anns[2].visible); // Consensus
- assertTrue(anns[3].visible); // IUPred for seq0
- assertTrue(anns[4].visible); // Beauty
- assertTrue(anns[5].visible); // JMol for seq3
- assertTrue(anns[6].visible); // IUPRED for seq2
- assertTrue(anns[7].visible); // JMol for seq1
+ for (AlignmentAnnotation ann : anns)
+ {
+ assertTrue(ann.visible);
+ }
}
/**
final Checkbox typeCheckbox = getTypeCheckbox("JMol");
// select JMol - all shown
setSelected(typeCheckbox, true);
- assertTrue(anns[5].visible); // JMol for seq3
- assertTrue(anns[7].visible); // JMol for seq1
+ int autocalc = countAutocalc(anns);
+ assertTrue(anns[autocalc + 2].visible); // JMol for seq3
+ assertTrue(anns[autocalc + 4].visible); // JMol for seq1
// deselect JMol - all hidden
setSelected(typeCheckbox, false);
assertTrue(anns[0].visible); // Conservation
assertTrue(anns[1].visible); // Quality
assertTrue(anns[2].visible); // Consensus
- assertTrue(anns[3].visible); // IUPred for seq0
- assertTrue(anns[4].visible); // Beauty
- assertFalse(anns[5].visible); // JMol for seq3
- assertTrue(anns[6].visible); // IUPRED for seq2
- assertFalse(anns[7].visible); // JMol for seq1
+ assertTrue(anns[3].visible); // Occupancy
+ assertTrue(anns[4].visible); // IUPred for seq0
+ assertTrue(anns[5].visible); // Beauty
+ assertFalse(anns[6].visible); // JMol for seq3
+ assertTrue(anns[7].visible); // IUPRED for seq2
+ assertFalse(anns[8].visible); // JMol for seq1
}
/**
// select JMol - should remain visible
setSelected(getTypeCheckbox("JMol"), true);
- assertTrue(anns[5].visible); // JMol for seq3
- assertTrue(anns[7].visible); // JMol for seq1
+ int autocalc = countAutocalc(anns);
+ assertTrue(anns[autocalc + 2].visible); // JMol for seq3
+ assertTrue(anns[autocalc + 4].visible); // JMol for seq1
// deselect JMol - should be hidden for selected sequences only
setSelected(getTypeCheckbox("JMol"), false);
assertTrue(anns[0].visible); // Conservation
assertTrue(anns[1].visible); // Quality
assertTrue(anns[2].visible); // Consensus
- assertTrue(anns[3].visible); // IUPred for seq0
- assertTrue(anns[4].visible); // Beauty
- assertTrue(anns[5].visible); // JMol for seq3 not in selection group
- assertTrue(anns[6].visible); // IUPRED for seq2
- assertFalse(anns[7].visible); // JMol for seq1 in selection group
+ assertTrue(anns[3].visible); // Occupancy
+ assertTrue(anns[4].visible); // IUPred for seq0
+ assertTrue(anns[5].visible); // Beauty
+ assertTrue(anns[6].visible); // JMol for seq3 not in selection group
+ assertTrue(anns[7].visible); // IUPRED for seq2
+ assertFalse(anns[8].visible); // JMol for seq1 in selection group
}
/**
AlignmentAnnotation[] anns = parentPanel.getAlignment()
.getAlignmentAnnotation();
- // remember 3 annotations to skip (Conservation/Quality/Consensus)
- assertFalse(testee.isInActionScope(anns[3]));
- assertFalse(testee.isInActionScope(anns[4]));
- assertFalse(testee.isInActionScope(anns[5]));
- assertTrue(testee.isInActionScope(anns[6]));
- assertTrue(testee.isInActionScope(anns[7]));
+ int autocalc = countAutocalc(anns);
+ assertFalse(testee.isInActionScope(anns[autocalc]));
+ assertFalse(testee.isInActionScope(anns[autocalc + 1]));
+ assertFalse(testee.isInActionScope(anns[autocalc + 2]));
+ assertTrue(testee.isInActionScope(anns[autocalc + 3]));
+ assertTrue(testee.isInActionScope(anns[autocalc + 4]));
}
/**
AlignmentAnnotation[] anns = parentPanel.getAlignment()
.getAlignmentAnnotation();
- // remember 3 annotations to skip (Conservation/Quality/Consensus)
- assertTrue(testee.isInActionScope(anns[3]));
- assertTrue(testee.isInActionScope(anns[4]));
- assertTrue(testee.isInActionScope(anns[5]));
- assertFalse(testee.isInActionScope(anns[6]));
- assertFalse(testee.isInActionScope(anns[7]));
+ int autocalc = countAutocalc(anns);
+ assertTrue(testee.isInActionScope(anns[autocalc]));
+ assertTrue(testee.isInActionScope(anns[autocalc + 1]));
+ assertTrue(testee.isInActionScope(anns[autocalc + 2]));
+ assertFalse(testee.isInActionScope(anns[autocalc + 3]));
+ assertFalse(testee.isInActionScope(anns[autocalc + 4]));
}
/**
assertTrue(anns[0].visible); // Conservation
assertTrue(anns[1].visible); // Quality
assertTrue(anns[2].visible); // Consensus
- assertFalse(anns[3].visible); // IUPRED
- assertTrue(anns[4].visible); // Beauty (not seq-related)
- assertFalse(anns[5].visible); // JMol
- assertFalse(anns[6].visible); // IUPRED
- assertFalse(anns[7].visible); // JMol
+ assertTrue(anns[3].visible); // Occupancy
+ assertFalse(anns[4].visible); // IUPRED
+ assertTrue(anns[5].visible); // Beauty (not seq-related)
+ assertFalse(anns[6].visible); // JMol
+ assertFalse(anns[7].visible); // IUPRED
+ assertFalse(anns[8].visible); // JMol
// reset - should all be visible
testee.resetOriginalState();
av.setGlobalColourScheme(new ZappoColourScheme());
// @see ResidueProperties.zappo
- assertEquals(Color.pink, sr.getResidueColour(seq, 0, null)); // M
- assertEquals(Color.green, sr.getResidueColour(seq, 2, null)); // T
- assertEquals(Color.magenta, sr.getResidueColour(seq, 5, null)); // G
- assertEquals(Color.orange, sr.getResidueColour(seq, 12, null)); // F
+ assertEquals(Color.pink, sr.getResidueBoxColour(seq, 0)); // M
+ assertEquals(Color.green, sr.getResidueBoxColour(seq, 2)); // T
+ assertEquals(Color.magenta, sr.getResidueBoxColour(seq, 5)); // G
+ assertEquals(Color.orange, sr.getResidueBoxColour(seq, 12)); // F
}
// TODO more tests for getResidueBoxColour covering groups, feature rendering,
// gaps, overview...
import java.util.Random;
import org.testng.annotations.Test;
+import org.testng.internal.junit.ArrayAsserts;
public class MatrixTest
{
+ final static double DELTA = 0.0001d;
+
@Test(groups = "Timing")
public void testPreMultiply_timing()
{
* 1x3 times 3x1 is 1x1
* 2x5 + 3x6 + 4*7 = 56
*/
- Matrix m3 = m2.preMultiply(m1);
- assertEquals(m3.rows, 1);
- assertEquals(m3.cols, 1);
- assertEquals(m3.value[0][0], 56d);
+ MatrixI m3 = m2.preMultiply(m1);
+ assertEquals(m3.height(), 1);
+ assertEquals(m3.width(), 1);
+ assertEquals(m3.getValue(0, 0), 56d);
/*
* 3x1 times 1x3 is 3x3
*/
m3 = m1.preMultiply(m2);
- assertEquals(m3.rows, 3);
- assertEquals(m3.cols, 3);
- assertEquals(Arrays.toString(m3.value[0]), "[10.0, 15.0, 20.0]");
- assertEquals(Arrays.toString(m3.value[1]), "[12.0, 18.0, 24.0]");
- assertEquals(Arrays.toString(m3.value[2]), "[14.0, 21.0, 28.0]");
+ assertEquals(m3.height(), 3);
+ assertEquals(m3.width(), 3);
+ assertEquals(Arrays.toString(m3.getRow(0)), "[10.0, 15.0, 20.0]");
+ assertEquals(Arrays.toString(m3.getRow(1)), "[12.0, 18.0, 24.0]");
+ assertEquals(Arrays.toString(m3.getRow(2)), "[14.0, 21.0, 28.0]");
}
@Test(
private boolean matrixEquals(Matrix m1, Matrix m2) {
- return Arrays.deepEquals(m1.value, m2.value);
+ if (m1.width() != m2.width() || m1.height() != m2.height())
+ {
+ return false;
+ }
+ for (int i = 0; i < m1.height(); i++)
+ {
+ if (!Arrays.equals(m1.getRow(i), m2.getRow(i)))
+ {
+ return false;
+ }
+ }
+ return true;
}
@Test(groups = "Functional")
* (3020 30200)
* (5040 50400)
*/
- Matrix m1 = new Matrix(new double[][] { { 2, 3 }, { 4, 5 } });
- Matrix m2 = new Matrix(new double[][] { { 10, 100 }, { 1000, 10000 } });
- Matrix m3 = m1.postMultiply(m2);
- assertEquals(Arrays.toString(m3.value[0]), "[3020.0, 30200.0]");
- assertEquals(Arrays.toString(m3.value[1]), "[5040.0, 50400.0]");
+ MatrixI m1 = new Matrix(new double[][] { { 2, 3 }, { 4, 5 } });
+ MatrixI m2 = new Matrix(new double[][] { { 10, 100 }, { 1000, 10000 } });
+ MatrixI m3 = m1.postMultiply(m2);
+ assertEquals(Arrays.toString(m3.getRow(0)), "[3020.0, 30200.0]");
+ assertEquals(Arrays.toString(m3.getRow(1)), "[5040.0, 50400.0]");
/*
* also check m2.preMultiply(m1) - should be same as m1.postMultiply(m2)
*/
m3 = m2.preMultiply(m1);
- assertEquals(Arrays.toString(m3.value[0]), "[3020.0, 30200.0]");
- assertEquals(Arrays.toString(m3.value[1]), "[5040.0, 50400.0]");
+ assertEquals(Arrays.toString(m3.getRow(0)), "[3020.0, 30200.0]");
+ assertEquals(Arrays.toString(m3.getRow(1)), "[5040.0, 50400.0]");
/*
* m1 has more rows than columns
m1 = new Matrix(new double[][] { { 2 }, { 3 } });
m2 = new Matrix(new double[][] { { 10, 100, 1000 } });
m3 = m1.postMultiply(m2);
- assertEquals(m3.rows, 2);
- assertEquals(m3.cols, 3);
- assertEquals(Arrays.toString(m3.value[0]), "[20.0, 200.0, 2000.0]");
- assertEquals(Arrays.toString(m3.value[1]), "[30.0, 300.0, 3000.0]");
+ assertEquals(m3.height(), 2);
+ assertEquals(m3.width(), 3);
+ assertEquals(Arrays.toString(m3.getRow(0)), "[20.0, 200.0, 2000.0]");
+ assertEquals(Arrays.toString(m3.getRow(1)), "[30.0, 300.0, 3000.0]");
m3 = m2.preMultiply(m1);
- assertEquals(m3.rows, 2);
- assertEquals(m3.cols, 3);
- assertEquals(Arrays.toString(m3.value[0]), "[20.0, 200.0, 2000.0]");
- assertEquals(Arrays.toString(m3.value[1]), "[30.0, 300.0, 3000.0]");
+ assertEquals(m3.height(), 2);
+ assertEquals(m3.width(), 3);
+ assertEquals(Arrays.toString(m3.getRow(0)), "[20.0, 200.0, 2000.0]");
+ assertEquals(Arrays.toString(m3.getRow(1)), "[30.0, 300.0, 3000.0]");
/*
* m1 has more columns than rows
m1 = new Matrix(new double[][] { { 2, 3, 4 } });
m2 = new Matrix(new double[][] { { 5, 4 }, { 6, 3 }, { 7, 2 } });
m3 = m1.postMultiply(m2);
- assertEquals(m3.rows, 1);
- assertEquals(m3.cols, 2);
- assertEquals(m3.value[0][0], 56d);
- assertEquals(m3.value[0][1], 25d);
+ assertEquals(m3.height(), 1);
+ assertEquals(m3.width(), 2);
+ assertEquals(m3.getRow(0)[0], 56d);
+ assertEquals(m3.getRow(0)[1], 25d);
/*
* and check premultiply equivalent
*/
m3 = m2.preMultiply(m1);
- assertEquals(m3.rows, 1);
- assertEquals(m3.cols, 2);
- assertEquals(m3.value[0][0], 56d);
- assertEquals(m3.value[0][1], 25d);
+ assertEquals(m3.height(), 1);
+ assertEquals(m3.width(), 2);
+ assertEquals(m3.getRow(0)[0], 56d);
+ assertEquals(m3.getRow(0)[1], 25d);
}
@Test(groups = "Functional")
}
}
Matrix m1 = new Matrix(in);
- Matrix m2 = m1.copy();
+ Matrix m2 = (Matrix) m1.copy();
assertTrue(matrixEquals(m1, m2));
}
// / origmat.print(System.out);
// System.out.println();
// System.out.println(" --- transpose matrix ---- ");
- Matrix trans = origmat.transpose();
+ MatrixI trans = origmat.transpose();
// trans.print(System.out);
// System.out.println();
// System.out.println(" --- OrigT * Orig ---- ");
- Matrix symm = trans.postMultiply(origmat);
+ MatrixI symm = trans.postMultiply(origmat);
// symm.print(System.out);
// System.out.println();
// }
// System.out.println();
}
+
+ @Test(groups = "Timing")
+ public void testSign()
+ {
+ assertEquals(Matrix.sign(-1, -2), -1d);
+ assertEquals(Matrix.sign(-1, 2), 1d);
+ assertEquals(Matrix.sign(-1, 0), 1d);
+ assertEquals(Matrix.sign(1, -2), -1d);
+ assertEquals(Matrix.sign(1, 2), 1d);
+ assertEquals(Matrix.sign(1, 0), 1d);
+ }
+
+ /**
+ * Helper method to make values for a sparse, pseudo-random symmetric matrix
+ *
+ * @param rows
+ * @param cols
+ * @param occupancy
+ * one in 'occupancy' entries will be non-zero
+ * @return
+ */
+ public double[][] getSparseValues(int rows, int cols, int occupancy)
+ {
+ Random r = new Random(1729);
+
+ /*
+ * generate whole number values between -12 and +12
+ * (to mimic score matrices used in Jalview)
+ */
+ double[][] d = new double[rows][cols];
+ int m = 0;
+ for (int i = 0; i < rows; i++)
+ {
+ if (++m % occupancy == 0)
+ {
+ d[i][i] = r.nextInt() % 13; // diagonal
+ }
+ for (int j = 0; j < i; j++)
+ {
+ if (++m % occupancy == 0)
+ {
+ d[i][j] = r.nextInt() % 13;
+ d[j][i] = d[i][j];
+ }
+ }
+ }
+ return d;
+
+ }
+
+ /**
+ * Verify that the results of method tred() are the same if the calculation is
+ * redone
+ */
+ @Test(groups = "Functional")
+ public void testTred_reproducible()
+ {
+ /*
+ * make a pseudo-random symmetric matrix as required for tred/tqli
+ */
+ int rows = 10;
+ int cols = rows;
+ double[][] d = getSparseValues(rows, cols, 3);
+
+ /*
+ * make a copy of the values so m1, m2 are not
+ * sharing arrays!
+ */
+ double[][] d1 = new double[rows][cols];
+ for (int row = 0; row < rows; row++)
+ {
+ for (int col = 0; col < cols; col++)
+ {
+ d1[row][col] = d[row][col];
+ }
+ }
+ Matrix m1 = new Matrix(d);
+ Matrix m2 = new Matrix(d1);
+ assertMatricesMatch(m1, m2); // sanity check
+ m1.tred();
+ m2.tred();
+ assertMatricesMatch(m1, m2);
+ }
+
+ private void assertMatricesMatch(MatrixI m1, MatrixI m2)
+ {
+ if (m1.height() != m2.height())
+ {
+ fail("height mismatch");
+ }
+ if (m1.width() != m2.width())
+ {
+ fail("width mismatch");
+ }
+ for (int row = 0; row < m1.height(); row++)
+ {
+ for (int col = 0; col < m1.width(); col++)
+ {
+ double v2 = m2.getValue(row, col);
+ double v1 = m1.getValue(row, col);
+ if (Math.abs(v1 - v2) > DELTA)
+ {
+ fail(String.format("At [%d, %d] %f != %f", row, col, v1, v2));
+ }
+ }
+ }
+ ArrayAsserts.assertArrayEquals(m1.getD(), m2.getD(), 0.00001d);
+ ArrayAsserts.assertArrayEquals(m1.getE(), m2.getE(), 0.00001d);
+ }
}
--- /dev/null
+package jalview.math;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+import java.util.Random;
+
+import org.testng.annotations.Test;
+import org.testng.internal.junit.ArrayAsserts;
+
+public class SparseMatrixTest
+{
+ final static double DELTA = 0.0001d;
+
+ Random r = new Random(1729);
+
+ @Test(groups = "Functional")
+ public void testConstructor()
+ {
+ MatrixI m1 = new SparseMatrix(
+ new double[][] { { 2, 0, 4 }, { 0, 6, 0 } });
+ assertEquals(m1.getValue(0, 0), 2d);
+ assertEquals(m1.getValue(0, 1), 0d);
+ assertEquals(m1.getValue(0, 2), 4d);
+ assertEquals(m1.getValue(1, 0), 0d);
+ assertEquals(m1.getValue(1, 1), 6d);
+ assertEquals(m1.getValue(1, 2), 0d);
+ }
+
+ @Test(groups = "Functional")
+ public void testTranspose()
+ {
+ MatrixI m1 = new SparseMatrix(
+ new double[][] { { 2, 0, 4 }, { 5, 6, 0 } });
+ MatrixI m2 = m1.transpose();
+ assertTrue(m2 instanceof SparseMatrix);
+ assertEquals(m2.height(), 3);
+ assertEquals(m2.width(), 2);
+ assertEquals(m2.getValue(0, 0), 2d);
+ assertEquals(m2.getValue(0, 1), 5d);
+ assertEquals(m2.getValue(1, 0), 0d);
+ assertEquals(m2.getValue(1, 1), 6d);
+ assertEquals(m2.getValue(2, 0), 4d);
+ assertEquals(m2.getValue(2, 1), 0d);
+ }
+ @Test(groups = "Functional")
+ public void testPreMultiply()
+ {
+ MatrixI m1 = new SparseMatrix(new double[][] { { 2, 3, 4 } }); // 1x3
+ MatrixI m2 = new SparseMatrix(new double[][] { { 5 }, { 6 }, { 7 } }); // 3x1
+
+ /*
+ * 1x3 times 3x1 is 1x1
+ * 2x5 + 3x6 + 4*7 = 56
+ */
+ MatrixI m3 = m2.preMultiply(m1);
+ assertFalse(m3 instanceof SparseMatrix);
+ assertEquals(m3.height(), 1);
+ assertEquals(m3.width(), 1);
+ assertEquals(m3.getValue(0, 0), 56d);
+
+ /*
+ * 3x1 times 1x3 is 3x3
+ */
+ m3 = m1.preMultiply(m2);
+ assertEquals(m3.height(), 3);
+ assertEquals(m3.width(), 3);
+ assertEquals(m3.getValue(0, 0), 10d);
+ assertEquals(m3.getValue(0, 1), 15d);
+ assertEquals(m3.getValue(0, 2), 20d);
+ assertEquals(m3.getValue(1, 0), 12d);
+ assertEquals(m3.getValue(1, 1), 18d);
+ assertEquals(m3.getValue(1, 2), 24d);
+ assertEquals(m3.getValue(2, 0), 14d);
+ assertEquals(m3.getValue(2, 1), 21d);
+ assertEquals(m3.getValue(2, 2), 28d);
+ }
+
+ @Test(
+ groups = "Functional",
+ expectedExceptions = { IllegalArgumentException.class })
+ public void testPreMultiply_tooManyColumns()
+ {
+ Matrix m1 = new SparseMatrix(
+ new double[][] { { 2, 3, 4 }, { 3, 4, 5 } }); // 2x3
+
+ /*
+ * 2x3 times 2x3 invalid operation -
+ * multiplier has more columns than multiplicand has rows
+ */
+ m1.preMultiply(m1);
+ fail("Expected exception");
+ }
+
+ @Test(
+ groups = "Functional",
+ expectedExceptions = { IllegalArgumentException.class })
+ public void testPreMultiply_tooFewColumns()
+ {
+ Matrix m1 = new SparseMatrix(
+ new double[][] { { 2, 3, 4 }, { 3, 4, 5 } }); // 2x3
+
+ /*
+ * 3x2 times 3x2 invalid operation -
+ * multiplier has more columns than multiplicand has row
+ */
+ m1.preMultiply(m1);
+ fail("Expected exception");
+ }
+
+ @Test(groups = "Functional")
+ public void testPostMultiply()
+ {
+ /*
+ * Square matrices
+ * (2 3) . (10 100)
+ * (4 5) (1000 10000)
+ * =
+ * (3020 30200)
+ * (5040 50400)
+ */
+ MatrixI m1 = new SparseMatrix(new double[][] { { 2, 3 }, { 4, 5 } });
+ MatrixI m2 = new SparseMatrix(new double[][] { { 10, 100 },
+ { 1000, 10000 } });
+ MatrixI m3 = m1.postMultiply(m2);
+ assertEquals(m3.getValue(0, 0), 3020d);
+ assertEquals(m3.getValue(0, 1), 30200d);
+ assertEquals(m3.getValue(1, 0), 5040d);
+ assertEquals(m3.getValue(1, 1), 50400d);
+
+ /*
+ * also check m2.preMultiply(m1) - should be same as m1.postMultiply(m2)
+ */
+ MatrixI m4 = m2.preMultiply(m1);
+ assertMatricesMatch(m3, m4, 0.00001d);
+
+ /*
+ * m1 has more rows than columns
+ * (2).(10 100 1000) = (20 200 2000)
+ * (3) (30 300 3000)
+ */
+ m1 = new SparseMatrix(new double[][] { { 2 }, { 3 } });
+ m2 = new SparseMatrix(new double[][] { { 10, 100, 1000 } });
+ m3 = m1.postMultiply(m2);
+ assertEquals(m3.height(), 2);
+ assertEquals(m3.width(), 3);
+ assertEquals(m3.getValue(0, 0), 20d);
+ assertEquals(m3.getValue(0, 1), 200d);
+ assertEquals(m3.getValue(0, 2), 2000d);
+ assertEquals(m3.getValue(1, 0), 30d);
+ assertEquals(m3.getValue(1, 1), 300d);
+ assertEquals(m3.getValue(1, 2), 3000d);
+
+ m4 = m2.preMultiply(m1);
+ assertMatricesMatch(m3, m4, 0.00001d);
+
+ /*
+ * m1 has more columns than rows
+ * (2 3 4) . (5 4) = (56 25)
+ * (6 3)
+ * (7 2)
+ * [0, 0] = 2*5 + 3*6 + 4*7 = 56
+ * [0, 1] = 2*4 + 3*3 + 4*2 = 25
+ */
+ m1 = new SparseMatrix(new double[][] { { 2, 3, 4 } });
+ m2 = new SparseMatrix(new double[][] { { 5, 4 }, { 6, 3 }, { 7, 2 } });
+ m3 = m1.postMultiply(m2);
+ assertEquals(m3.height(), 1);
+ assertEquals(m3.width(), 2);
+ assertEquals(m3.getValue(0, 0), 56d);
+ assertEquals(m3.getValue(0, 1), 25d);
+
+ /*
+ * and check premultiply equivalent
+ */
+ m4 = m2.preMultiply(m1);
+ assertMatricesMatch(m3, m4, 0.00001d);
+ }
+
+ @Test(groups = "Timing")
+ public void testSign()
+ {
+ assertEquals(Matrix.sign(-1, -2), -1d);
+ assertEquals(Matrix.sign(-1, 2), 1d);
+ assertEquals(Matrix.sign(-1, 0), 1d);
+ assertEquals(Matrix.sign(1, -2), -1d);
+ assertEquals(Matrix.sign(1, 2), 1d);
+ assertEquals(Matrix.sign(1, 0), 1d);
+ }
+
+ /**
+ * Verify that the results of method tred() are the same for SparseMatrix as
+ * they are for Matrix (i.e. a regression test rather than an absolute test of
+ * correctness of results)
+ */
+ @Test(groups = "Functional")
+ public void testTred_matchesMatrix()
+ {
+ /*
+ * make a pseudo-random symmetric matrix as required for tred/tqli
+ */
+ int rows = 10;
+ int cols = rows;
+ double[][] d = getSparseValues(rows, cols, 3);
+
+ /*
+ * make a copy of the values so m1, m2 are not
+ * sharing arrays!
+ */
+ double[][] d1 = new double[rows][cols];
+ for (int row = 0; row < rows; row++)
+ {
+ for (int col = 0; col < cols; col++)
+ {
+ d1[row][col] = d[row][col];
+ }
+ }
+ Matrix m1 = new Matrix(d);
+ Matrix m2 = new SparseMatrix(d1);
+ assertMatricesMatch(m1, m2, 0.00001d); // sanity check
+ m1.tred();
+ m2.tred();
+ assertMatricesMatch(m1, m2, 0.00001d);
+ }
+
+ private void assertMatricesMatch(MatrixI m1, MatrixI m2, double delta)
+ {
+ if (m1.height() != m2.height())
+ {
+ fail("height mismatch");
+ }
+ if (m1.width() != m2.width())
+ {
+ fail("width mismatch");
+ }
+ for (int row = 0; row < m1.height(); row++)
+ {
+ for (int col = 0; col < m1.width(); col++)
+ {
+ double v2 = m2.getValue(row, col);
+ double v1 = m1.getValue(row, col);
+ if (Math.abs(v1 - v2) > DELTA)
+ {
+ fail(String.format("At [%d, %d] %f != %f", row, col, v1, v2));
+ }
+ }
+ }
+ ArrayAsserts.assertArrayEquals(m1.getD(), m2.getD(), delta);
+ ArrayAsserts.assertArrayEquals(m1.getE(), m2.getE(), 0.00001d);
+ }
+
+ @Test
+ public void testGetValue()
+ {
+ double[][] d = new double[][] { { 0, 0, 1, 0, 0 }, { 2, 3, 0, 0, 0 },
+ { 4, 0, 0, 0, 5 } };
+ MatrixI m = new SparseMatrix(d);
+ for (int row = 0; row < 3; row++)
+ {
+ for (int col = 0; col < 5; col++)
+ {
+ assertEquals(m.getValue(row, col), d[row][col],
+ String.format("At [%d, %d]", row, col));
+ }
+ }
+ }
+
+ /**
+ * Verify that the results of method tqli() are the same for SparseMatrix as
+ * they are for Matrix (i.e. a regression test rather than an absolute test of
+ * correctness of results)
+ *
+ * @throws Exception
+ */
+ @Test(groups = "Functional")
+ public void testTqli_matchesMatrix() throws Exception
+ {
+ /*
+ * make a pseudo-random symmetric matrix as required for tred
+ */
+ int rows = 6;
+ int cols = rows;
+ double[][] d = getSparseValues(rows, cols, 3);
+
+ /*
+ * make a copy of the values so m1, m2 are not
+ * sharing arrays!
+ */
+ double[][] d1 = new double[rows][cols];
+ for (int row = 0; row < rows; row++)
+ {
+ for (int col = 0; col < cols; col++)
+ {
+ d1[row][col] = d[row][col];
+ }
+ }
+ Matrix m1 = new Matrix(d);
+ Matrix m2 = new SparseMatrix(d1);
+
+ // have to do tred() before doing tqli()
+ m1.tred();
+ m2.tred();
+ assertMatricesMatch(m1, m2, 0.00001d);
+
+ m1.tqli();
+ m2.tqli();
+ assertMatricesMatch(m1, m2, 0.00001d);
+ }
+
+ /**
+ * Helper method to make values for a sparse, pseudo-random symmetric matrix
+ *
+ * @param rows
+ * @param cols
+ * @param occupancy
+ * one in 'occupancy' entries will be non-zero
+ * @return
+ */
+ public double[][] getSparseValues(int rows, int cols, int occupancy)
+ {
+ /*
+ * generate whole number values between -12 and +12
+ * (to mimic score matrices used in Jalview)
+ */
+ double[][] d = new double[rows][cols];
+ int m = 0;
+ for (int i = 0; i < rows; i++)
+ {
+ if (++m % occupancy == 0)
+ {
+ d[i][i] = r.nextInt() % 13; // diagonal
+ }
+ for (int j = 0; j < i; j++)
+ {
+ if (++m % occupancy == 0)
+ {
+ d[i][j] = r.nextInt() % 13;
+ d[j][i] = d[i][j];
+ }
+ }
+ }
+ return d;
+
+ }
+
+ /**
+ * Test that verifies that the result of preMultiply is a SparseMatrix if more
+ * than 80% zeroes, else a Matrix
+ */
+ @Test(groups = "Functional")
+ public void testPreMultiply_sparseProduct()
+ {
+ MatrixI m1 = new SparseMatrix(new double[][] { { 1 }, { 0 }, { 0 },
+ { 0 }, { 0 } }); // 5x1
+ MatrixI m2 = new SparseMatrix(new double[][] { { 1, 1, 1, 1 } }); // 1x4
+
+ /*
+ * m1.m2 makes a row of 4 1's, and 4 rows of zeros
+ * 20% non-zero so not 'sparse'
+ */
+ MatrixI m3 = m2.preMultiply(m1);
+ assertFalse(m3 instanceof SparseMatrix);
+
+ /*
+ * replace a 1 with a 0 in the product:
+ * it is now > 80% zero so 'sparse'
+ */
+ m2 = new SparseMatrix(new double[][] { { 1, 1, 1, 0 } });
+ m3 = m2.preMultiply(m1);
+ assertTrue(m3 instanceof SparseMatrix);
+ }
+
+ @Test(groups = "Functional")
+ public void testFillRatio()
+ {
+ SparseMatrix m1 = new SparseMatrix(new double[][] { { 2, 0, 4, 1, 0 },
+ { 0, 6, 0, 0, 0 } });
+ assertEquals(m1.getFillRatio(), 0.4f);
+ }
+
+ /**
+ * Verify that the results of method tred() are the same if the calculation is
+ * redone
+ */
+ @Test(groups = "Functional")
+ public void testTred_reproducible()
+ {
+ /*
+ * make a pseudo-random symmetric matrix as required for tred/tqli
+ */
+ int rows = 10;
+ int cols = rows;
+ double[][] d = getSparseValues(rows, cols, 3);
+
+ /*
+ * make a copy of the values so m1, m2 are not
+ * sharing arrays!
+ */
+ double[][] d1 = new double[rows][cols];
+ for (int row = 0; row < rows; row++)
+ {
+ for (int col = 0; col < cols; col++)
+ {
+ d1[row][col] = d[row][col];
+ }
+ }
+ Matrix m1 = new SparseMatrix(d);
+ Matrix m2 = new SparseMatrix(d1);
+ assertMatricesMatch(m1, m2, 1.0e16); // sanity check
+ m1.tred();
+ m2.tred();
+ assertMatricesMatch(m1, m2, 0.00001d);
+ }
+}
\ No newline at end of file
--- /dev/null
+package jalview.renderer.seqfeatures;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import jalview.api.FeatureColourI;
+import jalview.datamodel.SequenceFeature;
+import jalview.datamodel.SequenceI;
+import jalview.gui.AlignFrame;
+import jalview.gui.AlignViewport;
+import jalview.gui.FeatureRenderer;
+import jalview.io.DataSourceType;
+import jalview.io.FileLoader;
+import jalview.schemes.FeatureColour;
+
+import java.awt.Color;
+
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+
+/**
+ * Unit tests for feature colour determination, including but not limited to
+ * <ul>
+ * <li>gap position</li>
+ * <li>no features present</li>
+ * <li>features present but show features turned off</li>
+ * <li>features displayed but selected feature turned off</li>
+ * <li>features displayed but feature group turned off</li>
+ * <li>feature displayed but none at the specified position</li>
+ * <li>multiple features at position, with no transparency</li>
+ * <li>multiple features at position, with transparency</li>
+ * <li>score graduated feature colour</li>
+ * <li>contact feature start at the selected position</li>
+ * <li>contact feature end at the selected position</li>
+ * <li>contact feature straddling the selected position (not shown)</li>
+ * </ul>
+ */
+public class FeatureColourFinderTest
+{
+ private AlignViewport av;
+
+ private SequenceI seq;
+
+ private FeatureColourFinder finder;
+
+ private AlignFrame af;
+
+ private FeatureRenderer fr;
+
+ @BeforeTest(alwaysRun = true)
+ public void setUp()
+ {
+ // aligned column 8 is sequence position 6
+ String s = ">s1\nABCDE---FGHIJKLMNOPQRSTUVWXYZ\n";
+ af = new FileLoader().LoadFileWaitTillLoaded(s,
+ DataSourceType.PASTE);
+ av = af.getViewport();
+ seq = av.getAlignment().getSequenceAt(0);
+ fr = af.getFeatureRenderer();
+ finder = new FeatureColourFinder(fr);
+ }
+
+ /**
+ * Clear down any sequence features before each test (not as easy as it
+ * sounds...)
+ */
+ @BeforeMethod(alwaysRun = true)
+ public void setUpBeforeTest()
+ {
+ SequenceFeature[] sfs = seq.getSequenceFeatures();
+ if (sfs != null)
+ {
+ for (SequenceFeature sf : sfs)
+ {
+ seq.deleteFeature(sf);
+ }
+ }
+ fr.findAllFeatures(true);
+
+ /*
+ * reset all feature groups to visible
+ */
+ for (String group : fr.getGroups(false))
+ {
+ fr.setGroupVisibility(group, true);
+ }
+
+ fr.clearRenderOrder();
+ av.setShowSequenceFeatures(true);
+ }
+
+ @Test(groups = "Functional")
+ public void testFindFeatureColour_noFeatures()
+ {
+ av.setShowSequenceFeatures(false);
+ Color c = finder.findFeatureColour(Color.blue, seq, 10);
+ assertEquals(c, Color.blue);
+
+ av.setShowSequenceFeatures(true);
+ c = finder.findFeatureColour(Color.blue, seq, 10);
+ assertEquals(c, Color.blue);
+ }
+
+ @Test(groups = "Functional")
+ public void testFindFeatureColour_noFeaturesShown()
+ {
+ seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
+ Float.NaN, "MetalGroup"));
+ fr.featuresAdded();
+ av.setShowSequenceFeatures(false);
+ Color c = finder.findFeatureColour(Color.blue, seq, 10);
+ assertEquals(c, Color.blue);
+ }
+
+ @Test(groups = "Functional")
+ public void testFindFeatureColour_singleFeatureAtPosition()
+ {
+ seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
+ Float.NaN, "MetalGroup"));
+ fr.setColour("Metal", new FeatureColour(Color.red));
+ fr.featuresAdded();
+ av.setShowSequenceFeatures(true);
+ Color c = finder.findFeatureColour(Color.blue, seq, 10);
+ assertEquals(c, Color.red);
+ }
+
+ @Test(groups = "Functional")
+ public void testFindFeatureColour_gapPosition()
+ {
+ seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12, 0f,
+ null));
+ fr.setColour("Metal", new FeatureColour(Color.red));
+ fr.featuresAdded();
+ av.setShowSequenceFeatures(true);
+ Color c = finder.findFeatureColour(null, seq, 6);
+ assertEquals(c, Color.white);
+ }
+
+ @Test(groups = "Functional")
+ public void testFindFeatureColour_multipleFeaturesAtPositionNoTransparency()
+ {
+ /*
+ * featuresAdded -> FeatureRendererModel.updateRenderOrder which adds any
+ * new features 'on top' (but reverses the order of any added features)
+ */
+ seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
+ Float.NaN, "MetalGroup"));
+ FeatureColour red = new FeatureColour(Color.red);
+ fr.setColour("Metal", red);
+ fr.featuresAdded();
+ seq.addSequenceFeature(new SequenceFeature("Domain", "Domain", 4, 15,
+ Float.NaN, "DomainGroup"));
+ FeatureColour green = new FeatureColour(Color.green);
+ fr.setColour("Domain", green);
+ fr.featuresAdded();
+ av.setShowSequenceFeatures(true);
+
+ /*
+ * expect Domain (green) to be rendered above Metal (red)
+ */
+ Color c = finder.findFeatureColour(Color.blue, seq, 10);
+ assertEquals(c, Color.green);
+
+ /*
+ * now promote Metal above Domain
+ * - currently no way other than mimicking reordering of
+ * table in Feature Settings
+ */
+ Object[][] data = new Object[2][];
+ data[0] = new Object[] { "Metal", red, true };
+ data[1] = new Object[] { "Domain", green, true };
+ fr.setFeaturePriority(data);
+ c = finder.findFeatureColour(Color.blue, seq, 10);
+ assertEquals(c, Color.red);
+
+ /*
+ * ..and turn off display of Metal
+ */
+ data[0][2] = false;
+ fr.setFeaturePriority(data);
+ c = finder.findFeatureColour(Color.blue, seq, 10);
+ assertEquals(c, Color.green);
+ }
+
+ @Test(groups = "Functional")
+ public void testFindFeatureColour_singleFeatureNotAtPosition()
+ {
+ seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 8, 12,
+ Float.NaN, "MetalGroup"));
+ fr.setColour("Metal", new FeatureColour(Color.red));
+ fr.featuresAdded();
+ av.setShowSequenceFeatures(true);
+ // column 2 = sequence position 3
+ Color c = finder.findFeatureColour(Color.blue, seq, 2);
+ assertEquals(c, Color.blue);
+ }
+
+ @Test(groups = "Functional")
+ public void testFindFeatureColour_featureTypeNotDisplayed()
+ {
+ seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
+ Float.NaN, "MetalGroup"));
+ FeatureColour red = new FeatureColour(Color.red);
+ fr.setColour("Metal", red);
+ fr.featuresAdded();
+ av.setShowSequenceFeatures(true);
+ Color c = finder.findFeatureColour(Color.blue, seq, 10);
+ assertEquals(c, Color.red);
+
+ /*
+ * turn off display of Metal - is this the easiest way to do it??
+ */
+ Object[][] data = new Object[1][];
+ data[0] = new Object[] { "Metal", red, false };
+ fr.setFeaturePriority(data);
+ c = finder.findFeatureColour(Color.blue, seq, 10);
+ assertEquals(c, Color.blue);
+
+ /*
+ * turn display of Metal back on
+ */
+ data[0] = new Object[] { "Metal", red, true };
+ fr.setFeaturePriority(data);
+ c = finder.findFeatureColour(Color.blue, seq, 10);
+ assertEquals(c, Color.red);
+ }
+
+ @Test(groups = "Functional")
+ public void testFindFeatureColour_featureGroupNotDisplayed()
+ {
+ seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
+ Float.NaN, "MetalGroup"));
+ FeatureColour red = new FeatureColour(Color.red);
+ fr.setColour("Metal", red);
+ fr.featuresAdded();
+ av.setShowSequenceFeatures(true);
+ Color c = finder.findFeatureColour(Color.blue, seq, 10);
+ assertEquals(c, Color.red);
+
+ /*
+ * turn off display of MetalGroup
+ */
+ fr.setGroupVisibility("MetalGroup", false);
+ c = finder.findFeatureColour(Color.blue, seq, 10);
+ assertEquals(c, Color.blue);
+
+ /*
+ * turn display of MetalGroup back on
+ */
+ fr.setGroupVisibility("MetalGroup", true);
+ c = finder.findFeatureColour(Color.blue, seq, 10);
+ assertEquals(c, Color.red);
+ }
+
+ @Test(groups = "Functional")
+ public void testFindFeatureColour_contactFeature()
+ {
+ /*
+ * currently contact feature == type "Disulphide Bond" or "Disulfide Bond" !!
+ */
+ seq.addSequenceFeature(new SequenceFeature("Disulphide Bond",
+ "Contact", 2, 12, Float.NaN, "Disulphide"));
+ fr.setColour("Disulphide Bond", new FeatureColour(Color.red));
+ fr.featuresAdded();
+ av.setShowSequenceFeatures(true);
+
+ /*
+ * Contact positions are residues 2 and 12
+ * which are columns 1 and 14
+ * positions in between don't count for a contact feature!
+ */
+ Color c = finder.findFeatureColour(Color.blue, seq, 10);
+ assertEquals(c, Color.blue);
+ c = finder.findFeatureColour(Color.blue, seq, 8);
+ assertEquals(c, Color.blue);
+ c = finder.findFeatureColour(Color.blue, seq, 1);
+ assertEquals(c, Color.red);
+ c = finder.findFeatureColour(Color.blue, seq, 14);
+ assertEquals(c, Color.red);
+ }
+
+ @Test(groups = "Functional")
+ public void testFindFeatureColour_graduatedFeatureColour()
+ {
+ seq.addSequenceFeature(new SequenceFeature("kd", "hydrophobicity", 2,
+ 2, 0f, "KdGroup"));
+ seq.addSequenceFeature(new SequenceFeature("kd", "hydrophobicity", 4,
+ 4, 5f, "KdGroup"));
+ seq.addSequenceFeature(new SequenceFeature("kd", "hydrophobicity", 7,
+ 7, 10f, "KdGroup"));
+
+ /*
+ * graduated colour from 0 to 10
+ */
+ Color min = new Color(100, 50, 150);
+ Color max = new Color(200, 0, 100);
+ FeatureColourI fc = new FeatureColour(min, max, 0, 10);
+ fr.setColour("kd", fc);
+ fr.featuresAdded();
+ av.setShowSequenceFeatures(true);
+
+ /*
+ * position 2, column 1, score 0 - minimum colour in range
+ */
+ Color c = finder.findFeatureColour(Color.blue, seq, 1);
+ assertEquals(c, min);
+
+ /*
+ * position 7, column 9, score 10 - maximum colour in range
+ */
+ c = finder.findFeatureColour(Color.blue, seq, 9);
+ assertEquals(c, max);
+
+ /*
+ * position 4, column 3, score 5 - half way from min to max
+ */
+ c = finder.findFeatureColour(Color.blue, seq, 3);
+ assertEquals(c, new Color(150, 25, 125));
+ }
+
+ @Test(groups = "Functional")
+ public void testFindFeatureColour_transparencySingleFeature()
+ {
+ seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
+ Float.NaN, "MetalGroup"));
+ FeatureColour red = new FeatureColour(Color.red);
+ fr.setColour("Metal", red);
+ fr.featuresAdded();
+ av.setShowSequenceFeatures(true);
+
+ /*
+ * the FeatureSettings transparency slider has range 0-70 which
+ * corresponds to a transparency value of 1 - 0.3
+ * A value of 0.4 gives a combination of
+ * 0.4 * red(255, 0, 0) + 0.6 * cyan(0, 255, 255) = (102, 153, 153)
+ */
+ fr.setTransparency(0.4f);
+ Color c = finder.findFeatureColour(Color.cyan, seq, 10);
+ assertEquals(c, new Color(102, 153, 153));
+ }
+
+ @Test(groups = "Functional")
+ public void testFindFeatureColour_transparencyTwoFeatures()
+ {
+ seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
+ Float.NaN, "MetalGroup"));
+ FeatureColour red = new FeatureColour(Color.red);
+ fr.setColour("Metal", red);
+ fr.featuresAdded();
+ seq.addSequenceFeature(new SequenceFeature("Domain", "Domain", 4, 15,
+ Float.NaN, "DomainGroup"));
+ FeatureColour green = new FeatureColour(Color.green);
+ fr.setColour("Domain", green);
+ fr.featuresAdded();
+ av.setShowSequenceFeatures(true);
+
+ /*
+ * Domain (green) rendered above Metal (red) above background (cyan)
+ * 1) 0.6 * red(255, 0, 0) + 0.4 * cyan(0, 255, 255) = (153, 102, 102)
+ * 2) 0.6* green(0, 255, 0) + 0.4 * (153, 102, 102) = (61, 194, 41) rounded
+ */
+ fr.setTransparency(0.6f);
+ Color c = finder.findFeatureColour(Color.cyan, seq, 10);
+ assertEquals(c, new Color(61, 194, 41));
+
+ /*
+ * now promote Metal above Domain
+ * - currently no way other than mimicking reordering of
+ * table in Feature Settings
+ * Metal (red) rendered above Domain (green) above background (cyan)
+ * 1) 0.6 * green(0, 255, 0) + 0.4 * cyan(0, 255, 255) = (0, 255, 102)
+ * 2) 0.6* red(255, 0, 0) + 0.4 * (0, 255, 102) = (153, 102, 41) rounded
+ */
+ Object[][] data = new Object[2][];
+ data[0] = new Object[] { "Metal", red, true };
+ data[1] = new Object[] { "Domain", green, true };
+ fr.setFeaturePriority(data);
+ c = finder.findFeatureColour(Color.cyan, seq, 10);
+ assertEquals(c, new Color(153, 102, 41));
+
+ /*
+ * ..and turn off display of Metal
+ * Domain (green) above background (pink)
+ * 0.6 * green(0, 255, 0) + 0.4 * pink(255, 175, 175) = (102, 223, 70)
+ */
+ data[0][2] = false;
+ fr.setFeaturePriority(data);
+ c = finder.findFeatureColour(Color.pink, seq, 10);
+ assertEquals(c, new Color(102, 223, 70));
+ }
+
+ @Test(groups = "Functional")
+ public void testNoFeaturesDisplayed()
+ {
+ /*
+ * no features on alignment to render
+ */
+ assertTrue(finder.noFeaturesDisplayed());
+
+ /*
+ * add a feature
+ * it will be automatically set visible but we leave
+ * the viewport configured not to show features
+ */
+ av.setShowSequenceFeatures(false);
+ seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
+ Float.NaN, "MetalGroup"));
+ FeatureColour red = new FeatureColour(Color.red);
+ fr.setColour("Metal", red);
+ fr.featuresAdded();
+ assertTrue(finder.noFeaturesDisplayed());
+
+ /*
+ * turn on feature display
+ */
+ av.setShowSequenceFeatures(true);
+ assertFalse(finder.noFeaturesDisplayed());
+
+ /*
+ * turn off display of Metal
+ */
+ Object[][] data = new Object[1][];
+ data[0] = new Object[] { "Metal", red, false };
+ fr.setFeaturePriority(data);
+ assertTrue(finder.noFeaturesDisplayed());
+
+ /*
+ * turn display of Metal back on
+ */
+ fr.setVisible("Metal");
+ assertFalse(finder.noFeaturesDisplayed());
+
+ /*
+ * turn off MetalGroup - has no effect here since the group of a
+ * sequence feature instance is independent of its type
+ */
+ fr.setGroupVisibility("MetalGroup", false);
+ assertFalse(finder.noFeaturesDisplayed());
+
+ /*
+ * a finder with no feature renderer
+ */
+ FeatureColourFinder finder2 = new FeatureColourFinder(null);
+ assertTrue(finder2.noFeaturesDisplayed());
+ }
+}
* set and check Taylor colours
*/
af.changeColour_actionPerformed(JalviewColourScheme.Taylor.toString());
- Color taylor1 = sr.getResidueBoxColour(seq, 88); // E 255,0,102
- Color taylor2 = sr.getResidueBoxColour(seq, 89); // A 204,255,0
- Color taylor3 = sr.getResidueBoxColour(seq, 90); // G 255,153,0
+ Color taylor1 = sr.getResidueColour(seq, 88, null); // E 255,0,102
+ Color taylor2 = sr.getResidueColour(seq, 89, null); // A 204,255,0
+ Color taylor3 = sr.getResidueColour(seq, 90, null); // G 255,153,0
assertEquals(taylor1, new Color(255, 0, 102));
assertEquals(taylor2, new Color(204, 255, 0));
assertEquals(taylor3, new Color(255, 153, 0));
* set and check Zappo colours
*/
af.changeColour_actionPerformed(JalviewColourScheme.Zappo.toString());
- Color zappo1 = sr.getResidueBoxColour(seq, 88); // E red
- Color zappo2 = sr.getResidueBoxColour(seq, 89); // A pink
- Color zappo3 = sr.getResidueBoxColour(seq, 90); // G magenta
+ Color zappo1 = sr.getResidueColour(seq, 88, null); // E red
+ Color zappo2 = sr.getResidueColour(seq, 89, null); // A pink
+ Color zappo3 = sr.getResidueColour(seq, 90, null); // G magenta
assertEquals(zappo1, Color.red);
assertEquals(zappo2, Color.pink);
assertEquals(zappo3, Color.magenta);
* set 'stripy' colours - odd columns are Taylor and even are Zappo
*/
af.changeColour_actionPerformed("stripy");
- Color stripy1 = sr.getResidueBoxColour(seq, 88);
- Color stripy2 = sr.getResidueBoxColour(seq, 89);
- Color stripy3 = sr.getResidueBoxColour(seq, 90);
+ Color stripy1 = sr.getResidueColour(seq, 88, null);
+ Color stripy2 = sr.getResidueColour(seq, 89, null);
+ Color stripy3 = sr.getResidueColour(seq, 90, null);
assertEquals(stripy1, zappo1);
assertEquals(stripy2, taylor2);
assertEquals(stripy3, zappo3);
* set and check Clustal colours
*/
af.changeColour_actionPerformed(JalviewColourScheme.Clustal.toString());
- Color clustal1 = sr.getResidueBoxColour(seq, 88);
- Color clustal2 = sr.getResidueBoxColour(seq, 89);
- Color clustal3 = sr.getResidueBoxColour(seq, 90);
+ Color clustal1 = sr.getResidueColour(seq, 88, null);
+ Color clustal2 = sr.getResidueColour(seq, 89, null);
+ Color clustal3 = sr.getResidueColour(seq, 90, null);
assertEquals(clustal1, ClustalColour.MAGENTA.colour);
assertEquals(clustal2, ClustalColour.BLUE.colour);
assertEquals(clustal3, ClustalColour.ORANGE.colour);
* set 'MyClustal' colours - uses AWT colour equivalents
*/
af.changeColour_actionPerformed("MyClustal");
- Color myclustal1 = sr.getResidueBoxColour(seq, 88);
- Color myclustal2 = sr.getResidueBoxColour(seq, 89);
- Color myclustal3 = sr.getResidueBoxColour(seq, 90);
+ Color myclustal1 = sr.getResidueColour(seq, 88, null);
+ Color myclustal2 = sr.getResidueColour(seq, 89, null);
+ Color myclustal3 = sr.getResidueColour(seq, 90, null);
assertEquals(myclustal1, Color.MAGENTA);
assertEquals(myclustal2, Color.BLUE);
assertEquals(myclustal3, Color.ORANGE);
import java.util.Map;
import org.testng.annotations.BeforeClass;
-import org.testng.annotations.Test;
public class ScoreMatrixPrinter
{
JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
}
- @Test(groups = { "Functional" })
public void printAllMatrices()
{
for (Map.Entry<String, ScoreModelI> sm : ResidueProperties.scoreMatrices
}
}
- @Test(groups = { "Functional" })
public void printHTMLMatrices()
{
for (Map.Entry<String, ScoreModelI> _sm : ResidueProperties.scoreMatrices
--- /dev/null
+package jalview.schemes;
+
+import static org.testng.Assert.assertEquals;
+
+import jalview.math.MatrixI;
+
+import org.testng.annotations.Test;
+
+public class ScoreMatrixTest
+{
+ @Test(groups = "Functional")
+ public void testSymmetric()
+ {
+ verifySymmetric(ResidueProperties.getScoreMatrix("BLOSUM62"));
+ verifySymmetric(ResidueProperties.getScoreMatrix("PAM250"));
+ verifySymmetric(ResidueProperties.getScoreMatrix("DNA"));
+ }
+
+ private void verifySymmetric(ScoreMatrix sm)
+ {
+ int[][] m = sm.getMatrix();
+ int rows = m.length;
+ for (int row = 0; row < rows; row++)
+ {
+ assertEquals(m[row].length, rows);
+ for (int col = 0; col < rows; col++)
+ {
+ assertEquals(m[row][col], m[col][row], String.format("%s [%s, %s]",
+ sm.getName(), ResidueProperties.aa[row],
+ ResidueProperties.aa[col]));
+ }
+ }
+
+ /*
+ * also check the score matrix is sized for
+ * the number of symbols scored, plus gap
+ */
+ assertEquals(rows, (sm.isDNA() ? ResidueProperties.maxNucleotideIndex
+ : ResidueProperties.maxProteinIndex) + 1);
+ }
+
+ /**
+ * A test that just asserts the expected values in the Blosum62 score matrix
+ */
+ @Test(groups = "Functional")
+ public void testBlosum62_values()
+ {
+ ScoreMatrix sm = ResidueProperties.getScoreMatrix("BLOSUM62");
+
+ /*
+ * verify expected scores against ARNDCQEGHILKMFPSTWYVBZX
+ * scraped from https://www.ncbi.nlm.nih.gov/Class/FieldGuide/BLOSUM62.txt
+ */
+ verifyValues(sm, 'A', new int[] { 4, -1, -2, -2, 0, -1, -1, 0, -2, -1,
+ -1, -1, -1, -2, -1, 1, 0, -3, -2, 0, -2, -1, 0 });
+ verifyValues(sm, 'R', new int[] { -1, 5, 0, -2, -3, 1, 0, -2, 0, -3,
+ -2, 2, -1, -3, -2, -1, -1, -3, -2, -3, -1, 0, -1 });
+ verifyValues(sm, 'N', new int[] { -2, 0, 6, 1, -3, 0, 0, 0, 1, -3, -3,
+ 0, -2, -3, -2, 1, 0, -4, -2, -3, 3, 0, -1 });
+ verifyValues(sm, 'D', new int[] { -2, -2, 1, 6, -3, 0, 2, -1, -1, -3,
+ -4, -1, -3, -3, -1, 0, -1, -4, -3, -3, 4, 1, -1 });
+ verifyValues(sm, 'C', new int[] { 0, -3, -3, -3, 9, -3, -4, -3, -3, -1,
+ -1, -3, -1, -2, -3, -1, -1, -2, -2, -1, -3, -3, -2 });
+ verifyValues(sm, 'Q', new int[] { -1, 1, 0, 0, -3, 5, 2, -2, 0, -3, -2,
+ 1, 0, -3, -1, 0, -1, -2, -1, -2, 0, 3, -1 });
+ verifyValues(sm, 'E', new int[] { -1, 0, 0, 2, -4, 2, 5, -2, 0, -3, -3,
+ 1, -2, -3, -1, 0, -1, -3, -2, -2, 1, 4, -1 });
+ verifyValues(sm, 'G', new int[] { 0, -2, 0, -1, -3, -2, -2, 6, -2, -4,
+ -4, -2, -3, -3, -2, 0, -2, -2, -3, -3, -1, -2, -1 });
+ verifyValues(sm, 'H', new int[] { -2, 0, 1, -1, -3, 0, 0, -2, 8, -3,
+ -3, -1, -2, -1, -2, -1, -2, -2, 2, -3, 0, 0, -1 });
+ verifyValues(sm, 'I', new int[] { -1, -3, -3, -3, -1, -3, -3, -4, -3,
+ 4, 2, -3, 1, 0, -3, -2, -1, -3, -1, 3, -3, -3, -1 });
+ verifyValues(sm, 'L', new int[] { -1, -2, -3, -4, -1, -2, -3, -4, -3,
+ 2, 4, -2, 2, 0, -3, -2, -1, -2, -1, 1, -4, -3, -1 });
+ verifyValues(sm, 'K', new int[] { -1, 2, 0, -1, -3, 1, 1, -2, -1, -3,
+ -2, 5, -1, -3, -1, 0, -1, -3, -2, -2, 0, 1, -1 });
+ verifyValues(sm, 'M', new int[] { -1, -1, -2, -3, -1, 0, -2, -3, -2, 1,
+ 2, -1, 5, 0, -2, -1, -1, -1, -1, 1, -3, -1, -1 });
+ verifyValues(sm, 'F', new int[] { -2, -3, -3, -3, -2, -3, -3, -3, -1,
+ 0, 0, -3, 0, 6, -4, -2, -2, 1, 3, -1, -3, -3, -1 });
+ verifyValues(sm, 'P', new int[] { -1, -2, -2, -1, -3, -1, -1, -2, -2,
+ -3, -3, -1, -2, -4, 7, -1, -1, -4, -3, -2, -2, -1, -2 });
+ verifyValues(sm, 'S', new int[] { 1, -1, 1, 0, -1, 0, 0, 0, -1, -2, -2,
+ 0, -1, -2, -1, 4, 1, -3, -2, -2, 0, 0, 0 });
+ verifyValues(sm, 'T', new int[] { 0, -1, 0, -1, -1, -1, -1, -2, -2, -1,
+ -1, -1, -1, -2, -1, 1, 5, -2, -2, 0, -1, -1, 0 });
+ verifyValues(sm, 'W', new int[] { -3, -3, -4, -4, -2, -2, -3, -2, -2,
+ -3, -2, -3, -1, 1, -4, -3, -2, 11, 2, -3, -4, -3, -2 });
+ verifyValues(sm, 'Y', new int[] { -2, -2, -2, -3, -2, -1, -2, -3, 2,
+ -1, -1, -2, -1, 3, -3, -2, -2, 2, 7, -1, -3, -2, -1 });
+ verifyValues(sm, 'V', new int[] { 0, -3, -3, -3, -1, -2, -2, -3, -3, 3,
+ 1, -2, 1, -1, -2, -2, 0, -3, -1, 4, -3, -2, -1 });
+ verifyValues(sm, 'B', new int[] { -2, -1, 3, 4, -3, 0, 1, -1, 0, -3,
+ -4, 0, -3, -3, -2, 0, -1, -4, -3, -3, 4, 1, -1 });
+ verifyValues(sm, 'Z', new int[] { -1, 0, 0, 1, -3, 3, 4, -2, 0, -3, -3,
+ 1, -1, -3, -1, 0, -1, -3, -2, -2, 1, 4, -1 });
+ verifyValues(sm, 'X', new int[] { 0, -1, -1, -1, -2, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -2, 0, 0, -2, -1, -1, -1, -1, -1 });
+ }
+ /**
+ * Helper method to check pairwise scores for one residue
+ *
+ * @param sm
+ * @param res
+ * @param expected
+ * score values against 'res', in ResidueProperties.aaIndex order
+ */
+ private void verifyValues(ScoreMatrix sm, char res, int[] expected)
+ {
+ for (int j = 0; j < expected.length; j++)
+ {
+ char c2 = ResidueProperties.aa[j].charAt(0);
+ assertEquals(sm.getPairwiseScore(res, c2), expected[j],
+ String.format("%s->%s", res, c2));
+ }
+ }
+
+ @Test(groups = "Functional")
+ public void testComputePairwiseScores()
+ {
+ String[] seqs = new String[] { "FKL", "R-D", "QIA", "GWC" };
+ ScoreMatrix sm = ResidueProperties.getScoreMatrix("BLOSUM62");
+
+ MatrixI pairwise = sm.computePairwiseScores(seqs);
+
+ /*
+ * should be NxN where N = number of sequences
+ */
+ assertEquals(pairwise.height(), 4);
+ assertEquals(pairwise.width(), 4);
+
+ /*
+ * should be symmetrical (because BLOSUM62 is)
+ */
+ for (int i = 0; i < pairwise.height(); i++)
+ {
+ for (int j = 0; j < pairwise.width(); j++)
+ {
+ assertEquals(pairwise.getValue(i, j), pairwise.getValue(j, i),
+ "Not symmetric");
+ }
+ }
+ /*
+ * verify expected BLOSUM dot product scores
+ */
+ // F.F + K.K + L.L = 6 + 5 + 4 = 15
+ assertEquals(pairwise.getValue(0, 0), 15d);
+ // R.R + -.- + D.D = 5 + 1 + 6 = 12
+ assertEquals(pairwise.getValue(1, 1), 12d);
+ // Q.Q + I.I + A.A = 5 + 4 + 4 = 13
+ assertEquals(pairwise.getValue(2, 2), 13d);
+ // G.G + W.W + C.C = 6 + 11 + 9 = 26
+ assertEquals(pairwise.getValue(3, 3), 26d);
+ // F.R + K.- + L.D = -3 + -4 + -4 = -11
+ assertEquals(pairwise.getValue(0, 1), -11d);
+ // F.Q + K.I + L.A = -3 + -3 + -1 = -7
+ assertEquals(pairwise.getValue(0, 2), -7d);
+ // F.G + K.W + L.C = -3 + -3 + -1 = -7
+ assertEquals(pairwise.getValue(0, 3), -7d);
+ // R.Q + -.I + D.A = 1 + -4 + -2 = -5
+ assertEquals(pairwise.getValue(1, 2), -5d);
+ // R.G + -.W + D.C = -2 + -4 + -3 = -9
+ assertEquals(pairwise.getValue(1, 3), -9d);
+ // Q.G + I.W + A.C = -2 + -3 + 0 = -5
+ assertEquals(pairwise.getValue(2, 3), -5d);
+ }
+}
--- /dev/null
+package jalview.structure;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.fail;
+
+import org.testng.annotations.Test;
+
+public class AtomSpecTest
+{
+ @Test
+ public void testFromChimeraAtomSpec()
+ {
+ AtomSpec as = AtomSpec.fromChimeraAtomspec("#1:12.B");
+ assertEquals(as.getModelNumber(), 1);
+ assertEquals(as.getPdbResNum(), 12);
+ assertEquals(as.getChain(), "B");
+ assertNull(as.getPdbFile());
+
+ // no model - default to zero
+ as = AtomSpec.fromChimeraAtomspec(":13.C");
+ assertEquals(as.getModelNumber(), 0);
+ assertEquals(as.getPdbResNum(), 13);
+ assertEquals(as.getChain(), "C");
+ assertNull(as.getPdbFile());
+
+ // model.submodel
+ as = AtomSpec.fromChimeraAtomspec("#3.2:15");
+ assertEquals(as.getModelNumber(), 3);
+ assertEquals(as.getPdbResNum(), 15);
+ assertEquals(as.getChain(), "");
+ assertNull(as.getPdbFile());
+
+ String spec = "3:12.B";
+ try
+ {
+ as = AtomSpec.fromChimeraAtomspec(spec);
+ fail("Expected exception for " + spec);
+ } catch (IllegalArgumentException e)
+ {
+ // ok
+ }
+
+ spec = "#3:12-14.B";
+ try
+ {
+ as = AtomSpec.fromChimeraAtomspec(spec);
+ fail("Expected exception for " + spec);
+ } catch (IllegalArgumentException e)
+ {
+ // ok
+ }
+
+ spec = "";
+ try
+ {
+ as = AtomSpec.fromChimeraAtomspec(spec);
+ fail("Expected exception for " + spec);
+ } catch (IllegalArgumentException e)
+ {
+ // ok
+ }
+
+ spec = null;
+ try
+ {
+ as = AtomSpec.fromChimeraAtomspec(spec);
+ fail("Expected exception for " + spec);
+ } catch (NullPointerException e)
+ {
+ // ok
+ }
+ }
+}
--- /dev/null
+package jalview.structure;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.util.HashMap;
+import java.util.List;
+
+import org.testng.annotations.Test;
+
+public class StructureMappingTest
+{
+ @Test(groups = "Functional")
+ public void testgetPDBResNumRanges()
+ {
+ HashMap<Integer, int[]> map = new HashMap<Integer, int[]>();
+
+ StructureMapping mapping = new StructureMapping(null, null, null, null,
+ map, null);
+
+ List<int[]> ranges = mapping.getPDBResNumRanges(1, 2);
+ assertTrue(ranges.isEmpty());
+
+ map.put(1, new int[] { 12, 20 }); // 1 maps to 12
+ ranges = mapping.getPDBResNumRanges(2, 3);
+ assertTrue(ranges.isEmpty());
+ ranges = mapping.getPDBResNumRanges(1, 2);
+ assertEquals(ranges.size(), 1);
+ assertEquals(ranges.get(0)[0], 12);
+ assertEquals(ranges.get(0)[1], 12);
+
+ map.put(2, new int[] { 13, 20 }); // 2 maps to 13
+ ranges = mapping.getPDBResNumRanges(1, 2);
+ assertEquals(ranges.size(), 1);
+ assertEquals(ranges.get(0)[0], 12);
+ assertEquals(ranges.get(0)[1], 13);
+
+ map.put(3, new int[] { 15, 20 }); // 3 maps to 15 - break
+ ranges = mapping.getPDBResNumRanges(1, 5);
+ assertEquals(ranges.size(), 2);
+ assertEquals(ranges.get(0)[0], 12);
+ assertEquals(ranges.get(0)[1], 13);
+ assertEquals(ranges.get(1)[0], 15);
+ assertEquals(ranges.get(1)[1], 15);
+ }
+}
import java.awt.Color;
import java.util.Arrays;
+import java.util.BitSet;
import java.util.List;
import org.testng.annotations.BeforeClass;
}
@Override
- public void superposeStructures(AlignmentI[] als, int[] alm,
+ public String superposeStructures(AlignmentI[] als, int[] alm,
ColumnSelection[] alc)
{
+ return null;
}
@Override
@Override
protected StructureMappingcommandSet[] getColourBySequenceCommands(
- String[] files, SequenceRenderer sr, FeatureRenderer fr,
- AlignmentI alignment)
- {
- return null;
- }
-
- @Override
- public FeatureRenderer getFeatureRenderer(AlignmentViewPanel alignment)
+ String[] files, SequenceRenderer sr, AlignmentViewPanel avp)
{
return null;
}
public void colourByCharge()
{
}
+
+ @Override
+ public FeatureRenderer getFeatureRenderer(
+ AlignmentViewPanel alignment)
+ {
+ return null;
+ }
};
}
structs[i] = testee.new SuperposeData(al.getWidth());
}
/*
- * initialise array of 'superposable columns' to true (would be false for
+ * initialise BitSet of 'superposable columns' to true (would be false for
* hidden columns)
*/
- boolean[] matched = new boolean[al.getWidth()];
- Arrays.fill(matched, true);
+ BitSet matched = new BitSet();
+ for (int i = 0; i < al.getWidth(); i++)
+ {
+ matched.set(i);
+ }
int refStructure = testee
.findSuperposableResidues(al, matched, structs);
/*
* only ungapped, structure-mapped columns are superposable
*/
- assertFalse(matched[0]); // gap in first sequence
- assertTrue(matched[1]);
- assertFalse(matched[2]); // gap in third sequence
- assertFalse(matched[3]); // gap in fourth sequence
- assertTrue(matched[4]);
- assertTrue(matched[5]); // gap in second sequence
+ assertFalse(matched.get(0)); // gap in first sequence
+ assertTrue(matched.get(1));
+ assertFalse(matched.get(2)); // gap in third sequence
+ assertFalse(matched.get(3)); // gap in fourth sequence
+ assertTrue(matched.get(4));
+ assertTrue(matched.get(5)); // gap in second sequence
assertEquals("1YCS", structs[0].pdbId);
assertEquals("3A6S", structs[1].pdbId);
structs[i] = testee.new SuperposeData(al.getWidth());
}
/*
- * initialise array of 'superposable columns' to true (would be false for
+ * initialise BitSet of 'superposable columns' to true (would be false for
* hidden columns)
*/
- boolean[] matched = new boolean[al.getWidth()];
- Arrays.fill(matched, true);
+ BitSet matched = new BitSet();
+ for (int i = 0; i < al.getWidth(); i++)
+ {
+ matched.set(i);
+ }
+
// treat column 5 of the alignment as hidden
- matched[4] = false;
+ matched.clear(4);
int refStructure = testee
.findSuperposableResidues(al, matched, structs);
assertEquals(0, refStructure);
// only ungapped, structure-mapped columns are not superposable
- assertFalse(matched[0]);
- assertTrue(matched[1]);
- assertFalse(matched[2]);
- assertFalse(matched[3]);
- assertFalse(matched[4]); // superposable, but hidden, column
- assertTrue(matched[5]);
- }
-
- public FeatureRenderer getFeatureRenderer(AlignmentViewPanel alignment)
- {
- return null;
- }
-
- public SequenceRenderer getSequenceRenderer(AlignmentViewPanel alignment)
- {
- return null;
+ assertFalse(matched.get(0));
+ assertTrue(matched.get(1));
+ assertFalse(matched.get(2));
+ assertFalse(matched.get(3));
+ assertFalse(matched.get(4)); // superposable, but hidden, column
+ assertTrue(matched.get(5));
}
}
--- /dev/null
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview 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.
+ *
+ * Jalview 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.urls;
+
+import jalview.urls.api.UrlProviderFactoryI;
+import jalview.urls.api.UrlProviderI;
+import jalview.urls.applet.AppletUrlProviderFactory;
+import jalview.util.UrlConstants;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+public class AppletUrlProviderFactoryTest {
+
+ @Test(groups = { "Functional" })
+ public void testCreateUrlProvider()
+ {
+ final String defaultUrl = UrlConstants.DEFAULT_STRING.substring(
+ UrlConstants.DEFAULT_STRING.indexOf(UrlConstants.SEP) + 1,
+ UrlConstants.DEFAULT_STRING.length());
+ Map<String, String> urlList = new HashMap<String, String>()
+ {
+ {
+ put("Test1", "http://identifiers.org/uniprot/$DB_ACCESSION$");
+ put("Test2", defaultUrl);
+ }
+ };
+
+ UrlProviderFactoryI factory = new AppletUrlProviderFactory("Test2",
+ urlList);
+ UrlProviderI prov = factory.createUrlProvider();
+
+ // default url correctly set
+ Assert.assertEquals(prov.getPrimaryUrlId(), "Test2");
+ Assert.assertEquals(prov.getPrimaryUrl("FER_CAPAN"),
+ defaultUrl.replace("$SEQUENCE_ID$",
+ "FER_CAPAN"));
+
+ List<UrlLinkDisplay> allLinks = prov.getLinksForTable();
+
+ // 2 links in provider
+ Assert.assertEquals(allLinks.size(), 2);
+
+ // first link set correctly
+ Assert.assertEquals(allLinks.get(0).getId(), "Test1");
+ Assert.assertEquals(allLinks.get(0).getDescription(), "Test1");
+ Assert.assertEquals(allLinks.get(0).getUrl(),
+ "http://identifiers.org/uniprot/$DB_ACCESSION$");
+ Assert.assertFalse(allLinks.get(0).getIsPrimary());
+ Assert.assertTrue(allLinks.get(0).getIsSelected());
+
+ // second link set correctly
+ Assert.assertEquals(allLinks.get(1).getId(), "Test2");
+ Assert.assertEquals(allLinks.get(1).getDescription(), "Test2");
+ Assert.assertEquals(allLinks.get(1).getUrl(), defaultUrl);
+ Assert.assertTrue(allLinks.get(1).getIsPrimary());
+ Assert.assertTrue(allLinks.get(1).getIsSelected());
+ }
+}
--- /dev/null
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview 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.
+ *
+ * Jalview 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.urls;
+
+import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertFalse;
+import static org.testng.AssertJUnit.assertTrue;
+
+import jalview.urls.api.UrlProviderI;
+import jalview.util.UrlConstants;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Vector;
+
+import org.testng.annotations.Test;
+
+public class CustomUrlProviderTest
+{
+
+ private static final String cachedList = "TEST|http://someurl.blah/$DB_ACCESSION$|"
+ + "ANOTHER|http://test/t$SEQUENCE_ID$|"
+ + "TEST2|http://address/$SEQUENCE_ID$|SRS|"
+ + "http://theSRSlink/$SEQUENCE_ID$";
+
+ private static final String unselectedList = "NON1|http://x/y/$DB_ACCESSION$|"
+ + "NON2|http://a/b/c/$DB_ACCESSION";
+
+ private static final HashMap<String, String> urlMap = new HashMap<String, String>()
+ {
+ {
+ put("TEST","http://someurl.blah/$DB_ACCESSION$");
+ put("ANOTHER","http://test/t$SEQUENCE_ID$");
+ put("TEST2", "http://address/$SEQUENCE_ID$");
+ put("SRS", "http://theSRSlink/$SEQUENCE_ID$");
+ }
+ };
+
+ private static final HashMap<String, String> unselUrlMap = new HashMap<String, String>()
+ {
+ {
+ put("NON1", "http://x/y/$DB_ACCESSION$");
+ put("NON2", "http://a/b/c/$DB_ACCESSION");
+ }
+ };
+
+ private static final String[] dlinks = {
+ "TEST|http://someurl.blah/$DB_ACCESSION$",
+ "ANOTHER|http://test/t$SEQUENCE_ID$",
+ "TEST2|http://address/$SEQUENCE_ID$",
+ UrlConstants.DEFAULT_STRING };
+
+ private static final String[] unselDlinks = {
+ "NON1|http://x/y/$DB_ACCESSION$", "NON2|http://a/b/c/$DB_ACCESSION" };
+
+ private static final Vector<String> displayLinks = new Vector<String>(
+ Arrays.asList(dlinks));
+
+ private static final Vector<String> unselDisplayLinks = new Vector<String>(
+ Arrays.asList(unselDlinks));
+
+ private static final String[] dlinks2 = { "a|http://x.y.z/$SEQUENCE_ID$" };
+
+ private static final Vector<String> displayLinks2 = new Vector<String>(
+ Arrays.asList(dlinks2));
+
+ private static final String[] list1 = { "a" };
+
+ private static final String[] list2 = { "http://x.y.z/$SEQUENCE_ID$" };
+
+ private static final Vector<String> names = new Vector<String>(
+ Arrays.asList(list1));
+
+ private static final Vector<String> urls = new Vector<String>(
+ Arrays.asList(list2));
+
+ /*
+ * Test default url is set and returned correctly
+ */
+ @Test(groups = { "Functional" })
+ public void testDefaultUrl()
+ {
+ UrlProviderI customProv = new CustomUrlProvider(cachedList,
+ unselectedList);
+
+ // default url can be set
+ assertTrue(customProv.setPrimaryUrl("ANOTHER"));
+
+ // supplied replacement id must be more than 4 chars
+ String result = customProv.getPrimaryUrl("123");
+ assertEquals(null, result);
+
+ // default url can be retrieved given a sequence id
+ result = customProv.getPrimaryUrl("seqid");
+ assertEquals("http://test/tseqid", result);
+
+ // if there is no default url it sets the default to null
+ assertFalse(customProv.setPrimaryUrl("No default"));
+ result = customProv.getPrimaryUrl("testid");
+ assertEquals(null, result);
+
+ // choosing the default picks the DEFAULT_STRING option
+ customProv.choosePrimaryUrl();
+ result = customProv.getPrimaryUrl("seqid");
+ assertEquals(
+ UrlConstants.DEFAULT_STRING.split("\\|")[1].split("\\$")[0]
+ + "seqid",
+ result);
+ }
+
+ /*
+ * Test urls are set and returned correctly
+ */
+ @Test(groups = { "Functional" })
+ public void testUrlLinks()
+ {
+ // creation from cached url list works + old links upgraded
+ UrlProviderI customProv = new CustomUrlProvider(cachedList,
+ unselectedList);
+ assertTrue(displayLinks.containsAll(customProv.getLinksForMenu()));
+
+ // creation from map works + old links upgraded
+ UrlProviderI customProv2 = new CustomUrlProvider(urlMap, unselUrlMap);
+ assertTrue(displayLinks.containsAll(customProv2.getLinksForMenu()));
+
+ // writing url links as a string works
+ // because UrlProvider does not guarantee order of links, we can't just
+ // compare the output of writeUrlsAsString to a string, hence the hoops here
+ String result = customProv.writeUrlsAsString(true);
+ UrlProviderI up = new CustomUrlProvider(result, "");
+ assertTrue(displayLinks.containsAll(up.getLinksForMenu()));
+
+ result = customProv.writeUrlsAsString(false);
+ up = new CustomUrlProvider("", result);
+ assertTrue(unselDisplayLinks.containsAll(up.getLinksForMenu()));
+
+ result = customProv2.writeUrlsAsString(true);
+ UrlProviderI up2 = new CustomUrlProvider(result, "");
+ assertTrue(displayLinks.containsAll(up2.getLinksForMenu()));
+
+ result = customProv2.writeUrlsAsString(false);
+ up2 = new CustomUrlProvider("", result);
+ assertTrue(displayLinks.containsAll(up2.getLinksForMenu()));
+ }
+}
--- /dev/null
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview 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.
+ *
+ * Jalview 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.urls;
+
+import jalview.urls.api.UrlProviderI;
+import jalview.urls.desktop.DesktopUrlProviderFactory;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.List;
+
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+public class DesktopUrlProviderFactoryTest
+{
+ private static final String testIdOrgString = "{\"Local\": [{\"id\":\"MIR:00000002\",\"name\":\"ChEBI\",\"pattern\":\"^CHEBI:\\d+$\","
+ + "\"definition\":\"Chemical Entities of Biological Interest (ChEBI)\",\"prefix\":\"chebi\","
+ + "\"url\":\"http://identifiers.org/chebi\"},{\"id\":\"MIR:00000005\",\"name\":\"UniProt Knowledgebase\","
+ + "\"pattern\":\"^([A-N,R-Z][0-9]([A-Z][A-Z, 0-9][A-Z, 0-9][0-9]){1,2})|([O,P,Q][0-9][A-Z, 0-9][A-Z, 0-9][A-Z, 0-9][0-9])(\\.\\d+)?$\","
+ + "\"definition\":\"The UniProt Knowledgebase (UniProtKB)\",\"prefix\":\"uniprot\",\"url\":\"http://identifiers.org/uniprot\"},"
+ + "{\"id\":\"MIR:00000011\",\"name\":\"InterPro\",\"pattern\":\"^IPR\\d{6}$\",\"definition\":\"InterPro\",\"prefix\":\"interpro\","
+ + "\"url\":\"http://identifiers.org/interpro\"},"
+ + "{\"id\":\"MIR:00000372\",\"name\":\"ENA\",\"pattern\":\"^[A-Z]+[0-9]+(\\.\\d+)?$\",\"definition\":\"The European Nucleotide Archive (ENA),\""
+ + "\"prefix\":\"ena.embl\",\"url\":\"http://identifiers.org/ena.embl\"}]}";
+
+ @BeforeMethod(alwaysRun = true)
+ public void setup()
+ {
+ // make a dummy identifiers.org download file
+ File temp = null;
+
+ try
+ {
+ temp = File.createTempFile("tempfile", ".tmp");
+ temp.deleteOnExit();
+ BufferedWriter bw = new BufferedWriter(new FileWriter(temp));
+ bw.write(testIdOrgString);
+ bw.close();
+ } catch (IOException e)
+ {
+ System.out
+ .println("Error initialising DesktopUrlProviderFactoryTest test: "
+ + e.getMessage());
+ }
+
+ IdOrgSettings.setDownloadLocation(temp.getPath());
+ }
+
+ @Test(groups = { "Functional" })
+ public void testCreateUrlProvider()
+ {
+ String defaultUrlString = "Test1";
+ String defaultUrl = "http://blah.blah/$SEQUENCE_ID$";
+ String cachedUrlList = "MIR:00000005|MIR:00000011|Test1|http://blah.blah/$SEQUENCE_ID$|"
+ + "Test2|http://test2/$DB_ACCESSION$|Test3|http://test3/$SEQUENCE_ID$";
+ String userUrlList = "MIR:00000372|Test4|httpL//another.url/$SEQUENCE_ID$";
+
+ DesktopUrlProviderFactory factory = new DesktopUrlProviderFactory(
+ defaultUrlString, cachedUrlList, userUrlList);
+ UrlProviderI prov = factory.createUrlProvider();
+
+ // default url correctly set
+ Assert.assertEquals(prov.getPrimaryUrlId(), "Test1");
+ Assert.assertEquals(prov.getPrimaryUrl("FER_CAPAN"),
+ defaultUrl.replace("$SEQUENCE_ID$", "FER_CAPAN"));
+
+ List<String> menulinks = prov.getLinksForMenu();
+ List<UrlLinkDisplay> allLinks = prov.getLinksForTable();
+
+ // 8 links in provider - 4 from id file, 4 custom links
+ Assert.assertEquals(allLinks.size(), 8);
+
+ // 5 links in menu (cachedUrlList)
+ Assert.assertEquals(menulinks.size(), 5);
+
+ Assert.assertTrue(menulinks
+ .contains("Test1|http://blah.blah/$SEQUENCE_ID$"));
+ Assert.assertTrue(menulinks
+ .contains("Test2|http://test2/$DB_ACCESSION$"));
+ Assert.assertTrue(menulinks
+ .contains("Test3|http://test3/$SEQUENCE_ID$"));
+ Assert.assertTrue(menulinks
+ .contains("UniProt Knowledgebase|http://identifiers.org/uniprot/$DB_ACCESSION$|uniprot"));
+ Assert.assertTrue(menulinks
+ .contains("InterPro|http://identifiers.org/interpro/$DB_ACCESSION$|interpro"));
+ }
+}
--- /dev/null
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview 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.
+ *
+ * Jalview 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+
+package jalview.urls;
+
+import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertFalse;
+import static org.testng.AssertJUnit.assertTrue;
+
+import jalview.urls.api.UrlProviderI;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Vector;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class IdentifiersUrlProviderTest
+{
+ private static final String testIdOrgFile = "{\"Local\": [{\"id\":\"MIR:00000002\",\"name\":\"ChEBI\",\"pattern\":\"^CHEBI:\\d+$\","
+ + "\"definition\":\"Chemical Entities of Biological Interest (ChEBI)\",\"prefix\":\"chebi\","
+ + "\"url\":\"http://identifiers.org/chebi\"},{\"id\":\"MIR:00000005\",\"name\":\"UniProt Knowledgebase\","
+ + "\"pattern\":\"^([A-N,R-Z][0-9]([A-Z][A-Z, 0-9][A-Z, 0-9][0-9]){1,2})|([O,P,Q][0-9][A-Z, 0-9][A-Z, 0-9][A-Z, 0-9][0-9])(\\.\\d+)?$\","
+ + "\"definition\":\"The UniProt Knowledgebase (UniProtKB)\",\"prefix\":\"uniprot\",\"url\":\"http://identifiers.org/uniprot\"},"
+ + "{\"id\":\"MIR:00000011\",\"name\":\"InterPro\",\"pattern\":\"^IPR\\d{6}$\",\"definition\":\"InterPro\",\"prefix\":\"interpro\","
+ + "\"url\":\"http://identifiers.org/interpro\"},"
+ + "{\"id\":\"MIR:00000372\",\"name\":\"ENA\",\"pattern\":\"^[A-Z]+[0-9]+(\\.\\d+)?$\",\"definition\":\"The European Nucleotide Archive (ENA),\""
+ + "\"prefix\":\"ena.embl\",\"url\":\"http://identifiers.org/ena.embl\"}]}";
+
+ private static final String[] dlinks = {
+ "UniProt Knowledgebase|http://identifiers.org/uniprot/$DB_ACCESSION$|uniprot",
+ "InterPro|http://identifiers.org/interpro/$DB_ACCESSION$|interpro",
+ "ENA|http://identifiers.org/ena.embl/$DB_ACCESSION$|ena.embl" };
+
+ private static final String[] dlinks1 = {
+ "MIR:00000011|http://identifiers.org/interpro/$DB_ACCESSION$",
+ "MIR:00000372|http://identifiers.org/ena.embl/$DB_ACCESSION$" };
+
+ private static final String[] dlinks2 = {
+ "MIR:00000005|http://identifiers.org/uniprot/$DB_ACCESSION$",
+ "MIR:00000011|http://identifiers.org/interpro/$DB_ACCESSION$" };
+
+ private static final String stringLinks = "MIR:00000005|http://identifiers.org/uniprot/$DB_ACCESSION$"
+ + "MIR:00000011|http://identifiers.org/interpro/$DB_ACCESSION$"
+ + "MIR:00000372|http://identifiers.org/ena.embl/$DB_ACCESSION$";
+
+ private static final String[] unselDlinks = { "ChEBI|http://identifiers.org/chebi/$DB_ACCESSION$" };
+
+ private static final Vector<String> displayLinks = new Vector<String>(
+ Arrays.asList(dlinks));
+
+ private static final Vector<String> unselDisplayLinks = new Vector<String>(
+ Arrays.asList(unselDlinks));
+
+ private static final Vector<String> displayLinks1 = new Vector<String>(
+ Arrays.asList(dlinks1));
+
+ private static final Vector<String> displayLinks2 = new Vector<String>(
+ Arrays.asList(dlinks2));
+
+ private static final HashMap<String, String> urlMap = new HashMap<String, String>()
+ {
+ {
+ put("MIR:00000005", "http://identifiers.org/uniprot/$DB_ACCESSION$");
+ put("MIR:00000011", "http://identifiers.org/interpro/$DB_ACCESSION$");
+ put("MIR:00000372", "http://identifiers.org/ena.embl/$DB_ACCESSION$");
+ }
+ };
+
+ private String testfile = "";
+
+
+ @BeforeClass(alwaysRun = true)
+ public void setup()
+ {
+ // setup test ids in a file
+ File outFile = null;
+ try
+ {
+ outFile = File.createTempFile("testidsfile", "txt");
+ outFile.deleteOnExit();
+
+ FileWriter fw = new FileWriter(outFile);
+ fw.write(testIdOrgFile);
+ fw.close();
+
+ testfile = outFile.getAbsolutePath();
+
+ } catch (Exception ex)
+ {
+ System.err.println(ex);
+ }
+
+ IdOrgSettings.setDownloadLocation(testfile);
+ }
+
+ /*
+ * Test urls are set and returned correctly
+ */
+ @Test(groups = { "Functional" })
+ public void testUrlLinks()
+ {
+ // creation from cached id list
+ String idList = "MIR:00000005|MIR:00000011|MIR:00000372";
+ UrlProviderI idProv = new IdentifiersUrlProvider(idList);
+
+ assertTrue(displayLinks.containsAll(idProv.getLinksForMenu()));
+
+ // because UrlProvider does not guarantee order of links, we can't just
+ // compare the output of writeUrlsAsString to a string, hence the hoops here
+ String result = idProv.writeUrlsAsString(true);
+ UrlProviderI up = new IdentifiersUrlProvider(result);
+ assertTrue(displayLinks.containsAll(up.getLinksForMenu()));
+
+ result = idProv.writeUrlsAsString(false);
+ up = new IdentifiersUrlProvider(result);
+ assertTrue(unselDisplayLinks.containsAll(up.getLinksForMenu()));
+
+ }
+
+ /*
+ * Test default is set and returned correctly
+ */
+ @Test(groups = { "Functional" })
+ public void testDefaultUrl()
+ {
+ // creation from cached id list
+ String idList = "MIR:00000005|MIR:00000011|MIR:00000372";
+ UrlProviderI idProv = new IdentifiersUrlProvider(idList);
+
+ // initially no default
+ assertEquals(null, idProv.getPrimaryUrl("seqid"));
+
+ // set and then retrieve default
+ assertTrue(idProv.setPrimaryUrl("MIR:00000005"));
+ assertEquals("http://identifiers.org/uniprot/seqid",
+ idProv.getPrimaryUrl("seqid"));
+
+ // ids less than length 4 return null
+ assertEquals(null,
+ idProv.getPrimaryUrl("123"));
+
+ // attempt to set bad default
+ assertFalse(idProv.setPrimaryUrl("MIR:00001234"));
+ // default set to null (as default should have been set elsewhere)
+ assertEquals(null, idProv.getPrimaryUrl("seqid"));
+
+ // chooseDefaultUrl not implemented for IdentifiersUrlProvider
+ assertEquals(null, idProv.choosePrimaryUrl());
+ }
+}
--- /dev/null
+package jalview.urls;
+
+import jalview.util.UrlLink;
+
+import java.util.List;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+public class UrlLinkDisplayTest {
+
+ @Test(groups = { "Functional" })
+ public void testDisplayColumnNames()
+ {
+ // 5 column names returned although 6 names internal to UrlLinkDisplay
+ List<String> names = UrlLinkDisplay.getDisplayColumnNames();
+ Assert.assertEquals(names.size(), 5);
+ }
+
+ @Test(groups = { "Functional" })
+ public void getValue()
+ {
+ UrlLink link = new UrlLink("Test Name",
+ "http://identifiers.org/$DB_ACCESSION$", "TestDB");
+ UrlLinkDisplay u = new UrlLinkDisplay("Test", link, false, false);
+
+ Assert.assertFalse((boolean) u.getValue(UrlLinkDisplay.PRIMARY));
+ Assert.assertEquals(u.getValue(UrlLinkDisplay.ID), "Test");
+ Assert.assertEquals(u.getValue(UrlLinkDisplay.DATABASE), "TestDB");
+ Assert.assertEquals(u.getValue(UrlLinkDisplay.NAME), "Test Name");
+ Assert.assertFalse((boolean) u.getValue(UrlLinkDisplay.SELECTED));
+ Assert.assertEquals(u.getValue(UrlLinkDisplay.URL),
+ "http://identifiers.org/$DB_ACCESSION$");
+ }
+
+ @Test(groups = { "Functional" })
+ public void testIsEditable()
+ {
+ // only default and selected columns are editable ever
+ // default only editable if link contains $SEQUENCE_ID$
+
+ UrlLink link = new UrlLink("Test Url",
+ "http://identifiers.org/$DB_ACCESSION$",
+ "TestName");
+ UrlLinkDisplay u = new UrlLinkDisplay("Test", link, false, false);
+
+ Assert.assertFalse(u.isEditable(UrlLinkDisplay.PRIMARY));
+ Assert.assertTrue(u.isEditable(UrlLinkDisplay.SELECTED));
+ Assert.assertFalse(u.isEditable(UrlLinkDisplay.ID));
+ Assert.assertFalse(u.isEditable(UrlLinkDisplay.URL));
+ Assert.assertFalse(u.isEditable(UrlLinkDisplay.NAME));
+ Assert.assertFalse(u.isEditable(UrlLinkDisplay.DATABASE));
+
+ UrlLink vlink = new UrlLink("Test Sequence ID Url",
+ "http://myurl/$SEQUENCE_ID$", "TestName");
+ UrlLinkDisplay v = new UrlLinkDisplay("Test", vlink, false, false);
+
+ Assert.assertTrue(v.isEditable(UrlLinkDisplay.PRIMARY));
+ Assert.assertTrue(v.isEditable(UrlLinkDisplay.SELECTED));
+ Assert.assertFalse(v.isEditable(UrlLinkDisplay.ID));
+ Assert.assertFalse(v.isEditable(UrlLinkDisplay.URL));
+ Assert.assertFalse(v.isEditable(UrlLinkDisplay.NAME));
+ Assert.assertFalse(v.isEditable(UrlLinkDisplay.DATABASE));
+ }
+
+ @Test(groups = { "Functional" })
+ public void testName()
+ {
+ UrlLink link = new UrlLink("Test Url",
+ "http://identifiers.org/$DB_ACCESSION$", "TestName");
+ UrlLinkDisplay u = new UrlLinkDisplay("Test", link, false, false);
+
+ // Name initially as input in link
+ Assert.assertEquals(u.getDBName(), "TestName");
+
+ // Setting updates name
+ u.setDBName("NewName");
+ Assert.assertEquals(u.getDBName(), "NewName");
+ }
+
+ @Test(groups = { "Functional" })
+ public void testDescription()
+ {
+ UrlLink link = new UrlLink("Test Name",
+ "http://identifiers.org/$DB_ACCESSION$", "TestDB");
+ UrlLinkDisplay u = new UrlLinkDisplay("Test", link, false, false);
+
+ // Desc initially as input in link
+ Assert.assertEquals(u.getDescription(), "Test Name");
+
+ // Setting updates name
+ u.setDescription("New Desc");
+ Assert.assertEquals(u.getDescription(), "New Desc");
+ }
+
+ @Test(groups = { "Functional" })
+ public void testUrl()
+ {
+ UrlLink link = new UrlLink("Test Name",
+ "http://identifiers.org/$DB_ACCESSION$", "TestDB");
+ UrlLinkDisplay u = new UrlLinkDisplay("Test", link, false, false);
+
+ // Url initially as input in link
+ Assert.assertEquals(u.getUrl(), "http://identifiers.org/$DB_ACCESSION$");
+
+ // Setting updates url
+ u.setUrl("http://something.new/$SEQUENCE_ID$");
+ Assert.assertEquals(u.getUrl(), "http://something.new/$SEQUENCE_ID$");
+ }
+
+ @Test(groups = { "Functional" })
+ public void testGetSetValue()
+ {
+ UrlLink link = new UrlLink("Test Name",
+ "http://identifiers.org/$DB_ACCESSION$", "TestDB");
+ UrlLinkDisplay u = new UrlLinkDisplay("Test", link, false, false);
+
+ Assert.assertFalse((boolean) u.getValue(UrlLinkDisplay.PRIMARY));
+ Assert.assertFalse((boolean) u.getValue(UrlLinkDisplay.SELECTED));
+ Assert.assertEquals(u.getValue(UrlLinkDisplay.DATABASE), "TestDB");
+ Assert.assertEquals(u.getValue(UrlLinkDisplay.NAME), "Test Name");
+ Assert.assertEquals(u.getValue(UrlLinkDisplay.ID), "Test");
+ Assert.assertEquals(u.getValue(UrlLinkDisplay.URL),
+ "http://identifiers.org/$DB_ACCESSION$");
+
+ u.setValue(UrlLinkDisplay.PRIMARY, true);
+ Assert.assertTrue((boolean) u.getValue(UrlLinkDisplay.PRIMARY));
+
+ u.setValue(UrlLinkDisplay.SELECTED, true);
+ Assert.assertTrue((boolean) u.getValue(UrlLinkDisplay.SELECTED));
+
+ u.setValue(UrlLinkDisplay.NAME, "New Desc");
+ Assert.assertEquals(u.getValue(UrlLinkDisplay.NAME), "New Desc");
+
+ u.setValue(UrlLinkDisplay.DATABASE, "NewName");
+ Assert.assertEquals(u.getValue(UrlLinkDisplay.DATABASE), "NewName");
+
+ u.setValue(UrlLinkDisplay.ID, "New ID");
+ Assert.assertEquals(u.getValue(UrlLinkDisplay.ID), "New ID");
+
+ u.setValue(UrlLinkDisplay.URL, "http://something.new/$SEQUENCE_ID$");
+ Assert.assertEquals(u.getValue(UrlLinkDisplay.URL),
+ "http://something.new/$SEQUENCE_ID$");
+ }
+}
--- /dev/null
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview 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.
+ *
+ * Jalview 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+
+package jalview.urls;
+
+import static jalview.util.UrlConstants.DELIM;
+import static jalview.util.UrlConstants.SEP;
+import static jalview.util.UrlConstants.SEQUENCE_ID;
+
+import jalview.urls.api.UrlProviderI;
+import jalview.util.MessageManager;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.event.TableModelListener;
+
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+public class UrlLinkTableModelTest {
+
+ private static final String inmenu = "TEST|http://someurl.blah/$DB_ACCESSION$|"
+ + "ANOTHER|http://test/t$SEQUENCE_ID$|"
+ + "TEST2|http://address/$SEQUENCE_ID$|SRS|"
+ + "http://theSRSlink/$SEQUENCE_ID$|"
+ + "MIR:00000005|MIR:00000011|MIR:00000372";
+
+ private static final String notinmenu = "Not1|http://not.in.menu/$DB_ACCESSION$|"
+ + "Not2|http://not.in.menu.either/$DB_ACCESSION$";
+
+ private static final String testIdOrgString = "{\"Local\": [{\"id\":\"MIR:00000002\",\"name\":\"ChEBI\",\"pattern\":\"^CHEBI:\\d+$\","
+ + "\"definition\":\"Chemical Entities of Biological Interest (ChEBI)\",\"prefix\":\"chebi\","
+ + "\"url\":\"http://identifiers.org/chebi\"},{\"id\":\"MIR:00000005\",\"name\":\"UniProt Knowledgebase\","
+ + "\"pattern\":\"^([A-N,R-Z][0-9]([A-Z][A-Z, 0-9][A-Z, 0-9][0-9]){1,2})|([O,P,Q][0-9][A-Z, 0-9][A-Z, 0-9][A-Z, 0-9][0-9])(\\.\\d+)?$\","
+ + "\"definition\":\"The UniProt Knowledgebase (UniProtKB)\",\"prefix\":\"uniprot\",\"url\":\"http://identifiers.org/uniprot\"},"
+ + "{\"id\":\"MIR:00000011\",\"name\":\"InterPro\",\"pattern\":\"^IPR\\d{6}$\",\"definition\":\"InterPro\",\"prefix\":\"interpro\","
+ + "\"url\":\"http://identifiers.org/interpro\"},"
+ + "{\"id\":\"MIR:00000372\",\"name\":\"ENA\",\"pattern\":\"^[A-Z]+[0-9]+(\\.\\d+)?$\",\"definition\":\"The European Nucleotide Archive (ENA),\""
+ + "\"prefix\":\"ena.embl\",\"url\":\"http://identifiers.org/ena.embl\"}]}";
+
+ private UrlProviderI prov;
+
+ @BeforeMethod(alwaysRun = true)
+ public void setup()
+ {
+ // set up UrlProvider data as the source for the TableModel
+ // the data gets updated by the TableModel, so needs to be reinitialised for
+ // each test
+
+ // make a dummy identifiers.org download file
+ File temp = null;
+ try
+ {
+ temp = File.createTempFile("tempfile", ".tmp");
+ temp.deleteOnExit();
+ BufferedWriter bw = new BufferedWriter(new FileWriter(temp));
+ bw.write(testIdOrgString);
+ bw.close();
+ } catch (IOException e)
+ {
+ System.out.println("Error initialising UrlLinkTableModel test: "
+ + e.getMessage());
+ }
+
+ // set up custom and identifiers.org url providers
+ IdOrgSettings.setDownloadLocation(temp.getPath());
+ IdentifiersUrlProvider idprov = new IdentifiersUrlProvider(inmenu);
+ CustomUrlProvider cprov = new CustomUrlProvider(inmenu, notinmenu);
+ List<UrlProviderI> provlist = new ArrayList<UrlProviderI>();
+ provlist.add(idprov);
+ provlist.add(cprov);
+
+ prov = new UrlProvider("TEST2", provlist);
+ }
+
+ /*
+ * Test that the table model is correctly initialised
+ * Display columns and default row are set; data provider listening event set up
+ */
+ @Test(groups = { "Functional" })
+ public void testInitialisation()
+ {
+ int defaultCol = 4;
+ int dbCol = 0;
+ int descCol = 1;
+
+ UrlLinkTableModel m = new UrlLinkTableModel(prov);
+
+ // exactly one table model listener
+ TableModelListener[] listeners = m
+ .getListeners(TableModelListener.class);
+ Assert.assertEquals(listeners.length, 1);
+
+ // default row exists, there is exactly 1, and it matches the supplied
+ // default
+ int count = 0;
+ for (int row = 0; row < m.getRowCount(); row++)
+ {
+ boolean isDefault = (boolean) m.getValueAt(row, defaultCol);
+ if (isDefault)
+ {
+ count++;
+ String defaultDBName = (String) m.getValueAt(row, dbCol);
+ Assert.assertEquals(defaultDBName, "TEST2");
+
+ String defaultDesc = (String) m.getValueAt(row, descCol);
+ Assert.assertEquals(defaultDesc, "TEST2");
+ }
+ }
+ Assert.assertEquals(count, 1);
+ }
+
+ /*
+ * Test row and column counts
+ */
+ @Test(groups = { "Functional" })
+ public void testCounts()
+ {
+ UrlLinkTableModel m = new UrlLinkTableModel(prov);
+
+ // correct numbers of column and rows
+ Assert.assertEquals(m.getColumnCount(), 5);
+ Assert.assertEquals(m.getRowCount(), 10);
+ }
+
+ /*
+ * Test column access
+ */
+ @Test(groups = { "Functional" })
+ public void testColumns()
+ {
+ UrlLinkTableModel m = new UrlLinkTableModel(prov);
+
+ // check column names
+ Assert.assertEquals(m.getColumnName(0),
+ MessageManager.formatMessage("label.database"));
+ Assert.assertEquals(m.getColumnName(1),
+ MessageManager.formatMessage("label.name"));
+ Assert.assertEquals(m.getColumnName(2),
+ MessageManager.formatMessage("label.url"));
+ Assert.assertEquals(m.getColumnName(3),
+ MessageManager.formatMessage("label.inmenu"));
+ Assert.assertEquals(m.getColumnName(4),
+ MessageManager.formatMessage("label.primary"));
+
+ // check column classes
+ Assert.assertEquals(m.getColumnClass(0), String.class);
+ Assert.assertEquals(m.getColumnClass(1), String.class);
+ Assert.assertEquals(m.getColumnClass(2), String.class);
+ Assert.assertEquals(m.getColumnClass(3), Boolean.class);
+ Assert.assertEquals(m.getColumnClass(4), Boolean.class);
+ }
+
+ /*
+ * Test row insertion
+ */
+ @Test(groups = { "Functional" })
+ public void testRowInsert()
+ {
+ UrlLinkTableModel m = new UrlLinkTableModel(prov);
+
+ m.insertRow("newname", "newurl");
+
+ // check table has new row inserted
+ Assert.assertEquals(m.getValueAt(10, 0), "newname");
+ Assert.assertEquals(m.getValueAt(10, 1), "newname");
+ Assert.assertEquals(m.getValueAt(10, 2), "newurl");
+ Assert.assertEquals(m.getValueAt(10, 3), true);
+ Assert.assertEquals(m.getValueAt(10, 4), false);
+
+ // check data source has new row insrte
+ Assert.assertTrue(prov.getLinksForMenu().contains(
+ "newname" + SEP + "newurl"));
+ }
+
+ /*
+ * Test row deletion
+ */
+ @Test(groups = { "Functional" })
+ public void testRowDelete()
+ {
+ UrlLinkTableModel m = new UrlLinkTableModel(prov);
+
+ // get name and url at row 0
+ String name = (String) m.getValueAt(0, 0);
+ String url = (String) m.getValueAt(0, 1);
+
+ m.removeRow(0);
+
+ // check table no longer has row 0 elements in it
+ for (int row = 0; row < m.getRowCount(); row++)
+ {
+ Assert.assertNotEquals(m.getValueAt(row, 0), name);
+ }
+
+ // check data source likewise
+ Assert.assertFalse(prov.getLinksForMenu().contains(name + SEP + url));
+ }
+
+ /*
+ * Test value setting and getting
+ */
+ @Test(groups = { "Functional" })
+ public void testValues()
+ {
+ UrlLinkTableModel m = new UrlLinkTableModel(prov);
+
+ // get original default
+ int olddefault;
+ boolean isDefault = false;
+ for (olddefault = 0; olddefault < m.getRowCount() && !isDefault; olddefault++)
+ {
+ isDefault = (boolean) m.getValueAt(olddefault, 3);
+ }
+
+ // set new values, one in each row
+ m.setValueAt("dbnamechanged", 6, 0);
+ m.setValueAt("descchanged", 6, 1);
+ m.setValueAt("urlchanged", 7, 2);
+ m.setValueAt(false, 8, 3);
+ m.setValueAt(true, 6, 4);
+
+ m.setValueAt("dbnamechanged", 5, 0);
+
+ // check values updated in table
+ Assert.assertEquals(m.getValueAt(6, 0), "descchanged"); // custom url can't
+ // change db name
+ Assert.assertEquals(m.getValueAt(6, 1), "descchanged");
+ Assert.assertEquals(m.getValueAt(7, 2), "urlchanged");
+ Assert.assertFalse((boolean) m.getValueAt(8, 3));
+ Assert.assertTrue((boolean) m.getValueAt(6, 4));
+ Assert.assertFalse((boolean) m.getValueAt(olddefault, 4));
+
+ Assert.assertEquals(m.getValueAt(5, 0), "dbnamechanged");
+
+ // check default row is exactly one row still
+ for (int row = 0; row < m.getRowCount(); row++)
+ {
+ isDefault = (boolean) m.getValueAt(row, 4);
+
+ // if isDefault is true, row is 9
+ // if isDefault is false, row is not 9
+ Assert.assertFalse(isDefault && !(row == 6));
+ }
+
+ // check table updated
+ Assert.assertTrue(prov.writeUrlsAsString(true).contains(
+ "descchanged" + SEP + m.getValueAt(6, 2)));
+ Assert.assertTrue(prov.writeUrlsAsString(true).contains(
+ m.getValueAt(7, 1) + SEP + "urlchanged"));
+ Assert.assertTrue(prov.writeUrlsAsString(false).contains(
+ (String) m.getValueAt(8, 1)));
+ Assert.assertEquals(prov.getPrimaryUrl("seqid"), m.getValueAt(6, 2)
+ .toString().replace(DELIM + SEQUENCE_ID + DELIM, "seqid"));
+ }
+
+ /*
+ * Test cell editability
+ */
+ @Test(groups = { "Functional" })
+ public void testEditable()
+ {
+ UrlLinkTableModel m = new UrlLinkTableModel(prov);
+
+ for (int row = 0; row < m.getRowCount(); row++)
+ {
+ Assert.assertFalse(m.isCellEditable(row, 0));
+ Assert.assertFalse(m.isCellEditable(row, 1));
+ Assert.assertFalse(m.isCellEditable(row, 2));
+ Assert.assertTrue(m.isCellEditable(row, 3));
+
+ if ((row == 4) || (row == 6) || (row == 7))
+ {
+ Assert.assertTrue(m.isCellEditable(row, 4));
+ }
+ else
+ {
+ Assert.assertFalse(m.isCellEditable(row, 4));
+ }
+ }
+ }
+
+ /*
+ * Test row 'deletability'
+ */
+ @Test(groups = { "Functional" })
+ public void testDeletable()
+ {
+ UrlLinkTableModel m = new UrlLinkTableModel(prov);
+
+ for (int row = 0; row < m.getRowCount(); row++)
+ {
+ if (row > 4)
+ {
+ Assert.assertTrue(m.isRowDeletable(row));
+ }
+ else
+ {
+ Assert.assertFalse(m.isRowDeletable(row));
+ }
+ }
+ }
+
+ /*
+ * Test indirect row editability
+ */
+ @Test(groups = { "Functional" })
+ public void testRowEditable()
+ {
+ UrlLinkTableModel m = new UrlLinkTableModel(prov);
+
+ for (int row = 0; row < m.getRowCount(); row++)
+ {
+ if (row > 3)
+ {
+ Assert.assertTrue(m.isRowEditable(row));
+ }
+ else
+ {
+ Assert.assertFalse(m.isRowEditable(row));
+ }
+ }
+ }
+}
--- /dev/null
+package jalview.urls;
+
+import jalview.urls.api.UrlProviderI;
+import jalview.urls.desktop.DesktopUrlProviderFactory;
+import jalview.util.UrlConstants;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.List;
+
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+
+public class UrlProviderTest {
+
+ // Test identifiers.org download file
+ private static final String testIdOrgString = "{\"Local\": [{\"id\":\"MIR:00000002\",\"name\":\"ChEBI\",\"pattern\":\"^CHEBI:\\d+$\","
+ + "\"definition\":\"Chemical Entities of Biological Interest (ChEBI)\",\"prefix\":\"chebi\","
+ + "\"url\":\"http://identifiers.org/chebi\"},{\"id\":\"MIR:00000005\",\"name\":\"UniProt Knowledgebase\","
+ + "\"pattern\":\"^([A-N,R-Z][0-9]([A-Z][A-Z, 0-9][A-Z, 0-9][0-9]){1,2})|([O,P,Q][0-9][A-Z, 0-9][A-Z, 0-9][A-Z, 0-9][0-9])(\\.\\d+)?$\","
+ + "\"definition\":\"The UniProt Knowledgebase (UniProtKB)\",\"prefix\":\"uniprot\",\"url\":\"http://identifiers.org/uniprot\"},"
+ + "{\"id\":\"MIR:00000011\",\"name\":\"InterPro\",\"pattern\":\"^IPR\\d{6}$\",\"definition\":\"InterPro\",\"prefix\":\"interpro\","
+ + "\"url\":\"http://identifiers.org/interpro\"},"
+ + "{\"id\":\"MIR:00000372\",\"name\":\"ENA\",\"pattern\":\"^[A-Z]+[0-9]+(\\.\\d+)?$\",\"definition\":\"The European Nucleotide Archive (ENA),\""
+ + "\"prefix\":\"ena.embl\",\"url\":\"http://identifiers.org/ena.embl\"}]}";
+
+ private UrlProviderI prov;
+
+ @BeforeMethod(alwaysRun = true)
+ public void setup()
+ {
+ // make a dummy identifiers.org download file
+ File temp = null;
+
+ try
+ {
+ temp = File.createTempFile("tempfile", ".tmp");
+ temp.deleteOnExit();
+ BufferedWriter bw = new BufferedWriter(new FileWriter(temp));
+ bw.write(testIdOrgString);
+ bw.close();
+ } catch (IOException e)
+ {
+ System.out.println("Error initialising UrlProviderTest test: "
+ + e.getMessage());
+ }
+
+ IdOrgSettings.setDownloadLocation(temp.getPath());
+
+ String defaultUrlString = "No default";
+ String cachedUrlList = "MIR:00000005|MIR:00000011|Test1|http://blah.blah/$SEQUENCE_ID$|"
+ + "Test2|http://test2/$DB_ACCESSION$|Test3|http://test3/$SEQUENCE_ID$";
+ String userUrlList = "MIR:00000372|Test4|httpL//another.url/$SEQUENCE_ID$";
+
+ DesktopUrlProviderFactory factory = new DesktopUrlProviderFactory(
+ defaultUrlString, cachedUrlList, userUrlList);
+ prov = factory.createUrlProvider();
+ }
+
+ @Test(groups = { "Functional" })
+ public void testInitUrlProvider()
+ {
+ String emblUrl = UrlConstants.DEFAULT_STRING.substring(
+ UrlConstants.DEFAULT_STRING.indexOf(UrlConstants.SEP) + 1,
+ UrlConstants.DEFAULT_STRING.length());
+
+ // chooses EMBL url when default Url id does not exist in provided url lists
+ Assert.assertEquals(prov.getPrimaryUrlId(), UrlConstants.DEFAULT_LABEL);
+ Assert.assertEquals(prov.getPrimaryUrl("FER_CAPAN"),
+ emblUrl.replace("$SEQUENCE_ID$", "FER_CAPAN"));
+
+ List<String> menulinks = prov.getLinksForMenu();
+ List<UrlLinkDisplay> allLinks = prov.getLinksForTable();
+
+ // 9 links in provider - 4 from id file, 4 custom links, 1 additional
+ // default
+ Assert.assertEquals(allLinks.size(), 9);
+
+ // 6 links in menu (cachedUrlList) + new default
+ Assert.assertEquals(menulinks.size(), 6);
+
+ Assert.assertTrue(menulinks
+ .contains("Test1|http://blah.blah/$SEQUENCE_ID$"));
+ Assert.assertTrue(menulinks
+ .contains("Test2|http://test2/$DB_ACCESSION$"));
+ Assert.assertTrue(menulinks
+ .contains("Test3|http://test3/$SEQUENCE_ID$"));
+ Assert.assertTrue(menulinks
+ .contains("UniProt Knowledgebase|http://identifiers.org/uniprot/$DB_ACCESSION$|uniprot"));
+ Assert.assertTrue(menulinks
+ .contains("InterPro|http://identifiers.org/interpro/$DB_ACCESSION$|interpro"));
+ Assert.assertTrue(menulinks.contains(UrlConstants.DEFAULT_LABEL
+ + UrlConstants.SEP + emblUrl));
+ }
+
+ @Test(groups = { "Functional" })
+ public void testSetDefaultUrl()
+ {
+ // set custom url as default
+ Assert.assertTrue(prov.setPrimaryUrl("Test1"));
+ Assert.assertEquals(prov.getPrimaryUrlId(), "Test1");
+
+ // set identifiers url as default
+ Assert.assertTrue(prov.setPrimaryUrl("MIR:00000011"));
+ Assert.assertEquals(prov.getPrimaryUrlId(), "MIR:00000011");
+ }
+
+ @Test(
+ groups = { "Functional" },
+ expectedExceptions = { IllegalArgumentException.class })
+ public void testSetDefaultUrlWrongly()
+ {
+ // don't allow default to be a non-key
+ prov.setPrimaryUrl("not-a-key");
+ }
+}
+ DELIM + URL_SUFFIX);
assertEquals(DB, ul.getTarget());
assertEquals(DB, ul.getLabel());
- assertEquals(URL_PREFIX, ul.getUrl_prefix());
- assertEquals(URL_SUFFIX, ul.getUrl_suffix());
+ assertEquals(URL_PREFIX, ul.getUrlPrefix());
+ assertEquals(URL_SUFFIX, ul.getUrlSuffix());
assertTrue(ul.isDynamic());
assertFalse(ul.usesDBAccession());
assertNull(ul.getRegexReplace());
+ URL_SUFFIX);
assertEquals(DB, ul.getTarget());
assertEquals(DB, ul.getLabel());
- assertEquals(URL_PREFIX, ul.getUrl_prefix());
- assertEquals(URL_SUFFIX, ul.getUrl_suffix());
+ assertEquals(URL_PREFIX, ul.getUrlPrefix());
+ assertEquals(URL_SUFFIX, ul.getUrlSuffix());
assertTrue(ul.isDynamic());
assertTrue(ul.usesDBAccession());
assertNull(ul.getRegexReplace());
ul = new UrlLink(DB + SEP + URL_PREFIX + URL_SUFFIX.substring(1));
assertEquals(DB, ul.getTarget());
assertEquals(DB, ul.getLabel());
- assertEquals(URL_PREFIX + URL_SUFFIX.substring(1), ul.getUrl_prefix());
+ assertEquals(URL_PREFIX + URL_SUFFIX.substring(1), ul.getUrlPrefix());
assertFalse(ul.isDynamic());
assertFalse(ul.usesDBAccession());
assertNull(ul.getRegexReplace());
+ REGEX_NESTED + DELIM + URL_SUFFIX);
assertEquals(DB, ul.getTarget());
assertEquals(DB, ul.getLabel());
- assertEquals(URL_PREFIX, ul.getUrl_prefix());
- assertEquals(URL_SUFFIX, ul.getUrl_suffix());
+ assertEquals(URL_PREFIX, ul.getUrlPrefix());
+ assertEquals(URL_SUFFIX, ul.getUrlSuffix());
assertTrue(ul.isDynamic());
assertFalse(ul.usesDBAccession());
assertEquals(REGEX_NESTED.substring(2, REGEX_NESTED.length() - 2),
+ REGEX_NESTED + DELIM + URL_SUFFIX);
assertEquals(DB, ul.getTarget());
assertEquals(DB, ul.getLabel());
- assertEquals(URL_PREFIX, ul.getUrl_prefix());
- assertEquals(URL_SUFFIX, ul.getUrl_suffix());
+ assertEquals(URL_PREFIX, ul.getUrlPrefix());
+ assertEquals(URL_SUFFIX, ul.getUrlSuffix());
assertTrue(ul.isDynamic());
assertTrue(ul.usesDBAccession());
assertEquals(REGEX_NESTED.substring(2, REGEX_NESTED.length() - 2),
+ REGEX_RUBBISH + DELIM + URL_SUFFIX);
assertEquals(DB, ul.getTarget());
assertEquals(DB, ul.getLabel());
- assertEquals(URL_PREFIX, ul.getUrl_prefix());
- assertEquals(URL_SUFFIX, ul.getUrl_suffix());
+ assertEquals(URL_PREFIX, ul.getUrlPrefix());
+ assertEquals(URL_SUFFIX, ul.getUrlSuffix());
assertTrue(ul.isDynamic());
assertTrue(ul.usesDBAccession());
assertEquals(REGEX_RUBBISH.substring(2, REGEX_RUBBISH.length() - 2),
String key = DB + SEP + URL_PREFIX;
assertEquals(1, linkset.size());
assertTrue(linkset.containsKey(key));
- assertEquals(linkset.get(key).get(0), DB);
- assertEquals(linkset.get(key).get(1), DB);
- assertEquals(linkset.get(key).get(2), null);
- assertEquals(linkset.get(key).get(3), URL_PREFIX);
+ assertEquals(DB, linkset.get(key).get(0));
+ assertEquals(DB, linkset.get(key).get(1));
+ assertEquals(null, linkset.get(key).get(2));
+ assertEquals(URL_PREFIX, linkset.get(key).get(3));
}
/**
String key = DB + SEP + URL_PREFIX + URL_SUFFIX;
assertEquals(1, linkset.size());
assertTrue(linkset.containsKey(key));
- assertEquals(linkset.get(key).get(0), DB);
- assertEquals(linkset.get(key).get(1), DB);
- assertEquals(linkset.get(key).get(2), null);
- assertEquals(linkset.get(key).get(3), URL_PREFIX + URL_SUFFIX);
+ assertEquals(DB, linkset.get(key).get(0));
+ assertEquals(DB, linkset.get(key).get(1));
+ assertEquals(null, linkset.get(key).get(2));
+ assertEquals(URL_PREFIX + URL_SUFFIX, linkset.get(key).get(3));
}
/**
+ URL_SUFFIX;
assertEquals(1, linkset.size());
assertTrue(linkset.containsKey(key));
- assertEquals(linkset.get(key).get(0), DB);
- assertEquals(linkset.get(key).get(1), DB);
- assertEquals(linkset.get(key).get(2), seq0.getName());
- assertEquals(linkset.get(key).get(3), URL_PREFIX + seq0.getName()
- + URL_SUFFIX);
+ assertEquals(DB, linkset.get(key).get(0));
+ assertEquals(DB, linkset.get(key).get(1));
+ assertEquals(seq0.getName(), linkset.get(key).get(2));
+ assertEquals(URL_PREFIX + seq0.getName() + URL_SUFFIX, linkset.get(key)
+ .get(3));
// Test where link takes a db annotation id and only has one dbref
ul = new UrlLink(links.get(1));
ul.createLinksFromSeq(seq0, linkset);
key = "P83527|http://www.uniprot.org/uniprot/P83527";
- assertEquals(1, linkset.size());
+ assertEquals(linkset.size(), 1);
assertTrue(linkset.containsKey(key));
- assertEquals(linkset.get(key).get(0), DBRefSource.UNIPROT);
- assertEquals(linkset.get(key).get(1), DBRefSource.UNIPROT + SEP
- + "P83527");
- assertEquals(linkset.get(key).get(2), "P83527");
- assertEquals(linkset.get(key).get(3),
- "http://www.uniprot.org/uniprot/P83527");
+ assertEquals(DBRefSource.UNIPROT, linkset.get(key).get(0));
+ assertEquals(DBRefSource.UNIPROT + SEP + "P83527", linkset.get(key)
+ .get(1));
+ assertEquals("P83527", linkset.get(key).get(2));
+ assertEquals("http://www.uniprot.org/uniprot/P83527", linkset.get(key)
+ .get(3));
// Test where link takes a db annotation id and has multiple dbrefs
ul = new UrlLink(links.get(2));
// check each link made it in correctly
key = "IPR001041|http://www.ebi.ac.uk/interpro/entry/IPR001041";
assertTrue(linkset.containsKey(key));
- assertEquals(linkset.get(key).get(0), "INTERPRO");
- assertEquals(linkset.get(key).get(1), "INTERPRO" + SEP + "IPR001041");
- assertEquals(linkset.get(key).get(2), "IPR001041");
- assertEquals(linkset.get(key).get(3),
- "http://www.ebi.ac.uk/interpro/entry/IPR001041");
+ assertEquals("INTERPRO", linkset.get(key).get(0));
+ assertEquals("INTERPRO" + SEP + "IPR001041", linkset.get(key).get(1));
+ assertEquals("IPR001041", linkset.get(key).get(2));
+ assertEquals("http://www.ebi.ac.uk/interpro/entry/IPR001041", linkset
+ .get(key).get(3));
key = "IPR006058|http://www.ebi.ac.uk/interpro/entry/IPR006058";
assertTrue(linkset.containsKey(key));
- assertEquals(linkset.get(key).get(0), "INTERPRO");
- assertEquals(linkset.get(key).get(1), "INTERPRO" + SEP + "IPR006058");
- assertEquals(linkset.get(key).get(2), "IPR006058");
- assertEquals(linkset.get(key).get(3),
- "http://www.ebi.ac.uk/interpro/entry/IPR006058");
+ assertEquals("INTERPRO", linkset.get(key).get(0));
+ assertEquals("INTERPRO" + SEP + "IPR006058", linkset.get(key).get(1));
+ assertEquals("IPR006058", linkset.get(key).get(2));
+ assertEquals("http://www.ebi.ac.uk/interpro/entry/IPR006058", linkset
+ .get(key).get(3));
key = "IPR012675|http://www.ebi.ac.uk/interpro/entry/IPR012675";
assertTrue(linkset.containsKey(key));
- assertEquals(linkset.get(key).get(0), "INTERPRO");
- assertEquals(linkset.get(key).get(1), "INTERPRO" + SEP + "IPR012675");
- assertEquals(linkset.get(key).get(2), "IPR012675");
- assertEquals(linkset.get(key).get(3),
- "http://www.ebi.ac.uk/interpro/entry/IPR012675");
+ assertEquals("INTERPRO", linkset.get(key).get(0));
+ assertEquals("INTERPRO" + SEP + "IPR012675", linkset.get(key).get(1));
+ assertEquals("IPR012675", linkset.get(key).get(2));
+ assertEquals("http://www.ebi.ac.uk/interpro/entry/IPR012675", linkset
+ .get(key).get(3));
// Test where there are no matching dbrefs for the link
ul = new UrlLink(DB + SEP + URL_PREFIX + DELIM + DB_ACCESSION + DELIM
assertTrue(linkset.isEmpty());
}
+ /**
+ * Test links where label and target are both included
+ */
+ @Test(groups = { "Functional" })
+ public void testLinksWithTargets()
+ {
+ UrlLink ul = new UrlLink(
+ "Protein Data Bank | http://www.identifiers.org/pdb/$"
+ + DB_ACCESSION + "$" + " | pdb");
+
+ assertEquals("Protein Data Bank", ul.getLabel());
+ assertEquals("pdb", ul.getTarget());
+ assertEquals("http://www.identifiers.org/pdb/$" + DB_ACCESSION + "$",
+ ul.getUrlWithToken());
+
+ assertEquals("Protein Data Bank|http://www.identifiers.org/pdb/$"
+ + DB_ACCESSION + "$" + "|pdb", ul.toStringWithTarget());
+
+ ul = new UrlLink("Protein Data Bank",
+ "http://www.identifiers.org/pdb/$" + DB_ACCESSION + "$", "pdb");
+
+ assertEquals("Protein Data Bank", ul.getLabel());
+ assertEquals("pdb", ul.getTarget());
+ assertEquals("http://www.identifiers.org/pdb/$" + DB_ACCESSION + "$",
+ ul.getUrlWithToken());
+
+ assertEquals("Protein Data Bank|http://www.identifiers.org/pdb/$"
+ + DB_ACCESSION + "$" + "|pdb", ul.toStringWithTarget());
+
+ }
+
}
--- /dev/null
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview 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.
+ *
+ * Jalview 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.viewmodel;
+
+import static org.testng.Assert.assertEquals;
+
+import jalview.analysis.AlignmentGenerator;
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceCollectionI;
+import jalview.datamodel.SequenceGroup;
+import jalview.datamodel.SequenceI;
+
+import java.util.Hashtable;
+
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+@Test(singleThreaded = true)
+public class OverviewDimensionsTest
+{
+ AlignmentI al;
+ OverviewDimensions od;
+
+ // cached widths and heights
+ int boxWidth;
+ int boxHeight;
+ int viewHeight;
+ int viewWidth;
+ int alheight;
+ int alwidth;
+
+ ViewportRanges vpranges;
+
+ Hashtable<SequenceI, SequenceCollectionI> hiddenRepSequences = new Hashtable<SequenceI, SequenceCollectionI>();
+
+ ColumnSelection hiddenCols = new ColumnSelection();
+
+ @BeforeClass(alwaysRun = true)
+ public void setUpJvOptionPane()
+ {
+ // create random alignment
+ AlignmentGenerator gen = new AlignmentGenerator(false);
+ al = gen.generate(157, 525, 123, 5, 5);
+ }
+
+ @BeforeMethod(alwaysRun = true)
+ public void setUp()
+ {
+ if (!hiddenRepSequences.isEmpty())
+ {
+ al.getHiddenSequences().showAll(hiddenRepSequences);
+ }
+ hiddenCols.revealAllHiddenColumns();
+
+ vpranges = new ViewportRanges(al);
+ vpranges.setStartRes(0);
+ vpranges.setEndRes(62);
+ vpranges.setStartSeq(0);
+ vpranges.setEndSeq(17);
+
+ viewHeight = vpranges.getEndSeq() - vpranges.getStartSeq() + 1;
+ viewWidth = vpranges.getEndRes() - vpranges.getStartRes() + 1;
+
+ ColumnSelection hiddenCols = new ColumnSelection();
+
+ od = new OverviewDimensions(vpranges, true);
+ // Initial box sizing - default path through code
+ od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges);
+
+ mouseClick(od, 0, 0);
+ moveViewport(0, 0);
+
+ // calculate before hidden columns so we get absolute values
+ alheight = vpranges.getAbsoluteAlignmentHeight();
+ alwidth = vpranges.getAbsoluteAlignmentWidth();
+
+ boxWidth = Math.round((float) (vpranges.getEndRes()
+ - vpranges.getStartRes() + 1)
+ * od.getWidth() / alwidth);
+ boxHeight = Math.round((float) (vpranges.getEndSeq()
+ - vpranges.getStartSeq() + 1)
+ * od.getSequencesHeight() / alheight);
+ }
+
+ @AfterClass(alwaysRun = true)
+ public void cleanUp()
+ {
+ al = null;
+ }
+
+ /**
+ * Test that the OverviewDimensions constructor sets width and height
+ * correctly
+ */
+ @Test(groups = { "Functional" })
+ public void testConstructor()
+ {
+ SequenceI seqa = new Sequence("Seq1", "ABC");
+ SequenceI seqb = new Sequence("Seq2", "ABC");
+ SequenceI seqc = new Sequence("Seq3", "ABC");
+ SequenceI seqd = new Sequence("Seq4", "ABC");
+ SequenceI seqe = new Sequence("Seq5",
+ "ABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+ int defaultGraphHeight = 20;
+ int maxWidth = 400;
+ int minWidth = 120;
+ int maxSeqHeight = 300;
+ int minSeqHeight = 40;
+
+ // test for alignment with width > height
+ SequenceI[] seqs1 = new SequenceI[] { seqa, seqb };
+ Alignment al1 = new Alignment(seqs1);
+ ViewportRanges props = new ViewportRanges(al1);
+
+ OverviewDimensions od = new OverviewDimensions(props, true);
+ int scaledHeight = 267;
+ assertEquals(od.getGraphHeight(), defaultGraphHeight);
+ assertEquals(od.getSequencesHeight(), scaledHeight);
+ assertEquals(od.getWidth(), maxWidth);
+ assertEquals(od.getHeight(), scaledHeight + defaultGraphHeight);
+
+ // test for alignment with width < height
+ SequenceI[] seqs2 = new SequenceI[] { seqa, seqb, seqc, seqd };
+ Alignment al2 = new Alignment(seqs2);
+ props = new ViewportRanges(al2);
+
+ od = new OverviewDimensions(props, true);
+ int scaledWidth = 300;
+ assertEquals(od.getGraphHeight(), defaultGraphHeight);
+ assertEquals(od.getSequencesHeight(), maxSeqHeight);
+ assertEquals(od.getWidth(), scaledWidth);
+ assertEquals(od.getHeight(), scaledWidth + defaultGraphHeight);
+
+ // test for alignment with width > height and sequence height scaled below
+ // min value
+ SequenceI[] seqs3 = new SequenceI[] { seqe };
+ Alignment al3 = new Alignment(seqs3);
+ props = new ViewportRanges(al3);
+
+ od = new OverviewDimensions(props, true);
+ assertEquals(od.getGraphHeight(), defaultGraphHeight);
+ assertEquals(od.getSequencesHeight(), minSeqHeight);
+ assertEquals(od.getWidth(), maxWidth);
+ assertEquals(od.getHeight(), minSeqHeight + defaultGraphHeight);
+
+ // test for alignment with width < height and width scaled below min value
+ SequenceI[] seqs4 = new SequenceI[] { seqa, seqb, seqc, seqd, seqa,
+ seqb, seqc, seqd, seqa, seqb, seqc, seqd, seqa, seqb, seqc, seqd };
+ Alignment al4 = new Alignment(seqs4);
+ props = new ViewportRanges(al4);
+
+ od = new OverviewDimensions(props, true);
+ assertEquals(od.getGraphHeight(), defaultGraphHeight);
+ assertEquals(od.getSequencesHeight(), maxSeqHeight);
+ assertEquals(od.getWidth(), minWidth);
+ assertEquals(od.getHeight(), maxSeqHeight + defaultGraphHeight);
+
+ Alignment al5 = new Alignment(seqs4);
+ props = new ViewportRanges(al5);
+
+ od = new OverviewDimensions(props, false);
+ assertEquals(od.getGraphHeight(), 0);
+ assertEquals(od.getSequencesHeight(), maxSeqHeight);
+ assertEquals(od.getWidth(), minWidth);
+ assertEquals(od.getHeight(), maxSeqHeight);
+ }
+
+ /**
+ * Test that validation after mouse adjustments to boxX and boxY sets box
+ * dimensions and scroll values correctly, when there are no hidden rows or
+ * columns.
+ */
+ @Test(groups = { "Functional" })
+ public void testSetBoxFromMouseClick()
+ {
+ od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols,
+ vpranges);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getScrollCol(), 0);
+ assertEquals(od.getScrollRow(), 0);
+
+ // negative boxX value reset to 0
+ mouseClick(od, -5, 10);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ assertEquals(od.getScrollRow(),
+ Math.round((float) 10 * alheight / od.getSequencesHeight()));
+ assertEquals(od.getScrollCol(), 0);
+
+ // negative boxY value reset to 0
+ mouseClick(od, 6, -2);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ assertEquals(od.getScrollCol(),
+ Math.round((float) 6 * alwidth / od.getWidth()));
+ assertEquals(od.getScrollRow(), 0);
+
+ // overly large boxX value reset to width-boxWidth
+ mouseClick(od, 100, 6);
+ assertEquals(od.getBoxX(), od.getWidth() - od.getBoxWidth());
+ assertEquals(od.getBoxY(), 6);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ assertEquals(od.getScrollCol(),
+ Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
+ assertEquals(od.getScrollRow(),
+ Math.round((float) od.getBoxY() * alheight
+ / od.getSequencesHeight()));
+
+ // overly large boxY value reset to sequenceHeight - boxHeight
+ mouseClick(od, 10, 520);
+ assertEquals(od.getBoxX(), 10);
+ assertEquals(od.getBoxY(), od.getSequencesHeight() - od.getBoxHeight());
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ assertEquals(od.getScrollCol(),
+ Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
+
+ // here (float) od.getBoxY() * alheight / od.getSequencesHeight() = 507.5
+ // and round rounds to 508; however we get 507 working with row values
+ // hence the subtraction of 1
+ assertEquals(od.getScrollRow(),
+ Math.round((float) od.getBoxY() * alheight
+ / od.getSequencesHeight()) - 1);
+
+ // click past end of alignment, as above
+ mouseClick(od, 3000, 5);
+ assertEquals(od.getBoxX(), od.getWidth() - od.getBoxWidth());
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ assertEquals(od.getScrollCol(),
+ Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
+ assertEquals(od.getScrollRow(),
+ Math.round((float) od.getBoxY() * alheight
+ / od.getSequencesHeight()));
+
+ // move viewport so startRes non-zero and then mouseclick
+ moveViewportH(50);
+
+ // click at viewport position
+ int oldboxx = od.getBoxX();
+ int oldboxy = od.getBoxY();
+ mouseClick(od, od.getBoxX() + 5, od.getBoxY() + 2);
+ assertEquals(od.getBoxX(), oldboxx + 5);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ assertEquals(od.getScrollCol(),
+ Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
+ assertEquals(od.getBoxY(), oldboxy + 2);
+ assertEquals(od.getScrollRow(),
+ Math.round((float) od.getBoxY() * alheight
+ / od.getSequencesHeight()));
+
+ // click at top corner
+ mouseClick(od, 0, 0);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getScrollCol(), 0);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getScrollRow(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ }
+
+ /**
+ * Test setting of the box position, when there are hidden cols at the start
+ * of the alignment
+ */
+ @Test(groups = { "Functional" })
+ public void testFromMouseWithHiddenColsAtStart()
+ {
+ od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols,
+ vpranges);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getScrollCol(), 0);
+ assertEquals(od.getScrollRow(), 0);
+
+ // hide cols at start and check updated box position is correct
+ // changes boxX but not boxwidth
+ int lastHiddenCol = 30;
+ hiddenCols.hideColumns(0, lastHiddenCol);
+
+ od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges);
+ assertEquals(od.getBoxX(),
+ Math.round((float) (lastHiddenCol + 1) * od.getWidth()
+ / alwidth));
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ // try to click in hidden cols, check box does not move
+ int xpos = 10;
+ mouseClick(od, xpos, 0);
+ assertEquals(
+ od.getBoxX(),
+ Math.round((float) (lastHiddenCol + 1) * od.getWidth()
+ / alwidth));
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ assertEquals(od.getScrollRow(), 0);
+ assertEquals(od.getScrollCol(), 0);
+
+ // click to right of hidden columns, box moves to click point
+ testBoxIsAtClickPoint(40, 0);
+ assertEquals(od.getScrollRow(), 0);
+ assertEquals(od.getScrollCol(),
+ Math.round((float) 40 * alwidth / od.getWidth())
+ - (lastHiddenCol + 1));
+
+ // click to right of hidden columns such that box runs over right hand side
+ // of alignment
+ // box position is adjusted away from the edge
+ // overly large boxX value reset to width-boxWidth
+ xpos = 100;
+ mouseClick(od, xpos, 5);
+ assertEquals(od.getBoxX(), od.getWidth() - od.getBoxWidth());
+ assertEquals(od.getBoxY(), 5);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ assertEquals(od.getScrollCol(),
+ Math.round((float) od.getBoxX() * alwidth / od.getWidth())
+ - (lastHiddenCol + 1));
+ assertEquals(od.getScrollRow(),
+ Math.round((float) od.getBoxY() * alheight
+ / od.getSequencesHeight()));
+ }
+
+ /**
+ * Test setting of the box position, when there are hidden cols in the middle
+ * of the alignment
+ */
+ @Test(groups = { "Functional" })
+ public void testFromMouseWithHiddenColsInMiddle()
+ {
+ od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols,
+ vpranges);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getScrollCol(), 0);
+ assertEquals(od.getScrollRow(), 0);
+
+ // hide columns 63-73, no change to box position or dimensions
+ int firstHidden = 63;
+ int lastHidden = 73;
+ hiddenCols.hideColumns(firstHidden, lastHidden);
+
+ od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getScrollCol(), 0);
+ assertEquals(od.getScrollRow(), 0);
+
+ // move box so that it overlaps with hidden cols on one side
+ // box width changes, boxX and scrollCol as for unhidden case
+ int xpos = 55 - boxWidth; // 55 is position in overview approx halfway
+ // between cols 60 and 70
+ mouseClick(od, xpos, 0);
+ assertEquals(od.getBoxX(), xpos);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(
+ od.getBoxWidth(),
+ Math.round(boxWidth + (float) (lastHidden - firstHidden + 1)
+ * od.getWidth() / alwidth));
+ assertEquals(od.getBoxHeight(), boxHeight);
+ assertEquals(od.getScrollCol(),
+ Math.round(xpos * alwidth / od.getWidth()));
+ assertEquals(od.getScrollRow(), 0);
+
+ // move box so that it completely covers hidden cols
+ // box width changes, boxX and scrollCol as for hidden case
+ xpos = 33;
+ mouseClick(od, xpos, 0);
+ assertEquals(od.getBoxX(), xpos);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(
+ od.getBoxWidth(),
+ Math.round(boxWidth + (float) (lastHidden - firstHidden + 1)
+ * od.getWidth() / alwidth));
+ assertEquals(od.getBoxHeight(), boxHeight);
+ assertEquals(od.getScrollCol(),
+ Math.round((float) xpos * alwidth / od.getWidth()));
+ assertEquals(od.getScrollRow(), 0);
+
+ // move box so boxX is in hidden cols, box overhangs at right
+ // boxX and scrollCol at left of hidden area, box width extends across
+ // hidden region
+ xpos = 50;
+ mouseClick(od, xpos, 0);
+ assertEquals(od.getBoxX(),
+ Math.round((float) (firstHidden - 1) * od.getWidth() / alwidth));
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(
+ od.getBoxWidth(),
+ boxWidth
+ + Math.round((float) (lastHidden - firstHidden + 1)
+ * od.getWidth() / alwidth));
+ assertEquals(od.getBoxHeight(), boxHeight);
+ assertEquals(od.getScrollCol(), firstHidden - 1);
+ assertEquals(od.getScrollRow(), 0);
+
+ // move box so boxX is to right of hidden cols, but does not go beyond full
+ // width of alignment
+ // box width, boxX and scrollCol all as for non-hidden case
+ xpos = 75;
+ testBoxIsAtClickPoint(xpos, 0);
+ assertEquals(od.getScrollRow(), 0);
+ assertEquals(od.getScrollCol(),
+ Math.round(xpos * alwidth / od.getWidth())
+ - (lastHidden - firstHidden + 1));
+
+ // move box so it goes beyond full width of alignment
+ // boxX, scrollCol adjusted back, box width normal
+ xpos = 3000;
+ mouseClick(od, xpos, 5);
+ assertEquals(od.getBoxX(), od.getWidth() - od.getBoxWidth());
+ assertEquals(od.getBoxY(), 5);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ assertEquals(od.getScrollCol(),
+ Math.round(((float) od.getBoxX() * alwidth / od.getWidth())
+ - (lastHidden - firstHidden + 1)));
+ assertEquals(od.getScrollRow(),
+ Math.round((float) od.getBoxY() * alheight
+ / od.getSequencesHeight()));
+
+ }
+
+ /**
+ * Test setting of the box position, when there are hidden cols at the end of
+ * the alignment
+ */
+ @Test(groups = { "Functional" })
+ public void testFromMouseWithHiddenColsAtEnd()
+ {
+ od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols,
+ vpranges);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getScrollCol(), 0);
+ assertEquals(od.getScrollRow(), 0);
+
+ // hide columns 140-164, no change to box position or dimensions
+ int firstHidden = 140;
+ int lastHidden = 164;
+ hiddenCols.hideColumns(firstHidden, lastHidden);
+ od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getScrollCol(), 0);
+ assertEquals(od.getScrollRow(), 0);
+
+ // click to left of hidden cols, without overlapping
+ // boxX, scrollCol and width as normal
+ int xpos = 5;
+ testBoxIsAtClickPoint(xpos, 0);
+ assertEquals(od.getScrollRow(), 0);
+ assertEquals(od.getScrollCol(),
+ Math.round((float) xpos * alwidth / od.getWidth()));
+
+ // click to left of hidden cols, with overlap
+ // boxX and scrollCol adjusted for hidden cols, width normal
+ xpos = Math.round((float) 145 * od.getWidth() / alwidth) - boxWidth;
+ mouseClick(od, xpos, 0);
+ assertEquals(od.getBoxX(),
+ Math.round((float) (firstHidden - 1) * od.getWidth() / alwidth)
+ - boxWidth + 1);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ assertEquals(od.getScrollCol(),
+ Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
+ assertEquals(od.getScrollRow(), 0);
+
+ // click in hidden cols
+ // boxX and scrollCol adjusted for hidden cols, width normal
+ xpos = 115;
+ assertEquals(od.getBoxX(),
+ Math.round((float) (firstHidden - 1) * od.getWidth() / alwidth)
+ - boxWidth + 1);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ assertEquals(od.getScrollCol(),
+ Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
+ assertEquals(od.getScrollRow(), 0);
+
+ // click off end of alignment
+ // boxX and scrollCol adjusted for hidden cols, width normal
+ xpos = 3000;
+ assertEquals(od.getBoxX(),
+ Math.round((float) (firstHidden - 1) * od.getWidth() / alwidth)
+ - boxWidth + 1);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ assertEquals(od.getScrollCol(),
+ Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
+ assertEquals(od.getScrollRow(), 0);
+ }
+
+ /**
+ * Test that the box position is set correctly when set from the viewport,
+ * with no hidden rows or columns
+ */
+ @Test(groups = { "Functional" })
+ public void testSetBoxFromViewport()
+ {
+ // move viewport to start of alignment
+ moveViewport(0, 0);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ // move viewport to right
+ moveViewportH(70);
+ assertEquals(od.getBoxX(),
+ Math.round((float) 70 * od.getWidth() / alwidth));
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ // move viewport down
+ moveViewportV(100);
+ assertEquals(od.getBoxX(),
+ Math.round((float) 70 * od.getWidth() / alwidth));
+ assertEquals(od.getBoxY(),
+ Math.round(100 * od.getSequencesHeight() / alheight));
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ // move viewport to bottom right
+ moveViewport(98, 508);
+ assertEquals(od.getBoxX(),
+ Math.round((float) 98 * od.getWidth() / alwidth));
+ assertEquals(od.getBoxY(),
+ Math.round((float) 508 * od.getSequencesHeight() / alheight));
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ }
+
+ /**
+ * Test that the box position is set correctly when there are hidden columns
+ * at the start
+ */
+ @Test(groups = { "Functional" })
+ public void testSetBoxFromViewportHiddenColsAtStart()
+ {
+ int firstHidden = 0;
+ int lastHidden = 20;
+ hiddenCols.hideColumns(firstHidden, lastHidden);
+
+ // move viewport to start of alignment
+ moveViewport(0, 0);
+ assertEquals(od.getBoxX(),
+ Math.round((float) (lastHidden + 1) * od.getWidth() / alwidth));
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ // move viewport to end of alignment - need to make startRes by removing
+ // hidden cols because of how viewport/overview are implemented
+ moveViewport(98 - lastHidden - 1, 0);
+ assertEquals(od.getBoxX(),
+ Math.round((float) 98 * od.getWidth() / alwidth));
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ }
+
+ /**
+ * Test that the box position is set correctly when there are hidden columns
+ * in the middle
+ */
+ @Test(groups = { "Functional" })
+ public void testSetBoxFromViewportHiddenColsInMiddle()
+ {
+ int firstHidden = 68;
+ int lastHidden = 78;
+ hiddenCols.hideColumns(firstHidden, lastHidden);
+
+ // move viewport before hidden columns
+ moveViewport(3, 0);
+
+ assertEquals(od.getBoxX(),
+ Math.round((float) 3 * od.getWidth() / alwidth));
+ assertEquals(od.getBoxY(), 0);
+ System.out.println(od.getBoxWidth());
+ assertEquals(od.getBoxWidth(), boxWidth);
+ System.out.println(od.getBoxWidth());
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ // move viewport to left of hidden columns with overlap
+ moveViewport(10, 0);
+ assertEquals(od.getBoxX(),
+ Math.round((float) 10 * od.getWidth() / alwidth));
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(
+ od.getBoxWidth(),
+ boxWidth
+ + Math.round((float) (lastHidden - firstHidden + 1)
+ * od.getWidth() / alwidth));
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ // move viewport to straddle hidden columns
+ moveViewport(63, 0);
+ assertEquals(od.getBoxX(),
+ Math.round((float) 63 * od.getWidth() / alwidth));
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(
+ od.getBoxWidth(),
+ boxWidth
+ + Math.round((lastHidden - firstHidden + 1)
+ * od.getWidth() / alwidth));
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ // move viewport to right of hidden columns, no overlap
+ moveViewport(80 - (lastHidden - firstHidden + 1), 0);
+ assertEquals(od.getBoxX(),
+ Math.round((float) 80 * od.getWidth() / alwidth));
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ }
+
+ /**
+ * Test that the box position is set correctly when there are hidden columns
+ * at the end
+ */
+ @Test(groups = { "Functional" })
+ public void testSetBoxFromViewportHiddenColsAtEnd()
+ {
+ int firstHidden = 152;
+ int lastHidden = 164;
+ hiddenCols.hideColumns(firstHidden, lastHidden);
+
+ // move viewport before hidden columns
+ moveViewport(3, 0);
+ assertEquals(od.getBoxX(),
+ Math.round((float) 3 * od.getWidth() / alwidth));
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ // move viewport to hidden columns
+ // viewport can't actually extend into hidden cols,
+ // so move to the far right edge of the viewport
+ moveViewport(firstHidden - viewWidth, 0);
+ assertEquals(od.getBoxX(),
+ Math.round((float) (firstHidden - viewWidth)
+ * od.getWidth() / alwidth));
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ }
+
+ /**
+ * Test that the box position is set correctly when there are hidden rows at
+ * the start
+ */
+ @Test(groups = { "Functional" })
+ public void testSetBoxFromViewportHiddenRowsAtStart()
+ {
+ int firstHidden = 0;
+ int lastHidden = 20;
+ hideSequences(firstHidden, lastHidden);
+
+ // move viewport to start of alignment:
+ // box moves to below hidden rows, height remains same
+ moveViewport(0, 0);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(),
+ Math.round((float) (lastHidden + 1) * od.getSequencesHeight()
+ / alheight));
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ // move viewport to end of alignment
+ moveViewport(0, 525 - viewHeight - lastHidden - 1);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(
+ od.getBoxY(),
+ Math.round((float) (525 - viewHeight) * od.getSequencesHeight()
+ / alheight));
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ }
+
+ /**
+ * Test that the box position is set correctly when there are hidden rows in
+ * the middle
+ */
+ @Test(groups = { "Functional" })
+ public void testSetBoxFromViewportHiddenRowsInMiddle()
+ {
+ int firstHidden = 200;
+ int lastHidden = 210;
+ hideSequences(firstHidden, lastHidden);
+
+ // move viewport to start of alignment:
+ // box, height etc as in non-hidden case
+ moveViewport(0, 0);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ // move viewport to straddle hidden rows
+ moveViewport(0, 198);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(), Math.round ((float)198 * od.getSequencesHeight()
+ / alheight));
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(
+ od.getBoxHeight(),
+ Math.round((float) (viewHeight + lastHidden - firstHidden + 1)
+ * od.getSequencesHeight() / alheight));
+ }
+
+ /**
+ * Test that the box position is set correctly when there are hidden rows at
+ * the bottom
+ */
+ @Test(groups = { "Functional" })
+ public void testSetBoxFromViewportHiddenRowsAtEnd()
+ {
+ int firstHidden = 500;
+ int lastHidden = 524;
+ hideSequences(firstHidden, lastHidden);
+
+ // move viewport to start of alignment:
+ // box, height etc as in non-hidden case
+ moveViewport(0, 0);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ // move viewport to end of alignment
+ // viewport sits above hidden rows and does not include them
+ moveViewport(0, firstHidden - viewHeight - 1);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(
+ od.getBoxY(),
+ Math.round((float) (firstHidden - viewHeight - 1)
+ * od.getSequencesHeight() / alheight));
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ }
+
+ /**
+ * Test setting of the box position, when there are hidden rows at the start
+ * of the alignment
+ */
+ @Test(groups = { "Functional" })
+ public void testFromMouseWithHiddenRowsAtStart()
+ {
+ od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols,
+ vpranges);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getScrollCol(), 0);
+ assertEquals(od.getScrollRow(), 0);
+
+ // hide rows at start and check updated box position is correct
+ // changes boxY but not boxheight
+ int lastHiddenRow = 30;
+ hideSequences(0, lastHiddenRow);
+
+ od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(),
+ Math.round((float) (lastHiddenRow + 1)
+ * od.getSequencesHeight() / alheight));
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ // click in hidden rows - same result
+ mouseClick(od, 0, 0);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(
+ od.getBoxY(),
+ Math.round((float) (lastHiddenRow + 1)
+ * od.getSequencesHeight() / alheight));
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ // click below hidden rows
+ mouseClick(od, 0, 150);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(), 150);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ }
+
+ /**
+ * Test setting of the box position, when there are hidden rows at the middle
+ * of the alignment
+ */
+ @Test(groups = { "Functional" })
+ public void testFromMouseWithHiddenRowsInMiddle()
+ {
+ od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols,
+ vpranges);
+
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ assertEquals(od.getScrollCol(), 0);
+ assertEquals(od.getScrollRow(), 0);
+
+ // hide rows in middle and check updated box position is correct
+ // no changes
+ int firstHiddenRow = 50;
+ int lastHiddenRow = 54;
+ hideSequences(firstHiddenRow, lastHiddenRow);
+
+ od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges);
+
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ // click above hidden rows, so that box overlaps
+ int ypos = 35; // column value in residues
+ mouseClick(od, 0,
+ Math.round((float) ypos * od.getSequencesHeight() / alheight));
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(),
+ Math.round((float) ypos * od.getSequencesHeight() / alheight));
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(
+ od.getBoxHeight(),
+ boxHeight
+ + Math.round((float) (lastHiddenRow - firstHiddenRow + 1)
+ * od.getSequencesHeight() / alheight));
+
+ // click so that box straddles hidden rows
+ ypos = 44; // column value in residues
+ mouseClick(od, 0,
+ Math.round((float) ypos * od.getSequencesHeight() / alheight));
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(),
+ Math.round((float) ypos * od.getSequencesHeight() / alheight));
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(
+ od.getBoxHeight(),
+ boxHeight
+ + Math.round((float) (lastHiddenRow - firstHiddenRow + 1)
+ * od.getSequencesHeight() / alheight));
+ }
+
+ /**
+ * Test setting of the box position, when there are hidden rows at the end of
+ * the alignment
+ */
+ @Test(groups = { "Functional" })
+ public void testFromMouseWithHiddenRowsAtEnd()
+ {
+ od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols,
+ vpranges);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ assertEquals(od.getScrollCol(), 0);
+ assertEquals(od.getScrollRow(), 0);
+
+ // hide rows at end and check updated box position is correct
+ // no changes
+ int firstHidden = 500;
+ int lastHidden = 524;
+ hideSequences(firstHidden, lastHidden);
+
+ od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ // click above hidden rows
+ int ypos = 40; // row 40
+ mouseClick(od, 0,
+ Math.round((float) ypos * od.getSequencesHeight() / alheight));
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(),
+ Math.round((float) ypos * od.getSequencesHeight() / alheight));
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ // click above hidden rows so box overlaps
+ // boxY moved upwards, boxHeight remains same
+ ypos = 497; // row 497
+ mouseClick(od, 0,
+ Math.round((float) ypos * od.getSequencesHeight() / alheight));
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(
+ od.getBoxY(),
+ Math.round((float) (firstHidden - viewHeight)
+ * od.getSequencesHeight() / alheight));
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ // click within hidden rows
+ ypos = 505;
+ mouseClick(od, 0,
+ Math.round((float) ypos * od.getSequencesHeight() / alheight));
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(
+ od.getBoxY(),
+ Math.round((firstHidden - viewHeight) * od.getSequencesHeight()
+ / alheight));
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ }
+
+ /*
+ * Move viewport horizontally: startRes + previous width gives new horizontal extent. Vertical extent stays the same.
+ */
+ private void moveViewportH(int startRes)
+ {
+ vpranges.setStartRes(startRes);
+ vpranges.setEndRes(startRes + viewWidth - 1);
+ od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges);
+ }
+
+ /*
+ * Move viewport vertically: startSeq and endSeq give new vertical extent. Horizontal extent stays the same.
+ */
+ private void moveViewportV(int startSeq)
+ {
+ vpranges.setStartSeq(startSeq);
+ vpranges.setEndSeq(startSeq + viewHeight - 1);
+ od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges);
+ }
+
+ /*
+ * Move viewport horizontally and vertically.
+ */
+ private void moveViewport(int startRes, int startSeq)
+ {
+ vpranges.setStartRes(startRes);
+ vpranges.setEndRes(startRes + viewWidth - 1);
+ vpranges.setStartSeq(startSeq);
+ vpranges.setEndSeq(startSeq + viewHeight - 1);
+ od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges);
+ }
+
+ /*
+ * Mouse click as position x,y in overview window
+ */
+ private void mouseClick(OverviewDimensions od, int x, int y)
+ {
+ od.updateViewportFromMouse(x, y, al.getHiddenSequences(), hiddenCols,
+ vpranges);
+
+ // updates require an OverviewPanel to exist which it doesn't here
+ // so call setBoxPosition() as it would be called by the AlignmentPanel
+ // normally
+
+ vpranges.setStartRes(od.getScrollCol());
+ vpranges.setEndRes(od.getScrollCol() + viewWidth - 1);
+ vpranges.setStartSeq(od.getScrollRow());
+ vpranges.setEndSeq(od.getScrollRow() + viewHeight - 1);
+ od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges);
+ }
+
+ /*
+ * Test that the box is positioned with the top left corner at xpos, ypos
+ * and with the original width and height
+ */
+ private void testBoxIsAtClickPoint(int xpos, int ypos)
+ {
+ mouseClick(od, xpos, ypos);
+ assertEquals(od.getBoxX(), xpos);
+ assertEquals(od.getBoxY(), ypos);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ }
+
+ /*
+ * Hide sequences between start and end
+ */
+ private void hideSequences(int start, int end)
+ {
+ SequenceI[] allseqs = al.getSequencesArray();
+ SequenceGroup theseSeqs = new SequenceGroup();
+
+ for (int i = start; i <= end; i++)
+ {
+ theseSeqs.addSequence(allseqs[i], false);
+ al.getHiddenSequences().hideSequence(allseqs[i]);
+ }
+
+ hiddenRepSequences.put(allseqs[start], theseSeqs);
+ }
+}
--- /dev/null
+package jalview.viewmodel;
+
+import static org.testng.Assert.assertEquals;
+
+import jalview.analysis.AlignmentGenerator;
+import jalview.datamodel.AlignmentI;
+
+import org.testng.annotations.Test;
+
+public class ViewportRangesTest {
+
+ AlignmentGenerator gen = new AlignmentGenerator(false);
+
+ AlignmentI al = gen.generate(20, 30, 1, 5, 5);
+
+ @Test
+ public void testViewportRanges()
+ {
+ ViewportRanges vr = new ViewportRanges(al);
+
+ assertEquals(vr.getStartRes(),0);
+ assertEquals(vr.getEndRes(), al.getWidth()-1);
+ assertEquals(vr.getStartSeq(), 0);
+ assertEquals(vr.getEndSeq(), al.getHeight() - 1);
+ }
+
+ @Test
+ public void testGetAbsoluteAlignmentHeight()
+ {
+ ViewportRanges vr = new ViewportRanges(al);
+
+ assertEquals(vr.getAbsoluteAlignmentHeight(), al.getHeight());
+
+ al.getHiddenSequences().hideSequence(al.getSequenceAt(3));
+ assertEquals(vr.getAbsoluteAlignmentHeight(), al.getHeight() + 1);
+ }
+
+ @Test
+ public void testGetAbsoluteAlignmentWidth()
+ {
+ ViewportRanges vr = new ViewportRanges(al);
+ assertEquals(vr.getAbsoluteAlignmentWidth(), al.getWidth());
+ }
+
+ @Test
+ public void testSetEndRes()
+ {
+ ViewportRanges vr = new ViewportRanges(al);
+ vr.setEndRes(-1);
+ assertEquals(vr.getEndRes(), 0);
+
+ vr.setEndRes(al.getWidth());
+ assertEquals(vr.getEndRes(), al.getWidth() - 1);
+
+ vr.setEndRes(al.getWidth() - 1);
+ assertEquals(vr.getEndRes(), al.getWidth() - 1);
+ }
+
+ @Test
+ public void testSetEndSeq()
+ {
+ ViewportRanges vr = new ViewportRanges(al);
+ vr.setEndSeq(-1);
+ assertEquals(vr.getEndSeq(), 0);
+
+ vr.setEndSeq(al.getHeight());
+ assertEquals(vr.getEndSeq(), al.getHeight() - 1);
+
+ vr.setEndRes(al.getHeight() - 1);
+ assertEquals(vr.getEndSeq(), al.getHeight() - 1);
+ }
+
+ @Test
+ public void testSetStartRes()
+ {
+ ViewportRanges vr = new ViewportRanges(al);
+ vr.setStartRes(-1);
+ assertEquals(vr.getStartRes(), 0);
+
+ vr.setStartRes(al.getWidth());
+ assertEquals(vr.getStartRes(), al.getWidth() - 1);
+
+ vr.setStartRes(al.getWidth() - 1);
+ assertEquals(vr.getStartRes(), al.getWidth() - 1);
+ }
+
+ @Test
+ public void testSetStartSeq()
+ {
+ ViewportRanges vr = new ViewportRanges(al);
+ vr.setStartSeq(-1);
+ assertEquals(vr.getStartSeq(), 0);
+
+ vr.setStartSeq(al.getHeight());
+ assertEquals(vr.getStartSeq(), al.getHeight() - 1);
+
+ vr.setStartSeq(al.getHeight() - 1);
+ assertEquals(vr.getStartSeq(), al.getHeight() - 1);
+ }
+}
*/
package jalview.ws.seqfetcher;
+import static org.testng.Assert.assertTrue;
+
+import jalview.bin.Cache;
import jalview.gui.JvOptionPane;
-import org.testng.AssertJUnit;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
}
- @Test(groups = { "Functional" })
+ @Test(groups = { "Network" })
public void testDasRegistryContact()
{
- jalview.bin.Cache.getDasSourceRegistry().refreshSources();
- AssertJUnit
- .assertTrue(
- "Expected to find at least one DAS source at the registry. Check config.",
- jalview.bin.Cache.getDasSourceRegistry().getSources()
- .size() > 0);
+ Cache.getDasSourceRegistry().refreshSources();
+ assertTrue(Cache.getDasSourceRegistry().getSources().isEmpty(),
+ "Expected to find no DAS sources at the registry. Check config.");
}
}
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
import org.testng.Assert;
import org.testng.FileAssert;
"A", testSeq, null);
Assert.assertEquals(testSeq.getStart(), 1);
Assert.assertEquals(testSeq.getEnd(), 147);
- Assert.assertEquals(actualMapping, expectedMapping);
+ // Can't do Assert.assertEquals(actualMapping, expectedMapping);
+ // because this fails in our version of TestNG
+ Assert.assertEquals(actualMapping.size(), expectedMapping.size());
+ Iterator<Map.Entry<Integer, int[]>> it = expectedMapping.entrySet()
+ .iterator();
+ while (it.hasNext())
+ {
+ Map.Entry<Integer, int[]> pair = it.next();
+ Assert.assertTrue(actualMapping.containsKey(pair.getKey()));
+ Assert.assertEquals(actualMapping.get(pair.getKey()),
+ pair.getValue());
+ }
+
} catch (Exception e)
{
e.printStackTrace();
Assert.assertEquals(strucMapping.getMappingDetailsOutput(),
expectedMappingOutput);
- Assert.assertEquals(strucMapping.getMapping(), expectedMapping);
+
+ // Can't do Assert.assertEquals(strucMapping.getMapping(), expectedMapping);
+ // because this fails in our version of TestNG
+ Assert.assertEquals(strucMapping.getMapping().size(),
+ expectedMapping.size());
+ Iterator<Map.Entry<Integer, int[]>> it = expectedMapping.entrySet()
+ .iterator();
+ while (it.hasNext())
+ {
+ Map.Entry<Integer, int[]> pair = it.next();
+ Assert.assertTrue(strucMapping.getMapping()
+ .containsKey(pair.getKey()));
+ Assert.assertEquals(strucMapping.getMapping().get(pair.getKey()),
+ pair.getValue());
+ }
}
@Test(groups = { "Network" })
--- /dev/null
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview 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.
+ *
+ * Jalview 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.ws.utils;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+public class UrlDownloadClientTest {
+
+ /**
+ * Test that url is successfully loaded into download file
+ */
+ @Test(groups = { "Network" }, enabled = true)
+ public void UrlDownloadTest()
+ {
+ UrlDownloadClient client = new UrlDownloadClient();
+ String urlstring = "http://identifiers.org/rest/collections/";
+ String outfile = "testfile.tmp";
+
+ try
+ {
+ client.download(urlstring, outfile);
+ } catch (IOException e)
+ {
+ Assert.fail("Exception was thrown from UrlDownloadClient download: "
+ + e.getMessage());
+ File f = new File(outfile);
+ if (f.exists())
+ {
+ f.delete();
+ }
+ }
+
+ // download file exists
+ File f = new File(outfile);
+ Assert.assertTrue(f.exists());
+
+ // download file has a believable size
+ // identifiers.org file typically at least 250K
+ Assert.assertTrue(f.length() > 250000);
+
+ if (f.exists())
+ {
+ f.delete();
+ }
+
+ }
+
+ /**
+ * Test that garbage in results in IOException
+ */
+ @Test(
+ groups = { "Network" },
+ enabled = true,
+ expectedExceptions = { IOException.class })
+ public void DownloadGarbageUrlTest() throws IOException
+ {
+ UrlDownloadClient client = new UrlDownloadClient();
+ String urlstring = "identifiers.org/rest/collections/";
+ String outfile = "testfile.tmp";
+
+ client.download(urlstring, outfile);
+ }
+}