Repository: jtablesaw/tablesaw
Pull request #1146 (2022-09-12 08:16:47)

Take prefix/suffix TickSettings into account and add format option
Thanks for contributing.

- [X] Tick to sign-off your agreement to the [Developer Certificate of Origin (DCO) 1.1](https://developercertificate.org)

## Description

In tablesaw-jsplot, `AxisSettings.{prefix|suffix|showPrefix|showSuffix}` were not used in `axis_template.html`, making them useless.
I updated the template to use these options, and also added a `format` option matching plotly's `tickformat`.
I also fixed the value for `DisplayRules.ALL` from 'outside' to 'all'

## Testing

No new unit tests



Patch:
diff --git a/arrow/pom.xml b/arrow/pom.xml
index 6c2585a4..49942a4b 100644
--- a/arrow/pom.xml
+++ b/arrow/pom.xml
@@ -88,18 +88,18 @@
     <dependency>
       <groupId>org.apache.arrow</groupId>
       <artifactId>arrow-vector</artifactId>
-      <version>7.0.0</version>
+      <version>15.0.1</version>
     </dependency>
     <dependency>
       <groupId>com.fasterxml.jackson.core</groupId>
       <artifactId>jackson-annotations</artifactId>
-      <version>2.13.2</version>
+      <version>2.17.0</version>
     </dependency>
 
     <dependency>
       <groupId>org.apache.arrow</groupId>
       <artifactId>arrow-memory-netty</artifactId>
-      <version>7.0.0</version>
+      <version>15.0.1</version>
       <exclusions>
         <exclusion>
           <groupId>com.fasterxml.jackson.core</groupId>
diff --git a/core/pom.xml b/core/pom.xml
index 2f91c8dc..f6069972 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -56,7 +56,7 @@
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-jar-plugin</artifactId>
-                <version>3.0.2</version>
+                <version>3.3.0</version>
                 <executions>
                     <execution>
                         <goals>
@@ -76,7 +76,7 @@
         <dependency>
             <groupId>com.google.guava</groupId>
             <artifactId>guava</artifactId>
-            <version>30.0-jre</version>
+            <version>33.0.0-jre</version>
         </dependency>
         <dependency>
             <groupId>org.apache.commons</groupId>
@@ -86,27 +86,27 @@
         <dependency>
             <groupId>it.unimi.dsi</groupId>
             <artifactId>fastutil</artifactId>
-            <version>8.3.0</version>
+            <version>8.5.13</version>
         </dependency>
        <dependency>
             <groupId>org.roaringbitmap</groupId>
             <artifactId>RoaringBitmap</artifactId>
-            <version>0.9.25</version>
+            <version>1.0.5</version>
         </dependency>
         <dependency>
             <groupId>com.univocity</groupId>
             <artifactId>univocity-parsers</artifactId>
-            <version>2.8.4</version>
+            <version>2.9.1</version>
         </dependency>
         <dependency>
             <groupId>com.ibm.icu</groupId>
             <artifactId>icu4j</artifactId>
-            <version>68.2</version>
+            <version>74.2</version>
         </dependency>
         <dependency>
             <groupId>io.github.classgraph</groupId>
             <artifactId>classgraph</artifactId>
-            <version>4.8.60</version>
+            <version>4.8.168</version>
         </dependency>
         <dependency>
             <groupId>org.slf4j</groupId>
@@ -115,7 +115,7 @@
         <dependency>
             <groupId>com.github.haifengl</groupId>
             <artifactId>smile-data</artifactId>
-            <version>2.0.0</version>
+            <version>2.6.0</version>
             <optional>true</optional>
             <scope>provided</scope> <!-- because the shade plugin doesn't exclude optional dependencies -->
         </dependency>
@@ -132,37 +132,43 @@
         <dependency>
             <groupId>org.apache.commons</groupId>
             <artifactId>commons-lang3</artifactId>
-            <version>3.9</version>
+            <version>3.14.0</version>
             <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>org.apache.commons</groupId>
             <artifactId>commons-text</artifactId>
-            <version>1.8</version>
+            <version>1.11.0</version>
             <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>com.github.jbellis</groupId>
             <artifactId>jamm</artifactId> <!-- Memory usage testing -->
-            <version>0.3.3</version>
+            <version>0.4.0</version>
             <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>com.h2database</groupId>
             <artifactId>h2</artifactId>
-            <version>2.1.210</version>
+            <version>2.2.224</version>
             <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>com.github.haifengl</groupId>
             <artifactId>smile-core</artifactId>
-            <version>2.0.0</version>
+            <version>2.6.0</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.github.haifengl</groupId>
+            <artifactId>smile-mkl</artifactId>
+            <version>2.6.0</version>
             <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>com.google.jimfs</groupId>
             <artifactId>jimfs</artifactId>
-            <version>1.1</version>
+            <version>1.3.0</version>
             <scope>test</scope>
         </dependency>
     </dependencies>
diff --git a/core/src/main/java/tech/tablesaw/api/BooleanColumn.java b/core/src/main/java/tech/tablesaw/api/BooleanColumn.java
index 6775b313..9bfa5833 100644
--- a/core/src/main/java/tech/tablesaw/api/BooleanColumn.java
+++ b/core/src/main/java/tech/tablesaw/api/BooleanColumn.java
@@ -133,7 +133,7 @@ public class BooleanColumn extends AbstractColumn<BooleanColumn, Boolean>
   }
 
   /**
-   * Returns a new Boolean column of the given size. All elements are false
+   * Returns a new Boolean column of the given size.
    *
    * @param name The column name
    * @param initialSize The column size
@@ -422,7 +422,7 @@ public class BooleanColumn extends AbstractColumn<BooleanColumn, Boolean>
     return (double) countTrue() / (size() - countMissing());
   }
 
-  /** Returns the proportion of non-missing row elements that contain true */
+  /** Returns the proportion of non-missing row elements that contain false */
   public double proportionFalse() {
     return 1.0 - proportionTrue();
   }
diff --git a/core/src/main/java/tech/tablesaw/columns/AbstractColumn.java b/core/src/main/java/tech/tablesaw/columns/AbstractColumn.java
index 31ab2d76..8fa22860 100644
--- a/core/src/main/java/tech/tablesaw/columns/AbstractColumn.java
+++ b/core/src/main/java/tech/tablesaw/columns/AbstractColumn.java
@@ -194,4 +194,11 @@ public abstract class AbstractColumn<C extends Column<T>, T> implements Column<T
   public int indexOf(final Object o) {
     return IntStream.range(0, size()).filter(i -> get(i).equals(o)).findFirst().orElse(-1);
   }
+
+  /** {@inheritDoc} */
+  @Override
+  public int lastIndexOf(Object o) {
+    return IntStream.iterate(size() - 1, i -> (i >= 0), i -> i - 1).filter(i -> get(i).equals(o))
+            .findFirst().orElse(-1);
+  }
 }
diff --git a/core/src/main/java/tech/tablesaw/columns/Column.java b/core/src/main/java/tech/tablesaw/columns/Column.java
index f88ebd2c..83ba1dc8 100644
--- a/core/src/main/java/tech/tablesaw/columns/Column.java
+++ b/core/src/main/java/tech/tablesaw/columns/Column.java
@@ -743,4 +743,10 @@ public interface Column<T> extends Iterable<T>, Comparator<T> {
    * not in the column.
    */
   int indexOf(Object o);
+
+  /**
+   * Returns the index of the last occurrence of {@code o} in the column or -1 if the element is not
+   * in the column.
+   */
+  int lastIndexOf(Object o);
 }
