<commit_before>/**
* @license Apache-2.0
*
* Copyright (c) 2018 The Stdlib Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

'use strict';

var EventEmitter = require( 'events' ).EventEmitter;
var logger = require( 'debug' );
var getKeys = require( 'object-keys' ).shim();
var setReadOnly = require( '@stdlib/utils/define-read-only-property' );
var isObject = require( '@stdlib/assert/is-plain-object' );
var copy = require( '@stdlib/utils/copy' );
var inherit = require( '@stdlib/utils/inherit' );
var mergeFcn = require( '@stdlib/utils/merge' ).factory;
var minstd = require( '@stdlib/random/base/minstd' );
var view = require( './view/view.js' );
var defaults = require( './defaults.js' );


// VARIABLES //

var debug = logger( 'plot:main' );
var PRIVATE_PROPS = [
	'_autoRender',
	'_autoView',
	'_colors',
	'_description',
	'_engine',
	'_height',
	'_isDefined',
	'_labels',
	'_lineOpacity',
	'_lineStyle',
	'_lineWidth',
	'_paddingBottom',
	'_paddingLeft',
	'_paddingRight',
	'_paddingTop',
	'_renderFormat',
	'_symbols',
	'_symbolsOpacity',
	'_symbolsSize',
	'_title',
	'_viewer',
	'_width',
	'_xAxisOrient',
	'_xData',
	'_xLabel',
	'_xMax',
	'_xMin',
	'_xNumTicks',
	'_xRug',
	'_xRugOpacity',
	'_xRugOrient',
	'_xRugSize',
	'_xScale',
	'_xTickFormat',
	'_yAxisOrient',
	'_yData',
	'_yLabel',
	'_yMax',
	'_yMin',
	'_yNumTicks',
	'_yRug',
	'_yRugOpacity',
	'_yRugOrient',
	'_yRugSize',
	'_yScale',
	'_yTickFormat'
];


// FUNCTIONS //

var merge = mergeFcn({
	'extend': false
});


// MAIN //

/**
* Plot constructor.
*
* @constructor
* @param {Array} [x] - x-values
* @param {Array} [y] - y-values
* @param {Options} [options] - constructor options
* @param {boolean} [options.autoRender=true] - indicates whether to re-render on a change event
* @param {boolean} [options.autoView=false] - indicates whether to generate an updated view on a render event
* @param {(string|StringArray)} [options.colors='category10'] - data colors
* @param {string} [options.description=''] - plot description
* @param {string} [options.engine='svg'] - plot engine
* @param {PositiveNumber} [options.height=400] - plot height
* @param {Function} [options.isDefined] - accessor indicating whether a datum is defined
* @param {(StringArray|EmptyArray)} [options.labels] - data labels
* @param {(number|NumberArray)} [options.lineOpacity=0.9] - data line opacity
* @param {(string|StringArray)} [options.lineStyle='-'] - data line style(s)
* @param {(NonNegativeInteger|Array<NonNegativeInteger>)} [options.lineWidth=2] - data line width(s)
* @param {NonNegativeInteger} [options.paddingBottom=80] - bottom padding
* @param {NonNegativeInteger} [options.paddingLeft=90] - left padding
* @param {NonNegativeInteger} [options.paddingRight=20] - right padding
* @param {NonNegativeInteger} [options.paddingTop=80] - top padding
* @param {string} [options.renderFormat='vdom'] - plot render format
* @param {(string|StringArray)} [options.symbols='none'] - data symbols
* @param {(number|NumberArray)} [options.symbolsOpacity=0.9] - symbols opacity
* @param {(NonNegativeInteger|Array<NonNegativeInteger>)} [options.symbolsSize=6] - symbols size
* @param {string} [options.title=''] - plot title
* @param {string} [options.viewer='none'] - plot viewer
* @param {PositiveNumber} [options.width=400] - plot width
* @param {Array} [options.x=[]] - x-values
* @param {string} [options.xAxisOrient='bottom'] - x-axis orientation
* @param {string} [options.xLabel='x'] - x-axis label
* @param {(Date|FiniteNumber|null)} [options.xMax=null] - maximum value of x-axis domain
* @param {(Date|FiniteNumber|null)} [options.xMin=null] - minimum value of x-axis domain
* @param {(NonNegativeInteger|null)} [options.xNumTicks=5] - number of x-axis tick marks
* @param {(boolean|BooleanArray)} [options.xRug=false] - indicates whether to render a rug plot along the x-axis
* @param {(string|StringArray)} [options.xRugOrient='bottom'] - x-axis rug orientation
* @param {(number|NumberArray)} [options.xRugOpacity=0.1] - x-axis rug opacity
* @param {(NonNegativeInteger|Array<NonNegativeInteger>)} [options.xRugSize=6] - x-axis rug tick (tassel) size
* @param {string} [options.xScale='linear'] - x-axis scale
* @param {(string|null)} [options.xTickFormat=null] - x-axis tick format
* @param {Array} [options.y=[]] - y-values
* @param {string} [options.yAxisOrient='left'] - y-axis orientation
* @param {string} [options.yLabel='y'] - y-axis label
* @param {(FiniteNumber|null)} [options.yMax=null] - maximum value of y-axis domain
* @param {(FiniteNumber|null)} [options.yMin=null] - minimum value of y-axis domain
* @param {(NonNegativeInteger|null)} [options.yNumTicks=5] - number of y-axis tick marks
* @param {(boolean|BooleanArray)} [options.yRug=false] - indicates whether to render a rug plot along the y-axis
* @param {(string|StringArray)} [options.yRugOrient='left'] - y-axis rug orientation
* @param {(number|NumberArray)} [options.yRugOpacity=0.1] - y-axis rug opacity
* @param {(NonNegativeInteger|Array<NonNegativeInteger>)} [options.yRugSize=6] - y-axis rug tick (tassel) size
* @param {string} [options.yScale='linear'] - y-axis scale
* @param {(string|null)} [options.yTickFormat=null] - y-axis tick format
* @throws {TypeError} must provide valid options
* @returns {Plot} Plot instance
*
* @example
* var plot = new Plot();
*/
function Plot() {
	var options;
	var nargs;
	var keys;
	var self;
	var opts;
	var key;
	var i;

	nargs = arguments.length;
	if ( !(this instanceof Plot) ) {
		if ( nargs === 0 ) {
			return new Plot();
		}
		if ( nargs === 1 ) {
			return new Plot( arguments[0] );
		}
		if ( nargs === 2 ) {
			return new Plot( arguments[0], arguments[1] );
		}
		return new Plot( arguments[0], arguments[1], arguments[2] );
	}
	self = this;

	opts = defaults();
	if ( nargs === 0 ) {
		options = {};
	} else if ( nargs === 1 ) {
		options = arguments[ 0 ];
		if ( !isObject( options ) ) {
			throw new TypeError( 'invalid input argument. Options argument must be an `object`. Value: `' + options + '`.' );
		}
	} else if ( nargs === 2 ) {
		options = {
			'x': arguments[ 0 ],
			'y': arguments[ 1 ]
		};
	} else if ( nargs > 2 ) {
		if ( !isObject( arguments[2] ) ) {
			throw new TypeError( 'invalid input argument. Options argument must be an `object`. Value: `' + arguments[2] + '`.' );
		}
		options = copy( arguments[2] ); // avoid mutation
		options.x = arguments[ 0 ];
		options.y = arguments[ 1 ];
	}
	opts = merge( opts, options );

	debug( 'Creating an instance with the following configuration: %s.', JSON.stringify( opts ) );
	EventEmitter.call( this );

	for ( i = 0; i < PRIVATE_PROPS.length; i++ ) {
		Object.defineProperty( this, PRIVATE_PROPS[i], {
			'configurable': false,
			'enumerable': false,
			'writable': true,
			'value': null
		});
	}
	// Set a clipping path id:
	Object.defineProperty( this, '_clipPathId', {
		'configurable': false,
		'enumerable': false,
		'writable': false,
		'value': minstd().toString() // TODO: uuid
	});

	// Initialize an internal cache for renderers...
	Object.defineProperty( this, '$', {
		'configurable': false,
		'enumerable': false,
		'writable': false,
		'value': {}
	});
	Object.defineProperty( this.$, 'svg', {
		'configurable': false,
		'enumerable': false,
		'writable': false,
		'value': {}
	});

	// Set options...
	keys = getKeys( opts );
	for ( i = 0; i < keys.length; i++ ) {
		key = keys[ i ];
		this[ key ] = opts[ key ];
	}

	// Add event listeners:
	this.on( 'change', onChange );
	this.on( 'render', onRender );

	return this;

	/**
	* Callback invoked upon receiving a change event.
	*
	* @private
	*/
	function onChange() {
		/* eslint-disable no-underscore-dangle */
		debug( 'Received a change event.' );
		if ( self._autoRender ) {
			self.render();
		}
	}

	/**
	* Callback invoked upon receiving a render event.
	*
	* @private
	* @param {*} plot - rendered plot
	*/
	function onRender( plot ) {
		/* eslint-disable no-underscore-dangle */
		debug( 'Received a render event.' );
		if ( self._autoView ) {
			debug( 'Viewer: %s.', self._viewer );
			debug( 'Generating view...' );
			view( self, self._viewer, plot );
		}
	}
}

