Java tutorial
/*- * * Copyright 2016 Skymind, Inc. * * * * Licensed under the Apache License, Version 2.0 (the "License"); * * you may not use this file except in compliance with the License. * * You may obtain a copy of the License at * * * * http://www.apache.org/licenses/LICENSE-2.0 * * * * Unless required by applicable law or agreed to in writing, software * * distributed under the License is distributed on an "AS IS" BASIS, * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * * See the License for the specific language governing permissions and * * limitations under the License. */ package org.datavec.api.transform.ui; import freemarker.template.Configuration; import freemarker.template.Template; import freemarker.template.TemplateExceptionHandler; import freemarker.template.Version; import org.apache.commons.io.FileUtils; import org.datavec.api.transform.ColumnType; import org.datavec.api.transform.metadata.CategoricalMetaData; import org.datavec.api.transform.metadata.ColumnMetaData; import org.datavec.api.transform.schema.Schema; import org.datavec.api.transform.ui.components.RenderableComponentLineChart; import org.datavec.api.transform.ui.components.RenderableComponentTable; import org.datavec.api.writable.Writable; import org.joda.time.DateTimeZone; import org.joda.time.format.DateTimeFormat; import org.joda.time.format.DateTimeFormatter; import org.nd4j.shade.jackson.databind.DeserializationFeature; import org.nd4j.shade.jackson.databind.MapperFeature; import org.nd4j.shade.jackson.databind.ObjectMapper; import org.nd4j.shade.jackson.databind.SerializationFeature; import java.io.File; import java.io.StringWriter; import java.io.Writer; import java.util.*; /** * A simple utility for plotting DataVec sequence data to HTML files. * Each file contains only one sequence. Each column is plotted separately; only numerical and categorical columns are * plotted. * * @author Alex Black */ public class HtmlSequencePlotting { private HtmlSequencePlotting() { } /** * Create a HTML file with plots for the given sequence. * * @param title Title of the page * @param schema Schema for the data * @param sequence Sequence to plot * @return HTML file as a string */ public static String createHtmlSequencePlots(String title, Schema schema, List<List<Writable>> sequence) throws Exception { Configuration cfg = new Configuration(new Version(2, 3, 23)); // Where do we load the templates from: cfg.setClassForTemplateLoading(HtmlSequencePlotting.class, "/templates/"); // Some other recommended settings: cfg.setIncompatibleImprovements(new Version(2, 3, 23)); cfg.setDefaultEncoding("UTF-8"); cfg.setLocale(Locale.US); cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER); Map<String, Object> input = new HashMap<>(); input.put("pagetitle", title); ObjectMapper ret = new ObjectMapper(); ret.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); ret.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); ret.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true); ret.enable(SerializationFeature.INDENT_OUTPUT); List<DivObject> divs = new ArrayList<>(); List<String> divNames = new ArrayList<>(); //First: create table for schema int n = schema.numColumns(); String[][] table = new String[n / 2 + n % 2][6]; //Number, name, type; 2 columns List<ColumnMetaData> meta = schema.getColumnMetaData(); for (int i = 0; i < meta.size(); i++) { int o = i % 2; table[i / 2][o * 3] = String.valueOf(i); table[i / 2][o * 3 + 1] = meta.get(i).getName(); table[i / 2][o * 3 + 2] = meta.get(i).getColumnType().toString(); } for (int i = 0; i < table.length; i++) { for (int j = 0; j < table[i].length; j++) { if (table[i][j] == null) { table[i][j] = ""; } } } RenderableComponentTable rct = new RenderableComponentTable.Builder().table(table) .header("#", "Name", "Type", "#", "Name", "Type").backgroundColor("#FFFFFF").headerColor("#CCCCCC") .colWidthsPercent(8, 30, 12, 8, 30, 12).border(1).padLeftPx(4).padRightPx(4).build(); divs.add(new DivObject("tablesource", ret.writeValueAsString(rct))); //Create the plots double[] x = new double[sequence.size()]; for (int i = 0; i < x.length; i++) { x[i] = i; } for (int i = 0; i < n; i++) { double[] lineData; switch (meta.get(i).getColumnType()) { case Integer: case Long: case Double: case Float: case Time: lineData = new double[sequence.size()]; for (int j = 0; j < lineData.length; j++) { lineData[j] = sequence.get(j).get(i).toDouble(); } break; case Categorical: //This is a quick-and-dirty way to plot categorical variables as a line chart List<String> stateNames = ((CategoricalMetaData) meta.get(i)).getStateNames(); lineData = new double[sequence.size()]; for (int j = 0; j < lineData.length; j++) { String state = sequence.get(j).get(i).toString(); int idx = stateNames.indexOf(state); lineData[j] = idx; } break; case Bytes: case String: case Boolean: default: //Skip continue; } String name = meta.get(i).getName(); String chartTitle = "Column: \"" + name + "\" - Column Type: " + meta.get(i).getColumnType(); if (meta.get(i).getColumnType() == ColumnType.Categorical) { List<String> stateNames = ((CategoricalMetaData) meta.get(i)).getStateNames(); StringBuilder sb = new StringBuilder(chartTitle); sb.append(" - ("); for (int j = 0; j < stateNames.size(); j++) { if (j > 0) { sb.append(", "); } sb.append(j).append("=").append(stateNames.get(j)); } sb.append(")"); chartTitle = sb.toString(); } RenderableComponentLineChart lc = new RenderableComponentLineChart.Builder().title(chartTitle) .addSeries(name, x, lineData).build(); String divname = "plot_" + i; divs.add(new DivObject(divname, ret.writeValueAsString(lc))); divNames.add(divname); } input.put("divs", divs); input.put("divnames", divNames); //Current date/time, UTC DateTimeFormatter formatter = DateTimeFormat.forPattern("YYYY-MM-dd HH:mm:ss zzz") .withZone(DateTimeZone.UTC); long currTime = System.currentTimeMillis(); String dateTime = formatter.print(currTime); input.put("datetime", dateTime); Template template = cfg.getTemplate("sequenceplot.ftl"); //Process template to String Writer stringWriter = new StringWriter(); template.process(input, stringWriter); return stringWriter.toString(); } /** * Create a HTML file with plots for the given sequence and write it to a file. * * @param title Title of the page * @param schema Schema for the data * @param sequence Sequence to plot */ public static void createHtmlSequencePlotFile(String title, Schema schema, List<List<Writable>> sequence, File output) throws Exception { String s = createHtmlSequencePlots(title, schema, sequence); FileUtils.writeStringToFile(output, s); } }