import * as React from 'react';
import _ from 'lodash';
import { toConditionalPrecision } from 'shared/lib/NumberUtils';
import numeral from 'numeral';
export function toPrecision(
value: number,
precision: number,
threshold: number
) {
// round to precision significant figures
// with threshold being the upper bound on the numbers that are
// rewritten in exponential notation
if (0.000001 <= value && value < threshold)
return value.toExponential(precision);
let ret = value.toPrecision(precision);
//if (ret.indexOf(".")!==-1)
// ret = ret.replace(/\.?0+$/,'');
return ret;
}
export function toFixedWithoutTrailingZeros(
value: number,
digits: number
): string {
let fixed = value.toFixed(digits);
let zeros = '';
for (let i = 0; i < digits; i++) {
zeros += '0';
}
return numeral(value).format(`0[.][${zeros}]`);
}
/**
* Works the same as the default toFixed() function when the result string is not expected to be a zero value
* such as 0.0, 0.00, 0.000, etc.
*
* If the default toFixed() function returns a zero value, then converts it to an inequality such as
* <0.1, <0.01, <0.001, etc.
*/
export function toFixedWithThreshold(value: number, digits: number): string {
let fixed = value.toFixed(digits);
// if we end up with 0.0...0, returns <0.0...1 instead
if (value !== 0 && parseFloat(fixed) === 0) {
const floatingZeros = digits > 1 ? _.fill(Array(digits - 1), '0') : [];
// in case the value is negative, direction of the inequality changes
// (because, for example, 0.02 < 0.1 but, -0.02 > -0.1)
// we need to add the minus sign as well...
const prefix = value > 0 ? '<' : '>-';
fixed = `${prefix}0.${floatingZeros.join('')}1`;
}
return fixed;
}
export function getPercentage(proportion: number) {
const perc = 100 * proportion;
if (perc === 0) {
return '0%';
} else if (perc < 1) {
return `<1%`;
} else {
return `${Math.round(perc)}%`;
}
}
export function formatSignificanceValueWithStyle(value: number): JSX.Element {
let formattedValue = {toConditionalPrecision(value, 3, 0.01)};
if (value < 0.05) {
formattedValue = {formattedValue};
}
return formattedValue;
}
export function formatLogOddsRatio(logOddsRatio: number): string {
if (logOddsRatio < -10) {
return '<-10';
} else if (logOddsRatio > 10) {
return '>10';
}
return logOddsRatio.toFixed(2);
}
export function roundLogRatio(logRatio: number, threshold: number): number {
if (logRatio > threshold) {
return threshold;
} else if (logRatio < -threshold) {
return -threshold;
} else {
return Number(logRatio.toFixed(2));
}
}
export function toConditionalPrecisionWithMinimum(
positiveNumber: number,
precision: number,
precisionThreshold: number,
minimumExponent: number,
prependEqualSign?: boolean
): string | React.ReactNode {
if (positiveNumber === 0 || Math.log10(positiveNumber) < minimumExponent) {
return (
< 10{minimumExponent}
);
} else {
let transformed = toConditionalPrecision(
positiveNumber,
precision,
precisionThreshold
);
return (
<>
{prependEqualSign ? ' = ' : ''}
{transformed}
>
);
}
}
// return 'NA' for NaN value
// difference between this function and the previous one is it will display percentages less than 1% as <1%
export function getMutationalSignaturePercentage(
proportion: number,
digits: number = 0
) {
//0.003 -> 0.3
if (Number.isNaN(proportion)) {
return 'NA';
} else {
if (100 * proportion < 1) {
return '<1%';
}
return `${toFixedWithThreshold(100 * proportion, digits)}%`;
}
}
export function shortenStudyName(studyName: string) {
const parenIndex = studyName.indexOf('(');
if (parenIndex > 50) {
const studyNameRight: string = studyName.substring(parenIndex);
const studyNameLeft: string = studyName.substring(0, 49);
return studyNameLeft + '...' + studyNameRight;
} else return studyName;
}