/* hgGeneRing - Gene Network Browser. */ #include "common.h" #include "linefile.h" #include "hash.h" #include "cheapcgi.h" #include "htmshell.h" #include "obscure.h" #include "web.h" #include "cart.h" #include "hdb.h" #include "dbDb.h" #include "hgFind.h" #include "hCommon.h" #include "hui.h" #include "interaction.h" #include "bdgpGeneInfo.h" #include "portable.h" char *errMsg = NULL; char *geneList = NULL; struct slName *geneNames = NULL; struct hash *aliasHash = NULL; struct interaction *interactions = NULL; struct node { char *name; /* name or id - use also as hash key */ char *alias; /* if used */ struct nodelist *xrays; /* out-going rays in directed graph */ struct nodelist *nrays; /* in-coming rays in directed graph */ boolean ring; /* member of gene-ring? */ int ringRank; /* number of ring members connected to by x or n rays */ int xpos; /* x position */ int ypos; /* y position */ }; struct nodelist { struct nodelist *next; /* next in list */ struct node *node; }; struct nodelist* allNodes = NULL; struct hash *nodeHash = NULL; int ringCount = 0; int insideCount = 0; int outsideCount = 0; struct cart *cart = NULL; struct hash *oldVars = NULL; char *clade = NULL; char *organism = NULL; char *db = NULL; /* ------ old junk cloned from hgGateway --------- */ void hgGateway() /* hgGateway - Human Genome Browser Gateway. */ { char *defaultPosition = hDefaultPos(db); char *position = cloneString(cartUsualString(cart, "position", defaultPosition)); boolean gotClade = hGotClade(); /* JavaScript to copy input data on the change genome button to a hidden form This was done in order to be able to flexibly arrange the UI HTML */ char *onChangeDB = "onchange=\"document.orgForm.db.value = document.mainForm.db.options[document.mainForm.db.selectedIndex].value; document.orgForm.submit();\""; char *onChangeOrg = "onchange=\"document.orgForm.org.value = document.mainForm.org.options[document.mainForm.org.selectedIndex].value; document.orgForm.db.value = 0; document.orgForm.submit();\""; char *onChangeClade = "onchange=\"document.orgForm.clade.value = document.mainForm.clade.options[document.mainForm.clade.selectedIndex].value; document.orgForm.org.value = 0; document.orgForm.db.value = 0; document.orgForm.submit();\""; if (sameString(position, "genome") || sameString(position, "hgBatch")) position = defaultPosition; puts("
\n" "
" "\n" "
\n" "The UCSC Genome Browser was created by the \n" "Genome Bioinformatics Group of UC Santa Cruz.\n" "
" "Software Copyright (c) The Regents of the University of California.\n" "All rights reserved.\n" "
\n"); puts("\n" "
\n" "\n" "
\n" "\n" "
\n" "\n" "\n" "
\n" ""); if (gotClade) puts(""); puts("\n" "\n" "\n" "\n" "\n" "\n"); if (gotClade) { puts("\n"); } puts("\n"); puts("\n"); puts("\n"); #ifdef SORRY_GILL_I_HIT_INSTEAD_OF_SUBMIT_TOO_MANY_TIMES puts("\n"); #endif /* SORRY_GILL_I_HIT_INSTEAD_OF_SUBMIT_TOO_MANY_TIMES */ cartSetString(cart, "position", position); cartSetString(cart, "db", db); cartSetString(cart, "org", organism); if (gotClade) cartSetString(cart, "clade", clade); freez(&defaultPosition); position = NULL; puts("\n"); printf("\n"); puts("
cladegenomeassemblypositionimage width  
\n"); printCladeListHtml(organism, onChangeClade); puts("\n"); if (gotClade) printGenomeListForCladeHtml(db, onChangeOrg); else printGenomeListHtml(db, onChangeOrg); puts("\n"); /* HACK ALERT - Zoo needs to have different pulldown behavior - Hiram */ if ( startsWith( "Zoo", organism ) ) { puts(""); } else { printAssemblyListHtml(db, onChangeDB); } puts("\n"); cgiMakeTextVar("position", addCommasToPos(position), 30); printf("\n"); cgiMakeOnClickButton("document.mainForm.position.value=''","clear"); printf("\n"); cgiMakeIntVar("pix", cartUsualInt(cart, "pix", hgDefaultPixWidth), 4); cartSaveSession(cart); printf(""); cgiMakeButton("Submit", "Submit"); printf("
\n" "
\n" "Click here to reset the browser user interface settings to their defaults.
\n" "
\n" "
\n"); cgiMakeButton("customTrackPage", "Add Your Own Custom Tracks"); puts("
\n" "
\n" "
\n" "
\n"); puts("
"); hgPositionsHelpHtml(organism, db); puts("
\n" ); puts("
"); if (gotClade) printf("\n", clade); printf("\n", organism); printf("\n", db); cartSaveSession(cart); puts("

