/* File: sprdmap.c * Author: Jean Thierry-Mieg (mieg@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: ** The aim of this tool is to display on a unique graph as many ** system of maps as control by sprdctrl.c * Exported functions: * HISTORY: * Last edited: May 6 10:22 2003 (edgrif) * * Feb 8 16:45 1999 (edgrif): Remove use of graph internals in myMapPrint() * * Oct 15 16:44 1998 (edgrif): Change names of MAP2GRAPH & GRAPH2MAP * as they clash with the graph headers versions. * Created: Wed May 27 11:40:21 1992 (mieg) * CVS info: $Id: multimapdisp.c,v 1.11 2003/05/06 13:13:12 edgrif Exp $ *------------------------------------------------------------------- */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include BITSET_MAKE_BITFIELD /* define bitField for bitset.h ops */ /************************************************************/ typedef struct MapColumnStruct MapColumn; typedef struct SegStruct SEG; struct MapColumnStruct { char type; BOOL isMappable; BOOL isFlipMap; float mag, centre, min, max; Array segs , segps ; /* segps are used to reorder the segs without loosing the friend info */ int subTitleBox; int mapColBox; BUMP bump ; } ; struct SegStruct { KEY key ; int line ; MapColumn *mcol; int x, xs ; float y, ys ; int flag ; SEG *friends ; /* Loop of related segs */ int ibox ; KEY parent, grandParent ; } ; typedef struct { SEG* seg ; /* pointer OK: segs fixed when drawing */ int color ; float xs, ys ; } BOX ; static magic_t MultiMap_MAGIC = "MultiMap"; typedef struct MultiMapStruct { magic_t *magic; Graph graph, parentGraph; TABLE *table; char *title; BOOL zoomAll ; Array mapColumns; /* of type MapColumn */ MapColumn *activeMapColumn ; int activeColBox ; Array mapBoxes ; int cursorBox , chromoBox , allButton ; } *MultiMap; static int nx, ny ; /* window dimensions */ static float yCentre ; /* ny/2 */ static float yLength ; /* length of picture */ static float topMargin = 6 ; /* space at top for buttons etc */ static float bottomMargin = 1 ; /* space at bottom */ static float xCursor = 5 ; /* midline of mini-chromosome */ static float xScale = 10 ; /* scale bar text LHS */ static float symbolSize_L = 3.0 ; /* size of little squares */ static BOOL isPapDisp = FALSE ; #define SPRDMAP2GRAPH(mcol, x) \ (yCentre + mcol->mag * ((float)(x) - mcol->centre)) #define SPRDGRAPH2MAP(c,x) \ (((x) - yCentre) / mcol->mag + c->centre) #define MAP2CHROM(x) \ (topMargin + yLength * (x - mcol->min) / (mcol->max != mcol->min ? mcol->max - mcol->min : 1 )) #define FLAG_HIGHLIGHT 1 /* not implemented yet */ #define FLAG_INSITU 2 #define FLAG_NAME 4 /************************************************************/ /* p1, p2 are used for contigs: multiMap <-> pmap for in_situ data for in_situ clones */ static void multiMapDisplayDestroy (void); static void multiMapDraw (MultiMap mmdisp); static MultiMap currentMultiMap (char *caller); static void multiMapPick (int box, double x , double y, int modifier_unused) ; static void multiMapDragCursor (float *x, float *y, BOOL isDone) ; static void multiMapMiddleDown (double x, double y) ; static void multiMapMiddleDrag (double x, double y) ; static void multiMapMiddleUp (double x, double y) ; static void multiMapConvert (MultiMap mmdisp) ; static void multiMapDrawKey (MultiMap mmdisp, KEY key) ; static void multiMapResize (void) ; static void multiMapSelect (MultiMap mmdisp, int box) ; static void multiMapFollow (MultiMap mmdisp, double x, double y) ; static void multiMapChangeSymbolSize (void) ; static void drawChromosomeBox (MultiMap mmdisp) ; static void multiMapWhole (void) ; static void multiMapZoomIn (void); static void multiMapZoomOut (void); static void multiMapZoomAll (void); static void multiMapFlip (void); static void multiMapClear (void); static void myMapPrint(void) ; static Array multiMapFindLimits(TABLE *table, Array isFlipMapArray); /************************************************************/ static MENUOPT multiMapMenu[] = { {graphDestroy, "Quit"}, {help, "Help"}, {graphPrint, "Print Screen"}, {myMapPrint, "Print Whole Map"}, {menuSpacer, ""}, {displayPreserve, "Preserve"}, {multiMapChangeSymbolSize, "Symbol size"}, {0, 0} } ; static MENUOPT buttonOpts[] = { {multiMapWhole, "Whole"}, {multiMapZoomIn, "Zoom In"}, {multiMapZoomOut, "Zoom Out"}, {multiMapClear, "Clear"}, {multiMapFlip, "Flip"}, {0, 0} } ; /************************************************************/ /* * DisplayFunc for _VMultiMap objects */ BOOL multiMapDisplay (KEY key, KEY from, BOOL isOldGraph, void *unused) { OBJ obj ; KEY map, anchor = 0 , anchor_group; int n = 0 , cl, minMap = 2 ; KEYSET ks ; char *cp ; BOOL isSuccess; if (key == KEY_UNDEFINED || class(key) != _VMultiMap || !(obj = bsCreate(key))) { return FALSE ; } ks = keySetCreate(); bsGetData(obj, _Min, _Int, &minMap) ; if (minMap <1) minMap = 1 ; if (bsGetKey(obj, _Map, &map)) do { keySet(ks, n++) = map ; } while (bsGetKey(obj, _bsDown, &map)) ; if (minMap >n) minMap = n ; if (bsGetData (obj, _Anchor, _Text, &cp) && (cl = pickWord2Class (cp)) && bsGetData (obj, _bsRight, _Text, &cp) && lexword2key (cp, &anchor_group, _VSystem) && bsGetData (obj, _bsRight, _Text, &cp) && lexword2key (cp, &anchor, _VSystem)) ; else { cl = 0 ; anchor = 0 ; anchor_group = 0 ; } bsDestroy(obj) ; isSuccess = multiMapDisplayKeySet (name(key), ks, cl, anchor_group, anchor, minMap); keySetDestroy (ks); /* is this correct here ? */ return isSuccess; } /* multiMapDisplay */ /************************************************************/ BOOL multiMapDisplayKeySet (char *title, KEYSET ks, int cl, KEY anchor_group, KEY anchor, int minMap) /* also called from keySetDisplay */ { OBJ obj ; Stack s = 0 ; KEYSET loci = 0 , loci1 = 0 ; Array aa = 0; Array flipped ; int i, j, n = 0 ; SPREAD spread; TABLE *table; char *tableTitle; aa = arrayCreate(100, BSunit) ; loci = keySetCreate() ; n = 0 ; flipped = arrayCreate(12, BOOL) ; /* this may take very long, * but when it does the user has probably chosen the wrong keyset */ messStatus ("Multimap, F4 to interrupt..."); for (i = 0; i < keySetMax(ks); i++) { if (messIsInterruptCalled()) { messout("Multimap interrupted...\n" "Processed %d out of %d possible objects", i, keySetMax(ks)); break; } if ((obj = bsCreate(keySet(ks, i)))) { arrayMax(aa) = 0 ; if (bsFindTag(obj, _Contains) && bsFlatten(obj, 2, aa)) for (j = 1 ; j < arrayMax(aa); j += 2) keySet(loci, n++) = arr(aa, j, BSunit).k ; if (bsFindTag(obj, _Flipped)) array(flipped,i,BOOL) = TRUE ; bsDestroy(obj) ; } } if (keySetMax(loci) == 0) { messout("Objects do not contain loci\n" "Unable to make a multi-map !"); return FALSE; } keySetSort(loci) ; keySetCompress(loci) ; s = stackCreate(100) ; if (!anchor) { /*************** Multi-map ***************/ loci1 = loci ; loci = query(loci1, "COUNT Map >= 1") ; if (ks) { pushText(s,"Title \"") ; catText(s, "Multi-map") ; if (title) { catText (s, " ") ; catText (s, title) ; } catText (s, "\"\n\n") ; catText(s,"Colonne 1\n" "Subtitle Locus\n" "Width 12\nVisible\nClass Locus\n"); catText(s,messprintf("Condition COUNT Map >= %d\n\n", minMap)) ; for (i = 0; i < keySetMax(ks) ; i++) { catText(s, "Colonne ") ; catText(s, messprintf("%d\n", i + 2)) ; catText(s, messprintf("Subtitle %s\n", name(keySet(ks,i)))) ; catText(s, "Float\nFrom 1\nTag Map = \"") ; catText(s, name(keySet(ks,i))) ; catText(s, "\"") ; catText(s," # Position") ; catText(s," \nVisible \nOptional") ; if (array(flipped,i,BOOL)) catText(s,"\nFlipMap") ; catText(s, "\n\n") ; } } } else { /***************** Homology-map ****************/ loci1 = loci ; loci = query(loci1, messprintf(">%s", name(anchor_group))) ; if (ks) { pushText(s,"Title \"") ; catText(s, "Homology-map") ; if (title) { catText (s, " ") ; catText (s, title) ; } catText (s, "\"\n\n") ; catText(s,"Colonne 1\n" "Subtitle "); catText (s, pickClass2Word (cl)) ; catText(s, "\n" "Width 12 \nVisible \nClass ") ; catText (s, pickClass2Word (cl)) ; catText (s, "\n") ; for (i = 0; i < keySetMax(ks) ; i++) { catText(s, "Colonne ") ; catText(s, messprintf("%d\n", 2*i + 2)) ; catText(s, messprintf("Subtitle Locus on %s\n", name(keySet(ks,i)))) ; catText(s,"Class ") ; catText (s, pickClass2Word (cl)) ; catText (s, " \nFrom 1 \nTag ") ; catText (s, freeprotect(name (anchor))) ; catText (s, "\n ") ; catText(s,"Condition Map = ") ; catText(s, freeprotect(name(keySet(ks,i)))) ; catText(s,"\n") ; catText(s," \nVisible \nOptional") ; catText(s, "\n\n") ; catText(s, "Colonne ") ; catText(s, messprintf("%d\n", 2*i + 3)) ; catText(s, messprintf("Subtitle %s\n", name(keySet(ks,i)))) ; catText(s,messprintf("Float\n From %d \n Tag Map = ", 2*i + 2)) ; catText(s,freeprotect(name(keySet(ks,i)))) ; catText(s," # Position \n") ; catText(s,"Visible \nOptional") ; if (array(flipped,i,BOOL)) catText(s,"\nFlipMap") ; catText(s, "\n\n") ; } } } /********** display data and multi-map for these definitions ********/ /* parse definition Stack */ spread = spreadCreateFromStack (s, NULL); table = spreadCalculateOverKeySet (spread, loci, NULL); tableTitle = spreadGetTitle (spread); /* display results */ tableDisplayCreate (table, tableTitle, flipped, 0) ; multiMapDisplayCreate (table, tableTitle, flipped) ; /******** clean up ********/ spreadDestroy (spread); keySetDestroy(loci) ; if (keySetExists(loci1)) keySetDestroy(loci1) ; arrayDestroy(aa) ; arrayDestroy (flipped); stackDestroy(s) ; /* NOTE, do -NOT- destroy ks, it belongs to caller * (e.g. keysetdisplay) */ return TRUE ; } /* multiMapDisplayKeySet */ /************************************************************/ Graph multiMapDisplayCreate (TABLE *table, char *title, Array isFlipMapArray) { MultiMap mmdisp; Array mapColumns; Graph oldGraph = graphActive(); mapColumns = multiMapFindLimits(table, isFlipMapArray); if (!mapColumns) { messout("No visible numerical column in this spread sheet") ; return -1 ; } mmdisp = (MultiMap)messalloc(sizeof(struct MultiMapStruct)); mmdisp->magic = &MultiMap_MAGIC; mmdisp->graph = displayCreate("DtMULTIMAP"); mmdisp->table = tableCopy(table, 0); mmdisp->title = strnew(title, 0); mmdisp->mapColumns = mapColumns; mmdisp->parentGraph = oldGraph; mmdisp->zoomAll = TRUE ; /* default for help, if undef in displays.wrm */ if (graphHelp(0) == NULL) graphHelp("Multi_Map"); graphMenu (multiMapMenu) ; graphAssociate (&MultiMap_MAGIC, mmdisp) ; graphRegister (DESTROY, multiMapDisplayDestroy); graphRegister (RESIZE, multiMapResize) ; graphRegister (PICK, multiMapPick) ; graphRegister (MIDDLE_DOWN, multiMapMiddleDown) ; graphRegister (MIDDLE_DRAG, multiMapMiddleDrag) ; graphRegister (MIDDLE_UP, multiMapMiddleUp) ; multiMapDraw (mmdisp); return mmdisp->graph; } /* multiMapDisplayCreate */ void multiMapDisplayReCreate (TABLE *table, char *title, Array isFlipMapArray) { MultiMap mmdisp = currentMultiMap("multiMapDisplayReCreate"); Array mapColumns; mapColumns = multiMapFindLimits(table, isFlipMapArray); if (!mapColumns) { messout("No visible numerical column in this spread sheet") ; return ; } messfree(mmdisp->title); mmdisp->title = strnew(title, 0); tableDestroy(mmdisp->table); mmdisp->table = tableCopy(table, 0); mmdisp->mapColumns = mapColumns; multiMapDraw (mmdisp); return; } /* multiMapDisplayReCreate */ /*****************************************/ static MultiMap currentMultiMap (char *caller) { /* find and verify MultiMap struct on active graph */ MultiMap mmdisp = 0 ; if (!(graphAssFind(&MultiMap_MAGIC, &mmdisp))) messcrash("%s() could not find MultiMapStruct on graph", caller); if (!mmdisp) messcrash("%s() received NULL MultiMapStruct pointer", caller); if (mmdisp->magic != &MultiMap_MAGIC) messcrash("%s() received non-magic MultiMapStruct pointer", caller); return mmdisp; } /* currentMultiMap */ /************************************************************/ static void multiMapDisplayDestroy (void) { MultiMap mmdisp = currentMultiMap("multiMapDisplayDestroy"); int colNum; MapColumn *mcol; tableDestroy(mmdisp->table); messfree(mmdisp->title); for (colNum = 0; colNum < arrayMax(mmdisp->mapColumns); colNum++) { mcol = arrp(mmdisp->mapColumns, colNum, MapColumn) ; bumpDestroy(mcol->bump); arrayDestroy(mcol->segs); arrayDestroy(mcol->segps); } arrayDestroy(mmdisp->mapColumns); mmdisp->magic = 0; messfree(mmdisp); return; } /* multiMapDisplayDestroy */ static void multiMapDraw (MultiMap mmdisp) { char *windowTitle; if (!graphActivate(mmdisp->graph)) return; windowTitle = displayGetTitle("DtMULTIMAP"); if (strcmp(windowTitle, "DtMULTIMAP") == 0) windowTitle = "Multi Map"; /* if unchanged in displays.wrm */ if (strlen(mmdisp->title) > 0) graphRetitle(messprintf("%s : %s", windowTitle, mmdisp->title)); else graphRetitle(messprintf("%s : untitled", windowTitle)); /*****************/ graphClear(); multiMapConvert(mmdisp) ; multiMapWhole () ; /* sets ->centre, ->mag and calls Draw() */ return; } /* multiMapDraw */ static void multiMapResize (void) { MultiMap mmdisp = currentMultiMap("multiMapResize") ; multiMapDrawKey (mmdisp, 0) ; } /***********************************/ static void multiMapPick (int box, double x, double y, int modifier_unused) { int i ; MapColumn *mcol ; MultiMap mmdisp = currentMultiMap("multiMapPick") ; if (!box) return ; if (box == mmdisp->cursorBox) graphBoxDrag (mmdisp->cursorBox, multiMapDragCursor) ; for (i = 0; i < arrayMax(mmdisp->mapColumns); i++) { mcol = arrp(mmdisp->mapColumns, i, MapColumn) ; if (box == mcol->subTitleBox || box == mcol->mapColBox) { if (mcol != mmdisp->activeMapColumn) { if (mmdisp->activeMapColumn && mmdisp->activeMapColumn->subTitleBox) graphBoxDraw(mmdisp->activeMapColumn->subTitleBox, BLACK, WHITE) ; mmdisp->activeMapColumn = mcol ; if (mmdisp->activeMapColumn->subTitleBox) graphBoxDraw(mmdisp->activeMapColumn->subTitleBox, BLACK, LIGHTGREEN) ; drawChromosomeBox(mmdisp) ; } return ; } } if (box == mmdisp->activeColBox) multiMapFollow (mmdisp, x, y) ; else multiMapSelect (mmdisp, box) ; return; } /* multiMapPick */ /*********************/ static void multiMapClear (void) { KEY curr ; MultiMap mmdisp = currentMultiMap("multiMapClear") ; if (mmdisp->activeColBox && arrp(mmdisp->mapBoxes, mmdisp->activeColBox,BOX)->seg) curr = arrp(mmdisp->mapBoxes,mmdisp->activeColBox,BOX)->seg->key ; else curr = 0 ; multiMapDrawKey (mmdisp, curr) ; return; } /* multiMapClear */ static void multiMapSelect (MultiMap mmdisp, int box) { MapColumn *mcol ; SEG *seg, *friend ; if (mmdisp->activeColBox) { graphBoxDraw (mmdisp->activeColBox, BLACK, LIGHTBLUE) ; seg = friend = arrp(mmdisp->mapBoxes, mmdisp->activeColBox, BOX)->seg ; while (friend = friend->friends, friend != seg) if (friend->ibox) graphBoxDraw (friend->ibox, BLACK, LIGHTBLUE) ; } if ((seg = arrp(mmdisp->mapBoxes, box, BOX)->seg)) { mmdisp->activeColBox = box ; graphBoxDraw (mmdisp->activeColBox, BLACK, RED) ; seg = friend = arrp(mmdisp->mapBoxes, mmdisp->activeColBox, BOX)->seg ; while (friend = friend->friends, friend != seg) if (friend->ibox) graphBoxDraw (friend->ibox, BLACK, LIGHTRED) ; mcol = seg->mcol ; if (mcol != mmdisp->activeMapColumn) { if (mmdisp->activeMapColumn && /* check if we had no * previously selected column */ mmdisp->activeMapColumn->subTitleBox) graphBoxDraw(mmdisp->activeMapColumn->subTitleBox, BLACK, WHITE) ; mmdisp->activeMapColumn = mcol ; if (mmdisp->activeMapColumn->subTitleBox) graphBoxDraw(mmdisp->activeMapColumn->subTitleBox, BLACK, LIGHTGREEN) ; drawChromosomeBox(mmdisp) ; } /* graphActivate(spread->dataGraph) ; spreadSelectFromMap(spread, seg->line, c->colonne) ; graphActivate(spread->mapGraph) ; */ } else mmdisp->activeColBox = 0 ; return; } /* multiMapSelect */ static void multiMapFollow (MultiMap mmdisp, double x, double y) { SEG *seg ; seg = arrp(mmdisp->mapBoxes, mmdisp->activeColBox, BOX)->seg ; if (seg && seg->parent) { if (seg->grandParent) { if (display (seg->parent, seg->grandParent, 0)) displayPreserve() ; /* automatically preserve the called map */ } else display (seg->parent, 0, "TREE") ; } return; } /* multiMapFollow */ /*****************************************/ /**************************************************/ /**************** drawing info ********************/ static int segpOrder(void *a, void *b) { SEG *seg1 = *(SEG**)a; SEG *seg2 = *(SEG**)b; float ya = seg1->ys; float yb = seg2->ys; if (seg1->mcol && seg2->mcol) return ya > yb ? 1 : ( ya == yb ? 0 : -1 ) ; if (seg1->mcol) /* !seg2-> implied */ return -1 ; if (seg2->mcol) return 1 ; return seg1 < seg2 ? -1 : 1 ; } /* segpOrder */ /***********************************************/ /********* start off with some utility routines ********/ static void getNxNy(void) { graphFitBounds (&nx, &ny) ; yLength = (ny - topMargin - bottomMargin) ; yCentre = topMargin + 0.5*yLength ; } /***************************************/ static void multiMapWhole (void) { float l ; MapColumn *mcol ; int j, maxCol ; MultiMap mmdisp = currentMultiMap("multiMapWhole") ; getNxNy() ; if (!mmdisp->activeMapColumn || mmdisp->zoomAll) { maxCol = arrayMax(mmdisp->mapColumns) ; for(j = 0 ; j < maxCol ; j++) { mcol = arrp(mmdisp->mapColumns, j, MapColumn) ; if (!j || mcol->isMappable) { l = mcol->max - mcol->min ; mcol->centre = mcol->min + 0.5 * l ; if (l == 0) l = 1 ; mcol->mag = .9 * yLength / l ; mmdisp->activeMapColumn = mcol ; } } } else { mcol = mmdisp->activeMapColumn; if (mcol && mcol->mag) /* will work on name collone */ { l = mcol->max - mcol->min ; if (l == 0) l = 1 ; mcol->centre = mcol->min + 0.5 * l ; mcol->mag = .9 * yLength / l ; } } multiMapDrawKey (mmdisp, 0) ; return; } /* multiMapWhole */ static void multiMapZoomIn (void) { MapColumn *mcol; int j, maxCol; MultiMap mmdisp = currentMultiMap("multiMapZoomIn") ; if (mmdisp->zoomAll) { maxCol = arrayMax(mmdisp->mapColumns) ; for(j = 0 ; j < maxCol ; j++) { mcol = arrp(mmdisp->mapColumns, j, MapColumn) ; if (!j || mcol->isMappable) mcol->mag *= 2 ; } } else if (mmdisp->activeMapColumn) { mcol = mmdisp->activeMapColumn; if (mcol->mag) mcol->mag *= 2 ; } multiMapDrawKey (mmdisp, 0) ; return; } /* multiMapZoomIn */ static void multiMapZoomOut (void) { MapColumn *mcol ; int j , maxCol ; MultiMap mmdisp = currentMultiMap("multiMapZoomIn") ; if (mmdisp->zoomAll) { maxCol = arrayMax(mmdisp->mapColumns) ; for(j = 0 ; j < maxCol ; j++) { mcol = arrp(mmdisp->mapColumns, j, MapColumn) ; if (!j || mcol->isMappable) mcol->mag /= 2 ; } } else if (mmdisp->activeMapColumn) { mcol = mmdisp->activeMapColumn; if (mcol->mag) mcol->mag /= 2 ; } multiMapDrawKey (mmdisp, 0) ; return; } /* multiMapZoomOut */ static void multiMapZoomAll (void) { MultiMap mmdisp = currentMultiMap("multiMapZoomAll") ; mmdisp->zoomAll = TRUE ; graphBoxDraw(mmdisp->allButton, BLACK, LIGHTBLUE) ; graphBoxDraw(mmdisp->allButton + 1, BLACK, WHITE) ; return; } /* multiMapZoomAll */ static void multiMapZoomActive (void) { MultiMap mmdisp = currentMultiMap("multiMapZoomActive") ; mmdisp->zoomAll = FALSE ; graphBoxDraw(mmdisp->allButton + 1, BLACK, LIGHTBLUE) ; graphBoxDraw(mmdisp->allButton, BLACK, WHITE) ; return; } /* multiMapZoomActive */ static void multiMapChangeSymbolSize (void) { ACEIN size_in; size_in = messPrompt ("Change size of little square symbols to", messprintf ("%f", symbolSize_L), "fz", 0); if (size_in) { aceInFloat (size_in, &symbolSize_L) ; aceInDestroy (size_in); } return; } /* multiMapChangeSymbolSize */ static void multiMapFlip (void) { MapColumn *mcol ; SEG *seg ; int i ; float tmp ; MultiMap mmdisp = currentMultiMap("multiMapFlip") ; mcol = mmdisp->activeMapColumn ; if (!mcol) return ; mcol->isFlipMap = ! mcol->isFlipMap ; i = arrayMax(mcol->segs) ; seg = arrp(mcol->segs, 0, SEG) - 1 ; while(seg++, i--) if (seg->mcol == mcol) seg->y = - seg->y ; tmp = mcol->min ; mcol->min = - mcol->max ; mcol->max = - tmp ; mcol->centre = - mcol->centre ; multiMapDrawKey (mmdisp, 0) ; return; } /* multiMapFlip */ /**************************************************************/ /***************** dragging code - middle button **************/ static double oldy, oldDy, oldx; static BOOL dragFast ; #define DRAGFASTLIMIT xScale static void multiMapMiddleDrag (double x, double y) { if (dragFast) { graphXorLine (0, oldy - oldDy, DRAGFASTLIMIT, oldy - oldDy) ; graphXorLine (0, oldy + oldDy, DRAGFASTLIMIT, oldy + oldDy) ; } else graphXorLine (DRAGFASTLIMIT, oldy, nx, oldy) ; oldy = y ; if (dragFast) { oldDy *= exp ((x - oldx) / 25.) ; oldx = x ; graphXorLine (0, y - oldDy, DRAGFASTLIMIT, y - oldDy) ; graphXorLine (0, y + oldDy, DRAGFASTLIMIT, y + oldDy) ; } else graphXorLine (DRAGFASTLIMIT, y, nx, y) ; return; } /* multiMapMiddleDrag */ static void multiMapMiddleUp (double x, double y) { MapColumn *mcol ; float x1,x2,y1,y2 ; int j, maxCol ; MultiMap mmdisp = currentMultiMap("multiMapMiddleUp") ; if (mmdisp->zoomAll) { maxCol = arrayMax(mmdisp->mapColumns) ; for(j = 0 ; j < maxCol ; j++) { mcol = arrp(mmdisp->mapColumns,j, MapColumn) ; if (!j || mcol->isMappable) { if (dragFast) { graphBoxDim (mmdisp->cursorBox, &x1, &y1, &x2, &y2) ; mcol->mag *= (y2 - y1) / (2. * oldDy) ; mcol->centre = mcol->min + (mcol->max - mcol->min) * (y - topMargin) / yLength ; } else mcol->centre += (y - 0.5 - yCentre) / mcol->mag ; } } } else if (mmdisp->activeMapColumn) { mcol = mmdisp->activeMapColumn ; if (dragFast) { graphBoxDim (mmdisp->cursorBox, &x1, &y1, &x2, &y2) ; mcol->mag *= (y2 - y1) / (2. * oldDy) ; mcol->centre = mcol->min + (mcol->max - mcol->min) * (y - topMargin) / yLength ; } else mcol->centre += (y - 0.5 - yCentre) / mcol->mag ; } multiMapDrawKey (mmdisp, 0) ; return; } /* multiMapMiddleUp */ static void multiMapMiddleDown (double x, double y) { float x1,x2,y1,y2 ; MultiMap mmdisp = currentMultiMap("multiMapMiddleDown") ; getNxNy () ; graphBoxDim (mmdisp->cursorBox, &x1, &y1, &x2, &y2) ; oldDy = (y2 - y1) / 2. ; dragFast = (x < DRAGFASTLIMIT) ? TRUE : FALSE ; if(dragFast) { graphXorLine (0, y - oldDy, DRAGFASTLIMIT, y - oldDy) ; graphXorLine (0, y + oldDy, DRAGFASTLIMIT, y + oldDy) ; } else graphXorLine (DRAGFASTLIMIT, y, nx, y) ; oldx = x ; oldy = y ; graphRegister (MIDDLE_DRAG, multiMapMiddleDrag) ; graphRegister (MIDDLE_UP, multiMapMiddleUp) ; return; } /* multiMapMiddleDown */ static void multiMapDragCursor (float *x, float *y, BOOL isDone) { if (isDone) { float x1,y1,x2,y2 ; MapColumn *mcol ; int j, maxCol ; MultiMap mmdisp = currentMultiMap("multiMapDragCursor") ; getNxNy() ; graphBoxDim (mmdisp->cursorBox, &x1, &y1, &x2, &y2) ; if (mmdisp->zoomAll) { maxCol = arrayMax(mmdisp->mapColumns) ; for(j = 0 ; j < maxCol ; j++) { mcol = arrp(mmdisp->mapColumns,j, MapColumn) ; if (!j || mcol->isMappable) mcol->centre = mcol->min + (mcol->max - mcol->min) * ((*y + 0.5*(y2-y1)) - topMargin) / yLength ; } } else if (mmdisp->activeMapColumn) { mcol = mmdisp->activeMapColumn ; mcol->centre = mcol->min + (mcol->max - mcol->min) * ((*y + 0.5*(y2-y1)) - topMargin) / yLength ; } multiMapDrawKey (mmdisp, 0) ; } else *x = xCursor - 0.5 ; return; } /* multiMapDragCursor */ /**************************************************/ /**************************************************/ static void drawScale (MapColumn *mcol, int xScale1) { float cutoff = 5 / mcol->mag ; float unit = 0.01 ; float subunit = 0.001 ; float x, xx, y, start, end ; while (unit < cutoff) { unit *= 2 ; subunit *= 5 ; if (unit >= cutoff) break ; unit *= 2.5 ; if (unit >= cutoff) break ; unit *= 2 ; subunit *= 2 ; } start = SPRDGRAPH2MAP(mcol, topMargin) ; if (start < mcol->min) start = mcol->min ; end = SPRDGRAPH2MAP(mcol, ny-bottomMargin) ; if (end > mcol->max) end = mcol->max ; x = unit * (((start > mcol->min) ? 1 : 0) + (int)(start/unit)) ; while (x <= end) { y = SPRDMAP2GRAPH(mcol, x) ; xx = mcol->isFlipMap ? -x : x ; graphLine (xScale1-1.5,y,xScale1-0.5,y) ; if(unit >= 1) graphText (messprintf ("%-4.0f",xx),xScale1,y-.5) ; else if(unit >= .1) graphText (messprintf ("%-4.1f",xx),xScale1,y-.5) ; else if(unit >= .01) graphText (messprintf ("%-4.2f",xx),xScale1,y-.5) ; else if(unit >= .001) graphText (messprintf ("%-4.3f",xx),xScale1,y-.5) ; x += unit ; } x = subunit * (((start >= mcol->min)? 1 : 0) + (int)(start/subunit)) ; while (x <= end) { y = SPRDMAP2GRAPH(mcol, x) ; graphLine (xScale1-1.0,y,xScale1-0.5,y) ; x += subunit ; } graphLine (xScale1-0.5, SPRDMAP2GRAPH(mcol,start), xScale1-0.5, SPRDMAP2GRAPH(mcol,end)) ; return; } /* drawScale */ static void drawChromosomeBox (MultiMap mmdisp) { MapColumn *mcol = mmdisp->activeMapColumn ; if (!mcol) return ; if (mmdisp->chromoBox) graphBoxClear(mmdisp->chromoBox) ; mmdisp->chromoBox = graphBoxStart() ; graphFillRectangle (xCursor - 0.25, topMargin, xCursor + 0.25, ny - bottomMargin) ; mmdisp->cursorBox = graphBoxStart() ; arrayp(mmdisp->mapBoxes, mmdisp->cursorBox, BOX)->seg = 0 ; if (mcol->max != mcol->min) graphRectangle (xCursor - 0.5, MAP2CHROM(SPRDGRAPH2MAP(mcol, topMargin)), xCursor + 0.5, MAP2CHROM(SPRDGRAPH2MAP(mcol, ny - bottomMargin))) ; graphBoxEnd () ; graphBoxEnd () ; graphBoxDraw (mmdisp->chromoBox,BLACK, WHITE) ; graphBoxDraw (mmdisp->cursorBox,DARKGREEN,GREEN) ; return; } /* drawChromosomeBox */ static void drawChromosomeLine (MultiMap mmdisp) { int i ; mmdisp->chromoBox = 0 ; /* graphColor (DARKGRAY) ; graphLine (xCursor, MAP2CHROM(SPRDGRAPH2MAP(c,topMargin)), xScale-0.5, topMargin ) ; graphLine (xCursor, MAP2CHROM(SPRDGRAPH2MAP(c,ny - bottomMargin)), xScale-0.5, ny - bottomMargin) ; graphColor (BLACK) ; */ graphBoxStart() ; graphTextHeight (0.75) ; for (i = 0 ; i <= 10 ; ++i) graphText (messprintf ("%3d%%",10*i), 1, topMargin + yLength * i / 10.0 - 0.25) ; graphTextHeight (0) ; graphBoxEnd() ; return; } /* drawChromosomeLine */ /***********************************************/ static void multiMapBoxEnd (int ibox, BOX *box) { graphBoxEnd () ; if (box->seg && box->seg->flag & FLAG_HIGHLIGHT) graphBoxDraw (ibox, BLACK, MAGENTA) ; else graphBoxDraw (ibox, BLACK, box->color) ; return; } /* multiMapBoxEnd */ /***********************************************/ static Array multiMapFindLimits(TABLE *table, Array isFlipMapArray) { int rowNum, colNum, colNum1 ; BOOL isSuccess = FALSE ; float y ; BOOL first, found ; MapColumn *mcol; Array mapColumns = arrayCreate(table->ncol, MapColumn); if (table->ncol == 0) messcrash("multiMapFindLimits() - received table without columns"); for(colNum = 0 ; colNum < table->ncol ; colNum++) { mcol = arrayp(mapColumns, colNum, MapColumn); mcol->type = table->type[colNum]; if (isFlipMapArray && array(isFlipMapArray, colNum, BOOL)) mcol->isFlipMap = TRUE; else mcol->isFlipMap = FALSE; if ((mcol->type == 'i' || mcol->type == 'f') /*&& !mcol->isHidden*/) mcol->isMappable = TRUE; else { mcol->isMappable = FALSE; continue; } first = TRUE; for (rowNum = 0 ; rowNum < tabMax(table, colNum) ; rowNum++) { y = 0.0 ; found = FALSE ; if (!tabEmpty(table, rowNum, colNum)) switch (table->type[colNum]) { case 'i': found = TRUE ; y = (float)tabInt(table, rowNum, colNum) ; break ; case 'f': found = TRUE ; y = tabFloat(table, rowNum, colNum) ; break ; } if (found) { y = mcol->isFlipMap ? -y : y ; if (first) { isSuccess = TRUE ; first = FALSE ; mcol->min = y ; mcol->max = y ; } if (y < mcol->min) mcol->min = y ; if (y > mcol->max) mcol->max = y ; } } } for(colNum = 0 ; colNum < table->ncol ; colNum++) { mcol = arrp(mapColumns, colNum, MapColumn); if (!mcol->isMappable /*&& !mcol->isHidden*/) { for(colNum1 = table->ncol-1 ; colNum1 >= 0 ; colNum1--) { MapColumn *mcol1; mcol1 = arrp(mapColumns,colNum1, MapColumn) ; if(mcol1->isMappable) { mcol->min = mcol1->min ; mcol->max = mcol1->max ; break ; } } } } if (!isSuccess) { arrayDestroy(mapColumns); mapColumns = NULL; } return mapColumns ; } /* multiMapFindLimits */ /************************************************************/ static void multiMapConvert (MultiMap mmdisp) { SEG *seg, *oldSeg ; int rowNum, rowMax, colNum, colMax ; float y ; MapColumn *mcol; colMax = mmdisp->table->ncol ; rowMax = tableMax(mmdisp->table); for (colNum = 0 ; colNum < colMax ; colNum++) { mcol = arrp(mmdisp->mapColumns, colNum, MapColumn); if (colNum == 0 || mcol->isMappable) mcol->segs = arrayReCreate (mcol->segs, rowMax, SEG) ; else arrayDestroy(mcol->segs) ; } for(rowNum = 0 ; rowNum < rowMax ; rowNum++) { oldSeg = 0 ; for(colNum = 0 ; colNum < colMax ; colNum++) { mcol = arrp(mmdisp->mapColumns, colNum, MapColumn); if (!mcol->isMappable) continue ; if (tabEmpty(mmdisp->table, rowNum, colNum)) continue; seg = arrayp(mcol->segs, rowNum, SEG) ; seg->line = rowNum ; seg->mcol = mcol ; if (oldSeg) { seg->friends = oldSeg->friends ; oldSeg->friends = seg ; } else { seg->friends = seg ; /* loop ! */ oldSeg = seg ; } switch (mcol->type) { case 'i': y = (float)tabInt(mmdisp->table, rowNum, colNum) ; break ; case 'f': y = tabFloat(mmdisp->table, rowNum, colNum) ; break ; } seg->y = mcol->isFlipMap ? -y : y ; seg->parent = tabParent(mmdisp->table, rowNum, colNum) ; seg->grandParent = tabGrandParent(mmdisp->table, rowNum, colNum) ; } /* Now the names - they are the keys in the master-column No 0 */ mcol = arrp(mmdisp->mapColumns, 0, MapColumn); seg = arrayp(mcol->segs, rowNum, SEG) ; seg->key = tabKey(mmdisp->table, rowNum, 0); seg->parent = tabKey(mmdisp->table, rowNum, 0); seg->grandParent = 0 ; seg->line = rowNum ; seg->flag = FLAG_NAME ; seg->mcol = mcol ; if (oldSeg) { seg->friends = oldSeg->friends ; oldSeg->friends = seg ; seg->y = seg->friends->y ; } else seg->friends = seg ; /* loop ! */ } for(colNum = 0 ; colNum < colMax ; colNum++) { mcol = arrp(mmdisp->mapColumns, colNum, MapColumn); if (mcol->segs) { SEG *zs, **zsp ; mcol->segps = arrayReCreate (mcol->segps, rowMax, SEG*) ; rowNum = rowMax ; zsp = arrayp(mcol->segps, rowNum - 1, SEG*) ; zs = arrp(mcol->segs, rowNum - 1, SEG) ; while (rowNum--) *zsp-- = zs-- ; } } return; } /* multiMapConvert */ /**********/ static void multiMapDrawKeyC(MapColumn *mcol, Array mapBoxes, float x) { int i = arrayMax(mcol->segs), ibox, oldFormat ; SEG *seg = arrp(mcol->segs, 0, SEG) - 1 ; BOX *box ; int screenMin = topMargin, screenMax = ny - bottomMargin ; while(seg++, i--) { if (!seg->mcol) continue ; if (seg->ys > screenMin && seg->ys < screenMax + 30) { ibox = graphBoxStart() ; box = arrayp(mapBoxes, ibox, BOX) ; box->seg = seg ; seg->ibox = ibox ; box->color = YELLOW ; if (seg->flag & FLAG_NAME) { box->color = WHITE ; if (iskey(seg->key) == 2) oldFormat = graphTextFormat(BOLD) ; graphText (name(seg->key), x + seg->xs, seg->ys) ; if (iskey(seg->key) == 2) graphTextFormat(oldFormat) ; seg->x = x + seg->xs ; } else { graphLine(x , seg->ys, x + symbolSize_L, seg->ys ) ; graphLine(x , seg->ys , x , seg->ys + .5) ; seg->x = x + seg->xs ; } multiMapBoxEnd(ibox, box) ; } else { seg->x = x ; /* needed to draw lines */ seg->ibox = 0 ; } } } /* multiMapDrawKeyC */ /**********/ static void multiMapDrawKeyLines(Array segs) { float x, y ; int i = arrayMax(segs) ; int screenMin = topMargin, screenMax = ny - bottomMargin ; SEG *friend, *seg = arrp(segs, 0, SEG) - 1 ; while (seg++, i--) { friend = seg ; x = seg->x ; y = seg->ys ; if (seg->mcol) /* may be zero if line is hidden */ while (friend = friend->friends, friend != seg) { if ((y > screenMin && y < screenMax) || (friend->ys > screenMin && friend->ys < screenMax)) if (x - friend->x < 26) /* I hope nearest neighbours */ graphLine(x, y, friend->x + symbolSize_L, friend->ys) ; x = friend->x ; y = friend->ys ; } } return; } /* multiMapDrawKeyLines */ /**********/ static void multiMapBump (MapColumn *mcol) { int i = arrayMax(mcol->segs) ; SEG **segp, *seg ; int screenMin = topMargin ; float h = freelower(mcol->type) == 'k' ? 1 : .01 ; segp = arrp(mcol->segps, 0, SEG*) ; while (i--) { seg = *segp++ ; if (seg->mcol) { seg->xs = 0 ; if ((seg->flag & FLAG_NAME) && seg->friends) seg->ys = SPRDMAP2GRAPH (seg->friends->mcol, seg->y) ; else seg->ys = SPRDMAP2GRAPH (seg->mcol, seg->y) ; } } i = arrayMax(mcol->segs) ; arraySort(mcol->segps, segpOrder) ; mcol->bump = bumpReCreate(mcol->bump, 1, ny) ; segp = arrp(mcol->segps, 0, SEG*) ; while(i--) { seg = *segp++ ; if (!(seg->flag & FLAG_NAME) || seg->ys >= screenMin) bumpItem(mcol->bump, 1, h, &seg->xs, &seg->ys) ; } } /**********/ static void multiMapDrawKey (MultiMap mmdisp, KEY curr) { int x, j, maxCol; MapColumn *mcol, *lastmcol ; mmdisp->mapBoxes = arrayReCreate (mmdisp->mapBoxes, 64, BOX) ; mmdisp->activeColBox = 0 ; if (mmdisp->activeMapColumn && !mmdisp->activeMapColumn->isMappable) mmdisp->activeMapColumn = 0 ; getNxNy () ; if (!isPapDisp) { graphClear () ; graphColor (BLACK) ; if (yLength < 6) { messout ("Sorry, this window is too small for a multi map") ; return ; } drawChromosomeLine (mmdisp) ; } maxCol = arrayMax(mmdisp->mapColumns) ; if (strlen(mmdisp->title) > 0) graphText(mmdisp->title, 32, 1.5) ; x = xScale; for(j = 0 ; j < maxCol ; j++) { mcol = arrp(mmdisp->mapColumns, j, MapColumn) ; if (mcol->isMappable) { drawScale(mcol, x) ; lastmcol = mcol ; x += 8 ; multiMapBump(mcol) ; mcol->mapColBox = graphBoxStart() ; multiMapDrawKeyC(mcol, mmdisp->mapBoxes, x) ; if (strlen(tableGetColumnName(mmdisp->table, j)) > 0) { mcol->subTitleBox = graphBoxStart() ; graphText(tableGetColumnName(mmdisp->table, j), x, 5) ; graphBoxEnd() ; } else mcol->subTitleBox = 0; graphBoxEnd() ; /* mapColBox */ x += 3 * symbolSize_L + 2 ; } if (!mmdisp->activeMapColumn) mmdisp->activeMapColumn = mcol ; } drawChromosomeBox (mmdisp) ; mcol = lastmcol ; arrp(mmdisp->mapColumns, 0, MapColumn)->mag = mcol->mag ; arrp(mmdisp->mapColumns, 0, MapColumn)->centre = mcol->centre ; arrp(mmdisp->mapColumns, 0, MapColumn)->min = mcol->min ; arrp(mmdisp->mapColumns, 0, MapColumn)->max = (mcol->max > mcol->min ? mcol->max : mcol->max + 1) ; mcol = arrp(mmdisp->mapColumns, 0, MapColumn) ; x += 4 ; multiMapBump(mcol) ; multiMapDrawKeyC(mcol, mmdisp->mapBoxes, x) ; multiMapDrawKeyLines(mcol->segs) ; mmdisp->allButton = graphButton ("Zoom All", multiMapZoomAll, 5, 0.5) ; graphButton ("Zoom Active", multiMapZoomActive, 15, 0.5) ; /* has to be the box right after the "Zoom All" button */ if (mmdisp->zoomAll) { graphBoxDraw(mmdisp->allButton, BLACK, LIGHTBLUE) ; graphBoxDraw(mmdisp->allButton + 1, BLACK, WHITE) ; } else { graphBoxDraw(mmdisp->allButton + 1, BLACK, LIGHTBLUE) ; graphBoxDraw(mmdisp->allButton, BLACK, WHITE) ; } graphButtons (buttonOpts, 5, 2.5, nx) ; mmdisp->activeMapColumn = 0 ; /* ? ? ? */ if (mmdisp->activeMapColumn && mmdisp->activeMapColumn->subTitleBox) graphBoxDraw(mmdisp->activeMapColumn->subTitleBox, BLACK, LIGHTGREEN) ; graphRedraw () ; return; } /* multiMapDrawKey */ /*********************************************************/ /* This routine is a bit artificial in that it used to dig in * the internals of graph but this has been changed so that it uses * some calls provided by graph just to support it. */ static void myMapPrint(void) { float min, max ; float oldcentre ; int oldh, newh ; int oldtype ; float olduh, newuh ; float yfac ; MapColumn *mcol ; MultiMap mmdisp = currentMultiMap("myMapPrintWhole") ; ACEIN zone_in; mcol = mmdisp->activeMapColumn ; if (!mcol) { messerror ("No active column"); return; } min = mcol->min ; max = mcol->max ; zone_in = messPrompt("Please state the zone you wish to print", messprintf("%g %g", min, max), "ff", 0); if (!zone_in) return ; aceInFloat(zone_in, &min) ; aceInFloat(zone_in, &max) ; aceInDestroy (zone_in); if (min >= max) return ; if (min < mcol->min) min = mcol->min ; if (max > mcol->max) max = mcol->max ; oldcentre = mcol->centre ; mcol->centre = (max + min) / 2 ; /* Record current settings of active graph height etc. */ graphGetSprdmapData(&oldh, &olduh, &oldtype, &yfac) ; /* Set a new height and draw the map. */ newuh = 1.05 * (max - min) * mcol->mag + topMargin + 5 ; newh = newuh * yfac ; graphSetSprdmapCoords(newh, newuh) ; multiMapDrawKey (mmdisp, 0) ; /* OK, now it's drawn we can print it. */ graphSetSprdmapType(TEXT_SCROLL) ; graphPrint() ; graphSetSprdmapType(oldtype) ; /* Restore the old graph height settings and redraw the map. */ graphSetSprdmapCoords(oldh, olduh) ; mcol->centre = oldcentre ; multiMapDrawKey (mmdisp, 0) ; return; } /* myMapPrint */ /*************************** eof ****************************/