Flourish chart layout
Create axes and plotting regions for data
How to install
npm install -s @flourish/chart-layout
Add objects to your template state representing the x and/or y and/or y2 axes, and optionally also the background area. For example:
export var state = {
x: {},
y: {},
y2: {},
chart_bg: {},
...
}
Import the corresponding settings into your template.yml
.
- X axis
- property: x
import: "@flourish/chart-layout/x"
- Y axis
- property: y
import: "@flourish/chart-layout/y"
- Y2 axis
- property: y2
import: "@flourish/chart-layout/y"
- Chart background
- property: chart_bg
import: "@flourish/chart-layout/background"
For typed templates you can also add overrides to show or hide settings based on the type of a data binding. For example:
- property: x
import: "@flourish/chart-layout/x"
overrides:
- tag: numeric
method: extend
show_if:
data.data.x.type: number
- tag: temporal
method: extend
show_if:
data.data.x.type: datetime
- tag: categorical
method: extend
show_if:
data.data.x.type: string
- tag: continuous
method: extend
show_if:
data.data.x.type: [number, datetime]
How to use
Initialise a chart-layout object for every chart you want to create. You need a container
SVG element (a node, a d3-selection or a CSS selector string) which you will add the chart to and an object containing the relevant state properties. For example
import createChartLayout from "@flourish/chart-layout";
var container = select(layout.getSection("primary")).select("svg");
var props = { x: state.x, y: state.y, y2: state.y2, background: state.chart_bg };
var chart_layout = createChartLayout(container, props);
This adds a number of SVG elements to the container
and returns an object, chart_layout
.
Properties of chart_layout
chart_layout.chart
A d3-selection of the route SVG element created by chart_element
.
chart_layout.container
A d3-selection of the container
specified at the time of creation.
chart_layout.data_background
A d3-selection of an area created within the chart_element
that is suitable for adding data to. Data elements placed within this container will appear below any visible gridlines.
chart_layout.data_foreground
A d3-selection of an area created within the chart_element
that is suitable for adding data to. Data elements placed within this container will appear above any visible gridlines.
The update
method of chart_layout
chart_layout.update([options])
Call this method to recalculate and redraw (with animation) the chart layout components based on the current set of stored values and state properties. Returns the chart_layout
instance.
Properties of optional options
object can be used to modify the update method's functionality. If skip_rendering
is true then distances, margins and ticks will be recalculated and any changes to the chart offset will be applied, but the chart components will not be re-rendered.
If a margins
object is supplied and any of its top
, right
, bottom
or left
properties are not undefined
then the corresponding margin will be fixed to that value. If you want to set a margin based off the calculated value, e.g. to increase or decrease the margin based on the default, you can pass in a function for any of these properties:
chart_layout.update({
margins: {
top: (calculated) => calculated + 32,
left: (calculated) => calculated + 32,
right: (calculated) => calculated + 32,
bottom: (calculated) => calculated + 32,
}
});
chart_layout.update({
margins: {
top: 32,
left: 32,
right: 32,
bottom: 32,
}
});
In some cases it's useful to add an inner margin to the chart layout. This is applied between the axes and the plot area, therefore keeping both axes fixed to the positions set by margins
. If an inner_margins
object is supplied and any of its top
, right
, bottom
or left
properties are not undefined
then the corresponding margin will be fixed to that value. They default to 0
.
chart_layout.update({
inner_margins: {
top: 10,
left: 10,
right: 10,
bottom: 10
}
});
chart_layout.update({
margins: {
top: 32,
left: 32,
right: 32,
bottom: 32
},
inner_margins: {
top: 10,
left: 10,
right: 10,
bottom: 10
}
});
The Data
methods of chart_layout
These three methods expect values
to be either an array or an instance of a Flourish enhanced array (see @flourish/enhanced-array). In the case of the former, an optional accessor
method can be included in order to, for example, extract a specific property from each object in an array of objects. The stored data is used to determine both the type of axis (numeric or ordinal) and its domain. If values
is an enhanced array then a numeric axis will be constructed for the relevant dimension if it is a numeric enhanced array and an ordinal scale will be constructed if it is a string enhanced array. If values
is a regular array then the type of the first element (after application of the accessor
function) will be used to determine whether the scale should be numeric or ordinal.
If values
is undefined
, an enhanced array will be returned that is either the original one passed in or one derived from the regular array passed in. When values is defined, the chart_layout
instance is returned so that methods can be chained.
chart_layout.xData([values, [accessor]])
Gets or sets the data associated with the horizontal axis.
chart_layout.yData([values, [accessor]])
Gets or sets the data associated with the primary (left) vertical axis.
chart_layout.y2Data([values, [accessor]])
Gets or sets the data associated with the secondary (right) vertical axis.
The Scale
methods of chart_layout
These three methods get d3-scales suitable for plotting data. Because this module uses SVG transforms then, in general by default, the scale will be useful for plotting data only within the chart_layout.chart
container, and particularly the chart_layout.data_background
or chart_layout.data_foreground
containers. However, if the options
object is present and has a global
property that is truthy, the scale is suitable for use outside the chart_layout.chart
object (and, generally, not inside it), anywhere that has the same calculated transform as chart_layout.container
. The domain_only
property of options
specifies that a suitable range for the scale should not be calculated. This can be useful if you want to extract the domain for one axis before you specify the data for the other.
chart_layout.xScale([options])
Gets a scale function for calculating x-coordinates.
chart_layout.yScale([options])
Gets a scale function for calculating primary y-coordinates.
chart_layout.y2Scale([options])
Gets a scale function for calculating secondary y-coordinates.
In addition to the three *Scale
methods and three *Data
methods described above, the chart_layout
instance also provides methods for returning the calculated minimum distances between data points on a given axis. This can be useful in the construction of bar charts, for example.
chart_layout.xMinStep()
Returns the minimum screen-coordinate distance between xData
points.
chart_layout.yMinStep()
Returns the minimum screen-coordinate distance between yData
points.
chart_layout.y2MinStep()
Returns the minimum screen-coordinate distance between y2Data
points.
Dimensional and margin functions and properties of chart_layout
chart_layout.height([value])
If value
is specified, sets the total height of the chart_layout
area and returns the chart_layout
instance. If value
is null, the height of the bounding rectangle of chart_layout.svg
is used (if the plotAspect
hasn't been set). If value
is undefined
returns the calculated total height of the chart_layout
area. Calling the plotAspect
method with a value will lead to a recalculation of the height.
chart_layout.plotAspect([value])
If value
is specified, sets the aspect ratio of the plot area and returns the chart_layout
instance. If value
is null, the plotAspect
is unset and the aspect is determined implicitly from the width
, height
and margins
. If value
is undefined
returns the calculated or previously set plot aspect ratio. Calling the height
method with a value will lead to a recalculation of the plot aspect.
chart_layout.width([value])
If value
is specified, sets the total width of the chart_layout
area and returns the chart_layout
instance. If value
is any falsy value other than undefined
, the width of the bounding rectangle of chart_layout.container
is used. If value
is undefined
returns the calculated total width of the chart_layout
area.
chart_layout.margins()
Returns an object containing the top, right, bottom and left margins as used the last time update
was called. These can also be read individually as properties of the method, ie chart_layout.margins.top
, chart_layout.margins.right
, chart_layout.margins.bottom
and chart_layout.margins.left
.
chart_layout.plot_height
Read-only plot height of the chart_layout
area.
chart_layout.plot_width
Read-only plot width of the chart_layout
area.
chart_layout.x_left
Read-only on-screen x-coordinate for the left end of the x axis.
chart_layout.x_right
Read-only on-screen x-coordinate for the right end of the x axis.
chart_layout.y_bottom
Read-only on-screen y-coordinate for the bottom end of the y (and y2) axis.
chart_layout.y_top
Read-only on-screen y-coordinate for the top end of the y (and y2) axis.
The Ticks
methods of chart_layout
chart_layout.xTicks()
Returns a frozen array of frozen objects, where each object includes properties of a single tick mark/label pair that was drawn on the x axis the last time update
was called.
chart_layout.yTicks()
Returns a frozen array of frozen objects, where each object includes properties of a single tick mark/label pair that was drawn on the y axis the last time update
was called.
chart_layout.y2Ticks()
Returns a frozen array of frozen objects, where each object includes properties of a single tick mark/label pair that was drawn on the y2 axis the last time update
was called.
chart_layout.xTicks.autoLabelSpace([value, [unit]])
chart_layout.yTicks.autoLabelSpace([value, [unit]])
chart_layout.y2Ticks.autoLabelSpace([value, [unit]])
All three *Ticks
methods outlined above have a sub-method that can be used to define how the maximum space for tick labels is calculated when the Flourish-user specifies the "auto" option for the relevant tick_label_space_mode
property. These methods recognise up to two parameters. value
specifies the magnitude of the margin in the given unit
. Recognised units are "px", "rem" and "fraction". In the case of "fraction", this refers to the height (for the x method) or width of the chart-layout instance. If only a value
is specified when calling one of these methods, the unit
is assumed to be "px". The instance
is returned in either case. If value
is not specified when calling one of these functions then an object is returned that includes the current choice of unit
and the calculated values for all three options based on the currently specified value
and unit
combination.
The space being defined is a height for the x axis and a width for the y and y2 axes. Labels that are too long for the defined space may be automatically shorted (with trailing characters replaced by a single "…" character). However, if the labels are oriented at right angles to the relevant spatial dimension, no shortening will occur.
The Title
methods of chart_layout
chart_layout.xTitle()
Returns the computed title text for the x axis.
chart_layout.yTitle()
Returns the computed title text for the y axis.
chart_layout.y2Title()
Returns the computed title text for the y2 axis.
Other methods of chart_layout
All the methods below act like both getters and setters. When a value
is specified the return value is always the chart_layout
instance to allow for method chaining. When a value is not specified, the return value is the currently saved value(s) associated with that property.
chart_layout.animationDuration([value])
If value
is specified, sets the duration of animations (in milliseconds) that take place when chart_layout.update
is called.
chart_layout.clip([value])
If value
is specified, sets whether (truthy) or not (falsy) the data is clipped to the bounds of the axes.
chart_layout.debug([value])
Sets whether (if value
is truthy) or not to draw a bounding rectangle around the chart_layout
container. This can be useful for debugging layout issues. The default is false
.
chart_layout.debugColor([value])
Sets the color for the bounding rectangle discussed in chart_layout.debug
. Defaults to red.
chart_layout.identifier([value])
If value
is specified, sets the charts identifier to that value. This is used to make an id for clipping purposes so should not be used on more than one chart_layout
instance on a page and should match the rules for HTML id attributes. If a value has never been passed to this method then a value that should be unique is used. It takes the form of the string "fl-chart-layout-" with a number appended.
chart_layout.offsetTop([value])
If value
is specified, sets the vertical transform applied to the whole chart_layout
instance (defaults to 0).
chart_layout.offsetLeft([value])
If value
is specified, sets the horizontal transform applied to the whole chart_layout
instance (defaults to 0).
chart_layout.xAutoTicks([value])
If value
is specified, sets the array to be used or function to be called when the user sets the x-tick mode to “Auto”. null
can also be passed, in which case the default function will be restored. This method has no effect when the x-axis is categorical.
chart_layout.xAutoTitle([value])
If value
is specified, sets the title text to be used for the x axis to value
when the Flourish user choses auto
for the title_mode
.
chart_layout.xDatetimeParse([func])
If func
is specified, sets the parsing function to be applied when the Flourish user inputs dates in string format in the settings for the x axis. Currently this means the min and max for the date range and the values of custom ticks.
chart_layout.xFlipAxis([value])
If value
is specified, sets whether the x axis should be flipped (after converting value
to a Boolean) so it runs from right to left rather than left to right.
chart_layout.xFormat([func])
If func
is specified, sets the formatting function to be applied to the tick formats on the x axis. The func
function is called for every tick on the axis on update
with the ticks own value as the only argument. The value returned is then used as the printed tick label. If chart_layout.xFormat
is never called with a func
or func
is falsy (but not undefined) the default formatting function, function(value) { return "" + value; }
, is used.
chart_layout.xHide([value])
If value
is specified then sets whether or not the x axis should be hidden. By default this means the tick marks, labels, axis title and gridlines will not be drawn and no space will be left for them. The xScale
and xTicks
methods will still function as if the axis was visible (assuming it hasn't been switched off through settings). If value
is an object with a keep_gridlines
property that is truthy the tick marks, labels and axis title will not be drawn but gridlines will be (assuming they aren't switched off through settings).
chart_layout.xNumberParse([func])
If func
is specified, sets the parsing function to be applied when the Flourish user inputs numbers in string format in the settings for the x axis. Currently this means the values of custom ticks.
chart_layout.xPadding([object])
If object
is specified, sets the current left
, right
and unit
properties for the x-axis padding. Any of these properties may be omitted from object
, in which case their value remains unchanged. left
and right
should be numbers (default: 0). unit
should be a string, either “px” or “steps” (default “px”). A value of “px” means the left
and right
values are specified in pixels, a value of “steps” means the left
and right
values are specified as a multiple of the minimum on-screen separation (AKA step-size) between the xData
points. The padding setting is ignored for categorical scales and also for logarithmic numeric scales if the unit
isn't “px”.
chart_layout.xZeroAxis([value])
Specifies the behaviour when the x axis zero_axis
settings is set to auto
. In this situation, if value
is specified and is truthy then the x axis will include 0 if the data is numeric and the axis linear, regardless of the xData
values. Can be overriden by user-set min
and max
values.
chart_layout.yAutoTicks([value])
If value
is specified, sets the array to be used or function to be called when the user sets the y-tick mode to “Auto”. null
can also be passed, in which case the default function will be restored. This method has no effect when the y-axis is categorical.
chart_layout.yAutoTitle([value])
If value
is specified, sets the title text to be used for the y axis to value
when the Flourish user choses auto
for the title_mode
.
chart_layout.yDatetimeParse([func])
If func
is specified, sets the parsing function to be applied when the Flourish user inputs dates in string format in the settings for the y axis. Currently this means the min and max for the date range and the values of custom ticks.
chart_layout.yFlipAxis([value])
If value
is specified, sets whether the y axis should be flipped (after converting value
to a Boolean) so it runs from top to bottom rather than bottom to top.
chart_layout.yFormat([func])
If func
is specified, sets the formatting function to be applied to the tick formats on the primary y axis. The func
function is called for every tick on the axis on update
with the ticks own value as the only argument. The value returned is then used as the printed tick label. If chart_layout.yFormat
is never called with a func
or func
is falsy (but not undefined) the default formatting function, function(value) { return "" + value; }
, is used.
chart_layout.yHide([value])
If value
is specified then sets whether or not the y axis should be hidden. By default this means the tick marks, labels, axis title and gridlines will not be drawn and no space will be left for them. The yScale
and yTicks
methods will still function as if the axis was visible (assuming it hasn't been switched off through settings). If value
is an object with a keep_gridlines
property that is truthy the tick marks, labels and axis title will not be drawn but gridlines will be (assuming they aren't switched off through settings).
chart_layout.yNumberParse([func])
If func
is specified, sets the parsing function to be applied when the Flourish user inputs numbers in string format in the settings for the y axis. Currently this means the values of custom ticks.
chart_layout.yPadding([object])
If object
is specified, sets the current bottom
, top
and unit
properties for the y-axis padding. Any of these properties may be omitted from object
, in which case their value remains unchanged. bottom
and top
should be numbers (default: 0). unit
should be a string, either “px” or “steps” (default “px”). A value of “px” means the bottom
and top
values are specified in pixels, a value of “steps” means the bottom
and top
values are specified as a multiple of the minimum on-screen separation (AKA step-size) between the yData
points. The padding setting is ignored for categorical scales and also for logarithmic numeric scales if the unit
isn't “px”.
chart_layout.yZeroAxis([value])
Specifies the behaviour when the y axis zero_axis
settings is set to auto
. In this situation, if value
is specified and is truthy then the y axis will include 0 if the data is numeric and the axis linear, regardless of the yData
values. Can be overriden by user-set min
and max
values.
chart_layout.y2AutoTicks([value])
If value
is specified, sets the array to be used or function to be called when the user sets the y2-tick mode to “Auto”. null
can also be passed, in which case the default function will be restored. This method has no effect when the y2-axis is categorical.
chart_layout.y2AutoTitle([value])
If value
is specified, sets the title text to be used for the y2 axis to value
when the Flourish user choses auto
for the title_mode
.
chart_layout.y2DatetimeParse([func])
If func
is specified, sets the parsing function to be applied when the Flourish user inputs dates in string format in the settings for the y2 axis. Currently this means the min and max for the date range and the values of custom ticks.
chart_layout.yF2lipAxis([value])
If value
is specified, sets whether the y2 axis should be flipped (after converting value
to a Boolean) so it runs from top to bottom rather than bottom to top.
chart_layout.y2Format([func])
If func
is specified, sets the formatting function to be applied to the tick formats on the secondary y axis. The func
function is called for every tick on the axis on update
with the ticks own value as the only argument. The value returned is then used as the printed tick label. If chart_layout.y2Format
is never called with a func
or func
is falsy (but not undefined) the default formatting function, function(value) { return "" + value; }
, is used.
chart_layout.y2Hide([value])
If value
is specified then sets whether or not the y2 axis should be hidden. By default this means the tick marks, labels, axis title and gridlines will not be drawn and no space will be left for them. The y2Scale
and y2Ticks
methods will still function as if the axis was visible (assuming it hasn't been switched off through settings). If value
is an object with a keep_gridlines
property that is truthy the tick marks, labels and axis title will not be drawn but gridlines will be (assuming they aren't switched off through settings). Unlike for the xHide
and yHide
methods above, the default value for this method is true
: you must explicitly turn the y2 axis on.
chart_layout.y2NumberParse([func])
If func
is specified, sets the parsing function to be applied when the Flourish user inputs numbers in string format in the settings for the y2 axis. Currently this means the values of custom ticks.
chart_layout.yPadding([object])
If object
is specified, sets the current bottom
, top
and unit
properties for the y2-axis padding. Any of these properties may be omitted from object
, in which case their value remains unchanged. bottom
and top
should be numbers (default: 0). unit
should be a string, either “px” or “steps” (default “px”). A value of “px” means the bottom
and top
values are specified in pixels, a value of “steps” means the bottom
and top
values are specified as a multiple of the minimum on-screen separation (AKA step-size) between the y2Data
points. The padding setting is ignored for categorical scales and also for logarithmic numeric scales if the unit
isn't “px”.
chart_layout.y2ZeroAxis([value])
Specifies the behaviour when the y axis zero_axis
settings is set to auto
. In this situation, if value
is specified and is truthy then the y2 axis will include 0 if the data is numeric and the axis linear, regardless of the y2Data
values. Can be overriden by user-set min
and max
values.