"); } /* end of hgGateway junk that this code was cloned from */ /* ----------------------------------------------------------------------- */ boolean getGenesAsList() /* create name-list from geneString, so that we don't have to keep re-parsing the cart string in different places */ { char* ss = cloneString(geneList); char* s = ss; char* w = NULL; int c=0; char emsg[256]; /* clean up unwanted characters if any */ subChar(ss, ',' ,' '); subChar(ss, '\t',' '); subChar(ss, '\n',' '); subChar(ss, '\r',' '); while (1) { if (!(w = nextWord(&s))) break; if (slNameInList(geneNames, w)) /* could be optimized, but not expecting large lists for ring */ { safef(emsg,sizeof(emsg), "Duplicate gene id (%s) found in list.",w); errMsg = cloneString(emsg); freez(&ss); return FALSE; } slNameAddHead(&geneNames, w); c++; } slReverse(&geneNames); if (c==0) { errMsg = "No genes in list. Please specify genes for ring."; return FALSE; } freez(&ss); return TRUE; } void updateGeneList() /* update the cart list of genes */ { char *sep = ""; struct slName *sn = geneNames; struct dyString *geneList=newDyString(512); while(sn) { dyStringPrintf(geneList,"%s%s",sep,sn->name); sep=" "; sn=sn->next; } cartSetString(cart, "ring_geneList", geneList->string); freeDyString(&geneList); } struct bdgpGeneInfo *bdgpGeneInfoLoadByQuery(struct sqlConnection *conn, char *query) /* Load all interaction from table that satisfy the query given. * Where query is of the form 'select * from example where something=something' * or 'select example.* from example, anotherTable where example.something = * anotherTable.something'. * Dispose of this with bdgpGeneInfoFreeList(). */ { struct bdgpGeneInfo *list = NULL, *el; struct sqlResult *sr; char **row; sr = sqlGetResult(conn, query); while ((row = sqlNextRow(sr)) != NULL) { el = bdgpGeneInfoLoad(row); slAddHead(&list, el); } slReverse(&list); sqlFreeResult(&sr); return list; } void getGeneAliasesFromTable(char* table) /* read all the gene aliases from database, return bdgpGeneInfo-list */ { struct bdgpGeneInfo *result = NULL, *this=NULL; struct dyString *query=newDyString(512); char *sep = "where"; struct slName *sn = geneNames; dyStringPrintf(query,"select * from %s",table); while(sn) { char * nm = sn->name; if (startsWith("CG",nm)) { dyStringPrintf(query," %s bdgpName='%s'",sep,nm); sep = "or"; } else if (!startsWith("FBgn",nm)) { dyStringPrintf(query," %s symbol='%s'",sep,nm); sep = "or"; } sn = sn->next; } //uglyf("
SQL=%s

\n",query->string); struct sqlConnection* conn = hAllocConn(); result = bdgpGeneInfoLoadByQuery(conn, query->string); for(this=result;this;this=this->next) { //uglyf("
adding %s=%s
\n",this->bdgpName,this->flyBaseId); // debug hashAdd(aliasHash,this->bdgpName,cloneString(this->flyBaseId)); //uglyf("
adding %s=%s
\n",this->symbol,this->flyBaseId); // debug hashAdd(aliasHash,this->symbol,cloneString(this->flyBaseId)); } // Mysterious crashes if I free this list: //bdgpGeneInfoFreeList(&result); hFreeConn(&conn); freeDyString(&query); } struct interaction *getGenesFromTable(char* table) /* read all the gene interactions from database, returns interaction-list */ { struct interaction *result = NULL; struct dyString *query=newDyString(512); char *sep = "where"; struct slName *sn = geneNames; getGeneAliasesFromTable("bdgpGeneInfo"); /* load aliases into hash */ dyStringPrintf(query,"select * from %s",table); while(sn) { struct hashEl *hel = NULL, *hf=NULL; char * nm = sn->name; char * alias = NULL; if (!startsWith("FBgn",nm)) { if (hf = hashLookup(aliasHash,nm)) { alias = sn->name; //uglyf("
aliasing %s with %s
\n",nm,(char *)hf->val); // debug nm = (char *)hf->val; } } hel = hashStore(nodeHash,nm); if (!hel->val) /* add geneList elements to the hash */ { struct node *n; struct nodelist *nl; AllocVar(n); AllocVar(nl); n->name = cloneString(nm); n->alias = cloneString(alias); n->ring = TRUE; /* this is a special ring member */ nl->node = n; slAddHead(&allNodes,nl); /* all nodes going in hash are added to all-nodes list */ hel->val = n; } dyStringPrintf(query," %s fromX='%s' or toY='%s'",sep,nm,nm); sep = "or"; sn = sn->next; } //uglyf("
SQL=%s

