import java.awt.Desktop;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.HPos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.scene.control.TextField;
import javafx.scene.control.ComboBox;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import java.awt.image.BufferedImage;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.Rectangle2D;
import javax.imageio.ImageIO;
/**
* Mutual Information of Biological Sequences
* This module is used to take two multiple sequence alignments and determine, position by position, the mutual information between the two. Alternatively, intramolecular mutual information can be found.
* @author Devin Camenares, PhD
*
* @version 12-15-16
* @since 1-19-16
*/
/*
Mutual Information of Biological Sequences
Copyright (C) 2016 Devin Camenares
This program 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 3 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, see .
*/
public final class MutualInfoBio extends Application {
private Desktop desktop = Desktop.getDesktop();
/**
* This method was written by CC and modified by DJC, based upon code from StackOverflow user Kip.
* It takes a string and writes it to a specified file, appending said file.
* The purpose of this method is to save information and results as they are generated, reducing memory load.
*
* @param content The string to be written
* @param file The destination file for the string output
*/
private void writeFile(String content, File file){
try (FileWriter fw = new FileWriter(file, true)) {
fw.write(content);//
} catch (IOException ex)
{
Logger.getLogger(MutualInfoBio.class.getName()).log(Level.SEVERE, null, ex);
}
}
/**
* This method was written by CC and modified by DJC, based upon code from StackOverflow user Kip.
* It takes a string and writes it to a specified file, appending said file.
* The purpose of this method is to save information and results as they are generated, reducing memory load.
*
* @param content The string to be written
* @param file The destination file for the string output
*/
private void writeFileN(String content, File file){
try (FileWriter fw = new FileWriter(file, true)) {
content += "" + System.lineSeparator();
fw.write(content);//
} catch (IOException ex)
{
Logger.getLogger(MutualInfoBio.class.getName()).log(Level.SEVERE, null, ex);
}
}
/**
* This method was written by CC
*
* @param file The desired file to be opened.
*/
private void openFile(File file) {
try {
desktop.open(file);
} catch (IOException ex) {
Logger.getLogger(
MutualInfoBio.class.getName()).log(
Level.SEVERE, null, ex
);
}
}
// Configures the File Chooser, from Oracle Documentation Example 26-5
private static void configureFileChooser(
final FileChooser fileChooser) {
fileChooser.setTitle("View Files");
fileChooser.setInitialDirectory(
new File(System.getProperty("user.dir"))
);
fileChooser.getExtensionFilters().addAll(
new FileChooser.ExtensionFilter("Plain Text", "*.txt"),
new FileChooser.ExtensionFilter("FASTA", "*.fasta"),
new FileChooser.ExtensionFilter("Rich Text Format", "*.rtf"),
new FileChooser.ExtensionFilter("All Files", "*.*")
);
}
// Initialize All Global Variables, containers
/**
* Container for first file information / path
*/
File file1 = new File("");
/**
* Container for second file information / path
*/
File file2 = new File("");
/**
* String to hold name of the first file loaded
*/
public static String flName1 = "";
/**
* String to hold name of the second file loaded
*/
public static String flName2 = "";
/**
* String to hold path of the first file loaded
*/
public static String flPath1 = "";
/**
* String to hold path of the second file loaded
*/
public static String flPath2 = "";
/**
* Display text of the grouped protein category, representing selection of String protgr
*/
public static String protgrCat = "Protein, Grouped";
/**
* Display text of the individual amino acid category, representing selection of string aa
*/
public static String aaCat = "Protein";
/**
* Display text of the individual DNA residue category, representing selection of string dna
*/
public static String dnaCat = "DNA";
/**
* Display text of the individual RNA residue category, representing selection of string rna
*/
public static String rnaCat = "RNA";
/**
* Display text of the choice for a custom category
*/
public static String customCat = "Custom Category";
/**
* Amino acid residue grouping based on chemical properties, separated by comma
*/
public static String protgr = "MC, VIAL, DE, KR, FWY, TSNQ, H, P, G, -X";
/**
* Amino acid residue grouping
*/
public static String aa = "M, C, V, I, A, L, D, E, K, R, F, W, Y, T, S, N, Q, H, P, G, -X";
/**
* DNA nucleotide residue grouping
*/
public static String dna = "A, G, T, C, N-";
/**
* RNA nucleotide residue grouping
*/
public static String rna = "A, G, U, C, N-";
/**
* Generic counter for determining number of residue pairs analyzed
*/
public static int zcount = 0;
/**
* Initial system time
*/
final long timeID = System.currentTimeMillis();
/**
* Initial unique ID, based on system time upon loading
*/
public String uniqueID = Long.toString(timeID);
/**
* Counter for number of sequences
*/
public static int seqCount = 0;
/**
* Selection to report the instance of each possible combination at any given residue pair
*/
public static boolean pairData = false;
/**
* Selection to signify comparison is intramolecular, and that MI should equal zero when x = y
*/
public static boolean intraMol = false;
/**
* Verification that the first file has been loaded
*/
public boolean chosenFile1 = false;
/**
* Verification that the second file has been loaded
*/
public boolean chosenFile2 = false;
@Override
public void start(final Stage stage) {
stage.setTitle("Biological Mutual Information");
// Initialize Filechooser, Buttons
final FileChooser fileChooser = new FileChooser();
final Button openButton1 = new Button("Open Sequence File");
final Button openButton2 = new Button("Open Sequence File");
final Button processingButton = new Button("Process File");
final Button idButton = new Button("New Unique ID");
// Initialize Gridpane
final GridPane inputGridPane = new GridPane();
// Set Master Style Strings
String bigText = "-fx-font: 35px Tahoma";
// Initialize Texts. Contributed by Christopher Camenares, with Modification
Text lbl1 = new Text(" Sequence Collection 1 ");
lbl1.setStyle(bigText);
Text lbl2 = new Text(System.lineSeparator() + " Sequence Collection 2 ");
lbl2.setStyle(bigText);
Text lbl3 = new Text("No File Loaded");
Text lbl4 = new Text("No File Loaded");
Text lbl5 = new Text("Presets");
Text lbl6 = new Text("Presets");
Text lbl7 = new Text(System.lineSeparator() + "Output Parameters");
lbl7.setStyle(bigText);
Text lbl8 = new Text("Job ID#: ");
Text lbl9 = new Text(" Data Submission ");
lbl9.setStyle(bigText);
Text statusLbl = new Text(System.lineSeparator() + "Program Awaiting Input");
// Initialize ComboBoxes. Contributed by Christopher Camenares, with Modification
final ComboBox comboBox1;
comboBox1 = new ComboBox();
comboBox1.getItems().addAll(protgrCat, aaCat, dnaCat, rnaCat, customCat);
comboBox1.setMinWidth(50);
comboBox1.setMinHeight(25);
comboBox1.setValue(protgrCat);
final ComboBox comboBox2;
comboBox2 = new ComboBox();
comboBox2.getItems().addAll(protgrCat, aaCat, dnaCat, rnaCat, customCat);
comboBox2.setMinWidth(50);
comboBox2.setMinHeight(25);
comboBox2.setValue(protgrCat);
HBox comboBoxSection1;
comboBoxSection1 = new HBox();
comboBoxSection1.setSpacing(10);
comboBoxSection1.getChildren().addAll(comboBox1);
HBox comboBoxSection2;
comboBoxSection2 = new HBox();
comboBoxSection2.setSpacing(10);
comboBoxSection2.getChildren().addAll(comboBox2);
// Initialize Text Fields, for adding Categories or JobID. Contributed by Christopher Camenares
TextField txtField1;
txtField1 = new TextField();
txtField1.setText("Enter Custom");
txtField1.setMinWidth(200);
TextField txtField2;
txtField2 = new TextField();
txtField2.setText("Enter Custom");
txtField2.setMinWidth(200);
TextField txtField3;
txtField3 = new TextField();
txtField3.setText(uniqueID);
txtField3.setMinWidth(100);
TextField txtField4;
txtField4 = new TextField();
txtField4.setText("5");
txtField4.setMaxWidth(100);
TextField txtField5;
txtField5 = new TextField();
txtField5.setText("1");
txtField5.setMaxWidth(100);
// Correction Options: APC, RCW, etc
Text lbl11 = new Text("Which Data to Output:");
CheckBox chck1;
chck1 = new CheckBox("Sort Scores - Default");
chck1.setSelected(true);
CheckBox chck2;
chck2 = new CheckBox("APC");
CheckBox chck3;
chck3 = new CheckBox("RCW");
CheckBox chck5;
chck5 = new CheckBox("All Pair Data");
CheckBox chck4;
chck4 = new CheckBox("Triplet Calculation");
CheckBox chck6;
chck6 = new CheckBox("Substract Shuffled Sequence");
CheckBox chck7;
chck7 = new CheckBox("Substract Shuffled Sequence");
CheckBox chck8;
chck8 = new CheckBox("Substract Shuffled Order, Iterative");
CheckBox chck9;
chck9 = new CheckBox("Save Shuffled Sequences");
CheckBox chck10;
chck10 = new CheckBox("Save Shuffled Sequences");
Text lbl12 = new Text("Heatmap Cell Size (Pixels):");
// Setup the Grid, Populate with items
//Header 1
inputGridPane.add(lbl1, 0, 0);
inputGridPane.setColumnSpan(lbl1, 2);
inputGridPane.setHalignment(lbl1, HPos.CENTER);
//Open Button 1
inputGridPane.add(openButton1, 0, 1);
//Open Button 2
inputGridPane.add(openButton2, 0, 5);
//Did Button 1 work?
inputGridPane.add(lbl3, 1, 1);
inputGridPane.setColumnSpan(lbl3, 2);
//Did Button 2 work?
inputGridPane.add(lbl4, 1, 5);
inputGridPane.setColumnSpan(lbl4, 2);
//Header 2
inputGridPane.add(lbl2, 0, 4);
inputGridPane.setColumnSpan(lbl2, 2);
inputGridPane.setHalignment(lbl2, HPos.CENTER);
//Presets
// inputGridPane.add(lbl5, 0, 2);
//Categories 1
inputGridPane.add(comboBoxSection1, 0, 2);
//Presets
// inputGridPane.add(lbl6, 0, 6);
//Categories 2
inputGridPane.add(comboBoxSection2, 0, 6);
//Custom Categories
inputGridPane.add(txtField1, 1, 2);
// inputGridPane.setColumnSpan(txtField1, 2);
// Shuffle DNA 1
inputGridPane.add(chck6, 0, 3);
inputGridPane.add(chck9, 1, 3);
// Shuffle DNA 2
inputGridPane.add(chck7, 0, 7);
inputGridPane.add(chck10, 1, 7);
//Custom Categories
inputGridPane.add(txtField2, 1, 6);
// inputGridPane.setColumnSpan(txtField2, 2);
//Output
inputGridPane.add(lbl7, 0, 8);
inputGridPane.setColumnSpan(lbl7, 2);
inputGridPane.setHalignment(lbl7, HPos.CENTER);
//Correction
inputGridPane.add(lbl11, 0, 9);
inputGridPane.add(chck1, 0, 10);
inputGridPane.add(chck2, 0, 11);
inputGridPane.add(chck3, 0, 12);
inputGridPane.add(chck5, 0, 13);
//Graphics
inputGridPane.add(lbl12, 1, 9);
inputGridPane.add(txtField4, 1, 10);
// Triplet Scoring
inputGridPane.add(chck4, 1, 11);
// Shuffle Organism 1 (Sufficient vs other collection)
inputGridPane.add(chck8, 1, 12);
// Shuffle Iteration
inputGridPane.add(txtField5, 1, 13);
//Submission
inputGridPane.add(lbl9, 0, 14);
inputGridPane.setColumnSpan(lbl9, 2);
inputGridPane.setHalignment(lbl9, HPos.CENTER);
//Job ID Label
inputGridPane.add(lbl8, 0, 15);
inputGridPane.setHalignment(lbl8, HPos.RIGHT);
//Job ID Entry
inputGridPane.add(txtField3, 1, 15);
//ID Button
inputGridPane.add(idButton, 0, 16);
inputGridPane.setColumnSpan(idButton, 2);
inputGridPane.setHalignment(idButton, HPos.CENTER);
//Status Update
inputGridPane.add(statusLbl, 0, 17);
inputGridPane.setColumnSpan(statusLbl, 2);
inputGridPane.setHalignment(statusLbl, HPos.CENTER);
//Process Button
inputGridPane.add(processingButton, 0, 18);
inputGridPane.setColumnSpan(processingButton, 2);
inputGridPane.setHalignment(processingButton, HPos.CENTER);
inputGridPane.setHgap(25);
inputGridPane.setVgap(5);
final Pane rootGroup = new VBox(15);
rootGroup.getChildren().addAll(inputGridPane);
rootGroup.setPadding(new Insets(25, 25, 25, 25));
// Button to Generate New ID
idButton.setOnAction(
new EventHandler() {
@Override
public void handle(final ActionEvent e) {
final long timeButton = System.currentTimeMillis();
txtField3.setText(Long.toString(timeButton));
}
}
);
// Hanlde Events for Opening File#1, read into program as String
openButton1.setOnAction(
new EventHandler() {
@Override
public void handle(final ActionEvent e) {
configureFileChooser(fileChooser);
file1 = fileChooser.showOpenDialog(stage);
if (file1 != null) {
flName1 = file1.getName();
flPath1 = file1.getPath();
lbl3.setText(flName1);
statusLbl.setText("File 1 Loaded, Awaiting File 2");
chosenFile1 = true;
if (chosenFile2){
statusLbl.setText(System.lineSeparator() + "Two Files loaded, Ready to Process!");
}
}
}
});
// Hanlde Events for Opening File#2, read into program as String
openButton2.setOnAction(
new EventHandler() {
@Override
public void handle(final ActionEvent e) {
configureFileChooser(fileChooser);
file2 = fileChooser.showOpenDialog(stage);
if (file2 != null) {
flName2 = file2.getName();
flPath2 = file2.getPath();
lbl4.setText(flName2);
statusLbl.setText("File 2 Loaded, Awaiting File 1");
chosenFile2 = true;
if (chosenFile1){
statusLbl.setText(System.lineSeparator() + "Two Files loaded, Ready to Process!");
}
}
}
});
// Hanlde Events for Calculations and Saving the File
processingButton.setOnAction(
new EventHandler() {
@Override
public void handle(final ActionEvent e) {
boolean reportMI = chck1.isSelected();
boolean reportAPC = chck2.isSelected();
boolean reportRCW = chck3.isSelected();
boolean tripletZ = chck4.isSelected();
boolean shuffleSeq1 = chck6.isSelected();
boolean shuffleSeq2 = chck7.isSelected();
boolean shuffleOrg1 = chck8.isSelected();
boolean saveShuf1 = chck9.isSelected();
boolean saveShuf2 = chck10.isSelected();
pairData = chck5.isSelected();
int processCount = 1;
/**
* Beginning timestamp to track processing time
*/
final long timeStart = System.currentTimeMillis();
// Interpret category choice and identity, with user input specified
String catA1 = catSwitch(comboBox1.getValue(), txtField1.getText());
String catB1 = catSwitch(comboBox2.getValue(), txtField2.getText());
// Interpret user choice regarding shuffling
int shuffleIt1 = Integer.parseInt(txtField5.getText());
// Interpret user choice regarding graphical interface
int pixelSize = Integer.parseInt(txtField4.getText());
// Initialize temp. string variable
String reporter = "";
// Get new name for directory, initialize directory
String dirName = txtField3.getText();
File dir = new File(dirName);
dir.mkdir();
File dir_sub = null;
String dir_subName = null;
//Initalize final files
/**
* Recipient file for runtime and processing information
*/
File fileRun = new File(dirName + "\\Runtime_Info_" + dirName + ".txt");
/**
* Recipient file for raw MI scores from comparing collection A against collection B
*/
File fRawMIxy = new File(dirName + "\\rawMIxy" + ".txt");
/**
* Recipient file for raw MI scores from comparing collection A against itself
*/
File fRawMIx = new File(dirName + "\\rawMIx" + ".txt");
/**
* Recipient file for raw MI scores from comparing collection B against itself
*/
File fRawMIy = new File(dirName + "\\rawMIy" + ".txt");
/**
* Recipient file for sorted MI scores from comparing collection A against collection B
*/
File fSortMIxy = new File(dirName + "\\sortedMIxy" + ".txt");
/**
* Recipient file for sorted MI scores from comparing collection A against itself
*/
File fSortMIx = new File(dirName + "\\sortedMIx" + ".txt");
/**
* Recipient file for sorted MI scores from comparing collection B against itself
*/
File fSortMIy = new File(dirName + "\\sortedMIy" + ".txt");
// If pair data is selected, initialize the file
if (pairData)
{
String[] tempCatA = catA1.split(", ");
String[] tempCatB = catB1.split(", ");
ArrayList tempCatCombo = new ArrayList<>();
for (String tempCatA1 : tempCatA) {
for (String tempCatB1 : tempCatB) {
tempCatCombo.add(tempCatA1 + "%" + tempCatB1);
}
}
reporter = "\t" + "\t" + "\t";
for (String tempCatCombo1 : tempCatCombo) {
reporter += tempCatCombo1 + "\t";
}
writeFileN(reporter, fRawMIxy);
}
// Convert category string into array
char[][] catA2 = formatCat(catA1);
char[][] catB2 = formatCat(catB1);
statusLbl.setText(System.lineSeparator() + "Processing Incomplete: Please Standby or Restart");
// End of common code for processing run
// If only file 2 is selected
if (file1 == null & file2 != null)
{
file1 = file2;
file2 = null;
chosenFile1 = true;
chosenFile2 = false;
if (shuffleSeq2 && !shuffleSeq1)
{
shuffleSeq1 = true;
shuffleSeq2 = false;
}
if (saveShuf2 && !saveShuf1)
{
saveShuf1 = true;
saveShuf2 = false;
}
}
// If only 1 file is selected
if (chosenFile1 && !chosenFile2)
{
intraMol = true;
char[][] seqA1 = null;
int[][][] seqA2 = null;
seqA1 = formatFasta(file1);
int countSeqA = seqCount;
seqA2 = ccSeq(seqA1, catA2);
double[][][] arrayMIx = mutualInfo(seqA2, seqA2, true, true, fRawMIx);
drawHeatMap(arrayMIx[0], dirName + "\\heatmapMIx.PNG", pixelSize, "gray");
if(reportMI)
{
sortReport(arrayMIx[0], fSortMIx);
}
String res1 = "";
if(reportAPC)
{
dir_subName = dirName + "\\APCx";
dir_sub = new File(dir_subName);
dir_sub.mkdir();
apcProcess(arrayMIx, dir_subName, seqA2[0].length, seqA2[0].length, pixelSize);
}
if(reportRCW)
{
dir_subName = dirName + "\\RCWx";
dir_sub = new File(dir_subName);
dir_sub.mkdir();
rcwProcess(arrayMIx, dir_subName, seqA2[0].length, seqA2[0].length, pixelSize);
}
// Initiate shuffle / background routine
if (shuffleSeq1)
{
//Initialize Files
/**
* Recipient file for raw MI scores from comparing collection A against itself, shuffle subtracted
*/
dir_subName = dirName + "\\shuffleX";
dir_sub = new File(dir_subName);
dir_sub.mkdir();
File fSortMIxShSub = new File(dirName + "\\sortedMIxShuffle" + ".txt");
File fRawMIxShSub = new File(dirName + "\\rawMIxShuffle" + ".txt");
countSeqA = seqCount;
char[][] seqA1s = null;
double shuffleIt1D = (double)shuffleIt1;
double[][][] arrayMIxS1 = arrayMIx;
for (int sh = 0; sh < shuffleIt1; sh++)
{
File fRawMIxShN = new File(dir_sub + "\\rawMIxShuffle_" + sh + ".txt");
File fSortMIxShN = new File(dir_sub + "\\sortedMIxShuffle_" + sh + ".txt");
// Generate Shuffle, substract shuffle
seqA1s = new char[seqA1.length][seqA1[0].length];
for (int i = 0; i < seqA1.length; i++)
{
int shuffleArr[] = shuffleRandom(seqA1[i].length);
for (int j = 0; j < shuffleArr.length; j++)
{
int newPosition = shuffleArr[j];
seqA1s[i][j] = seqA1[i][newPosition];
}
}
seqA2 = ccSeq(seqA1s, catA2);
double[][][] arrayMIxS2 = mutualInfo(seqA2, seqA2, true, saveShuf1, fRawMIxShN);
if(reportMI && saveShuf1)
{
sortReport(arrayMIxS2[0], fSortMIxShN);
}
arrayMIxS1 = average3Darr(arrayMIxS1, arrayMIxS2, sh);
}
arrayMIx = subtract3Darr(arrayMIx, arrayMIxS1);
write2Darr(arrayMIx[0], fRawMIxShSub);
drawHeatMap(arrayMIx[0], dirName + "\\heatmapMIx_shuffle_subtracted.PNG", pixelSize, "gray");
if(reportMI)
{
sortReport(arrayMIx[0], fSortMIxShSub);
}
res1 = "";
if(reportAPC)
{
dir_subName = dirName + "\\APCx_" + "_subtract_shuffle";
dir_sub = new File(dir_subName);
dir_sub.mkdir();
apcProcess(arrayMIx, dir_subName, seqA2[0].length, seqA2[0].length, pixelSize);
}
if(reportRCW)
{
dir_subName = dirName + "\\RCWx_" + "_subtract_shuffle";
dir_sub = new File(dir_subName);
dir_sub.mkdir();
rcwProcess(arrayMIx, dir_subName, seqA2[0].length, seqA2[0].length, pixelSize);
}
}
// Get final runtime statistics
final long timeEnd = System.currentTimeMillis();
long runMinutesL = (timeEnd - timeStart) / 60000;
int runMinutesI = (int) runMinutesL;
String runRep = "Job ID#: " + dirName;
runRep += System.lineSeparator();
runRep += System.lineSeparator();
runRep += Long.toString(timeEnd - timeStart) + " milliseconds of processing time";
runRep += System.lineSeparator();
runRep += "- or about " + Integer.toString(runMinutesI) + " minutes";
runRep += System.lineSeparator();
runRep += System.lineSeparator();
runRep += "Source file 1: " + flPath1 + ", contained " + countSeqA + " sequences, aligned to a length of " + Integer.toString(seqA2[0].length);
runRep += System.lineSeparator();
runRep += "Analyzed with category identities: " + catA1;
runRep += System.lineSeparator();
runRep += System.lineSeparator();
runRep += zcount + " total residue pairs analyzed";
if(shuffleSeq1)
{
runRep += System.lineSeparator();
runRep += shuffleIt1 + " iterations of shuffling subtracted from sequence";
}
// Save runtime information
writeFile(runRep, fileRun);
openFile(dir);
statusLbl.setText(System.lineSeparator() + "Processing Complete! Ready for new input.");
}
// If both files are selected, proceed with full routine.
else if (chosenFile1 && chosenFile2)
{
// Initialize all variables
char[][] seqA1 = null;
char[][] seqB1 = null;
int[][][] seqA2 = null;
int[][][] seqB2 = null;
// Read and process file 1
seqA1 = formatFasta(file1);
int countSeqA = seqCount;
seqA2 = ccSeq(seqA1, catA2);
// Read and process file 2
seqB1 = formatFasta(file2);
int countSeqB = seqCount;
seqB2 = ccSeq(seqB1, catB2);
double[][][] arrayMIx = mutualInfo(seqA2, seqA2, true, true, fRawMIx);
double[][][] arrayMIy = mutualInfo(seqB2, seqB2, true, true, fRawMIy);
double[][][] arrayMIxy = mutualInfo(seqA2, seqB2, false, true, fRawMIxy);
if(tripletZ)
{
/**
* Recipient File for Triplet Calculations
*/
File fRawMIxyz = new File(dirName + "\\rawMIxyz" + ".txt");
/**
* Recipient File for Triplet Calculations
*/
File fSortMIxyz = new File(dirName + "\\sortedMIxyz" + ".txt");
double[][] arrayMIxyZ = new double[seqA2[0].length][seqB2[0].length];
arrayMIxyZ = dumdoub2Darr(arrayMIxyZ);
for (int i = 0; i < arrayMIxyZ.length; i++)
{
for (int j = 0; j < arrayMIxyZ[i].length; j++)
{
arrayMIxyZ[i][j] = arrayMIxy[0][i][j] / (arrayMIx[1][0][i] * arrayMIy[2][0][j]);
if(arrayMIx[1][0][i] == 0 || arrayMIy[2][0][j] == 0)
{
arrayMIxyZ[i][j] = 0.0;
}
String zRep = Integer.toString(i + 1) + "\t" + Integer.toString(j + 1) + "\t" + String.format("%.10f", arrayMIxyZ[i][j]);
writeFileN(zRep, fRawMIxyz);
}
}
if(reportMI)
{
sortReport(arrayMIxyZ, fSortMIxyz);
}
drawHeatMap(arrayMIxyZ, dirName + "\\heatmapMIxyZ.PNG", pixelSize, "red");
}
// sortReport, Draw Heatmaps
if(reportMI)
{
sortReport(arrayMIx[0], fSortMIx);
sortReport(arrayMIy[0], fSortMIy);
sortReport(arrayMIxy[0], fSortMIxy);
}
drawHeatMap(arrayMIx[0], dirName + "\\heatmapMIx.PNG", pixelSize, "gray");
drawHeatMap(arrayMIy[0], dirName + "\\heatmapMIy.PNG", pixelSize, "gray");
drawHeatMap(arrayMIxy[0], dirName + "\\heatmapMIxy.PNG", pixelSize, "green");
if(reportAPC)
{
dir_subName = dirName + "\\APCx";
dir_sub = new File(dir_subName);
dir_sub.mkdir();
apcProcess(arrayMIx, dir_subName, seqA2[0].length, seqA2[0].length, pixelSize);
dir_subName = dirName + "\\APCy";
dir_sub = new File(dir_subName);
dir_sub.mkdir();
apcProcess(arrayMIy, dir_subName, seqB2[0].length, seqB2[0].length, pixelSize);
dir_subName = dirName + "\\APCxy";
dir_sub = new File(dir_subName);
dir_sub.mkdir();
apcProcess(arrayMIxy, dir_subName, seqA2[0].length, seqB2[0].length, pixelSize);
}
if(reportRCW)
{
dir_subName = dirName + "\\RCWx";
dir_sub = new File(dir_subName);
dir_sub.mkdir();
rcwProcess(arrayMIx, dir_subName, seqA2[0].length, seqA2[0].length, pixelSize);
dir_subName = dirName + "\\RCWy";
dir_sub = new File(dir_subName);
dir_sub.mkdir();
rcwProcess(arrayMIy, dir_subName, seqB2[0].length, seqB2[0].length, pixelSize);
dir_subName = dirName + "\\RCWxy";
dir_sub = new File(dir_subName);
dir_sub.mkdir();
rcwProcess(arrayMIxy, dir_subName, seqA2[0].length, seqB2[0].length, pixelSize);
}
// Initiate shuffle / background routine
if (shuffleSeq1 || shuffleSeq2 || shuffleOrg1)
{
//Initialize Files
/**
* Recipient file for raw MI scores from comparing collection A against itself, shuffle subtracted
*/
dir_subName = dirName + "\\shuffleX_XY";
dir_sub = new File(dir_subName);
dir_sub.mkdir();
File fRawMIxShSub = new File(dirName + "\\RawMIxShuffleSub" + ".txt");
File fRawMIyShSub = new File(dirName + "\\RawMIyShuffleSub" + ".txt");
File fRawMIxyShSub = new File(dirName + "\\RawMIxyShuffleSub" + ".txt");
File fSortMIxShSub = new File(dirName + "\\sortedMIxShuffleSub" + ".txt");
File fSortMIyShSub = new File(dirName + "\\sortedMIyShuffleSub" + ".txt");
File fSortMIxyShSub = new File(dirName + "\\sortedMIxyShuffleSub" + ".txt");
countSeqA = seqCount;
char[][] seqA1s = null;
char[][] seqB1s = null;
double shuffleIt1D = (double)shuffleIt1;
double[][][] arrayMIxS1 = new double[arrayMIx.length][][];
arrayMIxS1 = clone3Darr(arrayMIx);
double[][][] arrayMIyS1 = new double[arrayMIy.length][][];
arrayMIyS1 = clone3Darr(arrayMIy);
double[][][] arrayMIxyS1 = new double[arrayMIxy.length][][];
arrayMIxyS1 = clone3Darr(arrayMIxy);
for (int sh = 0; sh < shuffleIt1; sh++)
{
File fRawMIxShN = new File(dir_sub + "\\rawMIxShuffle_" + sh + ".txt");
File fSortMIxShN = new File(dir_sub + "\\sortedMIxShuffle_" + sh + ".txt");
File fRawMIyShN = new File(dir_sub + "\\rawMIyShuffle_" + sh + ".txt");
File fSortMIyShN = new File(dir_sub + "\\sortedMIyShuffle_" + sh + ".txt");
File fRawMIxyShN = new File(dir_sub + "\\rawMIxyShuffle_" + sh + ".txt");
File fSortMIxyShN = new File(dir_sub + "\\sortedMIxyShuffle_" + sh + ".txt");
// Generate Shuffle, substract shuffle
seqA1s = new char[seqA1.length][seqA1[0].length];
seqB1s = new char[seqB1.length][seqB1[0].length];
if(shuffleSeq1)
{
for (int i = 0; i < seqA1.length; i++)
{
int shuffleArr[] = shuffleRandom(seqA1[i].length);
for (int j = 0; j < shuffleArr.length; j++)
{
int newPosition = shuffleArr[j];
seqA1s[i][j] = seqA1[i][newPosition];
}
}
}
else
{
seqA1s = seqA1;
}
if(shuffleSeq2)
{
for (int i = 0; i < seqB1.length; i++)
{
int shuffleArr[] = shuffleRandom(seqB1[i].length);
for (int j = 0; j < shuffleArr.length; j++)
{
int newPosition = shuffleArr[j];
seqB1s[i][j] = seqB1[i][newPosition];
}
}
}
else
{
seqB1s = seqB1;
}
int shuffSize = Math.min(seqA1.length, seqB1.length);
if(shuffleOrg1)
{
int shuffleArr[] = shuffleRandom(shuffSize);
for (int i = 0; i < shuffleArr.length; i++)
{
int newPosition = shuffleArr[i];
seqA1s[i] = seqA1s[newPosition];
seqB1s[i] = seqB1s[newPosition];
}
}
seqA2 = ccSeq(seqA1s, catA2);
seqB2 = ccSeq(seqB1s, catB2);
double[][][] arrayMIxS2 = mutualInfo(seqA2, seqA2, true, saveShuf1, fRawMIxShN);
double[][][] arrayMIyS2 = mutualInfo(seqB2, seqB2, true, saveShuf2, fRawMIyShN);
double[][][] arrayMIxyS2 = mutualInfo(seqA2, seqB2, false, (saveShuf1 || saveShuf2), fRawMIxyShN);
if(reportMI && saveShuf1)
{
sortReport(arrayMIxS2[0], fSortMIxShN);
}
if(reportMI && saveShuf2)
{
sortReport(arrayMIyS2[0], fSortMIyShN);
}
if(reportMI && (saveShuf1 || saveShuf2))
{
sortReport(arrayMIxyS2[0], fSortMIxyShN);
}
arrayMIxS1 = average3Darr(arrayMIxS1, arrayMIxS2, (sh + 1));
arrayMIyS1 = average3Darr(arrayMIyS1, arrayMIyS2, (sh + 1));
arrayMIxyS1 = average3Darr(arrayMIxyS1, arrayMIxyS2, (sh + 1));
}
arrayMIx = subtract3Darr(arrayMIx, arrayMIxS1);
arrayMIy = subtract3Darr(arrayMIy, arrayMIyS1);
arrayMIxy = subtract3Darr(arrayMIxy, arrayMIxyS1);
write2Darr(arrayMIx[0], fRawMIxShSub);
write2Darr(arrayMIy[0], fRawMIyShSub);
write2Darr(arrayMIxy[0], fRawMIxyShSub);
drawHeatMap(arrayMIx[0], dirName + "\\heatmapMIx_shuffle_subtracted.PNG", pixelSize, "gray");
drawHeatMap(arrayMIy[0], dirName + "\\heatmapMIy_shuffle_subtracted.PNG", pixelSize, "gray");
drawHeatMap(arrayMIxy[0], dirName + "\\heatmapMIxy_shuffle_subtracted.PNG", pixelSize, "blue");
if(reportMI)
{
sortReport(arrayMIx[0], fSortMIxShSub);
sortReport(arrayMIy[0], fSortMIyShSub);
sortReport(arrayMIxy[0], fSortMIxyShSub);
}
if(reportAPC)
{
dir_subName = dirName + "\\APC" + "_subtract_shuffle";
dir_sub = new File(dir_subName);
dir_sub.mkdir();
apcProcess(arrayMIx, dir_subName, seqA2[0].length, seqA2[0].length, pixelSize);
apcProcess(arrayMIy, dir_subName, seqB2[0].length, seqB2[0].length, pixelSize);
apcProcess(arrayMIxy, dir_subName, seqA2[0].length, seqB2[0].length, pixelSize);
}
if(reportRCW)
{
dir_subName = dirName + "\\RCW" + "_subtract_shuffle";
dir_sub = new File(dir_subName);
dir_sub.mkdir();
rcwProcess(arrayMIx, dir_subName, seqA2[0].length, seqA2[0].length, pixelSize);
rcwProcess(arrayMIy, dir_subName, seqB2[0].length, seqB2[0].length, pixelSize);
rcwProcess(arrayMIxy, dir_subName, seqA2[0].length, seqB2[0].length, pixelSize);
}
}
// Get final runtime statistics
final long timeEnd = System.currentTimeMillis();
long runMinutesL = (timeEnd - timeStart) / 60000;
int runMinutesI = (int) runMinutesL;
String runRep = "Job ID#: " + dirName;
runRep += System.lineSeparator();
runRep += System.lineSeparator();
runRep += Long.toString(timeEnd - timeStart) + " milliseconds of processing time";
runRep += System.lineSeparator();
runRep += "- or about " + Integer.toString(runMinutesI) + " minutes";
runRep += System.lineSeparator();
runRep += System.lineSeparator();
runRep += "Source file 1: " + flPath1 + ", contained " + countSeqA + " sequences, aligned to a length of " + Integer.toString(seqA2[0].length);
runRep += System.lineSeparator();
runRep += "Analyzed with category identities: " + catA1;
runRep += System.lineSeparator();
runRep += System.lineSeparator();
runRep += "Source file 2: " + flPath2 + ", contained " + countSeqB + " sequences, aligned to a length of " + Integer.toString(seqB2[0].length);
runRep += System.lineSeparator();
runRep += "Analyzed with category identities: " + catB1;
runRep += System.lineSeparator();
runRep += System.lineSeparator();
runRep += zcount + " total residue pairs analyzed";
if(shuffleSeq1 || shuffleSeq2 || shuffleOrg1)
{
runRep += System.lineSeparator();
runRep += shuffleIt1 + " iterations of shuffling subtracted from sequence";
}
// Save runtime information
writeFile(runRep, fileRun);
openFile(dir);
statusLbl.setText(System.lineSeparator() + "Processing Complete! Ready for new input.");
}
else
{
txtField1.setText("Input parameters undefined");
}
}
});
stage.setScene(new Scene(rootGroup));
stage.show();
}
// Main Method, Launch Program
public static void main(String[] args) {
Application.launch(args);
}
// Group String Array into String, line Separator (Used for Debugging)
private static String arrStr(String[] strArr){
StringBuilder strBuilder = new StringBuilder();
for (int i = 0; i < strArr.length; i++)
{
strBuilder.append(strArr[i]);
strBuilder.append(System.lineSeparator());
}
String newString = strBuilder.toString();
return newString;
}
// Group 2D char Array into Strings, line Separator for 1st Dimension (Used for Debugging)
private static String arr2Dstr(char[][] strArr){
String res = new String();
for (int i = 0; i < strArr.length; i++)
{
String inter = new String(strArr[i]);
res += inter;
res += System.lineSeparator();
}
return res;
}
// Format Sequences and Create Array; splitting by sequence; then, flip position & organism dimensions
private static char[][] formatFasta(File fileA){
/**
* Boolean to determine if new sequence body should be added
*/
boolean addBody = false;
/**
* Temporary container to hold or build the sequence body from lines
*/
String seqBody = "";
seqCount = 0;
ArrayList seqArr = new ArrayList<>();
try (BufferedReader br = new BufferedReader(new FileReader(fileA))) {
String line;
while ((line = br.readLine()) != null) {
// process the line.
if (line.contains(">") && addBody)
{
//Process preceeding sequence
seqArr.add(seqBody);
// Reset Parameters
addBody = false;
seqBody = "";
}
if (line.contains(">"))
{
addBody = true;
seqCount++;
}
else if (addBody)
{
seqBody += line.toUpperCase();
}
}
// This code is for the last sequence block in collection 2
if (addBody)
{
//Process preceeding sequence
seqArr.add(seqBody);
}
} catch (FileNotFoundException ex) {
Logger.getLogger(MutualInfoBio.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(MutualInfoBio.class.getName()).log(Level.SEVERE, null, ex);
}
char[][] seqC = new char[seqArr.size()][];
int[] lenB = new int[seqArr.size()];
for (int i = 0; i < seqArr.size(); i++)
{
seqC[i] = seqArr.get(i).toCharArray();
lenB[i] = seqC[i].length;
}
int maxLen = 0;
for (int i = 0; i < lenB.length; i++)
{
if (lenB[i] > maxLen)
{
maxLen = lenB[i];
}
}
// Flip array
char[][] seqD = new char[maxLen][seqC.length];
for (int i = 0; i < seqC.length; i++)
{
for (int j = 0; j < seqC[i].length; j++)
{
seqD[j][i] = seqC[i][j];
}
}
return seqD;
}
// Process Category String into Groups and Identity Double Array.
private static char[][] formatCat(String catA){
// Find the number of categories or groups to be analyzed, Collection A
int catlenA = catA.length() - catA.replace(",", "").length() + 1;
// Split the category A string, by category, into separate arrays
String[] catB = catA.split(", ");
// Within category A array, sub-split any identities that are to be considered equal
char[][] catC = new char[catB.length][];
for (int i = 0; i < catB.length; i++)
{
catC[i] = catB[i].toCharArray();
}
return catC;
}
// Determine Category String to use, Based on User Choise
private static String catSwitch(String choice, String userI){
String res = new String();
switch (choice)
{
case "Protein, Grouped": res = protgr; break;
case "Protein": res = aa; break;
case "DNA": res = dna; break;
case "RNA": res = rna; break;
case "Custom Category": res = userI; break;
}
return res;
}
// Subroutine for converting sequence string based on categories
// Label sequence identity according to category groups, Count instances
private static int[][][] ccSeq(char[][] seq, char[][] cat){
int[][] seq1 = new int[seq.length][seq[0].length];
int[][] obs1 = new int[seq.length][cat.length];
for (int i = 0; i < seq.length; i++)
{
for (int j = 0; j < seq[i].length; j++)
{
for (int k = 0; k < cat.length; k++)
{
for (int m = 0; m < cat[k].length; m++)
{
if (seq[i][j] == cat[k][m])
{
seq1[i][j] = k;
obs1[i][k] += 1;
}
}
}
}
}
int[][][] res = new int[2][seq1.length][obs1.length];
res[0] = seq1;
res[1] = obs1;
return res;
}
/**
* Takes a sequence set and an observed count and determines the frequency
* @param combo A 3D dimensional array: the first dimension splits between the sequence identity and the observed count 2D arrays.
* @return
*/
private static double[][] oFreq(int[][][] combo){
double[][] res = new double[combo[1].length][combo[1][0].length];
for (int i = 0; i < combo[1].length; i++)
{
for (int j = 0; j < combo[1][i].length; j++)
{
int calc = (combo[1][i][j] * 1000) / (combo[0][i].length);
double calc2 = (double) calc;
calc2 = calc2 / 1000.0;
res[i][j] = calc2;
}
};
return res;
}
/**
* MutualInfo Method: Calculate MI for all pairs across two sets of biological data
* @param seq1 The 2nd sequence collection
* @param seq2 The first sequence collection
* @param intraMol Trigger switch to determine if diagonals (i = j) are ignored.
* @param saveIt Trigger switch to determine if the results are saved
* @param resFile File to which the information is saved
* @return A 3D array; In first dimension, 0 = MI scores(2D), 1,0 = Row sums(1D), 2,0 = Col sums(1D), 3,0,0 = total sum(0D)
*/
private double[][][] mutualInfo(int[][][] seq1, int[][][] seq2, boolean intraMol, boolean saveIt, File resFile)
{
// BEGIN BLOCK FOR MI METHOD
double[][] pX = null;
double[][] pY = null;
pX = oFreq(seq1);
pY = oFreq(seq2);
double[] sumMIi = new double[seq1[0].length];
double[] sumMIj = new double[seq2[0].length];
sumMIi = dumdoub1Darr(sumMIi);
sumMIj = dumdoub1Darr(sumMIj);
double sumMIij = 0.0;
double[][] arrayMImet = new double[seq1[0].length][seq2[0].length];
for (int i = 0; i < seq1[0].length; i++)
{
for (int j = 0; j < seq2[0].length; j++)
{
double ijMI = 0.0;
// Find and Report raw MI
ijMI = miIJ(seq1[0][i], seq2[0][j], pX[i], pY[j], i, j, saveIt, resFile);
if(intraMol && i == j)
{
ijMI = 0.0;
}
// Add MI to Arrays for Later Processing
arrayMImet[i][j] += ijMI;
// Add to sumMIi array
sumMIi[i] += ijMI;
// Add to sumMIj array
sumMIj[j] += ijMI;
// Add to overall total
sumMIij += ijMI;
// Add to counter
zcount++;
}
}
double[][][] resArray = new double[4][][];
resArray[1] = new double[1][];
resArray[2] = new double[1][];
resArray[0] = arrayMImet;
resArray[1][0] = sumMIi;
resArray[2][0] = sumMIj;
resArray[3] = new double[1][1];
resArray[3][0][0] = sumMIij;
return resArray;
}
/**
* miIJ: Calculates the Mutual Information between two residue pairs, I & J
* @param seq1 The collection of identities from the MSA for the 1st residue
* @param seq2 The collection of identities from the MSA for the 2nd residue
* @param pX The probabilities for the identities for the 1st residue
* @param pY The probabilities for the identities for the 2nd residue
* @param iA The 1st residue position, used for reporting purposes
* @param jB The 1st residue position, used for reporting purposes
* @param resFile The file location to which pair data information is written
* @return The mutual information score, give as a whole number or fraction
*/
private double miIJ(int[] seq1, int[] seq2, double[] pX, double[] pY, int iA, int jB, boolean saveIt, File resFile)
{
int[][] obsXY = new int[pX.length][pY.length];
//Initialize the obsXY array
for (int i = 0; i < obsXY.length; i++)
{
for (int j = 0; j < obsXY[i].length; j++)
{
obsXY[i][j] = 0;
}
}
double ijMI = 0.0;
int minLen = Math.min(seq1.length, seq2.length);
double[][] pXY = new double[pX.length][pY.length];
for (int i = 0; i < minLen; i++)
{
int x = seq1[i];
int y = seq2[i];
obsXY[x][y] += 1;
};
for (int k = 0; k < obsXY.length; k++)
{
for (int m = 0; m < obsXY[k].length; m++)
{
double calc1 = (double) obsXY[k][m];
double calc2 = (double) minLen;
pXY[k][m] = calc1 / calc2;
}
}
for (int x = 0; x < pX.length; x++)
{
for (int y = 0; y < pY.length; y++)
{
double xyMI = 0.0;
double dpX = (double) pX[x];
double dpY = (double) pY[y];
double pXpY = dpX * dpY;
if (pXpY > 0.0 && pXY[x][y] > 0.0)
{
xyMI = pXY[x][y] * Math.log(pXY[x][y] / pXpY);
}
else
{
xyMI = 0.0;
}
if (intraMol && x == y)
{
xyMI = 0.0;
}
ijMI += xyMI;
}
}
String reporter = Double.toString(ijMI);
String res1 = Integer.toString(iA + 1) + "\t" + Integer.toString(jB + 1) + "\t" + String.format("%.10f", ijMI);
if (pairData)
{
res1 += "\t";
for (int q = 0; q < obsXY.length; q++)
{
for (int s = 0; s < obsXY[q].length; s++)
{
res1 += obsXY[q][s] + "\t";
}
}
}
if(saveIt)
{
writeFileN(res1, resFile);
}
return ijMI;
}
private static double[] dumdoub1Darr (double[] arr){
for (int i = 0; i < arr.length; i++)
{
arr[i] = 0.0;
}
return arr;
}
private static double[][] dumdoub2Darr (double[][] arr){
for (int i = 0; i < arr.length; i++)
{
for (int j = 0; j < arr[i].length; j++)
{
arr[i][j] = 0.0;
}
}
return arr;
}
/**
* A method for taking an array and sorting, from highest value to lowest, and returning a sorted matrix
* @param arr The array to be sorted
* @return A multidimensional array, with the first dimension containing the scores, i-th positions, and j-th positions, in that order as doubles
*/
private double[][] sortArr (double[][] arr){
int totalArrSize = 0;
//Find Min
double arrMin = 10000;
for (int i = 0; i < arr.length; i++)
{
for (int j = 0; j < arr[i].length; j++)
{
totalArrSize++;
arrMin = Math.min(arrMin, arr[i][j]);
}
}
String[] arrS = new String[totalArrSize];
// Boost by minimum, to ensure all values are positive
for (int i = 0; i < arr.length; i++)
{
for (int j = 0; j < arr[i].length; j++)
{
arr[i][j] -= arrMin;
}
}
int z = 0;
for (int i = 0; i < arr.length; i++)
{
for (int j = 0; j < arr[i].length; j++)
{
arrS[z] = String.format("%.10f", arr[i][j]) + "\t" + (i + 1) + "\t" + (j + 1);
// rep = Double.toString(arr[i][j]);
// arrS[z] = rep + "\t" + i + "\t" + j;
z++;
}
}
Arrays.sort(arrS);
double[][] res = new double[3][arrS.length];
for (int i = 0; i < arrS.length; i++)
{
String[] arrStemp = arrS[i].split("\t");
res[0][i] = Double.parseDouble(arrStemp[0]) + arrMin;
res[1][i] = Double.parseDouble(arrStemp[1]);
res[2][i] = Double.parseDouble(arrStemp[2]);
}
return res;
}
/**
* A simple method for sorting and reporting an Array, used to eliminate the need to return large array values just to record them
* @param arr The array to be sorted
* @param resFile The file to which the results will be written
*/
private void sortReport (double[][] arr, File resFile){
double[][] sorted = sortArr(arr);
int totalArrSize = sorted[0].length;
for (int i = totalArrSize - 1; i > 0; i--)
{
String temp = String.format("%.10f", sorted[0][i]) + "\t" + String.format("%.0f", sorted[1][i]) + "\t" + String.format("%.0f", sorted[2][i]);
writeFileN(temp, resFile);
}
}
/**
* A method for drawing a filled square
* This method will take X and Y starting positions and draw a square of a specified size and color
* @param img The image object to which the square will be drawn
* @param size The size of the square
* @param xStart The starting X coordinate
* @param yStart The starting Y coordinate
* @param color The square color, as a RBG int
*/
private static void fillSq (BufferedImage img, int size, int xStart, int yStart, int color)
{
size += 1;
int xEnd = xStart + size;
int yEnd = yStart + size;
for (int i = xStart; i < xEnd; i++)
{
for (int j = yStart; j < yEnd; j++)
{
img.setRGB(i, j, color);
}
}
}
/**
* Method for drawing a 2D heatmap from array values
* @param arr The 2D double array for which the values and size will be used for the heatmap
* @param fileName The name for the destination file for the heatmap
* @param scale The scale for the heatmap, in terms of square pixels per data point.
*/
private static void drawHeatMap (double[][] arr, String fileName, int scale, String colorChoice)
{
int totXsize = arr.length;
int totYsize = 0;
double arrMax = 0;
double arrMin = 10000;
// Find max, min score value, max Y size
for (int i = 0; i < arr.length; i++)
{
totYsize = Math.max(arr[i].length, totYsize);
for (int j = 0; j < arr[i].length; j++)
{
arrMax = Math.max(arrMax, arr[i][j]);
arrMin = Math.min(arrMin, arr[i][j]);
}
}
arrMax -= arrMin;
double normFactor = 255 / arrMax;
int[][] normScore = new int[totXsize][totYsize];
// Normalize score
for (int i = 0; i < arr.length; i++)
{
for (int j = 0; j < arr[i].length; j++)
{
double tempScore = arr[i][j];
tempScore -= arrMin;
tempScore *= normFactor;
normScore[i][j] = 255;
normScore[i][j] -= (int) tempScore;
}
}
totXsize++;
totXsize *= scale;
totYsize++;
totYsize *= scale;
// Normalize / categorize sccores
BufferedImage img = new BufferedImage(totXsize, totYsize, BufferedImage.TYPE_INT_RGB);
int posX = 0;
int posY = 0;
int red = 65536;
int green = 256;
int blue = 1;
for (int i = 0; i < arr.length; i++)
{
for (int j = 0; j < arr[i].length; j++)
{
// default is gray
int color = (red * normScore[i][j]) + (green * normScore[i][j]) + (blue * normScore[i][j]);
switch (colorChoice)
{
case "red":
color = (red * 255) + (green * normScore[i][j]) + (blue * normScore[i][j]);
break;
case "green":
color = (red * normScore[i][j]) + (green * 255) + (blue * normScore[i][j]);
break;
case "blue":
color = (red * normScore[i][j]) + (green * normScore[i][j]) + (blue * 255);
break;
case "gray":
color = (red * normScore[i][j]) + (green * normScore[i][j]) + (blue * normScore[i][j]);
break;
}
fillSq(img, scale, posX, posY, color);
posY += scale;
}
posX += scale;
posY = 0;
}
try {
ImageIO.write(img, "PNG", new File(fileName));
} catch (IOException ex) {
Logger.getLogger(MutualInfoBio.class.getName()).log(Level.SEVERE, null, ex);
}
}
/**
* Method for generating an array that represents a random, shuffled order of another array (that can be used to shuffle several arrays in the same way)
* @param size The size of the array that needs a shuffle order
* @return The array with the order listed
*/
private int[] shuffleRandom (int size)
{
int[] resArr = new int[size];
double[] randomArr1 = new double[size];
double[] randomArr2 = new double[size];
for (int i = 0; i < randomArr1.length; i++)
{
double randomNum = Math.random();
// Check to make sure random number isn't a duplicate of value already present
for (int j = 0; j < randomArr1.length; j++)
{
if (randomNum == randomArr1[j])
{
randomNum = Math.random();
j = 0;
}
}
randomArr1[i] = randomNum;
randomArr2[i] = randomNum;
};
Arrays.sort(randomArr2);
for (int i = 0; i < resArr.length; i++)
{
for (int j = 0; j < randomArr1.length; j++)
{
if (randomArr1[j] == randomArr2[i])
{
resArr[i] = j;
}
}
}
return resArr;
}
/**
* Method is designed to apply the APC correction factor on a set of mutual information data
* @param arrayMI The mutual information array to be corrected
* @param sumMIi An array with the sum of each row
* @param sumMIj An array with the sum of each column
* @param sumMIij The overall sum of the mutual information double array
* @param dirName The name of the directory to place the files generated
* @param size The size of the arrayMI
* @param pixelSize The size of the pixels in the heatmap
* @param processCount The iteration of this process, for use in naming files
*/
private void apcProcess (double[][][] arrayMI, String dirName, int size1, int size2, int pixelSize)
{
double[] sumMIi = arrayMI[1][0];
double[] sumMIj = arrayMI[2][0];
double sumMIij = arrayMI[3][0][0];
/**
* Recipient file for Raw APC scores, comparing collection B and A
*/
File fRawAPC = new File(dirName + "\\APC_raw" + ".txt");
/**
* Recipient file for sorted APC scores, comparing collection A against itself
*/
File fSortAPC = new File(dirName + "\\APC_sorted" + ".txt");
// Calculate raw APC values and Report as String
String res1 = "";
double[][] arrayAPCx = new double[size1][size2];
// Fill with dummy values
arrayAPCx = dumdoub2Darr(arrayAPCx);
for (int i = 0; i < arrayMI[0].length; i++)
{
for (int j = 0; j < arrayMI[0][i].length; j++)
{
// Make APC Adjustments
double adjAPC = (sumMIi[i] * sumMIj[j]) / sumMIij;
if(sumMIij == 0.0)
{
adjAPC = 0.0;
}
arrayAPCx[i][j] = arrayMI[0][i][j] - adjAPC;
res1 = Integer.toString(i) + "\t" + Integer.toString(j) + "\t" + String.format("%.10f", arrayAPCx[i][j]);
writeFileN(res1, fRawAPC);
}
}
sortReport(arrayAPCx, fSortAPC);
drawHeatMap(arrayAPCx, dirName + "\\heatmap" + ".PNG", pixelSize, "blue");
}
private void rcwProcess(double[][][] arrayMI, String dirName, int size1, int size2, int pixelSize)
{
double[] sumMIi = arrayMI[1][0];
double[] sumMIj = arrayMI[2][0];
double sumMIij = arrayMI[3][0][0];
/**
* Recipient file for Raw APC scores, comparing collection B and A
*/
File fRawRCW = new File(dirName + "\\RCW_raw" + ".txt");
/**
* Recipient file for sorted APC scores, comparing collection A against itself
*/
File fSortRCW = new File(dirName + "\\RCW_sorted" + ".txt");
double[][] arrayRCW = new double[size1][size2];
// Fill with dummy values
arrayRCW = dumdoub2Darr(arrayRCW);
// Calculate raw RCW values and Report as String
String res1 = "";
for (int i = 0; i < arrayMI[0].length; i++)
{
for (int j = 0; j < arrayMI[0][i].length; j++)
{
// Make RCW Adjustments
double adjRCW = (sumMIi[i] + sumMIj[j]) / 2.0;
if(adjRCW != 0.0)
{
arrayRCW[i][j] = arrayMI[0][i][j] / adjRCW;
}
else
{
arrayRCW[i][j] = 0.0;
}
res1 = Integer.toString(i) + "\t" + Integer.toString(j) + "\t" + String.format("%.10f", arrayRCW[i][j]);
writeFileN(res1, fRawRCW);
}
}
sortReport(arrayRCW, fSortRCW);
drawHeatMap(arrayRCW, dirName + "\\heatmap" + ".PNG", pixelSize, "red");
}
/**
* Subtract one 3D double array by another.
* @param arr1 The 1st array
* @param arr2 The 2nd array
* @return The transformed array
*/
private static double[][][] subtract3Darr(double[][][] arr1, double[][][] arr2)
{
for (int i = 0; i < arr1.length; i++)
{
for (int j = 0; j < arr1[i].length; j++)
{
for (int k = 0; k < arr1[i][j].length; k++)
{
arr1[i][j][k] -= arr2[i][j][k];
}
}
}
return arr1;
}
/**
* Method for taking two 3D double arrays and averaging them together, using a weight factor to allow iteration in code.
* @param arr1 The first array
* @param arr2 The second array
* @param weight The weighting to apply to the first array
* @return The averaged values
*/
private static double[][][] average3Darr(double[][][] arr1, double[][][] arr2, int weight)
{
for (int i = 0; i < arr1.length; i++)
{
for (int j = 0; j < arr1[i].length; j++)
{
for (int k = 0; k < arr1[i][j].length; k++)
{
double weightD = (double)weight;
arr1[i][j][k] = ((arr1[i][j][k] * weightD) + arr2[i][j][k]) / (weightD + 1);
}
}
}
return arr1;
}
private static double[][][] clone3Darr(double[][][] arr)
{
double[][][] arr2 = new double[arr.length][][];
for (int i = 0; i < arr.length; i++)
{
double[][] arr2i = new double[arr[i].length][];
for (int j = 0; j < arr[i].length; j++)
{
double[] arr2j = new double[arr[i][j].length];
for (int k = 0; k < arr[i][j].length; k++)
{
double arr2k = arr[i][j][k];
arr2j[k] = arr2k;
}
arr2i[j] = arr2j;
}
arr2[i] = arr2i;
}
return arr2;
}
private void write2Darr(double[][] arr, File file1)
{
for (int i = 0; i < arr.length; i++)
{
for (int j = 0; j < arr[i].length; j++)
{
String zRep = Integer.toString(i + 1) + "\t" + Integer.toString(j + 1) + "\t" + String.format("%.10f", arr[i][j]);
writeFileN(zRep, file1);
}
}
}
}