/*
* Inherit from the `EventEmitter` prototype.
*/
inherit( Plot, EventEmitter );

/**
* `x` values.
*
* @name x
* @memberof Plot.prototype
* @type {Array}
* @throws {TypeError} must be an array
* @default []
*
* @example
* var plot = new Plot();
* plot.x = [ [ 1417563950959, 1417563952959 ] ];
*
* @example
* var plot = new Plot({
*     'x': [ [ 1417563950959, 1417563952959 ] ]
* });
* var x = plot.x;
* // returns [ [ 1417563950959, 1417563952959 ] ]
*/
Object.defineProperty( Plot.prototype, 'x', {
	'configurable': false,
	'enumerable': true,
	'set': require( './props/x/set.js' ),
	'get': require( './props/x/get.js' )
});

/**
* `y` values.
*
* @name y
* @memberof Plot.prototype
* @type {Array}
* @throws {TypeError} must be an array
* @default []
*
* @example
* var plot = new Plot();
* plot.x = [ [ 1417563950959, 1417563952959 ] ];
* plot.y = [ [ 0.25, 0.23 ] ];
*
* @example
* var plot = new Plot({
*     'x': [ [ 1417563950959, 1417563952959 ] ],
*     'y': [ [ 0.25, 0.23 ] ]
* });
* var y = plot.y;
* // returns [ [ 0.25, 0.23 ] ]
*/
Object.defineProperty( Plot.prototype, 'y', {
	'configurable': false,
	'enumerable': true,
	'set': require( './props/y/set.js' ),
	'get': require( './props/y/get.js' )
});

/**
* Data labels.
*
* @name labels
* @memberof Plot.prototype
* @type {(StringArray|EmptyArray)}
* @throws {TypeError} must be either an array of strings or an empty array
* @default []
*
* @example
* var plot = new Plot();
* plot.labels = [ 'beep', 'boop' ];
*
* @example
* var plot = new Plot({
*     'labels': [ 'beep', 'boop' ]
* });
* var labels = plot.labels;
* // returns [ 'beep', 'boop' ]
*/
Object.defineProperty( Plot.prototype, 'labels', {
	'configurable': false,
	'enumerable': true,
	'set': require( './props/labels/set.js' ),
	'get': require( './props/labels/get.js' )
});

/**
* Accessor which defines whether a datum is defined.
*
* ## Notes
*
* -   This accessor is used to define how missing values are encoded.
* -   The default behavior is to ignore values which are `NaN`.
*
* @name isDefined
* @memberof Plot.prototype
* @type {Function}
* @param {*} d - datum
* @param {integer} i - index
* @throws {TypeError} must be a function
*
* @example
* var plot = new Plot();
* plot.isDefined = function isDefined( d ) {
*     // Check for `NaN`:
*     return ( d === d );
* }
*
* @example
* function isDefined( d ) {
*     // Check for `NaN`:
*     return ( d === d );
* }
* var plot = new Plot({
*     'isDefined': isDefined
* });
* var fcn = plot.isDefined;
* // returns <Function>
*/
Object.defineProperty( Plot.prototype, 'isDefined', {
	'configurable': false,
	'enumerable': true,
	'set': require( './props/is-defined/set.js' ),
	'get': require( './props/is-defined/get.js' )
});

/**
* Data colors. When retrieved, the returned value is always an `array`.
*
* @name colors
* @memberof Plot.prototype
* @type {(string|StringArray)}
* @throws {TypeError} must be either a string or an array of strings
* @default 'category10'
*
* @example
* var plot = new Plot();
* plot.colors = 'category20';
*
* @example
* var plot = new Plot({
*     'colors': 'category20'
* });
* var colors = plot.colors;
* // returns [...]
*/
Object.defineProperty( Plot.prototype, 'colors', {
	'configurable': false,
	'enumerable': true,
	'set': require( './props/colors/set.js' ),
	'get': require( './props/colors/get.js' )
});

/**
* Data line style(s).
*
* ## Notes
*
* -   When retrieved, the returned value is always an `array`.
*
* @name lineStyle
* @memberof Plot.prototype
* @type {(string|StringArray)}
* @throws {TypeError} must be a string or string array
* @throws {Error} must be a supported line style
* @default '-'
*
* @example
* var plot = new Plot();
* plot.lineStyle = [ '-', 'none' ];
*
* @example
* var plot = new Plot({
*     'lineStyle': 'none'
* });
* var lineStyle = plot.lineStyle;
* // returns [ 'none' ]
*/
Object.defineProperty( Plot.prototype, 'lineStyle', {
	'configurable': false,
	'enumerable': true,
	'set': require( './props/line-style/set.js' ),
	'get': require( './props/line-style/get.js' )
});