\n",query->string); struct sqlConnection* conn = hAllocConn(); result = interactionLoadByQuery(conn, query->string); hFreeConn(&conn); freeDyString(&query); return result; } void getGeneList() /* hgGeneRing - Gene Network Browser. */ { /* not much point in this, though called old it's the same as current at this point. It is not the old value from before the last submit. char *oldGeneList = hashFindVal(oldVars, "ring_geneList"); */ if (!sameString(errMsg,"")) { printf("
%s
\n",errMsg); } puts("
\n" "
" "\n" "
\n" "Enter gene list for gene network ring.\n" "
\n"); puts("
" "\n" "\n"); puts("\n"); puts("\n"); printf("\n"); puts("
\n"); cgiMakeTextArea("ring_geneList", geneList, 25, 30); printf("
"); cgiMakeButton("Submit", "Submit"); printf("
\n"); puts("
\n"); cartSetString(cart, "ring_action", "saveGeneList"); cartSetString(cart, "ring_errMsg", ""); } int compareNodes(const void *va, const void *vb) { const struct nodelist *a = *((struct nodelist **)va); const struct nodelist *b = *((struct nodelist **)vb); if (a->node->ring && !b->node->ring) return -1; if (!a->node->ring && b->node->ring) return 1; if (a->node->ring && b->node->ring) { return differentWord(a->node->name,b->node->name)*-1; } if (a->node->ringRank == b->node->ringRank) { return differentWord(a->node->name,b->node->name)*-1; } else { return (b->node->ringRank - a->node->ringRank); } } boolean saveGeneList(boolean showAll) /* Check for valid gene-list: parse and save. If list not ok, return to getGeneList page. Otherwise, show user's list and offer some links. */ { struct interaction* intr; struct nodelist *nl; if (!getGenesAsList()) { getGeneList(); return FALSE; } if (showAll) { puts("
" "\n" "
\n"); printf("geneList: %s
\n", geneList ); puts("
" "gene-list\n" "
" "screen\n"); puts("
\n"); } interactions = getGenesFromTable("intrP2P"); /* adds geneList elements to hash */ if (showAll) { uglyf("slCount = %d for result list for %s.

\n",slCount(interactions),geneList); } /* this might get moved later */ /* add to hash the remaining interactions members */ for(intr=interactions;intr;intr=intr->next) { //uglyf("%s %s %f.
\n",intr->fromX,intr->toY,intr->score); struct hashEl *helX = hashStore(nodeHash,intr->fromX); struct hashEl *helY = hashStore(nodeHash,intr->toY); struct node *x, *y; struct nodelist *nl; if (!helX->val) /* add X to hash for 1st time */ { AllocVar(x); AllocVar(nl); x->name = cloneString(intr->fromX); nl->node = x; slAddHead(&allNodes,nl); /* add X to list of all nodes */ helX->val = x; } if (!helY->val) /* do same stuff for Y */ { AllocVar(y); AllocVar(nl); y->name = cloneString(intr->toY); nl->node = y; slAddHead(&allNodes,nl); helY->val = y; } x = helX->val; /* get X,Y from hash */ y = helY->val; if (x->ring) y->ringRank++; /* increment ringRank counts */ if (y->ring) x->ringRank++; AllocVar(nl); nl->node = y; slAddHead(&x->xrays,nl); /* add Y to X's list of x-rays */ AllocVar(nl); nl->node = x; slAddHead(&y->nrays,nl); /* likewise */ } interactionFreeList(&interactions); slReverse(&allNodes); slSort(&allNodes, compareNodes); /* sum counts and if showAll, display our structure */ if (showAll) { uglyf("
\n");
    uglyf("name        xrays nrays  ring? ringRank \n");
    uglyf("-------------------------------------- \n");
    }
