/* BLIXEM - BLast matches In an X-windows Embedded Multiple alignment ------------------------------------------------------------- * Acedb 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 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * or see the on-line version at http://www.gnu.org/copyleft/gpl.txt * ------------------------------------------------------------- | File: blxview.c | | Author: Erik.Sonnhammer | | Copyright (C) E Sonnhammer 1993-1997 | ------------------------------------------------------------- * * Exported functions: See wh/blxview.h * HISTORY: * Last edited: Mar 3 10:45 2004 (edgrif) * * Jan 10 10:35 2002 (edgrif): Fix up socket code and add various * options for better sequence display. * previous mods: Date Modification -------- --------------------------------------------------- 93-02-20 Created 93-05-25 Dispstart/dispend fix by Richard for seq's < displen. 93-07-24 All boxes of a protein turn black when one is picked Sorting by protein name or score added 93-11-16 Added picking of Big Picture HSP's and Reverse Strand Big Picture 93-11-17 Added blastn support 94-01-29 Added Highlight sequences by names matching regexp 94-03-07 Fixed window limits. Added initial settings (BigPict, gotoNext) 94-03-08 Added 'always-both-strands' in blastn mode. 94-03-27 Added Tblastn support (works in seqbl mode). 94-12-01 [2.0] Added dotter calling. 95-02-02 Rewrote auxseq and padseq allocation to be fully dynamic and unlimited. 95-02-06 Added Tblastx support (works in seqbl mode). 95-06-01 [2.1] Added entropy display 95-06-23 [2.1] Added Settings window 95-07-21 2.1 announced-------------------------------------- 95-08-01 [2.2] Initial Sorting mode on command line. 95-09-15 [2.2] Added Settings pull-down menu for faster manipulation. 95-09-29 [2.2] Improved WWW browser finding with findCommand() - doesn't get fooled so easily. 95-10-04 [2.2] Added "Print whole alignment" 95-10-27 [2.2] Added acedb-fetching at double clicking. BLIXEM_FETCH_ACEDB makes this default. Reorganised Settings window to Toggles and Menus rows. 95-11-01 [2.3] Changed command line syntax to "-" for piping. Added X options capability (-acefont, -font). 96-01-05 [2.3] Force all tblastn HSP's to be qframe +1, to harmonize with MSPcrunch 1.4 which gives sframe for tblastn (otherwise the output would be dead). 96-02-08 [2.3] Added option -S "Start display at position #" to stand-alone command line. 96-02-08 [2.3] Added checkmarks to pull-down settings menu. 96-03-05 2.3 Announced. 96-03-08 [2.4] Only look for WWW browser once. 96-05-09 [2.4] Proper grayscale print colours. 96-05-09 [2.4] Enabled piping of query sequence too, for Pepmap and WWW calls. 96-08-20 [2.4] Fixed minor bug in squashed mode and added restoring of previous sorting after squash. 97-05-28 [2.4] Fixed parsing to handle gapped matches. Added "Highlight lower case residues" for gapped alignments and "Show sequence descriptions" (for MSPcrunch 2.1). Added setting the color of matching residues in the Settings window. 97-06-17 [2.4] Fixed "Highlight differences" for gapped alignments ('.' -> '-'). Changed "Highlight lower case residues" to "Highlight subject insertions" and set this automatically for gapped alignments. Works for both lower case and number insert markers. Changed blviewRedraw to use strlen to accommodate reverse gapped alignments. Simplified (and thereby debugged) selection of Big Picture MSPs to be drawn. Made Big Picture ON/OFF control more logical and consistent. Added a calcID() step to fix sortById() at startup. Added "Hilight Upper/Lower case" - useful general purpose feature. 97-10-14 [2.4] Added Description box when picking sequences. 97-03-07 [3.0] Added code for FS Feature Segment data. (shared code with Dotter for control and parsing; the display code is unique to Blixem). Added Inverted sorting order. Fixed bug in coordinate display in tblastn mode. 99-07-07 [3.0] Added msp->shape attribute. Added support for XY curve shapes PARTIAL and INTERPOLATE. Overhauled selective drawing of BigPicture MSPs, now simple enough to be bugfree (hopefully). 01-10-05 Added getsseqsPfetch to fetch all missing sseqs in one go via socket connection to pfetch [RD] * Created: Thu Feb 20 10:27:39 1993 (esr) * CVS info: $Id: blxview.c,v 1.181 2004/03/03 10:49:16 edgrif Exp $ *------------------------------------------------------------------- */ /* Pending: Do exons and introns like SFS segments (i.e. eliminate magic scores. Requires changes to fmapfeatures.c). Known bugs: ----------- revcomp broken when called from acedb. Slen/send problem? MSP score codes: ---------------- -1 exon -> Big picture + Alignment -2 intron -> Big picture + Alignment -3 Any coloured segment -> Big picture -4 stringentSEGcolor -> Big picture -5 mediumSEGcolor -> Big picture -6 nonglobularSEGcolor -> Big picture -10 hidden by hand */ #include #include #include #include #include #include #include #include #include /* for socket(), connect(), send(), and recv() */ #include #include /* for sockaddr_in and inet_addr() */ #include /* for gethostbyname() */ #include #include #include #include #include #include #include #include #include #ifdef ACEDB #include #endif char *blixemVersion = BLIXEM_VERSION_STRING ; /* get rid of these...ugh.....horrible.....horrific.... */ extern void externalCommand (char *command); extern int pickMatch (char *cp, char *tp); #define max(a,b) (((a) > (b)) ? (a) : (b)) #define BPoffset 4 #define NAMESPACE 12 #define SEQ2BP(i) (float)plusmin*(i-BigPictStart-qoffset)*BPx/BigPictLen + BPoffset #define MAXALIGNLEN 10000 #define separatorwidth 0.5 #define autoDotterParamsStr "Automatic Dotter parameters" typedef struct _BPMSP { char sname[FULLNAMESIZE+1]; char *desc; int box; Graph graph; struct _BPMSP *next; } BPMSP; /* MSP list is sorted by one of these criteria, currently SORTBYID is the default. */ typedef enum {SORTBYUNSORTED, SORTBYSCORE, SORTBYID, SORTBYNAME, SORTBYPOS} SortByType ; static void blDestroy(void) ; static void blxPrint(void) ; static void wholePrint(void) ; static void sortByName(void) ; static void sortByScore(void) ; static void sortByScore(void) ; static void sortByPos(void) ; static void sortById(void) ; static void sortToggleInv(void) ; static void MSPsort(SortByType sort_mode) ; static void squashMatches(void) ; static void squashFSdo(void) ; static void toggleIDdots (void) ; static void toggleVerbose(void) ; static void toggleHiliteSins(void) ; static void toggleHiliteUpper(void) ; static void toggleHiliteLower(void) ; static void toggleDESC(void) ; static void ToggleStrand(void) ; static void printColors (void) ; static void scrollRightBig(void); static void scrollLeftBig(void); static void scrollRight1(void); static void scrollLeft1(void); static void Goto(void); static void gotoMatch(int direc); static void prevMatch(void) ; static void nextMatch(void); static void keyboard (int key, int modifier_unused); static void toggleColors (void); static void blviewPick (int box, double x_unused, double y_unused, int modifier_unused); static void blviewHelp(void); static Graph blviewCreate(char *opts) ; static void blviewDestroy(GtkWidget *unused) ; static char *getqseq(int start, int end, char *q); static char *get3rd_base(int start, int end, char *q); static void calcID(MSP *msp); static int gapCoord(MSP *msp, int x, int qfact); static GtkWidget *makeButtonBar(void); static BOOL haveAllSequences(MSP *msplist, DICT *dict) ; static char *fetchSeqRaw(char *seqname) ; static BOOL getsseqsPfetch(MSP *msplist, DICT *dict, char* pfetchIP, int port, BOOL External) ; static void getsseq(MSP *msp) ; static char *getFetchProg(char *fetch_mode) ; static char *getSeq(char *seqname, char *fetch_prog) ; static BOOL smartDotterRange(char *selected_sequence, MSP *msp_list, int blastn, int strand_sign, int view_start, int view_end, char **dottersseq_out, int *dotter_start_out, int *dotter_end_out) ; static char *abbrevTxt(char *text, int max_len) ; /* * Local globals....sigh.... */ static void BigPictToggle(void), entropytoggle(void), BigPictToggleRev(void), zoomIn(void), zoomOut(void), zoomWhole(void), MiddleDragBP(double x, double y), MiddleUpBP(double x, double y), MiddleDownBP(double x, double y), MiddleDragQ(double x, double y), MiddleUpQ(double x, double y), MiddleDownQ(double x, double y), setHighlight(void), clrHighlight(void), callDotter(void), callDotterHSPs(void), callDotterSelf(void), /* dotterPanel(void), */ setDotterParams(void), autoDotterParams(void), allocAuxseqs(int len), blixemSettings(void), settingsRedraw(void), menuCheck(MENU menu, int mode, int thismode, char *str), hidePicked(void), setMenuCheckmarks(void); #ifdef ED_G_NEVER_INCLUDE_THIS_CODE /* currently unused... */ static void pfetchWindow (MSP *msp); #endif /* ED_G_NEVER_INCLUDE_THIS_CODE */ /* some low level socket functions that follow the main function */ static int socketConstruct(char *ipAddress, int port, BOOL External) ; static BOOL socketSend(int sock, char *text) ; /* GLOBAL VARIABLES...really its hard to beat this for a list of globals, * one for the Guinness Book of Records perhaps... */ static BPMSP BPMSPlist, *bpmsp; static int fetchCount; static Graph blixemGraph=0; /* The blxview window */ GtkWidget *blixemWindow = NULL ; static GtkWidget *messageWidget; static Graph frameGraph[3]; static Graph frameGraphQ[3]; static Graph settingsGraph=0; static int actstart, /* Active region coordinates relative to query in BASES */ actend, dispstart, /* Displayed region relative to query in BASES */ displen=240; /* Displayed sequence length in BASES */ static char actframe[16]="(+1)"; /* Active frame */ static int plusmin=1; /* +1 for top strand, -1 */ static float queryy, /* Screen coords of genome seq */ separator_y, /* y coord of previous panel separator */ lastExonx, BPboxheight = 5.7, BPboxstart, BPboxwidth, BigPictZoom = 10, oldLinew; static char *q; /* The genomic sequence (query=the translated seq) */ static int qlen; static int qoffset; /* Offset to the 'real' DNA start */ static char *qname_G = NULL ; MSP *MSPlist, /* List of MSP's */ *msp; static MSP *pickedMSP = NULL ; /* Last picked MSP */ static char message[1024], HighlightSeq[NAMESIZE+4] = "", searchSeq[NAMESIZE+4] = "", *cp, *padseq = 0, *auxseq = 0, *auxseq2 = 0, dotterqname[NAMESIZE+1], *dottersseq = NULL, stringentEntropytx[10], mediumEntropytx[10], nonglobularEntropytx[10], sortModeStr[32] = "Identity", fetchMode[32] = "efetch", /* Not done with enum to get menu-strings for free */ *URL = NULL ; static int lastbox = 0; static int colortoggle = 0; static int backgColor = LIGHTGRAY, IDcolor = CYAN, consColor = MIDBLUE, geneColor = BLUE, hiColor = YELLOW, oldcolor, BigPictON = 1, BigPictRev = 0, /* Draw other strand in Big picture */ BigPictStart, BigPictLen, BPbox, BPx, gridColor = YELLOW, nx, ny, blastx = 1, blastp = 0, blastn = 0, tblastn = 0, tblastx = 0, symbfact = 3, i, start_nextMatch = 0, dotter_first = 0, compN, IDdots = 0, squash = 0, squashFS = 1, verbose = 0, HiliteSins = 0, HiliteUpperOn = 0, HiliteLowerOn = 0, DESCon = 0, dotterZoom = 0, dotterStart = 0, dotterEnd = 0, dotterHSPs = 0, auxseqlen = 0, smartDotter = 1, entropyOn = 0, stringentEntropycolor = LIGHTGREEN, stringentEntropybox, mediumEntropycolor = GREEN, mediumEntropybox, nonglobularEntropycolor = DARKGREEN, nonglobularEntropybox, alphabetsize, stringentEntropywin = 12, mediumEntropywin = 25, nonglobularEntropywin = 45, printColorsOn, wholePrintOn, oneGraph, settingsButton, sortInvOn = 0, HSPgaps = 0; static SortByType sortMode = SORTBYUNSORTED ; static int oldWidth = 0, oldHeight = 0; static double oldx, DNAstep; static Array stringentEntropyarr, mediumEntropyarr, nonglobularEntropyarr; static MENU blixemMenu ; /* Main menu - contains function calls, etc. */ static MENU settingsMenu; /* Contains toggles and 'states' */ #define SortByScoreStr "Sort by score" #define SortByIdStr "Sort by identity" #define SortByNameStr "Sort by name" #define SortByPosStr "Sort by position" #define SortInvStr "Inverted sorting order" #define BigPictToggleStr "Big Picture" #define BigPictToggleRevStr "Big Picture Other Strand" #define toggleIDdotsStr "Highlight differences" #define squashMatchesStr "Squash matches" #define squashFSStr "Squash features" #define entropytoggleStr "Complexity curves" #define printColorsStr "B/W Print colours" #define toggleColorsStr "No colours" #define toggleVerboseStr "Verbose mode" #define toggleHiliteSinsStr "Highlight subject insertions" #define toggleHiliteUpperStr "Highlight upper case" #define toggleHiliteLowerStr "Highlight lower case" #define toggleDESCStr "Show sequence descriptions" static MENUOPT mainMenu[] = { {blDestroy, "Quit"}, {blviewHelp, "Help"}, {blxPrint, "Print"}, {wholePrint, "Print whole alignment"}, {blixemSettings, "Change Settings"}, {selectFeatures, selectFeaturesStr}, {menuSpacer, ""}, /* {dotterPanel, "Dotter panel"},*/ {callDotter, "Dotter"}, {callDotterHSPs, "Dotter HSPs only"}, {callDotterSelf, "Dotter query vs. itself"}, {setDotterParams, "Manual Dotter parameters"}, {autoDotterParams, autoDotterParamsStr}, {menuSpacer, ""}, {hidePicked, "Hide picked match"}, {setHighlight, "Highlight sequences by name"}, {clrHighlight, "Clear highlighted and unhide"}, {0, 0} }; static MENUOPT settingsMenuOpt[] = { {sortByScore, SortByScoreStr}, {sortById, SortByIdStr}, {sortByName, SortByNameStr}, {sortByPos, SortByPosStr}, {sortToggleInv, SortInvStr}, {menuSpacer, ""}, {BigPictToggle, BigPictToggleStr}, {BigPictToggleRev, BigPictToggleRevStr}, {entropytoggle, entropytoggleStr}, {menuSpacer, ""}, {toggleDESC, toggleDESCStr}, {toggleHiliteSins, toggleHiliteSinsStr}, {squashFSdo, squashFSStr}, {squashMatches, squashMatchesStr}, {toggleIDdots, toggleIDdotsStr}, {toggleHiliteUpper,toggleHiliteUpperStr}, {toggleHiliteLower,toggleHiliteLowerStr}, {menuSpacer, ""}, {printColors, printColorsStr}, {toggleColors, toggleColorsStr}, {toggleVerbose, toggleVerboseStr}, {menuSpacer, ""}, {blixemSettings, "Settings window"}, {0, 0} }; #ifdef ED_G_NEVER_INCLUDE_THIS_CODE /* unused... */ static MENUOPT gotoMenu[] = { { gotoBegin, " <- Goto Beginning " }, { gotoEnd, " Goto End -> " }, { 0, 0 } }; #endif /* ED_G_NEVER_INCLUDE_THIS_CODE */ /* * Start of the code..... */ /* Print out MSP's, probably for debugging.... */ static void printMSPs(void) { MSP *msp; for (msp = MSPlist; msp; msp = msp->next) { #ifdef ACEDB if (msp->key) printf("%d %s ", msp->key, name(msp->key)) ; else printf("0 NULL_KEY") ; #endif printf("%s %d %d %d %d %d %d :%s:\n", msp->sname, msp->score, msp->id, msp->qstart+qoffset, msp->qend+qoffset, msp->sstart, msp->send, (msp->sseq ? msp->sseq : "")); } return ; } static void toggleVerbose(void) { MSP *msp; verbose = (verbose ? 0 : 1); if (verbose) printMSPs() ; blviewRedraw(); return ; } static void toggleHiliteSins(void) { HiliteSins = (HiliteSins ? 0 : 1); blviewRedraw(); } static void toggleHiliteUpper(void) { HiliteUpperOn = (HiliteUpperOn ? 0 : 1); blviewRedraw(); } static void toggleHiliteLower(void) { HiliteLowerOn = (HiliteLowerOn ? 0 : 1); blviewRedraw(); } static void toggleDESC(void) { DESCon = (DESCon ? 0 : 1); blviewRedraw(); } static void ToggleStrand(void) { dispstart += plusmin*(displen-1); plusmin = -plusmin; sprintf(actframe, "(%+d)", plusmin); blviewRedraw(); } static void scrollRightBig(void) { dispstart = dispstart + plusmin*displen*.5; blviewRedraw(); } static void scrollLeftBig(void) { dispstart = dispstart - plusmin*displen*.5; blviewRedraw(); } static void scrollRight1(void) { dispstart = dispstart + plusmin*symbfact; blviewRedraw(); } static void scrollLeft1(void) { dispstart = dispstart - plusmin*symbfact; blviewRedraw(); } static void Goto(void) { static char dfault[32] = ""; int i = 0; ACEIN pos_in; /*sprintf(posstr, "%d", dispstart + qoffset);*/ if (!(pos_in = messPrompt ("Goto which position: ", dfault, "t", 0))) return; aceInInt(pos_in, &i); aceInDestroy (pos_in); dispstart = i - qoffset; sprintf(dfault, "%d", i); blviewRedraw(); } static void gotoMatch(int direc) { MSP *msp, *closest; int offset, closest_offset; char strand; if ( strchr(actframe, '+')) strand = '+'; else strand = '-'; if (direc != -1 && direc != 1) { messerror ( "gotoMatch must have -1 or 1 as argument\n" ) ; return; } closest_offset = 0; closest = NULL; for (msp = MSPlist; msp ; msp = msp->next) if ( strchr(msp->qframe, strand) && (msp->qstart - dispstart)*plusmin*direc - 2 > 0) { offset = (msp->qstart - dispstart)*plusmin*direc - 2; if (!closest_offset) closest_offset = offset; else if (offset < closest_offset) closest_offset = offset; } if (!closest_offset) { blviewRedraw(); return; } if (direc < 0) dispstart -= 4*plusmin; dispstart = dispstart + direc*plusmin*(closest_offset ); blviewRedraw(); } static void prevMatch(void) { gotoMatch(-1); } static void nextMatch(void) { gotoMatch(1); } #ifdef ED_G_NEVER_INCLUDE_THIS_CODE /* unsued... */ static void gotoBegin(void) { dispstart = (plusmin > 0 ? 0 : qlen); blviewRedraw(); } static void gotoEnd(void) { dispstart = (plusmin > 0 ? qlen : 0); blviewRedraw(); } #endif /* ED_G_NEVER_INCLUDE_THIS_CODE */ static void keyboard (int key, int modifier_unused) { switch (key) { case '<': case ',': scrollLeft1(); break; case '>': case '.': scrollRight1(); break; case UP_KEY: blviewPick(lastbox - 1, 0, 0, 0); break; case DOWN_KEY: blviewPick(lastbox + 1, 0, 0, 0); break; default: return; } } static void toggleColors (void) { static int oldback, oldgrid, oldID, oldcons, oldgene, oldhi; graphActivate(settingsGraph); if (!colortoggle) { oldback = backgColor; backgColor = WHITE; oldgrid = gridColor; gridColor = BLACK; oldID = IDcolor; IDcolor = WHITE; oldcons = consColor; consColor = WHITE; oldgene = geneColor; geneColor = BLACK; oldhi = hiColor; hiColor = WHITE; colortoggle = 1; } else { backgColor = oldback; gridColor= oldgrid; IDcolor = oldID; consColor = oldcons; geneColor = oldgene; hiColor = oldhi; colortoggle = 0; } blviewRedraw(); } static void printColors (void) { static int oldback, oldgrid, oldID, oldcons, oldgene, oldhi; graphActivate(settingsGraph); if (!printColorsOn) { oldback = backgColor; backgColor = WHITE; oldgrid = gridColor; gridColor = LIGHTGRAY; oldID = IDcolor; IDcolor = GRAY; oldcons = consColor; consColor = PALEGRAY; oldgene = geneColor; geneColor = BLACK; oldhi = hiColor; hiColor = LIGHTGRAY; printColorsOn = 1; } else { backgColor = oldback; gridColor= oldgrid; IDcolor = oldID; consColor = oldcons; geneColor = oldgene; hiColor = oldhi; printColorsOn = 0; } blviewRedraw(); } static void toggleIDdots (void) { IDdots = !IDdots; blviewRedraw(); } static void calcEntropyArray(Array array, int win) { int i, j, *rescount; float pi, sum; rescount = (int *)messalloc(24*sizeof(int)); for (i=0; i < qlen; i++) { rescount[aa_atob[(unsigned int)q[i]]]++; if (i+1 >= win) { for (sum = j = 0; j < 24; j++) if (rescount[j]) { pi = (float)rescount[j]/win; sum += pi*log(pi); } arr(array, i-win/2, float) = -sum/log(2); rescount[aa_atob[(unsigned int)q[i+1-win]]]--; } } messfree(rescount); /* TEST - delete later * / for (i=0; i < qlen; i++) printf ("%3d %c %f\n", i, q[i], arr(stringentEntropyarr, i, float)); */ } static void calcEntropyArrays(BOOL force) { /* force: FALSE - only calculate if necessary, i.e. first call. TRUE - force (re)calculation. */ if (!stringentEntropyarr) { calcEntropyArray(stringentEntropyarr = arrayCreate(qlen, float), stringentEntropywin); calcEntropyArray(mediumEntropyarr = arrayCreate(qlen, float), mediumEntropywin); calcEntropyArray(nonglobularEntropyarr = arrayCreate(qlen, float), nonglobularEntropywin); } else if (force) { calcEntropyArray(stringentEntropyarr = arrayCreate(qlen, float), stringentEntropywin); calcEntropyArray(mediumEntropyarr = arrayCreate(qlen, float), mediumEntropywin); calcEntropyArray(nonglobularEntropyarr = arrayCreate(qlen, float), nonglobularEntropywin); } } static void entropytoggle (void) { entropyOn = !entropyOn; if (entropyOn) BigPictON = 1; calcEntropyArrays(FALSE); blviewRedraw(); } /* Find the expression 'query' in the string 'text' * Return 1 if found, 0 otherwise */ int strMatch(char *text, char *query) { /* Non-ANSI bsd way: * / if (re_exec(text) == 1) return 1; else return 0; */ /* ANSI way: */ return pickMatch(text, query); } void highlightProteinboxes(BOOL warpScroll) { MSP *msp; /* Highlight alignment boxes of current search string seq */ if (*searchSeq) for (msp = MSPlist; msp ; msp = msp->next) if (msp->box && strMatch(msp->sname, searchSeq)) { graphActivate(msp->graph); graphBoxDraw(msp->box, BLACK, RED); } /* Highlight alignment boxes of currently selected seq */ if (!squash) for (msp = MSPlist; msp ; msp = msp->next) if (msp->box && !strcmp(msp->sname, HighlightSeq)) { float x1, x2, y1, y2; graphActivate(msp->graph); graphBoxDraw(msp->box, WHITE, BLACK); if (warpScroll) { /* Scroll the alignment window so that the currently selected seq is visible. Not that this only happens in response to clicking on the big picture when warpScroll is TRUE. */ graphBoxDim(msp->box, &x1, &y1, &x2, &y2); graphGoto(x1, y1); } } if (BigPictON) { /* Highlight Big Picture boxes of current search string seq */ if (*searchSeq) for (bpmsp = BPMSPlist.next; bpmsp && *bpmsp->sname; bpmsp = bpmsp->next) if (strMatch(bpmsp->sname, searchSeq)) { graphActivate(bpmsp->graph); graphBoxDraw(bpmsp->box, RED, BLACK); } /* Highlight Big Picture boxes of currently selected seq */ for (bpmsp = BPMSPlist.next; bpmsp && *bpmsp->sname; bpmsp = bpmsp->next) if (!strcmp(bpmsp->sname, HighlightSeq)) { graphActivate(bpmsp->graph); graphBoxDraw(bpmsp->box, CYAN, BLACK); } } } static void hidePicked (void) { MSP *msp; for (msp = MSPlist; msp ; msp = msp->next) if (!strcmp(msp->sname, HighlightSeq)) { msp->id = msp->score; msp->score = -999; } blviewRedraw () ; } /* Callback for when user clicks on a sequence to retrieve the EMBL entry */ /* for that sequence. The method of retrieving the sequence can be changed */ /* via environment variables. */ /* */ static void blviewPick(int box, double x_unused, double y_unused, int modifier_unused) { MSP *msp; Graph origGraph = graphActive(); if (!box) return ; if (box == lastbox) { /* Second click - efetch this seq */ for (msp = MSPlist; msp ; msp = msp->next) { if (msp->box == box && msp->graph == graphActive()) break; } if (msp && *msp->sname) { if (!strcmp(fetchMode, "pfetch")) { /* --client gives logging information to pfetch server, * -F makes sure we get a full sequence entry returned. */ externalCommand(messprintf("pfetch --client=acedb_%s_%s -F '%s' &", getSystemName(), getLogin(TRUE), msp->sname)); /* currently unused... pfetchWindow(msp); */ } else if (!strcmp(fetchMode, "efetch")) { externalCommand(messprintf("efetch '%s' &", msp->sname)); } else if (!strcmp(fetchMode, "WWW-efetch")) { #ifdef ACEDB graphWebBrowser (messprintf ("%s%s", URL, msp->sname)); #else { char *browser = NULL ; if (!browser && !(browser = getenv("BLIXEM_WWW_BROWSER"))) { printf("Looking for WWW browsers ...\n"); if (!findCommand("netscape", &browser) && !findCommand("Netscape", &browser) && !findCommand("Mosaic", &browser) && !findCommand("mosaic", &browser) && !findCommand("xmosaic", &browser)) { messout("Couldn't find any WWW browser. Looked for " "netscape, Netscape, Mosaic, xmosaic & mosaic. " "System message: \"%s\"", browser); return; } } printf("Using WWW browser %s\n", browser); fflush(stdout); system(messprintf("%s %s%s&", browser, URL, msp->sname)); } #endif } #ifdef ACEDB else if (!strcmp(fetchMode, "acedb")) { display(msp->key, 0, 0); } else if (!strcmp(fetchMode, "acedb text")) { display(msp->key, 0, "TREE"); } #endif else messout("Unknown fetchMode: %s", fetchMode); } } else { /* Reset all highlighted boxes */ if (!squash) { for (msp = MSPlist; msp ; msp = msp->next) if (msp->box && !strcmp(msp->sname, HighlightSeq)) { graphActivate(msp->graph); graphBoxDraw(msp->box, BLACK, backgColor); } } if (BigPictON) { for (bpmsp = BPMSPlist.next; bpmsp && *bpmsp->sname; bpmsp = bpmsp->next) if (!strcmp(bpmsp->sname, HighlightSeq)) { graphActivate(bpmsp->graph); graphBoxDraw(bpmsp->box, BLACK, backgColor); } } /* Find clicked protein ***********************/ for (msp = MSPlist; msp ; msp = msp->next) { if (msp->box == box && msp->graph == origGraph) break; } if (msp) { /* Picked box in alignment */ strcpy(HighlightSeq, msp->sname); pickedMSP = msp; } else if (BigPictON) { /* look for picked box in BigPicture */ for (bpmsp = BPMSPlist.next; bpmsp && *bpmsp->sname; bpmsp = bpmsp->next) if (bpmsp->box == box && bpmsp->graph == origGraph) break; if (bpmsp && *bpmsp->sname) strcpy(HighlightSeq, bpmsp->sname); } if (msp || (bpmsp && *bpmsp->sname)) { /* Put description in message box */ if (msp) { strncpy(message, msp->sname, 1023); if (msp->desc) { strcat(message, " "); strncat(message, msp->desc, 1023-strlen(message)); } /* Highlight picked box */ graphActivate(blixemGraph); highlightProteinboxes(FALSE); } else { strncpy(message, bpmsp->sname, 1023); if (bpmsp->desc) { strcat(message, " "); strncat(message, bpmsp->desc, 1023-strlen(message)); } /* Highlight picked box */ graphActivate(blixemGraph); highlightProteinboxes(TRUE); } gtk_entry_set_text(GTK_ENTRY(messageWidget), message); lastbox = box; } } return ; } static void mspcpy(MSP *dest, MSP *src) { dest->type = src->type; dest->score = src->score; dest->id = src->id; strcpy(dest->qframe, src->qframe); dest->qstart = src->qstart; dest->qend = src->qend; dest->sname = src->sname; strcpy(dest->sframe, src->sframe); dest->sstart = src->sstart; dest->send = src->send; dest->sseq = src->sseq; dest->desc = src->desc; dest->box = src->box; dest->color = src->color; dest->shape = src->shape; dest->fs = src->fs; dest->xy = src->xy; dest->gaps = src->gaps; #ifdef ACEDB dest->key = src->key; #endif } static void sortMSPs(int (*func)()) { MSP tmpmsp, *msp1, *msp2; if (!MSPlist) return; for (msp1 = MSPlist ; msp1->next ; msp1 = msp1->next ) { for (msp2 = msp1->next ; msp2 ; msp2 = msp2->next ) { if ( (*func)(msp1, msp2)*(sortInvOn ? -1 : 1) > 0 ) { mspcpy(&tmpmsp, msp2); mspcpy(msp2, msp1); mspcpy(msp1, &tmpmsp); } } } if (graphActivate(blixemGraph)) blviewRedraw() ; return ; } /* aghhh, this all needs rewriting, how opaque can you get sigh... */ #define FSpriority {if (FS(msp1) && !FS(msp2)) return -1; else if (FS(msp2) && !FS(msp1)) return 1;} static int possort(MSP *msp1, MSP *msp2) { FSpriority return ( (msp1->qstart > msp2->qstart) ? 1 : -1 ); } static int namesort(MSP *msp1, MSP *msp2) { FSpriority if (strcmp(msp1->sname, msp2->sname)) return strcmp(msp1->sname, msp2->sname); else return possort(msp1, msp2); } static int scoresort(MSP *msp1, MSP *msp2) { FSpriority return ( (msp1->score < msp2->score) ? 1 : -1 ); } static int idsort(MSP *msp1, MSP *msp2) { int result = 0 ; FSpriority result = ( (msp1->id < msp2->id) ? 1 : -1 ) ; return result ; } /* Set of callbacks to set up different methods of fetching EMBL entry for a */ /* sequence. */ /* */ static void fetchBypfetch(void) { strcpy(fetchMode, "pfetch"); if (graphActivate(blixemGraph)) blviewRedraw(); return ; } static void fetchByefetch(void) { strcpy(fetchMode, "efetch"); if (graphActivate(blixemGraph)) blviewRedraw(); return ; } static void fetchByWWWefetch(void) { strcpy(fetchMode, "WWW-efetch"); if (graphActivate(blixemGraph)) blviewRedraw(); return ; } #ifdef ACEDB static void fetchByacedb(void) { strcpy(fetchMode, "acedb"); if (graphActivate(blixemGraph)) blviewRedraw(); return ; } static void fetchByacedbtext(void) { strcpy(fetchMode, "acedb text"); if (graphActivate(blixemGraph)) blviewRedraw(); return ; } #endif /* Sort the match entries by..... */ static void sortByName(void) { sortMode = SORTBYNAME; strcpy(sortModeStr, "Name"); sortMSPs(namesort); return ; } static void sortByScore(void) { sortMode = SORTBYSCORE; strcpy(sortModeStr, "Score"); sortMSPs(scoresort); return ; } static void sortByPos(void) { sortMode = SORTBYPOS; strcpy(sortModeStr, "Position"); sortMSPs(possort); return ; } static void sortById(void) { sortMode = SORTBYID; strcpy(sortModeStr, "Identity"); sortMSPs(idsort); return ; } static void MSPsort(SortByType sort_mode) { switch (sort_mode) { case SORTBYNAME : sortByName(); break; case SORTBYSCORE : sortByScore(); break; case SORTBYPOS : sortByPos(); break; case SORTBYID : default: /* Make the default sort by Identity */ { for (msp = MSPlist; msp; msp = msp->next) if (!msp->id) calcID(msp); sortById(); } break ; } return ; } static void sortToggleInv(void) { sortInvOn = !sortInvOn; switch (sortMode) { case SORTBYNAME : sortByName(); break; case SORTBYSCORE : sortByScore(); break; case SORTBYPOS : sortByPos(); break; case SORTBYID : sortById(); break; default: blviewRedraw(); break; } return ; } /* static void incBack(void) { backgColor++; if (!(backgColor % BLACK)) backgColor++; blviewRedraw(); } static void decBack(void) { backgColor--; if (!(backgColor % BLACK)) backgColor--; blviewRedraw(); } static void incGrid(void) { gridColor++; blviewRedraw(); } static void decGrid(void) { gridColor--; blviewRedraw(); } */ static void squashMatches(void) { static int oldSortMode; if (!squash) { oldSortMode = sortMode; sortByName(); squash = 1; } else { switch (oldSortMode) { case SORTBYNAME : sortByName(); break; case SORTBYSCORE : sortByScore(); break; case SORTBYPOS : sortByPos(); break; case SORTBYID : sortById(); break; } squash = 0; } blviewRedraw(); } static void squashFSdo(void) { squashFS = !squashFS; blviewRedraw(); } static void blviewHelp(void) { graphMessage (messprintf("\ \ BLIXEM - BLast matches\n\ In an\n\ X-windows\n\ Embedded\n\ Multiple alignment\n\ \n\ LEFT MOUSE BUTTON:\n\ Pick on boxes and sequences.\n\ Fetch annotation by double clicking on sequence (Requires 'efetch' to be installed.)\n\ \n\ MIDDLE MOUSE BUTTON:\n\ Scroll horizontally.\n\ \n\ RIGHT MOUSE BUTTON:\n\ Menu. Note that the buttons Settings and Goto have their own menus.\n\ \n\ RESIDUE COLOURS:\n\ Yellow = Query.\n\ See Settings Panel for matching residues (click on Settings button).\n\ \n\ version %s\n\ (c) Erik Sonnhammer", blixemVersion)); } static void wholePrint(void) { int tmp, dispstart_save = dispstart, BigPictON_save = BigPictON; static int start=1, end=0; ACEIN zone_in; if (!end) end = qlen; /* Swap coords if necessary */ if ((plusmin < 0 && start < end) || (plusmin > 0 && start > end )) { tmp = start; start = end; end = tmp; } /* Apply max limit MAXALIGNLEN */ if ((abs(start-end)+1) > MAXALIGNLEN*symbfact) { start = dispstart - plusmin*MAXALIGNLEN*symbfact; if (start < 1) start = 1; if (start > qlen) start = qlen; end = start + plusmin*MAXALIGNLEN*symbfact; if (end > qlen) end = qlen; if (end < 1) end = 1; } if (!(zone_in = messPrompt("Please state the zone you wish to print", messprintf("%d %d", start, end), "iiz", 0))) return; aceInInt(zone_in, &start); aceInInt(zone_in, &end); aceInDestroy (zone_in); dispstart = start; displen = abs(end-start)+1; /* Validation */ if (plusmin > 0 && start > end) { messout("Please give a range where from: is less than to:"); return; } else if (plusmin < 0 && start < end) { messout("Please give a range where from: is more than to:"); return; } if (displen/symbfact > MAXALIGNLEN) { messout("Sorry, can't print more than %d residues. Anyway, think of the paper!", MAXALIGNLEN*symbfact); return; } wholePrintOn = 1; BigPictON = 0; oneGraph = 1; blviewRedraw(); graphPrint(); /* Restore */ wholePrintOn = 0; dispstart = dispstart_save; displen = dispstart_save; oneGraph = 0; BigPictON = BigPictON_save; blviewRedraw(); } static void blxPrint(void) { oneGraph = 1; blviewRedraw(); graphPrint(); oneGraph = 0; blviewRedraw(); } /* input is co-ord on query sequence, find corresonding base in target */ /* "Look on my works, ye mighty, and despair." */ static int gapCoord(MSP *msp, int x, int qfact) { Array gaps = msp->gaps; int savepos; if (!gaps || arrayMax(gaps) == 0) { int result ; if (msp->qstart < msp->qend) result = ((x - msp->qstart)/qfact) + msp->sstart ; else result = ((msp->qstart - x)/qfact) + msp->sstart ; return result ; } if (msp->qstart < msp->qend) { if (x < msp->qstart) return msp->sstart - 1; if (x > msp->qend) return msp->send + 1; savepos = msp->sstart - 1; for (i=0; ir2 >= x) { if (m->r1 <= x) return (x - m->r1)/qfact + m->s1; else return savepos; } if (plusmin == 1) savepos = m->s2; else savepos = m->s2 + 1; } } else { if (x > msp->qstart) return msp->sstart - 1; if (x < msp->qend) return msp->send + 1; savepos = msp->send + 1; for (i=arrayMax(gaps)-1; i >= 0; i--) { SMapMap *m = arrp(gaps, i, SMapMap); if (m->r1 >= x) { if (m->r2 <= x) return m->s2 - (x - m->r2)/qfact; else return savepos; } if (plusmin == 1) savepos = m->s1; else savepos = m->s1 - 1; } } return savepos; } static void setModeP(void) { blastp = 1; blastx = blastn = tblastn = tblastx = 0; alphabetsize = 24; symbfact = 1; BigPictZoom = 10; } static void setModeN(void) { blastn = 1; blastp = blastx = tblastn = tblastx = 0; alphabetsize = 4; symbfact = 1; BigPictZoom = 30; } static void setModeX(void) { blastx = 1; blastp = blastn = tblastn = tblastx = 0; alphabetsize = 4; symbfact = 3; BigPictZoom = 10; } static void setModeT(void) { tblastn = 1; blastp = blastx = blastn = tblastx = 0; alphabetsize = 24; symbfact = 1; } static void setModeL(void) { tblastx = 1; blastp = blastx = blastn = tblastn = 0; alphabetsize = 24; symbfact = 3; BigPictZoom = 10; } /* blxview() can be called either from other functions in the Blixem * program itself or directly by functions in other programs such as * xace. * * Interface * opts: may contain a number of options that tell blixem to * start up with different defaults * pfetch: if non-NULL, then we use pfetch instead of efetch for * _all_ sequence fetching (use the node/port info. in the * pfetch struct to locate the pfetch server). * */ Graph blxview(char *seq, char *seqname, int start, int offset, MSP *msplist, char *opts, PfetchParams *pfetch, BOOL External) { Graph result = GRAPH_NULL ; char *opt; BOOL use_pfetch = FALSE ; BOOL status = TRUE ; DICT *dict ; oneGraph = 0; if (blixemWindow) gtk_widget_destroy(blixemWindow) ; q = seq; qlen = actend = strlen(q) ; qname_G = g_strdup(seqname) ; dispstart = start; actstart=1; qoffset = offset; MSPlist = msplist; BPMSPlist.next = 0; *HighlightSeq = 0; blastx = blastp = blastn = tblastn = tblastx = 0 ; sortMode = SORTBYUNSORTED ; opt = opts; while (*opt) { /* Used options: BGILMNPRSTXZ-+brsinp */ switch (*opt) { case 'I': sortInvOn = 1; break; case 'G': /* Gapped HSPs */ HiliteSins = HSPgaps = 1; break; case 'P': setModeP(); break; case 'N': setModeN(); break; case 'X': setModeX(); break; case 'T': setModeT(); break; case 'L': setModeL(); break; case '-': strcpy(actframe, "(-1)"); plusmin = -1; break; case '+': strcpy(actframe, "(+1)"); plusmin = 1; break; case 'B': BigPictON = 1; break; case 'b': BigPictON = 0; break; case 'd': dotter_first = 1; break; case 'i': sortMode = SORTBYID ; break; case 'M': start_nextMatch = 1; break; case 'n': sortMode = SORTBYNAME ; break; case 'p': sortMode = SORTBYPOS ; break; case 'R': BigPictRev = 1; break; case 'r': BigPictRev = 0; break; case 's': sortMode = SORTBYSCORE ; break ; case 'Z': BigPictZoom = strlen(seq); break; } opt++; } if (blastx + blastn + blastp + tblastn + tblastx == 0) { printf("\nNo blast type specified. Detected "); if (Seqtype(q) == 'P') { printf("protein sequence. Will try to run Blixem in blastp mode\n"); setModeP(); } else { printf("nucleotide sequence. Will try to run Blixem in blastn mode\n"); setModeN(); } } /* Check env. vars to see how to fetch EMBL entries for sequences. */ if (pfetch || (getenv("BLIXEM_FETCH_PFETCH"))) { use_pfetch = TRUE ; strcpy(fetchMode, "pfetch"); } else if ((URL = getenv("BLIXEM_FETCH_WWW"))) strcpy(fetchMode, "WWW-efetch"); else if (getenv("BLIXEM_FETCH_EFETCH")) strcpy(fetchMode, "efetch"); else #ifdef ACEDB strcpy(fetchMode, "acedb"); #else strcpy(fetchMode, "WWW-efetch"); #endif if (!URL) { URL = messalloc(256); strcpy(URL, "http://www.sanger.ac.uk/cgi-bin/seq-query?"); } /* Find out if we need to fetch any sequences (they may all be contained in the input * files), if we do need to, then fetch them by the appropriate method. */ dict = dictCreate(128) ; if (!haveAllSequences(MSPlist, dict)) { if (use_pfetch) { /* Fill msp->sseq fast by pfetch if possible * two ways to use this: * 1) call blixem main with "-P node:port" commandline option * 2) setenv BLIXEM_PFETCH to a dotted quad IP address for the * pfetch server, e.g. "193.62.206.200" = Plato's IP address * or to the name of the machine, e.g. "plato" * and optionally setenv BLIXEM_PORT to the port number for * the pfetch server. */ enum {PFETCH_PORT = 22100} ; /* default port to connect on */ char *net_id = NULL ; int port = PFETCH_PORT ; if (pfetch) { net_id = pfetch->net_id ; if (!(port = pfetch->port)) port = PFETCH_PORT ; } else if ((net_id = getenv("BLIXEM_PFETCH"))) { if (!(atoi(getenv("BLIXEM_PORT")))) port = PFETCH_PORT ; } if (net_id) status = getsseqsPfetch(MSPlist, dict, net_id, port, External) ; } } messfree(dict) ; /* Note that we create a blxview even if MSPlist is empty. * But only if it's an internal call. If external & anything's wrong, we die. */ if (status || !External) result = blviewCreate(opts) ; /* Sort the MSPs according to mode chosen. */ MSPsort(sortMode) ; #ifdef ED_G_NEVER_INCLUDE_THIS_CODE printMSPs() ; #endif /* ED_G_NEVER_INCLUDE_THIS_CODE */ return result ; } /* BLVIEWCREATE initializes the display and the buttons */ static void addgraph(GtkWidget *vbox, BOOL doFrame, Graph graph) { GtkWidget *widget; if (doFrame) { widget = gtk_frame_new(NULL); gtk_container_add(GTK_CONTAINER(widget), gexGraph2Widget(graph)); } else widget = gexGraph2Widget(graph); gtk_container_border_width (GTK_CONTAINER (widget), 0); gtk_box_pack_start(GTK_BOX(vbox), widget, !doFrame, TRUE, 0); graphActivate(graph); graphRegister (PICK, blviewPick) ; graphRegister (MIDDLE_DOWN, MiddleDownQ) ; graphRegister (KEYBOARD, keyboard) ; graphNewMenu(blixemMenu); } static void blDestroy(void) { gtk_widget_destroy(blixemWindow); } static Graph blviewCreate(char *opts) { if (!blixemWindow) { float w, h; GtkWidget *vbox; int i, frames = blastx ? 3 : 2 ; BOOL pep_nuc_align ; blixemWindow = gexWindowCreate(); vbox = gtk_vbox_new(FALSE, 0); gtk_container_add(GTK_CONTAINER(blixemWindow), vbox); if (!oldWidth) gtk_window_set_default_size(GTK_WINDOW(blixemWindow), (int)(((float)gdk_screen_width())*0.9), (int)(((float)gdk_screen_height())*0.6)); else gtk_window_set_default_size(GTK_WINDOW(blixemWindow), oldWidth, oldHeight); pep_nuc_align = (*opts == 'X' || *opts == 'N') ; gtk_window_set_title(GTK_WINDOW(blixemWindow), messprintf("Blixem %s%s%s: %s", (pep_nuc_align ? " (" : ""), (*opts == 'X' ? "peptide" : (*opts == 'N' ? "nucleotide" : "")), (pep_nuc_align ? " alignment)" : ""), qname_G)); w=3.0; h=3.0; blixemMenu = menuInitialise ("blixem", (MENUSPEC*)mainMenu) ; menuSetFlags(menuItem(blixemMenu, autoDotterParamsStr), MENUFLAG_DISABLED); if (!fsArr) menuSetFlags(menuItem(blixemMenu, selectFeaturesStr ), MENUFLAG_DISABLED); blixemGraph = graphNakedResizeCreate(TEXT_FIT, NULL, w, h, TRUE); addgraph(vbox, TRUE, blixemGraph); graphRegister (MIDDLE_DOWN, MiddleDownBP) ; graphRegister (RESIZE, blviewRedraw); gtk_box_pack_start(GTK_BOX(vbox), makeButtonBar(), FALSE, TRUE, 0); for (i=0; isname && (MSPlist->type == HSP || MSPlist->type == GSP)) { strcpy(HighlightSeq, MSPlist->sname); callDotter(); } if (start_nextMatch) nextMatch(); else blviewRedraw(); return blixemGraph; } /* BLVIEWDESTROY frees all the allocated memory N.B. This memory was allocated in the calling program (acedb) WHAT THIS ROUTINE DOES NOT ADDRESS IS RESETTING THE LARGE NUMBER OF GLOBALS IN ANY SENSIBLE WAY......NOT IDEAL TO HAVE GLOBALS, EVEN LESS TO TO NOT RESET THEM....GRRRRRRRRRRRRRR............ Could free auxseq, auxseq2 and padseq too, but they'd have to be remalloc'ed next time then. */ static void blviewDestroy(GtkWidget *unused) { MSP *msp, *fmsp; BPMSP *tmsp; g_free(qname_G) ; messfree(q); /* Free the allocated sequences and names */ for (msp = MSPlist; msp; msp = msp->next) { if (msp->sseq && msp->sseq != padseq) { for (fmsp = msp->next; fmsp; fmsp = fmsp->next) if (fmsp->sseq == msp->sseq) fmsp->sseq = 0; /* Bug in fmapfeatures.c causes introns to have stale sseq's */ if (msp->score >= 0) { messfree(msp->sseq); messfree(msp->qname); messfree(msp->sname); messfree(msp->desc); arrayDestroy(msp->gaps); arrayDestroy(msp->xy); } } } for (msp = MSPlist; msp; ) { fmsp = msp; msp = msp->next; messfree(fmsp); } for (bpmsp = BPMSPlist.next; bpmsp; ) { tmsp = bpmsp; bpmsp = bpmsp->next; messfree(tmsp); } arrayDestroy(stringentEntropyarr); arrayDestroy(mediumEntropyarr); arrayDestroy(nonglobularEntropyarr); blixemWindow = NULL ; pickedMSP = NULL ; return ; } void drawBigPictMSP(MSP *msp, int BPx, char strand) { float msp_y, msp_sx, msp_ex, midx; if (FS(msp)) return; msp_sx = max((float)plusmin*(msp->qstart-BigPictStart)*BPx/BigPictLen +BPoffset, 4); msp_ex = max((float)plusmin*(msp->qend-BigPictStart)*BPx/BigPictLen +BPoffset, 4); if (msp->score == -1) /* EXON */ { oldcolor = graphColor(geneColor); oldLinew = graphLinewidth(.15); msp_y = 7.9 + queryy ; if (strand == 'R') msp_y += 1.5 ; graphRectangle(msp_sx, msp_y, msp_ex, msp_y + 0.7); graphColor(oldcolor); graphLinewidth(oldLinew); } else if (msp->score == -2) /* INTRON */ { oldcolor = graphColor(geneColor); oldLinew = graphLinewidth(.15); msp_y = 7.9 + queryy ; if (strand == 'R') msp_y += 1.5 ; midx = 0.5 * (msp_sx + msp_ex) ; graphLine (msp_sx, msp_y+0.4, midx, msp_y) ; graphLine (msp_ex, msp_y+0.4, midx, msp_y) ; graphColor(oldcolor); graphLinewidth(oldLinew); } else if (msp->score > 0) /* BLAST MATCH */ { if (!msp->sseq) getsseq(msp); if (!msp->id) calcID(msp); msp_y = (float)(140 - msp->id)/20 + queryy ; if (strand == 'R') msp_y += 9 ; if (!bpmsp->next) bpmsp->next = (BPMSP *)messalloc(sizeof(BPMSP)); bpmsp = bpmsp->next; strcpy(bpmsp->sname, msp->sname); bpmsp->desc = msp->desc; oldLinew = graphLinewidth(0.1); bpmsp->box = graphBoxStart(); bpmsp->graph = graphActive(); graphFillRectangle(msp_sx, msp_y, msp_ex, msp_y+.2); /* graphLine doesn't want to be picked */ graphBoxEnd(); graphBoxDraw(bpmsp->box, BLACK, TRANSPARENT); graphLinewidth(oldLinew); } } /* Function: return true if pos is a value in between or equal to start and end */ static int inRange(pos, start, end) { if (start < end) { if (pos >= start && pos <= end) return 1; else return 0; } else { if (pos >= end && pos <= start) return 1; else return 0; } } /* Checks if the msp is supposed to be drawn given its frame and position */ static void selectBigPictMSP(MSP *msp, int BPx, int BigPictStart, int BigPictLen) { int BPend = (actframe[1] == '+' ? BigPictStart+BigPictLen : BigPictStart-BigPictLen); /* Check if MSP is in range. There are three cases: 1. MSP spans beginning of BP range 2. MSP spans end of BP range 3. MSP spans entire BP range (i.e. BigPictStart is within the MSP-range) (4. MSP is included in BP range, falls into 1. and 2.) */ if (!inRange(msp->qstart, BigPictStart, BPend) && !inRange(msp->qend, BigPictStart, BPend) && !inRange(BigPictStart, msp->qstart, msp->qend)) return; if (actframe[1] == msp->qframe[1]) drawBigPictMSP(msp, BPx, 'M'); if (BigPictRev) if (actframe[1] != msp->qframe[1]) drawBigPictMSP(msp, BPx, 'R'); return; #ifdef OLD_CODE_TOO_COMPLICATED_AND_BUGGED__LEFT_FOR_AMUSEMENT if (( ((actframe[1] == '+' && msp->frame[1] == '+')) && (msp->qstart < BigPictStart && msp->qend > BigPictStart || /* left || span */ msp->qstart >= BigPictStart && msp->qend <= BigPictStart+BigPictLen || /* middle */ msp->qstart < BigPictStart+BigPictLen && msp->qend > BigPictStart+BigPictLen)) /* right || span */ || (actframe[1] == '-' && msp->frame[1] == '-' && (msp->qend > BigPictStart && msp->qstart < BigPictStart || msp->qend <= BigPictStart && msp->qstart >= BigPictStart-BigPictLen || msp->qend > BigPictStart-BigPictLen && msp->qstart < BigPictStart-BigPictLen))) drawBigPictMSP(msp, BPx, 'M'); if (BigPictRev) if ( (strchr(actframe, '+') && strchr(msp->frame, '-') && (msp->qend < BigPictStart && msp->qstart < BigPictStart+BigPictLen || msp->qend >= BigPictStart && msp->qstart <= BigPictStart+BigPictLen || msp->qend < BigPictStart+BigPictLen && msp->qstart > BigPictStart+BigPictLen)) || (strchr(actframe, '-') && strchr(msp->frame, '+') && (msp->qend > BigPictStart && msp->qstart < BigPictStart || msp->qend <= BigPictStart && msp->qstart >= BigPictStart-BigPictLen || msp->qend > BigPictStart-BigPictLen && msp->qstart < BigPictStart-BigPictLen))) drawBigPictMSP(msp, BPx, 'R'); #endif } /* Function: Put feature segment on the screen Note: this routine does not support reversed mode. Worry about that later. */ static void drawSEG(MSP *msp, float offset) { float msp_sy, msp_ey = queryy + offset-1, msp_sx, msp_ex; if (msp->qstart > BigPictStart+BigPictLen-1 || msp->qend < BigPictStart) return; msp_sx = max(SEQ2BP(msp->qstart), 4); msp_ex = max(SEQ2BP(msp->qend+1), 4); msp_sy = msp_ey - (float)msp->score/100; oldcolor = graphColor(msp->color); oldLinew = graphLinewidth(.1); graphFillRectangle(msp_sx, msp_sy, msp_ex, msp_ey); graphColor(BLACK); graphRectangle(msp_sx, msp_sy, msp_ex, msp_ey); graphText(msp->desc, msp_sx, msp_ey); graphColor(oldcolor); graphLinewidth(oldLinew); } /* Function: put XY curves on the screen. Note: this routine does not support reversed mode. Worry about that later. */ static void drawSEGxy(MSP *msp, float offset) { int i, inNotFilled=0, descShown=0; float msp_y = queryy + offset-1, x, y, xold=0, yold=0; oldcolor = graphColor(msp->color); oldLinew = graphLinewidth(.25); /* Must go through interpolated data outside the visible area in case the interpolation spans the start or the end of the visible area */ if (msp->shape == XY_INTERPOLATE) { for (i = 0; i < BigPictStart; i++) { if (arr(msp->xy, i, int) != XY_NOT_FILLED) { xold = SEQ2BP(i); yold = msp_y - (float)arr(msp->xy, i, int)/100*fsPlotHeight; } } } for (i = BigPictStart; i < BigPictStart+BigPictLen-1; i++) { if (arr(msp->xy, i, int) == XY_NOT_FILLED) { inNotFilled = 1; } else { x = SEQ2BP(i); y = msp_y - (float)arr(msp->xy, i, int)/100*fsPlotHeight; if (xold && (!inNotFilled || msp->shape == XY_INTERPOLATE)) { if (x != xold || y != yold) graphLine(xold, yold, x, y); if (!descShown && msp->desc) { int linecolor = graphColor(BLACK); graphText(msp->desc, (xold > BPoffset ? xold : BPoffset), msp_y); graphColor(linecolor); descShown = 1; } } xold = x; yold = y; inNotFilled = 0; } } /* Draw interpolated data if it spans the end of the visible area */ if (msp->shape == XY_INTERPOLATE && xold) { for (; i < qlen; i++) { if (arr(msp->xy, i, int) != XY_NOT_FILLED) { x = SEQ2BP(i); y = msp_y - (float)arr(msp->xy, i, int)/100*fsPlotHeight; graphLine(xold, yold, x, y); break; } } } graphColor(oldcolor); graphLinewidth(oldLinew); } static void drawEntropycurve(int start, int end, Array array, int win) { int i; float x, y, xold=0, yold=0; oldLinew = graphLinewidth(.3); for (i = start; i < end; i++) { if (i > win/2 && i < qlen - win/2) { x = SEQ2BP(i); y = queryy + 9 - arr(array, i, float)*2; if (xold) graphLine(xold, yold, x, y); xold = x; yold = y; /*if (arr(array, i, float) < min) min = arr(array, i, float); if (arr(array, i, float) > max) max = arr(array, i, float);*/ } /**c = q[i]; graphText(c, SEQ2BP(i), queryy+5);*/ } /* printf("min = %f , max = %f\n", min, max); */ graphLinewidth(oldLinew); } /* Draw separator line a la Mosaic
*/ static void drawSeparator(void) { oldLinew = graphLinewidth(separatorwidth); if (squash) graphColor(RED); else graphColor(DARKGRAY); graphLine(0, queryy-1.0, nx+1, queryy-1.0); graphLinewidth(.2); graphColor(WHITE); graphLine(0, queryy-1.1+0.5*separatorwidth, nx+1, queryy-1.1+0.5*separatorwidth); graphColor(BLACK); graphLinewidth(oldLinew); } int frame2graphno(int frame) { if (blastn) { if (frame == 1) return 0; else return 1; } else { if (abs(frame) == 1) return 0; else if (abs(frame) == 2) return 1; else return 2; } } /* blViewRedraw Redraws the view in the disp_region */ void blviewRedraw(void) { unsigned char querysym, subjectsym ; int i, dbdisp, /* number of msp's displayed */ frame=0, curframe, DNAline, TickStart, TickUnit, gridx, pos, msp_offset, prev_offset, exon_end, firstRes; MSP *msp; float alignstart; int charHeight; float fy; int py; char *query = NULL, *lastname = NULL ; char text[MAXALIGNLEN+1] ; gdk_window_get_geometry(blixemWindow->window, NULL, NULL, &oldWidth, &oldHeight, NULL); settingsRedraw(); graphActivate(blixemGraph); graphClear(); graphBoxDraw(0, backgColor, backgColor); graphTextFormat(FIXED_WIDTH); graphScreenSize( NULL, NULL, NULL, &fy, NULL, &py); charHeight = (int)((float)py/fy)+1; for (msp = MSPlist; msp ; msp = msp->next) msp->box = 0; lastbox = 0; queryy = separator_y = 0.2; /* Calculate window sizes **************************/ graphFitBounds (&nx, &ny); nx -= 2; /* scrollbars */ graphColor(backgColor); graphRectangle(0, 0, nx+100, ny+100);graphColor(BLACK); if (wholePrintOn) { nx = displen/symbfact + 43; } else { displen = (nx - 43)*symbfact ; /* Keep spacious for printing */ } /* Window boundary check */ if (strchr(actframe, '+')) { if (displen > qlen - (symbfact+1) ) /* Window too big for sequence */ { dispstart = 1; displen = qlen - (symbfact+1); if (blastp || blastn) displen = qlen; } else if (dispstart < 1) /* Off the left edge */ dispstart = 1 ; else if (dispstart + displen > qlen - (blastx||tblastx ? 3 : -1)) /* Off the right edge */ dispstart = qlen - (blastx||tblastx ? 3 : -1) - displen; } else if (strchr(actframe, '-')) { if (displen > qlen - (symbfact+1)) /* Window too big for sequence */ { dispstart = qlen; displen = qlen - (symbfact+1); if (blastn) displen = qlen; } else if (dispstart > qlen) /* Off the left edge */ dispstart = qlen ; else if (dispstart - displen < (blastx||tblastx ? 4 : 0) ) /* Off the right edge */ dispstart = (blastx||tblastx ? 4 : 0) + displen ; } /* Draw Big Picture **************************/ if (BigPictON) { BigPictLen = displen * BigPictZoom; if (BigPictLen > qlen) { BigPictLen = qlen; BigPictZoom = (float)qlen/displen; } BigPictStart = dispstart + plusmin*displen/2 - plusmin*BigPictLen/2; if (plusmin > 0) { if (BigPictStart + BigPictLen > qlen) BigPictStart = qlen - BigPictLen; if (BigPictStart < 1) BigPictStart = 1; } else { if (BigPictStart - BigPictLen < 1) BigPictStart = BigPictLen; if (BigPictStart > qlen) BigPictStart = qlen; } BPx = nx - BPoffset; graphButton("Zoom In", zoomIn, .5, queryy +.1); graphButton("Zoom Out", zoomOut, 9, queryy +.1); graphButton("Whole", zoomWhole, 18.5, queryy +.1); /* Draw position lines (ticks) */ TickUnit = (int)pow(10.0, floor(log10((float)BigPictLen))); /* Basic scaleunit */ while (TickUnit*5 > BigPictLen) TickUnit /= 2; /* Final scaleunit */ TickStart = (int)TickUnit*( floor((float)(BigPictStart+qoffset)/TickUnit + .5)); /* Round off */ for (i=TickStart; (plusmin == 1 ? i < BigPictStart+qoffset + BigPictLen : i > BigPictStart+qoffset - BigPictLen); i = i + plusmin*TickUnit) { gridx = (float)plusmin*(i-BigPictStart-qoffset)*BPx/BigPictLen + BPoffset; if (gridx > 24 && gridx < nx-10) { graphText(messprintf("%d", i), gridx, queryy); graphColor(gridColor); graphLine(gridx, queryy+1, gridx, queryy+7 /*+fsTotalHeight(MSPlist)+2*/ ); if (BigPictRev) graphLine(gridx, queryy+11, gridx, queryy+16); graphColor(BLACK); } } /* Draw Percentage lines */ for (i=0; i<=100; i += 20) { graphText(messprintf("%3i%%", i), 0, queryy + (float)(130-i)/20); if (BigPictRev) graphText(messprintf("%3i%%", i), 0, queryy+9 + (float)(130-i)/20); graphColor(gridColor); graphLine(4, queryy + (float)(140-i)/20, nx+1, queryy + (float)(140-i)/20); if (BigPictRev) graphLine(4, queryy+9 + (float)(140-i)/20, nx+1, queryy+9 + (float)(140-i)/20); graphColor(BLACK); } /* Draw active window frame */ oldLinew = graphLinewidth(.3); BPboxstart = (float)plusmin*(dispstart-BigPictStart)*BPx/BigPictLen + BPoffset; BPboxwidth = (float)displen*BPx/BigPictLen; BPbox = graphBoxStart(); graphRectangle(BPboxstart, queryy +1.7, BPboxstart+BPboxwidth, queryy +1.7 + BPboxheight); graphBoxEnd(); graphBoxDraw(BPbox, geneColor, TRANSPARENT); graphLinewidth(.5); graphLinewidth(oldLinew); /* Draw Big Picture MSPs */ lastExonx = 0; bpmsp = &BPMSPlist; for (msp = MSPlist; msp; msp = msp->next) { if (strcmp(msp->sname, HighlightSeq) && !strMatch(msp->sname, searchSeq)) selectBigPictMSP(msp, BPx, BigPictStart, BigPictStart+BigPictLen); } /* Draw the highlighted later, so they're not blocked by black ones */ for (msp = MSPlist; msp; msp = msp->next) { if (!strcmp(msp->sname, HighlightSeq) || strMatch(msp->sname, searchSeq)) selectBigPictMSP(msp, BPx, BigPictStart, BigPictStart+BigPictLen); } if (bpmsp->next) *bpmsp->next->sname = 0; queryy += 10; if (BigPictRev) queryy += 8; /* Draw separator line with perforation * / oldLinew = graphLinewidth(1); if (squash) graphColor(RED); else graphColor(BLACK); graphLine(0, queryy-.5, nx+1, queryy-.5); graphLinewidth(.1); graphColor(WHITE); for (i = 0; i <= nx+1; i++) graphLine((float)i, queryy-.5, (float)i+.8, queryy-.5); graphColor(BLACK); graphLinewidth(oldLinew); */ /* Draw entropy curves **************************/ if (entropyOn) { int y; drawSeparator(); /* Draw scale */ for (i = 1; i <= 4; i++) { y = queryy+5 - (i-2)*2; graphText(messprintf("%d", i), 1, y-.5); graphColor(DARKGRAY); graphLine (BPoffset, y, nx, y); graphColor(BLACK); } /* Draw entropy curves */ graphColor(stringentEntropycolor); drawEntropycurve(BigPictStart, BigPictStart+BigPictLen, stringentEntropyarr, stringentEntropywin); graphColor(mediumEntropycolor); drawEntropycurve(BigPictStart, BigPictStart+BigPictLen, mediumEntropyarr, mediumEntropywin); graphColor(nonglobularEntropycolor); drawEntropycurve(BigPictStart, BigPictStart+BigPictLen, nonglobularEntropyarr, nonglobularEntropywin); queryy += 9; } /* Draw colored feature segments ********************************/ if (fsArr && arrayMax(fsArr)) { float maxy=0; /* drawSeparator();*/ if (fsArr) { for (i = 0; i < arrayMax(fsArr); i++) arrp(fsArr, i, FEATURESERIES)->y = 0; } for (msp = MSPlist; msp; msp = msp->next) { if (FS(msp) && arrp(fsArr, msp->fs, FEATURESERIES)->on && (!strcmp(msp->qname, qname_G) || !strcmp(msp->qname, "@1"))) { if (msp->type == FSSEG) { drawSEG(msp, fs2y(msp, &maxy, 1+1)); } else if (msp->type == XY) { drawSEGxy(msp, fs2y(msp, &maxy, fsPlotHeight+1)); } } } queryy += maxy + 2; } separator_y = queryy; } /* Draw buttons & boxes **************************/ #if 0 if (BigPictON) { menuUnsetFlags(menuItem(settingsMenu, BigPictToggleRevStr), MENUFLAG_DISABLED); } else if (blastn || blastx || tblastx) { menuSetFlags(menuItem(settingsMenu, BigPictToggleRevStr), MENUFLAG_DISABLED); } #endif if (!oneGraph) gtk_widget_set_usize(gexGraph2Widget(blixemGraph), -2, charHeight*queryy); for (curframe = 1; abs(curframe) <= symbfact; curframe += (blastn ? -2 : 1)) { int frameno; frame = plusmin * curframe; sprintf(actframe, "(%+d)", frame); if (blastn && curframe == -1) compN = 1; else compN = 0; alignstart = NAMESIZE + 22 + (blastx || tblastx ? (float)(curframe - 1)/3 : 0); frameno = frame2graphno(curframe); if (!oneGraph) { graphActivate(frameGraphQ[frameno]); queryy = 0; /* at start of new graph */ graphClear(); graphBoxDraw(0, backgColor, backgColor); graphTextFormat(FIXED_WIDTH); graphColor(backgColor); graphRectangle(0, 0, nx+100, ny+100); graphColor(BLACK); } if (frameno == 0) { if (!blastn) { separator_y = queryy; queryy += 3; DNAline = queryy-2; } else { queryy += 1; DNAline = queryy; } graphText( "Score %ID Start", 14, queryy); graphText( "End", NAMESIZE + 23 + displen/symbfact, queryy); queryy++; graphLine(NAMESIZE + 1.0, queryy-1, NAMESIZE + 1.0, ny+100); graphLine(NAMESIZE + 7.5, queryy-1, NAMESIZE + 7.5, ny+100); graphLine(NAMESIZE + 11.5, queryy-1, NAMESIZE + 11.5, ny+100); graphLine(NAMESIZE + 21.5, queryy-1, NAMESIZE + 21.5, ny+100); graphLine(NAMESIZE + 22.5 + displen/symbfact, queryy-1, NAMESIZE + 22.5 + displen/symbfact, ny+100); graphLine(NAMESIZE + 22.5 + displen/symbfact/2, DNAline-1, NAMESIZE + 22.5 + displen/symbfact/2, DNAline); } /* Draw the query (ususally black text on yellow) ********************/ if (blastx || tblastx) { /* Force dispstart to cohere to the frame */ if (strchr(actframe, '-')) while ((qlen - dispstart +1 +frame) % symbfact) dispstart--; else while ((dispstart - frame) % symbfact) dispstart++; } if (!(query = getqseq(dispstart, dispstart + plusmin*(displen-1), q))) return; if (compN) compl(query); if (!colortoggle) graphColor(hiColor); else graphColor(WHITE); graphFillRectangle(0, queryy, nx, queryy+1); graphColor(BLACK); graphText(query, alignstart, queryy); #ifdef ED_G_NEVER_INCLUDE_THIS_CODE /* check whether we really needed the left align junk.... */ graphText(messprintf ("%-8s%s", abbrevTxt(qname_G, NAMESPACE+4), actframe), 1, queryy); #endif /* ED_G_NEVER_INCLUDE_THIS_CODE */ graphText(messprintf ("%s%s", abbrevTxt(qname_G, NAMESPACE+4), actframe), 1, queryy); graphText(messprintf ("%9d", dispstart + qoffset), NAMESPACE+12, queryy); sprintf (text, "%-9d", dispstart+plusmin*displen + qoffset -plusmin); graphText (text, alignstart + 1 + displen/symbfact, queryy); if (blastx || tblastx) { /* Draw the DNA sequence */ if (!oneGraph) graphActivate(frameGraphQ[0]); graphText(get3rd_base(dispstart, dispstart + plusmin*(displen-1), q), alignstart, DNAline++); if (!oneGraph) graphActivate(frameGraphQ[frameno]); } if (!oneGraph) { gtk_widget_set_usize(gexGraph2Widget(frameGraphQ[frameno]), -2, charHeight*(queryy+1)); graphRedraw(); frameno = frame2graphno(curframe); graphActivate(frameGraph[frameno]); queryy = 0; /* at start of new graph */ graphClear(); graphBoxDraw(0, backgColor, backgColor); graphTextFormat(FIXED_WIDTH); graphColor(backgColor); graphRectangle(0, 0, nx+100, ny+100); graphColor(BLACK); graphLine(NAMESIZE + 1.0, 0, NAMESIZE + 1.0, ny+100); graphLine(NAMESIZE + 7.5, 0, NAMESIZE + 7.5, ny+100); graphLine(NAMESIZE + 11.5, 0, NAMESIZE + 11.5, ny+100); graphLine(NAMESIZE + 21.5, 0, NAMESIZE + 21.5, ny+100); graphLine(NAMESIZE + 22.5 + displen/symbfact, 0, NAMESIZE + 22.5 + displen/symbfact, ny+100); } /* Draw the dbhits *********************/ dbdisp = oneGraph ? 0 : -1; fetchCount = 0; for (msp = MSPlist ; msp ; msp = msp->next) { /* Current frame MSP - display if in window */ if (!strcmp(msp->qframe, actframe) || (blastn && msp->qframe[1] == actframe[1])) { if ((!compN && frame>0 && msp->qstart <= dispstart + displen && msp->qend >= dispstart) || (!compN && frame<0 && msp->qstart >= dispstart - displen && msp->qend <= dispstart) || ( compN && frame<0 && msp->qend <= dispstart + displen && msp->qstart >= dispstart) || ( compN && frame>0 && msp->qend >= dispstart - displen && msp->qstart <= dispstart)) { if (msp->score == -1) { /* EXON */ if (blastx || tblastx || (blastn && msp->qframe[1] == actframe[1]) ) { dbdisp++; if (!compN) { pos = (msp->qstart - dispstart) / symbfact ; exon_end = (msp->qend - dispstart) / symbfact ; } else { pos = dispstart - msp->qend; exon_end = dispstart - msp->qstart; } if (frame < 0) { pos = -pos; exon_end = -exon_end; } exon_end++; if (pos < 0) pos = 0 ; if (exon_end > displen/symbfact) exon_end = displen/symbfact; graphColor(geneColor); oldLinew = graphLinewidth(0.3) ; graphRectangle(alignstart+pos, queryy, alignstart+exon_end, queryy+1); graphColor(hiColor); graphFillRectangle(alignstart+pos, queryy+dbdisp, alignstart+exon_end, queryy+dbdisp+1); graphColor(BLACK); graphText(abbrevTxt(msp->sname, NAMESIZE), 1, queryy+dbdisp); sprintf(text, "%5d %3d %9d", msp->score, msp->id, (compN? msp->send : msp->sstart)); graphText(text, NAMESIZE+1, queryy+dbdisp); sprintf(text, "%-6d", (compN? msp->sstart : msp->send)); graphText(text, alignstart+1+displen/symbfact, queryy+dbdisp); /* graphText(msp->sseq, alignstart+pos, queryy+dbdisp); */ graphLinewidth(oldLinew); } } else if (msp->score >= 0) { BOOL squashdo = 0; int seq_len = 0 ; if (FS(msp)) { if (squashFS) squashdo = 1; } else if (squash) squashdo = 1; if (FS(msp) && !arrp(fsArr, msp->fs, FEATURESERIES)->on) continue; if (FS(msp)) msp->sseq = q; else { if (!msp->sseq) getsseq(msp); } /* Sanity check on match sequence coords to catch */ /* errors in homolgy data, no point in displaying them.*/ seq_len = strlen(msp->sseq) ; if (msp->sstart < 1 || msp->send < 1 || msp->sstart > seq_len || msp->send > seq_len) { messerror("Match coordinates for homology %s are partly or completely " "outside of its own sequence. " "Sequence for %s is %d long but the start/end " "coordinates are %d to %d.", msp->sname, msp->sname, seq_len, msp->sstart, msp->send) ; continue ; } if (!msp->id) calcID(msp); if (!squashdo || !lastname || strcmp(msp->sname, lastname)) dbdisp++; lastname = msp->sname; if (!FS(msp)) { msp->box = graphBoxStart(); msp->graph = graphActive(); } if ((cp = (char *)strchr(msp->sname, ':'))) cp++; else cp = msp->sname; strncpy(text, cp, NAMESIZE); text[NAMESIZE] = 0; graphText(text, 1, queryy+dbdisp); if (!squashdo) { sprintf(text, "%5d %3d", msp->score, msp->id); strcat(text, messprintf(" %9d", (compN ? msp->send : msp->sstart))); graphText(text, NAMESIZE+1, queryy+dbdisp); sprintf(text, "%-6d", (compN ? msp->sstart : msp->send)); graphText(text, alignstart+1+displen/symbfact, queryy+dbdisp); } firstRes = -1 ; for (i = 0 ; i < displen/symbfact ; i++) { text[i] = ' '; if ( (!compN && frame>0 && msp->qstart <= dispstart + i*symbfact && msp->qend >= dispstart + i*symbfact) || (!compN && frame<0 && msp->qstart >= dispstart - i*symbfact && msp->qend <= dispstart - i*symbfact) || (compN && frame<0 && msp->qend <= dispstart + i && msp->qstart >= dispstart + i) || (compN && frame>0 && msp->qend >= dispstart - i && msp->qstart <= dispstart - i)) { if (firstRes == -1) firstRes = i; msp_offset = gapCoord(msp, dispstart+plusmin*i*symbfact, symbfact); prev_offset = gapCoord(msp, dispstart+plusmin*(i-1)*symbfact, symbfact); if (prev_offset == msp_offset) subjectsym = '.' ; else subjectsym = msp->sseq[msp_offset - 1] ; querysym = query[i]; if (FS(msp)) { if (!colortoggle) graphColor(msp->color); else graphColor(backgColor); } else if (freeupper(querysym) == freeupper(subjectsym)) { if (IDdots) subjectsym = '.'; if (!colortoggle && !IDdots) graphColor(IDcolor); else graphColor(backgColor); } else if (!blastn && PAM120[aa_atob[(unsigned int)querysym]-1 ][aa_atob[(unsigned int)subjectsym]-1 ] > 0) { if (!colortoggle) graphColor(consColor); else graphColor(backgColor); } else { /* Mismatch */ if (IDdots && !colortoggle) { if (subjectsym == '.') subjectsym = '-'; graphColor(IDcolor); } else graphColor(backgColor); } if (HiliteSins && ((isdigit(subjectsym) || subjectsym == '(' || subjectsym == ')') || (isalpha(subjectsym) && subjectsym == freelower(subjectsym)))) graphColor(RED); if (HiliteUpperOn && isupper(subjectsym)) graphColor(RED); if (HiliteLowerOn && islower(subjectsym)) graphColor(RED); text[i] = subjectsym ; graphFillRectangle(i+alignstart, queryy+dbdisp, i+alignstart+1, queryy+dbdisp+1); if (abs(prev_offset - msp_offset) > 1) { graphColor(YELLOW); graphFillRectangle(alignstart+i-0.2, queryy+dbdisp, alignstart+i+0.2, queryy+dbdisp+1); graphColor(BLACK); } } } text[i] = '\0'; graphColor(BLACK); graphText(text, alignstart, queryy+dbdisp); if (!FS(msp)) { graphBoxEnd(); graphBoxDraw(msp->box, BLACK, TRANSPARENT); } if (squashdo) { graphColor(RED); graphLine(alignstart+firstRes, queryy+dbdisp, alignstart+firstRes, queryy+dbdisp+1); graphColor(BLACK); } } if (!FS(msp) && DESCon && msp->desc) { /* Draw DESC line */ int box; dbdisp++; box = graphBoxStart(); graphText(messprintf("%s %s", msp->sname, msp->desc), 1, queryy+dbdisp); graphBoxEnd(); graphBoxDraw(box, BLACK, WHITE); } } } /* else not in active frame */ } /* End of HSPs */ queryy += dbdisp + 2; if (!wholePrintOn) graphRedraw(); if (!oneGraph) { if (queryy == 1) gtk_widget_hide(gexGraph2Widget(frameGraph[frameno])); else { graphTextBounds(nx, queryy-1); gtk_widget_show(gexGraph2Widget(frameGraph[frameno])); } } } /* End of frames */ if (oneGraph) gtk_widget_set_usize(gexGraph2Widget(blixemGraph), -2, charHeight*queryy); else graphActivate(blixemGraph); if (blastn) { frame = -frame; sprintf(actframe, "(%+d)", frame); } if (blastx || tblastx) dispstart -= plusmin*2; if (!wholePrintOn) graphRedraw(); highlightProteinboxes(TRUE); messfree(query); setMenuCheckmarks(); return ; } /* GET3RD_BASE returns every third base from string q */ static char *get3rd_base(int start, int end, char *q) { static int i, len; static char *bases = 0, *aux, *aux2; if (start < 1 || end > qlen) { messerror ( "Genomic sequence coords out of range: %d - %d\n", start, end); return NULL; } if (!bases) { bases = messalloc(qlen+1); aux = messalloc(qlen+1); aux2 = messalloc(qlen+1); } len = abs(end-start) + 1; if (start < end) for (i=start; i < end; i += 3 ) bases[(i-start)/3] = q[i-1]; else if (start > end) /* Reverse and complement it first */ { strncpy(aux2, q+end-1, start-end+1); aux2[start-end+1] = 0; if (!revcomp(aux, aux2)) messcrash ("Cannot reverse & complement") ; for (i=0; i < len; i += 3) bases[i/3] = aux[i]; } else return NULL; bases[len/3] = '\0'; return bases; } /* calcID: caculated percent identity of an MSP * * There seems to be a general problem with this routine for protein * alignments, the existing code certainly does not do the right thing. * I have fixed this routine for gapped sequence alignments but not for * protein stuff at all. * * To be honest I think this routine is a _waste_ of time, the alignment * programs that feed data to blixem produce an identity anyway so why * not use that...why reinvent the wheel...... * * */ static void calcID(MSP *msp) { static int id, i, len ; char *qseq ; if (msp->sseq && msp->sseq != padseq) { /* Note that getqseq() will reverse complement if qstart > qend, this means that * where there is no gaps array the comparison is trivial as coordinates can be * ignored and the two sequences just whipped through. */ if (!(qseq = getqseq(msp->qstart, msp->qend, q))) { messout ( "calcID failed: Don't have genomic sequence %d - %d\n", msp->qstart, msp->qend); msp->id = 0; return; } /* NOTE, tblastn/x are not implemented for gaps yet. */ if (!(msp->gaps) || arrayMax(msp->gaps) == 0) { /* Ungapped alignments. */ if (tblastn) { len = msp->qend - msp->qstart + 1; for (i=0, id=0; i < len; i++) if (freeupper(msp->sseq[i]) == freeupper(qseq[i])) id++; } else if (tblastx) { len = abs(msp->qend - msp->qstart + 1)/3; for (i=0, id=0; i < len; i++) if (freeupper(msp->sseq[i]) == freeupper(qseq[i])) id++; } else /* blastn, blastp & blastx */ { len = msp->send - msp->sstart + 1; for (i=0, id=0; i< len; i++) if (freeupper(msp->sseq[i + msp->sstart -1]) == freeupper(qseq[i])) id++; } } else { /* Gapped alignments. */ int i ; Array gaps = msp->gaps; BOOL forward ; if (strchr(msp->qframe, '+')) forward = TRUE ; else forward = FALSE ; /* To do tblastn and tblastx is not imposssible but would like to work from * examples to get it right.... */ if (tblastn) { printf("not implemented yet\n") ; } else if (tblastx) { printf("not implemented yet\n") ; } else { /* blastn and blastp remain simple but blastx is more complex since the query * coords are nucleic not protein. */ int factor ; if (blastx) factor = 3 ; else factor = 1 ; len = 0 ; for (i = 0, id = 0 ; i < arrayMax(gaps) ; i++) { SMapMap *m = arrp(gaps, i, SMapMap); int j, k ; int q_start ; len += (m->s2 - m->s1 + 1) ; if (forward) { q_start = (m->r1 - msp->qstart) / factor ; } else { q_start = -(m->r1 - msp->qstart) / factor ; } for (j = (m->s1 - 1), k = q_start ; j < m->s2 ; j++, k++) { char *sub, *query ; char *dummy ; #ifdef ED_G_NEVER_INCLUDE_THIS_CODE /* for debug..... */ sub = msp->sseq + j ; query = qseq + k ; #endif /* ED_G_NEVER_INCLUDE_THIS_CODE */ if (freeupper(msp->sseq[j]) == freeupper(qseq[k])) id++ ; #ifdef ED_G_NEVER_INCLUDE_THIS_CODE else dummy = sub ; #endif /* ED_G_NEVER_INCLUDE_THIS_CODE */ } } } } msp->id = (int)((float)100*id/len + .5); messfree(qseq); } else msp->id = 0 ; return ; } static void assignPadseq(MSP *msp) { static int padseqlen=0; char *oldpadseq; int len = max(msp->sstart, msp->send); MSP *hsp; if (!padseq) { padseq = messalloc(INITDBSEQLEN+1); memset(padseq, '-', INITDBSEQLEN); padseqlen = INITDBSEQLEN; } if (len > padseqlen) { oldpadseq = padseq; messfree(padseq); padseq = messalloc(len+1); memset(padseq, '-', len); padseqlen = len; /* Change all old padseqs to new */ for (hsp = MSPlist; hsp ; hsp = hsp->next) if (hsp->sseq == oldpadseq) hsp->sseq = padseq; } msp->sseq = padseq; } static void allocAuxseqs(int len) { if (auxseq) { messfree(auxseq); messfree(auxseq2); } auxseq = messalloc(len+1); auxseq2 = messalloc(len+1); auxseqlen = len; } /* GETQSEQ translates a segment of the query seq (with 'sequence' coords = 1...) */ static char *getqseq(int start, int end, char *q) { char *query; if (start < 1 || end < 1 || start > strlen(q) || end > strlen(q)) { messout ( "Requested query sequence %d - %d out of available range: 1 - %d\n", start, end, strlen(q)); return NULL; } if (blastp || tblastn) { query = messalloc(end-start+2); strncpy(query, q+start-1, end-start+1); query[end-start+1] = 0; return query; } if (abs(end-start)+1 > auxseqlen) allocAuxseqs(abs(end-start)+1); if (start <= end) { strncpy(auxseq, q+start-1, end-start+1); auxseq[end-start+1] = 0; } else if (start > end) /* Reverse and complement it */ { strncpy(auxseq2, q+end-1, start-end+1); auxseq2[start-end+1] = 0; if (!revcomp(auxseq, auxseq2)) messcrash ("Cannot reverse & complement") ; } else return NULL; if (blastn) { query = messalloc(strlen(auxseq)+1); strcpy(query, auxseq); return query; } /* Translate the DNA sequence */ if (!(query = translate(auxseq, stdcode1))) messcrash ("Cannot translate the genomic sequence") ; return query; } /* GETSSEQ fetches the database sequence from an external database, * currently uses either efetch or pfetch. */ static void getsseq(MSP *msp) { MSP *auxmsp; int len; char *fetch_prog ; char *seq_buf = NULL ; if (!*msp->sname) { messout ( "Nameless HSP at %d-%d - skipping Efetch\n", msp->qstart+qoffset, msp->qend+qoffset); assignPadseq(msp); return ; } fetch_prog = getFetchProg(fetchMode) ; if (verbose) printf("%sing %s\n", fetch_prog, msp->sname); else { if (!fetchCount) { fetchCount++; printf("\n%sing external sequences", fetch_prog); } printf("."); fflush(stdout); } if (msp->score >= 0) { if ((seq_buf = getSeq(msp->sname, fetchMode))) { msp->sseq = messalloc(strlen(seq_buf)+1); /* Harmonize upper and lower case - (t)blastx always translate * the query to upper case */ if (isupper(*q) || tblastx || blastx) { for (i=0; seq_buf[i]; i++) msp->sseq[i] = freeupper(seq_buf[i]); msp->sseq[i] = 0; } else { for (i=0; seq_buf[i]; i++) msp->sseq[i] = freelower(seq_buf[i]); msp->sseq[i] = 0; } /* Check illegal offsets */ len = strlen(msp->sseq); for (auxmsp = MSPlist; auxmsp ; auxmsp = auxmsp->next) if (!strcmp(auxmsp->sname, msp->sname) && auxmsp->send > len ) { printf("%s HSP with offset beyond sequence (%d > %d) - using pads\n", msp->sname, auxmsp->send, len); assignPadseq(msp); break; } } else { #if !defined(ACEDB) messout ( "Unable to %s %s - using pads instead\n", fetch_prog, msp->sname); #endif /* Sequence not in database - fill up with pads */ assignPadseq(msp); } /* Set sseq for all MSPs of this subject */ for (auxmsp = MSPlist; auxmsp ; auxmsp = auxmsp->next) if (!strcmp(auxmsp->sname, msp->sname)) { if (msp->sseq == padseq) assignPadseq(auxmsp); else auxmsp->sseq = msp->sseq; calcID(auxmsp); } } return ; } /* Get a sequence entry using either efetch or pfetch. */ static char *fetchSeqRaw(char *seqname) { char *result = NULL ; char *fetch_prog = NULL ; char *seq_buf = NULL ; if (!*seqname) { messout ( "Nameless sequence - skipping Efetch\n"); return NULL ; } fetch_prog = getFetchProg(fetchMode) ; if ((seq_buf = getSeq(seqname, fetch_prog))) { result = messalloc(strlen(seq_buf)+1) ; strcpy(result, seq_buf) ; } else { messout("Unable to %s %s \n", fetch_prog, seqname); result = 0; } return result ; } /* Set program to be used for fetching sequences depending on setting * of fetchmode: if fetchmode is pfetch we use pfetch, _otherwise_ efetch. */ static char *getFetchProg(char *fetch_mode) { char *fetch_prog = NULL ; if (!strcmp(fetch_mode, "pfetch")) fetch_prog = "pfetch" ; else fetch_prog = "efetch" ; return fetch_prog ; } /* Common routine to call efetch or pfetch to retrieve a sequence entry. */ static char *getSeq(char *seqname, char *fetch_prog) { char *result = NULL ; static char *fetchstr = NULL ; char *cp ; FILE *pipe ; int len ; FILE *fp = fopen("myoutput","w"); if (!strcmp(fetch_prog, "pfetch")) { /* --client gives logging information to pfetch server, * -q Sequence only output (one line) */ fetchstr = hprintf(0, "%s --client=acedb_%s_%s -q '%s' &", fetch_prog, getSystemName(), getLogin(TRUE), seqname) ; } else { fetchstr = hprintf(0, "%s -q '%s'", fetch_prog, seqname) ; } printf("%sing %s...\n", fetch_prog, seqname); /* Try and get the sequence, if we overrun the buffer then we need to try again. */ if (!(pipe = (FILE*)popen(fetchstr, "r"))) messcrash("Failed to open pipe %s\n", fetchstr); len = 0; cp = auxseq ; while (!feof(pipe)) { if (len < auxseqlen) *cp++ = fgetc(pipe); else fgetc(pipe); len++; fprintf(fp, "%s", cp); } pclose(pipe); /* Check if auxseq was long enough */ if (len > auxseqlen) { allocAuxseqs(len); cp = auxseq; if (!(pipe = (FILE*)popen(fetchstr, "r"))) messcrash("Failed to open pipe %s\n", fetchstr); while (!feof(pipe)) { *cp++ = fgetc(pipe); } pclose(pipe); } *cp = 0; if (len > 1) /* Otherwise failed */ { if ((cp = (char *)strchr(auxseq, '\n'))) *cp = 0; result = auxseq ; } else { result = NULL ; } if (fetchstr) messfree(fetchstr) ; fclose(fp); return result ; } /******************************************************************************** ** BIG PICTURE ROUTINES *** ********************************************************************************/ static void GSettings(GtkButton *button, gpointer args) { blixemSettings(); } static void GGoto(GtkButton *button, gpointer args) { Goto(); } static void GprevMatch(GtkButton *button, gpointer args) { prevMatch(); } static void GnextMatch(GtkButton *button, gpointer args) { nextMatch(); } static void GscrollLeftBig(GtkButton *button, gpointer args) { scrollLeftBig(); } static void GscrollRightBig(GtkButton *button, gpointer args) { scrollRightBig(); } static void GscrollLeft1(GtkButton *button, gpointer args) { scrollLeft1(); } static void GscrollRight1(GtkButton *button, gpointer args) { scrollRight1(); } static void GToggleStrand(GtkButton *button, gpointer args) { ToggleStrand(); } static void GHelp(GtkButton *button, gpointer args) { blviewHelp(); } static void comboChange(GtkEditable *edit, gpointer args) { gchar *val = gtk_editable_get_chars(edit, 0, -1); if (GTK_WIDGET_REALIZED(blixemWindow)) { if (strcmp(val, "score") == 0) sortByScore(); else if (strcmp(val, "identity") == 0) sortById(); else if (strcmp(val, "name") == 0) sortByName(); else if (strcmp(val, "position") == 0) sortByPos(); } g_free(val); } static void buttonAttach(GtkHandleBox *handlebox, GtkWidget *toolbar, gpointer data) { gtk_widget_set_usize(toolbar, 1, -2); } static void buttonDetach(GtkHandleBox *handlebox, GtkWidget *toolbar, gpointer data) { gtk_widget_set_usize(toolbar, -1, -2); } static GtkWidget *makeButtonBar(void) { GtkWidget *handleBox = gtk_handle_box_new(); #ifdef GTK2 GtkWidget *toolbar = gtk_toolbar_new(); #else GtkWidget *toolbar = gtk_toolbar_new(GTK_ORIENTATION_HORIZONTAL, GTK_TOOLBAR_TEXT); #endif GtkWidget *entry = gtk_entry_new(); GtkWidget *combo = gtk_combo_new(); GList *sortList = NULL; /* next three lines stop toolbar forcing the size of a blixem window */ gtk_signal_connect(GTK_OBJECT(handleBox), "child-attached", GTK_SIGNAL_FUNC(buttonAttach), NULL); gtk_signal_connect(GTK_OBJECT(handleBox), "child-detached", GTK_SIGNAL_FUNC(buttonDetach), NULL); gtk_widget_set_usize(toolbar, 1, -2); gtk_editable_set_editable(GTK_EDITABLE(entry), FALSE); gtk_widget_set_usize(entry, 350, -2); messageWidget = entry; sortList = g_list_append(sortList, "score"); sortList = g_list_append(sortList, "identity"); sortList = g_list_append(sortList, "name"); sortList = g_list_append(sortList, "position"); gtk_editable_set_editable(GTK_EDITABLE(GTK_COMBO(combo)->entry), FALSE); gtk_widget_set_usize(GTK_COMBO(combo)->entry, 80, -2); gtk_signal_connect(GTK_OBJECT(GTK_COMBO(combo)->entry), "changed", (GtkSignalFunc)comboChange, NULL); gtk_combo_set_popdown_strings(GTK_COMBO(combo), sortList); gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), "identity"); gtk_container_add(GTK_CONTAINER(handleBox), toolbar); gtk_toolbar_append_widget(GTK_TOOLBAR(toolbar), gtk_label_new(" Sort HSPs by: "), NULL, NULL); gtk_toolbar_append_widget(GTK_TOOLBAR(toolbar), combo, NULL, NULL); gtk_toolbar_append_item(GTK_TOOLBAR(toolbar), "Settings", "Open the Preferences Window", NULL, NULL, GTK_SIGNAL_FUNC(GSettings), NULL); gtk_toolbar_append_item(GTK_TOOLBAR(toolbar), "Goto", "Go to specified co-ordinates", NULL, NULL, GTK_SIGNAL_FUNC(GGoto), NULL); gtk_toolbar_append_item(GTK_TOOLBAR(toolbar), "< match", "Next (leftward) match", NULL, NULL, GTK_SIGNAL_FUNC(GprevMatch), NULL); gtk_toolbar_append_item(GTK_TOOLBAR(toolbar), "match >", "Next (rightward) match", NULL, NULL, GTK_SIGNAL_FUNC(GnextMatch), NULL); gtk_toolbar_append_item(GTK_TOOLBAR(toolbar), "<<", "Scroll leftward lots", NULL, NULL, GTK_SIGNAL_FUNC(GscrollLeftBig), NULL); gtk_toolbar_append_item(GTK_TOOLBAR(toolbar), ">>", "Scroll rightward lots", NULL, NULL, GTK_SIGNAL_FUNC(GscrollRightBig), NULL); gtk_toolbar_append_item(GTK_TOOLBAR(toolbar), "<", "Scroll leftward one base", NULL, NULL, GTK_SIGNAL_FUNC(GscrollLeft1), NULL); gtk_toolbar_append_item(GTK_TOOLBAR(toolbar), ">", "Scroll rightward one base", NULL, NULL, GTK_SIGNAL_FUNC(GscrollRight1), NULL); if (blastx ||tblastx || blastn) gtk_toolbar_append_item(GTK_TOOLBAR(toolbar), "Strand^v", "Toggle strand", NULL, NULL, GTK_SIGNAL_FUNC(GToggleStrand), NULL); gtk_toolbar_append_widget(GTK_TOOLBAR(toolbar), entry, NULL, NULL); gtk_toolbar_append_item(GTK_TOOLBAR(toolbar), "Help", "Don't Panic", NULL, NULL, GTK_SIGNAL_FUNC(GHelp), NULL); gtk_widget_show_all(handleBox); return handleBox; } static void BigPictToggle (void) { BigPictON = !BigPictON; blviewRedraw(); } static void BigPictToggleRev (void) { BigPictRev = !BigPictRev; blviewRedraw(); } static void zoomOut(void) { BigPictZoom *= 2; blviewRedraw(); } static void zoomIn(void) { BigPictZoom /= (float)2; if (BigPictZoom < 1) BigPictZoom = 1; blviewRedraw(); } static void zoomWhole(void) { BigPictZoom = (float)qlen/displen; blviewRedraw(); } /* If crosshair-coordinates are screwed up, change here! ********************************************************/ static int x_to_residue(float x) { int retval; if (blastx || tblastx) retval = dispstart + plusmin*(x - NAMESIZE - 22.3)*3; else retval = dispstart + plusmin*(x - NAMESIZE - 22); if (plusmin > 0) { if (retval < dispstart) retval = dispstart; if (retval > dispstart+displen-1) retval = dispstart+displen-1; return retval; } else { if (retval > dispstart-1) retval = dispstart-1; if (retval < dispstart-displen) retval = dispstart-displen; return retval +1; } } static void displayResidue(double x) { int qpos, spos; static char queryname[NAMESIZE+1]; /* Probably I should use by abbrev code here.....one thing at a time though... */ if (!*queryname) { if (!*qname_G) strcpy(queryname, "Query"); else { char *abbrev ; #ifdef ED_G_NEVER_INCLUDE_THIS_CODE strncpy(queryname, qname_G, NAMESIZE); #endif /* ED_G_NEVER_INCLUDE_THIS_CODE */ abbrev = abbrevTxt(qname_G, NAMESIZE) ; strncpy(queryname, abbrev, NAMESIZE) ; } queryname[NAMESIZE] = 0; } qpos = x_to_residue(x); if (!pickedMSP) sprintf(message, "%s: %d No subject picked", queryname, qpos + qoffset); else { if (blastx || tblastx) { spos = gapCoord(pickedMSP, qpos, 3); if (spos < pickedMSP->sstart) spos = pickedMSP->sstart; if (spos > pickedMSP->send) spos = pickedMSP->send; } else if (blastn) { spos = gapCoord(pickedMSP, qpos, 1); if (spos < pickedMSP->sstart) spos = pickedMSP->sstart; if (spos > pickedMSP->send) spos = pickedMSP->send; } else if (tblastn) { if (pickedMSP->sstart < pickedMSP->send) { spos = (qpos - pickedMSP->qstart)*3 + pickedMSP->sstart; if (spos < pickedMSP->sstart) spos = pickedMSP->sstart; if (spos > pickedMSP->send) spos = pickedMSP->send; } else { spos = pickedMSP->sstart - (qpos - pickedMSP->qstart)*3; if (spos > pickedMSP->sstart) spos = pickedMSP->sstart; if (spos < pickedMSP->send) spos = pickedMSP->send; } } else { spos = qpos - pickedMSP->qstart + pickedMSP->sstart; if (spos < pickedMSP->sstart) spos = pickedMSP->sstart; if (spos > pickedMSP->send) spos = pickedMSP->send; } sprintf(message, "%s: %d ", queryname, qpos + qoffset); if (HSPgaps) strcat(message, "Gapped HSP - no coords"); else strcat(message, messprintf("%s: %d", pickedMSP->sname, spos)); } gtk_entry_set_text(GTK_ENTRY(messageWidget), message); return ; } static void markDNA(double y) { Graph old = graphActive(); if (y < 0) return; graphActivate(frameGraphQ[0]); graphXorLine (NAMESIZE+22, 1.5 + y, NAMESIZE+22+displen/3, 1.5 + y); graphActivate(old); } static void MiddleDragBP (double x, double y) { graphXorBox (BPbox, oldx - BPboxwidth/2, 1.85); graphXorBox (BPbox, x - BPboxwidth/2, 1.85); oldx = x ; } static void MiddleDragQ (double x, double y) { int i, noframes = blastn ? 2 : 3; for(i=0; i