Skip to content

Commit 0a475a1

Browse files
committed
v5.7.5
Self-synteny query and display improvements
1 parent b84833d commit 0a475a1

51 files changed

Lines changed: 1844 additions & 2196 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,19 @@
1-
**Description**: SyMAP (Synteny Mapping and Analysis Program) is a software package for detecting, displaying, and querying syntenic relationships between a fully sequenced genome and (i) another sequenced genome, (ii) draft sequence, (iii) self-synteny, or (iv) FPC physical maps. It is designed for medium-to-high divergent eukaryotic genomes (not bacteria).
1+
### SyMAP (Synteny Mapping and Analysis Program) ###
22

3-
**Download SyMAP tarball**: https://github.com/csoderlund/SyMAP/releases. The SyMAP tarball contains the executable jar files, external packages and demo files.
3+
**Description**: SyMAP is a software package for detecting, displaying, and querying syntenic relationships between a fully sequenced genome and
4+
(i) another sequenced genome, (ii) draft sequence, and (iii) self-synteny. It is designed for divergent eukaryotic genomes (not bacteria).
45

5-
**Documentation**: https://csoderlund.github.io/SyMAP
6+
**Download SyMAP tarball**: https://github.com/csoderlund/SyMAP/releases. The SyMAP tarball contains the executable jar file, all necessary external software, and demo files.
67

