net.maizegenetics.pangenome.hapCalling.PathToIgraphPlugin Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of phg Show documentation
Show all versions of phg Show documentation
PHG - Practical Haplotype Graph
package net.maizegenetics.pangenome.hapCalling;
import java.awt.Frame;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.NavigableMap;
import java.util.Properties;
import java.util.regex.Pattern;
import javax.swing.ImageIcon;
import org.apache.log4j.Logger;
import net.maizegenetics.dna.map.Chromosome;
import net.maizegenetics.pangenome.api.HaplotypeGraph;
import net.maizegenetics.pangenome.api.HaplotypeNode;
import net.maizegenetics.pangenome.api.ReferenceRange;
import net.maizegenetics.pangenome.db_loading.DBLoadingUtils;
import net.maizegenetics.plugindef.AbstractPlugin;
import net.maizegenetics.plugindef.DataSet;
import net.maizegenetics.plugindef.Datum;
import net.maizegenetics.plugindef.PluginParameter;
import net.maizegenetics.taxa.TaxaList;
import net.maizegenetics.util.Utils;
/**
* @author Peter Bradbury
*
* The PathToIgraphPlugin exports data for a path and the graph used to generate it from a PHG database.
* The data is exported in a format that can be imported by the igraph package in R. There is also
* an igraph package available for Python as well.
*
* The export consists of two files for each chromosome, a vertex file and an edge file. The vertex (or node) file contains the following
* columns:
* id a sequential id assigned to each node
* range a sequential id assigned to each reference range according to its position in a chromosome
* hapid the haplotype_id from the database for each node
* name the name used to label each node in the graph, set to ntaxa
* ntaxa the number of taxa in each node
* inclusion the inclusion count for each node
* exclusion the exclusion count for each node
* ispath whether a node is on the path
* istarget whether the node is contains the target taxon
* chr the chromosome of the node
* start the start position of the range
* end the end position of the range
*
* The edge file consists of the following columns:
* from the id of the node (vertex) from which the edge originates
* to the id of the node to which the edge connects
* prob the edge weight. It equals the number of taxa shared in common between the connected nodes
* divided by the total taxa in common between the adjacent ranges
*
* The path is the path imputed by the fastq file used to generate the path. The target taxon is
* a taxon chosen by the user to compare to the imputed path.
*
* The input expected by the Plugin is a HaplotypeGraph, presumably created by
* HaplotypeGraphBuilderPlugin using the same parameters and database used to impute the path.
* The other parameters taken by the PathToIgraphPlugin should match parameter values used to create
* the path.
*/
@Deprecated
public class PathToIgraphPlugin extends AbstractPlugin {
private static Logger myLogger = Logger.getLogger(PathToIgraphPlugin.class);
private PluginParameter taxonName = new PluginParameter.Builder<>("taxonName", null, String.class)
.description("The name of the taxon for which the path is requested.")
.required(true)
.guiName("Path taxon name")
.required(true)
.build();
private PluginParameter targetName = new PluginParameter.Builder<>("targetName", null, String.class)
.description("The name of the taxon in the PHG to which the path will be compared.")
.required(true)
.guiName("PHG target name")
.required(true)
.build();
private PluginParameter pathName = new PluginParameter.Builder<>("pathName", null, String.class)
.description("The path method name assigned when the path was created and stored in the DB. Not required if a path file name is supplied.")
.guiName("Path method name")
.build();
private PluginParameter countMethod = new PluginParameter.Builder<>("countMethod", null, String.class)
.description("The haplotype count method name assigned when the counts were created and stored in the DB. "
+ "Not required if a path file name is supplied or if only one method was used to find a path for this taxon.")
.guiName("Haplotype count method name")
.build();
private PluginParameter fastqName = new PluginParameter.Builder<>("fastqName", null, String.class)
.description("The name of the fastq file used to create the path. This must be the full path as supplied to FastqToHapCountPlugin.rawReadFile "
+ "Not required if the path and count data can be retrieved using other parameters.")
.guiName("Fastq name")
.build();
private PluginParameter configFile = new PluginParameter.Builder("configFile", null, String.class)
.description("Database configuration file")
.guiName("Database Config File")
.required(true)
.inFile()
.build();
private PluginParameter splitTransitionProb = new PluginParameter.Builder<>("splitProb", 0.99, Double.class)
.description("When the consensus nodes are split by taxa, this is the transition probability for moving from a node to the next node of the same taxon. It equals 1 minus the probability of a recombination between adjacent nodes.")
.build();
private PluginParameter taxaFilter = new PluginParameter.Builder<>("taxa", null, TaxaList.class)
.description("A list of taxa to include in graph. Only nodes containing these taxa will be included in the graph."
+ " If no taxa list is supplied, then all taxa in the full graph will be used.")
.build();
private PluginParameter refRangeFile = new PluginParameter.Builder<>("refRangeFile", null, String.class)
.description("The name of the file containing the reference ranges to keep.")
.inFile()
.build();
private PluginParameter outputBase = new PluginParameter.Builder<>("outbase", null, String.class)
.required(true)
.description("base name for output files from this Plugin. Two files will be produced for each chromosome.")
.guiName("Output file base")
.outFile()
.build();
public PathToIgraphPlugin(Frame parentFrame, boolean isInteractive) {
super(parentFrame, isInteractive);
}
@Override
public DataSet processData(DataSet input) {
// Process the config file as a properties file
Properties dbProperties = new Properties();
try {
dbProperties.load(Utils.getBufferedReader(configFile.value()));
} catch (Exception e) {
myLogger.debug(e.getMessage(), e);
throw new IllegalArgumentException("PathToIgraphPlugin: buildHaplotypeGraph: connection: problem reading properties file: " + configFile.value());
}
//Check to see if the tassel pipeline passes in a graph
List temp = input.getDataOfType(HaplotypeGraph.class);
if (temp.size() != 1) {
throw new IllegalArgumentException("PathToIgraphPlugin: processData: must input one HaplotypeGraph: " + temp.size());
}
HaplotypeGraph graph = ((HaplotypeGraph)temp.get(0).getData());
List rangesToKeep = readRefRangeFile();
//retrieve haplotype counts
int hapCountId = getHaplotypeCountID();
int[][] haplotypeCounts = inclusionExclusionCountsFromDB(hapCountId);
//make the haplotypeCounts into maps expected by ConvertGBSToSnps
Map inclusionMap = new HashMap<>();
Map exclusionMap = new HashMap<>();
for (int idx = 0;idx < haplotypeCounts[0].length; idx++) {
int hapid = haplotypeCounts[0][idx];
inclusionMap.put(hapid, haplotypeCounts[1][idx]);
exclusionMap.put(hapid, haplotypeCounts[2][idx]);
}
///initialize ConvertReadsToPathUsingHMM because it will be used to replicate filter
ConvertReadsToPathUsingHMM converter = new ConvertReadsToPathUsingHMM()
.minReadsPerRange(Integer.parseInt(dbProperties.getProperty("minReads","1")))
.maxReadsPerRangeKB(Integer.parseInt(dbProperties.getProperty("maxReadsPerKB","100")))
.taxaFilterList(taxaFilter.value())
.minTransitionProbability(Double.parseDouble(dbProperties.getProperty("minTransitionProb","0.001")))
.transitionProbabilitySameTaxon(splitTransitionProb.value())
.probabilityReadMappingCorrect(Double.parseDouble(dbProperties.getProperty("probReadMappedCorrectly","0.99")))
.hapidCountMap(inclusionMap);
// .hapidExclusionCountMap(exclusionMap)
// .emissionProbabilityMethod(ReferenceRangeEmissionProbability.METHOD.valueOf(dbProperties.getProperty("emissionMethod","allCounts")));
if (rangesToKeep == null) converter.filterHaplotypeGraph(graph);
else converter.filterHaplotypeGraph(graph, rangesToKeep);
HaplotypeGraph filteredGraph = converter.filteredGraph();
//retrieve path
int[] myPath;
myPath = pathFromDB(hapCountId);
writeGraphInfoAllChr(outputBase.value(), myPath, filteredGraph, haplotypeCounts, targetName.value());
return null;
}
public void writeGraphInfoAllChr(String outbase, int[] pathids,
HaplotypeGraph graph, int[][] inclusionExclusionCounts, String target) {
Map inclusionMap = new HashMap<>();
Map exclusionMap = new HashMap<>();
for (int i = 0; i < inclusionExclusionCounts[0].length; i++) {
inclusionMap.put(inclusionExclusionCounts[0][i], inclusionExclusionCounts[1][i]);
exclusionMap.put(inclusionExclusionCounts[0][i], inclusionExclusionCounts[2][i]);
}
for (Chromosome chr : graph.chromosomes()) {
writeGraphInfoFilesForChr(outbase, pathids, graph, inclusionMap, exclusionMap,
chr, target);
}
}
public void writeGraphInfoFilesForChr(String outbase, int[] pathids,
HaplotypeGraph graph, Map inclusionMap, Map exclusionMap,
Chromosome chr, String target) {
//sort the pathids
//first make a copy to be safe
int[] sortedPathIds = Arrays.copyOf(pathids, pathids.length);
Arrays.sort(sortedPathIds);
//write edge data, vertex data with inclusion counts, path (list of haplotype id's)
String edgefilename = outbase + "_chr_" + chr.getName() + "_edges.txt";
String vertexfilename = outbase + "_chr_" + chr.getName() + "_vertices.txt";
//set up data structures
NavigableMap> tree = graph.tree(chr);
Map graphidMap = new HashMap<>();
int rangeCount = 0;
int nodeCount = 0;
for (List nodeList : tree.values()) {
for (HaplotypeNode node : nodeList) {
graphidMap.put(node, new int[] {rangeCount, nodeCount++});
}
rangeCount++;
}
//write the edges
try(PrintWriter pw = new PrintWriter(edgefilename)) {
pw.println("from\tto\tprob");
tree.values().stream().flatMap(List::stream)
.flatMap(hn -> graph.rightEdges(hn).stream())
.forEach(he -> {
int sourceid = graphidMap.get(he.leftHapNode())[1];
int targetid = graphidMap.get(he.rightHapNode())[1];
pw.printf("%d\t%d\t%1.3e%n", sourceid, targetid, he.edgeProbability());
});
} catch (FileNotFoundException e) {
myLogger.error("PrintWriter unable to write to " + edgefilename);
}
//write the vertices
try(PrintWriter pw = new PrintWriter(vertexfilename)) {
pw.println("id\trange\thapid\tname\tntaxa\tinclusion\texclusion\tispath\tistarget\tchr\tstart\tend");
for (HaplotypeNode node : graphidMap.keySet()) {
int[] ids = graphidMap.get(node);
pw.print(Integer.toString(ids[1])); //id
pw.print("\t");
pw.print(Integer.toString(ids[0])); //range
pw.print("\t");
pw.print(Integer.toString(node.id())); //hapid (place holder)
pw.print("\t");
pw.print(Integer.toString(node.numTaxa())); //name (place holder)
pw.print("\t");
pw.print(Integer.toString(node.numTaxa())); //ntaxa
pw.print("\t");
pw.print(Integer.toString(inclusionMap.getOrDefault(node.id(), 0))); //inclusion
pw.print("\t");
pw.print(Integer.toString(exclusionMap.getOrDefault(node.id(), 0))); //exclusion
pw.print("\t");
pw.print(Arrays.binarySearch(sortedPathIds, node.id()) > -1 ? "T" : "F");//ispath
pw.print("\t");
if (target == null) pw.print("F"); //istarget
else pw.print(node.taxaList().indexOf(target) >= 0 ? "T" : "F");
pw.print("\t");
pw.print(node.referenceRange().chromosome().getName()); //chr
pw.print("\t");
pw.print(Integer.toString(node.referenceRange().start())); //start
pw.print("\t");
pw.print(Integer.toString(node.referenceRange().end())); //end
pw.println();
}
} catch (FileNotFoundException e) {
myLogger.error("PrintWriter unable to write to " + vertexfilename);
}
}
private int getHaplotypeCountID() {
try (Connection connection = DBLoadingUtils.connection(configFile.value(), false)) {
//get the haplotype_counts_id for this method and genotype
Statement dbst = connection.createStatement();
boolean noCountMethod = (countMethod.value() == null);
boolean noFastqName = (fastqName.value() == null);
int haplotypeCountsId = -1;
//get a haplotype id
//if there is no count method, see if using line name returns only a single path
//if 0 or multiple paths complain
//if there is no
if (noCountMethod && noFastqName) {
String sql;
sql = String.format("SELECT haplotype_counts_id FROM haplotype_counts hc, genotypes g "
+ "WHERE hc.genoid=g.genoid AND g.line_name='%s'", taxonName.value());
ResultSet rs = dbst.executeQuery(sql);
if (!rs.next()) { //no path
rs.close();
dbst.close();
throw new RuntimeException("No haplotype counts for " + taxonName.value());
}
haplotypeCountsId = rs.getInt(1);
if (rs.next()) { //multiple paths
rs.close();
dbst.close();
throw new RuntimeException("Multiple haplotype count data sets for " + taxonName.value() + ". Please provide a count method and/or a fastq name.");
}
} else if (noFastqName) { //there is a count method
String sql = String.format("SELECT haplotype_counts_id FROM haplotype_counts hc, genotypes g, methods m "
+ "WHERE hc.genoid=g.genoid AND g.line_name='%s' AND hc.method_id=m.method_id AND m.name='%s'",
taxonName.value(), countMethod.value());
myLogger.debug("executing sql query: " + sql);
ResultSet rs = dbst.executeQuery(sql);
if (!rs.next()) { //no path
rs.close();
dbst.close();
throw new RuntimeException("No haplotype counts for " + taxonName.value() + ", method = " + countMethod.value());
}
haplotypeCountsId = rs.getInt(1);
if (rs.next()) { //multiple paths
rs.close();
dbst.close();
throw new RuntimeException("Multiple haplotype count data sets for " + taxonName.value() + ", method = " + countMethod.value() + ". Please provide a fastq file name.");
}
} else if (noCountMethod) { //there is a fastq name
String sql = String.format("SELECT haplotype_counts_id FROM haplotype_counts hc, genotypes g "
+ "WHERE hc.genoid=g.genoid AND g.line_name='%s' AND hc.fastq_file='%s'",
taxonName.value(), fastqName.value());
myLogger.debug("executing sql query: " + sql);
ResultSet rs = dbst.executeQuery(sql);
if (!rs.next()) { //no path
rs.close();
dbst.close();
throw new RuntimeException("No haplotype counts for " + taxonName.value() + ", fastq = " + fastqName.value());
}
haplotypeCountsId = rs.getInt(1);
if (rs.next()) { //multiple paths
rs.close();
dbst.close();
throw new RuntimeException("Multiple haplotype count data sets for " + taxonName.value() + ", fastq = " + fastqName.value() + ". Please provide a method.");
}
} else { //there is a count method and a fastq name
String sql = String.format("SELECT haplotype_counts_id FROM haplotype_counts hc, genotypes g, methods m "
+ "WHERE hc.genoid=g.genoid AND g.line_name='%s' AND hc.method_id=m.method_id AND m.name='%s' AND hc.fastq_file='%s'",
taxonName.value(), countMethod.value(), fastqName.value());
myLogger.debug("executing sql query: " + sql);
ResultSet rs = dbst.executeQuery(sql);
if (!rs.next()) { //no path
rs.close();
dbst.close();
throw new RuntimeException("No haplotype counts for " + taxonName.value() + ", method = " + countMethod.value() + ", fastq = " + fastqName.value());
}
haplotypeCountsId = rs.getInt(1);
if (rs.next()) { //multiple paths
rs.close();
dbst.close();
throw new RuntimeException("Multiple haplotype count data sets for " + taxonName.value() + ", method = " + countMethod.value() + ", fastq = " + fastqName.value());
}
}
return haplotypeCountsId;
} catch (Exception e) {
myLogger.debug(e.getMessage(), e);
throw new IllegalStateException("processData: DB connection failure in PathToIgraphPlugin: " + e.getMessage());
}
}
private int[][] inclusionExclusionCountsFromDB(int haplotypeCountId) {
try (Connection connection = DBLoadingUtils.connection(configFile.value(), false)) {
//get the haplotype_counts_id for this method and genotype
Statement dbst = connection.createStatement();
String sql = String.format("SELECT data FROM haplotype_counts WHERE haplotype_counts_id=%d", haplotypeCountId);
ResultSet rs = dbst.executeQuery(sql);
//haplotypeCountId has already been verified to return a single record
if (rs.next()) {
byte[] dataAsBytes = rs.getBytes(1);
int[][] counts = DBLoadingUtils.decodeHapCountsArray(dataAsBytes);
return counts;
} else {
rs.close();
dbst.close();
throw new IllegalArgumentException("haplotypeCountId does not return haplotype counts");
}
} catch (Exception e) {
myLogger.debug(e.getMessage(), e);
throw new IllegalStateException("processData: DB connection failure in PathToIgraphPlugin: " + e.getMessage());
}
}
private int[] pathFromDB(int haplotypeCountId) {
try (Connection connection = DBLoadingUtils.connection(configFile.value(), false)) {
//get the haplotype_counts_id for this method and genotype
Statement dbst = connection.createStatement();
boolean noPathMethod = (pathName.value() == null);
int[] path = null;
if (noPathMethod) {
String sql = String.format("SELECT haplotype_paths FROM paths WHERE haplotype_counts_id=%d", haplotypeCountId);
ResultSet rs = dbst.executeQuery(sql);
if (rs.next()) { //one or more paths
byte[] byteval = rs.getBytes(1);
if (rs.next()) {
rs.close();
dbst.close();
throw new RuntimeException("Multiple haplotype paths for " + taxonName.value() + ". Please provide a path method.");
}
path = DBLoadingUtils.decodePathsArray(byteval);
rs.close();
} else { //no path
rs.close();
dbst.close();
throw new RuntimeException("No haplotype path for " + taxonName.value());
}
} else { //there is a path method
String sql = String.format("SELECT p.haplotype_paths FROM paths p, methods m "
+ "WHERE p.haplotype_counts_id=%d AND p.method_id=m.method_id AND m.name='%s'",
haplotypeCountId, pathName.value());
myLogger.debug("sql: " + sql);
ResultSet rs = dbst.executeQuery(sql);
if (rs.next()) { //one or more paths
byte[] byteval = rs.getBytes(1);
if (rs.next()) {
rs.close();
dbst.close();
throw new RuntimeException("Multiple haplotype paths for " + taxonName.value() + ", method = " + pathName.value());
}
path = DBLoadingUtils.decodePathsArray(byteval);
rs.close();
} else { //no path
rs.close();
dbst.close();
throw new RuntimeException("No haplotype path for " + taxonName.value() + ", method = " + pathName.value());
}
}
dbst.close();
return path;
} catch (Exception e) {
myLogger.debug(e.getMessage(), e);
throw new IllegalStateException("processData: DB connection failure in PathToIgraphPlugin: " + e.getMessage());
}
}
private List readRefRangeFile() {
if (refRangeFile.value() == null) return null;
Pattern tab = Pattern.compile("\t");
try (BufferedReader br = Utils.getBufferedReader(refRangeFile.value())) {
List listOfRangesId = new ArrayList<>();
String currentLine = br.readLine();
while ((currentLine = br.readLine()) != null) {
String[] data = tab.split(currentLine);
listOfRangesId.add(Integer.parseInt(data[0]));
}
return listOfRangesId;
} catch (IOException ioe) {
throw new RuntimeException("Failed to read ref range data from " + refRangeFile.value(), ioe);
}
}
@Override
public ImageIcon getIcon() {
return null;
}
@Override
public String getButtonName() {
return "Export igraph";
}
@Override
public String getToolTipText() {
return "export files for use by igraph";
}
// public static void main(String[] args) {
// GeneratePluginCode.generate(PathToIgraphPlugin.class);
// }
/**
* Convenience method to run plugin that returns nothing.
*/
public void runPlugin(DataSet input) {
performFunction(input).getData(0).getData();
}
/**
* The name of the taxon for which the path is requested.
*
* @return Taxon name
*/
public String taxonName() {
return taxonName.value();
}
/**
* Set Taxon name. The name of the taxon for which the
* path is requested.
*
* @param value Taxon name
*
* @return this plugin
*/
public PathToIgraphPlugin taxonName(String value) {
taxonName = new PluginParameter<>(taxonName, value);
return this;
}
/**
* The name of the taxon to which the path will be compared.
*
* @return Taxon name
*/
public String targetName() {
return targetName.value();
}
/**
* Set Taxon name. The name of the taxon to which the
* path will be compared.
*
* @param value Taxon name
*
* @return this plugin
*/
public PathToIgraphPlugin targetName(String value) {
targetName = new PluginParameter<>(targetName, value);
return this;
}
/**
* The path method name assigned when the path was created
* and stored in the DB. Not required if a path file name
* is supplied.
*
* @return Path method name
*/
public String pathName() {
return pathName.value();
}
/**
* Set Path method name. The path method name assigned
* when the path was created and stored in the DB. Not
* required if a path file name is supplied.
*
* @param value Path method name
*
* @return this plugin
*/
public PathToIgraphPlugin pathName(String value) {
pathName = new PluginParameter<>(pathName, value);
return this;
}
/**
* The haplotype count method name assigned when the counts
* were created and stored in the DB. Not required if
* a path file name is supplied or if only one method
* was used to find a path for this taxon.
*
* @return Haplotype count method name
*/
public String countMethod() {
return countMethod.value();
}
/**
* Set Haplotype count method name. The haplotype count
* method name assigned when the counts were created and
* stored in the DB. Not required if a path file name
* is supplied or if only one method was used to find
* a path for this taxon.
*
* @param value Haplotype count method name
*
* @return this plugin
*/
public PathToIgraphPlugin countMethod(String value) {
countMethod = new PluginParameter<>(countMethod, value);
return this;
}
/**
* The name of the fastq file used to create the path.
* This must be the name only, not the full path. Not
* required if the path and count data can be retrieved
* using other parameters.
*
* @return Fastq name
*/
public String fastqName() {
return fastqName.value();
}
/**
* Set Fastq name. The name of the fastq file used to
* create the path. This must be the name only, not the
* full path. Not required if the path and count data
* can be retrieved using other parameters.
*
* @param value Fastq name
*
* @return this plugin
*/
public PathToIgraphPlugin fastqName(String value) {
fastqName = new PluginParameter<>(fastqName, value);
return this;
}
/**
* Database configuration file
*
* @return Database Config File
*/
public String configFile() {
return configFile.value();
}
/**
* Set Database Config File. Database configuration file
*
* @param value Database Config File
*
* @return this plugin
*/
public PathToIgraphPlugin configFile(String value) {
configFile = new PluginParameter<>(configFile, value);
return this;
}
/**
* When the consensus nodes are split by taxa, this is
* the transition probability for moving from a node to
* the next node of the same taxon. It equals 1 minus
* the probability of a recombination between adjacent
* nodes.
*
* @return Split Prob
*/
public Double splitTransitionProb() {
return splitTransitionProb.value();
}
/**
* Set Split Prob. When the consensus nodes are split
* by taxa, this is the transition probability for moving
* from a node to the next node of the same taxon. It
* equals 1 minus the probability of a recombination between
* adjacent nodes.
*
* @param value Split Prob
*
* @return this plugin
*/
public PathToIgraphPlugin splitTransitionProb(Double value) {
splitTransitionProb = new PluginParameter<>(splitTransitionProb, value);
return this;
}
/**
* A list of taxa to include in graph. Only nodes containing these
* taxa will be included in the graph. If no taxa list is supplied,
* then all taxa in the full graph will be used.
*
* @return Taxa
*/
public TaxaList taxaFilterString() {
return taxaFilter.value();
}
/**
* Set Taxa. A list of taxa to include in graph. Only nodes containing
* these taxa will be included in the graph. If no taxa
* list is supplied, then all taxa in the full graph will
* be used.
*
* @param value Taxa
*
* @return this plugin
*/
public PathToIgraphPlugin taxaFilter(TaxaList value) {
taxaFilter = new PluginParameter<>(taxaFilter, value);
return this;
}
/**
* The name of the file containing the reference ranges
* to keep.
*
* @return Ref Range File
*/
public String refRangeFile() {
return refRangeFile.value();
}
/**
* Set Ref Range File. The name of the file containing
* the reference ranges to keep.
*
* @param value Ref Range File
*
* @return this plugin
*/
public PathToIgraphPlugin refRangeFile(String value) {
refRangeFile = new PluginParameter<>(refRangeFile, value);
return this;
}
/**
* base name for output files from this Plugin. Two files
* will be produced for each chromosome.
*
* @return Output file base
*/
public String outputBase() {
return outputBase.value();
}
/**
* Set Output file base. base name for output files from
* this Plugin. Two files will be produced for each chromosome.
*
* @param value Output file base
*
* @return this plugin
*/
public PathToIgraphPlugin outputBase(String value) {
outputBase = new PluginParameter<>(outputBase, value);
return this;
}
}