/**
* Data line opacity.
*
* ## Notes
*
* -   When retrieved, the returned value is always an `array`.
*
* @name lineOpacity
* @memberof Plot.prototype
* @type {(number|NumberArray)}
* @throws {TypeError} must be a number or number array
* @throws {RangeError} must be a number on the interval `[0,1]`
* @default '0.9'
*
* @example
* var plot = new Plot();
* plot.lineOpacity = [ 1.0, 0.5 ];
*
* @example
* var plot = new Plot({
*     'lineOpacity': 0.5
* });
* var opacity = plot.lineOpacity;
* // returns [ 0.5 ]
*/
Object.defineProperty( Plot.prototype, 'lineOpacity', {
	'configurable': false,
	'enumerable': true,
	'set': require( './props/line-opacity/set.js' ),
	'get': require( './props/line-opacity/get.js' )
});

/**
* Data line width.
*
* ## Notes
*
* -   When retrieved, the returned value is always an `array`.
*
* @name lineWidth
* @memberof Plot.prototype
* @type {(NonNegativeInteger|NonNegativeIntegerArray)}
* @throws {TypeError} must be a nonnegative integer or nonnegative integer array
* @default 2
*
* @example
* var plot = new Plot();
* plot.lineWidth = 1;
*
* @example
* var plot = new Plot({
*     'lineWidth': [ 1, 3 ]
* });
* var width = plot.lineWidth;
* // returns [ 1, 3 ]
*/
Object.defineProperty( Plot.prototype, 'lineWidth', {
	'configurable': false,
	'enumerable': true,
	'set': require( './props/line-width/set.js' ),
	'get': require( './props/line-width/get.js' )
});

/**
* Data symbols. When retrieved, the returned value is always an `array`.
*
* @name symbols
* @memberof Plot.prototype
* @type {(string|StringArray)}
* @throws {TypeError} must be a string or string array
* @throws {Error} must be a supported symbol
* @default 'none'
*
* @example
* var plot = new Plot();
* plot.symbols = [ 'open-circle', 'closed-circle' ];
*
* @example
* var plot = new Plot({
*     'symbols': 'closed-circle'
* });
* var symbols = plot.symbols;
* // returns [ 'closed-circle' ]
*/
Object.defineProperty( Plot.prototype, 'symbols', {
	'configurable': false,
	'enumerable': true,
	'set': require( './props/symbols/set.js' ),
	'get': require( './props/symbols/get.js' )
});

/**
* Symbols size. When retrieved, the returned value is always an `array`.
*
* @name symbolsSize
* @memberof Plot.prototype
* @type {(NonNegativeInteger|NonNegativeIntegerArray)}
* @throws {TypeError} must be a nonnegative integer or nonnegative integer array
* @default 6
*
* @example
* var plot = new Plot();
* plot.symbolsSize = 4;
*
* @example
* var plot = new Plot({
*     'symbolsSize': [ 4, 6 ]
* });
* var size = plot.symbolsSize;
* // returns [ 4, 6 ]
*/
Object.defineProperty( Plot.prototype, 'symbolsSize', {
	'configurable': false,
	'enumerable': true,
	'set': require( './props/symbols-size/set.js' ),
	'get': require( './props/symbols-size/get.js' )
});

/**
* Symbols opacity. When retrieved, the returned value is always an `array`.
*
* @name symbolsOpacity
* @memberof Plot.prototype
* @type {(number|NumberArray)}
* @throws {TypeError} must be a number or number array
* @throws {RangeError} must be a number on the interval `[0,1]`
* @default 0.9
*
* @example
* var plot = new Plot();
* plot.symbolsOpacity = [ 0.2, 0.5 ];
*
* @example
* var plot = new Plot({
*     'symbolsOpacity': 0.2
* });
* var opacity = plot.symbolsOpacity;
* // returns 0.2
*/
Object.defineProperty( Plot.prototype, 'symbolsOpacity', {
	'configurable': false,
	'enumerable': true,
	'set': require( './props/symbols-opacity/set.js' ),
	'get': require( './props/symbols-opacity/get.js' )
});

/**
* Plot width.
*
* @name width
* @memberof Plot.prototype
* @type {PositiveNumber}
* @throws {TypeError} must be a positive number
* @default 400 (px)
*
* @example
* var plot = new Plot();
* plot.width = 100;
*
* @example
* var plot = new Plot({
*     'width': 480
* });
* var width = plot.width;
* // returns 480
*/
Object.defineProperty( Plot.prototype, 'width', {
	'configurable': false,
	'enumerable': true,
	'set': require( './props/width/set.js' ),
	'get': require( './props/width/get.js' )
});

/**
* Plot height.
*
* @name height
* @memberof Plot.prototype
* @type {PositiveNumber}
* @throws {TypeError} must be a positive number
* @default 400 (px)
*
* @example
* var plot = new Plot();
* plot.height = 100;
*
* @example
* var plot = new Plot({
*     'height': 360
* });
* var height = plot.height;
* // returns 360
*/
Object.defineProperty( Plot.prototype, 'height', {
	'configurable': false,
	'enumerable': true,
	'set': require( './props/height/set.js' ),
	'get': require( './props/height/get.js' )
});

/**
* Plot left padding.
*
* ## Notes
*
* -   Typically used to create space for a left-oriented y-axis.
*
* @name paddingLeft
* @memberof Plot.prototype
* @type {NonNegativeInteger}
* @throws {TypeError} must be a nonnegative integer
* @default 90 (px)
*
* @example
* var plot = new Plot();
* plot.paddingLeft = 100;
*
* @example
* var plot = new Plot({
*     'paddingLeft': 100
* });
* var padding = plot.paddingLeft;
* // returns 100
*/
Object.defineProperty( Plot.prototype, 'paddingLeft', {
	'configurable': false,
	'enumerable': true,
	'set': require( './props/padding-left/set.js' ),
	'get': require( './props/padding-left/get.js' )
});

/**
* Plot right padding.
*
* ## Notes
*
* -   Typically used to create space for a right-oriented y-axis.
*
* @name paddingRight
* @memberof Plot.prototype
* @type {NonNegativeInteger}
* @throws {TypeError} must be a nonnegative integer
* @default 20 (px)
*
* @example
* var plot = new Plot();
* plot.paddingRight = 100;
*
* @example
* var plot = new Plot({
*     'paddingRight': 100
* });
* var padding = plot.paddingRight;
* // returns 100
*/
Object.defineProperty( Plot.prototype, 'paddingRight', {
	'configurable': false,
	'enumerable': true,
	'set': require( './props/padding-right/set.js' ),
	'get': require( './props/padding-right/get.js' )
});

/**
* Plot top padding.
*
* ## Notes
*
* -   Typically used to create space for a title or top-oriented x-axis.
*
* @name paddingTop
* @memberof Plot.prototype
* @type {NonNegativeInteger}
* @throws {TypeError} must be a nonnegative integer
* @default 80 (px)
*
* @example
* var plot = new Plot();
* plot.paddingTop = 100;
*
* @example
* var plot = new Plot({
*     'paddingTop': 100
* });
* var padding = plot.paddingTop;
* // returns 100
*/
Object.defineProperty( Plot.prototype, 'paddingTop', {
	'configurable': false,
	'enumerable': true,
	'set': require( './props/padding-top/set.js' ),
	'get': require( './props/padding-top/get.js' )
});

