diff --git a/src/plots/geo/geo.js b/src/plots/geo/geo.js
index 2472ab9956e..ed0c5a9ac0c 100644
--- a/src/plots/geo/geo.js
+++ b/src/plots/geo/geo.js
@@ -15,8 +15,6 @@ var d3 = require('d3');
 
 var Color = require('../../components/color');
 var Drawing = require('../../components/drawing');
-
-var Plots = require('../../plots/plots');
 var Axes = require('../../plots/cartesian/axes');
 
 var addProjectionsToD3 = require('./projections');
@@ -139,6 +137,20 @@ proto.plot = function(geoData, fullLayout, promises) {
     // to avoid making multiple request while streaming
 };
 
+// filter out non-visible trace
+// geo plot routine use the classic join/enter/exit pattern to update traces
+function filterData(dataIn) {
+    var dataOut = [];
+
+    for(var i = 0; i < dataIn.length; i++) {
+        var trace = dataIn[i];
+
+        if(trace.visible === true) dataOut.push(trace);
+    }
+
+    return dataOut;
+}
+
 proto.onceTopojsonIsLoaded = function(geoData, geoLayout) {
     var traceData = {};
 
@@ -153,8 +165,10 @@ proto.onceTopojsonIsLoaded = function(geoData, geoLayout) {
 
     var traceKeys = Object.keys(traceData);
     for(var j = 0; j < traceKeys.length; j++){
-        var traceKey = traceKeys[j];
-        Plots.getModule(traceKey).plot(this, traceData[traceKey], geoLayout);
+        var moduleData = traceData[traceKeys[j]];
+        var _module = moduleData[0]._module;
+
+        _module.plot(this, filterData(moduleData), geoLayout);
     }
 
     this.render();
diff --git a/src/traces/choropleth/plot.js b/src/traces/choropleth/plot.js
index 771b090daba..15a59206869 100644
--- a/src/traces/choropleth/plot.js
+++ b/src/traces/choropleth/plot.js
@@ -68,7 +68,7 @@ plotChoropleth.plot = function(geo, choroplethData, geoLayout) {
 
     var gChoroplethTraces = gChoropleth
         .selectAll('g.trace.choropleth')
-        .data(choroplethData);
+        .data(choroplethData, function(trace) { return trace.uid; });
 
     gChoroplethTraces.enter().append('g')
         .attr('class', 'trace choropleth');
@@ -77,8 +77,6 @@ plotChoropleth.plot = function(geo, choroplethData, geoLayout) {
 
     gChoroplethTraces
         .each(function(trace) {
-            if(trace.visible !== true) return;
-
             var cdi = plotChoropleth.calcGeoJSON(trace, geo.topojson),
                 cleanHoverLabelsFunc = makeCleanHoverLabelsFunc(geo, trace),
                 eventDataFunc = makeEventDataFunc(trace);
diff --git a/src/traces/scattergeo/plot.js b/src/traces/scattergeo/plot.js
index eee16c1d477..8c16d3159b8 100644
--- a/src/traces/scattergeo/plot.js
+++ b/src/traces/scattergeo/plot.js
@@ -31,7 +31,7 @@ plotScatterGeo.calcGeoJSON = function(trace, topojson) {
     var cdi = [],
         hasLocationData = Array.isArray(trace.locations);
 
-    var len, features, getLonLat, lonlat, locations, calcItem;
+    var len, features, getLonLat, locations;
 
     if(hasLocationData) {
         locations = trace.locations;
@@ -53,11 +53,11 @@ plotScatterGeo.calcGeoJSON = function(trace, topojson) {
     }
 
     for(var i = 0; i < len; i++) {
-        lonlat = getLonLat(trace, i);
+        var lonlat = getLonLat(trace, i);
 
         if(!lonlat) continue;  // filter the blank points here
 
-        calcItem = {
+        var calcItem = {
             lon: lonlat[0],
             lat: lonlat[1],
             location: hasLocationData ? trace.locations[i] : null
@@ -104,7 +104,7 @@ function makeLineGeoJSON(trace) {
     var N = trace.lon.length,
         coordinates = new Array(N);
 
-    for (var i = 0; i < N; i++) {
+    for(var i = 0; i < N; i++) {
         coordinates[i] = [trace.lon[i], trace.lat[i]];
     }
 
@@ -118,7 +118,7 @@ function makeLineGeoJSON(trace) {
 plotScatterGeo.plot = function(geo, scattergeoData) {
     var gScatterGeoTraces = geo.framework.select('.scattergeolayer')
         .selectAll('g.trace.scattergeo')
-        .data(scattergeoData);
+        .data(scattergeoData, function(trace) { return trace.uid; });
 
     gScatterGeoTraces.enter().append('g')
         .attr('class', 'trace scattergeo');
@@ -128,7 +128,8 @@ plotScatterGeo.plot = function(geo, scattergeoData) {
     // TODO add hover - how?
     gScatterGeoTraces
         .each(function(trace) {
-            if(!subTypes.hasLines(trace) || trace.visible !== true) return;
+            if(!subTypes.hasLines(trace)) return;
+
             d3.select(this)
                 .append('path')
                 .datum(makeLineGeoJSON(trace))
@@ -142,10 +143,7 @@ plotScatterGeo.plot = function(geo, scattergeoData) {
                 showMarkers = subTypes.hasMarkers(trace),
                 showText = subTypes.hasText(trace);
 
-            if((!showMarkers && !showText) || trace.visible !== true) {
-                s.remove();
-                return;
-            }
+            if((!showMarkers && !showText)) return;
 
             var cdi = plotScatterGeo.calcGeoJSON(trace, geo.topojson),
                 cleanHoverLabelsFunc = makeCleanHoverLabelsFunc(geo, trace),
diff --git a/test/jasmine/tests/geo_interact_test.js b/test/jasmine/tests/geo_interact_test.js
index 2c811b33b5e..9b50914ca32 100644
--- a/test/jasmine/tests/geo_interact_test.js
+++ b/test/jasmine/tests/geo_interact_test.js
@@ -180,5 +180,43 @@ describe('Test geo interactions', function() {
             });
         });
 
+        describe('trace visibility toggle', function() {
+            function countTraces(type) {
+                return d3.selectAll('g.trace.' + type).size();
+            }
+
+            it('should toggle scattergeo elements', function(done) {
+                expect(countTraces('scattergeo')).toBe(1);
+                expect(countTraces('choropleth')).toBe(1);
+
+                Plotly.restyle(gd, 'visible', false, [0]).then(function() {
+                    expect(countTraces('scattergeo')).toBe(0);
+                    expect(countTraces('choropleth')).toBe(1);
+
+                    Plotly.restyle(gd, 'visible', true, [0]).then(function() {
+                        expect(countTraces('scattergeo')).toBe(1);
+                        expect(countTraces('choropleth')).toBe(1);
+                        done();
+                    });
+                });
+            });
+
+            it('should toggle choropleth elements', function(done) {
+                expect(countTraces('scattergeo')).toBe(1);
+                expect(countTraces('choropleth')).toBe(1);
+
+                Plotly.restyle(gd, 'visible', false, [1]).then(function() {
+                    expect(countTraces('scattergeo')).toBe(1);
+                    expect(countTraces('choropleth')).toBe(0);
+
+                    Plotly.restyle(gd, 'visible', true, [1]).then(function() {
+                        expect(countTraces('scattergeo')).toBe(1);
+                        expect(countTraces('choropleth')).toBe(1);
+                        done();
+                    });
+                });
+            });
+
+        });
     });
 });