@@ -24,6 +24,8 @@ var axisIds = require('./axis_ids');
2424var id2name = axisIds . id2name ;
2525var name2id = axisIds . name2id ;
2626
27+ var AX_ID_PATTERN = require ( './constants' ) . AX_ID_PATTERN ;
28+
2729var Registry = require ( '../../registry' ) ;
2830var traceIs = Registry . traceIs ;
2931var getComponentMethod = Registry . getComponentMethod ;
@@ -133,7 +135,28 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
133135
134136 var bgColor = Color . combine ( plotBgColor , layoutOut . paper_bgcolor ) ;
135137
136- var axName , axLetter , axLayoutIn , axLayoutOut ;
138+ // name of single axis (e.g. 'xaxis', 'yaxis2')
139+ var axName ;
140+ // id of single axis (e.g. 'y', 'x5')
141+ var axId ;
142+ // 'x' or 'y'
143+ var axLetter ;
144+ // input layout axis container
145+ var axLayoutIn ;
146+ // full layout axis container
147+ var axLayoutOut ;
148+
149+ function newAxLayoutOut ( ) {
150+ var traces = ax2traces [ axName ] || [ ] ;
151+ axLayoutOut . _traceIndices = traces . map ( function ( t ) { return t . _expandedIndex ; } ) ;
152+ axLayoutOut . _annIndices = [ ] ;
153+ axLayoutOut . _shapeIndices = [ ] ;
154+ axLayoutOut . _imgIndices = [ ] ;
155+ axLayoutOut . _subplotsWith = [ ] ;
156+ axLayoutOut . _counterAxes = [ ] ;
157+ axLayoutOut . _name = axLayoutOut . _attr = axName ;
158+ axLayoutOut . _id = axId ;
159+ }
137160
138161 function coerce ( attr , dflt ) {
139162 return Lib . coerce ( axLayoutIn , axLayoutOut , layoutAttributes , attr , dflt ) ;
@@ -147,9 +170,6 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
147170 return ( axLetter === 'x' ) ? yIds : xIds ;
148171 }
149172
150- var counterAxes = { x : getCounterAxes ( 'x' ) , y : getCounterAxes ( 'y' ) } ;
151- var allAxisIds = counterAxes . x . concat ( counterAxes . y ) ;
152-
153173 function getOverlayableAxes ( axLetter , axName ) {
154174 var list = ( axLetter === 'x' ) ? xNames : yNames ;
155175 var out = [ ] ;
@@ -165,9 +185,30 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
165185 return out ;
166186 }
167187
188+ // list of available counter axis names
189+ var counterAxes = { x : getCounterAxes ( 'x' ) , y : getCounterAxes ( 'y' ) } ;
190+ // list of all x AND y axis ids
191+ var allAxisIds = counterAxes . x . concat ( counterAxes . y ) ;
192+ // lookup and list of axis ids that axes in axNames have a reference to,
193+ // even though they are missing from allAxisIds
194+ var missingMatchedAxisIdsLookup = { } ;
195+ var missingMatchedAxisIds = [ ] ;
196+
197+ // fill in 'missing' axis lookup when an axis is set to match an axis
198+ // not part of the allAxisIds list, save axis type so that we can propagate
199+ // it to the missing axes
200+ function addMissingMatchedAxis ( ) {
201+ var matchesIn = axLayoutIn . matches ;
202+ if ( AX_ID_PATTERN . test ( matchesIn ) && allAxisIds . indexOf ( matchesIn ) === - 1 ) {
203+ missingMatchedAxisIdsLookup [ matchesIn ] = axLayoutIn . type ;
204+ missingMatchedAxisIds = Object . keys ( missingMatchedAxisIdsLookup ) ;
205+ }
206+ }
207+
168208 // first pass creates the containers, determines types, and handles most of the settings
169209 for ( i = 0 ; i < axNames . length ; i ++ ) {
170210 axName = axNames [ i ] ;
211+ axId = name2id ( axName ) ;
171212 axLetter = axName . charAt ( 0 ) ;
172213
173214 if ( ! Lib . isPlainObject ( layoutIn [ axName ] ) ) {
@@ -176,20 +217,7 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
176217
177218 axLayoutIn = layoutIn [ axName ] ;
178219 axLayoutOut = Template . newContainer ( layoutOut , axName , axLetter + 'axis' ) ;
179-
180- var traces = ax2traces [ axName ] || [ ] ;
181- axLayoutOut . _traceIndices = traces . map ( function ( t ) { return t . _expandedIndex ; } ) ;
182- axLayoutOut . _annIndices = [ ] ;
183- axLayoutOut . _shapeIndices = [ ] ;
184- axLayoutOut . _imgIndices = [ ] ;
185- axLayoutOut . _subplotsWith = [ ] ;
186- axLayoutOut . _counterAxes = [ ] ;
187-
188- // set up some private properties
189- axLayoutOut . _name = axLayoutOut . _attr = axName ;
190- var id = axLayoutOut . _id = name2id ( axName ) ;
191-
192- var overlayableAxes = getOverlayableAxes ( axLetter , axName ) ;
220+ newAxLayoutOut ( ) ;
193221
194222 var visibleDflt =
195223 ( axLetter === 'x' && ! xaMustDisplay [ axName ] && xaMayHide [ axName ] ) ||
@@ -207,13 +235,13 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
207235 font : layoutOut . font ,
208236 outerTicks : outerTicks [ axName ] ,
209237 showGrid : ! noGrids [ axName ] ,
210- data : traces ,
238+ data : ax2traces [ axName ] || [ ] ,
211239 bgColor : bgColor ,
212240 calendar : layoutOut . calendar ,
213241 automargin : true ,
214242 visibleDflt : visibleDflt ,
215243 reverseDflt : reverseDflt ,
216- splomStash : ( ( layoutOut . _splomAxes || { } ) [ axLetter ] || { } ) [ id ]
244+ splomStash : ( ( layoutOut . _splomAxes || { } ) [ axLetter ] || { } ) [ axId ]
217245 } ;
218246
219247 coerce ( 'uirevision' , layoutOut . uirevision ) ;
@@ -239,12 +267,63 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
239267 handlePositionDefaults ( axLayoutIn , axLayoutOut , coerce , {
240268 letter : axLetter ,
241269 counterAxes : counterAxes [ axLetter ] ,
242- overlayableAxes : overlayableAxes ,
270+ overlayableAxes : getOverlayableAxes ( axLetter , axName ) ,
243271 grid : layoutOut . grid
244272 } ) ;
245273
246274 coerce ( 'title.standoff' ) ;
247275
276+ addMissingMatchedAxis ( ) ;
277+
278+ axLayoutOut . _input = axLayoutIn ;
279+ }
280+
281+ // coerce the 'missing' axes
282+ i = 0 ;
283+ while ( i < missingMatchedAxisIds . length ) {
284+ axId = missingMatchedAxisIds [ i ++ ] ;
285+ axName = id2name ( axId ) ;
286+ axLetter = axName . charAt ( 0 ) ;
287+
288+ if ( ! Lib . isPlainObject ( layoutIn [ axName ] ) ) {
289+ layoutIn [ axName ] = { } ;
290+ }
291+
292+ axLayoutIn = layoutIn [ axName ] ;
293+ axLayoutOut = Template . newContainer ( layoutOut , axName , axLetter + 'axis' ) ;
294+ newAxLayoutOut ( ) ;
295+
296+ var defaultOptions2 = {
297+ letter : axLetter ,
298+ font : layoutOut . font ,
299+ outerTicks : outerTicks [ axName ] ,
300+ showGrid : ! noGrids [ axName ] ,
301+ data : [ ] ,
302+ bgColor : bgColor ,
303+ calendar : layoutOut . calendar ,
304+ automargin : true ,
305+ visibleDflt : false ,
306+ reverseDflt : false ,
307+ splomStash : ( ( layoutOut . _splomAxes || { } ) [ axLetter ] || { } ) [ axId ]
308+ } ;
309+
310+ coerce ( 'uirevision' , layoutOut . uirevision ) ;
311+
312+ axLayoutOut . type = missingMatchedAxisIdsLookup [ axId ] || 'linear' ;
313+
314+ handleAxisDefaults ( axLayoutIn , axLayoutOut , coerce , defaultOptions2 , layoutOut ) ;
315+
316+ handlePositionDefaults ( axLayoutIn , axLayoutOut , coerce , {
317+ letter : axLetter ,
318+ counterAxes : counterAxes [ axLetter ] ,
319+ overlayableAxes : getOverlayableAxes ( axLetter , axName ) ,
320+ grid : layoutOut . grid
321+ } ) ;
322+
323+ coerce ( 'fixedrange' ) ;
324+
325+ addMissingMatchedAxis ( ) ;
326+
248327 axLayoutOut . _input = axLayoutIn ;
249328 }
250329
@@ -295,25 +374,32 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
295374 var constraintGroups = layoutOut . _axisConstraintGroups = [ ] ;
296375 // similar to _axisConstraintGroups, but for matching axes
297376 var matchGroups = layoutOut . _axisMatchGroups = [ ] ;
377+ // make sure to include 'missing' axes here
378+ var allAxisIdsIncludingMissing = allAxisIds . concat ( missingMatchedAxisIds ) ;
379+ var axNamesIncludingMissing = axNames . concat ( Lib . simpleMap ( missingMatchedAxisIds , id2name ) ) ;
298380
299- for ( i = 0 ; i < axNames . length ; i ++ ) {
300- axName = axNames [ i ] ;
381+ for ( i = 0 ; i < axNamesIncludingMissing . length ; i ++ ) {
382+ axName = axNamesIncludingMissing [ i ] ;
301383 axLetter = axName . charAt ( 0 ) ;
302384 axLayoutIn = layoutIn [ axName ] ;
303385 axLayoutOut = layoutOut [ axName ] ;
304386
305387 var scaleanchorDflt ;
306388 if ( axLetter === 'y' && ! axLayoutIn . hasOwnProperty ( 'scaleanchor' ) && axHasImage [ axName ] ) {
307389 scaleanchorDflt = axLayoutOut . anchor ;
308- } else { scaleanchorDflt = undefined ; }
390+ } else {
391+ scaleanchorDflt = undefined ;
392+ }
309393
310394 var constrainDflt ;
311395 if ( ! axLayoutIn . hasOwnProperty ( 'constrain' ) && axHasImage [ axName ] ) {
312396 constrainDflt = 'domain' ;
313- } else { constrainDflt = undefined ; }
397+ } else {
398+ constrainDflt = undefined ;
399+ }
314400
315401 handleConstraintDefaults ( axLayoutIn , axLayoutOut , coerce , {
316- allAxisIds : allAxisIds ,
402+ allAxisIds : allAxisIdsIncludingMissing ,
317403 layoutOut : layoutOut ,
318404 scaleanchorDflt : scaleanchorDflt ,
319405 constrainDflt : constrainDflt
@@ -324,7 +410,6 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
324410 var group = matchGroups [ i ] ;
325411 var rng = null ;
326412 var autorange = null ;
327- var axId ;
328413
329414 // find 'matching' range attrs
330415 for ( axId in group ) {
0 commit comments