/**
* Plot bottom padding.
*
* ## Notes
*
* -   Typically used to create space for a bottom-oriented y-axis.
*
* @name paddingBottom
* @memberof Plot.prototype
* @type {NonNegativeInteger}
* @throws {TypeError} must be a nonnegative integer
* @default 80 (px)
*
* @example
* var plot = new Plot();
* plot.paddingBottom = 100;
*
* @example
* var plot = new Plot({
*     'paddingBottom': 100
* });
* var padding = plot.paddingBottom;
* // returns 100
*/
Object.defineProperty( Plot.prototype, 'paddingBottom', {
	'configurable': false,
	'enumerable': true,
	'set': require( './props/padding-bottom/set.js' ),
	'get': require( './props/padding-bottom/get.js' )
});

/**
* Minimum value of the x-axis domain.
*
* ## Notes
*
* -   When retrieved, if the value has been set to `null`, the returned value is computed from the `x` data.
*
* @name xMin
* @memberof Plot.prototype
* @type {(FiniteNumber|null)}
* @throws {TypeError} must be a finite number primitive or null
* @default null
*
* @example
* var plot = new Plot();
* plot.xMin = -1.0;
*
* @example
* var plot = new Plot({
*     'xMin': -10.0
* });
* var xmin = plot.xMin;
* // returns -10.0
*/
Object.defineProperty( Plot.prototype, 'xMin', {
	'configurable': false,
	'enumerable': true,
	'set': require( './props/x-min/set.js' ),
	'get': require( './props/x-min/get.js' )
});

/**
* Maximum value of the x-axis domain.
*
* ## Notes
*
* -   When retrieved, if the value has been set to `null`, the returned value is computed from the `x` data.
*
* @name xMax
* @memberof Plot.prototype
* @type {(FiniteNumber|null)}
* @throws {TypeError} must be a finite number primitive or null
* @default null
*
* @example
* var plot = new Plot();
* plot.xMax = 100.0;
*
* @example
* var plot = new Plot({
*     'xMax': 10.0
* });
* var xmax = plot.xMax;
* // returns 10.0
*/
Object.defineProperty( Plot.prototype, 'xMax', {
	'configurable': false,
	'enumerable': true,
	'set': require( './props/x-max/set.js' ),
	'get': require( './props/x-max/get.js' )
});

/**
* Minimum value of the y-axis domain.
*
* ## Notes
*
* -   When retrieved, if the value has been set to `null`, the returned value is computed from the `y` data.
*
* @name yMin
* @memberof Plot.prototype
* @type {(FiniteNumber|null)}
* @throws {TypeError} must be a finite number primitive or null
* @default null
*
* @example
* var plot = new Plot();
* plot.yMin = -100.0;
*
* @example
* var plot = new Plot({
*     'yMin': 3.14
* });
* var ymin = plot.yMin;
* // returns 3.14
*/
Object.defineProperty( Plot.prototype, 'yMin', {
	'configurable': false,
	'enumerable': true,
	'set': require( './props/y-min/set.js' ),
	'get': require( './props/y-min/get.js' )
});

/**
* Maximum value of the y-axis domain.
*
* ## Notes
*
* -   When retrieved, if the value has been set to `null`, the returned value is computed from the `y` data.
*
* @name yMax
* @memberof Plot.prototype
* @type {(FiniteNumber|null)}
* @throws {TypeError} must be a finite number primitive or null
* @default null
*
* @example
* var plot = new Plot();
* plot.yMax = 100.0;
*
* @example
* var plot = new Plot({
*     'yMax': 31.4
* });
* var ymax = plot.yMax;
* // returns 31.4
*/
Object.defineProperty( Plot.prototype, 'yMax', {
	'configurable': false,
	'enumerable': true,
	'set': require( './props/y-max/set.js' ),
	'get': require( './props/y-max/get.js' )
});

/**
* Scale function for mapping values to a coordinate along the x-axis. When retrieved, the returned value is a scale function.
*
* @name xScale
* @memberof Plot.prototype
* @type {string}
* @throws {TypeError} must be a string primitive
* @default 'linear'
*
* @example
* var plot = new Plot();
* plot.xScale = 'time';
*
* @example
* var plot = new Plot({
*     'xScale': 'time'
* });
* var scale = plot.xScale;
* // returns <Function>
*/
Object.defineProperty( Plot.prototype, 'xScale', {
	'configurable': false,
	'enumerable': true,
	'get': require( './props/x-scale/get.js' ),
	'set': require( './props/x-scale/set.js' )
});

/**
* Scale function for mapping values to a coordinate along the y-axis. When retrieved, the returned value is a scale function.
*
* @name yScale
* @memberof Plot.prototype
* @type {string}
* @throws {TypeError} must be a string primitive
* @default 'linear'
*
* @example
* var plot = new Plot();
* plot.yScale = 'linear';
*
* @example
* var plot = new Plot({
*     'yScale': 'linear'
* });
* var scale = plot.yScale;
* // returns <Function>
*/
Object.defineProperty( Plot.prototype, 'yScale', {
	'configurable': false,
	'enumerable': true,
	'get': require( './props/y-scale/get.js' ),
	'set': require( './props/y-scale/set.js' )
});

/**
* x-axis tick format. When retrieved, if the value is not `null`, the returned value is a formatting function.
*
* @name xTickFormat
* @memberof Plot.prototype
* @type {(string|null)}
* @throws {TypeError} must be a string primitive or null
* @default null
*
* @example
* var plot = new Plot();
* plot.xScale = 'time';
* plot.xTickFormat = '%H:%M';
*
* @example
* var plot = new Plot({
*     'xScale': 'time',
*     'xTickFormat': '%H:%M'
* });
* var fmt = plot.xTickFormat;
* // returns '%H:%M'
*/
Object.defineProperty( Plot.prototype, 'xTickFormat', {
	'configurable': false,
	'enumerable': true,
	'set': require( './props/x-tick-format/set.js' ),
	'get': require( './props/x-tick-format/get.js' )
});

/**
* y-axis tick format. If the value is not `null`, when retrieved, the returned value is a formatting function.
*
* @name yTickFormat
* @memberof Plot.prototype
* @type {(string|null)}
* @throws {TypeError} must be a string primitive or null
* @default null
*
* @example
* var plot = new Plot();
* plot.yTickFormat = '%%';
*
* @example
* var plot = new Plot({
*     'yTickFormat': '%%'
* });
* var fmt = plot.yTickFormat;
* // returns '%%'<commit_msg>Reformat comments<commit_after>/**
* @license Apache-2.0
*
* Copyright (c) 2018 The Stdlib Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

'use strict';

var EventEmitter = require( 'events' ).EventEmitter;
var logger = require( 'debug' );
var getKeys = require( 'object-keys' ).shim();
var setReadOnly = require( '@stdlib/utils/define-read-only-property' );
var isObject = require( '@stdlib/assert/is-plain-object' );
var copy = require( '@stdlib/utils/copy' );
var inherit = require( '@stdlib/utils/inherit' );
var mergeFcn = require( '@stdlib/utils/merge' ).factory;
var minstd = require( '@stdlib/random/base/minstd' );
var view = require( './view/view.js' );
var defaults = require( './defaults.js' );


// VARIABLES //

var debug = logger( 'plot:main' );
var PRIVATE_PROPS = [
	'_autoRender',
	'_autoView',
	'_colors',
	'_description',
	'_engine',
	'_height',
	'_isDefined',
	'_labels',
	'_lineOpacity',
	'_lineStyle',
	'_lineWidth',
	'_paddingBottom',
	'_paddingLeft',
	'_paddingRight',
	'_paddingTop',
	'_renderFormat',
	'_symbols',
	'_symbolsOpacity',
	'_symbolsSize',
	'_title',
	'_viewer',
	'_width',
	'_xAxisOrient',
	'_xData',
	'_xLabel',
	'_xMax',
	'_xMin',
	'_xNumTicks',
	'_xRug',
	'_xRugOpacity',
	'_xRugOrient',
	'_xRugSize',
	'_xScale',
	'_xTickFormat',
	'_yAxisOrient',
	'_yData',
	'_yLabel',
	'_yMax',
	'_yMin',
	'_yNumTicks',
	'_yRug',
	'_yRugOpacity',
	'_yRugOrient',
	'_yRugSize',
	'_yScale',
	'_yTickFormat'
];


// FUNCTIONS //

var merge = mergeFcn({
	'extend': false
});


// MAIN //

/**
* Plot constructor.
*
* @constructor
* @param {Array} [x] - x-values
* @param {Array} [y] - y-values
* @param {Options} [options] - constructor options
* @param {boolean} [options.autoRender=true] - indicates whether to re-render on a change event
* @param {boolean} [options.autoView=false] - indicates whether to generate an updated view on a render event
* @param {(string|StringArray)} [options.colors='category10'] - data colors
* @param {string} [options.description=''] - plot description
* @param {string} [options.engine='svg'] - plot engine
* @param {PositiveNumber} [options.height=400] - plot height
* @param {Function} [options.isDefined] - accessor indicating whether a datum is defined
* @param {(StringArray|EmptyArray)} [options.labels] - data labels
* @param {(number|NumberArray)} [options.lineOpacity=0.9] - data line opacity
* @param {(string|StringArray)} [options.lineStyle='-'] - data line style(s)
* @param {(NonNegativeInteger|Array<NonNegativeInteger>)} [options.lineWidth=2] - data line width(s)
* @param {NonNegativeInteger} [options.paddingBottom=80] - bottom padding
* @param {NonNegativeInteger} [options.paddingLeft=90] - left padding
* @param {NonNegativeInteger} [options.paddingRight=20] - right padding
* @param {NonNegativeInteger} [options.paddingTop=80] - top padding
* @param {string} [options.renderFormat='vdom'] - plot render format
* @param {(string|StringArray)} [options.symbols='none'] - data symbols
* @param {(number|NumberArray)} [options.symbolsOpacity=0.9] - symbols opacity
* @param {(NonNegativeInteger|Array<NonNegativeInteger>)} [options.symbolsSize=6] - symbols size
* @param {string} [options.title=''] - plot title
* @param {string} [options.viewer='none'] - plot viewer
* @param {PositiveNumber} [options.width=400] - plot width
* @param {Array} [options.x=[]] - x-values
* @param {string} [options.xAxisOrient='bottom'] - x-axis orientation
* @param {string} [options.xLabel='x'] - x-axis label
* @param {(Date|FiniteNumber|null)} [options.xMax=null] - maximum value of x-axis domain
* @param {(Date|FiniteNumber|null)} [options.xMin=null] - minimum value of x-axis domain
* @param {(NonNegativeInteger|null)} [options.xNumTicks=5] - number of x-axis tick marks
* @param {(boolean|BooleanArray)} [options.xRug=false] - indicates whether to render a rug plot along the x-axis
* @param {(string|StringArray)} [options.xRugOrient='bottom'] - x-axis rug orientation
* @param {(number|NumberArray)} [options.xRugOpacity=0.1] - x-axis rug opacity
* @param {(NonNegativeInteger|Array<NonNegativeInteger>)} [options.xRugSize=6] - x-axis rug tick (tassel) size
* @param {string} [options.xScale='linear'] - x-axis scale
* @param {(string|null)} [options.xTickFormat=null] - x-axis tick format
* @param {Array} [options.y=[]] - y-values
* @param {string} [options.yAxisOrient='left'] - y-axis orientation
* @param {string} [options.yLabel='y'] - y-axis label
* @param {(FiniteNumber|null)} [options.yMax=null] - maximum value of y-axis domain
* @param {(FiniteNumber|null)} [options.yMin=null] - minimum value of y-axis domain
* @param {(NonNegativeInteger|null)} [options.yNumTicks=5] - number of y-axis tick marks
* @param {(boolean|BooleanArray)} [options.yRug=false] - indicates whether to render a rug plot along the y-axis
* @param {(string|StringArray)} [options.yRugOrient='left'] - y-axis rug orientation
* @param {(number|NumberArray)} [options.yRugOpacity=0.1] - y-axis rug opacity
* @param {(NonNegativeInteger|Array<NonNegativeInteger>)} [options.yRugSize=6] - y-axis rug tick (tassel) size
* @param {string} [options.yScale='linear'] - y-axis scale
* @param {(string|null)} [options.yTickFormat=null] - y-axis tick format
* @throws {TypeError} must provide valid options
* @returns {Plot} Plot instance
*
* @example
* var plot = new Plot();
*/
function Plot() {
	var options;
	var nargs;
	var keys;
	var self;
	var opts;
	var key;
	var i;

	nargs = arguments.length;
	if ( !(this instanceof Plot) ) {
		if ( nargs === 0 ) {
			return new Plot();
		}
		if ( nargs === 1 ) {
			return new Plot( arguments[0] );
		}
		if ( nargs === 2 ) {
			return new Plot( arguments[0], arguments[1] );
		}
		return new Plot( arguments[0], arguments[1], arguments[2] );
	}
	self = this;

	opts = defaults();
	if ( nargs === 0 ) {
		options = {};
	} else if ( nargs === 1 ) {
		options = arguments[ 0 ];
		if ( !isObject( options ) ) {
			throw new TypeError( 'invalid input argument. Options argument must be an `object`. Value: `' + options + '`.' );
		}
	} else if ( nargs === 2 ) {
		options = {
			'x': arguments[ 0 ],
			'y': arguments[ 1 ]
		};
	} else if ( nargs > 2 ) {
		if ( !isObject( arguments[2] ) ) {
			throw new TypeError( 'invalid input argument. Options argument must be an `object`. Value: `' + arguments[2] + '`.' );
		}
		options = copy( arguments[2] ); // avoid mutation
		options.x = arguments[ 0 ];
		options.y = arguments[ 1 ];
	}
	opts = merge( opts, options );

	debug( 'Creating an instance with the following configuration: %s.', JSON.stringify( opts ) );
	EventEmitter.call( this );

	for ( i = 0; i < PRIVATE_PROPS.length; i++ ) {
		Object.defineProperty( this, PRIVATE_PROPS[i], {
			'configurable': false,
			'enumerable': false,
			'writable': true,
			'value': null
		});
	}
	// Set a clipping path id:
	Object.defineProperty( this, '_clipPathId', {
		'configurable': false,
		'enumerable': false,
		'writable': false,
		'value': minstd().toString() // TODO: uuid
	});

	// Initialize an internal cache for renderers...
	Object.defineProperty( this, '$', {
		'configurable': false,
		'enumerable': false,
		'writable': false,
		'value': {}
	});
	Object.defineProperty( this.$, 'svg', {
		'configurable': false,
		'enumerable': false,
		'writable': false,
		'value': {}
	});

	// Set options...
	keys = getKeys( opts );
	for ( i = 0; i < keys.length; i++ ) {
		key = keys[ i ];
		this[ key ] = opts[ key ];
	}

	// Add event listeners:
	this.on( 'change', onChange );
	this.on( 'render', onRender );

	return this;

	/**
	* Callback invoked upon receiving a change event.
	*
	* @private
	*/
	function onChange() {
		/* eslint-disable no-underscore-dangle */
		debug( 'Received a change event.' );
		if ( self._autoRender ) {
			self.render();
		}
	}

	/**
	* Callback invoked upon receiving a render event.
	*
	* @private
	* @param {*} plot - rendered plot
	*/
	function onRender( plot ) {
		/* eslint-disable no-underscore-dangle */
		debug( 'Received a render event.' );
		if ( self._autoView ) {
			debug( 'Viewer: %s.', self._viewer );
			debug( 'Generating view...' );
			view( self, self._viewer, plot );
		}
	}
}

