Scientific axes

While displaying scientific plots, you might find yourselves fighting with units and unit scaling. jsGraph helps you with that:

  • Displaying scientific notation

  • Displaying engineering notation

  • Adding the SI prefix when scaling (mg, g, kg, …)

Let us consider the following example:

const years = [1980, 1981, 1982, 1983, 1984, 1985, 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012];
const coalConsumption = [0.020494449, 0.020919039, 0.021248864, 0.021850876, 0.02315959, 0.024146973, 0.024530887, 0.025317155, 0.026103415, 0.026055829, 0.026108312, 0.025206791, 0.024850082, 0.025047841, 0.025224058, 0.025698446, 0.026416749, 0.026247128, 0.02613963, 0.026560849, 0.027977463, 0.028029715, 0.02855675, 0.030803576, 0.033055718, 0.034708407, 0.036478632, 0.038019204, 0.038728538, 0.038927756, 0.041658958, 0.043534821, 0.043029446];

const g = new Graph('example-1');
g
    .resize(500, 300)
    .newSerie('coal_consumption')
    .setWaveform(Graph.newWaveform().setData(coalConsumption, years))
    .setLineColor('#A52B11')
    .setMarkers(true)
    .setMarkerStyle({ shape: 'circle', r: 4, fill: '#A52B11', stroke: 'white', strokeWidth: '2px' })
    .autoAxis();

g.getBottomAxis().setLabel('year');
g.getLeftAxis().setLabel('World coal consumption');
g.draw();

Although years are fairly easy to understand, there’s no unit in the y axis. What are we talking about ? Oranges ? Burgers over Bald Eagles ? Or kWh ? Or btu ? Of course you could include it directly in the label, but we can do better than that.

Setting axes units

Let’s start setting the unit of the axis:

// Setting the SI unit
g.getLeftAxis().setUnit('Wh').setUnitWrapper('[', ']');

Obviously, the data we’re dealing with is not in Wh, but it is given to us in some retarded unit, the btu, or british thermal unit. More specifically, in quadrillions of btus. (algthough we may wish for a coal-free world, we’re actually going into the opposite direction). So we must scale the data accordingly. First of all, let’s transform all of this into some normal SI unit, the Wh.

We could change the original data, but we could also make use of the waveform.setScale method:

// Setting the SI unit
w.setScale(
    ( 0.000293071 * 1000 )  // Conversion to Wh
    * 1e15                  // there are quadrilions of them
)

Ok, it’s not looking pretty, but at least everything is in SI units, which is good. Let us see how we can play around with the units.

Warning

If you change the scaling of a waveform after binding it to a serie, you should rebind it with serie.setWaveform( w ).

Enabling the scientific scaling

First up, enable the scientific scaling:

// Setting the SI unit
g.getLeftAxis().setScientific( true );

Alright, now we’re talking ! The axis now uses scientific units, and adds the exponent in the label.

Note

Scientific scaling allows jsGraph to try to optimize the unit display. If you want to keep complete control of the graph, you have access to the method setExponentialFactor, which scales the axis by 10^x but does not affect the label. You may use it in the following condition for example:

// Force GWh display
g.getLeftAxis()
    .setScientific( false )
    .setUnit('GWh')
    .setExponentialFactor( -9 ); // Need to remove 1 billion to the Wh unit

However, note that there is also a possibility to force the exponent factor with scientific scaling (read on to find out how).

Enabling the engineering scaling

Engineering scaling is a type of scientific scaling, but where the exponent is always a power of 3. This eliminates the weird 10 13 and replaces it by 10 12 and multiplies all labels by 10. That’s normally a lot more natural if you’re dealing when quantities, like time, mass, etc.

Forcing the exponent

When in scientific scale, force the exponent of the axis using axis.setScientificExponent( 3 ), for example, to display the axis in x1000 Wh.

Using unit decades

Instead of displaying 10^x in the scale, you may be interested in displaying a letter (e.g. n for nano, T for tera, etc…). Use the setUnitDecade together with setScientificScaling for that purpose:

g.getLeftAxis()
    .setScientific( true )
    .setUnitDecode( true );

See how now the data displayed is in TWh, instead of Wh x10 13 .

jsGraph will replace the unit scaling by the following letters when appropriate:

  • 10 -15 : f

  • 10 -12 : p

  • 10 -9 : n

  • 10 -6 : µ

  • 10 -3 : k

  • 10 3 : k

  • 10 6 : M

  • 10 9 : G

  • 10 12 : T

  • 10 15 : E

Log scale

We finish our discussion of the scientific axes by mentionning that you can ask the axis to display a logarithmic scale (only in base 10 for now). Use:

const g = new Graph('example-7');

let w = Graph.newWaveform()
    .setData(new Array(20)) // Use an empty array to define the length
    .rescaleX(-3, 0.5) // x = -3, -2.5, -2, etc...
    .math((y, x) => { return Math.exp(x) });

let s = g
    .resize(500, 300)
    .newSerie('log')
    .setWaveform(w)
    .setLineColor('#3f9169')
    .setMarkers(true)
    .setMarkerStyle({ shape: 'circle', r: 4, fill: '#3f9169', stroke: 'white', strokeWidth: '2px' })
    .autoAxis();

g.getLeftAxis().setLogScale(true);
g.draw();