/* 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: May 17 11:22 2002 (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.158 2002/07/25 14:40:39 srk 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 extern void externalCommand (char *command); extern int pickMatch (char *cp, char *tp); char *blixemVersion = BLIXEM_VERSION_STRING ; #ifdef SUN /* extern void pclose(FILE*); */ /* fw 940906 now defined in mystdlib.h */ extern int atoi(char*), re_exec(char*); extern char *re_comp(char*)/*, toupper(char), tolower(char)*/; #endif #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; enum { UNSORTED, SORTBYSCORE, SORTBYID, SORTBYNAME, SORTBYPOS }; /* Global variables */ static BPMSP BPMSPlist, *bpmsp; static int fetchCount; 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); static void toggleColors (void); static void blviewPick (int box); static void blviewHelp(void); static Graph blviewCreate (void); static void blviewDestroy(void); 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 char *fetchSeqRaw(char *seqname) ; static BOOL getsseqsPfetch(MSP *msplist, char* pfetchIP, int port) ; static void getsseq(MSP *msp) ; static char *getFetchProg(char *fetch_mode) ; static char *getSeq(char *seqname, char *fetch_prog) ; 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); /* some low level socket functions that follow the main function */ static int socketConstruct(char *ipAddress, int port) ; 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 Graph blixemGraph=0; /* The blxview window */ GtkWidget *blixemWindow; 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; MSP *MSPlist, /* List of MSP's */ *msp; static MSP *pickedMSP; /* Last picked MSP */ static char message[1024], HighlightSeq[NAMESIZE+4] = "", searchSeq[NAMESIZE+4] = "", *cp, *padseq = 0, *auxseq = 0, *auxseq2 = 0, dotterqname[NAMESIZE+1], *dottersseq=0, stringentEntropytx[10], mediumEntropytx[10], nonglobularEntropytx[10], sortModeStr[32] = " ", 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, sortMode = UNSORTED, sortInvOn = 0, HSPgaps = 0; 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" /* The start of the code..... */ static void toggleVerbose(void) { MSP *msp; verbose = (verbose ? 0 : 1); if (verbose) for (msp = MSPlist; msp; msp = msp->next) { #ifdef ACEDB printf("%d %s ", msp->key, name(msp->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 : "")); } blviewRedraw(); } 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); } static void gotoBegin(void) { dispstart = (plusmin > 0 ? 0 : qlen); blviewRedraw(); } static void gotoEnd(void) { dispstart = (plusmin > 0 ? qlen : 0); blviewRedraw(); } static void keyboard (int key) { switch (key) { case '<': case ',': scrollLeft1(); break; case '>': case '.': scrollRight1(); break; case UP_KEY: blviewPick(lastbox - 1); break; case DOWN_KEY: blviewPick(lastbox + 1); 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(void) { 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)) { graphActivate(msp->graph); graphBoxDraw(msp->box, WHITE, BLACK); } 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) { 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)); } 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; 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)); } } else { strncpy(message, bpmsp->sname, 1023); if (bpmsp->desc) { strcat(message, " "); strncat(message, bpmsp->desc, 1023-strlen(message)); } } gtk_entry_set_text(GTK_ENTRY(messageWidget), message); /* Highlight picked box */ graphActivate(blixemGraph); highlightProteinboxes(); 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(); } #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) { FSpriority return ( (msp1->id < msp2->id) ? 1 : -1 ); } /* 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 ; } 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 ; } /* */ static void sortByName(void) { sortMode = SORTBYNAME; strcpy(sortModeStr, "Name"); sortMSPs(namesort); } static void sortByScore(void) { sortMode = SORTBYSCORE; strcpy(sortModeStr, "Score"); sortMSPs(scoresort); } static void sortByPos(void) { sortMode = SORTBYPOS; strcpy(sortModeStr, "Position"); sortMSPs(possort); } static void sortById(void) { sortMode = SORTBYID; strcpy(sortModeStr, "Identity"); sortMSPs(idsort); } 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; } } /* 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) { Graph result = GRAPH_NULL ; char *opt; BOOL use_pfetch = FALSE ; oneGraph = 0; if (blixemWindow) gtk_widget_destroy(blixemWindow); q = seq; qlen = actend = strlen(q); qname = seqname; dispstart = start; actstart=1; qoffset = offset; MSPlist = msplist; BPMSPlist.next = 0; *HighlightSeq = 0; blastx = blastp = blastn = tblastn = tblastx = 0; 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': for (msp = MSPlist; msp; msp = msp->next) if (!msp->id) calcID(msp); sortById(); break; case 'M': start_nextMatch = 1; break; case 'n': sortByName(); break; case 'p': sortByPos(); break; case 'R': BigPictRev = 1; break; case 'r': BigPictRev = 0; break; case 's': 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?"); } /* RD 011005 - 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. */ if (use_pfetch) { enum {PFETCH_PORT = 22100} ; /* default port to connect on */ char *net_id = NULL ; int port = PFETCH_PORT ; BOOL status = TRUE ; /* Unused currently. */ 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 ; } /* We ignore the status because the MSPlist may already contain some DNA * before we ask for sequences from pfetch. */ if (net_id) status = getsseqsPfetch(MSPlist, net_id, port) ; } /* Note that we create a blxview even if MSPlist is empty. */ result = blviewCreate() ; 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 (void) { 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} }; if (!blixemWindow) { float w, h; GtkWidget *vbox; int i, frames = blastx ? 3 : 2; 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); gtk_window_set_title(GTK_WINDOW(blixemWindow), messprintf("Blixem %s", qname)); 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 = graphNakedCreate(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; i NAMESPACE+4) qname[NAMESPACE+4] = 0; allocAuxseqs(INITDBSEQLEN); if (entropyOn) calcEntropyArrays(FALSE); #ifdef ACEDB /* Acedb passes revcomp exons incorrectly for blastn * / if (blastn) { messout ( "\nWarning: exons on the opposite strand may be invisible due " "to a strange bug in blastn mode in acedb which inverts them, " "although the identical routine works correctly in blastx mode.\n" "Also, when Blixem is called from REVCOMP blastn mode, the HSPs " "are not revcomped.\n"); }*/ #endif if (dotter_first && MSPlist && MSPlist->sname && (MSPlist->type == HSP || MSPlist->type == GSP)) { strcpy(HighlightSeq, MSPlist->sname); callDotter(); } if (start_nextMatch) nextMatch(); else blviewRedraw(); return FALSE /* g */ ; } static MENUOPT gotoMenu[] = { { gotoBegin, " <- Goto Beginning " }, { gotoEnd, " Goto End -> " }, { 0, 0 } }; /* BLVIEWDESTROY frees all the allocated memory N.B. This memory was allocated in the calling program (acedb) Could free auxseq, auxseq2 and padseq too, but they'd have to be remalloc'ed next time then. */ static void blviewDestroy(void) { MSP *msp, *fmsp; BPMSP *tmsp; 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 = 0; } 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) || !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 ********************/ 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); graphText (messprintf ("%-8s%s", qname, 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(.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); strncpy(text, msp->sname, NAMESIZE); text[NAMESIZE] = 0; graphText(text, 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(RED); graphLine(alignstart+i, queryy+dbdisp, alignstart+i, 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(); 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 */ static void calcID(MSP *msp) { static int id, i, len; char *qseq; if (msp->sseq && msp->sseq != padseq) { 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; } 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 { 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++; } messfree(qseq); msp->id = (int)((float)100*id/len + .5); } else msp->id = 0 ; } 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) { #if !(defined(MACINTOSH) || defined(WIN32)) 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); } } #else messout ( "WIN32/MAC Warning: efetch external command not implemented for blxview::getsseq()\n" "Cannot retrieve sequence \"%s\" HSP at %d-%d - using pads instead\n", msp->sname, msp->qstart+qoffset, msp->qend+qoffset); assignPadseq(msp); #endif /* !(defined(MACINTOSH) || defined(WIN32))*/ return ; } /* Get a sequence entry using either efetch or pfetch. */ static char *fetchSeqRaw(char *seqname) { #if !(defined(MACINTOSH) || defined(WIN32)) 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 ; #else messout ( "WIN32/MAC Warning: efetch external command not implemented for blxview::fetchSeqRaw()\n") ; return NULL ; #endif /* !(defined(MACINTOSH) || defined(WIN32)) */ } /* 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 ; if (!strcmp(fetch_prog, "pfetch")) { /* --client gives logging information to pfetch server, * -F makes sure we get a full sequence entry returned. */ 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++; } 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) ; 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(); GtkWidget *toolbar = gtk_toolbar_new(GTK_ORIENTATION_HORIZONTAL, GTK_TOOLBAR_TEXT); 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_COMBO(combo)->entry, FALSE); gtk_widget_set_usize(GTK_COMBO(combo)->entry, 50, -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), " "); 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]; if (!*queryname) { if (!*qname) strcpy(queryname, "Query"); else strncpy(queryname, qname, NAMESIZE); queryname[NAMESIZE] = 0; } qpos = x_to_residue(x); if (pickedMSP) { 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)); } else sprintf(message, "%s: %d No subject picked", queryname, qpos + qoffset); gtk_entry_set_text(GTK_ENTRY(messageWidget), message); } 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