7-
**Requirements**: Java v17 or later and MySQL. SyMAP uses [MUMmer](https://mummer4.github.io) for the sequence to sequence alignment, which requires Perl. SyMAP has been tested on Linux and MacOS.
8+
**Requirements**: Java v17 or later and MySQL (or MariaDB). SyMAP uses [MUMmer](https://mummer4.github.io) for the sequence to sequence alignment, which requires Perl.
9+
SyMAP has been tested on Linux and MacOS.
10+
11+
**To use**:
12+
1. Download the latest SyMAP tarball.
13+
2. Put the tarball in the location you want the symap_5 directory and untar it (tar xf symap_5.tar.gz).
14+
3. Follow the instructions in https://csoderlund.github.io/SyMAP/SystemGuide.html#demo to try the demo.
15+
16+
**Full Documentation**: https://csoderlund.github.io/SyMAP
817

918
**SyMAP github code**: To build, see SyMAP/java/README.
1019

java/src/backend/AlignMain.java

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
import java.util.TreeMap;
1111
import java.util.Queue;
12+
import java.util.Arrays;
1213
import java.util.Collections;
1314
import java.util.HashSet;
1415
import java.util.LinkedList;
@@ -34,7 +35,7 @@ public class AlignMain {
3435
private static final int maxFileSize = 60000000; // 'Concat' parameter works for demo using this size
3536

3637
private ProgressDialog plog;
37-
private String proj1Dir, proj2Dir; // also dbName
38+
private String proj1Dir, proj2Dir; // also dbName, directory name
3839
private Mproject mProj1, mProj2;
3940

4041
private String alignLogDirName;
@@ -140,8 +141,8 @@ public void run() {
140141
plog.msg("Alignments: success " + getNumCompleted());
141142

142143
String tmpDir = Constants.getNameTmpDir(proj1Dir, proj2Dir);// only delete tmp files if successful
143-
if (Constants.PRT_STATS) {
144-
System.out.println("Do not delete " + tmpDir);
144+
if (Globals.TRACE) {// CAS575 changed from Constants.Prt_stats
145+
Globals.prt("Do not delete " + tmpDir);
145146
}
146147
else {
147148
File dir = new File(tmpDir);
@@ -168,7 +169,7 @@ private boolean alignExists() {
168169
try {
169170
String alignDir = Constants.getNameResultsDir(proj1Dir, proj2Dir) + Constants.alignDir;
170171
File f = new File(alignDir);
171-
if (!f.exists()) return false; /*-- alignments to be done CAS571 was written .used... --*/
172+
if (!f.exists()) return false; /*-- alignments to be done ... --*/
172173

173174
boolean bdone = Utils.checkDoneFile(alignDir); // all.done
174175
nAlignDone = Utils.checkDoneMaybe(alignDir); // # existing .mum files
@@ -217,8 +218,7 @@ private void mummerParamsWrite() {
217218
alignParams += mp.getChgAlign(Mpair.FILE, true); // true, do not add command line
218219
if (Ext.isMummer4Path()) alignParams += Ext.getMummerPath() + " ";
219220

220-
//String resultDir = "./" + Constants.getNameResultsDir(mProj1.strDBName, mProj2.strDBName);
221-
File pfile = Utils.getParamsFile(resultDir,Constants.usedFile); // CAS569 use this so renamed...
221+
File pfile = Utils.getParamsFile(resultDir,Constants.usedFile);
222222
if (pfile==null) pfile = new File(resultDir,Constants.usedFile); // create
223223

224224
PrintWriter out = new PrintWriter(pfile);
@@ -231,7 +231,7 @@ private void mummerParamsWrite() {
231231
private void paramsRead(String dateTime) {
232232
try {
233233
alignParams = "Use previous " + nAlignDone + " MUMmer files " + dateTime;
234-
File pfile = Utils.getParamsFile(resultDir,Constants.usedFile); // CAS569 use this so renamed...
234+
File pfile = Utils.getParamsFile(resultDir,Constants.usedFile);
235235
if (pfile==null) return; // okay, not written yet
236236

237237
alignParams = "Use previous " + nAlignDone + " "; // completed with what is in file
@@ -250,12 +250,12 @@ private void paramsRead(String dateTime) {
250250
*/
251251
private void buildAlignments() {
252252
try {
253-
plog.msg("\nAligning " + proj1Dir + " and " + proj2Dir + " with " + nMaxCPUs + " CPUs"); // CAS568 remove mp.getAlign, but add CPU
253+
plog.msg("\nAligning " + proj1Dir + " and " + proj2Dir + " with " + nMaxCPUs + " CPUs");
254254

255255
/* create directories */
256256
// result directory (e.g. data/seq_results/demo1_to_demo2)
257257
Utilities.checkCreateDir(resultDir, true /* bPrt */);
258-
mummerParamsWrite(); // CAS571 write here after creating the directory
258+
mummerParamsWrite(); // write here after creating the directory
259259

260260
// temporary directories to put data for alignment
261261
String tmpDir = Constants.getNameTmpDir(proj1Dir, proj2Dir);
@@ -288,8 +288,8 @@ private void buildAlignments() {
288288
if (isSelf) program = Ext.exNucmer;
289289

290290
// user over-rides
291-
if (program.equals(Ext.exPromer) && mp.isNucmer(Mpair.FILE)) program = Ext.exNucmer; // CAS568 was backwards
292-
else if (program.equals(Ext.exNucmer) && mp.isPromer(Mpair.FILE)) program = Ext.exPromer; // CAS568 was backwards
291+
if (program.equals(Ext.exPromer) && mp.isNucmer(Mpair.FILE)) program = Ext.exNucmer;
292+
else if (program.equals(Ext.exNucmer) && mp.isPromer(Mpair.FILE)) program = Ext.exPromer;
293293

294294
String args = (program.contentEquals(Ext.exPromer)) ? mp.getPromerArgs(Mpair.FILE) : mp.getNucmerArgs(Mpair.FILE);
295295
String self = (isSelf) ? (" " + mp.getSelfArgs(Mpair.FILE)) : "";
@@ -300,18 +300,22 @@ private void buildAlignments() {
300300
// For self, p1=p2
301301
String alignDir = resultDir + Constants.alignDir;
302302
Utilities.checkCreateDir(alignDir, false);
303+
File[] fs1 = fh_tDir1.listFiles(); // order, not necessary, but nice; CAS575
304+
Arrays.sort(fs1);
305+
File[] fs2 = fh_tDir2.listFiles();
306+
Arrays.sort(fs2);
303307

304-
for (File f1 : fh_tDir1.listFiles()) {
308+
for (File f1 : fs1) {
305309
if (!f1.isFile() || f1.isHidden()) continue;
306310

307-
for (File f2 : fh_tDir2.listFiles()) {
311+
for (File f2 : fs2) {
308312
if (!f2.isFile() || f2.isHidden()) continue;
309313

310314
// XXX
311315
String aArgs = args;
312316
if (isSelf) { // chr files have been written as is
313317
if (f1.getName().equals(f2.getName())) aArgs += self;
314-
else if (f1.getName().compareTo(f2.getName()) < 0) continue;
318+
else if (f1.getName().compareTo(f2.getName()) < 0) continue; // AnchorMain will correct order when wrong
315319
}
316320

317321
AlignRun ps = new AlignRun(program, aArgs, f1, f2, alignDir, alignLogDirName);
@@ -321,7 +325,7 @@ private void buildAlignments() {
321325
}
322326
}
323327
if (alignList.size()>0) {
324-
Collections.sort(alignList); // CAS566 add sort and add to queue after sort
328+
Collections.sort(alignList);
325329
for (AlignRun ps : alignList) {
326330
toDoQueue.add(ps);
327331
ps.setStatus(AlignRun.STATUS_QUEUED);
@@ -330,7 +334,7 @@ private void buildAlignments() {
330334
}
331335
if (nAlignDone>0) {
332336
if (alignList.size()==0) Utils.writeDoneFile(alignDir);
333-
plog.msg("Alignments to be completed: " + alignList.size()); // CAS566 add
337+
plog.msg("Alignments to be completed: " + alignList.size());
334338
}
335339
else if (alignList.size() == 0 && !Cancelled.isCancelled()) {
336340
plog.msg("Warning: no alignments between projects");
@@ -362,7 +366,7 @@ private boolean writePreprocSeq(File dir, Mproject mProj, boolean concat, boole
362366
}
363367

364368
boolean geneMask = (mp.mProj1.getIdx() == mProj.getIdx()) ?
365-
mp.isMask1(Mpair.FILE) : mp.isMask2(Mpair.FILE); // CAS568 mask in pairs instead of proj
369+
mp.isMask1(Mpair.FILE) : mp.isMask2(Mpair.FILE);
366370
String gmprop = (geneMask) ? "Masking non-genic sequence; " : "";
367371
if (geneMask) plog.msg(projName + ": " + gmprop);
368372

@@ -377,7 +381,7 @@ private boolean writePreprocSeq(File dir, Mproject mProj, boolean concat, boole
377381
if (concat) msg += "Concatenating all sequences into one file for " + who;
378382
else msg += "Writing sequences into one or more files for " + who;
379383
}
380-
else msg += "Writing separate chromosome files for self-synteny"; // CAS568
384+
else msg += "Writing separate chromosome files for self-synteny";
381385

382386
// pseudos (files): grp_idx, fileName (e.g. chr3.seq), length
383387
// xgroups (chrs): idx, proj_idx, chr#, fullname where grp_idx is xgroups.idx
@@ -469,7 +473,7 @@ private boolean writePreprocSeq(File dir, Mproject mProj, boolean concat, boole
469473
if (interrupted) break;
470474

471475
rs = tdbc2.executeQuery("select fullname from xgroups where idx=" + gIdx);
472-
rs.next(); // CAS560 was first()
476+
rs.next();
473477
String grpFullName = rs.getString(1);
474478
fw.write(">" + grpFullName + "\n");
475479

@@ -548,11 +552,11 @@ protected int getNumRunning() {
548552
}
549553
protected int getNumRemaining() {
550554
synchronized(threads) {
551-
return toDoQueue.size(); // CAS566 don't add error (was +getNumErrors();)
555+
return toDoQueue.size();
552556
}
553557
}
554558
protected int getNumCompleted() {
555-
return alignList.size() - getNumRunning() - getNumRemaining() - getNumErrors(); // CAS566 remove errors here
559+
return alignList.size() - getNumRunning() - getNumRemaining() - getNumErrors();
556560
}
557561
protected int getNumErrors() {
558562
int count = 0;

java/src/backend/AnchorMain.java

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@
2727
* Mproj1 (arab) is query and Mproj2 (cabb) is target; target coords (cabb) comes before query (arab)
2828
*/
2929
public class AnchorMain {
30-
public boolean doAlgo1=false;
30+
public boolean doAlgo1=false;
31+
private boolean isSelf=false; // CAS575 add
3132

3233
// variables may be accessed directly by AnchorMain1 or AnchorMain2
3334
public DBconn2 dbc2;
@@ -50,9 +51,10 @@ protected boolean run(Mproject pj1, Mproject pj2) throws Exception {
5051
try {
5152
/** setup **/
5253
long startTime = Utils.getTimeMem();
54+
isSelf = pj1.getIdx()==pj2.getIdx();
5355

5456
String proj1Name = pj1.getDBName(), proj2Name = pj2.getDBName();
55-
if (proj1Name.equals(proj2Name)) plog.msg("\nStart calculating cluster hits for " + proj1Name + " self synteny"); // CAS572 add
57+
if (isSelf) plog.msg("\nStart calculating cluster hits for " + proj1Name + " self synteny");
5658
else plog.msg("\nStart calculating cluster hits for " + proj1Name + " and " + proj2Name);
5759

5860
String resultDir = Constants.getNameResultsDir(proj1Name, proj2Name); // e.g. data/seq_results/p1_to_p2
@@ -79,7 +81,7 @@ protected boolean run(Mproject pj1, Mproject pj2) throws Exception {
7981
if (Cancelled.isCancelled()) {dbc2.close(); return false; }
8082

8183
saveHitNum();
82-
saveAnnoHitCnt();
84+
saveAnnoHitCnt(true);
8385

8486
/** Run before pseudo **/
8587
if (pj1.hasGenes() && pj2.hasGenes()) {
@@ -104,6 +106,7 @@ protected boolean run(Mproject pj1, Mproject pj2) throws Exception {
104106

105107
/***************************************************************
106108
* Assign hitnum, with them ordered by start1 ASC, len DESC
109+
* isSelf: just do upper part of diagonal: only number if refidx=0
107110
*/
108111
private boolean saveHitNum() {
109112
try {
@@ -113,18 +116,21 @@ private boolean saveHitNum() {
113116

114117
for (int g1 : grpMap1.keySet()) {
115118
for (int g2 : grpMap2.keySet()) {
119+
if (isSelf && g1<g2) continue; // DIR_SELF lower diagonal
120+
116121
int nhits = dbc2.executeCount("select count(*) from pseudo_hits "
117122
+ " where grp1_idx="+ g1 + " and grp2_idx=" + g2);
118123
if (nhits==0) continue; // mysql error if 0 in next query
119124

120125
dbc2.executeUpdate("update pseudo_hits set hitnum=0 where grp1_idx=" + g1 + " and grp2_idx=" + g2);
121126

127+
// do not use grp1_idx<grp2_idx because this assumes chr01 is loaded before chr02
122128
HashMap <Integer, Integer> hitNumMap = new HashMap <Integer, Integer> ();
123-
// assign
124129
int hitcnt=1;
125130
ResultSet rs = dbc2.executeQuery("select idx, (end1-start1) as len from pseudo_hits "
126-
+ " where grp1_idx= " + g1 + " and grp2_idx=" + g2
131+
+ " where grp1_idx= " + g1 + " and grp2_idx=" + g2 + " and refidx=0" // CAS575 add refidx for isSelf
127132
+ " order by start1 ASC, len DESC");
133+
128134
while (rs.next()) {
129135
int hidx = rs.getInt(1);
130136
hitNumMap.put(hidx, hitcnt);
@@ -145,15 +151,23 @@ private boolean saveHitNum() {
145151
}
146152
}
147153
Globals.rclear();
154+
155+
if (isSelf) { // mirror hitnum for self
156+
dbc2.executeUpdate("update pseudo_hits as ph1, pseudo_hits as ph2 "
157+
+ " set ph2.hitnum=ph1.hitnum "
158+
+ " where ph1.pair_idx=" + pairIdx + " and ph2.pair_idx=" + pairIdx
159+
+ " and ph1.idx=ph2.refidx");
160+
}
148161
return true;
149162
}
150163
catch (Exception e) {ErrorReport.print(e, "compute gene hit cnts"); return false;}
151164
}
152165
/********************************************************************
153-
* Count number of hits per gene; these include all pairwise projects except self;
166+
* Count number of hits per gene; these include all pairwise projects
167+
* CAS575 this includes self, but self hits get counted for both sides of the diagonal
154168
*/
155-
public void saveAnnoHitCnt() { // public for Mpair.removePairFromDB
156-
Globals.rprt("Compute and save gene numHits");
169+
public void saveAnnoHitCnt(boolean bPrt) { // public for Mpair.removePairFromDB; add bPrt CAS575 so does not show on remove
170+
if (bPrt) Globals.rprt("Compute and save gene numHits");
157171

158172
TreeMap <Integer, String> idxList1 = mp.mProj1.getGrpIdxMap();
159173
TreeMap <Integer, String> idxList2 = mp.mProj2.getGrpIdxMap();
@@ -177,7 +191,7 @@ public boolean saveAnnotHitCnt(int grpIdx, String grpName) { // public for Mproj
177191
+ "from pseudo_annot as pa "
178192
+ "join pseudo_hits_annot as pha on pha.annot_idx = pa.idx "
179193
+ "join pseudo_hits as ph on pha.hit_idx = ph.idx "
180-
+ "where pa.type='gene' and ph.proj1_idx != ph.proj2_idx and pa.grp_idx=" + grpIdx);
194+
+ "where pa.type='gene' and pa.grp_idx=" + grpIdx); // CAS575 remove ph.proj1_idx != ph.proj2_idx
181195

182196
while (rs.next()) {
183197
int aidx = rs.getInt(1);
@@ -301,15 +315,15 @@ private boolean addPseudo() {
301315

302316
int cnt=1;
303317
for (int g1 : grpMap1.keySet()) {
304-
chrPair = mProj1.getDisplayName() + " " + mProj1.getGrpNameFromIdx(g1);
318+
chrPair = mProj1.getDisplayName() + " " + mProj1.getGrpFullNameFromIdx(g1);
305319

306320
String where = " where grp1_idx= " + g1 + " and grp2_idx IN (" + grpList2 + ") and annot1_idx=0 ";
307321

308322
if (!addPseudoGrpGrp(g1, where, "annot1_idx", 0, cnt++, grpMap1.size())) return false;
309323
}
310324
cnt=1;
311325
for (int g2 : grpMap2.keySet()) {
312-
chrPair = mProj2.getDisplayName() + " " + mProj2.getGrpNameFromIdx(g2);
326+
chrPair = mProj2.getDisplayName() + " " + mProj2.getGrpFullNameFromIdx(g2);
313327

314328
String where = " where grp1_idx IN (" + grpList1 + ") and grp2_idx=" + g2 + " and annot2_idx=0 ";
315329

@@ -363,23 +377,16 @@ private boolean addPseudoGrpGrp(int grpIdx, String where, String annoStr, int i,
363377
rs.close();
364378

365379
String dn = (i==0) ? mProj1.getDisplayName() : mProj2.getDisplayName();
366-
String chr = (i==0) ? mProj1.getGrpNameFromIdx(grpIdx) : mProj2.getGrpNameFromIdx(grpIdx);
380+
String chr = (i==0) ? mProj1.getGrpFullNameFromIdx(grpIdx) : mProj2.getGrpFullNameFromIdx(grpIdx);
367381
String msg = String.format("Pseudo %-20s Genes %,6d Start %,6d ", (dn+" "+chr), genes, geneStart);
368-
/* too much output CAS572
369-
if (Constants.VERBOSE && cntGrp==1) Utils.prtIndentNumMsgFile(plog, 1, hitGeneMap.size(), msg);
370-
if (Constants.VERBOSE && cntGrp==2) {
371-
if (maxGrp>2) msg += "...";
372-
Utils.prtIndentNumMsgFile(plog, 1, hitGeneMap.size(), msg);
373-
}
374-
else */
375382
Globals.rprt(String.format("%,5d %s", hitGeneMap.size(),msg));
376383

377384
if (hitGeneMap.size()==0) return true;
378385

379386
cntPseudo[i] += hitGeneMap.size();
380387

381388
// pseudo_annot
382-
String name= "ID=pseudo-" + mProj1.getdbAbbrev()+"-"+mProj2.getdbAbbrev() +
389+
String name= "ID=pseudo-" + mProj1.getDBName() +"-"+mProj2.getDBName() + // was abbrev, which can change; CAS575
383390
";" + annoKey[i] + "=Not annotated; ";
384391

385392
int countBatch=0, cnt=0;

0 commit comments

Comments
 (0)