for(nl=allNodes;nl;nl=nl->next)
    {

    if (nl->node->ring)
	{
	ringCount++;
	}
    else
	{
	if (nl->node->ringRank > 1)
	    {
	    insideCount++;
	    }
	else
	    {
	    outsideCount++;
	    }
	}

    if (showAll)
	{
	uglyf("%11s %4d %4d     %4s %3d \n",
	    nl->node->name,
	    slCount(nl->node->xrays),
	    slCount(nl->node->nrays),
	    nl->node->ring ? "ring":"not!",
	    nl->node->ringRank
	    );
	}
    }

if (showAll)
    {
    uglyf("
\n"); } // TODO: add some real code for freeing these things properly // e.g. for xrays and nrays lists, free up the nodelist list itself, // but not the *node values themselves, which are allocated // in the main nodelist/hash. If the nodelist is freed up // properly then hash freeing should be easy enough. // Do we use valgrind or some other util to verify mem-release? return TRUE; } /* Count up elements in list that are outside ring. */ int slCountOutside(void *list) { struct slList *pt = (struct slList *)list; int len = 0; while (pt != NULL) { struct node *n = ((struct nodelist *)pt)->node; if ((!n->ring) && (n->ringRank==1)) len += 1; pt = pt->next; } return len; } #define NODE_SIZE 10 void addMap(struct nodelist *nl) { struct node *node = nl->node; int x=node->xpos; int y=node->ypos; int r=NODE_SIZE; char *name = node->name; if (node->alias) { name = node->alias; } printf( "\"%s\""", x,y,r, name, node->name, name, name ); } void drawScreen() /* Draw Gene Ring using given genes and interactions and display it in a page as a .gif */ { #define SCREEN_SIZE 800 #define RING_SIZE 200 #define INRING_SIZE 140 #define OUTRING_SIZE 340 struct tempName filename; int width,height; char *mapName="ring_map"; ZeroVar(&filename); makeTempName(&filename, "hgGeneRing_screen", ".gif"); printf("\n", mapName); struct memGfx *mg = mgNew(SCREEN_SIZE,SCREEN_SIZE); int i; double angle=0; int xCen = SCREEN_SIZE/2, yCen = SCREEN_SIZE/2; int x=0,y=0; struct nodelist *nl, *saveNl; /* draw the main RING */ mgCircle(mg, xCen, yCen, SCREEN_SIZE/4, MG_BLACK, FALSE); /* draw the RING genes and assign position */ angle=(M_PI*2)/ringCount; nl=allNodes; for(i=0;inode->xpos = x; nl->node->ypos = y; mgCircle(mg, x, y, NODE_SIZE, MG_BLACK, FALSE); addMap(nl); nl=nl->next; } /* draw the Inside genes, assign position, and draw rays */ angle=(M_PI*2)/insideCount; for(i=0;inode->xpos = x; nl->node->ypos = y; mgCircle(mg, x, y, NODE_SIZE, MG_BLACK, FALSE); addMap(nl); /* draw connections to ring */ { /*local*/ struct nodelist *l; for(l=nl->node->xrays;l;l=l->next) { /* blue = inward = to-ring */ mgDrawLine(mg, x, y, l->node->xpos, l->node->ypos, MG_BLUE); } for(l=nl->node->nrays;l;l=l->next) { /* red = outward = from-ring */ mgDrawLine(mg, x, y, l->node->xpos, l->node->ypos, MG_RED); } } nl=nl->next; } /* draw the Outside genes, assign position, draw rays do 1 ring member at a time. */ angle=(M_PI*2)/ringCount; nl=allNodes; for(i=0;inode->nrays); numOutside += slCountOutside(nl->node->xrays); subAngle = angle / (numOutside+1); /* add 1 to give a little space between ring groups */ /* draw connections to ring */ { /*local*/ struct nodelist *l; int j = 0; struct nodelist *rays; Color color; for (j=0;j<2;j++) { if (j==0) { color = MG_BLUE; rays = nl->node->xrays; } else { color = MG_RED; rays = nl->node->nrays; } for(l=rays;l;l=l->next) { if (l->node->ring) { /* this ring-ring line gets draw twice but that's ok */ x = l->node->xpos; y = l->node->ypos; mgDrawLine(mg, x, y, nl->node->xpos, nl->node->ypos, MG_BLACK); } else if (l->node->ringRank==1) { doneOutside++; x = xCen + (int) OUTRING_SIZE*cos((i-.5)*angle+(doneOutside*subAngle)); y = yCen + (int) OUTRING_SIZE*sin((i-.5)*angle+(doneOutside*subAngle)); l->node->xpos = x; l->node->ypos = y; mgCircle(mg, x, y, NODE_SIZE, MG_BLACK, FALSE); addMap(l); mgDrawLine(mg, x, y, nl->node->xpos, nl->node->ypos, color); } } } } nl=nl->next; } printf("\n"); mgSaveGif(mg, filename.forCgi, FALSE); width=height=SCREEN_SIZE; printf("
"); printf(""); printf(""); printf(""); printf( ""); printf("
", filename.forHtml, width, height, mapName); printf("
" "back " "gene-list " "refresh " "
"); } char *unAlias(char *gene) /* deal with alias mapping for gene names, return FBgn */ { struct hashEl *hf=NULL; if (!startsWith("FBgn",gene)) { if (hf=hashLookup(aliasHash,gene)) { gene=(char *)hf->val; } } return gene; } void drawDetails() { char *gene = cartUsualString(cart, "ring_gene", ""); char *targ = unAlias(gene); struct hashEl *hel = NULL; struct node *n; hel = hashLookup(nodeHash,targ); if (hel) { n = hel->val; printf( "Details page for gene %s " "" "%s Ring " " (rank=%d) " " return " "\n", gene, n->ring?"removeFromRing":"addToRing", gene, n->ring?"Remove From ":"Add To ", n->ringRank ); } else { printf("Unknown gene %s",gene); } } void hgGeneRing() /* hgGeneRing - Gene Network Browser. */ { char *action = cartUsualString(cart, "ring_action", ""); if (sameWord(action,"")) { action = "getGeneList"; } if (sameWord(action,"getGeneList")) { getGeneList(); } else if (sameWord(action,"saveGeneList")) { saveGeneList(TRUE); } else if (sameWord(action,"drawScreen")) { if (saveGeneList(FALSE)) drawScreen(); } else if (sameWord(action,"drawDetails")) { if (saveGeneList(FALSE)) drawDetails(); } else if (sameWord(action,"addToRing")) { char *gene = cartUsualString(cart, "ring_gene", ""); getGenesAsList(); slNameAddTail(&geneNames, gene); updateGeneList(); /* in lieue of actually just redirecting the browser */ cartSaveSession(cart); geneList = cloneString(cartUsualString(cart, "ring_geneList", "")); slFreeList(&geneNames); /* just reset everything */ if (saveGeneList(FALSE)) drawScreen(); } else if (sameWord(action,"removeFromRing")) { char *gene = cartUsualString(cart, "ring_gene", ""); struct slName **psn = &geneNames; getGenesAsList(); while(*psn) { if (sameString((*psn)->name,gene)) { *psn = (*psn)->next; break; } psn=&((*psn)->next); } updateGeneList(); /* in lieue of actually just redirecting the browser */ cartSaveSession(cart); geneList = cloneString(cartUsualString(cart, "ring_geneList", "")); slFreeList(&geneNames); /* just reset everything */ if (saveGeneList(FALSE)) drawScreen(); } else { getGeneList(); } } void doMiddle(struct cart *theCart) /* Set up pretty web display and save cart in global. */ { char *action = cgiUsualString("ring_action", ""); cart = theCart; getDbGenomeClade(cart, &db, &organism, &clade, oldVars); if (! hDbIsActive(db)) { db = hDefaultDb(); organism = hGenome(db); clade = hClade(organism); } /* temporary hack, set db to dm1 fly */ db = "dm1"; organism = "D. melanogaster"; clade = "insect"; cartSetString(cart, "db", db); cartSetString(cart, "org", organism); cartSetString(cart, "clade", clade); hSetDb(db); if (sameWord(action,"geneFrame")) { /* special handling for frameset - can't use cartWebStart etc. */ char *gene = cartUsualString(cart, "ring_gene", ""); char *position = cartUsualString(cart, "ring_position", ""); printf( "" " " " " "", gene, position, db ); } else { cartWebStart(theCart, database, "%s Gene Network Browser \n", organism); geneList = cloneString(cartUsualString(cart, "ring_geneList", "")); errMsg = cartUsualString(cart, "ring_errMsg", ""); /* any error from last time */ hgGeneRing(); cartSaveSession(cart); cartWebEnd(); } freez(&geneList); } char *excludeVars[] = {NULL}; int main(int argc, char *argv[]) /* Process command line. */ { oldVars = hashNew(10); cgiSpoof(&argc, argv); nodeHash = newHash(8); aliasHash = newHash(8); cartEmptyShell(doMiddle, hUserCookie(), excludeVars, oldVars); freeHashAndVals(&nodeHash); return 0; }