org.datavec.api.transform.ui.HtmlSequencePlotting Maven / Gradle / Ivy
/*-
* * 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> 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 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 divs = new ArrayList<>();
List 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 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 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 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> sequence,
File output) throws Exception {
String s = createHtmlSequencePlots(title, schema, sequence);
FileUtils.writeStringToFile(output, s);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy