diff --git a/frontend/src/metabase/visualizations/lib/fill_data.js b/frontend/src/metabase/visualizations/lib/fill_data.js
index 1e3196dde79b9eb9007bff1b151bbb4df26f476a..a6443b7eab38b851f7581c22ece36eefdbbb1c7a 100644
--- a/frontend/src/metabase/visualizations/lib/fill_data.js
+++ b/frontend/src/metabase/visualizations/lib/fill_data.js
@@ -8,6 +8,8 @@ import {
   isQuantitative,
   isHistogram,
   isHistogramBar,
+  isLine,
+  isArea,
 } from "./renderer_utils";
 import timeseriesScale from "./timeseriesScale";
 
@@ -52,12 +54,17 @@ function fillMissingValuesInData(
   rows,
 ) {
   const { settings } = props;
-  const { "line.missing": lineMissing } = settings.series(singleSeries);
+  const seriesSettings = settings.series(singleSeries);
+  const lineMissing = seriesSettings["line.missing"];
 
-  // return now if we're not filling with either 0 or null
   if (!(lineMissing === "zero" || lineMissing === "none")) {
-    return rows;
+    const shouldRemoveNulls =
+      lineMissing === "interpolate" &&
+      (isLine(seriesSettings) || isArea(seriesSettings));
+
+    return shouldRemoveNulls ? rows.filter(([_x, y]) => y !== null) : rows;
   }
+
   let getKey;
   const fillValue = lineMissing === "zero" ? 0 : null;
   if (isTimeseries(settings)) {
diff --git a/frontend/src/metabase/visualizations/lib/renderer_utils.js b/frontend/src/metabase/visualizations/lib/renderer_utils.js
index cae295d935f828287c0b6aeb5aba871c02a346fc..6a0f790619f750413def8cfa931c4cdcca4e2f6e 100644
--- a/frontend/src/metabase/visualizations/lib/renderer_utils.js
+++ b/frontend/src/metabase/visualizations/lib/renderer_utils.js
@@ -363,6 +363,8 @@ export const isHistogram = settings =>
   settings["graph.x_axis.scale"] === "histogram";
 export const isOrdinal = settings =>
   settings["graph.x_axis.scale"] === "ordinal";
+export const isLine = settings => settings.display === "line";
+export const isArea = settings => settings.display === "area";
 
 // bar histograms have special tick formatting:
 // * aligned with beginning of bar to show bin boundaries
diff --git a/frontend/test/metabase/scenarios/visualizations/line_chart.cy.spec.js b/frontend/test/metabase/scenarios/visualizations/line_chart.cy.spec.js
index 758d6ade7c5fed57143da30f9c40f62b3353985f..8b1d82391c4a6d8b928d53e392d49803b94b8134 100644
--- a/frontend/test/metabase/scenarios/visualizations/line_chart.cy.spec.js
+++ b/frontend/test/metabase/scenarios/visualizations/line_chart.cy.spec.js
@@ -147,6 +147,30 @@ describe("scenarios > visualizations > line chart", () => {
       .and("contain", "cat3");
   });
 
+  it("should interpolate null value by not rendering a data point (metabase#4122)", () => {
+    visitQuestionAdhoc({
+      dataset_query: {
+        type: "native",
+        native: {
+          query: `
+            select 'a' x, 1 y
+            union all
+            select 'b' x, null y
+            union all
+            select 'c' x, 2 y
+          `,
+          "template-tags": {},
+        },
+        database: 1,
+      },
+      display: "line",
+    });
+
+    cy.get(`.sub._0`)
+      .find("circle")
+      .should("have.length", 2);
+  });
+
   describe.skip("tooltip of combined dashboard cards (multi-series) should show the correct column title (metabase#16249", () => {
     const RENAMED_FIRST_SERIES = "Foo";
     const RENAMED_SECOND_SERIES = "Bar";