/*
* Inherit from the `EventEmitter` prototype.
*/
inherit( Plot, EventEmitter );

/**
* `x` values.
*
* @name x
* @memberof Plot.prototype
* @type {Array}
* @throws {TypeError} must be an array
* @default []
*
* @example
* var plot = new Plot();
* plot.x = [ [ 1417563950959, 1417563952959 ] ];
*
* @example
* var plot = new Plot({
*     'x': [ [ 1417563950959, 1417563952959 ] ]
* });
* var x = plot.x;
* // returns [ [ 1417563950959, 1417563952959 ] ]
*/
Object.defineProperty( Plot.prototype, 'x', {
	'configurable': false,
	'enumerable': true,
	'set': require( './props/x/set.js' ),
	'get': require( './props/x/get.js' )
});

/**
* `y` values.
*
* @name y
* @memberof Plot.prototype
* @type {Array}
* @throws {TypeError} must be an array
* @default []
*
* @example
* var plot = new Plot();
* plot.x = [ [ 1417563950959, 1417563952959 ] ];
* plot.y = [ [ 0.25, 0.23 ] ];
*
* @example
* var plot = new Plot({
*     'x': [ [ 1417563950959, 1417563952959 ] ],
*     'y': [ [ 0.25, 0.23 ] ]
* });
* var y = plot.y;
* // returns [ [ 0.25, 0.23 ] ]
*/
Object.defineProperty( Plot.prototype, 'y', {
	'configurable': false,
	'enumerable': true,
	'set': require( './props/y/set.js' ),
	'get': require( './props/y/get.js' )
});

/**
* Data labels.
*
* @name labels
* @memberof Plot.prototype
* @type {(StringArray|EmptyArray)}
* @throws {TypeError} must be either an array of strings or an empty array
* @default []
*
* @example
* var plot = new Plot();
* plot.labels = [ 'beep', 'boop' ];
*
* @example
* var plot = new Plot({
*     'labels': [ 'beep', 'boop' ]
* });
* var labels = plot.labels;
* // returns [ 'beep', 'boop' ]
*/
Object.defineProperty( Plot.prototype, 'labels', {
	'configurable': false,
	'enumerable': true,
	'set': require( './props/labels/set.js' ),
	'get': require( './props/labels/get.js' )
});

/**
* Accessor which defines whether a datum is defined.
*
* ## Notes
*
* -   This accessor is used to define how missing values are encoded.
* -   The default behavior is to ignore values which are `NaN`.
*
* @name isDefined
* @memberof Plot.prototype
* @type {Function}
* @param {*} d - datum
* @param {integer} i - index
* @throws {TypeError} must be a function
*
* @example
* var plot = new Plot();
* plot.isDefined = function isDefined( d ) {
*     // Check for `NaN`:
*     return ( d === d );
* }
*
* @example
* function isDefined( d ) {
*     // Check for `NaN`:
*     return ( d === d );
* }
* var plot = new Plot({
*     'isDefined': isDefined
* });
* var fcn = plot.isDefined;
* // returns <Function>
*/
Object.defineProperty( Plot.prototype, 'isDefined', {
	'configurable': false,
	'enumerable': true,
	'set': require( './props/is-defined/set.js' ),
	'get': require( './props/is-defined/get.js' )
});

/**
* Data colors. When retrieved, the returned value is always an `array`.
*
* @name colors
* @memberof Plot.prototype
* @type {(string|StringArray)}
* @throws {TypeError} must be either a string or an array of strings
* @default 'category10'
*
* @example
* var plot = new Plot();
* plot.colors = 'category20';
*
* @example
* var plot = new Plot({
*     'colors': 'category20'
* });
* var colors = plot.colors;
* // returns [...]
*/
Object.defineProperty( Plot.prototype, 'colors', {
	'configurable': false,
	'enumerable': true,
	'set': require( './props/colors/set.js' ),
	'get': require( './props/colors/get.js' )
});

/**
* Data line style(s).
*
* ## Notes
*
* -   When retrieved, the returned value is always an `array`.
*
* @name lineStyle
* @memberof Plot.prototype
* @type {(string|StringArray)}
* @throws {TypeError} must be a string or string array
* @throws {Error} must be a supported line style
* @default '-'
*
* @example
* var plot = new Plot();
* plot.lineStyle = [ '-', 'none' ];
*
* @example
* var plot = new Plot({
*     'lineStyle': 'none'
* });
* var lineStyle = plot.lineStyle;
* // returns [ 'none' ]
*/
Object.defineProperty( Plot.prototype, 'lineStyle', {
	'configurable': false,
	'enumerable': true,
	'set': require( './props/line-style/set.js' ),
	'get': require( './props/line-style/get.js' )
});

