/* file: fmapfeatures.c * Author: Richard Durbin (rd@mrc-lmb.cam.ac.uk) * Copyright (C) J Thierry-Mieg and R Durbin, 1992 * ------------------------------------------------------------------- * 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 * ------------------------------------------------------------------- * This file is part of the ACEDB genome database package, written by * Richard Durbin (MRC LMB, UK) rd@mrc-lmb.cam.ac.uk, and * Jean Thierry-Mieg (CRBM du CNRS, France) mieg@kaa.cnrs-mop.fr * * Description: feature display for fmap package * Exported functions: * HISTORY: * Last edited: Mar 26 14:27 2004 (edgrif) * * Oct 17 09:42 2001 (edgrif): Add support for calling blixem as a separate * process. * * Apr 20 11:54 2000 (edgrif): Moved column pulldown drawing to mapcontrol.c, * added 'access' functions so that mapcontrol can find out what * sort of column it is dealing with for menu building etc. * * Sep 16 10:47 1998 (edgrif): Insert macro to define bitField for * bitset.h ops. * * Jul 16 10:06 1998 (edgrif): Introduce private header fmap_.h * Created: Sun Jul 26 13:02:46 1992 (rd) * CVS info: $Id: fmapfeatures.c,v 1.163 2004/03/26 14:28:31 edgrif Exp $ *------------------------------------------------------------------- */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef ED_G_NEVER_INCLUDE_THIS_CODE /* I'd like to just include this but it include colcontrol.h which clashes * with an include of map.h somewhere above. */ #include #endif /* ED_G_NEVER_INCLUDE_THIS_CODE */ #include #include #include #define ACEDB /* for this include of blxview */ #include #undef ACEDB #include #include BITSET_MAKE_BITFIELD /* define bitField for bitset.h ops */ /* defined here once as constants, because we refer to these labels * in various places to get at the menuitem by name */ #define LABEL_OVERLAP " Overlap" #define LABEL_BUMPABLE " Bump" #define LABEL_CLUSTER " Cluster" #define LABEL_WIDTH " Width" #define LABEL_OFFSET " Offset" #define LABEL_HIST " Histogram" /************************************************************/ typedef enum { DEFAULT=0, WIDTH, OFFSET, HIST } BoxColModeType; typedef struct { FeatureMap look ; METHOD *meth; /* a method-struct from look->mcache */ MethodOverlapModeType overlap_mode ; /* See wh/method.h */ /* following not under user control */ float offset ; BOOL isDown ; BOOL isFrame ; /* TRUE if we're showing in 3 frames */ BoxColModeType mode ; float fmax ; BUMP bump ; Associator cluster ; /* only non-zero if METHOD_CLUSTER */ int clusterCount ; float histBase ; /* normalised meth->histBase, between 0 and 1 */ int width ; MENU menu; } BoxCol ; /* logically you might think that there should be an "insertion" type that is not a transposon * but the code does not seem to do this....so ALLELE_DRAW_INSERTION is a bit redundant at the * moment..... */ typedef enum {ALLELE_DRAW_DELETION, ALLELE_DRAW_REPLACMENT, ALLELE_DRAW_INSERTION, ALLELE_DRAW_TRANSPOSON} AlleleDrawType ; static void bcMenuSetOverlap (MENUITEM menu_item); static void bcMenuSetBump (MENUITEM menu_item); static void bcMenuSetCluster (MENUITEM menu_item); static void bcMenuSetWidth (MENUITEM menu_item); static void bcMenuSetOffset (MENUITEM menu_item); static void bcMenuSetHist (MENUITEM menu_item); static void bcMenuDeleteMapColumn (MENUITEM menu_item); static BoxCol *bcFromName (FeatureMap look, char *name, MENU *menu) ; static void bcCheck (BoxCol *bc); /* checks before using a column */ static BOOL bcTestMag (BoxCol *bc, float mag) ; static int bcDrawBox (BoxCol *bc, SEG *seg, float score, Array gaps) ; static void addVisibleInfo (FeatureMap look, int i) ; static void translationTitle (ACEOUT fo, KEY seq) ; static void pfetchWindow (KEY key); static void translateCDS(int box) ; static void translateAll(int box) ; static void translateGene(int box, BOOL CDS_only) ; static void changeGeneMenu(FeatureMap look, SEG *seg, BOOL cds_only) ; static void showCDSInPepDisp(int box) ; static void showAllInPepDisp(int box) ; static void showInPepDisp (int box, BOOL CDS_only) ; static void exportCDSTranslation (int box); static void exportCompleteTranslation (int box); static void exportTranslation(int box, BOOL CDS_only); static void fMapShowcDNA(int box) ; static void fMapShowCDS(int box) ; static void showDNA(int box, BOOL CDS_only) ; static void fMapExportcDNA(int box) ; static void fMapExportCDS(int box) ; static void exportDNA(int box, BOOL CDS_only) ; static void fMapColorIntronsExons (int box); #ifndef MACINTOSH static void fMaptRNAfold (int box) ; #endif /* !MACINTOSH */ /* Pep homology menu functions */ static void fMapShowPepAlign (int box) ; static void fMapShowPepAlignThis (int box) ; static void fMapExpandAlign (int box) ; static void fMapFetch (int box) ; static void fMapEfetch (int box) ; static void fMapPfetch (int box) ; /* DNA homology menu functions */ static void fMapShowDNAAlign (int box) ; static void fMapShowDNAAlignThis (int box) ; static void fMapExpandAlign (int box) ; static void fMapEfetch (int box) ; static void fMapPfetch (int box) ; /* Adjusts coords of features that get clipped by mapping or display. */ static BOOL clipCoords(FeatureMap look, SEG *seg, float *y1_out, float *y2_out, BOOL *off_top_out, BOOL *off_bottom_out) ; /* Gradually more generalised drawing routines are being added..... */ static BOOL drawAlleleStyle(FeatureMap look, float *offset, SEG *seg, AlleleDrawType allele_draw, int *box_out) ; static void drawInterruptedRectangle(FeatureMap look, Array gaps, float x1, float y1, float x2, float y2) ; /* Routines for controlling how blixem is called. */ static BOOL blixemGetPfetchParams(STORE_HANDLE handle, PfetchParams **out) ; static BOOL blixemIsExternal(void) ; static void blixemCallExternal(char *seq, char *seqname, int dispStart, int offset, MSP *msp, char *opts, PfetchParams *pfetch_params) ; /* Generic functions for selecting and unselecting SEGs */ static void selectSeg (int box) ; static void unselectSeg (int box) ; /******************************************************/ /*************** gene menu ****************************/ /* If you alter this menu be sure that the indexs for CDS translation and * complete translation are changed if they need to be. */ #define CDS_TRANS_ON "Show CDS translation" #define CDS_TRANS_OFF "Hide CDS translation" #define COMPLETE_TRANS_ON "Show Complete translation" #define COMPLETE_TRANS_OFF "Hide Complete translation" #define CDS_TRANS_INDEX 0 #define COMPLETE_TRANS_INDEX 4 static MENUOPT geneMenu[] = { { (GraphFunc)translateCDS, CDS_TRANS_ON }, { (GraphFunc)showCDSInPepDisp, "Display CDS translation in protein window" }, { (GraphFunc)exportCDSTranslation, "Export CDS translation" }, { menuSpacer, "" }, { (GraphFunc)translateAll, COMPLETE_TRANS_ON }, { (GraphFunc)showAllInPepDisp, "Display complete translation in protein window" }, { (GraphFunc)exportCompleteTranslation,"Export complete translation" }, { menuSpacer, "" }, { (GraphFunc)fMapCurateCDS, "Curate CDS" }, { menuSpacer, "" }, { (GraphFunc)fMapShowcDNA, "Display cDNA in new window" }, { (GraphFunc)fMapExportcDNA, "Export cDNA" }, { menuSpacer, "" }, { (GraphFunc)fMapShowCDS, "Display CDS in new window" }, { (GraphFunc)fMapExportCDS, "Export CDS" }, { menuSpacer, "" }, { (GraphFunc)fMapColorIntronsExons, "Highlight Exons" }, #ifndef MACINTOSH { (GraphFunc)fMaptRNAfold, "Fold tRNA" }, #endif /* !MACINTOSH */ { 0, 0 } } ; static MENUOPT pepHomolMenu[] = { { (GraphFunc)fMapShowPepAlign, "Show multiple protein alignment in Blixem"}, { (GraphFunc)fMapShowPepAlignThis, "Show multiple protein alignment of just this kind of homologies"}, { (GraphFunc)fMapExpandAlign, "Develop a table of these homologies" }, { (GraphFunc)fMapFetch, "(slow) Import this protein via the web" }, { (GraphFunc)fMapEfetch, "EFetch this sequence" }, { (GraphFunc)fMapPfetch, "PFetch this sequence" }, { (GraphFunc)selectSeg, "Select this segment" }, { (GraphFunc)unselectSeg, "Unselect this segment" }, { 0, 0 } } ; static MENUOPT dnaHomolMenu[] = { { (GraphFunc)fMapShowDNAAlign, "Show multiple dna alignment"}, { (GraphFunc)fMapShowDNAAlignThis, "Show multiple dna alignment of just this kind of homologies"}, { (GraphFunc)fMapExpandAlign, "Develop a table of these homologies" }, { (GraphFunc)fMapEfetch, "EFetch this sequence" }, { (GraphFunc)fMapPfetch, "PFetch this sequence" }, { (GraphFunc)selectSeg, "Select this segment" }, { (GraphFunc)unselectSeg, "Unselect this segment" }, { 0, 0 } } ; /*************************************/ /* column "Locator" */ void fMapShowMiniSeq (LOOK genericLook, float *offset, MENU *unused) /* This is of type MapColDrawFunc */ { FeatureMap look = (FeatureMap)genericLook; int i ; float y, newoff, x0 ; SEG *seg ; newoff = *offset + 5 ; mapShowLocator(genericLook, &newoff, NULL) ; x0 = (look->flag & FLAG_REVERSE) ? look->map->max : 0 ; /* Position main Markers = loci just now */ graphTextHeight (0.75) ; for (i = 1 ; i < arrayMax(look->segs) ; ++i) { seg = arrp(look->segs,i,SEG) ; if (class(seg->key) == _VLocus) { y = MAP2WHOLE(look->map,(seg->x1 + seg->x2 - 2*x0)/2.0) ; graphText (name(seg->key), *offset+0.5, y-0.4) ; } } graphTextHeight (0) ; *offset = newoff ; return; } /* fMapShowMiniSeq */ /************************************/ void fMapShowScale (LOOK genericLook, float *offset, MENU *unused) /* This is of type MapColDrawFunc */ { FeatureMap look = (FeatureMap)genericLook; float unit, subunit ; int iUnit, iSubunit, type, unitType ; int x, xf, xr, width = 0 ; float y ; char *cp, unitName[] = { 0, 'k', 'M', 'G', 'T', 'P' }, buf[2] ; BOOL isReverse ; xf = look->origin - 1 ; xr = look->length - look->origin ; isReverse = ((look->flag & FLAG_REVERSE) != 0) ; unit = subunit = 1.0 ; mapFindScaleUnit (look->map, &unit, &subunit) ; iUnit = unit + 0.5 ; iSubunit = subunit + 0.5 ; if (isReverse) x = xr - iUnit * ((xr - look->min)/iUnit) ; else x = xf + iUnit * ((look->min - xf)/iUnit) ; if (x < look->min) x += unit ; for (type = 1, unitType = 0 ; unit > 0 && 1000 * type < unit && unitType < 5; unitType++, type *= 1000) ; for ( ; x < look->max ; x += unit) { y = MAP2GRAPH(look->map, x) ; graphLine (*offset, y, *offset, y) ; buf[0] = unitName[unitType] ; buf[1] = 0 ; cp = messprintf ("%d%s", COORD(look,x)/type, buf) ; if (width < strlen (cp)) width = strlen (cp) ; graphText (cp, *offset+1.5, y-0.5) ; } if (isReverse) x = xr - iSubunit * ((xr - look->min)/iSubunit) ; else x = xf + iSubunit * ((look->min - xf)/iSubunit) ; if (x < look->min) x += subunit ; for ( ; x < look->max ; x += subunit) { y = MAP2GRAPH(look->map, x) ; graphLine (*offset+0.5, y, *offset+1, y) ; } graphLine (*offset+1, topMargin+2, *offset+1, mapGraphHeight-0.5) ; *offset += width + 4 ; return; } /* fMapShowScale */ /**********************************************************/ /**********************************************************/ /******************** geneMenu functions ******************/ /* Crude, but what else to do when the callback interface doesn't provide */ /* for passing of application data... */ static void translateCDS(int box) { BOOL cds_only = TRUE ; translateGene(box, cds_only) ; return ; } static void translateAll(int box) { BOOL cds_only = FALSE ; translateGene(box, cds_only) ; return ; } static void translateGene(int box, BOOL cds_only) { BOOL isNewGene = FALSE, new_translation, no_dna = FALSE ; SEG *seg ; FeatureMap look = currentFeatureMap("translateGene") ; MapColSet column_set ; if (box >= arrayMax(look->boxIndex) || !(seg = BOXSEG(box))) { messerror ("problem picking boxes for translation"); return ; } /* Has user asked for a change of which part of dna is translated ? */ /* i.e. CDS -> complete or complete -> CDS */ if (arrp(look->seqInfo, seg->data.i, SEQINFO)->cds_info.cds_only ^ cds_only) new_translation = TRUE ; else new_translation = FALSE ; arrp(look->seqInfo, seg->data.i, SEQINFO)->cds_info.cds_only = cds_only ; if (look->translateGene) /* there was a previous selection */ { if (look->translateGene != seg->parent) { /* the user has selected a different gene for translation */ isNewGene = TRUE ; /* May be we should always recompute to pick up errors... */ look->pleaseRecompute = TRUE ; } } else look->pleaseRecompute = TRUE ; /* select the gene for translation, from the selected SEG */ look->translateGene = seg->parent ; /* Before fiddling with column settings we need to check whether we can */ /* translate the dna, we do this by trying to get the dna. */ /* If this is too time consuming we could replace fMapGetDNA with a new */ /* routine that just checks whether its possible to get the DNA. */ if (new_translation) { Array cds, index ; if (!(fMapGetDNA(look, look->translateGene, &cds, &index, cds_only))) { messout("Select a down gene to translate with the pulldown menu on the genes") ; no_dna = TRUE ; look->pleaseRecompute = TRUE ; /* Make sure we redraw. */ } else { no_dna = FALSE ; arrayDestroy (cds) ; arrayDestroy (index) ; } } /* We want the column drawn if a new gene is selected OR if section of */ /* gene to be drawn has changed. */ if (no_dna) column_set = MAPCOL_OFF ; else if (isNewGene || new_translation) column_set = MAPCOL_ON ; else column_set = MAPCOL_TOGGLE ; if (seg->type == EXON_UP) { mapColSetByName(look->map, "Down Gene Translation", MAPCOL_OFF) ; mapColSetByName(look->map, "Up Gene Translation", column_set); } else { mapColSetByName(look->map, "Down Gene Translation", column_set); mapColSetByName(look->map, "Up Gene Translation", MAPCOL_OFF) ; } fMapDraw (look, 0) ; return; } /* translateGene */ /**************************************/ /* This is a bit clumsy but there is no built in mechanism in the graphmenu */ /* stuff for passing through "application data" so what else to do...??? */ /* */ static void showCDSInPepDisp(int box) { showInPepDisp(box, TRUE) ; /* Translate the CDS only. */ return ; } static void showAllInPepDisp(int box) { showInPepDisp(box, FALSE) ; /* Translate all the DNA. */ return ; } static void showInPepDisp(int box, BOOL CDS_only) { SEG *seg ; Array pep ; FeatureMap look = currentFeatureMap("showInPepDisp") ; if (box >= arrayMax(look->boxIndex) || !(seg = BOXSEG(box))) { messerror ("Problem picking box to show in PEP disp"); return; } if ((pep = peptideTranslate(seg->parent, CDS_only))) { PepDisplayData pep_create ; arrayDestroy(pep) ; pep_create.CDS_only = CDS_only ; displayApp(seg->parent, look->seqKey, "PEPMAP", (void *)&pep_create) ; } else messerror ("Can't generate protein sequence") ; return; } /* showInPepDisp */ /**************************************/ /* These functions show the spliced DNA of a set of exons in a separate */ /* fmap window. If our menu system catered for application data to be passed */ /* through we wouldn't need these cover functions. */ /* */ static void fMapShowcDNA (int box) { showDNA(box, FALSE) ; return ; } static void fMapShowCDS(int box) { showDNA(box, TRUE) ; return ; } static void showDNA(int box, BOOL cds_only) { KEY key ; Array cds = 0 ; SEG *seg ; Stack s ; FeatureMap look = currentFeatureMap("fMapShowcDNA"); ACEOUT cdna_out; OBJ obj = NULL ; char *temp_suffix ; if (box >= arrayMax(look->boxIndex) || !(seg = BOXSEG(box))) { messerror ("problem picking boxes in fMapShowcDNA"); return; } /* Can fail because caller asked for CDS DNA but object is not a CDS. */ if (!fMapGetDNA(look, seg->parent, &cds, 0, cds_only)) { messerror("Either no DNA present or you have asked for CDS DNA" " and the object is not a CDS.") ; return ; } /* Create a temporary sequence object containing just the cDNA and display * it in an fmap window. This object will get deleted when the user quits * the fmap window. We pass on some of the tags from the object that was * used to create this seg because they are needed for examining the cDNA * in the new temporary object. * n.b. must have different suffixes to produce different temporary objects */ if (cds_only) temp_suffix = "CDS.cDNA" ; else temp_suffix = "cDNA" ; lexaddkey(messprintf("%s.%s", name(seg->parent), temp_suffix), &key, _VSequence) ; s = stackCreate (500) ; cdna_out = aceOutCreateToStack (s, 0); aceOutPrint(cdna_out, "Sequence %s\ncDNA\n", name(key)) ; obj = bsCreate(seg->parent) ; if (bsFindTag(obj, _CDS)) { int cds_min = 0, cds_max = 0 ; aceOutPrint(cdna_out, "CDS") ; /* If we are only exporting the CDS section of the DNA we do not need */ /* the start/end. */ if (!cds_only) { if (bsGetData(obj, _bsRight, _Int, &cds_min)) { aceOutPrint(cdna_out, " %d", cds_min) ; if (bsGetData(obj, _bsRight, _Int, &cds_max)) aceOutPrint(cdna_out, " %d", cds_max) ; } } aceOutPrint(cdna_out, "\n") ; } else { /* Dreadful hack, fmapconvert() needs to find a CDS tag in order to do */ /* two things: 1) set the drawing method correctly, 2) create a dummy */ /* source exon seg for the method to draw. So even though we know */ /* there is not a CDS I output a cds tag so that fmapconvert() will do */ /* the drawing. A better way would be to create a dummy source exon */ /* here from the original objects Source_Exons and alter fmapconvert() */ /* so that it would draw them, maybe there is code to do this but I */ /* don't know the correct tag to do this....the #define code below */ /* will do this when I think of the way to fix up fmapconvert(). */ aceOutPrint(cdna_out, "CDS\n") ; #ifdef ED_G_NEVER_INCLUDE_THIS_CODE /* Dreadful hack, fmapconvert needs to find a CDS tag in order for it to */ /* make a dummy source exon to display in the fmap, if there is no CDS tag */ /* the source exon doesn't get created and nothing is displayed. To */ /* avoid this, we fix up our own source exon to cover the whole of */ /* this object. */ /* We should always be able to find the source exons because the user */ /* will have clicked on them to get this code executed. */ if (bsFindTag(obj, _Source_Exons)) { Array units = 0 ; units = arrayCreate(256, BSunit) ; if (bsFlatten(obj, 2, units)) { int i ; int start, end ; dnaExonsSort (units) ; start = arr(units, 0, BSunit).i ; for (i = 0, end = 0 ; i < arrayMax(units) ; i += 2) { end += (arr(units, i+1, BSunit).i - arr(units, i, BSunit).i + 1) ; } aceOutPrint(cdna_out, "Source_Exons %d %d\n", start, end) ; } else { messerror("Potential problem with database or acedb code, found source exons" " but cannot access them in object %s, fMapShowcDNA() failed.", name(seg->parent)) ; arrayDestroy(units) ; return ; } arrayDestroy(units) ; } else { messerror("Potential problem with database or acedb code," " cannot find source exons in object %s, fMapShowcDNA() failed.", name(seg->parent)) ; return ; } #endif /* ED_G_NEVER_INCLUDE_THIS_CODE */ } if (bsFindTag(obj, _Start_not_found)) { int start = 0 ; aceOutPrint(cdna_out, "Start_not_found") ; if (bsGetData(obj, _bsRight, _Int, &start)) aceOutPrint(cdna_out, " %d", start) ; aceOutPrint(cdna_out, "\n") ; } if (bsFindTag(obj, _End_not_found)) { aceOutPrint(cdna_out, "End_not_found\n") ; } bsDestroy(obj) ; aceOutPrint(cdna_out, "\nDNA %s\n", name(key)) ; dnaDecodeArray (cds) ; aceOutPrint (cdna_out, "%s", arrp(cds,0,char)) ; aceOutPrint (cdna_out, "\n\n") ; aceOutDestroy (cdna_out); arrayDestroy (cds) ; if (parseBufferInternal(stackText(s,0), 0, FALSE)) { FmapDisplayData create_data ; displayPreserve () ; create_data.destroy_obj = TRUE ; create_data.features = NULL ; create_data.include_methods = FALSE; create_data.include_sources = FALSE; create_data.methods_dict = NULL ; create_data.sources_dict = NULL ; displayApp(key, 0, 0, (void *)&create_data); } else messerror ("Parsing of %s to create cDNA object for fMapShowcDNA failed", name(key)) ; stackDestroy (s) ; return; } /* fMapShowcDNA */ /**************************************/ static void fMapColorIntronsExons (int box) { int i, j1, j2, j3, colour, length ; Array cds, index, colors ; SEG *seg ; FeatureMap look = currentFeatureMap("fMapColorIntronsExons"); Array tt = NULL ; if (box >= arrayMax(look->boxIndex) || !(seg = BOXSEG(box))) { messerror ("problem picking boxes for colouring"); return; } if (!fMapGetCDS(look, seg->parent, &cds, &index)) { messerror ("ColorIntronsExons only works on coding genes") ; return ; } if (!(tt = pepGetTranslationTable(seg->parent, KEY_UNDEFINED))) return ; length = look->length ; if (arrayMax(cds) % 3) messout ("Coding length is %d mod 3", arrayMax(cds) % 3) ; fMapClearDNA (look) ; colors = look->colors ; j1 = arr(index,0,int) ; j2 = arr(index,arrayMax(index)-1,int) ; if (j2 < j1) { j3 = j1 ; j1 = j2 ; j2 = j3 ; } if (j1 < 0) j1 = 0 ; if (j2 >= length) j2 = length-1 ; /* do not color the introns they print same as exons if CYAN and LIGHTGREEN for (i = j1 ; i <= j2 ; ++i) arr(colors,i,char) |= TINT_LIGHTGREEN ; */ for (i = 0 ; i < arrayMax(index)-2 ; i += 3) { j1 = arr(index,i,int) ; j2 = arr(index,i+1,int) ; j3 = arr(index,i+2,int) ; if (j1 < 0 || j3 < 0 || j1 >= length || j3 >= length) continue ; if (j3 == j1+2 || j1 == j3+2) { if (e_codon(arrp(cds,i,char), tt) == '*') colour = TINT_RED ; else colour = TINT_YELLOW ; /* was TINT_CYAN ; */ } else colour = TINT_MAGENTA ; arr(colors,j1,char) |= colour ; arr(colors,j2,char) |= colour ; arr(colors,j3,char) |= colour ; } arrayDestroy (cds) ; arrayDestroy (index) ; mapColSetByName(look->map, "DNA Sequence", MAPCOL_ON) ; look->activeBox = 0 ; fMapDraw (look, 0) ; return; } /* fMapColorIntronsExons */ /**************************************/ /* This is a bit clumsy but there is no built in mechanism in the graphmenu */ /* stuff for passing through "application data" so what else to do...??? */ /* */ static void exportCDSTranslation(int box) { exportTranslation(box, TRUE) ; /* Translate the CDS only. */ return ; } static void exportCompleteTranslation(int box) { exportTranslation(box, FALSE) ; /* Translate all the DNA. */ return ; } static void exportTranslation(int box, BOOL cds_only) { Array dna = NULL ; SEG *seg ; FeatureMap look = currentFeatureMap("exportTranslation") ; BOOL result_unused ; if (box >= arrayMax(look->boxIndex) || !(seg = BOXSEG(box))) { messerror ("Problem picking boxes to export translation"); return; } if (!fMapGetDNA(look, seg->parent, &dna, 0, cds_only)) { messerror ("ExportTranslation only works on coding genes") ; return ; } result_unused = pepTranslateAndExport(seg->parent, dna) ; arrayDestroy(dna) ; return; } /**************************************/ /* These functions export the spliced DNA of a set of exons to a file. */ /* If our menu system catered for application data to be passed through we */ /* wouldn't need these cover functions. */ /* */ static void fMapExportcDNA (int box) { exportDNA(box, FALSE) ; return ; } static void fMapExportCDS(int box) { exportDNA(box, TRUE) ; return ; } static void exportDNA(int box, BOOL cds_only) { static char fname[FIL_BUFFER_SIZE]="", dname[DIR_BUFFER_SIZE]="" ; ACEOUT cdna_out; Array cds = 0 ; int i ; SEG *seg ; FeatureMap look = currentFeatureMap ("fMapExportcDNA") ; char *feature = (cds_only ? "CDS" : "cDNA") ; char *file_ext = (cds_only ? "cds" : "cdna") ; char *chooser_txt = NULL ; if (box >= arrayMax(look->boxIndex) || !(seg = BOXSEG(box))) { messerror ("problem picking boxes to export %s", feature); return; } if (!fMapGetDNA(look, seg->parent, &cds, 0, cds_only)) { messerror ("Export %s only works on coding genes", feature) ; return ; } chooser_txt = hprintf(0, "File to store %s in", feature) ; cdna_out = aceOutCreateToChooser (chooser_txt, dname, fname, file_ext, "a", 0); messfree(chooser_txt) ; if (!cdna_out) { arrayDestroy (cds) ; return ; } translationTitle(cdna_out, seg->parent) ; for (i = 0 ; i < arrayMax(cds) ; ++i) { aceOutPrint (cdna_out, "%c", dnaDecodeChar[(int)arr(cds,i,char)]); if (((i+1) % 50) == 0) aceOutPrint (cdna_out, "\n"); } if (i % 50) aceOutPrint (cdna_out, "\n"); aceOutDestroy (cdna_out); arrayDestroy (cds) ; return; } /* fMapExportcDNA */ /**********************************************************/ /**************** select functions ************************/ static void selectFeature (FeatureMap look, BOOL isSelect, SegType type, int x1, int x2) { if (isSelect) { assInsert (look->chosen, HASH (type, x2), assVoid(x1)) ; assRemove (look->antiChosen, HASH (type, x2)) ; } else { assRemove (look->chosen, HASH (type, x2)) ; assRemove (look->antiChosen, HASH (type, x2)) ; } return ; } static void selectChangeSeg (int box, BOOL isSelect) { SEG *seg, *seg2 ; int i ; FeatureMap look = currentFeatureMap("intronConfirm") ; if (box >= arrayMax(look->boxIndex) || !(seg = BOXSEG(box))) { messerror ("Problem picking box in selectSeg") ; return ; } switch (seg->type) { case INTRON: selectFeature (look, SPLICE5, isSelect, seg->x1-1, seg->x1) ; selectFeature (look, SPLICE3, isSelect, seg->x2, seg->x2+1) ; break ; case CDS: selectFeature (look, ATG, isSelect, seg->x1, seg->x1+2) ; selectFeature (look, ORF, isSelect, seg->x2-5, seg->x2-3) ; break ; case EXON: /* find CDS with same parent */ for (i = 0 ; i < arrayMax(look->segs) ; ++i) { seg2 = arrp(look->segs, i, SEG) ; if (seg2->type == CDS && seg2->parent == seg->parent) break ; } if (i == arrayMax (look->segs)) /* do nothing if no CDS */ break ; if (seg->x1 > seg2->x1) selectFeature (look, SPLICE3, isSelect, seg->x1-1, seg->x1) ; else if (seg2->x1 < seg->x2) selectFeature (look, ATG, isSelect, seg2->x1, seg2->x1+2) ; if (seg->x2 < seg2->x2) selectFeature (look, SPLICE5, isSelect, seg->x2, seg->x2+1) ; else if (seg2->x2 > seg->x1) selectFeature(look, ORF, isSelect, seg2->x2-5, seg2->x2-3) ; break ; case HOMOL: /* make splices at exact internal gaps > 25 */ { HOMOLINFO *hinf = arrp(look->homolInfo, seg->data.i, HOMOLINFO) ; for (i = 0 ; i < arrayMax(look->segs) ; ++i) { seg2 = arrp (look->segs, i, SEG) ; if (seg2->key == seg->key) { if (seg2->x2 + 25 < seg->x1 && hinf->x1 == 1 + arrp(look->homolInfo, seg2->data.i, HOMOLINFO)->x2) selectFeature (look, SPLICE3, isSelect, seg->x1-1, seg->x1) ; if (seg->x2 + 25 < seg2->x1 && hinf->x2 + 1 == arrp(look->homolInfo, seg2->data.i, HOMOLINFO)->x1) selectFeature (look, SPLICE5, isSelect, seg->x2, seg->x2+1) ; } } break ; } default: break ; } return ; } static void selectSeg(int box) { selectChangeSeg (box, TRUE) ; return ; } static void unselectSeg (int box) { selectChangeSeg (box, FALSE) ; return ; } /***************** intronMenu functions *******************/ /* This routine used only to create "Confirmed Introns" on the forward strand for introns that * already existed but you can now confirm introns on either strand. */ static void intronConfirm (int box, int flag) { SEG *seg ; OBJ obj ; KEY key ; int x, y ; SEQINFO *oldSinf, *newSinf ; FeatureMap look = currentFeatureMap("intronConfirm") ; if (box >= arrayMax(look->boxIndex) || !(seg = BOXSEG(box))) { messerror ("Problem picking box in intronConfirm") ; return ; } /* The coordinates are tricky here, we use seg coords for the fMap call which are 0-based, _but_ * the coords in the database are 1-based so we must add one AND we must note the strand. */ key = KEY_UNDEFINED ; if (SEG_IS_DOWN(seg)) { x = seg->x1 ; y = seg->x2 ; } else { y = seg->x1 ; x = seg->x2 ; } if (!fMapFindSpanSequenceWriteable(look, &key, &x, &y)) { messerror("Can't find any parent object to store confirmation data in to.") ; return ; } x++ ; y++ ; /* convert to 1-based coords. */ if (!(obj = bsUpdate(key))) { messerror("Can't open object %s to store confirmation data in to.", nameWithClass(key)) ; return ; } bsAddData (obj, str2tag("Confirmed_intron"), _Int, &x) ; bsAddData (obj, _bsRight, _Int, &y) ; bsPushObj (obj) ; switch (flag) { case SEQ_CONFIRM_EST: bsAddTag (obj, str2tag("EST")) ; break ; case SEQ_CONFIRM_HOMOL: bsAddTag (obj, str2tag("Homology")) ; break ; case SEQ_CONFIRM_CDNA: bsAddTag (obj, str2tag("cDNA")) ; break ; case SEQ_CONFIRM_UTR: bsAddTag (obj, str2tag("UTR")) ; break ; case SEQ_CONFIRM_FALSE: bsAddTag (obj, str2tag("False")) ; break ; case SEQ_CONFIRM_INCONSIST: bsAddTag (obj, str2tag("Inconsistent")) ; break ; case 0: bsPrune (obj) ; break ; default: messerror ("Unrecognised flag in intronConfirm") ; break ; } bsSave (obj) ; newSinf = arrayp(look->seqInfo, arrayMax(look->seqInfo), SEQINFO) ; oldSinf = arrp(look->seqInfo, seg->data.i, SEQINFO) ; /* must follow in case seqInfo gets relocated. */ seg->data.i = arrayMax(look->seqInfo)-1 ; *newSinf = *oldSinf ; if (flag) { newSinf->flags |= flag ; graphBoxDraw (box, -1, newSinf->flags & SEQ_CONFIRM_UTR ? YELLOW : GREEN) ; } else { newSinf->flags &= ~SEQ_CONFIRMED ; /* clear all CONFIRM flags */ graphBoxDraw (box, -1, WHITE) ; } return; } static void intronConfirmEST (int box) { intronConfirm (box, SEQ_CONFIRM_EST) ; } static void intronConfirmHomol (int box) { intronConfirm (box, SEQ_CONFIRM_HOMOL) ; } static void intronConfirmCDNA (int box) { intronConfirm (box, SEQ_CONFIRM_CDNA) ; } static void intronConfirmUTR (int box) { intronConfirm (box, SEQ_CONFIRM_UTR) ; } static void intronConfirmFalse (int box) { intronConfirm (box, SEQ_CONFIRM_FALSE) ; } static void intronConfirmIncon (int box) { intronConfirm (box, SEQ_CONFIRM_INCONSIST) ; } static void intronUnconfirm (int box) { intronConfirm (box, 0) ; } static MENUOPT intronMenu[] = { { (GraphFunc)intronConfirmEST, "Confirm by EST" }, { (GraphFunc)intronConfirmHomol, "Confirm by Homol" }, { (GraphFunc)intronConfirmCDNA, "Confirm by CDNA" }, { (GraphFunc)intronConfirmUTR, "Confirm in UTR" }, { (GraphFunc)intronConfirmFalse, "Confirm as False" }, { (GraphFunc)intronConfirmIncon, "Confirm as Inconsistent" }, { (GraphFunc)intronUnconfirm, "Unconfirm" }, { 0, 0 } } ; /*****************************/ static void fMapBoxInfo (FeatureMap look, int box, SEG *seg) { /* only necessary in a non-interactive graphics session, e.g. giface */ if (isGifDisplay) { fMapReportLine (look, seg, TRUE, 0) ; graphBoxInfo (box, seg->key ? seg->key : seg->parent, strnew (look->segTextBuf, look->segsHandle)) ; } return; } /* fMapBoxInfo */ /*************************************/ /* THESE FUNCTIONS ARE CALLED FROM mapcontrol.c, basically to find out what */ /* sort of method will be used to draw a column, seems crazy, mapcontrol */ /* is doing the drawing but doesn't know the type of its own columns... */ /* wierd encapsulation... It needs to, not only to draw the pull down menus, */ /* but also to do some frame related stuff...don't know what goes on in that */ /* bit. */ /* Can a column have an interactive menu ?? */ /* This is a big hacky, I think that the cols themselves should "know" if */ /* they are configurable, this would be much better. They really need to */ /* retain more information than just the column drawing function pointer. */ /* I'll have a think about this. */ /* */ BOOL fmapColHasMenu(MapColDrawFunc func) { BOOL result = FALSE ; if (func == fMapShowSequence || func == fMapShowHomol || func == fMapShowFeature || func == fMapShowFeatureObj || func == fMapShowSplices || func == fMapShowCanonical) result = TRUE ; return result ; } /* Called from mapcontrol.c where comments are cryptic. */ BOOL fmapIsFrameFunc(MapColDrawFunc func) { BOOL result = FALSE ; if (func == fMapShow3FrameTranslation || func == fMapShowORF) result = TRUE ; return result ; } /* called from mapcontrol.c where comments are cryptic. */ BOOL fmapIsGeneTranslationFunc(MapColDrawFunc func) { BOOL result = FALSE ; if (func == fMapShowDownGeneTranslation || func == fMapShowUpGeneTranslation) result = TRUE ; return result ; } /*************************************/ /* This is of type MapColDrawFunc and is called to draw either a sequence */ /* block or for a series of exons/introns. */ /* Something to note about drawing of exons when there is a cds: we rely on */ /* the fact that segs have been sorted so that the cds for a set of exons */ /* will come _before_ the exons in the array of segs. This is achieved by */ /* sorting in fMapConvert. */ /* */ static void drawInterruptedRectangle(FeatureMap look, Array gaps, float x1, float y1, float x2, float y2) { float xmid = (x1+x2)/2; float p1, p2; int j; if (y1 > y2) { float tmp = y2; y2 = y1; y1 = tmp; } p2 = MAP2GRAPH(look->map, array(gaps, 0, SMapMap).r1); for (j = 0; j < arrayMax(gaps); j++) { float s1, s2; p1 = MAP2GRAPH(look->map, array(gaps, j, SMapMap).r1); if (p1 < p2) { s1 = p1; s2 = p2; } else { s1 = p2; s2 = p1; } if (s1 != s2 && s1 <= y2 && s2 >= y1) { float k; if (s1 < y1) s1 = y1; if (s2 > y2) s2 = y2; for (k = s1; k < s2; k++) graphLine(xmid, k, xmid, k+0.6 < s2 ? k+0.6 : s2) ; } p2 = MAP2GRAPH(look->map, array(gaps, j, SMapMap).r2); if (p1 < p2) { s1 = p1; s2 = p2; } else { s1 = p2; s2 = p1; } if (s1 <= y2 && s2 >= y1) { if (s1 < y1) s1 = y1; if (s2 > y2) s2 = y2; graphRectangle(x1, s1, x2, s2) ; } } } /* Shows sequence and exon/intron objects. * */ void fMapShowSequence (LOOK genericLook, float *offset, MENU *menu) { FeatureMap look = (FeatureMap)genericLook; void *xx ; int i, box, x ; float y1, y2, yb ; SEG *seg ; Associator seq2x = assCreate () ; SEQINFO *sinf ; BoxCol *bc ; BOOL isData = FALSE; BOOL firstError = TRUE ; BOOL off_top, off_bottom ; BOOL CDS_present = FALSE ; float CDS_top, CDS_bottom ; BOOL CDS_off_top, CDS_off_bottom ; float left, right ; fMapDebug = FALSE; if (fMapDebug) printf("\nstart:\n") ; /* Set up drawing style for sequence/exons/introns */ bc = bcFromName (look, look->map->activeColName, menu) ; if (!bcTestMag (bc, look->map->mag)) return ; bc->offset = *offset ; /* THIS IS NOT THE WAY TO SET DEFAULTS....AGGGGGGGHHHHHHHH........ */ if (!bc->meth->width) bc->width = 1.25 ; if (!bc->meth->colour) bc->meth->colour = BLUE ; if (!bc->meth->CDS_colour) bc->meth->CDS_colour = PURPLE ; /* Draw all the sequence/exon/intron segs. */ for (i = 1 ; i < arrayMax(look->segs) ; ++i) { seg = arrp(look->segs, i, SEG) ; if (seg->type != SEQUENCE && seg->type != SEQUENCE_UP && seg->type != EXON && seg->type != EXON_UP && seg->type != INTRON && seg->type != INTRON_UP) continue ; if ((seg->type & 0x01) == bc->isDown) continue ; if (fMapDebug) printf("SEG: parent: %s, type: %s at %d, %d before clip coords\n", name(seg->parent), fMapSegTypeName[seg->type], seg->x1, seg->x2) ; /* Set top/bottom coords for objects that will be clipped. */ if (!clipCoords(look, seg, &y1, &y2, &off_top, &off_bottom)) continue ; if (fMapDebug) printf("SEG: parent: %s, type: %s at %d, %d after clip coords\n", name(seg->parent), fMapSegTypeName[seg->type], seg->x1, seg->x2) ; switch (seg->type) { case SEQUENCE: case SEQUENCE_UP: sinf = arrp(look->seqInfo, seg->data.i, SEQINFO) ; if (lexAliasOf(sinf->method) != bc->meth->key) break ; x = 0 ; yb = seg->x1 ; /* bump in seg coords, since increasing */ isData = TRUE ; if (bc->bump) bumpItem (bc->bump, 1, (seg->x2-seg->x1+1), &x, &yb) ; assInsert (seq2x, assVoid(seg->parent), assVoid(x+1)) ; if (bc->meth->isShowText) addVisibleInfo (look, i) ; if (sinf->flags & SEQ_EXONS) /* will draw exons later */ break ; box = graphBoxStart () ; array(look->boxIndex, box, int) = i ; if ((bc->meth->flags & METHOD_GAPS) && sinf->gaps) drawInterruptedRectangle(look, sinf->gaps, *offset + (x + 0.25)*bc->width, y1, *offset + (x + 0.75)*bc->width, y2); else /* no gaps */ graphRectangle (*offset + (x + 0.25)*bc->width, y1, *offset + (x + 0.75)*bc->width, y2) ; graphBoxEnd() ; fMapBoxInfo (look, box, seg) ; graphBoxDraw (box, bc->meth->colour, WHITE) ; break ; case EXON: case EXON_UP: { sinf = arrp(look->seqInfo, seg->data.i, SEQINFO) ; if (lexAliasOf(sinf->method) != bc->meth->key) break ; if (assFind (seq2x, assVoid(seg->parent), &xx)) x = assInt(xx) - 1 ; else { if (firstError) messerror("Can't find exon offset for %s in fMapShowSequence", name(seg->parent)) ; firstError = FALSE ; break ; } if (sinf->flags & SEQ_CDS) { /* If CDS is not on screen then don't draw it. */ CDS_present = clipCoords(look, &(sinf->cds_info.cds_seg), &CDS_top, &CDS_bottom, &CDS_off_top, &CDS_off_bottom) ; if (fMapDebug && CDS_present) printf("%s - CDS start: %d -> %f, end: %d -> %f\n", nameWithClass(seg->parent), sinf->cds_info.cds_seg.x1, CDS_top, sinf->cds_info.cds_seg.x2, CDS_bottom) ; } else CDS_present = FALSE ; /* Set stuff that is the same for all exons/introns. */ left = *offset + ((x + 0.1) * bc->width) ; right = *offset + ((x + 0.9) * bc->width) ; changeGeneMenu(look, seg, sinf->cds_info.cds_only) ; if (!CDS_present) { fMapDrawBox(look, i, geneMenu, seg, left, y1, right, y2, off_top, off_bottom, bc->meth->colour, WHITE) ; } else { float start_rna_top, start_rna_bot ; /* pre-CDS dna in exon. */ float cds_top, cds_bot ; /* CDS dna in exon. */ float end_rna_top, end_rna_bot ; /* post-CDS in exon. */ /* following to record truncation */ BOOL start_rna_offtop = FALSE ; BOOL start_rna_offbot = FALSE ; BOOL cds_offtop = FALSE ; BOOL cds_offbot = FALSE ; BOOL end_rna_offtop = FALSE ; BOOL end_rna_offbot = FALSE ; start_rna_top = start_rna_bot = cds_top = cds_bot = end_rna_top = end_rna_bot = 0.0 ; /* initialised to 0 for drawing logic. */ /* In drawing the CDS we have to cope with when the coords are */ /* reversed, the -ve bit means we can keep the tests constant. */ if (CDS_top > CDS_bottom) { if (y1 < y2) { messerror("The exon and CDS coordinates for %s " "are going in different directions. " "Exon top: %d bot: %d, " "CDS top: %d bot: %d.", name(seg->parent), seg->x1, seg->x2, sinf->cds_info.cds_seg.x1, sinf->cds_info.cds_seg.x2) ; break ; } CDS_top = -CDS_top, CDS_bottom = -CDS_bottom, y1 = -y1, y2 = -y2 ; } /* Figure out how much of this exon is covered by CDS. */ /* Note that drawing will overlap because this is all in floats*/ if (y1 > CDS_bottom || y2 < CDS_top) { /* no CDS in exon. */ start_rna_top = y1 ; start_rna_bot = y2 ; start_rna_offtop = off_top, start_rna_offbot = off_bottom ; } else if (y1 >= CDS_top && y2 <= CDS_bottom) { /* exon is all CDS. */ cds_top = y1 ; cds_bot = y2 ; cds_offtop = off_top, cds_offbot = off_bottom ; } else if (y1 < CDS_top && y2 <= CDS_bottom) { /* exon contains start of CDS. */ start_rna_top = y1 ; start_rna_bot = CDS_top ; cds_top = CDS_top ; cds_bot = y2 ; start_rna_offtop = off_top, start_rna_offbot = FALSE ; cds_offtop = FALSE, cds_offbot = off_bottom ; } else if (y1 < CDS_top && y2 > CDS_bottom) { /* exon contains start of CDS and, pathologically, end of */ /* CDS as well. */ start_rna_top = y1 ; start_rna_bot = CDS_top ; cds_top = CDS_top ; cds_bot = CDS_bottom ; end_rna_top = CDS_bottom ; end_rna_bot = y2 ; start_rna_offtop = off_top, start_rna_offbot = FALSE ; cds_offtop = FALSE, cds_offbot = FALSE ; end_rna_offtop = FALSE, end_rna_offbot = off_bottom ; } else if (y1 >= CDS_top && y2 > CDS_bottom) { /* exon contains end of CDS. */ cds_top = y1 ; cds_bot = CDS_bottom ; end_rna_top = CDS_bottom ; end_rna_bot = y2 ; cds_offtop = off_top, cds_offbot = FALSE ; end_rna_offtop = FALSE, end_rna_offbot = off_bottom ; } else messcrash("Internal error in calculating position of CDS in EXON." "\n CDS coords: %f --> %f," "\nExon coords: %f --> %f", CDS_top, CDS_bottom, y1, y2) ; /* If we made coords negative for above tests, make them +ve. */ if (CDS_top < 0) { CDS_top = -CDS_top, CDS_bottom = -CDS_bottom, y1 = -y1, y2 = -y2 ; start_rna_top = -start_rna_top, start_rna_bot = -start_rna_bot, cds_top = -cds_top, cds_bot = -cds_bot, end_rna_top = -end_rna_top, end_rna_bot = -end_rna_bot ; } if (fMapDebug) { printf("%s - seg x1: %d -> %f, seg x2: %d -> %f\n", nameWithClass(seg->parent), seg->x1, y1, seg->x2, y2) ; printf("%s - rna_start: %f --> %f, CDS: %f --> %f, rna_end: %f --> %f\n", nameWithClass(seg->parent), start_rna_top, start_rna_bot, cds_top, cds_bot, end_rna_top, end_rna_bot) ; } /* Now draw any boxes that need to be drawn. */ /* NOTE how all boxes drawn are associated with the same exon */ /* seg, _not_ the CDS seg, so we pick up the DNA, menus etc. */ /* Draw CDS last so it overlays the exon, looks better. */ /* */ /* Actually this needs fixing, users would prefer to get to */ /* the CDS stuff when they click on the cds box. */ /* */ if (start_rna_bot != 0) fMapDrawBox(look, i, geneMenu, seg, left, start_rna_top, right, start_rna_bot, start_rna_offtop, start_rna_offbot, bc->meth->colour, WHITE) ; if (end_rna_bot != 0) fMapDrawBox(look, i, geneMenu, seg, left, end_rna_top, right, end_rna_bot, end_rna_offtop, end_rna_offbot, bc->meth->colour, WHITE) ; if (cds_bot != 0) fMapDrawBox(look, i, geneMenu, seg, left, cds_top, right, cds_bot, cds_offtop, cds_offbot, bc->meth->CDS_colour, WHITE) ; } break ; } case INTRON: case INTRON_UP: { float midway ; sinf = arrp(look->seqInfo, seg->data.i, SEQINFO) ; if (lexAliasOf(sinf->method) != bc->meth->key) break ; if (assFind (seq2x, assVoid(seg->parent), &xx)) x = assInt(xx) - 1 ; else { if (firstError) messerror ("Can't find intron offset for %s in fMapShowSequence().", name(seg->parent)) ; firstError = FALSE ; break ; } /* Draw the intron, line has no peak if its clipped at top/bot. */ box = graphBoxStart () ; array(look->boxIndex,box,int) = i ; left = *offset + ((x + 0.5) * bc->width) ; right = *offset + ((x + 0.9) * bc->width) ; if (off_top) graphLine(left, y2, right, y1) ; else if (off_bottom) graphLine(left, y1, right, y2) ; else { midway = 0.5 * (y1 + y2) ; graphLine(left, y1, right, midway) ; graphLine(right, midway, left, y2) ; } graphBoxEnd() ; fMapBoxInfo (look, box, seg) ; if (sinf->flags & SEQ_CONFIRMED) graphBoxDraw (box, bc->meth->colour, sinf->flags & SEQ_CONFIRM_UTR ? YELLOW : GREEN); else graphBoxDraw (box, bc->meth->colour, WHITE) ; if (seg->type == INTRON) graphBoxMenu (box, intronMenu) ; } break ; default: break ; } } if (bc->bump) { *offset += (bc->width * bumpMax(bc->bump)) ; bumpDestroy (bc->bump); } else if (isData) *offset += bc->width ; assDestroy (seq2x) ; if (fMapDebug) printf("\nend\n") ; fMapDebug = FALSE ; return; } /* fMapShowSequence */ /* Deal with coords that go off top/bottom of map or have been clipped * during mapping. * Returns FALSE and does not alter the X_out params if the coords are * not on the window at all, otherwise they get clipped to the top/bottom * of the window and off_top/bottom get set to indicate that top/bottom * have been clipped. */ static BOOL clipCoords(FeatureMap look, SEG *seg, float *y1_out, float *y2_out, BOOL *off_top_out, BOOL *off_bottom_out) { BOOL on_screen = TRUE ; int top, bot ; BOOL off_top, off_bottom ; off_top = off_bottom = FALSE ; top = seg->x1 ; bot = seg->x2 + 1 ; /* seg->x2+1 to cover full base */ if (top > look->max || bot < look->min) { on_screen = FALSE ; } else { on_screen = TRUE ; if (seg->flags & SEGFLAG_CLIPPED_TOP) off_top = TRUE ; if (top < look->min) { top = look->min ; off_top = TRUE ; } if (seg->flags & SEGFLAG_CLIPPED_BOTTOM) off_bottom = TRUE ; if (bot > look->max) { bot = look->max ; off_bottom = TRUE ; } *y1_out = MAP2GRAPH(look->map, top) ; *y2_out = MAP2GRAPH(look->map, bot) ; *off_top_out = off_top ; *off_bottom_out = off_bottom ; } return on_screen ; } /* Sometimes in fmap we want to draw rectangles that are clipped off at the */ /* top or bottom, this routine encapsulates this. I don't think its worth */ /* putting this in the graph package because I don't want to clutter up */ /* graph with this application specific stuff. */ /* This is an internal fmap routine and does not do basic checks, the caller */ /* should have done that. */ /* */ void fMapDrawBox(FeatureMap look, int box_index, MENUOPT gene_menu[], SEG *seg, float left, float top, float right, float bottom, BOOL off_top, BOOL off_bottom, int foreground, int background) { int box ; box = graphBoxStart() ; array(look->boxIndex, box, int) = box_index ; if (!off_top && !off_bottom) { graphRectangle(left, top, right, bottom) ; } else { graphLine(left, top, left, bottom) ; graphLine(right, top, right, bottom) ; if (!off_bottom) graphLine(left, bottom, right, bottom) ; if (!off_top) graphLine(left, top, right, top) ; } graphBoxEnd() ; fMapBoxInfo(look, box, seg) ; graphBoxDraw(box, foreground, background) ; if (gene_menu) graphBoxMenu(box, gene_menu) ; return ; } /***************************************/ /***** dynamically change geneMenu *****/ static void changeGeneMenu(FeatureMap look, SEG *seg, BOOL cds_only) { geneMenu[CDS_TRANS_INDEX].text = CDS_TRANS_ON ; geneMenu[COMPLETE_TRANS_INDEX].text = COMPLETE_TRANS_ON ; if (look->translateGene == seg->parent) /* we have that gene already selected for translation */ { BOOL column_on = FALSE ; if ((seg->type == EXON_UP && mapColSetByName(look->map, "Up Gene Translation", MAPCOL_QUERY)) || (seg->type == EXON && mapColSetByName(look->map, "Down Gene Translation", MAPCOL_QUERY))) { column_on = TRUE ; } if (cds_only) { geneMenu[COMPLETE_TRANS_INDEX].text = COMPLETE_TRANS_ON ; if (column_on) geneMenu[CDS_TRANS_INDEX].text = CDS_TRANS_OFF ; else geneMenu[CDS_TRANS_INDEX].text = CDS_TRANS_ON ; } else { geneMenu[CDS_TRANS_INDEX].text = CDS_TRANS_ON ; if (column_on) geneMenu[COMPLETE_TRANS_INDEX].text = COMPLETE_TRANS_OFF ; else geneMenu[COMPLETE_TRANS_INDEX].text = COMPLETE_TRANS_ON ; } } return ; } /* column "Confirmed introns" */ void fMapShowSoloConfirmed (LOOK genericLook, float *offset, MENU *unused) /* This is of type MapColDrawFunc */ { FeatureMap look = (FeatureMap)genericLook; int i, box, x ; float y1, y2 ; SEG *seg ; SEQINFO *sinf ; BUMP bump = bumpCreate (20, 0) ; BOOL isDown = (*look->map->activeColName == '-') ? FALSE : TRUE ; for (i = 1 ; i < arrayMax(look->segs) ; ++i) { seg = arrp(look->segs,i,SEG) ; if (seg->x1 > look->max || seg->x2 < look->min) continue ; if (!((seg->type == INTRON && isDown) || (seg->type == INTRON_UP && !isDown))) continue ; sinf = arrp(look->seqInfo, seg->data.i, SEQINFO) ; if (seg->parent || !(sinf->flags & SEQ_CONFIRMED)) continue ; y1 = MAP2GRAPH(look->map,seg->x1) ; y2 = MAP2GRAPH(look->map,seg->x2+1) ; /* to cover full base */ if (y1 < 2 + topMargin) y1 = 2 + topMargin ; if (y2 < 2 + topMargin) y2 = 2 + topMargin ; x = 1 ; bumpItem (bump, 1, (y2-y1), &x, &y1) ; box = graphBoxStart() ; array(look->boxIndex,box,int) = i ; graphLine (*offset + x, y1, *offset + x + 0.5, 0.5*(y1+y2)) ; graphLine (*offset + x, y2, *offset + x + 0.5, 0.5*(y1+y2)) ; graphBoxEnd() ; graphBoxDraw (box, BLACK, GREEN) ; graphBoxMenu (box, intronMenu) ; fMapBoxInfo (look, box, seg) ; } *offset += bumpMax (bump) ; bumpDestroy (bump) ; return; } /* fMapShowSoloConfirmed */ void fMapShowEmblFeatures (LOOK genericLook, float *offset, MENU *unused) /* This is of type MapColDrawFunc */ { FeatureMap look = (FeatureMap)genericLook; int i, box, x ; float y1, y2 ; SEG *seg ; BUMP bump = bumpCreate (20, 0) ; for (i = 1 ; i < arrayMax(look->segs) ; ++i) { seg = arrp(look->segs,i,SEG) ; if (seg->x1 > look->max || seg->x2 < look->min) continue ; y1 = MAP2GRAPH(look->map,seg->x1) ; y2 = MAP2GRAPH(look->map,seg->x2+1) ; /* to cover full base */ if (y1 < 2 + topMargin) y1 = 2 + topMargin ; if (y2 < 2 + topMargin) y2 = 2 + topMargin ; switch (seg->type) { case EMBL_FEATURE: case EMBL_FEATURE_UP: x = 0 ; bumpItem (bump, 1, (y2-y1), &x, &y1) ; box = graphBoxStart() ; array(look->boxIndex,box,int) = i ; graphRectangle (*offset + x + 0.25, y1, *offset + x + 0.75, y2) ; graphBoxEnd() ; fMapBoxInfo (look, box, seg) ; graphBoxDraw (box, DARKRED, WHITE) ; array(look->visibleIndices,arrayMax(look->visibleIndices),int) = i ; break ; default: break ; } } *offset += bumpMax (bump) ; bumpDestroy (bump) ; return; } /* fMapShowEmblFeatures */ /****************************************************************/ /******************** text features *****************************/ static BOOL showVisibleTagNames = FALSE ; /* suppress tag names in "Visible" column */ static int bumpOff ; static void bumpWrite (BUMP bump, char *text, int x, float y) { bumpItem (bump, strlen(text)+1, 1, &x, &y) ; graphText (text, bumpOff+x, y-0.5) ; } static BOOL isReversed ; static FeatureMap x1Look ; /* set in fMapShowText */ static int x1Order (void *a, void *b) { int diff ; if (isReversed) diff = arrp(x1Look->segs, *(int*)b, SEG)->x2 - arrp(x1Look->segs, *(int*)a, SEG)->x2 ; else diff = arrp(x1Look->segs, *(int*)a, SEG)->x1 - arrp(x1Look->segs, *(int*)b, SEG)->x1 ; if (diff > 0) return 1 ; else if (diff < 0) return -1 ; else return 0 ; } /* i is the index of a seg */ static void addVisibleInfo (FeatureMap look, int i) { KEY key = arrp(look->segs,i,SEG)->key ; register int j ; register SEG *seg = 0 ; static int jmin, jmax ; /* for efficiency cache start/end of VISIBLE segs */ /* relies on segs not being reordered during drawing */ if (!arrayMax(look->visibleIndices)) fMapFindSegBounds (look, VISIBLE, &jmin, &jmax) ; /* first add the item itself */ array(look->visibleIndices,arrayMax(look->visibleIndices),int) = i ; /* then related VISIBLEs */ if (jmin < jmax) seg = arrp(look->segs,jmin,SEG) ; for (j = jmin ; j < jmax ; ++j, ++seg) if (seg->parent == key) array(look->visibleIndices,arrayMax(look->visibleIndices),int) = j ; return; } /* addVisibleInfo */ void fMapShowText (LOOK genericLook, float *offset, MENU *unused) /* This is of type MapColDrawFunc */ { FeatureMap look = (FeatureMap)genericLook; int i, j, box ; Stack textStack = stackCreate(100) ; float y ; SEG *seg ; BUMP bump ; bump = bumpCreate (40, 0) ; bumpOff = *offset ; isReversed = ((look->flag & FLAG_REVERSE) > 0) ; x1Look = look ; arraySort (look->visibleIndices, x1Order) ; graphColor (BLACK) ; for (j = 0 ; j < arrayMax(look->visibleIndices) ; ++j) { i = arr(look->visibleIndices, j, int) ; seg = arrp(look->segs, i, SEG) ; if (isReversed) y = MAP2GRAPH(look->map,seg->x2) ; else y = MAP2GRAPH(look->map,seg->x1) ; if (y < topMargin + 2) y = topMargin + 2 ; box = 0 ; switch (seg->type) { case SEQUENCE: case SEQUENCE_UP: box = graphBoxStart() ; bumpWrite (bump,name(seg->key), 0, y) ; graphBoxEnd() ; break ; case HOMOL: case HOMOL_UP: box = graphBoxStart() ; bumpWrite (bump,name(seg->key), 4, y) ; graphBoxEnd() ; break ; case FEATURE: case FEATURE_UP: box = graphBoxStart() ; bumpWrite (bump, dictName (look->featDict, -seg->parent), 4, y) ; graphBoxEnd() ; break ; case VISIBLE: box = graphBoxStart() ; stackClear (textStack) ; if (showVisibleTagNames && iskey (seg->data.k)) /* mieg: prevents (NULL KEY)) */ { catText (textStack, name(seg->data.k)) ; catText (textStack, ":") ; } /* there is a problem if the model says: Visible foo Text this is the origin of the NULL KEY in the displays */ if (iskey (seg->key)) /* mieg: hack to prevents (NULL KEY)) */ catText (textStack, name(seg->key)) ; bumpWrite (bump,stackText(textStack,0),10,y) ; graphBoxEnd() ; if (iskey (seg->key)) graphBoxInfo (box, seg->key, strnew (messprintf ("%s:%s", iskey (seg->data.k) ? name(seg->data.k) : "" , name(seg->key)), look->segsHandle)) ; break ; case ALLELE: case ALLELE_UP: case EMBL_FEATURE: case EMBL_FEATURE_UP: box = graphBoxStart() ; stackClear (textStack) ; if (iskey (seg->key)) catText (textStack, name(seg->key)) ; if (seg->data.s) { catText (textStack, ":") ; catText (textStack, seg->data.s) ; } bumpWrite (bump,stackText(textStack,0),10,y) ; graphBoxEnd() ; break ; default: break ; } if (box) { array(look->boxIndex,box,int) = i ; fMapBoxInfo (look, box, seg) ; } } *offset += bumpMax(bump) ; bumpDestroy (bump) ; stackDestroy (textStack) ; return; } /* fMapShowText */ /*************************************************************/ /******** external stuff: efetch, blxview, trnafold ***********/ static void fMapEfetch (int box) { SEG *seg ; FeatureMap look = currentFeatureMap("fMapEfetch") ; if ((seg = BOXSEG(box))) externalCommand(messprintf("efetch '%s' &", name(seg->key))); return ; } static void fMapPfetch (int box) { SEG *seg ; FeatureMap look = currentFeatureMap("fMapPfetch") ; if ((seg = BOXSEG(box))) externalCommand(messprintf("pfetch -F '%s' &", name(seg->key))); /* pfetchWindow(seg->key); revert to prev version until gtk 2.2.2 implemented */ return ; } static void fMapFetch (int box) { static KEY _Database = 0 ; SEG *seg ; KEY lib ; OBJ obj = 0, libObj = 0 ; char *id, *pref, *suff, *url = 0 ; FeatureMap look = currentFeatureMap("fMapFetch") ; if (!_Database) lexaddkey ("Database", &_Database, 0) ; if (!(seg = BOXSEG(box))) return ; if ((obj = bsCreate (seg->key)) && bsGetKey (obj, _Database, &lib) && bsGetData (obj, _bsRight, _Text, &id) && (libObj = bsCreate (lib))) { if (bsGetData (libObj, _Arg1_URL_prefix, _Text, &pref)) { if (bsGetData (libObj, _Arg1_URL_suffix, _Text, &suff)) url = messprintf ("%s%s%s", pref, id, suff) ; else url = messprintf ("%s%s", pref, id) ; } else if (bsGetData (obj, _bsRight, _Text, &id) && bsGetData (libObj, _Arg2_URL_prefix, _Text, &pref)) { if (bsGetData (libObj, _Arg2_URL_suffix, _Text, &suff)) url = messprintf ("%s%s%s", pref, id, suff) ; else url = messprintf ("%s%s", pref, id) ; } } bsDestroy (obj) ; bsDestroy (libObj) ; /* OK if 0 */ if (!url) url = messprintf ("http://www.sanger.ac.uk/cgi-bin/seq-query?%s", name(seg->key)) ; graphWebBrowser (url) ; return; } /* fMapFetch */ static void showAlignAnticipate (KEYSET ks) { KEYSET ks2 ; if (!externalServer) return ; keySetSort (ks) ; keySetCompress (ks) ; oldSetForServer = ks ; externalServer (-1, 0, 0, TRUE) ; /* get these sequences */ ks2 = queryLocalParametrized(ks,"{FOLLOW DNA} $| {FOLLOW Peptide}",0) ; oldSetForServer = ks2 ; externalServer (-1, 0, 0, TRUE) ; oldSetForServer = 0 ; keySetDestroy (ks2) ; return; } /* showAlignAnticipate */ static int scoreOrder(void *a, void *b) { return (*(float*)a) < (*(float*)b) ? 1 : (*(float*)a) == (*(float*)b) ? 0 : -1 ; } /* Call blixem to show the alignments. */ static void doShowAlign (int x1, int x2, char *opts, KEY methodKey) { SEG *seg, seg_copy ; int nks = 0, i, min, max, first, offset; char *seq, *cp, *cq ; MSP *msp1, *msp, *msp2, *prevmsp=0; KEY key ; HOMOLINFO *hinf ; unsigned int methodFlag ; Array a ; KEYSET ks = 0 ; OBJ obj = 0 ; FeatureMap look = currentFeatureMap("fMapShowAlign") ; METHOD *meth; int scope = prefInt("BLIXEM_SCOPE"); int cutoff = prefInt("BLIXEM_HOMOL_MAX"); Array scores = arrayCreate(100, int); PfetchParams *pfetch_params = NULL ; KEY _Show_in_reverse_orientation = str2tag("Show_in_reverse_orientation") ; char *seq_name = NULL ; if (!scope) scope = 40000 ; /* Should be stored in prefs perhaps. */ methodFlag = (*opts == 'X') ? METHOD_BLIXEM_X : METHOD_BLIXEM_N ; min = x1 - scope/2 ; max = x2 + scope/2 ; if (min < 0) min = 0 ; if (max >= look->length) max = look->length - 1 ; seq = (char*) messalloc (max-min+2) ; cp = seq ; cq = arrp(look->dna, min, char) ; for (i = min ; i++ <= max ; ) { *cp++ = dnaDecodeChar[(int)*cq++] ; } *cp = 0 ; offset = min - look->origin ; first = x1 - min - 30 ; if (first <= 0) first = 1 ; ks = keySetCreate () ; nks = 0 ; msp = msp1 = (MSP*) messalloc (sizeof(MSP)) ; for (i = 1 ; i < arrayMax(look->segs) ; ++i) { seg = arrp(look->segs, i, SEG) ; if (seg->x1 < min || seg->x2 < min || seg->x1 > max || seg->x2 > max) continue ; /* Some homologies (e.g. for EST read pairs) were swopped to the opposite * strand for display, now we come to blixem them, we need to temporarily * swop them back to their original strand, hence the seg copying below. */ if (bIndexTag(seg->key, _Show_in_reverse_orientation)) { seg_copy = *seg ; /* n.b. struct copy. */ seg = &seg_copy ; SEG_FLIP(seg) ; } if (SEG_IS_UP(seg)) /* UP */ { msp->qstart = seg->x2 -min + 1 ; msp->qend = seg->x1 - min + 1 ; } else /* DOWN */ { msp->qstart = seg->x1 - min + 1 ; msp->qend = seg->x2 - min + 1 ; } switch (seg->type) { case HOMOL: case HOMOL_UP: hinf = arrp(look->homolInfo, seg->data.i, HOMOLINFO) ; if (methodKey && lexAliasOf(hinf->method) != lexAliasOf(methodKey)) break ; if (!(meth = methodCacheGet(look->mcache, hinf->method, ""))) break; if (!(meth->flags & methodFlag)) break ; msp->key = seg->key ; msp->sname = messalloc(strlen(name(seg->key)) + 1) ; strcpy (msp->sname, name(seg->key)) ; keySet(ks, nks++) = seg->key ; if (SEG_IS_UP(seg)) strcpy (msp->qframe, messprintf ("(-%d)", 1 + ((max-min+1) - msp->qstart) % 3)) ; else strcpy (msp->qframe, messprintf ("(+%d)", 1 + (msp->qstart-1) % 3)) ; msp->score = hinf->score + 0.5 ; /* float to int convert */ msp->sstart = hinf->x1 ; msp->send = hinf->x2 ; if (hinf->gaps) { int i; msp->gaps = arrayCopy(hinf->gaps); for(i = 0; i < arrayMax(msp->gaps); i++) { SMapMap *m = arrp(msp->gaps, i, SMapMap); m->r1 -= min; m->r2 -= min; } } break ; case CODING: case CODING_UP: msp->sstart = (seg->data.i + 3) / 3 ; msp->send = (seg->data.i + seg->x2 - seg->x1) / 3 ; msp->score = -1 ; msp->id = 100; msp->sname = messalloc(strlen(name(seg->parent))+2) ; sprintf (msp->sname, "%sx", name(seg->parent)) ; keySet(ks, nks++) = seg->parent ; if (!(seg->type & 0x1)) /* x separates from Wormpep entry */ sprintf (msp->qframe, "(+%d)", 1 + (msp->qstart - 1 - seg->data.i)%3) ; else sprintf (msp->qframe, "(-%d)", 1 + ((max-min+1) - msp->qstart - seg->data.i)%3) ; break ; case INTRON: case INTRON_UP: msp->sstart = msp->send = msp->id = 0 ; msp->score = -2 ; msp->id = 100; msp->sname = messalloc(strlen(name(seg->parent))+2) ; sprintf (msp->sname, "%si", name(seg->parent)) ; /* i for intron */ keySet(ks, nks++) = seg->parent ; if (!(seg->type & 0x1)) strcpy (msp->qframe, "(+1)") ; else strcpy (msp->qframe, "(-1)") ; break ; default: break ; } if (msp->score) /* filled it */ { msp->next = (MSP*) messalloc (sizeof(MSP)) ; prevmsp = msp ; msp = msp->next ; } } /* Free last MSP (empty) */ if (prevmsp) { messfree (prevmsp->next) ; prevmsp->next = 0; } else /* here of none found. */ { messfree(msp1); msp1 = 0; } if (externalServer) showAlignAnticipate (ks) ; keySetDestroy (ks) ; if (*opts == 'X') /* Protein */ for (msp = msp1 ; msp ; msp = msp->next) { if (msp->qstart < 1) { msp->sstart += (3 - msp->qstart) / 3 ; msp->qstart += 3 * ((3 - msp->qstart) / 3) ; } if (msp->qend > max-min+1) { msp->send -= (msp->qend + 2 - (max-min)) / 3 ; msp->qend -= 3 * ((msp->qend + 2 - (max-min)) / 3) ; } /* Fetch sequences, desc from ACEDB */ if (!msp->sseq && lexword2key (msp->sname, &key, _VProtein)) { if ((a = peptideGet(key))) { pepDecodeArray (a) ; msp->sseq = arrp(a, 0, char) ; a->base = 0 ; arrayDestroy(a) ; } else msp->sseq = seq ; /* empty sseq marker */ if ((obj = bsCreate (key))) { if (bsGetKey (obj, _Title, &key)) msp->desc = strnew (name(key), 0) ; bsDestroy (obj) ; } /* Avoid duplication */ for (msp2 = msp->next; msp2 ; msp2 = msp2->next) if (!strcmp(msp->sname, msp2->sname)) { msp2->sseq = msp->sseq ; msp2->desc = msp->desc ; } } } else /* DNA */ for (msp = msp1 ; msp ; msp = msp->next) { if (msp->qstart < 1) { msp->sstart += 1 - msp->qstart ; msp->qstart = 1 ; } if (msp->qend > max-min+1) { msp->send -= max-min+1 - msp->qend ; msp->qend = max-min+1 ; } /* Fetch sequences, desc from ACEDB */ if (!msp->sseq && lexword2key (msp->sname, &key, _VSequence)) { if ((a = dnaGet(key))) { dnaDecodeArray (a) ; msp->sseq = arrp(a, 0, char) ; a->base = 0 ; arrayDestroy(a) ; } else msp->sseq = seq ; /* empty sseq marker */ if ((obj = bsCreate (key))) { if (bsGetKey (obj, _Title, &key)) msp->desc = strnew (name(key), 0) ; bsDestroy (obj) ; } /* Avoid duplication */ for (msp2 = msp->next; msp2 ; msp2 = msp2->next) if (!strcmp(msp->sname, msp2->sname)) { msp2->sseq = msp->sseq ; msp2->desc = msp->desc ; } } } /* remove empty sequence markers and note the scores for pruning excess */ /* sequence-free msps */ for (msp = msp1 ; msp ; msp = msp->next) if (msp->sseq == seq) { msp->sseq = 0 ; array(scores, arrayMax(scores), int) = msp->score; } if (cutoff && (cutoff < arrayMax(scores))) { /* cut out of the chain and free any msps whose score is below the cutoff: fun with linked-lists. */ int chopped = 0, total = 0; int breakpoint; ACEIN score_in; STORE_HANDLE h = handleCreate(); arraySort(scores, scoreOrder); breakpoint = arr(scores, cutoff, int); for (msp = msp1; msp; msp = msp->next) if (!msp->sseq && msp->id != 100) { total++; if (msp->score < breakpoint) chopped++; } if ((score_in = messPrompt(hprintf(h, "%d of %d homologies without sequence " "will be ommited: " "if desired edit cutoff score below, " "or Cancel to see all homologies.", chopped, total), hprintf(h,"%d", breakpoint), "i", h))) { aceInInt(score_in, &breakpoint); msp = msp1; prevmsp = 0; while (msp) { if (!msp->sseq && msp->id != 100 && msp->score < breakpoint) { if (msp->sname) messfree(msp->sname); if (msp->gaps) messfree(msp->gaps); if (prevmsp == 0) /* first in chain */ { msp1 = msp->next; messfree(msp); msp = msp1; } else { prevmsp->next = msp->next; messfree(msp); msp = prevmsp->next; } } else { prevmsp = msp; msp = msp->next; } }; } handleDestroy(h); } arrayDestroy(scores); seq_name = g_strdup(name(look->seqKey)) ; /* Get blixem params from user preferences. */ pfetch_params = NULL ; blixemGetPfetchParams(0, &pfetch_params) ; /* Blixem can either be called synchronously as part of this program or */ /* asychronously as a separate external program. */ if (blixemIsExternal()) { blixemCallExternal(seq, seq_name, first, offset, msp1, opts, pfetch_params) ; } else { blxview(seq, seq_name, first, offset, msp1, opts, pfetch_params, FALSE) ; /* FALSE means it's not an external call */ } messfree(pfetch_params) ; g_free(seq_name) ; return ; } /* doShowAlign */ /**************************************************************/ static void fMapShowPepAlign (int box) { SEG *seg ; BOOL up ; FeatureMap look = currentFeatureMap("fMapShowPepAlign") ; if (!(seg = BOXSEG(box))) return ; if (seg->type == HOMOL_UP) up = TRUE ; else up = FALSE ; /* int x1, x2 ; if (look->flag & FLAG_REVERSE) reverse back temporarily * / { x1 = look->length + 1 - seg->x2 ; x2 = look->length + 1 - seg->x1 ; fMapRC (look) ; look->origin = look->length + 1 - look->origin ; doShowAlign (x1, x2, up ? "X+BR" : "X-BR" , 0) ; fMapRC (look) ; look->origin = look->length + 1 - look->origin ; } else */ doShowAlign(seg->x1, seg->x2, up ? "X-BR" : "X+BR", 0) ; return ; } static void fMapShowPepAlignThis (int box) { SEG *seg ; HOMOLINFO *hinf ; BOOL up ; FeatureMap look = currentFeatureMap("fMapShowPepAlignThis") ; if (!(seg = BOXSEG(box))) return ; hinf = arrp(look->homolInfo, seg->data.i, HOMOLINFO) ; if (seg->type == HOMOL_UP) up = TRUE ; else up = FALSE ; /* int x1, x2 ; if (look->flag & FLAG_REVERSE) // reverse back temporarily * / { x1 = look->length + 1 - seg->x2 ; x2 = look->length + 1 - seg->x1 ; fMapRC (look) ; look->origin = look->length + 1 - look->origin ; doShowAlign (x1, x2, up ? "X+BR" : "X-BR", hinf->method) ; fMapRC (look) ; look->origin = look->length + 1 - look->origin ; } else */ doShowAlign (seg->x1, seg->x2, up ? "X-BR" : "X+BR", hinf->method) ; } /* SHOULD WE DO UP/DOWN STUFF HERE......LIKE FOR PROTEINS ABOVE ???? * If not, WHY NOT ? Oh for just a few comments in the code, life * would be SO MUCH SIMPLER...sigh.... */ static void fMapShowDNAAlign (int box) { SEG *seg ; FeatureMap look = currentFeatureMap("fMapShowDNAAlign") ; if (!(seg = BOXSEG(box))) return ; doShowAlign (seg->x1, seg->x2, "N+BR", 0) ; return; } /* fMapShowDNAAlign */ static void fMapShowDNAAlignThis (int box) { SEG *seg ; HOMOLINFO *hinf ; FeatureMap look = currentFeatureMap("fMapShowDNAAlignThis") ; if (!(seg = BOXSEG(box))) return ; hinf = arrp(look->homolInfo, seg->data.i, HOMOLINFO) ; doShowAlign (seg->x1, seg->x2, "N+BR", hinf->method) ; return; } /* fMapShowDNAAlignThis */ static void fMapExpandAlign (int box) { SEG *seg ; int i, j , xMin, xMax ; KEYSET ks ; SegType type ; FeatureMap look = currentFeatureMap("fMapExpandAlign") ; if (!(seg = BOXSEG(box))) return ; type = seg->type | 0x1 ; ks = keySetCreate () ; xMin = look->zoneMin ; xMax = look->zoneMax ; for (i = 0, j = 0 ; i < arrayMax(look->segs) ; ++i) { seg = arrp(look->segs, i, SEG) ; if (seg->x1 > xMax || seg->x2 < xMin) continue ; if ((seg->type | 0x1) != type) continue ; keySet(ks, j++) = seg->key ; } keySetSort (ks) ; keySetCompress (ks) ; if (keySetMax(ks)) forestDisplayKeySet (0, ks, FALSE) ; /* will destroy ks */ else keySetDestroy (ks) ; return; } /* fMapExpandAlign */ /***************************************************************/ /* fMaptRNAfold uses nip to fold tRNA. Currently doesn't combine exons - fix! */ static void fMaptRNAfold (int box) { SEG *myseg; int i, min, max; char *seq, *cp, *cq ; FeatureMap look = currentFeatureMap("fMapRNAfold") ; if (!(myseg = BOXSEG(box))) return ; min = myseg->x1; max = myseg->x2; seq = (char*) messalloc (max - min +2); for (i = min, cp = seq, cq = arrp(look->dna, min, char) ; i++ <= max ; ) *cp++ = dnaDecodeChar[(int)*cq++] ; *cp = 0 ; externalPipeDisplay ("RNA fold", callScriptPipe ("tRNAfold", seq), 0) ; messfree (seq) ; return; } /* fMaptRNAfold */ /******************** end of external section ***************/ void fMapRemoveSelfHomol (FeatureMap look) { int i, max ; SEG *seg, *cds, *cdsMin, *cdsMax ; char *cp ; fMapFindSegBounds (look, CDS, &i, &max) ; cdsMin = arrp(look->segs, i, SEG) ; cdsMax = arrp(look->segs, max-1, SEG) + 1 ; /* -1+1 for arrayCheck */ fMapFindSegBounds (look, HOMOL, &i, &max) ; for ( ; i < max && i < arrayMax(look->segs) ; ++i) /* arrayMax(look->segs) can change */ { seg = arrp(look->segs, i, SEG) ; for (cp = name(seg->key) ; *cp && *cp != ':' ; ++cp) ; if (*cp) ++cp ; else cp = name(seg->key) ; for (cds = cdsMin ; cds < cdsMax && cds->x1 < seg->x2 ; ++cds) if (cds->x1 <= seg->x1 && cds->x2 >= seg->x2 && !strcmp (cp, name(cds->parent))) { *seg = array(look->segs,arrayMax(look->segs)-1,SEG) ; --arrayMax(look->segs) ; break ; } } fMapFindSegBounds (look, CDS_UP, &i, &max) ; cdsMin = arrp(look->segs, i, SEG) ; cdsMax = arrp(look->segs, max-1, SEG) + 1 ; /* -1+1 for arrayCheck */ fMapFindSegBounds (look, HOMOL_UP, &i, &max) ; for ( ; i < max && i < arrayMax(look->segs) ; ++i) /* arrayMax(look->segs) can change */ { seg = arrp(look->segs, i, SEG) ; for (cp = name(seg->key) ; *cp && *cp != ':' ; ++cp) ; if (*cp) ++cp ; else cp = name(seg->key) ; for (cds = cdsMin ; cds < cdsMax && cds->x1 < seg->x2 ; ++cds) if (cds->x1 <= seg->x1 && cds->x2 >= seg->x2 && !strcmp (cp, name(cds->parent))) { *seg = array(look->segs,arrayMax(look->segs)-1,SEG) ; --arrayMax(look->segs) ; break ; } } return; } /* fMapRemoveSelfHomol */ /****************************************************/ /* This is of type MapColDrawFunc */ void fMapShowHomol (LOOK genericLook, float *offset, MENU *menu) { FeatureMap look = (FeatureMap)genericLook; int i, box ; SEG *seg ; int frame = look->min % 3 ; HOMOLINFO *hinf ; BoxCol *bc ; bc = bcFromName (look, look->map->activeColName, menu) ; if (!bcTestMag(bc, look->map->mag)) return ; bc->offset = *offset ; for (i = 0 ; i < arrayMax(look->segs) ; ++i) { seg = arrp(look->segs, i, SEG) ; if (seg->x1 > look->max || seg->x2 < look->min) continue ; if (seg->type == HOMOL_GAP || seg->type == HOMOL_GAP_UP) { if (!bc->cluster) continue ; } if (seg->type == HOMOL || seg->type == HOMOL_GAP) { if (!bc->isDown) continue ; } else if (seg->type == HOMOL_UP || seg->type == HOMOL_GAP_UP) { if (bc->isDown && (bc->meth->flags & METHOD_STRAND_SENSITIVE)) continue ; } else continue ; if (bit(look->homolBury,seg->data.i)) /* bury */ continue ; hinf = arrp(look->homolInfo, seg->data.i, HOMOLINFO) ; if (lexAliasOf(hinf->method) != bc->meth->key) continue ; if (bc->isFrame && (seg->x1 % 3 != frame)) continue ; if (bc->meth->flags & METHOD_GAPS) box = bcDrawBox (bc, seg, hinf->score, hinf->gaps) ; else box = bcDrawBox (bc, seg, hinf->score, NULL) ; if (box) { array(bc->look->boxIndex, box, int) = i ; if (bc->meth->flags & METHOD_BLIXEM_X) graphBoxMenu (box, pepHomolMenu) ; else if (bc->meth->flags & METHOD_BLIXEM_N) graphBoxMenu (box, dnaHomolMenu) ; if (bc->meth->isShowText) addVisibleInfo (look, i) ; } } if (bc->bump) bumpDestroy (bc->bump); *offset += bc->fmax ; return; } /* fMapShowHomol */ /****************************************************/ /* This is of type MapColDrawFunc, it draws boxes for: * * Lightweight Features, i.e. features that are represented by the * Feature tag set which can be embedded in any object. * * */ void fMapShowFeature (LOOK genericLook, float *offset, MENU *menu) { FeatureMap look = (FeatureMap)genericLook; int i, box ; SEG *seg ; int frame = look->min % 3 ; BoxCol *bc ; bc = bcFromName (look, look->map->activeColName, menu) ; if (!bcTestMag (bc, look->map->mag)) return ; bc->offset = *offset ; for (i = 0 ; i < arrayMax(look->segs) ; ++i) { seg = arrp(look->segs, i, SEG) ; if (seg->x1 > look->max || seg->x2 < look->min) continue ; if (!((bc->isDown && (seg->type == FEATURE || (seg->type == FEATURE_UP && !(bc->meth->flags & METHOD_STRAND_SENSITIVE)))) || (!bc->isDown && seg->type == FEATURE_UP && bc->meth->flags & METHOD_STRAND_SENSITIVE))) continue ; if (lexAliasOf(seg->key) != bc->meth->key) continue ; if (bc->isFrame && (seg->x1 % 3 != frame)) continue ; box = bcDrawBox (bc, seg, seg->data.f, NULL) ; if (box) { array(bc->look->boxIndex, box, int) = i ; if (bc->meth->isShowText && seg->parent) /* -seg->parent = featDict index */ addVisibleInfo (look, i) ; } } if (bc->bump) bumpDestroy (bc->bump); *offset += bc->fmax ; return; } /* fMapShowFeature */ /********************************************/ /****************************************************/ /* This is of type MapColDrawFunc, it draws boxes for: * * Feature Objects, i.e. features that are represented by whole objects, * these could be alleles or anything. * * */ void fMapShowFeatureObj(LOOK genericLook, float *offset, MENU *menu) { FeatureMap look = (FeatureMap)genericLook; int i, box ; SEG *seg ; int frame = look->min % 3 ; BoxCol *bc ; FeatureInfo *feat ; BOOL scored_feature = FALSE ; bc = bcFromName(look, look->map->activeColName, menu) ; if (!bcTestMag (bc, look->map->mag)) return ; bc->offset = *offset ; for (i = 0 ; i < arrayMax(look->segs) ; ++i) { seg = arrp(look->segs, i, SEG) ; if (seg->x1 > look->max || seg->x2 < look->min) continue ; if (!((bc->isDown && (seg->type == FEATURE_OBJ || (seg->type == FEATURE_OBJ_UP && !(bc->meth->flags & METHOD_STRAND_SENSITIVE)))) || (!bc->isDown && seg->type == FEATURE_OBJ_UP && bc->meth->flags & METHOD_STRAND_SENSITIVE))) continue ; feat = arrp(look->feature_info, seg->data.i, FeatureInfo) ; if (lexAliasOf(feat->method) != bc->meth->key) continue ; if (bc->isFrame && (seg->x1 % 3 != frame)) continue ; /* Either we do the point like drawing or box like drawing, this code * is experimental and quite a lot of tidying up needs doing. */ if (bIndexTag(feat->method, str2tag("Point"))) { AlleleDrawType allele_style = ALLELE_DRAW_DELETION ; if (bIndexTag(feat->method, str2tag("Substitution"))) allele_style = ALLELE_DRAW_REPLACMENT ; else if (bIndexTag(feat->method, str2tag("Insertion"))) allele_style = ALLELE_DRAW_TRANSPOSON ; box = 0 ; drawAlleleStyle(look, offset, seg, allele_style, &box) ; } else { box = bcDrawBox (bc, seg, 0.5, NULL) ; } if (box) { array(bc->look->boxIndex, box, int) = i ; if (bc->meth->isShowText && seg->parent) /* -seg->parent = featDict index */ addVisibleInfo (look, i) ; } } if (bc->bump) bumpDestroy (bc->bump); *offset += bc->fmax ; return; } /********************************************/ #ifdef ED_G_NEVER_INCLUDE_THIS_CODE /* This is of type MapColDrawFunc and displays allele features which have * different shapes according to whether they are insertions/deletions etc. * The major feature of the drawing is that at low magnification the allele * is always visible as one of these symbols and as you zoom in the symbol * changes to be a bracket that indicates the extent of the allele. */ void fMapShowAlleles(LOOK genericLook, float *offset, MENU *unused) { static char DNAchars[] = "AGCTagct" ; static Array xy = 0 ; FeatureMap look = (FeatureMap)genericLook; char *cp ; int i, box ; SEG *seg ; BOOL isTransposon, isDeletion ; BOOL isDraw = FALSE ; if (!xy) { xy = arrayCreate (6, float) ; arrayMax(xy) = 6 ; } for (i = 0 ; i < arrayMax(look->segs) ; ++i) { seg = arrp(look->segs, i, SEG) ; if (seg->type > ALLELE_UP) break ; if ((seg->type != ALLELE && seg->type != ALLELE_UP) || (seg->parent != seg->key)) /* no explicit coords given */ continue ; if (look->map->mag * (seg->x2 - seg->x1) < 1) /* point symbol */ { float y = MAP2GRAPH(look->map, 0.5*(seg->x1+seg->x2)) ; if (y > mapGraphHeight || y < topMargin) continue ; isDeletion = isTransposon = FALSE ; if ((cp = seg->data.s)) { if (*cp == '-') isDeletion = TRUE ; else { while (*cp) if (!strchr (DNAchars, *cp++)) isTransposon = TRUE ; } } box = graphBoxStart() ; if (isDeletion) { float y1 = MAP2GRAPH(look->map, seg->x1) ; float y2 = MAP2GRAPH(look->map, seg->x2) ; graphLine (*offset, y1, *offset+1.0, y1) ; graphLine (*offset+1.0, y1, *offset+2.0, y-0.7) ; graphLine (*offset, y2, *offset+1.0, y2) ; graphLine (*offset+1.0, y2, *offset+2.0, y+0.7) ; graphLine (*offset+2.0, y-0.7, *offset+2.0, y+0.7) ; } else if (isTransposon) { arr(xy, 0, float) = *offset ; arr(xy, 1, float) = y ; arr(xy, 2, float) = *offset + 1.0 ; arr(xy, 3, float) = y - 0.7 ; arr(xy, 4, float) = *offset + 1.0 ; arr(xy, 5, float) = y + 0.7 ; graphPolygon (xy) ; graphLine (*offset+1.5, y-0.5, *offset+1.5, y+0.5) ; if (seg->type == ALLELE_UP) { graphLine (*offset+1.1, y, *offset+1.5, y-0.5) ; graphLine (*offset+1.9, y, *offset+1.5, y-0.5) ; } else { graphLine (*offset+1.1, y, *offset+1.5, y+0.5) ; graphLine (*offset+1.9, y, *offset+1.5, y+0.5) ; } } else { graphLine (*offset, y, *offset+0.5, y+0.4) ; graphLine (*offset, y, *offset+0.5, y-0.4) ; graphLine (*offset, y, *offset+1.1, y+0.2) ; graphLine (*offset+1.1, y+0.2, *offset+0.9, y-0.2) ; graphLine (*offset+2, y, *offset+0.9, y-0.2) ; } } else /* bracket to show region */ { float y1 = MAP2GRAPH(look->map, seg->x1) ; float y2 = MAP2GRAPH(look->map, seg->x2) ; if (y1 > mapGraphHeight || y2 < topMargin) continue ; box = graphBoxStart() ; if (y1 < topMargin) graphLine (*offset+2.0, topMargin, *offset+2.0, y2) ; else { graphLine (*offset+1.0, y1, *offset+2.0, y1) ; graphLine (*offset+2.0, y1, *offset+2.0, y2) ; } graphLine (*offset+1.0, y2, *offset+2.0, y2) ; } graphBoxEnd() ; graphBoxDraw (box, BLACK, TRANSPARENT) ; isDraw = TRUE ; array(look->boxIndex, box, int) = i ; fMapBoxInfo (look, box, seg) ; array(look->visibleIndices,arrayMax(look->visibleIndices),int) = i ; } if (isDraw) *offset += 2.0 ; return; } #endif /* ED_G_NEVER_INCLUDE_THIS_CODE */ /* This is of type MapColDrawFunc and displays allele features which have * different shapes according to whether they are insertions/deletions etc. * The major feature of the drawing is that at low magnification the allele * is always visible as one of these symbols and as you zoom in the symbol * changes to be a bracket that indicates the extent of the allele. */ void fMapShowAlleles(LOOK genericLook, float *offset, MENU *unused) { static char DNAchars[] = "AGCTagct" ; FeatureMap look = (FeatureMap)genericLook ; char *cp ; int i ; SEG *seg ; BOOL isDraw = FALSE ; int box ; for (i = 0 ; i < arrayMax(look->segs) ; ++i) { AlleleDrawType allele_draw ; seg = arrp(look->segs, i, SEG) ; if (seg->type > ALLELE_UP) break ; if ((seg->type != ALLELE && seg->type != ALLELE_UP) || (seg->parent != seg->key)) /* no explicit coords given */ continue ; /* Set the type of allele....this surely is hokey models/code stuff..... */ allele_draw = ALLELE_DRAW_REPLACMENT ; if ((cp = seg->data.s)) { if (*cp == '-') allele_draw = ALLELE_DRAW_DELETION ; else { while (*cp) if (!strchr(DNAchars, *cp++)) allele_draw = ALLELE_DRAW_TRANSPOSON ; } } if ((isDraw = drawAlleleStyle(look, offset, seg, allele_draw, &box))) { array(look->boxIndex, box, int) = i ; fMapBoxInfo (look, box, seg) ; array(look->visibleIndices,arrayMax(look->visibleIndices),int) = i ; } } if (isDraw) *offset += 2.0 ; return ; } /* Draw in the allele style....different symbols for different allele features. * The major feature of the drawing is that at low magnification the allele * is always visible as one of these symbols and as you zoom in the symbol * changes to be a bracket that indicates the extent of the allele. */ static BOOL drawAlleleStyle(FeatureMap look, float *offset, SEG *seg, AlleleDrawType allele_draw, int *box_out) { BOOL box_drawn = FALSE ; static Array xy = 0 ; int box ; if (!xy) { xy = arrayCreate (6, float) ; arrayMax(xy) = 6 ; } if (look->map->mag * (seg->x2 - seg->x1) < 1) { /* Less than one unit so draw as a point symbol */ float y = MAP2GRAPH(look->map, 0.5*(seg->x1+seg->x2)) ; if (y > mapGraphHeight || y < topMargin) /* UGH..... */ return FALSE ; box = graphBoxStart() ; if (allele_draw == ALLELE_DRAW_DELETION) { float y1 = MAP2GRAPH(look->map, seg->x1) ; float y2 = MAP2GRAPH(look->map, seg->x2) ; graphLine (*offset, y1, *offset+1.0, y1) ; graphLine (*offset+1.0, y1, *offset+2.0, y-0.7) ; graphLine (*offset, y2, *offset+1.0, y2) ; graphLine (*offset+1.0, y2, *offset+2.0, y+0.7) ; graphLine (*offset+2.0, y-0.7, *offset+2.0, y+0.7) ; } else if (allele_draw == ALLELE_DRAW_TRANSPOSON) { arr(xy, 0, float) = *offset ; arr(xy, 1, float) = y ; arr(xy, 2, float) = *offset + 1.0 ; arr(xy, 3, float) = y - 0.7 ; arr(xy, 4, float) = *offset + 1.0 ; arr(xy, 5, float) = y + 0.7 ; graphPolygon (xy) ; graphLine (*offset+1.5, y-0.5, *offset+1.5, y+0.5) ; if (seg->type == ALLELE_UP) { graphLine (*offset+1.1, y, *offset+1.5, y-0.5) ; graphLine (*offset+1.9, y, *offset+1.5, y-0.5) ; } else { graphLine (*offset+1.1, y, *offset+1.5, y+0.5) ; graphLine (*offset+1.9, y, *offset+1.5, y+0.5) ; } } else /* allele_draw == ALLELE_DRAW_REPLACMENT */ { graphLine (*offset, y, *offset+0.5, y+0.4) ; graphLine (*offset, y, *offset+0.5, y-0.4) ; graphLine (*offset, y, *offset+1.1, y+0.2) ; graphLine (*offset+1.1, y+0.2, *offset+0.9, y-0.2) ; graphLine (*offset+2, y, *offset+0.9, y-0.2) ; } } else { /* otherwise draw as a bracket to show region */ float y1 = MAP2GRAPH(look->map, seg->x1) ; float y2 = MAP2GRAPH(look->map, seg->x2) ; if (y1 > mapGraphHeight || y2 < topMargin) return FALSE ; /* UGH..... */ box = graphBoxStart() ; if (y1 < topMargin) graphLine (*offset+2.0, topMargin, *offset+2.0, y2) ; else { graphLine (*offset+1.0, y1, *offset+2.0, y1) ; graphLine (*offset+2.0, y1, *offset+2.0, y2) ; } graphLine (*offset+1.0, y2, *offset+2.0, y2) ; } graphBoxEnd() ; graphBoxDraw(box, BLACK, TRANSPARENT) ; box_drawn = TRUE ; *box_out = box ; return box_drawn ; } /********************************************/ static void showSplices (FeatureMap look, SegType type, BoxCol *bc, float origin) { char *v ; int i, box, background ; SEG *seg ; float y=0, delta=0, x=0 ; /* delta: mieg: shows frame by altering the drawing of the arrow */ float fac; fac = bc->width / (bc->meth->maxScore - bc->meth->minScore); for (i = 0 ; i < arrayMax(look->segs) ; ++i) { seg = arrp(look->segs, i, SEG) ; if (seg->x1 > look->max || seg->x2 < look->min || (lexAliasOf(seg->key) != bc->meth->key) || seg->type != type) continue ; y = MAP2GRAPH(look->map, seg->x2) ; if (seg->data.f <= bc->meth->minScore) x = 0 ; else if (seg->data.f >= bc->meth->maxScore) x = bc->width ; else x = fac * (seg->data.f - bc->meth->minScore) ; box = graphBoxStart() ; if (x > origin + 0.5 || x < origin - 0.5) graphLine (bc->offset+origin, y, bc->offset+x, y) ; else if (x > origin) graphLine (bc->offset+origin-0.5, y, bc->offset+x, y) ; else graphLine (bc->offset+origin+0.5, y, bc->offset+x, y) ; switch (type) { case SPLICE5: delta = (look->flag & FLAG_REVERSE) ? -0.5 : 0.5 ; break ; case SPLICE3: delta = (look->flag & FLAG_REVERSE) ? 0.5 : -0.5 ; break ; default: messcrash ("Bad type %d in showSplices", type) ; } graphLine (bc->offset+x, y, bc->offset+x, y+delta) ; graphBoxEnd() ; v = SEG_HASH (seg) ; if (assFind (look->chosen, v, 0)) background = GREEN ; else if (assFind (look->antiChosen, v, 0)) background = LIGHTGREEN ; else background = TRANSPARENT ; switch (seg->x2 % 3) { case 0: graphBoxDraw (box, RED, background) ; break ; case 1: graphBoxDraw (box, BLUE, background) ; break ; case 2: graphBoxDraw (box, DARKGREEN, background) ; break ; } array(look->boxIndex, box, int) = i ; fMapBoxInfo (look, box, seg) ; graphBoxFreeMenu (box, fMapChooseMenuFunc, fMapChooseMenu) ; } return; } /* showSplices */ void fMapShowSplices (LOOK genericLook, float *offset, MENU *menu) /* This is of type MapColDrawFunc */ { FeatureMap look = (FeatureMap)genericLook; float x, y1, y2, origin ; BoxCol *bc ; bc = bcFromName (look, look->map->activeColName, menu) ; /* NB old default diff was 5 - now using bc system it is 1 */ if (!bcTestMag (bc, look->map->mag)) return ; bc->offset = *offset ; y1 = MAP2GRAPH(look->map,look->min) ; y2 = MAP2GRAPH(look->map,look->max) ; graphColor(LIGHTGRAY) ; x = *offset + 0.5 * bc->width ; graphLine (x, y1, x, y2) ; x = *offset + 0.75 * bc->width ; graphLine (x, y1, x, y2) ; graphColor(DARKGRAY) ; if (bc->meth->minScore < 0 && 0 < bc->meth->maxScore) origin = bc->width * (-bc->meth->minScore / (bc->meth->maxScore - bc->meth->minScore)) ; else origin = 0 ; graphLine (*offset + origin, y1, *offset + origin, y2) ; graphColor (BLACK) ; showSplices (look, SPLICE5, bc, origin) ; showSplices (look, SPLICE3, bc, origin) ; *offset += bc->width + 1 ; return; } /* fMapShowSplices */ /*************************************************/ void fMapShowCDSBoxes (LOOK genericLook, float *offset, MENU *unused) /* This is of type MapColDrawFunc */ { FeatureMap look = (FeatureMap)genericLook; int i ; SEG *seg ; float y1, y2 ; graphText ("Genes", *offset-1, topMargin+1.5) ; *offset += 2.5 ; graphLine (*offset, topMargin+2, *offset, mapGraphHeight-0.5) ; for (i = 1 ; i < arrayMax(look->segs) ; ++i) { seg = arrp(look->segs,i,SEG) ; if (seg->x1 > look->max || seg->x2 < look->min) continue ; y1 = MAP2GRAPH(look->map,seg->x1) ; y2 = MAP2GRAPH(look->map,seg->x2+1) ; /* to cover full base */ if (y1 < 2 + topMargin) y1 = 2 + topMargin ; if (y2 < 2 + topMargin) y2 = 2 + topMargin ; if (seg->type == CDS) graphFillRectangle (*offset, y1, *offset+1, y2) ; if (seg->type == CDS_UP) graphFillRectangle (*offset, y1, *offset-1, y2) ; } *offset += 2.5 ; return; } /* fMapShowCDSBoxes */ void fMapShowCDSLines (LOOK genericLook, float *offset, MENU *unused) /* This is of type MapColDrawFunc */ { FeatureMap look = (FeatureMap)genericLook; int i ; SEG *seg ; float y ; for (i = 1 ; i < arrayMax(look->segs) ; ++i) { seg = arrp(look->segs,i,SEG) ; if (seg->x1 > look->max || seg->x2 < look->min) continue ; y = 0.5 * (MAP2GRAPH(look->map,seg->x1) + MAP2GRAPH(look->map,seg->x2+1)) ; if (y < 2 + topMargin) y = 2 + topMargin ; if (seg->type == CDS || seg->type == CDS_UP) graphLine (*offset+1, y, *offset+3, y) ; } *offset += 5 ; return; } /* fMapShowCDSLines */ static void generalBump (FeatureMap look, float *offset, int width, KEY tag) { int i, box ; SEG *seg ; float y ; BUMP bump = bumpCreate (width, 0) ; bumpOff = *offset ; graphColor (BLACK) ; i = (look->flag & FLAG_REVERSE) ? arrayMax(look->segs)-1 : 1 ; while (i && i < arrayMax(look->segs)) { seg = arrp(look->segs,i,SEG) ; if (seg->x1 > look->max || seg->x2 < look->min) goto loop ; y = 0.5 * (MAP2GRAPH(look->map,seg->x1) + MAP2GRAPH(look->map,seg->x2+1)) ; if (y < 2 + topMargin) y = 2 + topMargin ; if (seg->type == VISIBLE && seg->data.k == tag) { box = graphBoxStart() ; bumpWrite (bump, name(seg->key),0,y) ; graphBoxEnd () ; array(look->boxIndex, box, int) = i ; fMapBoxInfo (look, box, seg) ; } loop: if (look->flag & FLAG_REVERSE) --i ; else ++i ; } *offset += bumpMax(bump) ; bumpDestroy (bump) ; return; } /* generalBump */ void fMapShowGeneNames (LOOK genericLook, float *offset, MENU *unused) /* This is of type MapColDrawFunc */ { FeatureMap look = (FeatureMap)genericLook; generalBump (look, offset, 6, _Locus) ; } void fMapShowBriefID (LOOK genericLook, float *offset, MENU *unused) /* This is of type MapColDrawFunc */ { FeatureMap look = (FeatureMap)genericLook; generalBump (look, offset, 50, _Brief_identification) ; } /****** code for fMapShowCanonical ******/ void keyZoneAdd (Array a, KEY key, float y1, float y2, int iseg) { int i ; KEYZONE *z ; for (i = 0 ; i < arrayMax(a) ; ++i) if ((z = arrp(a, i, KEYZONE))->key == key) return ; z = arrayp(a, arrayMax(a), KEYZONE) ; z->key = key ; z->y1 = y1 ; z->y2 = y2 ; z->iseg = iseg ; } int keyZoneOrder (void *va, void *vb) { KEYZONE *a = (KEYZONE*) va, *b = (KEYZONE*) vb ; return (a->y1 + a->y2 > b->y1 + b->y2) ? 1 : -1 ; } /* This is of type MapColDrawFunc. * Column "Sequences & ends", ususally over to the left, sequences are vertical * white bars which are stepped relative to one another, next to them are arrows * to show clone left/right ends. */ void fMapShowCanonical (LOOK genericLook, float *offset, MENU *menu) { FeatureMap look = (FeatureMap)genericLook; int i ; SEG *seg, *oldseg = 0 ; BOOL isDown ; int x, box ; float y1, y2, y ; BoxCol *bc; BUMP bump = bumpCreate (3, 0) ; Array a = arrayCreate (8, KEYZONE) ; bc = bcFromName (look, "FMAP_Sequences_and_ends", menu); /* fw: shouldn't we call bcTextMag ? */ bc->offset = *offset ; /* first the bars */ ++*offset ; i = (look->flag & FLAG_REVERSE) ? arrayMax(look->segs)-1 : 1 ; while (i && i < arrayMax(look->segs)) { seg = arrp(look->segs,i,SEG) ; if (seg->x1 > look->max || seg->x2 < look->min) goto loop1 ; y1 = MAP2GRAPH(look->map,seg->x1) ; y2 = MAP2GRAPH(look->map,seg->x2+1) ; /* to cover full base */ if (y1 < 2 + topMargin) y1 = 2 + topMargin ; if (y1 > mapGraphHeight) y1 = mapGraphHeight ; if (y2 < 2 + topMargin) y2 = 2 + topMargin ; if (y2 > mapGraphHeight) y2 = mapGraphHeight ; if (seg->type == SEQUENCE || seg->type == SEQUENCE_UP) { SEQINFO *sinf = arrp(look->seqInfo, seg->data.i, SEQINFO) ; if (sinf->flags & SEQ_CANONICAL) { x = 0 ; y = seg->x1 ; /* bump in DNA coords so OK reversed */ bumpItem (bump, 1, seg->x2-seg->x1+1, &x, &y) ; box = graphBoxStart() ; graphRectangle (*offset+x, y1, *offset+x+0.75, y2) ; graphBoxEnd() ; array(look->boxIndex, box, int) = i; fMapBoxInfo (look, box, seg) ; addVisibleInfo (look, i) ; if (bc->meth->isShowText) addVisibleInfo (look, i) ; keyZoneAdd (a, seg->key, y1, y2, i) ; } } loop1: if (look->flag & FLAG_REVERSE) --i ; else ++i ; } *offset += bumpMax(bump) ; bumpDestroy (bump) ; /* then the ends */ bump = bumpCreate (3, 0) ; /* determine isDown: rely on MASTER running Left->Right */ seg = arrp(look->segs, 0, SEG) ; isDown = (seg->x2 > seg->x1) ; if (look->flag & FLAG_REVERSE) isDown = !isDown ; if (look->flag & FLAG_COMPLEMENT) /* because Clone_*_end tags not flipped by fMapRC() */ isDown = !isDown ; i = (look->flag & FLAG_REVERSE) ? arrayMax(look->segs)-1 : 1 ; while (i && i < arrayMax(look->segs)) { seg = arrp(look->segs,i,SEG) ; if (seg->type != CLONE_END || seg->x1 > look->max || seg->x2 < look->min) goto loop2 ; if (oldseg && seg->key == oldseg->key && seg->x1 == oldseg->x1) goto loop2 ; oldseg = seg ; y = MAP2GRAPH(look->map,seg->x1) ; box = graphBoxStart() ; array(look->boxIndex, box, int) = i; graphLine (*offset, y, *offset+1, y) ; if ((seg->data.k == _Clone_left_end && isDown) || (seg->data.k == _Clone_right_end && !isDown)) { graphLine (*offset+0.5, y, *offset+0.5, y+2) ; graphLine (*offset, y+1, *offset+0.5, y+2) ; graphLine (*offset+1, y+1, *offset+0.5, y+2) ; } else { graphLine (*offset+0.5, y, *offset+0.5, y-2) ; graphLine (*offset, y-1, *offset+0.5, y-2) ; graphLine (*offset+1, y-1, *offset+0.5, y-2) ; } graphBoxEnd() ; fMapBoxInfo (look, box, seg) ; keyZoneAdd (a, seg->parent, y, y, i) ; loop2: if (look->flag & FLAG_REVERSE) --i ; else ++i ; } *offset += bumpMax(bump) + 1 ; bumpDestroy (bump) ; /* then the text next to the clones */ bump = bumpCreate (12, 0) ; bumpOff = *offset ; arraySort (a, keyZoneOrder) ; for (i = 0 ; i < arrayMax(a) ; ++i) { KEYZONE *z = arrp(a, i, KEYZONE) ; box = graphBoxStart() ; array(look->boxIndex,box,int) = z->iseg ; bumpWrite (bump, name(z->key), 0, 0.5*(z->y1 + z->y2)) ; graphBoxEnd() ; fMapBoxInfo (look, box, seg) ; } *offset += bumpMax (bump) ; bumpDestroy (bump) ; arrayDestroy (a) ; return; } /* fMapShowCanonical */ /***********************************************************************/ void fMapShowAssemblyTags (LOOK genericLook, float *offset, MENU *unused) /* This is of type MapColDrawFunc */ { FeatureMap look = (FeatureMap)genericLook; int i; SEG *seg ; float y1, y2 ; BUMP bump = bumpCreate (30, 0) ; /* first the bars */ ++*offset ; i = (look->flag & FLAG_REVERSE) ? arrayMax(look->segs)-1 : 1 ; while (i && i < arrayMax(look->segs)) { seg = arrp(look->segs,i,SEG) ; if (seg->x1 > look->max || seg->x2 < look->min) goto loop ; y1 = MAP2GRAPH(look->map,seg->x1) ; y2 = MAP2GRAPH(look->map,seg->x2+1) ; /* to cover full base */ if (y1 < 2 + topMargin) y1 = 2 + topMargin ; if (y2 < 2 + topMargin) y2 = 2 + topMargin ; if (seg->type == ASSEMBLY_TAG) { int box = graphBoxStart(); int x = 0 ; int color; unsigned char *c = (unsigned char *)seg->data.s; switch(c[0] ^ c[1] ^ c[2] ^ c[3]) { case 'a'^'n'^'n'^'o': color = BLACK; break; case 'c'^'o'^'m'^'m': color = BLUE; break; case 'o'^'l'^'i'^'g': color = YELLOW; break; case 'c'^'o'^'m'^'p': color = RED; break; case 's'^'t'^'o'^'p': color = RED; break; case 'r'^'e'^'p'^'e': color = GREEN; break; case 'c'^'o'^'s'^'m': color = LIGHTGRAY; break; case 'A'^'l'^'u'^' ': color = GREEN; break; case 'i'^'g'^'n'^'o': color = LIGHTGRAY; break; default: color = LIGHTBLUE; break; } y2 -= y1 ; bumpItem (bump, 1, y2, &x, &y1) ; graphRectangle (*offset+x, y1, *offset+x+0.8, y1+y2) ; graphBoxEnd(); fMapBoxInfo (look, box, seg) ; graphBoxDraw(box, BLACK, color); array(look->boxIndex, box, int) = i; } loop: if (look->flag & FLAG_REVERSE) --i ; else ++i ; } *offset += bumpMax (bump) ; bumpDestroy (bump) ; return; } /* fMapShowAssemblyTags */ /*******************************************/ void fMapShowcDNAs (LOOK genericLook, float *offset, MENU *unused) /* This is of type MapColDrawFunc */ { FeatureMap look = (FeatureMap)genericLook; int i ; SEG *seg ; int x ; float y ; BUMP bump = bumpCreate (3, 0) ; i = (look->flag & FLAG_REVERSE) ? arrayMax(look->segs)-1 : 1 ; while (i && i < arrayMax(look->segs)) { seg = arrp(look->segs,i,SEG) ; if (seg->x1 > look->max || seg->x2 < look->min) goto loop ; y = 0.5 * (MAP2GRAPH(look->map,seg->x1) + MAP2GRAPH(look->map,seg->x2+1)) ; if (y < 2 + topMargin) y = 2 + topMargin ; if (seg->type == VISIBLE && seg->data.k == _Matching_cDNA) { x = 0 ; bumpItem (bump, 1, 0.5, &x, &y) ; graphFillRectangle (*offset+x, y-0.25, *offset+x+0.8, y+0.25) ; } loop: if (look->flag & FLAG_REVERSE) --i ; else ++i ; } *offset += bumpMax (bump) ; bumpDestroy (bump) ; return; } /* fMapShowcDNAs */ /**********************************************/ static FREEOPT segOpts[] = { { 8, "User controllable segments" }, { SPLICE3, "SPLICE3" }, { SPLICE5, "SPLICE5" }, { FEATURE, "FEATURE" }, { HOMOL, "HOMOL" }, { SPLICE3_UP, "SPLICE3_UP" }, { SPLICE5_UP, "SPLICE5_UP" }, { FEATURE_UP, "FEATURE_UP" }, { HOMOL_UP, "HOMOL_UP" } } ; void fMapAddSegments (void) { static char dirName[DIR_BUFFER_SIZE] ="", fileName[FIL_BUFFER_SIZE]=""; static Associator seq2seg = 0 ; void *v ; int i, x1, x2, n, level, seqIndex ; float score ; SEG *seg, *seqSeg ; KEY seq, type ; FILE *fil ; char *word ; FeatureMap look = currentFeatureMap("fMapAddSegments") ; if (!(fil = filqueryopen (dirName, fileName, "useg","r", "File of new items: sequence x1 x2 type [score|text...]"))) return ; /* first delete temp segs */ arrayMax(look->segs) = look->lastTrueSeg ; /* make seq2seg */ seq2seg = assReCreate (seq2seg) ; for (i = 1, seg = arrp(look->segs, 1, SEG) ; i < arrayMax(look->segs) ; ++i, ++seg) if (seg->type == SEQUENCE || seg->type == SEQUENCE_UP) assInsert (seq2seg, assVoid(seg->key), assVoid(i)) ; n = 0 ; level = freesetfile (fil,0) ; while (freecard (level)) { if (messIsInterruptCalled()) break ; if (!(word = freeword())) continue ; if (!lexword2key (word, &seq, _VSequence)) { messout ("Can't find sequence %s line %d - F4 to interrupt", word, freestreamline(level)) ; continue ; } if (!assFind (seq2seg, assVoid(seq), &v)) continue ; seqIndex = assInt(v) ; if (!freeint (&x1) || !freeint (&x2) || !freekey (&type, segOpts)) { messout ("No coords then segtype line %d - F4 to interrupt", freestreamline(level)) ; continue ; } if (x1 > x2) { i = x1 ; x1 = x2 ; x2 = i ; if (type & 0x01) --type ; else ++type ; } seg = arrayp(look->segs, arrayMax(look->segs), SEG) ; seg->parent = 0 ; seqSeg = arrp(look->segs, seqIndex, SEG) ; if (seqSeg->type == SEQUENCE) { seg->x1 = seqSeg->x1 + x1 - 1 ; seg->x2 = seqSeg->x1 + x2 - 1 ; } else /* SEQUENCE_UP */ { seg->x1 = seqSeg->x2 - x2 + 1 ; seg->x2 = seqSeg->x2 - x1 + 1 ; if (type & 0x01) --type ; else ++type ; } seg->type = type ; ++n ; #define ABORT(z) { --arrayMax(look->segs) ; \ messout ("%s line %d - F4 to interrupt", z, freestreamline(level)) ; \ continue ; } switch (type) { case SPLICE3: case SPLICE3_UP: case SPLICE5: case SPLICE5_UP: case FEATURE: case FEATURE_UP: if (!(word = freeword())) ABORT("No method") ; if (lexaddkey (word, &seg->key, _VMethod)) messout ("Previously unknown method %s for FEATURE line %d", word, freestreamline(level)) ; methodCacheGetByName (look->mcache, word, /* simple defaults */ "Colour WHITE\n" "Right_priority 0\n" "Width 0.5\n", /* no diff yet */ ""); seg->data.f = freefloat(&score) ? score : 0.0 ; break ; case HOMOL: case HOMOL_UP: { HOMOLINFO *hinf ; seg->data.i = arrayMax(look->homolInfo) ; hinf = arrayp (look->homolInfo, seg->data.i, HOMOLINFO) ; if (!(word = freeword())) ABORT("No method for HOMOL") ; if (lexaddkey (word, &hinf->method, _VMethod)) messout ("Previously unknown method %s for HOMOL line %d", word, freestreamline(level)) ; methodCacheGetByName (look->mcache, word, /* simple defaults */ "Colour WHITE\n" "Right_priority 0\n" "Width 0.5\n", /* no diff yet */ ""); if (!freefloat(&hinf->score)) ABORT("No score for HOMOL") ; if (!(word = freeword())) ABORT("No sequence for HOMOL") ; lexaddkey (word, &seg->key, _VSequence) ; if (!freeint(&hinf->x1) || !freeint(&hinf->x2)) ABORT("No target coords for HOMOL") ; } break ; } } freeclose (level) ; messout ("Added %d new segments", n) ; arraySort (look->segs, fMapOrder) ; look->lastTrueSeg = arrayMax(look->segs) ; fMapProcessMethods (look) ; fMapDraw (look, 0) ; return; } /* fMapAddSegments */ void fMapClearSegments (void) { int i ; KEY method ; SEG *seg ; FeatureMap look = currentFeatureMap("fMapClearSegments") ; ACEIN name_in; BOOL found; name_in = messPrompt ("Give method of segment to clear", "", "wz", 0); if (!name_in) return; found = lexword2key (aceInWord(name_in), &method, _VMethod); aceInDestroy (name_in); if (!found) return ; /* first delete temp segs */ arrayMax(look->segs) = look->lastTrueSeg ; for (i = 1 ; i < arrayMax(look->segs) ; ) if ((seg = arrp(look->segs, i, SEG))->key == method) *seg = arr(look->segs, --arrayMax(look->segs), SEG) ; else ++i ; arraySort (look->segs, fMapOrder) ; look->lastTrueSeg = arrayMax(look->segs) ; fMapDraw (look, 0) ; return; } /* fMapClearSegments */ /************************************************************/ void fMapSwitchColBump(FeatureMap look) { int box = look->activeBox ; SEG* seg ; if (box >= arrayMax(look->boxIndex) || !(seg = BOXSEG(box))) { messerror("problem picking boxes in fMapSwitchColBump()") ; return ; } /* We need to be able to go from box -> seg -> method the first part is ok, * but going from seg to method is not straightforward...need to think about this * a bit..... */ seg = BOXSEG(look->activeBox) ; return ; } /************************************************************/ /******* generic "box" column - for homols, features ********/ /* checks before using a column */ static void bcCheck (BoxCol *bc) { METHOD* meth = bc->meth ; if (bc->look->map->isFrame && meth->flags & METHOD_FRAME_SENSITIVE) bc->isFrame = TRUE; else bc->isFrame = FALSE; if (meth->flags & METHOD_SCORE) { bc->mode = WIDTH ; /* n.b. default. */ if (meth->flags & METHOD_SCORE_BY_OFFSET && !bc->look->map->isFrame) bc->mode = OFFSET ; else if (meth->flags & METHOD_SCORE_BY_HIST) bc->mode = HIST ; /* checks to prevent arithmetic crash */ if (bc->mode == OFFSET) { if (!meth->minScore) meth->minScore = 1 ; } else { if (meth->maxScore == meth->minScore) meth->maxScore = meth->minScore + 1 ; } } else { /* none of the SCORE_BY_xxx flags set */ bc->mode = DEFAULT ; } if (meth->width) { if (bc->mode == WIDTH && meth->flags & METHOD_SCORE_BY_OFFSET && meth->width > 2) bc->width = 2 ; else bc->width = meth->width ; } else { /* the method doesn't set the width */ if (bc->mode == OFFSET) bc->width = 7 ; else bc->width = 2 ; } if (bc->mode == HIST) { /* normalise the BoxCol's histBase */ if (meth->minScore == meth->maxScore) bc->histBase = meth->minScore ; else bc->histBase = (meth->histBase - meth->minScore) / (meth->maxScore - meth->minScore) ; if (bc->histBase < 0) bc->histBase = 0 ; if (bc->histBase > 1) bc->histBase = 1 ; bc->fmax = (bc->width * bc->histBase) + 0.2 ; } else bc->fmax = 0 ; if (bc->bump) bumpDestroy (bc->bump); if (bc->cluster) assDestroy (bc->cluster); if (bc->overlap_mode == METHOD_OVERLAP_BUMPED) { bc->bump = bumpCreate (1000, 0); } else if (bc->overlap_mode == METHOD_OVERLAP_CLUSTER) { bc->cluster = assHandleCreate (bc->look->handle) ; bc->clusterCount = 0 ; } /* set the toggle_states in the bcMenu according to this BoxCol */ if (bc->overlap_mode == METHOD_OVERLAP_BUMPED) { menuUnsetFlags (menuItem(bc->menu, LABEL_OVERLAP), MENUFLAG_TOGGLE_STATE); menuSetFlags (menuItem(bc->menu, LABEL_BUMPABLE), MENUFLAG_TOGGLE_STATE); menuUnsetFlags (menuItem(bc->menu, LABEL_CLUSTER), MENUFLAG_TOGGLE_STATE); } if (bc->overlap_mode == METHOD_OVERLAP_CLUSTER) { menuUnsetFlags (menuItem(bc->menu, LABEL_OVERLAP), MENUFLAG_TOGGLE_STATE); menuUnsetFlags (menuItem(bc->menu, LABEL_BUMPABLE), MENUFLAG_TOGGLE_STATE); menuSetFlags (menuItem(bc->menu, LABEL_CLUSTER), MENUFLAG_TOGGLE_STATE); } else { menuSetFlags (menuItem(bc->menu, LABEL_OVERLAP), MENUFLAG_TOGGLE_STATE); menuUnsetFlags (menuItem(bc->menu, LABEL_BUMPABLE), MENUFLAG_TOGGLE_STATE); menuUnsetFlags (menuItem(bc->menu, LABEL_CLUSTER), MENUFLAG_TOGGLE_STATE); } switch (bc->mode) { case WIDTH: menuSetFlags (menuItem(bc->menu, LABEL_WIDTH), MENUFLAG_TOGGLE_STATE); menuUnsetFlags (menuItem(bc->menu, LABEL_OFFSET), MENUFLAG_TOGGLE_STATE); menuUnsetFlags (menuItem(bc->menu, LABEL_HIST), MENUFLAG_TOGGLE_STATE); break; case OFFSET: menuUnsetFlags (menuItem(bc->menu, LABEL_WIDTH), MENUFLAG_TOGGLE_STATE); menuSetFlags (menuItem(bc->menu, LABEL_OFFSET), MENUFLAG_TOGGLE_STATE); menuUnsetFlags (menuItem(bc->menu, LABEL_HIST), MENUFLAG_TOGGLE_STATE); break; case HIST: menuUnsetFlags (menuItem(bc->menu, LABEL_WIDTH), MENUFLAG_TOGGLE_STATE); menuUnsetFlags (menuItem(bc->menu, LABEL_OFFSET), MENUFLAG_TOGGLE_STATE); menuSetFlags (menuItem(bc->menu, LABEL_HIST), MENUFLAG_TOGGLE_STATE); break; case DEFAULT: /* all options off */ menuUnsetFlags (menuItem(bc->menu, LABEL_WIDTH), MENUFLAG_TOGGLE_STATE); menuUnsetFlags (menuItem(bc->menu, LABEL_OFFSET), MENUFLAG_TOGGLE_STATE); menuUnsetFlags (menuItem(bc->menu, LABEL_HIST), MENUFLAG_TOGGLE_STATE); break; } return; } /* bcCheck */ static void bcFinalise (void *block) { /* ?? how does the bc->menu get finalised ? ?? */ #ifdef ED_G_NEVER_INCLUDE_THIS_CODE BoxCol *bc = (BoxCol*)block; #endif /* ED_G_NEVER_INCLUDE_THIS_CODE */ /* What happened to the clean up ??? */ /* When does this all get cleaned up ?? When would be logical, when the */ /* fmap disappears ?? */ return; } /* bcFinalise */ /* We need to return the menu we build here because it will become a submenu */ /* in a cascading menu for all overlapping columns at one screen position. */ /* */ static BoxCol *bcFromName(FeatureMap look, char *name, MENU *menu_out) { int i ; BoxCol *bc ; MENUITEM menu_item; if (!look->bcDict) { look->bcDict = dictHandleCreate (64, look->handle) ; look->bcArray = arrayHandleCreate (64, BoxCol*, look->handle) ; } if (dictFind (look->bcDict, name, &i)) { bc = arr(look->bcArray,i,BoxCol*) ; } else { /* initialise from method */ bc = (BoxCol*) halloc (sizeof(BoxCol), look->handle) ; blockSetFinalise (bc, bcFinalise); dictAdd (look->bcDict, name, &i) ; array(look->bcArray,i,BoxCol*) = bc ; bc->look = look ; if (name[0] == '-') { bc->isDown = FALSE ; bc->meth = methodCacheGetByName(look->mcache, name+1, "", /* no aceText-defaults */ ""); /* no aceDiff-variation */ } else { bc->isDown = TRUE ; bc->meth = methodCacheGetByName(look->mcache, name, "", /* no aceText-defaults */ ""); /* no aceDiff-variation */ } if (bc->meth->flags & METHOD_BUMPABLE) bc->overlap_mode = METHOD_OVERLAP_BUMPED ; else if (bc->meth->flags & METHOD_CLUSTER) bc->overlap_mode = METHOD_OVERLAP_CLUSTER ; else bc->overlap_mode = METHOD_OVERLAP_COMPLETE ; /********************/ /* Create the menu */ bc->menu = menuCreate(name); menu_item = menuCreateItem ("Handle overlapping entries by:", NULL); menuSetFlags (menu_item, MENUFLAG_DISABLED); menuAddItem (bc->menu, menu_item, NULL); menu_item = menuCreateItem (LABEL_OVERLAP, bcMenuSetOverlap); menuSetPtr (menu_item, bc); menuSetFlags (menu_item, MENUFLAG_TOGGLE); menuAddItem (bc->menu, menu_item, NULL); menu_item = menuCreateItem (LABEL_BUMPABLE, bcMenuSetBump); menuSetPtr (menu_item, bc); menuSetFlags (menu_item, MENUFLAG_TOGGLE); menuAddItem (bc->menu, menu_item, NULL); menu_item = menuCreateItem (LABEL_CLUSTER, bcMenuSetCluster); menuSetPtr (menu_item, bc); menuSetFlags (menu_item, MENUFLAG_TOGGLE); menuAddItem (bc->menu, menu_item, NULL); menu_item = menuCreateItem ("Show score by:", NULL); menuSetFlags (menu_item, MENUFLAG_DISABLED); menuAddItem (bc->menu, menu_item, NULL); menu_item = menuCreateItem (LABEL_WIDTH, bcMenuSetWidth); menuSetPtr (menu_item, bc); menuSetFlags (menu_item, MENUFLAG_TOGGLE); menuAddItem (bc->menu, menu_item, NULL); menu_item = menuCreateItem (LABEL_OFFSET, bcMenuSetOffset); menuSetPtr (menu_item, bc); menuSetFlags (menu_item, MENUFLAG_TOGGLE); menuAddItem (bc->menu, menu_item, NULL); menu_item = menuCreateItem (LABEL_HIST, bcMenuSetHist); menuSetPtr (menu_item, bc); menuSetFlags (menu_item, MENUFLAG_TOGGLE); menuAddItem (bc->menu, menu_item, NULL); menu_item = menuCreateItem ("", NULL); menuSetFlags (menu_item, MENUFLAG_SPACER); menuAddItem (bc->menu, menu_item, NULL); menu_item = menuCreateItem ("Switch off column", bcMenuDeleteMapColumn); menuSetPtr (menu_item, name); menuAddItem (bc->menu, menu_item, NULL); } /* run consistency checks - establish valid modes/flags */ bcCheck (bc) ; /* Return the menu for this column. */ *menu_out = bc->menu ; return bc ; } /* bcFromName */ static BOOL bcTestMag (BoxCol *bc, float mag) { if (mag < 0) mag = -mag ; mag = 1.0 / mag ; if (bc->meth->minMag && mag < bc->meth->minMag) return FALSE ; if (bc->meth->maxMag && mag > bc->meth->maxMag) return FALSE ; return TRUE ; } /* bcTestMag */ static int bcDrawBox (BoxCol *bc, SEG *seg, float score, Array gaps) { int box, xoff ; float x1 = 0, x2 = 0, y1 = 0, y2 = 0, dx = 0 ; float numerator, denominator ; double logdeux = log((double)2.0) ; if (seg->x1 < bc->look->min) y1 = MAP2GRAPH(bc->look->map, bc->look->min) ; else y1 = MAP2GRAPH(bc->look->map, seg->x1) ; if (seg->x2+1 > bc->look->max) y2 = MAP2GRAPH(bc->look->map, bc->look->max) ; else y2 = MAP2GRAPH(bc->look->map, seg->x2+1) ; if (y1 >= mapGraphHeight || y2 <= topMargin) return 0 ; /* Calculate the box size according to the style of column the * user has selected. */ box = graphBoxStart() ; numerator = score - bc->meth->minScore ; denominator = bc->meth->maxScore - bc->meth->minScore ; switch (bc->mode) { case OFFSET: if (denominator == 0) /* catch div by zero */ { if (numerator < 0) dx = 0.8 ; else if (numerator > 0) dx = 3 ; } else { dx = 1 + (((float)numerator)/ ((float)(denominator))) ; } if (dx < .8) dx = .8 ; if (dx > 3) dx = 3 ; /* allow some leeway & catch dx == 0 */ dx = bc->width * log((double)dx)/logdeux ; x1 = bc->offset + dx ; x2 = bc->offset + dx + .9 ; if (bc->fmax < dx + 1.5) bc->fmax = dx + 1.5 ; break ; case HIST: if (denominator == 0) /* catch div by zero */ { if (numerator < 0) dx = 0 ; else if (numerator > 1) dx = 1 ; } else { dx = numerator / denominator ; if (dx < 0) dx = 0 ; if (dx > 1) dx = 1 ; } x1 = bc->offset + (bc->width * bc->histBase) ; x2 = bc->offset + (bc->width * dx) ; if (bc->fmax < bc->width*dx) bc->fmax = bc->width*dx ; break ; case WIDTH: if (denominator == 0) /* catch div by zero */ { if (numerator < 0) dx = 0.25 ; else if (numerator > 0) dx = 1 ; } else { dx = 0.25 + ((0.75 * numerator) / denominator) ; } if (dx < 0.25) dx = 0.25 ; if (dx > 1) dx = 1 ; /* !WARNING! fall-through */ case DEFAULT: if (bc->mode == DEFAULT) dx = 0.75 ; xoff = 1 ; if (bc->bump) { if (bc->look->map->mag < 0) { y1 = -y1 ; y2 = -y2 ; bumpItem (bc->bump, 2, (y2-y1), &xoff, &y1) ; y1 = -y1 ; y2 = -y2 ; } else bumpItem (bc->bump, 2, (y2-y1), &xoff, &y1) ; } else if (bc->cluster) /* one subcolumn per key */ { void *v ; BOOL two_parent = seg->flags & SEGFLAG_TWO_PARENT_CLUSTER ; #ifdef ED_G_NEVER_INCLUDE_THIS_CODE /* Need to add code to retrieve other parent key and hash two keys together. */ if (assFind (bc->cluster, assVoid(seg->parent), &v)) xoff = assInt(v) ; #endif /* ED_G_NEVER_INCLUDE_THIS_CODE */ if (assFind (bc->cluster, assVoid(seg->parent), &v)) xoff = assInt(v) ; else { xoff = ++bc->clusterCount ; assInsert (bc->cluster, assVoid(seg->parent), assVoid(xoff)) ; } } x1 = bc->offset + (0.5 * bc->width * (xoff - dx)) ; x2 = bc->offset + (0.5 * bc->width * (xoff + dx)) ; if (bc->fmax < 0.5*bc->width*(xoff+1)) bc->fmax = 0.5*bc->width*(xoff+1) ; break ; default: messcrash("Unknown bc->mode in bcDrawBox(): %d", bc->mode) ; } /* OK, now draw the homology line/box/gapped box. */ if (seg->type == HOMOL_GAP || seg->type == HOMOL_GAP_UP) { /* Some homol lines are drawn dashed (e.g. between EST read pairs), note * that because the homol line box only has a line drawn in, we have to * artificially set its width to make it clickable. */ BOOL change_line_style = seg->flags & SEGFLAG_LINE_DASHED ; GraphLineStyle prev_style ; float mid_x, width ; float left, right ; if (change_line_style) prev_style = graphLineStyle(GRAPH_LINE_DASHED) ; mid_x = (x1 + x2) * 0.5 ; graphLine(mid_x, y1, mid_x, y2) ; if (change_line_style) graphLineStyle(prev_style) ; width = (x2 - x1) * 0.25 ; left = (mid_x - width) ; right = (mid_x + width) ; graphBoxSetDim(box, &left, NULL, &right, NULL) ; } else { if (gaps) drawInterruptedRectangle(bc->look, gaps, x1, y1, x2, y2) ; else graphRectangle(x1, y1, x2, y2) ; } graphBoxEnd() ; if (seg->type == HOMOL_GAP || seg->type == HOMOL_GAP_UP) graphBoxDraw (box, bc->meth->colour, WHITE) ; else graphBoxDraw (box, BLACK, bc->meth->colour) ; fMapBoxInfo (bc->look, box, seg) ; return box ; } /* bcDrawBox */ /************************************************************ **************** BoxCol menu functions ********************* ************************************************************/ static void bcMenuSetOverlap (MENUITEM menu_item) { BoxCol *bc = (BoxCol*)menuGetPtr (menu_item); bc->overlap_mode = METHOD_OVERLAP_COMPLETE ; if (bc->look->redrawColumns) fMapDraw (bc->look, 0) ; return; } /* bcMenuSetOverlap */ static void bcMenuSetBump (MENUITEM menu_item) { BoxCol *bc = (BoxCol*)menuGetPtr (menu_item); bc->overlap_mode = METHOD_OVERLAP_BUMPED ; if (bc->look->redrawColumns) fMapDraw (bc->look, 0) ; return; } /* bcMenuSetBump */ static void bcMenuSetCluster (MENUITEM menu_item) { BoxCol *bc = (BoxCol*)menuGetPtr (menu_item); bc->overlap_mode = METHOD_OVERLAP_CLUSTER ; if (bc->look->redrawColumns) fMapDraw (bc->look, 0) ; return; } /* bcMenuSetCluster */ static void bcMenuSetWidth (MENUITEM menu_item) { BoxCol *bc = (BoxCol*)menuGetPtr (menu_item); bc->meth->flags ^= METHOD_SCORE_BY_WIDTH; /* toggle flag */ bc->meth->flags &= ~METHOD_SCORE_BY_OFFSET; /* unset flag */ bc->meth->flags &= ~METHOD_SCORE_BY_HIST; /* unset flag */ bc->mode = WIDTH; if (bc->look->redrawColumns) fMapDraw (bc->look, 0) ; return; } /* bcMenuSetWidth */ static void bcMenuSetOffset (MENUITEM menu_item) { BoxCol *bc = (BoxCol*)menuGetPtr (menu_item); bc->meth->flags &= ~METHOD_SCORE_BY_WIDTH; /* unset flag */ bc->meth->flags ^= METHOD_SCORE_BY_OFFSET; /* toggle flag */ bc->meth->flags &= ~METHOD_SCORE_BY_HIST; /* unset flag */ bc->mode = OFFSET; if (bc->look->redrawColumns) fMapDraw (bc->look, 0) ; return; } /* bcMenuSetOffset */ static void bcMenuSetHist (MENUITEM menu_item) { BoxCol *bc = (BoxCol*)menuGetPtr (menu_item); bc->meth->flags &= ~METHOD_SCORE_BY_WIDTH; /* unset flag */ bc->meth->flags &= ~METHOD_SCORE_BY_OFFSET; /* unset flag */ bc->meth->flags ^= METHOD_SCORE_BY_HIST; /* toggle flag */ bc->mode = HIST; if (bc->look->redrawColumns) fMapDraw (bc->look, 0) ; return; } /* bcMenuSetHist */ static void bcMenuDeleteMapColumn (MENUITEM menu_item) { char *column_name = (char*)menuGetPtr(menu_item); FeatureMap look = currentFeatureMap("bcMenuDeleteMapColumn"); mapColSetByName (look->map, column_name, MAPCOL_OFF) ; if (look->redrawColumns) fMapDraw (look, 0) ; return; } /* bcMenuDeleteMapColumn */ /* BLIXEM routines */ /* */ /* Whether the blixem call is internal or external the user may have set */ /* preferences to use pfetch instead of efetch from blixem. */ /* Returns TRUE and a pointer to a filled in PfetchParams struct if pfetch */ /* is required, FALSE otherwise. */ /* NOTE: caller must free "out" using messfree(). */ /* */ static BOOL blixemGetPfetchParams(STORE_HANDLE handle, PfetchParams **out) { BOOL result = FALSE ; PfetchParams *params = NULL ; if ((result = prefValue(BLIXEM_PFETCH))) { params = (PfetchParams *)halloc(sizeof(PfetchParams), handle) ; params->net_id = prefString(BLIXEM_NETID) ; params->port = prefInt(BLIXEM_PORT_NUMBER) ; *out = params ; } return result ; } /* Has the user chosen to use blixem as an external program ? */ /* */ static BOOL blixemIsExternal(void) { BOOL result = FALSE ; result = prefValue("BLIXEM_EXTERNAL") ; return result ; } /* Call blixem as a stand alone external program. * The args to this program are identical to the synchronous call to blxview, * we convert the data into the input file formats that the standalone * blixem expects and then call it using the system() call but with an "&" * so that we don't wait. NOTE that this means that we have NO idea whether * blixem works, we can only tell that the shell started successfully. */ static void blixemCallExternal(char *seq, char *seqname, int start, int offset, MSP *msp, char *opts, PfetchParams *pfetch_params) { STORE_HANDLE handle = NULL ; BOOL status = TRUE ; char *script = NULL ; char *subdir = NULL ; ACETMP fasta_sequence = NULL, exblx_data = NULL, seqbl_data = NULL ; char *fasta_file = NULL, *exblx_file = NULL , *seqbl_file = NULL ; ACEOUT fasta_out = NULL, exblx_out = NULL, seqbl_out = NULL ; BOOL seqbl_written_to = FALSE ; handle = handleCreate() ; /* Can we find the cover script for blixem ? */ script = prefString("BLIXEM_SCRIPT") ; if (strcmp(script, "") == 0) script = dbPathFilName(WSCRIPTS, "blixem_standalone", "", "x", handle) ; if (!script) { messout("Could not find the script to launch blixem: %s", script); status = FALSE ; } /* Create some tmp files which will receive the input data that blixem */ /* needs to do its stuff. */ if (status) { subdir = hprintf(handle, "%s_ACEDB_BLIXEM", getLogin(TRUE)) ; } if (status) { fasta_sequence = aceTmpCreateDir(subdir, "w", handle) ; if (fasta_sequence) { aceTmpNoRemove(fasta_sequence, TRUE) ; fasta_file = aceTmpGetFileName(fasta_sequence) ; fasta_out = aceTmpGetOutput(fasta_sequence) ; } else { messerror("Could not create temporary file for Blixem Fasta sequence.") ; status = FALSE ; } } if (status) { exblx_data = aceTmpCreateDir(subdir, "w", handle) ; if (exblx_data) { aceTmpNoRemove(exblx_data, TRUE) ; exblx_file = aceTmpGetFileName(exblx_data) ; exblx_out = aceTmpGetOutput(exblx_data) ; } else { messerror("Could not create temporary file for Blixem MSP/exblx data.") ; status = FALSE ; } } if (status) { seqbl_data = aceTmpCreateDir(subdir, "w", handle) ; if (seqbl_data) { aceTmpNoRemove(seqbl_data, TRUE) ; seqbl_file = aceTmpGetFileName(seqbl_data) ; seqbl_out = aceTmpGetOutput(seqbl_data) ; } else { messerror("Could not create temporary file for Blixem MSP/seqbl data.") ; status = FALSE ; } } /* Write out the sequence to the Fasta file. */ if (status) { if (!dnaRawDumpFastA(seqname, seq, fasta_out)) messerror("Could not write to blixem input sequence file: %s", fasta_file) ; } /* Write out the MSPCrunch exblx and seqbl format files. */ if (status) { if (aceOutPrint(exblx_out, "%s\n%s%c\n", "# exblx", "# blast", *opts) != ESUCCESS) status = FALSE ; if (aceOutPrint(seqbl_out, "%s\n%s%c\n", "# seqbl", "# blast", *opts) != ESUCCESS) status = FALSE ; /* If we already have the sequence data for the homology from acedb */ /* then write the data to a seqbl file, otherwise write it to an exblx */ /* file. */ if (status) { for ( ; msp && status ; msp = msp->next) { ACEOUT out; char *seqstring; if (msp->sseq) { out = seqbl_out; seqstring = msp->sseq; seqbl_written_to = TRUE ; } else { out = exblx_out; seqstring = msp->desc ? msp->desc : ""; } if (aceOutPrint(out, "%d %s\t%d\t%d\t%d\t%d %s %s", msp->score, msp->qframe, msp->qstart, msp->qend, msp->sstart, msp->send, msp->sname, seqstring) != ESUCCESS) status = FALSE ; if (status) { /* If there are gaps, tack them on the end of the sequence. */ if (msp->gaps) { int i ; for (i = 0 ; status && i < arrayMax(msp->gaps) ; i++) { SMapMap *m = arrp(msp->gaps, i, SMapMap); if (aceOutPrint(out, " %d %d %d %d", m->s1, m->s2, m->r1, m->r2) != ESUCCESS) status = FALSE ; } } } if (status) { if (aceOutPrint(out, "\n") != ESUCCESS) status = FALSE ; } } } if (!status) messerror("Could not write to one or both of blixem data files: %s, %s", exblx_file, seqbl_file) ; } /* Close the files to make sure they are ready for the blixem process to */ /* read. */ if (status) { aceTmpClose(fasta_sequence) ; aceTmpClose(exblx_data) ; aceTmpClose(seqbl_data) ; /* If no data written to seqbl file make sure it will be removed when */ /* we finish. */ if (!seqbl_written_to) aceTmpNoRemove(seqbl_data, FALSE) ; } /* Construct the command line and start up blixem, NOTE that by appending * an "&" we do not find out if the blixem worked, only that it was * forked off successfully. */ if (status) { char *cmd_string = NULL ; char *pfetch_arg = NULL ; if (pfetch_params) { pfetch_arg = hprintf(handle, "-P %s:%d ", pfetch_params->net_id, pfetch_params->port) ; } cmd_string = hprintf(handle, "%s-r -S %d -O %d -o \"%s\" %s %s %s %s &", (pfetch_arg ? pfetch_arg : ""), start, offset, opts, (seqbl_written_to ? "-x" : ""), (seqbl_written_to ? seqbl_file : ""), fasta_file, exblx_file) ; if (callScript(script, cmd_string) != 0) messerror("Could not start blixem, check that %s exists and is executable by you.", script) ; } /* Clean up. */ handleDestroy(handle) ; return ; } /********************/ /* This duplicates a function in peptide.c, they should be amalgamated into one in a new * fasta.c file.... */ static void translationTitle (ACEOUT fo, KEY seq) { OBJ obj = bsCreate (seq) ; KEY key ; aceOutPrint (fo, ">%s", name(seq)) ; if (obj) { if (bsGetKey (obj, _Locus, &key)) aceOutPrint (fo, " %s:", name(key)) ; if (bsGetKey (obj, _Brief_identification, &key)) aceOutPrint (fo, " %s", name(key)) ; if (bsFindTag (obj, _Start_not_found)) aceOutPrint (fo, " (start missing)") ; if (bsFindTag (obj, _End_not_found)) aceOutPrint (fo, " (end missing)") ; bsDestroy (obj) ; } else messerror ("Missing object for %s in translationTitle", name(seq)) ; aceOutPrint (fo, "\n") ; return; } static void pfetchWindow (KEY key) { ACEIN pipe; char cmd[50+1] = "pfetch"; char title[50+1]; char *lineBuf, *textBuf; STORE_HANDLE handle = handleCreate(); sprintf(cmd, "pfetch -F '%s' &", name(key)); sprintf(title, "pfetch: %s", name(key)); pipe = aceInCreateFromPipe(cmd, "r", NULL, handle); if (pipe) { textBuf = strnew("", handle); aceInSpecial(pipe, "\n\t"); while ((lineBuf = aceInCard(pipe))) textBuf = g_strconcat(textBuf,"\n", lineBuf, NULL); /* call gexTextEditor with the pfetch output & no buttons */ gexTextEditorNew(title, textBuf, 0, NULL, NULL, /* editorOK */ NULL, /* editorCancel */ FALSE /* make window readonly */ ); } handleDestroy(handle); } /********************** end of file **************************/