Skip to content

Commit

Permalink
refactor: move getPrecision to numbers file and rename fns (#3128)
Browse files Browse the repository at this point in the history
Refactor work:

* getPrecision will be used by geojson layers, so it has been moved from utils/earthEngine
to utils/numbers
* numberPrecision has been renamed to clearly reflect that a function is being returned
* unit tests added for some functions in util/numbers
* removed old files from the previous DataTable, as they are no longer in use
* in classify remove exports that are not used outside of the file, and comment unused function
  • Loading branch information
jenniferarnesen committed Feb 21, 2024
1 parent 36a3593 commit 01d3821
Show file tree
Hide file tree
Showing 12 changed files with 155 additions and 180 deletions.
4 changes: 2 additions & 2 deletions i18n/en.pot
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ msgstr ""
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
"POT-Creation-Date: 2024-02-12T09:30:18.362Z\n"
"PO-Revision-Date: 2024-02-12T09:30:18.362Z\n"
"POT-Creation-Date: 2024-02-21T10:12:14.838Z\n"
"PO-Revision-Date: 2024-02-21T10:12:14.838Z\n"

msgid "Untitled map, {{date}}"
msgstr "Untitled map, {{date}}"
Expand Down
23 changes: 0 additions & 23 deletions src/components/datatable/ColorCell.js

This file was deleted.

27 changes: 0 additions & 27 deletions src/components/datatable/ColumnHeader.js

This file was deleted.

64 changes: 0 additions & 64 deletions src/components/datatable/EarthEngineColumns.js

This file was deleted.

8 changes: 4 additions & 4 deletions src/components/datatable/useTableData.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ import {
FACILITY_LAYER,
} from '../../constants/layers.js'
import { numberValueTypes } from '../../constants/valueTypes.js'
import { hasClasses, getPrecision } from '../../util/earthEngine.js'
import { hasClasses } from '../../util/earthEngine.js'
import { filterData } from '../../util/filter.js'
import { isValidUid } from '../../util/helpers.js'
import { numberPrecision } from '../../util/numbers.js'
import { getRoundToPrecisionFn, getPrecision } from '../../util/numbers.js'

const ASCENDING = 'asc'

Expand Down Expand Up @@ -123,15 +123,15 @@ const getEarthEngineHeaders = ({ aggregationType, legend, data }) => {
customFields = items.map(({ id, name }) => ({
name,
dataKey: String(id),
roundFn: numberPrecision(2),
roundFn: getRoundToPrecisionFn(2),
type: TYPE_NUMBER,
}))
} else if (Array.isArray(aggregationType) && aggregationType.length) {
customFields = aggregationType.map((type) => {
let roundFn = null
if (data?.length) {
const precision = getPrecision(data.map((d) => d[type]))
roundFn = numberPrecision(precision)
roundFn = getRoundToPrecisionFn(precision)
}
return {
name: toTitleCase(`${type} ${title}`),
Expand Down
11 changes: 7 additions & 4 deletions src/components/map/layers/earthEngine/EarthEnginePopup.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@ import { CircularLoader } from '@dhis2/ui'
import PropTypes from 'prop-types'
import React from 'react'
import { getEarthEngineAggregationType } from '../../../../constants/aggregationTypes.js'
import { hasClasses, getPrecision } from '../../../../util/earthEngine.js'
import { numberPrecision } from '../../../../util/numbers.js'
import { hasClasses } from '../../../../util/earthEngine.js'
import {
getRoundToPrecisionFn,
getPrecision,
} from '../../../../util/numbers.js'
import Popup from '../../Popup.js'
import styles from './styles/EarthEnginePopup.module.css'

Expand All @@ -20,7 +23,7 @@ const EarthEnginePopup = (props) => {

if (values) {
if (classes) {
const valueFormat = numberPrecision(isPercentage ? 2 : 0)
const valueFormat = getRoundToPrecisionFn(isPercentage ? 2 : 0)

table = (
<table className={styles.table}>
Expand Down Expand Up @@ -66,7 +69,7 @@ const EarthEnginePopup = (props) => {

// Returns the value format (precision) for an aggregation type
const getValueFormat = (type) =>
numberPrecision(
getRoundToPrecisionFn(
getPrecision(
Object.values(data)
.map((ou) =>
Expand Down
4 changes: 2 additions & 2 deletions src/components/orgunits/OrgUnitInfo.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ import i18n from '@dhis2/d2-i18n'
import { IconDimensionOrgUnit16 } from '@dhis2/ui'
import PropTypes from 'prop-types'
import React from 'react'
import { numberPrecision } from '../../util/numbers.js'
import { getRoundToPrecisionFn } from '../../util/numbers.js'
import { formatDate } from '../../util/time.js'
import ListItem from '../core/ListItem.js'
import styles from './styles/OrgUnitInfo.module.css'

export const coordFormat = numberPrecision(6) // Meter precision for longitude an latitude
export const coordFormat = getRoundToPrecisionFn(6) // Meter precision for longitude an latitude

/*
* Displays the fixed information for an org unit together with org unit groups (above) and metadata attributes (below)
Expand Down
4 changes: 2 additions & 2 deletions src/loaders/earthEngineLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { getOrgUnitsFromRows } from '../util/analytics.js'
import { hasClasses, getPeriodNameFromFilter } from '../util/earthEngine.js'
import { getDisplayProperty } from '../util/helpers.js'
import { toGeoJson } from '../util/map.js'
import { numberPrecision } from '../util/numbers.js'
import { getRoundToPrecisionFn } from '../util/numbers.js'
import {
getCoordinateField,
addAssociatedGeometries,
Expand Down Expand Up @@ -171,7 +171,7 @@ export const createLegend = ({ min, max, palette }) => {
const colors = palette.split(',')
const step = (max - min) / (colors.length - (min > 0 ? 2 : 1))
const precision = precisionRound(step, max)
const valueFormat = numberPrecision(precision)
const valueFormat = getRoundToPrecisionFn(precision)

let from = min
let to = valueFormat(min + step)
Expand Down
83 changes: 83 additions & 0 deletions src/util/__tests__/numbers.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { formatCount, getPrecision } from '../numbers.js'

describe('numbers', () => {
describe('formatCount', () => {
it('should return the original count for numbers less than 1000', () => {
expect(formatCount(500)).toEqual(500)
})

it('should format numbers between 1000 and 9500 with one decimal place and a "k"', () => {
expect(formatCount(3300)).toEqual('3.3k')
})

it('should round numbers between 9500 and 999500 to the nearest thousand and add a "k"', () => {
expect(formatCount(33000)).toEqual('33k')
})

it('should format numbers between 999500 and 1950000 with one decimal place and a "M"', () => {
expect(formatCount(1300000)).toEqual('1.3M')
})

it('should round numbers greater than 1950000 to the nearest million and add a "M"', () => {
expect(formatCount(33000000)).toEqual('33M')
})
})

describe('getPrecision', () => {
it('returns 0 for empty array', () => {
expect(getPrecision([])).toEqual(0)
})

it('returns 0 with absValue >=10000', () => {
expect(getPrecision([10000, 10011, 10020, 10030])).toEqual(0)
})

it('returns 0 with absValue >=1000 and gapValue > 10', () => {
expect(getPrecision([1010, 1000, 1050, 1030])).toEqual(0)
})

it('returns 1 with absValue >=1000 and gapValue <= 10', () => {
expect(getPrecision([1000, 1001.135, 1002, 1003])).toEqual(1)
})

it('returns 1 with absValue >=100 and gapValue > 1', () => {
expect(getPrecision([100, 106, 102, 103])).toEqual(1)
})

it('returns 2 with absValue >=100 and gapValue <= 1', () => {
expect(getPrecision([100.67, 100.1, 100.2, 100.3])).toEqual(2)
})

it('returns 2 with absValue >=10 and gapValue > 0.1', () => {
expect(getPrecision([20.99, 10.1, 10.2, 10.3])).toEqual(2)
})

it('returns 3 with absValue >=10 and gapValue <= 0.1', () => {
expect(getPrecision([10.02, 10.01, 10.03, 10])).toEqual(3)
})

it('returns 3 with absValue >=1 and gapValue > 0.01', () => {
expect(getPrecision([8, 8.07, 8.02, 8.03])).toEqual(3)
})

it('returns 4 with absValue >=1 and gapValue <= 0.01', () => {
expect(getPrecision([1, 1.001, 1.002, 1.003])).toEqual(4)
})

it('returns 4 with absValue <1 and gapValue > 0.001', () => {
expect(getPrecision([0.888, 0.101, 0.102, 0.103])).toEqual(4)
})

it('returns 5 with absValue <1 and gapValue <= 0.001', () => {
expect(getPrecision([0.1, 0.1001, 0.1002, 0.1003])).toEqual(5)
})

it('returns 1 with negative max and absValue >=100 and gapValue > 1', () => {
expect(getPrecision([100, -106, 102, 103])).toEqual(1)
})

it('returns 2 with negative max and absValue >=100 and gapValue <= 1', () => {
expect(getPrecision([-100.67, -100.1, -100.2, -100.3])).toEqual(2)
})
})
})
34 changes: 18 additions & 16 deletions src/util/classify.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
CLASSIFICATION_EQUAL_INTERVALS,
CLASSIFICATION_EQUAL_COUNTS,
} from '../constants/layers.js'
import { numberPrecision } from './numbers.js'
import { getRoundToPrecisionFn } from './numbers.js'

// Returns legend item where a value belongs
export const getLegendItemForValue = (legendItems, value) => {
Expand All @@ -30,25 +30,27 @@ export const getLegendItems = (values, method, numClasses) => {
return bins
}

export const getClassBins = (values, method, numClasses) => {
const minValue = values[0]
const maxValue = values[values.length - 1]
let bins
// This function is not in use, but keeping it
// just in case it's needed in the future
// export const getClassBins = (values, method, numClasses) => {
// const minValue = values[0]
// const maxValue = values[values.length - 1]
// let bins

if (method === CLASSIFICATION_EQUAL_INTERVALS) {
bins = getEqualIntervals(minValue, maxValue, numClasses)
} else if (method === CLASSIFICATION_EQUAL_COUNTS) {
bins = getQuantiles(values, numClasses)
}
// if (method === CLASSIFICATION_EQUAL_INTERVALS) {
// bins = getEqualIntervals(minValue, maxValue, numClasses)
// } else if (method === CLASSIFICATION_EQUAL_COUNTS) {
// bins = getQuantiles(values, numClasses)
// }

return bins
}
// return bins
// }

export const getEqualIntervals = (minValue, maxValue, numClasses) => {
const getEqualIntervals = (minValue, maxValue, numClasses) => {
const bins = []
const binSize = (maxValue - minValue) / numClasses
const precision = precisionRound(binSize, maxValue)
const valueFormat = numberPrecision(precision)
const valueFormat = getRoundToPrecisionFn(precision)

for (let i = 0; i < numClasses; i++) {
const startValue = minValue + i * binSize
Expand All @@ -63,7 +65,7 @@ export const getEqualIntervals = (minValue, maxValue, numClasses) => {
return bins
}

export const getQuantiles = (values, numClasses) => {
const getQuantiles = (values, numClasses) => {
const minValue = values[0]
const maxValue = values[values.length - 1]
const bins = []
Expand All @@ -72,7 +74,7 @@ export const getQuantiles = (values, numClasses) => {
(maxValue - minValue) / numClasses,
maxValue
)
const valueFormat = numberPrecision(precision)
const valueFormat = getRoundToPrecisionFn(precision)

let binLastValPos = binCount === 0 ? 0 : binCount

Expand Down
Loading

0 comments on commit 01d3821

Please sign in to comment.