docs: 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();
      }