All Downloads are FREE. Search and download functionalities are using the official Maven repository.

lphystudio.app.NarrativeCreator Maven / Gradle / Ivy

The newest version!
package lphystudio.app;

import lphy.core.io.UserDir;
import lphy.core.logger.LoggerUtils;
import lphy.core.model.NarrativeUtils;
import lphystudio.app.graphicalmodelcomponent.GraphicalModelComponent;
import lphystudio.app.graphicalmodelpanel.GraphicalModelPanel;
import lphystudio.app.graphicalmodelpanel.GraphicalModelParserDictionary;
import lphystudio.core.narrative.HTMLNarrative;
import lphystudio.core.narrative.LaTeXNarrative;
import lphystudio.core.narrative.Section;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Path;
import java.nio.file.Paths;

/**
 * Create markdown files for Jekyll containing the sections
 * (code, data, model, posterior, graphical model)
 * to introduce LPhy scripts for the tutorial.
 * Input: *.lphy
 * Output: narrative.md, references.md
 */
public class NarrativeCreator {
    public static final String DIV_BOX_BACKGR_COLOUR =
            "
"; HTMLNarrative htmlNarrative; LaTeXNarrative latexNarrative; StringBuilder code = new StringBuilder(); StringBuilder narrative = new StringBuilder(); StringBuilder references = new StringBuilder(); // static Preferences preferences = Preferences.userNodeForPackage(NarrativeCreator.class); public NarrativeCreator(String lphyFileName) throws IOException { htmlNarrative = new HTMLNarrative(); latexNarrative = new LaTeXNarrative(); Path wd = UserDir.getUserDir(); // working dir Path imgFile = Paths.get(wd.toString(), "GraphicalModel.png"); // assume file under working dir Path lphyPath = Paths.get(wd.toString(), lphyFileName); if (!lphyPath.toFile().exists()) throw new IOException("Cannot find lphy script at " + lphyPath); try { GraphicalModelParserDictionary parser = new GraphicalModelParserDictionary(); GraphicalModelPanel panel = new GraphicalModelPanel(parser, null); panel.getComponent().setShowConstantNodes(false); // parse and paint Utils.readFile(lphyPath.toFile(), panel); createNarrativeExclImg(panel.getParserDictionary(), imgFile); LoggerUtils.log.warning("Image " + imgFile.getFileName() + " needs to be created separately !"); // TODO The quality of PNG is too low LinguaPhylo/linguaPhylo#130 createImage(imgFile.toFile(), panel.getComponent()); } catch (IOException e) { e.printStackTrace(); } try { writeNarrative(wd); } catch (IOException e) { e.printStackTrace(); } } // private GraphicalModelContainer getParser(String lphyFileName) throws IOException { // if (!lphyFileName.endsWith(".lphy")) // throw new IllegalArgumentException("Invalid LPhy file name " + lphyFileName + " !"); // // Path path = UserDir.getUserPath(lphyFileName); // // set user.dir to the folder containing example file, // // so that the relative path given in readNexus always refers to it // UserDir.setUserDir(path.getParent().toString()); // // BufferedReader reader = new BufferedReader(new FileReader(path.toString())); // LPhyParser parser = new REPL(); // parser.source(reader); // // // A wrapper for any implementation of LPhyParser that will be used in the Studio // return new GraphicalModelContainer(parser); // } private void createImage(File imgFile, GraphicalModelComponent component) throws IOException { Utils.exportToPNG(imgFile, component); LoggerUtils.log.info("Save " + imgFile.getAbsolutePath()); } // exclude creating image private void createNarrativeExclImg(GraphicalModelParserDictionary parserDictionary, final Path imgFile) { // assume Data, Model, Posterior stay together with this order, // so wrap them with
for a box with diff background colour. for (Section section : Section.values()) { switch (section) { case Code -> { code.append(section("Code")); code.append(htmlNarrative.codeBlock(parserDictionary, 11)); code.append("\n"); } case GraphicalModel -> { code.append(section("Graphical Model")); // create html to load image code.append("\n
\n"); code.append(" \n"); code.append(" \"").append(imgFile.getFileName())\n"); code.append(" \n"); // replace fignum using Liquid in Jekyll MD code.append("
{{ include.fignum }}: The graphical model
\n"); code.append("
\n\n"); code.append("\n"); // create image later } // move Data, Model, Posterior to the bottom of webpage case Data -> { String dataSec = NarrativeUtils.getNarrative(parserDictionary, htmlNarrative, true, false); // narrative.append("\n
\n"); // narrative.append("Click to expand the auto-generated narrative from LPhyStudio ...\n"); narrative.append("\n" + DIV_BOX_BACKGR_COLOUR + "\n"); narrative.append(dataSec); narrative.append("\n"); } case Model -> { String modelSec = NarrativeUtils.getNarrative(parserDictionary, htmlNarrative, false, true); narrative.append(modelSec); narrative.append("\n"); } case Posterior -> { narrative.append(htmlNarrative.section("Posterior")); String pos = NarrativeUtils.getInferenceStatement(parserDictionary, latexNarrative); pos = htmlNarrative.rmLatexEquation(pos); // replace equation to $$ ... $$ narrative.append("$$\n").append(pos).append("\n$$\n\n"); narrative.append("\n
\n"); // narrative.append("\n\n"); } case References -> { String ref = htmlNarrative.referenceSection(); references.append(ref); } } } // special requirement // add link code.append("\nFor the details, please read the auto-generated ") .append("[narrative](#auto-generated)") .append(" from LPhyStudio.\n"); } private void writeNarrative(Path wd) throws IOException { String lphyStr = replaceEscapeCharInLPhyScript(code.toString()); Path path = Paths.get(wd.toString(), "lphy.md"); writeToFile(lphyStr, path); // it seems to print as it is if escape chars are inside
String narStr = narrative.toString(); validateTags(narStr, "div"); // validateTags(narStr, "details"); path = Paths.get(wd.toString(), "narrative.md"); writeToFile(narStr, path); String ref = references.toString(); // convert MD, otherwise will have a gap when add new ref in MD ref = convertHtmlListToMardown(ref); // rm all \n, otherwise will have a gap ref = trimEndNewLine(ref); path = Paths.get(wd.toString(), "references.md"); writeToFile(ref, path); } // case by case to replace escape char in lphy script. // if * is inside html which is inside a markdown (e.g. jekyll), then use \*, // also \| to \\|, " to ", and so on private String replaceEscapeCharInLPhyScript(String old) { // \| to \\| String newStr = old.replaceAll("\\\\\\|", "\\\\\\\\|"); // \. to \\. newStr = newStr.replaceAll("\\\\\\.", "\\\\\\\\."); // " (must be lphy code, not html) to " newStr = newStr.replaceAll(">\"", ">""); newStr = newStr.replaceAll("\"<", ""<"); // ' to ' newStr = newStr.replaceAll(">'", ">'"); newStr = newStr.replaceAll("'<", "'<"); // * to \* return newStr.replaceAll("\\*", "\\\\*"); } // if * is inside a jekyll markdown but not inside html tags, use * // private String replaceAsteriskInMD(String old) { // return old.replaceAll("\\*", "*"); // } private void writeToFile(String str, Path path) throws IOException { PrintWriter writer = new PrintWriter(new FileWriter(path.toString())); // references do not new line writer.print(str); writer.flush(); writer.close(); System.out.println("Write \"" + (str.length() > 20 ? str.substring(0, 20) : str) + "\" ...\nto " + path.toAbsolutePath()); } // markdown section private String section(String header) { return "## " + header + "\n\n"; } // convert html list into markdown private String convertHtmlListToMardown(String ref) { ref = ref.replace("
    ", ""); ref = ref.replace("
", ""); ref = ref.replace("
  • ", "* "); ref = ref.replace("
  • ", ""); return ref; } private String trimEndNewLine(String str) { final int tailIndex = 3; // a plain-text match, no regex if (str.endsWith("\n") && str.length() > tailIndex) { int mark = str.lastIndexOf("\n")-tailIndex; StringBuilder builder = new StringBuilder(str.substring(0, mark)); String end = str.substring(mark).replace("\n", ""); builder.append(end); return builder.toString(); } return str; } // check if
    and
    are in correct position private void validateTags(String narStr, String tagStr) { int openTag = narStr.toLowerCase().indexOf("<" + tagStr.toLowerCase()); // it may have attrs int closeTag = narStr.toLowerCase().indexOf(""); if (openTag >= closeTag) throw new IllegalStateException("Invalid position of <" + tagStr + "> !"); } private String replaceHTMLSection(String html) { return html.replaceFirst("<" + HTMLNarrative.SECTION_TAG + ">(.*)", section("$1")); } // input: -Duser.dir=/lphy/path/tutorials h3n2.lphy public static void main(String[] args) { if (args.length != 1) throw new IllegalArgumentException("Expecting LPhy file name !"); // always the last arg, such as h5n1.lphy, assuming the file is under user.dir String lphyFileName = args[args.length - 1]; try { NarrativeCreator narrativeCreator = new NarrativeCreator(lphyFileName); } catch (IOException e) { e.printStackTrace(); } System.exit(0); } }




    © 2015 - 2024 Weber Informatics LLC | Privacy Policy