diff --git a/frontend/src/metabase/visualizations/lib/apply_axis.js b/frontend/src/metabase/visualizations/lib/apply_axis.js
index c55936d1d50a4c3fe430d0190f2dd40c78633292..eead07d01c650173c8764e09c8646e87e87c9211 100644
--- a/frontend/src/metabase/visualizations/lib/apply_axis.js
+++ b/frontend/src/metabase/visualizations/lib/apply_axis.js
@@ -317,6 +317,17 @@ export function applyChartOrdinalXAxis(
   chart.x(d3.scale.ordinal().domain(xValues)).xUnits(dc.units.ordinal);
 }
 
+// Sometimes tick marks are placed *just* off from zero.
+// We still want to format these as "0" rather than "0.0000000000000018".
+// But! We need to allow for real non-zero ticks at very small values,
+// so we scale a tolerance to the extent of the yAxis.
+// The tolerance is arbitrarily set to one millionth of the yExtent.
+const TOLERANCE_TO_Y_EXTENT = 1e6;
+export function maybeRoundValueToZero(value, [yMin, yMax]) {
+  const tolerance = Math.abs(yMax - yMin) / TOLERANCE_TO_Y_EXTENT;
+  return Math.abs(value) < tolerance ? 0 : value;
+}
+
 export function applyChartYAxis(chart, series, yExtent, axisName) {
   let axis;
   if (axisName !== "right") {
@@ -358,11 +369,10 @@ export function applyChartYAxis(chart, series, yExtent, axisName) {
       axis.axis().tickFormat(value => Math.round(value * 100) + "%");
     } else {
       const metricColumn = series[0].data.cols[1];
-      axis
-        .axis()
-        .tickFormat(value =>
-          formatValue(value, chart.settings.column(metricColumn)),
-        );
+      axis.axis().tickFormat(value => {
+        value = maybeRoundValueToZero(value, yExtent);
+        return formatValue(value, chart.settings.column(metricColumn));
+      });
     }
     chart.renderHorizontalGridLines(true);
     adjustYAxisTicksIfNeeded(axis.axis(), chart.height());
diff --git a/frontend/test/metabase/visualizations/lib/apply_axis.unit.spec.js b/frontend/test/metabase/visualizations/lib/apply_axis.unit.spec.js
index d8df889abe1e203b1c21c563a1288d4522f13996..fb0ee1a75d523041b1ff37cb5fa11843406f8163 100644
--- a/frontend/test/metabase/visualizations/lib/apply_axis.unit.spec.js
+++ b/frontend/test/metabase/visualizations/lib/apply_axis.unit.spec.js
@@ -1,4 +1,7 @@
-import { stretchTimeseriesDomain } from "metabase/visualizations/lib/apply_axis";
+import {
+  maybeRoundValueToZero,
+  stretchTimeseriesDomain,
+} from "metabase/visualizations/lib/apply_axis";
 import moment from "moment";
 
 describe("visualization.lib.apply_axis", () => {
@@ -39,4 +42,24 @@ describe("visualization.lib.apply_axis", () => {
       ]);
     });
   });
+
+  describe("maybeRoundValueToZero", () => {
+    it("shouldn't change big values", () => {
+      const value = maybeRoundValueToZero(0.2, [-1, 1]);
+
+      expect(value).toBe(0.2);
+    });
+
+    it("should snap small values to zero", () => {
+      const value = maybeRoundValueToZero(0.0000000000018, [-1, 1]);
+
+      expect(value).toBe(0);
+    });
+
+    it("shouldn't snap small values to zero if the yExtent is small", () => {
+      const value = maybeRoundValueToZero(0.0000000000018, [-1e-20, 1e-20]);
+
+      expect(value).toBe(0.0000000000018);
+    });
+  });
 });