text: /**
  * Copyright 2012-2017, Plotly, Inc.
  * All rights reserved.
  *
  * This source code is licensed under the MIT license found in the
  * LICENSE file in the root directory of this source tree.
  */
  
  'use strict';
  
  var Registry = require('../../registry');
  var Plots = require('../plots');
  var Lib = require('../../lib');
  
  var constants = require('./constants');
  
  
  // convert between axis names (xaxis, xaxis2, etc, elements of gd.layout)
  // and axis id's (x, x2, etc). Would probably have ditched 'xaxis'
  // completely in favor of just 'x' if it weren't ingrained in the API etc.
  exports.id2name = function id2name(id) {
      if(typeof id !== 'string' || !id.match(constants.AX_ID_PATTERN)) return;
      var axNum = id.substr(1);
      if(axNum === '1') axNum = '';
      return id.charAt(0) + 'axis' + axNum;
  };
  
  exports.name2id = function name2id(name) {
      if(!name.match(constants.AX_NAME_PATTERN)) return;
      var axNum = name.substr(5);
      if(axNum === '1') axNum = '';
      return name.charAt(0) + axNum;
  };
  
  exports.cleanId = function cleanId(id, axLetter) {
      if(!id.match(constants.AX_ID_PATTERN)) return;
      if(axLetter && id.charAt(0) !== axLetter) return;
  
      var axNum = id.substr(1).replace(/^0+/, '');
      if(axNum === '1') axNum = '';
      return id.charAt(0) + axNum;
  };
  
  // get all axis object names
  // optionally restricted to only x or y or z by string axLetter
  // and optionally 2D axes only, not those inside 3D scenes
  function listNames(gd, axLetter, only2d) {
      var fullLayout = gd._fullLayout;
      if(!fullLayout) return [];
  
      function filterAxis(obj, extra) {
          var keys = Object.keys(obj),
              axMatch = /^[xyz]axis[0-9]*/,
              out = [];
  
          for(var i = 0; i < keys.length; i++) {
              var k = keys[i];
              if(axLetter && k.charAt(0) !== axLetter) continue;
              if(axMatch.test(k)) out.push(extra + k);
          }
  
          return out.sort();
      }
  
      var names = filterAxis(fullLayout, '');
      if(only2d) return names;
  
      var sceneIds3D = Plots.getSubplotIds(fullLayout, 'gl3d') || [];
      for(var i = 0; i < sceneIds3D.length; i++) {
          var sceneId = sceneIds3D[i];
          names = names.concat(
              filterAxis(fullLayout[sceneId], sceneId + '.')
          );
      }
  
      return names;
  }
  
  // get all axis objects, as restricted in listNames
  exports.list = function(gd, axletter, only2d) {
      return listNames(gd, axletter, only2d)
          .map(function(axName) {
              return Lib.nestedProperty(gd._fullLayout, axName).get();
          });
  };
  
  // get all axis ids, optionally restricted by letter
  // this only makes sense for 2d axes
  exports.listIds = function(gd, axletter) {
      return listNames(gd, axletter, true).map(exports.name2id);
  };
  
  // get an axis object from its id 'x','x2' etc
  // optionally, id can be a subplot (ie 'x2y3') and type gets x or y from it
  exports.getFromId = function(gd, id, type) {
      var fullLayout = gd._fullLayout;
  
      if(type === 'x') id = id.replace(/y[0-9]*/, '');
      else if(type === 'y') id = id.replace(/x[0-9]*/, '');
  
      return fullLayout[exports.id2name(id)];
  };
  
  // get an axis object of specified type from the containing trace
  exports.getFromTrace = function(gd, fullTrace, type) {
      var fullLayout = gd._fullLayout;
      var ax = null;
  
      if(Registry.traceIs(fullTrace, 'gl3d')) {
          var scene = fullTrace.scene;
          if(scene.substr(0, 5) === 'scene') {
              ax = fullLayout[scene][type + 'axis'];
          }
      }
      else {
          ax = exports.getFromId(gd, fullTrace[type + 'axis'] || type);
      }
  
      return ax;
  };
  