Initial Thoughts
One solution is to specify the base parameter for each trace as 0 and for the negative bars use a negative base value if the value is 0.
const altbase=-1000/3;
const trace1 = {
x: xValue,
y: [FN],
name: `Model 1`,
text: `${FN} <br> FN`,
type: 'bar',
base: 0,
textposition: 'outside'
};
const trace2 = {
x: xValue,
y: [-TN],
name: 'Model 1',
text: `${TN} <br> TN`,
base: altbase,
type: 'bar',
textposition: 'outside'
};
It looks like -max_y_lim / 3 results in a good offset which is what altbase is used for.
You could also define altbase as a variable checking if TN==0:
var altbase = ((TN==0) ? -FP/3 : 0);
UPDATE1: or you can bypass the variable and put the if statement right into trace definition like base: ((TN==0) ? -FP/3 : 0),
UPDATE2: and a slightly more elegant equation for the offset would be:
var altbase = ((TN==0) ? -1.4/4*Math.max(FN,TN,TP,FP) : 0);
Final Update
After some thought it's probably best to always calculate altbase so that it's available to the other potential negative bar and then use an if statement for setting the base: where needed.
var altbase = -1.4/4*Math.max(FN,TN,TP,FP);
const trace1 = {
x: xValue,
y: [FN],
name: `Model 1`,
text: `${FN} <br> FN`,
type: 'bar',
base: 0,
textposition: 'outside'
};
const trace2 = {
x: xValue,
y: [-TN],
name: 'Model 1',
text: `${TN} <br> TN`,
base: ((TN==0) ? altbase : 0),
type: 'bar',
textposition: 'outside'
};
Here is the implementation in CodePen.