/**
* Data line opacity.
*
* ## Notes
*
* -   When retrieved, the returned value is always an `array`.
*
* @name lineOpacity
* @memberof Plot.prototype
* @type {(number|NumberArray)}
* @throws {TypeError} must be a number or number array
* @throws {RangeError} must be a number on the interval `[0,1]`
* @default '0.9'
*
* @example
* var plot = new Plot();
* plot.lineOpacity = [ 1.0, 0.5 ];
*
* @example
* var plot = new Plot({
*     'lineOpacity': 0.5
* });
* var opacity = plot.lineOpacity;
* // returns [ 0.5 ]
*/
Object.defineProperty( Plot.prototype, 'lineOpacity', {
	'configurable': false,
	'enumerable': true,
	'set': require( './props/line-opacity/set.js' ),
	'get': require( './props/line-opacity/get.js' )
});

/**
* Data line width.
*
* ## Notes
*
* -   When retrieved, the returned value is always an `array`.
*
* @name lineWidth
* @memberof Plot.prototype
* @type {(NonNegativeInteger|NonNegativeIntegerArray)}
* @throws {TypeError} must be a nonnegative integer or nonnegative integer array
* @default 2
*
* @example
* var plot = new Plot();
* plot.lineWidth = 1;
*
* @example
* var plot = new Plot({
*     'lineWidth': [ 1, 3 ]
* });
* var width = plot.lineWidth;
* // returns [ 1, 3 ]
*/
Object.defineProperty( Plot.prototype, 'lineWidth', {
	'configurable': false,
	'enumerable': true,
	'set': require( './props/line-width/set.js' ),
	'get': require( './props/line-width/get.js' )
});

/**
* Data symbols. When retrieved, the returned value is always an `array`.
*
* @name symbols
* @memberof Plot.prototype
* @type {(string|StringArray)}
* @throws {TypeError} must be a string or string array
* @throws {Error} must be a supported symbol
* @default 'none'
*
* @example
* var plot = new Plot();
* plot.symbols = [ 'open-circle', 'closed-circle' ];
*
* @example
* var plot = new Plot({
*     'symbols': 'closed-circle'
* });
* var symbols = plot.symbols;
* // returns [ 'closed-circle' ]
*/
Object.defineProperty( Plot.prototype, 'symbols', {
	'configurable': false,
	'enumerable': true,
	'set': require( './props/symbols/set.js' ),
	'get': require( './props/symbols/get.js' )
});

/**
* Symbols size. When retrieved, the returned value is always an `array`.
*
* @name symbolsSize
* @memberof Plot.prototype
* @type {(NonNegativeInteger|NonNegativeIntegerArray)}
* @throws {TypeError} must be a nonnegative integer or nonnegative integer array
* @default 6
*
* @example
* var plot = new Plot();
* plot.symbolsSize = 4;
*
* @example
* var plot = new Plot({
*     'symbolsSize': [ 4, 6 ]
* });
* var size = plot.symbolsSize;
* // returns [ 4, 6 ]
*/
Object.defineProperty( Plot.prototype, 'symbolsSize', {
	'configurable': false,
	'enumerable': true,
	'set': require( './props/symbols-size/set.js' ),
	'get': require( './props/symbols-size/get.js' )
});

/**
* Symbols opacity. When retrieved, the returned value is always an `array`.
*
* @name symbolsOpacity
* @memberof Plot.prototype
* @type {(number|NumberArray)}
* @throws {TypeError} must be a number or number array
* @throws {RangeError} must be a number on the interval `[0,1]`
* @default 0.9
*
* @example
* var plot = new Plot();
* plot.symbolsOpacity = [ 0.2, 0.5 ];
*
* @example
* var plot = new Plot({
*     'symbolsOpacity': 0.2
* });
* var opacity = plot.symbolsOpacity;
* // returns 0.2
*/
Object.defineProperty( Plot.prototype, 'symbolsOpacity', {
	'configurable': false,
	'enumerable': true,
	'set': require( './props/symbols-opacity/set.js' ),
	'get': require( './props/symbols-opacity/get.js' )
});

/**
* Plot width.
*
* @name width
* @memberof Plot.prototype
* @type {PositiveNumber}
* @throws {TypeError} must be a positive number
* @default 400 (px)
*
* @example
* var plot = new Plot();
* plot.width = 100;
*
* @example
* var plot = new Plot({
*     'width': 480
* });
* var width = plot.width;
* // returns 480
*/
Object.defineProperty( Plot.prototype, 'width', {
	'configurable': false,
	'enumerable': true,
	'set': require( './props/width/set.js' ),
	'get': require( './props/width/get.js' )
});

/**
* Plot height.
*
* @name height
* @memberof Plot.prototype
* @type {PositiveNumber}
* @throws {TypeError} must be a positive number
* @default 400 (px)
*
* @example
* var plot = new Plot();
* plot.height = 100;
*
* @example
* var plot = new Plot({
*     'height': 360
* });
* var height = plot.height;
* // returns 360
*/
Object.defineProperty( Plot.prototype, 'height', {
	'configurable': false,
	'enumerable': true,
	'set': require( './props/height/set.js' ),
	'get': require( './props/height/get.js' )
});

/**
* Plot left padding.
*
* ## Notes
*
* -   Typically used to create space for a left-oriented y-axis.
*
* @name paddingLeft
* @memberof Plot.prototype
* @type {NonNegativeInteger}
* @throws {TypeError} must be a nonnegative integer
* @default 90 (px)
*
* @example
* var plot = new Plot();
* plot.paddingLeft = 100;
*
* @example
* var plot = new Plot({
*     'paddingLeft': 100
* });
* var padding = plot.paddingLeft;
* // returns 100
*/
Object.defineProperty( Plot.prototype, 'paddingLeft', {
	'configurable': false,
	'enumerable': true,
	'set': require( './props/padding-left/set.js' ),
	'get': require( './props/padding-left/get.js' )
});

/**
* Plot right padding.
*
* ## Notes
*
* -   Typically used to create space for a right-oriented y-axis.
*
* @name paddingRight
* @memberof Plot.prototype
* @type {NonNegativeInteger}
* @throws {TypeError} must be a nonnegative integer
* @default 20 (px)
*
* @example
* var plot = new Plot();
* plot.paddingRight = 100;
*
* @example
* var plot = new Plot({
*     'paddingRight': 100
* });
* var padding = plot.paddingRight;
* // returns 100
*/
Object.defineProperty( Plot.prototype, 'paddingRight', {
	'configurable': false,
	'enumerable': true,
	'set': require( './props/padding-right/set.js' ),
	'get': require( './props/padding-right/get.js' )
});

/**
* Plot top padding.
*
* ## Notes
*
* -   Typically used to create space for a title or top-oriented x-axis.
*
* @name paddingTop
* @memberof Plot.prototype
* @type {NonNegativeInteger}
* @throws {TypeError} must be a nonnegative integer
* @default 80 (px)
*
* @example
* var plot = new Plot();
* plot.paddingTop = 100;
*
* @example
* var plot = new Plot({
*     'paddingTop': 100
* });
* var padding = plot.paddingTop;
* // returns 100
*/
Object.defineProperty( Plot.prototype, 'paddingTop', {
	'configurable': false,
	'enumerable': true,
	'set': require( './props/padding-top/set.js' ),
	'get': require( './props/padding-top/get.js' )
});