diff --git a/core/src/main/java/tech/tablesaw/columns/dates/DateParser.java b/core/src/main/java/tech/tablesaw/columns/dates/DateParser.java
index 0012b50f..b2d99f31 100644
--- a/core/src/main/java/tech/tablesaw/columns/dates/DateParser.java
+++ b/core/src/main/java/tech/tablesaw/columns/dates/DateParser.java
@@ -8,6 +8,7 @@ import java.time.format.DateTimeParseException;
 import java.util.Locale;
 import tech.tablesaw.api.ColumnType;
 import tech.tablesaw.columns.AbstractColumnParser;
+import tech.tablesaw.columns.datetimes.DateTimeParser;
 import tech.tablesaw.io.ReadOptions;
 
 public class DateParser extends AbstractColumnParser<LocalDate> {
@@ -19,19 +20,19 @@ public class DateParser extends AbstractColumnParser<LocalDate> {
   private static final DateTimeFormatter dtf4 = DateTimeFormatter.ofPattern("MM.dd.yyyy");
   private static final DateTimeFormatter dtf5 = DateTimeFormatter.ofPattern("yyyy-MM-dd");
   private static final DateTimeFormatter dtf6 = DateTimeFormatter.ofPattern("yyyy/MM/dd");
-  private static final DateTimeFormatter dtf7 = DateTimeFormatter.ofPattern("dd/MMM/yyyy");
-  private static final DateTimeFormatter dtf8 = DateTimeFormatter.ofPattern("dd-MMM-yyyy");
+  private static final DateTimeFormatter dtf7 = DateTimeParser.caseInsensitiveFormatter("dd/MMM/yyyy");
+  private static final DateTimeFormatter dtf8 = DateTimeParser.caseInsensitiveFormatter("dd-MMM-yyyy");
   private static final DateTimeFormatter dtf9 = DateTimeFormatter.ofPattern("M/d/yyyy");
   private static final DateTimeFormatter dtf10 = DateTimeFormatter.ofPattern("M/d/yy");
-  private static final DateTimeFormatter dtf11 = DateTimeFormatter.ofPattern("MMM/dd/yyyy");
-  private static final DateTimeFormatter dtf12 = DateTimeFormatter.ofPattern("MMM-dd-yyyy");
-  private static final DateTimeFormatter dtf13 = DateTimeFormatter.ofPattern("MMM/dd/yy");
-  private static final DateTimeFormatter dtf14 = DateTimeFormatter.ofPattern("MMM-dd-yy");
-  private static final DateTimeFormatter dtf15 = DateTimeFormatter.ofPattern("MMM/dd/yyyy");
-  private static final DateTimeFormatter dtf16 = DateTimeFormatter.ofPattern("MMM/d/yyyy");
-  private static final DateTimeFormatter dtf17 = DateTimeFormatter.ofPattern("MMM-dd-yy");
-  private static final DateTimeFormatter dtf18 = DateTimeFormatter.ofPattern("MMM dd, yyyy");
-  private static final DateTimeFormatter dtf19 = DateTimeFormatter.ofPattern("MMM d, yyyy");
+  private static final DateTimeFormatter dtf11 = DateTimeParser.caseInsensitiveFormatter("MMM/dd/yyyy");
+  private static final DateTimeFormatter dtf12 = DateTimeParser.caseInsensitiveFormatter("MMM-dd-yyyy");
+  private static final DateTimeFormatter dtf13 = DateTimeParser.caseInsensitiveFormatter("MMM/dd/yy");
+  private static final DateTimeFormatter dtf14 = DateTimeParser.caseInsensitiveFormatter("MMM-dd-yy");
+  private static final DateTimeFormatter dtf15 = DateTimeParser.caseInsensitiveFormatter("MMM/dd/yyyy");
+  private static final DateTimeFormatter dtf16 = DateTimeParser.caseInsensitiveFormatter("MMM/d/yyyy");
+  private static final DateTimeFormatter dtf17 = DateTimeParser.caseInsensitiveFormatter("MMM-dd-yy");
+  private static final DateTimeFormatter dtf18 = DateTimeParser.caseInsensitiveFormatter("MMM dd, yyyy");
+  private static final DateTimeFormatter dtf19 = DateTimeParser.caseInsensitiveFormatter("MMM d, yyyy");
 
   // A formatter that handles all the date formats defined above
   public static final DateTimeFormatter DEFAULT_FORMATTER =
diff --git a/core/src/main/java/tech/tablesaw/columns/datetimes/DateTimeParser.java b/core/src/main/java/tech/tablesaw/columns/datetimes/DateTimeParser.java
index aa0dfd4e..cc6dd8f3 100644
--- a/core/src/main/java/tech/tablesaw/columns/datetimes/DateTimeParser.java
+++ b/core/src/main/java/tech/tablesaw/columns/datetimes/DateTimeParser.java
@@ -19,14 +19,26 @@ public class DateTimeParser extends AbstractColumnParser<LocalDateTime> {
       DateTimeFormatter.ofPattern(
           "yyyy-MM-dd HH:mm:ss.S"); // 2014-07-09 13:03:44.7 (as above, but without leading 0 in
   // millis)
-  private static final DateTimeFormatter dtTimef4 =
-      DateTimeFormatter.ofPattern("dd-MMM-yyyy HH:mm"); // 09-Jul-2014 13:03
+  private static final DateTimeFormatter dtTimef4 = caseInsensitiveFormatter("dd-MMM-yyyy HH:mm"); // 09-Jul-2014 13:03
   private static final DateTimeFormatter dtTimef5 = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
   private static final DateTimeFormatter dtTimef6; // ISO, with millis appended
   private static final DateTimeFormatter dtTimef7 = //  7/9/14 9:04
       DateTimeFormatter.ofPattern("M/d/yy H:mm");
-  private static final DateTimeFormatter dtTimef8 =
-      DateTimeFormatter.ofPattern("M/d/yyyy h:mm:ss a"); //  7/9/2014 9:04:55 PM
+  private static final DateTimeFormatter dtTimef8 = caseInsensitiveFormatter("M/d/yyyy h:mm:ss a"); //  7/9/2014 9:04:55 PM
+
+  /**
+   * Creates a Case-insensitive formatter using the specified pattern.
+   * This method will create a formatter based on a simple pattern of letters and symbols as described in the class documentation.
+   * For example, d MMM yyyy will format 2011-12-03 as '3 Dec 2011'. The formatter will use the default FORMAT locale.
+   * This function can handle cases like am/AM, pm/PM, Jan/JAN, Feb/FEB etc
+   *
+   * @param pattern the pattern to use, not null
+   * @return the formatter based on the pattern, not null
+   * @throws IllegalArgumentException if the pattern is invalid
+   */
+  public static DateTimeFormatter caseInsensitiveFormatter(String pattern) {
+    return new DateTimeFormatterBuilder().parseCaseInsensitive().appendPattern(pattern).toFormatter();
+  }
 
   static {
     dtTimef6 =
diff --git a/core/src/main/java/tech/tablesaw/columns/times/TimeParser.java b/core/src/main/java/tech/tablesaw/columns/times/TimeParser.java
index 35ee4107..242ed97f 100644
--- a/core/src/main/java/tech/tablesaw/columns/times/TimeParser.java
+++ b/core/src/main/java/tech/tablesaw/columns/times/TimeParser.java
@@ -9,16 +9,17 @@ import java.time.format.DateTimeParseException;
 import java.util.Locale;
 import tech.tablesaw.api.ColumnType;
 import tech.tablesaw.columns.AbstractColumnParser;
+import tech.tablesaw.columns.datetimes.DateTimeParser;
 import tech.tablesaw.io.ReadOptions;
 
 public class TimeParser extends AbstractColumnParser<LocalTime> {
 
   private static final DateTimeFormatter timef1 = DateTimeFormatter.ofPattern("HH:mm:ss.SSS");
-  private static final DateTimeFormatter timef2 = DateTimeFormatter.ofPattern("hh:mm:ss a");
-  private static final DateTimeFormatter timef3 = DateTimeFormatter.ofPattern("h:mm:ss a");
+  private static final DateTimeFormatter timef2 = DateTimeParser.caseInsensitiveFormatter("hh:mm:ss a");
+  private static final DateTimeFormatter timef3 = DateTimeParser.caseInsensitiveFormatter("h:mm:ss a");
   private static final DateTimeFormatter timef4 = DateTimeFormatter.ISO_LOCAL_TIME;
-  private static final DateTimeFormatter timef5 = DateTimeFormatter.ofPattern("hh:mm a");
-  private static final DateTimeFormatter timef6 = DateTimeFormatter.ofPattern("h:mm a");
+  private static final DateTimeFormatter timef5 = DateTimeParser.caseInsensitiveFormatter("hh:mm a");
+  private static final DateTimeFormatter timef6 = DateTimeParser.caseInsensitiveFormatter("h:mm a");
 
   // only for parsing:
   private static final DateTimeFormatter timef7 = DateTimeFormatter.ofPattern("HHmm");
diff --git a/core/src/main/java/tech/tablesaw/io/FileReader.java b/core/src/main/java/tech/tablesaw/io/FileReader.java
index bec89c04..4c8f96e5 100644
--- a/core/src/main/java/tech/tablesaw/io/FileReader.java
+++ b/core/src/main/java/tech/tablesaw/io/FileReader.java
@@ -132,12 +132,12 @@ public abstract class FileReader {
     Map<String, Integer> nameCounter = new HashMap<>();
     for (int i = 0; i < headerNames.length; i++) {
       String name = headerNames[i];
-      Integer count = nameCounter.get(name);
+      Integer count = nameCounter.get(name.toLowerCase());
       if (count == null) {
-        nameCounter.put(name, 1);
+        nameCounter.put(name.toLowerCase(), 1);
       } else {
         count++;
-        nameCounter.put(name, count);
+        nameCounter.put(name.toLowerCase(), count);
         headerNames[i] = name + "-" + count;
       }
     }
diff --git a/excel/pom.xml b/excel/pom.xml
index 25084a94..1bcacb80 100644
--- a/excel/pom.xml
+++ b/excel/pom.xml
@@ -71,7 +71,7 @@
       <dependency>
           <groupId>org.apache.poi</groupId>
           <artifactId>poi-ooxml</artifactId>
-          <version>5.2.2</version>
+          <version>5.2.5</version>
       </dependency>
     <dependency>
       <groupId>org.junit.jupiter</groupId>
diff --git a/html/pom.xml b/html/pom.xml
index 7d0bdc0d..9ea8593a 100644
--- a/html/pom.xml
+++ b/html/pom.xml
@@ -70,7 +70,7 @@
     <dependency>
       <groupId>org.jsoup</groupId>
       <artifactId>jsoup</artifactId>
-      <version>1.15.3</version>
+      <version>1.17.2</version>
     </dependency>
     <dependency>
       <groupId>org.junit.jupiter</groupId>
diff --git a/json/pom.xml b/json/pom.xml
index b3af65d1..b68faa9f 100644
--- a/json/pom.xml
+++ b/json/pom.xml
@@ -78,7 +78,7 @@
     <dependency>
       <groupId>com.github.wnameless.json</groupId>
       <artifactId>json-flattener</artifactId>
-      <version>0.8.1</version>
+      <version>0.16.6</version>
     </dependency>
     <dependency>
       <groupId>org.junit.jupiter</groupId>
diff --git a/json/src/main/java/tech/tablesaw/io/json/JsonReader.java b/json/src/main/java/tech/tablesaw/io/json/JsonReader.java
index 91bd4e4c..921e5df8 100644
--- a/json/src/main/java/tech/tablesaw/io/json/JsonReader.java
+++ b/json/src/main/java/tech/tablesaw/io/json/JsonReader.java
@@ -6,7 +6,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
 import com.github.wnameless.json.flattener.JsonFlattener;
 import java.io.IOException;
 import java.util.ArrayList;
-import java.util.HashSet;
+import java.util.LinkedHashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
@@ -103,7 +103,7 @@ public class JsonReader implements DataReader<JsonReadOptions> {
       throw new RuntimeIOException(e);
     }
 
-    Set<String> colNames = new HashSet<>();
+    Set<String> colNames = new LinkedHashSet<>();
     for (JsonNode row : flattenedJsonObj) {
       Iterator<String> fieldNames = row.fieldNames();
       while (fieldNames.hasNext()) {
diff --git a/jsplot/pom.xml b/jsplot/pom.xml
index 1cd691a2..372baf2b 100644
--- a/jsplot/pom.xml
+++ b/jsplot/pom.xml
@@ -69,7 +69,7 @@
         <dependency>
             <groupId>io.pebbletemplates</groupId>
             <artifactId>pebble</artifactId>
-            <version>3.1.2</version>
+            <version>3.2.2</version>
         </dependency>
         <dependency>
             <groupId>tech.tablesaw</groupId>
diff --git a/jsplot/src/main/java/tech/tablesaw/plotly/api/PricePlot.java b/jsplot/src/main/java/tech/tablesaw/plotly/api/PricePlot.java
index b0f11efa..be604922 100644
--- a/jsplot/src/main/java/tech/tablesaw/plotly/api/PricePlot.java
+++ b/jsplot/src/main/java/tech/tablesaw/plotly/api/PricePlot.java
@@ -27,17 +27,17 @@ public abstract class PricePlot {
     NumericColumn<?> low = table.numberColumn(lowCol);
     NumericColumn<?> close = table.numberColumn(closeCol);
     ScatterTrace trace;
-    if (x.type() == ColumnType.LOCAL_DATE) {
+    if (ColumnType.LOCAL_DATE.equals(x.type())) {
       trace =
           ScatterTrace.builder(table.dateColumn(xCol), open, high, low, close)
               .type(plotType)
               .build();
-    } else if (x.type() == ColumnType.LOCAL_DATE_TIME) {
+    } else if (ColumnType.LOCAL_DATE_TIME.equals(x.type())) {
       trace =
           ScatterTrace.builder(table.dateTimeColumn(xCol), open, high, low, close)
               .type(plotType)
               .build();
-    } else if (x.type() == ColumnType.INSTANT) {
+    } else if (ColumnType.INSTANT.equals(x.type())) {
       trace =
           ScatterTrace.builder(table.instantColumn(xCol), open, high, low, close)
               .type(plotType)
diff --git a/jsplot/src/main/java/tech/tablesaw/plotly/components/Component.java b/jsplot/src/main/java/tech/tablesaw/plotly/components/Component.java
index 6f8a8a38..d9af9988 100644
--- a/jsplot/src/main/java/tech/tablesaw/plotly/components/Component.java
+++ b/jsplot/src/main/java/tech/tablesaw/plotly/components/Component.java
@@ -3,9 +3,9 @@ package tech.tablesaw.plotly.components;
 import com.fasterxml.jackson.annotation.JsonInclude.Include;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.SerializationFeature;
-import com.mitchellbosecke.pebble.PebbleEngine;
-import com.mitchellbosecke.pebble.error.PebbleException;
-import com.mitchellbosecke.pebble.template.PebbleTemplate;
+import io.pebbletemplates.pebble.PebbleEngine;
+import io.pebbletemplates.pebble.error.PebbleException;
+import io.pebbletemplates.pebble.template.PebbleTemplate;
 import java.io.IOException;
 import java.io.StringWriter;
 import java.io.UncheckedIOException;
diff --git a/jsplot/src/main/java/tech/tablesaw/plotly/components/Figure.java b/jsplot/src/main/java/tech/tablesaw/plotly/components/Figure.java
index 47352e46..99421ee8 100644
--- a/jsplot/src/main/java/tech/tablesaw/plotly/components/Figure.java
+++ b/jsplot/src/main/java/tech/tablesaw/plotly/components/Figure.java
@@ -1,9 +1,6 @@
 package tech.tablesaw.plotly.components;
 
 import com.google.common.base.Preconditions;
-import com.mitchellbosecke.pebble.PebbleEngine;
-import com.mitchellbosecke.pebble.error.PebbleException;
-import com.mitchellbosecke.pebble.template.PebbleTemplate;
 import java.io.IOException;
 import java.io.StringWriter;
 import java.io.UncheckedIOException;
@@ -13,6 +10,10 @@ import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+
+import io.pebbletemplates.pebble.PebbleEngine;
+import io.pebbletemplates.pebble.error.PebbleException;
+import io.pebbletemplates.pebble.template.PebbleTemplate;
 import tech.tablesaw.plotly.event.EventHandler;
 import tech.tablesaw.plotly.traces.Trace;
 
diff --git a/jsplot/src/main/java/tech/tablesaw/plotly/components/Layout.java b/jsplot/src/main/java/tech/tablesaw/plotly/components/Layout.java
index fdc2571f..30a25873 100644
--- a/jsplot/src/main/java/tech/tablesaw/plotly/components/Layout.java
+++ b/jsplot/src/main/java/tech/tablesaw/plotly/components/Layout.java
@@ -1,14 +1,15 @@
 package tech.tablesaw.plotly.components;
 
-import com.mitchellbosecke.pebble.PebbleEngine;
-import com.mitchellbosecke.pebble.error.PebbleException;
-import com.mitchellbosecke.pebble.template.PebbleTemplate;
 import java.io.IOException;
 import java.io.StringWriter;
 import java.io.UncheckedIOException;
 import java.io.Writer;
 import java.util.HashMap;
 import java.util.Map;
+
+import io.pebbletemplates.pebble.PebbleEngine;
+import io.pebbletemplates.pebble.error.PebbleException;
+import io.pebbletemplates.pebble.template.PebbleTemplate;
 import tech.tablesaw.plotly.components.threeD.Scene;
 
 public class Layout {
diff --git a/jsplot/src/main/java/tech/tablesaw/plotly/components/TemplateUtils.java b/jsplot/src/main/java/tech/tablesaw/plotly/components/TemplateUtils.java
index 7a85336e..a5fd6086 100644
--- a/jsplot/src/main/java/tech/tablesaw/plotly/components/TemplateUtils.java
+++ b/jsplot/src/main/java/tech/tablesaw/plotly/components/TemplateUtils.java
@@ -1,11 +1,12 @@
 package tech.tablesaw.plotly.components;
 
-import com.mitchellbosecke.pebble.PebbleEngine;
-import com.mitchellbosecke.pebble.error.PebbleException;
-import com.mitchellbosecke.pebble.loader.ClasspathLoader;
-import com.mitchellbosecke.pebble.loader.DelegatingLoader;
-import com.mitchellbosecke.pebble.loader.FileLoader;
-import com.mitchellbosecke.pebble.loader.Loader;
+import io.pebbletemplates.pebble.PebbleEngine;
+import io.pebbletemplates.pebble.error.PebbleException;
+import io.pebbletemplates.pebble.loader.ClasspathLoader;
+import io.pebbletemplates.pebble.loader.DelegatingLoader;
+import io.pebbletemplates.pebble.loader.FileLoader;
+import io.pebbletemplates.pebble.loader.Loader;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
diff --git a/jsplot/src/main/java/tech/tablesaw/plotly/components/TickSettings.java b/jsplot/src/main/java/tech/tablesaw/plotly/components/TickSettings.java
index c39c2bf2..9ddb7490 100644
--- a/jsplot/src/main/java/tech/tablesaw/plotly/components/TickSettings.java
+++ b/jsplot/src/main/java/tech/tablesaw/plotly/components/TickSettings.java
@@ -51,7 +51,7 @@ public class TickSettings {
 
   /** Controls the display of prefixes, suffixes, and exponents on ticks */
   public enum DisplayRules {
-    ALL("outside"),
+    ALL("all"),
     FIRST("first"),
     LAST("last"),
     NONE("none");
@@ -132,6 +132,7 @@ public class TickSettings {
   private final int angle;
   private final String prefix;
   private final String suffix;
+  private final String format;
   private final boolean autoMargin;
   private final DisplayRules showPrefix;
   private final DisplayRules showSuffix;
@@ -167,6 +168,7 @@ public class TickSettings {
     angle = builder.angle;
     prefix = builder.prefix;
     suffix = builder.suffix;
+    format = builder.format;
     mirror = builder.mirror;
     separateThousands = builder.separateThousands;
   }
@@ -204,6 +206,7 @@ public class TickSettings {
     context.put("suffix", suffix);
     context.put("showPrefix", showPrefix);
     context.put("showSuffix", showSuffix);
+    context.put("format", format);
     context.put("angle", angle);
     context.put("autoMargin", autoMargin);
     context.put("tickMode", tickMode);
@@ -239,6 +242,7 @@ public class TickSettings {
     private boolean autoMargin = true;
     private DisplayRules showPrefix = ALL;
     private DisplayRules showSuffix = ALL;
+    private String format;
     private Mirror mirror;
     private boolean separateThousands;
 
@@ -399,6 +403,11 @@ public class TickSettings {
       return this;
     }
 
+    public TickSettings.TickSettingsBuilder format(String format) {
+      this.format = format;
+      return this;
+    }
+
     /**
      * TODO: this is pretty hack-y. Add a separate method for dealing with dates and maybe clean up
      * logs too
diff --git a/jsplot/src/main/java/tech/tablesaw/plotly/components/threeD/Scene.java b/jsplot/src/main/java/tech/tablesaw/plotly/components/threeD/Scene.java
index 9041853e..7d63f341 100644
--- a/jsplot/src/main/java/tech/tablesaw/plotly/components/threeD/Scene.java
+++ b/jsplot/src/main/java/tech/tablesaw/plotly/components/threeD/Scene.java
@@ -1,7 +1,7 @@
 package tech.tablesaw.plotly.components.threeD;
 
-import com.mitchellbosecke.pebble.error.PebbleException;
-import com.mitchellbosecke.pebble.template.PebbleTemplate;
+import io.pebbletemplates.pebble.error.PebbleException;
+import io.pebbletemplates.pebble.template.PebbleTemplate;
 import java.io.IOException;
 import java.io.StringWriter;
 import java.io.UncheckedIOException;
diff --git a/jsplot/src/main/java/tech/tablesaw/plotly/traces/AbstractTrace.java b/jsplot/src/main/java/tech/tablesaw/plotly/traces/AbstractTrace.java
index 0c4baebb..09a1e95d 100644
--- a/jsplot/src/main/java/tech/tablesaw/plotly/traces/AbstractTrace.java
+++ b/jsplot/src/main/java/tech/tablesaw/plotly/traces/AbstractTrace.java
@@ -1,8 +1,9 @@
 package tech.tablesaw.plotly.traces;
 
-import com.mitchellbosecke.pebble.PebbleEngine;
-import com.mitchellbosecke.pebble.error.PebbleException;
-import com.mitchellbosecke.pebble.template.PebbleTemplate;
+import io.pebbletemplates.pebble.PebbleEngine;
+import io.pebbletemplates.pebble.error.PebbleException;
+import io.pebbletemplates.pebble.template.PebbleTemplate;
+
 import java.io.IOException;
 import java.io.StringWriter;
 import java.io.UncheckedIOException;
diff --git a/jsplot/src/main/java/tech/tablesaw/plotly/traces/BarTrace.java b/jsplot/src/main/java/tech/tablesaw/plotly/traces/BarTrace.java
index 36f54ce2..e36690af 100644
--- a/jsplot/src/main/java/tech/tablesaw/plotly/traces/BarTrace.java
+++ b/jsplot/src/main/java/tech/tablesaw/plotly/traces/BarTrace.java
@@ -2,8 +2,8 @@ package tech.tablesaw.plotly.traces;
 
 import static tech.tablesaw.plotly.Utils.dataAsString;
 
-import com.mitchellbosecke.pebble.error.PebbleException;
-import com.mitchellbosecke.pebble.template.PebbleTemplate;
+import io.pebbletemplates.pebble.error.PebbleException;
+import io.pebbletemplates.pebble.template.PebbleTemplate;
 import java.io.IOException;
 import java.io.StringWriter;
 import java.io.UncheckedIOException;
diff --git a/jsplot/src/main/java/tech/tablesaw/plotly/traces/BoxTrace.java b/jsplot/src/main/java/tech/tablesaw/plotly/traces/BoxTrace.java
index dd2d3db0..ed484990 100644
--- a/jsplot/src/main/java/tech/tablesaw/plotly/traces/BoxTrace.java
+++ b/jsplot/src/main/java/tech/tablesaw/plotly/traces/BoxTrace.java
@@ -2,8 +2,8 @@ package tech.tablesaw.plotly.traces;
 
 import static tech.tablesaw.plotly.Utils.dataAsString;
 
-import com.mitchellbosecke.pebble.error.PebbleException;
-import com.mitchellbosecke.pebble.template.PebbleTemplate;
+import io.pebbletemplates.pebble.error.PebbleException;
+import io.pebbletemplates.pebble.template.PebbleTemplate;
 import java.io.IOException;
 import java.io.StringWriter;
 import java.io.UncheckedIOException;
diff --git a/jsplot/src/main/java/tech/tablesaw/plotly/traces/ContourTrace.java b/jsplot/src/main/java/tech/tablesaw/plotly/traces/ContourTrace.java
index aebee67c..7c82143b 100644
--- a/jsplot/src/main/java/tech/tablesaw/plotly/traces/ContourTrace.java
+++ b/jsplot/src/main/java/tech/tablesaw/plotly/traces/ContourTrace.java
@@ -1,7 +1,7 @@
 package tech.tablesaw.plotly.traces;
 
-import com.mitchellbosecke.pebble.error.PebbleException;
-import com.mitchellbosecke.pebble.template.PebbleTemplate;
+import io.pebbletemplates.pebble.error.PebbleException;
+import io.pebbletemplates.pebble.template.PebbleTemplate;
 
 import java.io.IOException;
 import java.io.StringWriter;
diff --git a/jsplot/src/main/java/tech/tablesaw/plotly/traces/HeatmapTrace.java b/jsplot/src/main/java/tech/tablesaw/plotly/traces/HeatmapTrace.java
index 6aea6b76..97928ac8 100644
--- a/jsplot/src/main/java/tech/tablesaw/plotly/traces/HeatmapTrace.java
+++ b/jsplot/src/main/java/tech/tablesaw/plotly/traces/HeatmapTrace.java
@@ -2,8 +2,8 @@ package tech.tablesaw.plotly.traces;
 
 import static tech.tablesaw.plotly.Utils.dataAsString;
 
-import com.mitchellbosecke.pebble.error.PebbleException;
-import com.mitchellbosecke.pebble.template.PebbleTemplate;
+import io.pebbletemplates.pebble.error.PebbleException;
+import io.pebbletemplates.pebble.template.PebbleTemplate;
 import java.io.IOException;
 import java.io.StringWriter;
 import java.io.UncheckedIOException;
diff --git a/jsplot/src/main/java/tech/tablesaw/plotly/traces/Histogram2DTrace.java b/jsplot/src/main/java/tech/tablesaw/plotly/traces/Histogram2DTrace.java
index 82c30c6a..c9b061ab 100644
--- a/jsplot/src/main/java/tech/tablesaw/plotly/traces/Histogram2DTrace.java
+++ b/jsplot/src/main/java/tech/tablesaw/plotly/traces/Histogram2DTrace.java
@@ -1,7 +1,7 @@
 package tech.tablesaw.plotly.traces;
 
-import com.mitchellbosecke.pebble.error.PebbleException;
-import com.mitchellbosecke.pebble.template.PebbleTemplate;
+import io.pebbletemplates.pebble.error.PebbleException;
+import io.pebbletemplates.pebble.template.PebbleTemplate;
 import java.io.IOException;
 import java.io.StringWriter;
 import java.io.UncheckedIOException;
diff --git a/jsplot/src/main/java/tech/tablesaw/plotly/traces/HistogramTrace.java b/jsplot/src/main/java/tech/tablesaw/plotly/traces/HistogramTrace.java
index fc8e476a..23893f79 100644
--- a/jsplot/src/main/java/tech/tablesaw/plotly/traces/HistogramTrace.java
+++ b/jsplot/src/main/java/tech/tablesaw/plotly/traces/HistogramTrace.java
@@ -1,7 +1,7 @@
 package tech.tablesaw.plotly.traces;
 
-import com.mitchellbosecke.pebble.error.PebbleException;
-import com.mitchellbosecke.pebble.template.PebbleTemplate;
+import io.pebbletemplates.pebble.error.PebbleException;
+import io.pebbletemplates.pebble.template.PebbleTemplate;
 import java.io.IOException;
 import java.io.StringWriter;
 import java.io.UncheckedIOException;
diff --git a/jsplot/src/main/java/tech/tablesaw/plotly/traces/PieTrace.java b/jsplot/src/main/java/tech/tablesaw/plotly/traces/PieTrace.java
index 02af6ad2..47ec1223 100644
--- a/jsplot/src/main/java/tech/tablesaw/plotly/traces/PieTrace.java
+++ b/jsplot/src/main/java/tech/tablesaw/plotly/traces/PieTrace.java
@@ -1,7 +1,7 @@
 package tech.tablesaw.plotly.traces;
 
-import com.mitchellbosecke.pebble.error.PebbleException;
-import com.mitchellbosecke.pebble.template.PebbleTemplate;
+import io.pebbletemplates.pebble.error.PebbleException;
+import io.pebbletemplates.pebble.template.PebbleTemplate;
 import java.io.IOException;
 import java.io.StringWriter;
 import java.io.UncheckedIOException;
diff --git a/jsplot/src/main/java/tech/tablesaw/plotly/traces/Scatter3DTrace.java b/jsplot/src/main/java/tech/tablesaw/plotly/traces/Scatter3DTrace.java
index 7ce39c2f..89a99d20 100644
--- a/jsplot/src/main/java/tech/tablesaw/plotly/traces/Scatter3DTrace.java
+++ b/jsplot/src/main/java/tech/tablesaw/plotly/traces/Scatter3DTrace.java
@@ -3,8 +3,8 @@ package tech.tablesaw.plotly.traces;
 import static tech.tablesaw.plotly.Utils.dataAsString;
 
 import com.google.common.base.Preconditions;
-import com.mitchellbosecke.pebble.error.PebbleException;
-import com.mitchellbosecke.pebble.template.PebbleTemplate;
+import io.pebbletemplates.pebble.error.PebbleException;
+import io.pebbletemplates.pebble.template.PebbleTemplate;
 import java.io.IOException;
 import java.io.StringWriter;
 import java.io.UncheckedIOException;
diff --git a/jsplot/src/main/java/tech/tablesaw/plotly/traces/ScatterTrace.java b/jsplot/src/main/java/tech/tablesaw/plotly/traces/ScatterTrace.java
index 0a3eb7df..7e8ee6fd 100644
--- a/jsplot/src/main/java/tech/tablesaw/plotly/traces/ScatterTrace.java
+++ b/jsplot/src/main/java/tech/tablesaw/plotly/traces/ScatterTrace.java
@@ -3,8 +3,8 @@ package tech.tablesaw.plotly.traces;
 import static tech.tablesaw.plotly.Utils.dataAsString;
 
 import com.google.common.base.Preconditions;
-import com.mitchellbosecke.pebble.error.PebbleException;
-import com.mitchellbosecke.pebble.template.PebbleTemplate;
+import io.pebbletemplates.pebble.error.PebbleException;
+import io.pebbletemplates.pebble.template.PebbleTemplate;
 import java.io.IOException;
 import java.io.StringWriter;
 import java.io.UncheckedIOException;
diff --git a/jsplot/src/main/java/tech/tablesaw/plotly/traces/ViolinTrace.java b/jsplot/src/main/java/tech/tablesaw/plotly/traces/ViolinTrace.java
index a9a545bf..ccc02e69 100644
--- a/jsplot/src/main/java/tech/tablesaw/plotly/traces/ViolinTrace.java
+++ b/jsplot/src/main/java/tech/tablesaw/plotly/traces/ViolinTrace.java
@@ -2,8 +2,8 @@ package tech.tablesaw.plotly.traces;
 
 import static tech.tablesaw.plotly.Utils.dataAsString;
 
-import com.mitchellbosecke.pebble.error.PebbleException;
-import com.mitchellbosecke.pebble.template.PebbleTemplate;
+import io.pebbletemplates.pebble.error.PebbleException;
+import io.pebbletemplates.pebble.template.PebbleTemplate;
 import java.io.IOException;
 import java.io.StringWriter;
 import java.io.UncheckedIOException;
diff --git a/jsplot/src/main/resources/axis_template.html b/jsplot/src/main/resources/axis_template.html
index 757e9427..18d20635 100644
--- a/jsplot/src/main/resources/axis_template.html
+++ b/jsplot/src/main/resources/axis_template.html
@@ -28,6 +28,21 @@
 {% if tick0 is not null %}
     tick0: '{{tick0}}',
 {% endif %}
+{% if showPrefix is not null %}
+    showtickprefix: '{{showPrefix}}',
+{% endif %}
+{% if showSuffix is not null %}
+    showticksuffix: '{{showSuffix}}',
+{% endif %}
+{% if prefix is not null %}
+    tickprefix: '{{prefix}}',
+{% endif %}
+{% if suffix is not null %}
+    ticksuffix: '{{suffix}}',
+{% endif %}
+{% if format is not null %}
+    tickformat: '{{format}}',
+{% endif %}
 {% if showExponent is not null %}
     showExponent: '{{showExponent}}',
 {% endif %}
@@ -85,7 +100,7 @@
     type: '{{type}}',
 {% endif %}
 {% if range is not null %}
-    range: {{range | raw}}
+    range: {{range | raw}},
 {% endif %}
 {% if visible is not null %}
     visible: {{visible}},
diff --git a/pom.xml b/pom.xml
index 6e4ec89c..955b9505 100644
--- a/pom.xml
+++ b/pom.xml
@@ -12,7 +12,6 @@
         <connection>scm:git:git@github.com:jtablesaw/tablesaw.git</connection>
         <developerConnection>scm:git:git@github.com:jtablesaw/tablesaw.git</developerConnection>
         <url>git@github.com:jtablesaw/tablesaw.git</url>
-        <tag>v0.23.4</tag>
     </scm>
     <licenses>
         <license>
@@ -73,6 +72,11 @@
                         <groupId>org.sonatype.plugins</groupId>
                         <artifactId>nexus-staging-maven-plugin</artifactId>
                     </plugin>
+                    <plugin>
+                        <groupId>org.codehaus.mojo</groupId>
+                        <artifactId>versions-maven-plugin</artifactId>
+                        <version>2.16.2</version>
+                    </plugin>
                 </plugins>
             </build>
         </profile>
@@ -84,7 +88,7 @@
                 <plugin>
                     <groupId>org.apache.maven.plugins</groupId>
                     <artifactId>maven-javadoc-plugin</artifactId>
-                    <version>3.1.1</version>
+                    <version>3.5.0</version>
                     <configuration>
                         <source>11</source>
                         <detectOfflineLinks>false</detectOfflineLinks>
@@ -105,7 +109,7 @@
                 <plugin>
                     <groupId>org.apache.maven.plugins</groupId>
                     <artifactId>maven-source-plugin</artifactId>
-                    <version>3.0.1</version>
+                    <version>3.2.1</version>
                     <executions>
                         <execution>
                             <id>attach-sources</id>
@@ -118,12 +122,12 @@
                 <plugin>
                     <groupId>org.apache.maven.plugins</groupId>
                     <artifactId>maven-surefire-plugin</artifactId>
-                    <version>2.22.1</version>
+                    <version>3.2.5</version>
                 </plugin>
                 <plugin>
                     <groupId>org.apache.maven.plugins</groupId>
                     <artifactId>maven-gpg-plugin</artifactId>
-                    <version>1.6</version>
+                    <version>3.0.1</version>
                     <executions>
                         <execution>
                             <id>sign-artifacts</id>
@@ -137,7 +141,7 @@
                 <plugin>
                     <groupId>org.apache.maven.plugins</groupId>
                     <artifactId>maven-release-plugin</artifactId>
-                    <version>2.5.3</version>
+                    <version>3.0.0-M7</version>
                     <configuration>
                         <tagNameFormat>v@{project.version}</tagNameFormat>
                         <autoVersionSubmodules>true</autoVersionSubmodules>
@@ -149,7 +153,7 @@
                 <plugin>
                     <groupId>org.sonatype.plugins</groupId>
                     <artifactId>nexus-staging-maven-plugin</artifactId>
-                    <version>1.6.8</version>
+                    <version>1.6.13</version>
                     <extensions>true</extensions>
                     <configuration>
                         <serverId>ossrh</serverId>
@@ -160,7 +164,7 @@
                 <plugin>
                     <groupId>org.apache.maven.plugins</groupId>
                     <artifactId>maven-compiler-plugin</artifactId>
-                    <version>3.6.2</version>
+                    <version>3.11.0</version>
                     <executions>
                         <!-- Replacing default-compile as it is treated specially by maven -->
                         <execution>
@@ -218,7 +222,7 @@
             <plugin>
                 <groupId>org.jacoco</groupId>
                 <artifactId>jacoco-maven-plugin</artifactId>
-                <version>0.8.6</version>
+                <version>0.8.8</version>
                 <executions>
                     <execution>
                         <id>prepare-agent</id>
@@ -251,7 +255,7 @@
             <plugin>
                 <groupId>com.cosium.code</groupId>
                 <artifactId>git-code-format-maven-plugin</artifactId>
-                <version>2.4</version>
+                <version>4.2</version>
                 <executions>
                     <!-- On commit, format the modified java files -->
                     <execution>
@@ -270,32 +274,32 @@
             <dependency>
                 <groupId>com.fasterxml.jackson.core</groupId>
                 <artifactId>jackson-core</artifactId>
-                <version>2.13.2</version>
+                <version>2.17.0</version>
             </dependency>
             <dependency>
                 <groupId>com.fasterxml.jackson.core</groupId>
                 <artifactId>jackson-databind</artifactId>
-                <version>2.13.2.1</version>
+                <version>2.17.0</version>
             </dependency>
             <dependency>
                 <groupId>com.fasterxml.jackson.datatype</groupId>
                 <artifactId>jackson-datatype-jsr310</artifactId>
-                <version>2.13.2</version>
+                <version>2.17.0</version>
             </dependency>
             <dependency>
                 <groupId>org.slf4j</groupId>
                 <artifactId>slf4j-api</artifactId>
-                <version>1.7.30</version>
+                <version>2.0.12</version>
             </dependency>
             <dependency>
                 <groupId>org.junit.jupiter</groupId>
                 <artifactId>junit-jupiter-engine</artifactId>
-                <version>5.5.2</version>
+                <version>5.10.2</version>
             </dependency>
             <dependency>
                 <groupId>org.junit.jupiter</groupId>
                 <artifactId>junit-jupiter-params</artifactId>
-                <version>5.5.2</version>
+                <version>5.10.2</version>
             </dependency>
         </dependencies>
     </dependencyManagement>
diff --git a/saw/pom.xml b/saw/pom.xml
index 69a839d9..f4dd207b 100644
--- a/saw/pom.xml
+++ b/saw/pom.xml
@@ -74,7 +74,7 @@
     <dependency>
       <groupId>org.iq80.snappy</groupId>
       <artifactId>snappy</artifactId>
-      <version>0.4</version>
+      <version>0.5</version>
     </dependency>
     <dependency>
       <groupId>org.lz4</groupId>


Test patch:
diff --git a/core/src/test/java/tech/tablesaw/api/DateColumnTest.java b/core/src/test/java/tech/tablesaw/api/DateColumnTest.java
index f3d6b0ef..adbe8cb1 100644
--- a/core/src/test/java/tech/tablesaw/api/DateColumnTest.java
+++ b/core/src/test/java/tech/tablesaw/api/DateColumnTest.java
@@ -12,6 +12,7 @@ import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import tech.tablesaw.columns.dates.DateColumnType;
 import tech.tablesaw.columns.dates.DateParser;
+import tech.tablesaw.columns.datetimes.DateTimeParser;
 
 public class DateColumnTest {
   private DateColumn column1;
@@ -61,7 +62,7 @@ public class DateColumnTest {
     column1.appendCell("12/23/1924");
     column1.appendCell("12-May-2015");
     column1.appendCell("12-Jan-2015");
-    column1.setPrintFormatter(DateTimeFormatter.ofPattern("MMM~dd~yyyy"), "");
+    column1.setPrintFormatter(DateTimeParser.caseInsensitiveFormatter("MMM~dd~yyyy"), "");
     assertEquals(
         "Column: Game date"
             + System.lineSeparator()
@@ -82,7 +83,7 @@ public class DateColumnTest {
     column1.appendCell("12/23/1924");
     column1.appendCell("12-May-2015");
     column1.appendCell("12-Jan-2015");
-    column1.setPrintFormatter(DateTimeFormatter.ofPattern("MMM~dd~yyyy"));
+    column1.setPrintFormatter(DateTimeParser.caseInsensitiveFormatter("MMM~dd~yyyy"));
     assertEquals(
         "Column: Game date"
             + System.lineSeparator()
diff --git a/core/src/test/java/tech/tablesaw/api/DateTimeColumnTest.java b/core/src/test/java/tech/tablesaw/api/DateTimeColumnTest.java
index aa160e87..12b23a07 100644
--- a/core/src/test/java/tech/tablesaw/api/DateTimeColumnTest.java
+++ b/core/src/test/java/tech/tablesaw/api/DateTimeColumnTest.java
@@ -22,7 +22,8 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
 import java.time.LocalDateTime;
 import java.time.ZoneOffset;
 import java.time.format.DateTimeFormatter;
-import java.util.Arrays;
+import java.util.List;
+
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import tech.tablesaw.columns.datetimes.DateTimeParser;
@@ -63,7 +64,7 @@ public class DateTimeColumnTest {
   public void testCustomParser() {
     // Just do enough to ensure the parser is wired up correctly
     DateTimeParser customParser = new DateTimeParser(ColumnType.LOCAL_DATE_TIME);
-    customParser.setMissingValueStrings(Arrays.asList("not here"));
+    customParser.setMissingValueStrings(List.of("not here"));
     column1.setParser(customParser);
 
     column1.appendCell("not here");
diff --git a/core/src/test/java/tech/tablesaw/columns/ColumnTest.java b/core/src/test/java/tech/tablesaw/columns/ColumnTest.java
index e07324ea..697ddbfe 100644
--- a/core/src/test/java/tech/tablesaw/columns/ColumnTest.java
+++ b/core/src/test/java/tech/tablesaw/columns/ColumnTest.java
@@ -338,4 +338,13 @@ public class ColumnTest {
     assertEquals(0, testDoubleCol.indexOf(0.0));
     assertEquals(1, testDoubleCol.indexOf(1.0));
   }
+
+  @Test
+  public void lastIndexOfTest() {
+    DoubleColumn testDoubleCol = DoubleColumn.create("t1", 0, 1, 1);
+    assertEquals(-1, testDoubleCol.lastIndexOf(2));
+    assertEquals(-1, testDoubleCol.lastIndexOf(0));
+    assertEquals(0, testDoubleCol.lastIndexOf(0.0));
+    assertEquals(2, testDoubleCol.lastIndexOf(1.0));
+  }
 }
diff --git a/core/src/test/java/tech/tablesaw/io/TypeUtilsTest.java b/core/src/test/java/tech/tablesaw/io/TypeUtilsTest.java
index 720b740b..b06567a1 100644
--- a/core/src/test/java/tech/tablesaw/io/TypeUtilsTest.java
+++ b/core/src/test/java/tech/tablesaw/io/TypeUtilsTest.java
@@ -27,7 +27,7 @@ import tech.tablesaw.columns.datetimes.DateTimeParser;
 public class TypeUtilsTest {
 
   @Test
-  public void testDateFormaterWithLocaleEN() {
+  public void testDateFormatterWithLocaleEN() {
     String anotherDate = "12-May-2015";
     LocalDate result =
         LocalDate.parse(anotherDate, DateParser.DEFAULT_FORMATTER.withLocale(Locale.ENGLISH));
@@ -35,8 +35,8 @@ public class TypeUtilsTest {
   }
 
   @Test
-  public void testDateFormater() {
-    final DateTimeFormatter dtTimef8 = DateTimeFormatter.ofPattern("M/d/yyyy h:mm:ss a");
+  public void testDateFormatter() {
+    final DateTimeFormatter dtTimef8 = DateTimeParser.caseInsensitiveFormatter("M/d/yyyy h:mm:ss a");
 
     String anotherDate = "10/2/2016 8:18:03 AM";
     dtTimef8.parse(anotherDate);
diff --git a/core/src/test/java/tech/tablesaw/io/csv/CsvReaderTest.java b/core/src/test/java/tech/tablesaw/io/csv/CsvReaderTest.java
index 4e96df96..e9b418c6 100644
--- a/core/src/test/java/tech/tablesaw/io/csv/CsvReaderTest.java
+++ b/core/src/test/java/tech/tablesaw/io/csv/CsvReaderTest.java
@@ -55,6 +55,7 @@ import tech.tablesaw.api.LongColumn;
 import tech.tablesaw.api.ShortColumn;
 import tech.tablesaw.api.StringColumn;
 import tech.tablesaw.api.Table;
+import tech.tablesaw.columns.datetimes.DateTimeParser;
 import tech.tablesaw.columns.numbers.DoubleColumnType;
 import tech.tablesaw.columns.numbers.NumberColumnFormatter;
 import tech.tablesaw.io.AddCellToColumnException;
@@ -302,7 +303,7 @@ public class CsvReaderTest {
     CsvReadOptions options =
         CsvReadOptions.builder(reader)
             .header(header)
-            .dateTimeFormat(DateTimeFormatter.ofPattern("dd-MMM-yyyy HH:mm:ss"))
+            .dateTimeFormat(DateTimeParser.caseInsensitiveFormatter("dd-MMM-yyyy HH:mm:ss"))
             .build();
 
     final List<ColumnType> actual = asList(new CsvReader().detectColumnTypes(reader, options));
@@ -327,7 +328,7 @@ public class CsvReaderTest {
     CsvReadOptions options =
         CsvReadOptions.builder(reader)
             .header(header)
-            .dateTimeFormat(DateTimeFormatter.ofPattern("dd-MMM-yyyy HH:mm:ss"))
+            .dateTimeFormat(DateTimeParser.caseInsensitiveFormatter("dd-MMM-yyyy HH:mm:ss"))
             .build();
 
     final List<ColumnType> actual = asList(new CsvReader().detectColumnTypes(reader, options));
diff --git a/core/src/test/java/tech/tablesaw/io/csv/CsvWriterTest.java b/core/src/test/java/tech/tablesaw/io/csv/CsvWriterTest.java
index 2f3488ac..1d0db44d 100644
--- a/core/src/test/java/tech/tablesaw/io/csv/CsvWriterTest.java
+++ b/core/src/test/java/tech/tablesaw/io/csv/CsvWriterTest.java
@@ -15,6 +15,7 @@ import java.util.Map;
 import org.junit.jupiter.api.Test;
 import tech.tablesaw.api.*;
 import tech.tablesaw.columns.booleans.BooleanFormatter;
+import tech.tablesaw.columns.datetimes.DateTimeParser;
 import tech.tablesaw.columns.instant.InstantColumnFormatter;
 import tech.tablesaw.columns.numbers.NumberColumnFormatter;
 import tech.tablesaw.columns.strings.StringColumnFormatter;
@@ -46,7 +47,7 @@ public class CsvWriterTest {
   @Test
   void dateFormatter() throws IOException {
     Table table = Table.read().csv("../data/bush.csv").rows(1);
-    table.dateColumn("date").setPrintFormatter(DateTimeFormatter.ofPattern("MMM dd, yyyy"));
+    table.dateColumn("date").setPrintFormatter(DateTimeParser.caseInsensitiveFormatter("MMM dd, yyyy"));
     StringWriter writer = new StringWriter();
     table.write().usingOptions(CsvWriteOptions.builder(writer).usePrintFormatters(true).build());
     assertEquals(
@@ -84,7 +85,7 @@ public class CsvWriterTest {
   @Test
   void printFormatter_date() throws IOException {
     Table table = Table.create("", DateColumn.create("dates"));
-    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-dd-MMM");
+    DateTimeFormatter formatter = DateTimeParser.caseInsensitiveFormatter("yyyy-dd-MMM");
     table.dateColumn("dates").setPrintFormatter(formatter, "WHAT?");
     table
         .dateColumn("dates")
@@ -154,7 +155,7 @@ public class CsvWriterTest {
   @Test
   void printFormatter_datetime() throws IOException {
     Table table = Table.create("", DateTimeColumn.create("dates"));
-    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMM d, yyyy - hh:mm");
+    DateTimeFormatter formatter = DateTimeParser.caseInsensitiveFormatter("MMM d, yyyy - hh:mm");
     table.dateTimeColumn("dates").setPrintFormatter(formatter, "WHAT?");
     table.dateTimeColumn("dates").append(LocalDateTime.of(2011, 1, 1, 4, 30));
     StringWriter writer = new StringWriter();
@@ -216,7 +217,7 @@ public class CsvWriterTest {
   @Test
   void printFormatter_instant() throws IOException {
     Table table = Table.create("", InstantColumn.create("dates"));
-    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMM d, yyyy - hh:mm");
+    DateTimeFormatter formatter = DateTimeParser.caseInsensitiveFormatter("MMM d, yyyy - hh:mm");
     table.instantColumn("dates").setPrintFormatter(new InstantColumnFormatter(formatter, "WHAT?"));
     table.instantColumn("dates").append(Instant.parse("2007-12-03T10:15:30.00Z")).appendMissing();
     StringWriter writer = new StringWriter();
@@ -253,7 +254,7 @@ public class CsvWriterTest {
     table.dateTimeColumn(0).append(LocalDateTime.of(2011, 1, 1, 4, 30));
     table
         .dateTimeColumn("dt")
-        .setPrintFormatter(DateTimeFormatter.ofPattern("MMM d, yyyy - hh:mm"));
+        .setPrintFormatter(DateTimeParser.caseInsensitiveFormatter("MMM d, yyyy - hh:mm"));
     StringWriter writer = new StringWriter();
     table.write().usingOptions(CsvWriteOptions.builder(writer).usePrintFormatters(true).build());
     assertEquals(
diff --git a/jsplot/src/test/java/tech/tablesaw/plotly/OhlcTest.java b/jsplot/src/test/java/tech/tablesaw/plotly/OhlcTest.java
new file mode 100644
index 00000000..cc1d5335
--- /dev/null
+++ b/jsplot/src/test/java/tech/tablesaw/plotly/OhlcTest.java
@@ -0,0 +1,47 @@
+package tech.tablesaw.plotly;
+
+import org.junit.jupiter.api.Test;
+import tech.tablesaw.api.DateTimeColumn;
+import tech.tablesaw.api.DoubleColumn;
+import tech.tablesaw.api.Table;
+import tech.tablesaw.plotly.api.OHLCPlot;
+import tech.tablesaw.plotly.components.Figure;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+public class OhlcTest {
+
+    @Test
+    void ohlcPlotDoesNotThrowIllegalArgumentException() {
+        // Test to fix bug reported at https://github.com/jtablesaw/tablesaw/issues/1237
+        String timeTitle = "time";
+        String openTitle = "open";
+        String closeTitle = "close";
+        String highTitle = "high";
+        String lowTitle = "low";
+        String graphTitle = "title";
+
+        LocalDateTime now = LocalDateTime.now();
+        List<LocalDateTime> time = List.of(now, now.plusSeconds(5), now.plusSeconds(10));
+        List<Double> open = List.of(1d, 2d, 3d);
+        List<Double> close = List.of(1d, 2d, 3d);
+        List<Double> high = List.of(1d, 2d, 3d);
+        List<Double> low = List.of(1d, 2d, 3d);
+
+        DateTimeColumn timeColumn = DateTimeColumn.create(timeTitle, time);
+        DoubleColumn openColumn = DoubleColumn.create(openTitle, open);
+        DoubleColumn closeColumn = DoubleColumn.create(closeTitle, close);
+        DoubleColumn highColumn = DoubleColumn.create(highTitle, high);
+        DoubleColumn lowColumn = DoubleColumn.create(lowTitle, low);
+
+        Table priceTable = Table.create(timeColumn, openColumn, closeColumn, highColumn, lowColumn);
+        Figure figure = OHLCPlot.create(graphTitle, priceTable, timeTitle, openTitle, highTitle, lowTitle, closeTitle);
+
+        assertNotNull(figure);
+        assertDoesNotThrow(() -> IllegalArgumentException.class);
+    }
+}