diff --git a/src/plots/plots.js b/src/plots/plots.js
index 1254552dcec..1200689c322 100644
--- a/src/plots/plots.js
+++ b/src/plots/plots.js
@@ -364,6 +364,9 @@ plots.sendDataToCloud = function(gd) {
 // gd._fullLayout._basePlotModules
 //   is a list of all the plot modules required to draw the plot.
 //
+// gd._fullLayout._transformModules
+//   is a list of all the transform modules invoked.
+//
 plots.supplyDefaults = function(gd) {
     var oldFullLayout = gd._fullLayout || {},
         newFullLayout = gd._fullLayout = {},
@@ -375,6 +378,9 @@ plots.supplyDefaults = function(gd) {
 
     var i;
 
+    // Create all the storage space for frames, but only if doesn't already exist
+    if(!gd._transitionData) plots.createTransitionData(gd);
+
     // first fill in what we can of layout without looking at data
     // because fullData needs a few things from layout
 
@@ -435,7 +441,7 @@ plots.supplyDefaults = function(gd) {
     }
 
     // finally, fill in the pieces of layout that may need to look at data
-    plots.supplyLayoutModuleDefaults(newLayout, newFullLayout, newFullData);
+    plots.supplyLayoutModuleDefaults(newLayout, newFullLayout, newFullData, gd._transitionData);
 
     // TODO remove in v2.0.0
     // add has-plot-type refs to fullLayout for backward compatibility
@@ -474,12 +480,6 @@ plots.supplyDefaults = function(gd) {
             (gd.calcdata[i][0] || {}).trace = trace;
         }
     }
-
-    // Create all the storage space for frames, but only if doesn't already
-    // exist:
-    if(!gd._transitionData) {
-        plots.createTransitionData(gd);
-    }
 };
 
 // Create storage for all of the data related to frames and transitions:
@@ -646,6 +646,8 @@ plots.supplyDataDefaults = function(dataIn, dataOut, layout, fullLayout) {
         basePlotModules = fullLayout._basePlotModules = [],
         cnt = 0;
 
+    fullLayout._transformModules = [];
+
     function pushModule(fullTrace) {
         dataOut.push(fullTrace);
 
@@ -863,6 +865,8 @@ function supplyTransformDefaults(traceIn, traceOut, layout) {
             transformOut = _module.supplyDefaults(transformIn, traceOut, layout, traceIn);
             transformOut.type = type;
             transformOut._module = _module;
+
+            Lib.pushUnique(layout._transformModules, _module);
         }
         else {
             transformOut = Lib.extendFlat({}, transformIn);
@@ -1032,7 +1036,7 @@ function calculateReservedMargins(margins) {
     return resultingMargin;
 }
 
-plots.supplyLayoutModuleDefaults = function(layoutIn, layoutOut, fullData) {
+plots.supplyLayoutModuleDefaults = function(layoutIn, layoutOut, fullData, transitionData) {
     var i, _module;
 
     // can't be be part of basePlotModules loop
@@ -1063,6 +1067,16 @@ plots.supplyLayoutModuleDefaults = function(layoutIn, layoutOut, fullData) {
         }
     }
 
+    // transform module layout defaults
+    var transformModules = layoutOut._transformModules;
+    for(i = 0; i < transformModules.length; i++) {
+        _module = transformModules[i];
+
+        if(_module.supplyLayoutDefaults) {
+            _module.supplyLayoutDefaults(layoutIn, layoutOut, fullData, transitionData);
+        }
+    }
+
     // should FX be a component?
     Plotly.Fx.supplyLayoutDefaults(layoutIn, layoutOut, fullData);
 
diff --git a/test/jasmine/tests/transform_filter_test.js b/test/jasmine/tests/transform_filter_test.js
index 722b810c7a2..89b09750926 100644
--- a/test/jasmine/tests/transform_filter_test.js
+++ b/test/jasmine/tests/transform_filter_test.js
@@ -11,6 +11,8 @@ var assertStyle = require('../assets/assert_style');
 
 describe('filter transforms defaults:', function() {
 
+    var fullLayout = { _transformModules: [] };
+
     var traceIn, traceOut;
 
     it('supplyTraceDefaults should coerce all attributes', function() {
@@ -22,7 +24,7 @@ describe('filter transforms defaults:', function() {
             }]
         };
 
-        traceOut = Plots.supplyTraceDefaults(traceIn, 0, {});
+        traceOut = Plots.supplyTraceDefaults(traceIn, 0, fullLayout);
 
         expect(traceOut.transforms).toEqual([{
             type: 'filter',
@@ -44,7 +46,7 @@ describe('filter transforms defaults:', function() {
             }]
         };
 
-        traceOut = Plots.supplyTraceDefaults(traceIn, 0, {});
+        traceOut = Plots.supplyTraceDefaults(traceIn, 0, fullLayout);
 
         expect(traceOut.transforms).toEqual([{
             type: 'filter',
@@ -70,7 +72,7 @@ describe('filter transforms defaults:', function() {
             }]
         };
 
-        traceOut = Plots.supplyTraceDefaults(traceIn, 0, {});
+        traceOut = Plots.supplyTraceDefaults(traceIn, 0, fullLayout);
 
         expect(traceOut.transforms[0].target).toEqual('x');
         expect(traceOut.transforms[1].target).toEqual('x');
diff --git a/test/jasmine/tests/transform_multi_test.js b/test/jasmine/tests/transform_multi_test.js
index 283885186e3..6930effbd8e 100644
--- a/test/jasmine/tests/transform_multi_test.js
+++ b/test/jasmine/tests/transform_multi_test.js
@@ -13,6 +13,8 @@ var assertStyle = require('../assets/assert_style');
 describe('general transforms:', function() {
     'use strict';
 
+    var fullLayout = { _transformModules: [] };
+
     var traceIn, traceOut;
 
     it('supplyTraceDefaults should supply the transform defaults', function() {
@@ -21,7 +23,7 @@ describe('general transforms:', function() {
             transforms: [{ type: 'filter' }]
         };
 
-        traceOut = Plots.supplyTraceDefaults(traceIn, 0, {});
+        traceOut = Plots.supplyTraceDefaults(traceIn, 0, fullLayout);
 
         expect(traceOut.transforms).toEqual([{
             type: 'filter',
@@ -39,7 +41,7 @@ describe('general transforms:', function() {
             transforms: [{ type: 'invalid' }]
         };
 
-        traceOut = Plots.supplyTraceDefaults(traceIn, 0, {});
+        traceOut = Plots.supplyTraceDefaults(traceIn, 0, fullLayout);
 
         expect(traceOut.y).toBe(traceIn.y);
     });
@@ -56,6 +58,7 @@ describe('general transforms:', function() {
         };
 
         var layout = {
+            _transformModules: [],
             _globalTransforms: [{
                 type: 'filter'
             }]
@@ -80,6 +83,8 @@ describe('general transforms:', function() {
             target: 'x',
             _module: Filter
         }, '- trace second');
+
+        expect(layout._transformModules).toEqual([Filter]);
     });
 
     it('supplyDataDefaults should apply the transform while', function() {
@@ -164,8 +169,10 @@ describe('user-defined transforms:', function() {
             transforms: [transformIn]
         }];
 
-        var layout = {},
-            fullLayout = {};
+        var fullData = [],
+            layout = {},
+            fullLayout = { _has: function() {} },
+            transitionData = {};
 
         function assertSupplyDefaultsArgs(_transformIn, traceOut, _layout) {
             expect(_transformIn).toBe(transformIn);
@@ -184,16 +191,25 @@ describe('user-defined transforms:', function() {
             return dataOut;
         }
 
+        function assertSupplyLayoutDefaultsArgs(_layout, _fullLayout, _fullData, _transitionData) {
+            expect(_layout).toBe(layout);
+            expect(_fullLayout).toBe(fullLayout);
+            expect(_fullData).toBe(fullData);
+            expect(_transitionData).toBe(transitionData);
+        }
+
         var fakeTransformModule = {
             moduleType: 'transform',
             name: 'fake',
             attributes: {},
             supplyDefaults: assertSupplyDefaultsArgs,
-            transform: assertTransformArgs
+            transform: assertTransformArgs,
+            supplyLayoutDefaults: assertSupplyLayoutDefaultsArgs
         };
 
         Plotly.register(fakeTransformModule);
-        Plots.supplyDataDefaults(dataIn, [], layout, fullLayout);
+        Plots.supplyDataDefaults(dataIn, fullData, layout, fullLayout);
+        Plots.supplyLayoutModuleDefaults(layout, fullLayout, fullData, transitionData);
         delete Plots.transformsRegistry.fake;
     });