/**
* Plot bottom padding.
*
* ## Notes
*
* -   Typically used to create space for a bottom-oriented y-axis.
*
* @name paddingBottom
* @memberof Plot.prototype
* @type {NonNegativeInteger}
* @throws {TypeError} must be a nonnegative integer
* @default 80 (px)
*
* @example
* var plot = new Plot();
* plot.paddingBottom = 100;
*
* @example
* var plot = new Plot({
*     'paddingBottom': 100
* });
* var padding = plot.paddingBottom;
* // returns 100
*/
Object.defineProperty( Plot.prototype, 'paddingBottom', {
	'configurable': false,
	'enumerable': true,
	'set': require( './props/padding-bottom/set.js' ),
	'get': require( './props/padding-bottom/get.js' )
});

/**
* Minimum value of the x-axis domain.
*
* ## Notes
*
* -   When retrieved, if the value has been set to `null`, the returned value is computed from the `x` data.
*
* @name xMin
* @memberof Plot.prototype
* @type {(FiniteNumber|null)}
* @throws {TypeError} must be a finite number primitive or null
* @default null
*
* @example
* var plot = new Plot();
* plot.xMin = -1.0;
*
* @example
* var plot = new Plot({
*     'xMin': -10.0
* });
* var xmin = plot.xMin;
* // returns -10.0
*/
Object.defineProperty( Plot.prototype, 'xMin', {
	'configurable': false,
	'enumerable': true,
	'set': require( './props/x-min/set.js' ),
	'get': require( './props/x-min/get.js' )
});

/**
* Maximum value of the x-axis domain.
*
* ## Notes
*
* -   When retrieved, if the value has been set to `null`, the returned value is computed from the `x` data.
*
* @name xMax
* @memberof Plot.prototype
* @type {(FiniteNumber|null)}
* @throws {TypeError} must be a finite number primitive or null
* @default null
*
* @example
* var plot = new Plot();
* plot.xMax = 100.0;
*
* @example
* var plot = new Plot({
*     'xMax': 10.0
* });
* var xmax = plot.xMax;
* // returns 10.0
*/
Object.defineProperty( Plot.prototype, 'xMax', {
	'configurable': false,
	'enumerable': true,
	'set': require( './props/x-max/set.js' ),
	'get': require( './props/x-max/get.js' )
});

/**
* Minimum value of the y-axis domain.
*
* ## Notes
*
* -   When retrieved, if the value has been set to `null`, the returned value is computed from the `y` data.
*
* @name yMin
* @memberof Plot.prototype
* @type {(FiniteNumber|null)}
* @throws {TypeError} must be a finite number primitive or null
* @default null
*
* @example
* var plot = new Plot();
* plot.yMin = -100.0;
*
* @example
* var plot = new Plot({
*     'yMin': 3.14
* });
* var ymin = plot.yMin;
* // returns 3.14
*/
Object.defineProperty( Plot.prototype, 'yMin', {
	'configurable': false,
	'enumerable': true,
	'set': require( './props/y-min/set.js' ),
	'get': require( './props/y-min/get.js' )
});

/**
* Maximum value of the y-axis domain.
*
* ## Notes
*
* -   When retrieved, if the value has been set to `null`, the returned value is computed from the `y` data.
*
* @name yMax
* @memberof Plot.prototype
* @type {(FiniteNumber|null)}
* @throws {TypeError} must be a finite number primitive or null
* @default null
*
* @example
* var plot = new Plot();
* plot.yMax = 100.0;
*
* @example
* var plot = new Plot({
*     'yMax': 31.4
* });
* var ymax = plot.yMax;
* // returns 31.4
*/
Object.defineProperty( Plot.prototype, 'yMax', {
	'configurable': false,
	'enumerable': true,
	'set': require( './props/y-max/set.js' ),
	'get': require( './props/y-max/get.js' )
});

/**
* Scale function for mapping values to a coordinate along the x-axis. When retrieved, the returned value is a scale function.
*
* @name xScale
* @memberof Plot.prototype
* @type {string}
* @throws {TypeError} must be a string primitive
* @default 'linear'
*
* @example
* var plot = new Plot();
* plot.xScale = 'time';
*
* @example
* var plot = new Plot({
*     'xScale': 'time'
* });
* var scale = plot.xScale;
* // returns <Function>
*/
Object.defineProperty( Plot.prototype, 'xScale', {
	'configurable': false,
	'enumerable': true,
	'get': require( './props/x-scale/get.js' ),
	'set': require( './props/x-scale/set.js' )
});

/**
* Scale function for mapping values to a coordinate along the y-axis. When retrieved, the returned value is a scale function.
*
* @name yScale
* @memberof Plot.prototype
* @type {string}
* @throws {TypeError} must be a string primitive
* @default 'linear'
*
* @example
* var plot = new Plot();
* plot.yScale = 'linear';
*
* @example
* var plot = new Plot({
*     'yScale': 'linear'
* });
* var scale = plot.yScale;
* // returns <Function>
*/
Object.defineProperty( Plot.prototype, 'yScale', {
	'configurable': false,
	'enumerable': true,
	'get': require( './props/y-scale/get.js' ),
	'set': require( './props/y-scale/set.js' )
});

/**
* x-axis tick format.
*
* ## Notes
*
* -   When retrieved, if the value is not `null`, the returned value is a formatting function.
*
* @name xTickFormat
* @memberof Plot.prototype
* @type {(string|null)}
* @throws {TypeError} must be a string primitive or null
* @default null
*
* @example
* var plot = new Plot();
* plot.xScale = 'time';
* plot.xTickFormat = '%H:%M';
*
* @example
* var plot = new Plot({
*     'xScale': 'time',
*     'xTickFormat': '%H:%M'
* });
* var fmt = plot.xTickFormat;
* // returns '%H:%M'
*/
Object.defineProperty( Plot.prototype, 'xTickFormat', {
	'configurable': false,
	'enumerable': true,
	'set': require( './props/x-tick-format/set.js' ),
	'get': require( './props/x-tick-format/get.js' )
});

/**
* y-axis tick format.
*
* ## Notes
*
* -   If the value is not `null`, when retrieved, the returned value is a formatting function.
*
* @name yTickFormat
* @memberof Plot.prototype
* @type {(string|null)}
* @throws {TypeError} must be a string primitive or null
* @default null
*
* @example
* var plot = new Plot();
* plot.yTickFormat = '%%';
*
* @example
* var plot = new Plot({
*     'yTickFormat': '%%'
* });
* var fmt = plot.yTickFormat;
* // returns '%%'
{'fraction_non_alphanumeric': 0.1814605162792565, 'fraction_numerical': 0.014412461359348027, 'mean_word_length': 3.8670379054318094, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6336948', 'n_tokens_mistral': 18085, 'n_tokens_neox': 17196, 'n_words': 4919}