Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support Outlier table visualization type (DHIS2-13858) #2942

Merged
merged 31 commits into from
Mar 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
bc66f0a
feat: add outliers table vis type + layout (DHIS2-16344)
edoardo Dec 19, 2023
830ddc2
feat: use outlierDetection analytics endpoint (DHIS2-16345)
edoardo Dec 19, 2023
3f17c56
feat: configure options for Outlier table vis type (DHIS2-16347)
edoardo Dec 20, 2023
a93e7d0
feat: add plugin component for outliers table (DHIS2-16356)
edoardo Dec 20, 2023
a1bdeba
chore: update pot file
edoardo Dec 23, 2023
c49fdad
feat: disable all dim sections except Main (DHIS2-16346)
edoardo Jan 5, 2024
76d1590
feat: allow only 1 selected period item (DHIS2-16399)
edoardo Jan 5, 2024
87f7801
feat: set up feature toggle for outliers table for v41 (DHIS2-16421)
edoardo Jan 8, 2024
d2f9e7d
feat: implement sorting (DHIS2-16518)
edoardo Jan 24, 2024
0d0ebfa
feat: enable only data elements in data dialog (DHIS2-16433)
edoardo Jan 24, 2024
3bfdd6d
fix: adjust download menu and request (DHIS2-16595)
edoardo Jan 26, 2024
3d2ba78
fix: add missing period at the end of the text
edoardo Feb 9, 2024
09f3f8f
fix: pass relativePeriodDate and displayProperty in donwload (DHIS2-1…
edoardo Feb 9, 2024
24ef5dc
fix: support sorting in both interpretation modal and plugin (DHIS2-1…
edoardo Feb 12, 2024
be7e4db
fix: respect DGS from options (DHIS2-16773)
edoardo Feb 12, 2024
f8cd2ad
fix: use a better message for no outliers (DHIS2-16798)
edoardo Feb 13, 2024
1d5a245
fix: add loading spinner in plugin/modal (DHIS2-16770)
edoardo Feb 14, 2024
293639c
fix: allow table to scroll (DHIS2-16768)
edoardo Feb 14, 2024
36cff9d
fix: support translations for column labels and tooltips (DHIS2-16774)
edoardo Feb 14, 2024
009df59
fix: resize table to fit available space (DHIS2-16771)
edoardo Feb 15, 2024
349c01e
fix: filter out non data element items (DHIS2-16857)
edoardo Feb 20, 2024
34e124a
feat: implement skipRounding option (DHIS2-16870)
edoardo Feb 21, 2024
5b1907c
test: fix failing test and update snapshot
edoardo Feb 21, 2024
d8b7154
fix: add help text on Max results option (DHIS2-16873)
edoardo Feb 21, 2024
2b77b96
fix: update various texts
edoardo Feb 26, 2024
bbd6781
fix: fix crash when switching Scatter/Outlier (DHIS2-16895)
edoardo Feb 27, 2024
748ab17
fix: avoid removing trailing 0 while typing (DHIS2-16896)
edoardo Feb 27, 2024
ce717fa
fix: show custom error when no data in use (DHIS2-16892)
edoardo Feb 27, 2024
1c76a2a
fix: re-render plugin when props change
edoardo Mar 5, 2024
6c7b36b
chore: remove debug console log
edoardo Mar 5, 2024
2db39fe
chore: use alpha version of analytics
edoardo Mar 5, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
142 changes: 130 additions & 12 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: 2023-11-13T12:11:28.959Z\n"
"PO-Revision-Date: 2023-11-13T12:11:28.959Z\n"
"POT-Creation-Date: 2024-03-01T08:28:43.727Z\n"
"PO-Revision-Date: 2024-03-01T08:28:43.727Z\n"

msgid "All items"
msgstr "All items"
Expand Down Expand Up @@ -43,11 +43,11 @@ msgid "Add to {{axisName}}"
msgstr "Add to {{axisName}}"

msgid ""
"'{{visualizationType}}' is intended to show a single data item. Only the "
"first item will be used and saved."
"'{{visualizationType}}' is intended to show a single item for this type of "
"dimension. Only the first item will be used and saved."
msgstr ""
"'{{visualizationType}}' is intended to show a single data item. Only the "
"first item will be used and saved."
"'{{visualizationType}}' is intended to show a single item for this type of "
"dimension. Only the first item will be used and saved."

msgid ""
"'{{visualiationType}}' is intended to show maximum {{maxNumber}} number of "
Expand All @@ -63,6 +63,13 @@ msgstr ""
"'Scatter' is intended to show a single data item per axis. Only the first "
"item will be used and saved."

msgid ""
"'Outlier table' shows values from data elements only. Only data elements "
"will be used and saved."
msgstr ""
"'Outlier table' shows values from data elements only. Only data elements "
"will be used and saved."

msgid "Vertical"
msgstr "Vertical"

Expand Down Expand Up @@ -183,11 +190,14 @@ msgstr "horizontal"
msgid "None selected"
msgstr "None selected"

msgid "None in use"
msgstr "None in use"

msgid "Only '{{- name}}' in use"
msgstr "Only '{{- name}}' in use"

msgid "Only '{{number}}' in use"
msgstr "Only '{{number}}' in use"
msgid "Only {{number}} in use"
msgstr "Only {{number}} in use"

msgid "All items are selected"
msgstr "All items are selected"
Expand Down Expand Up @@ -581,6 +591,16 @@ msgstr ""
msgid "Outlier detection method"
msgstr "Outlier detection method"

msgid "Max results"
msgstr "Max results"

msgid ""
"The maximum number of outlier values to show in the table. Must be between "
"1-500."
msgstr ""
"The maximum number of outlier values to show in the table. Must be between "
"1-500."

msgid "Organisation unit"
msgstr "Organisation unit"

Expand Down Expand Up @@ -706,12 +726,101 @@ msgstr "Change org unit"
msgid "{{level}} level in {{orgunit}}"
msgstr "{{level}} level in {{orgunit}}"

msgid "Sort ascending by {{columnName}} and update"
msgstr "Sort ascending by {{columnName}} and update"

msgid "Sort descending by {{columnName}} and update"
msgstr "Sort descending by {{columnName}} and update"

msgid "Open as Map"
msgstr "Open as Map"

msgid "Visually plot data on a world map. Data elements use separate map layers."
msgstr "Visually plot data on a world map. Data elements use separate map layers."

msgid "Category option combination"
msgstr "Category option combination"

msgid "Absolute deviation"
msgstr "Absolute deviation"

msgid ""
"A measure of the absolute difference between each data point and a central "
"value, usually the mean or median, providing a straightforward "
"understanding of dispersion in the dataset."
msgstr ""
"A measure of the absolute difference between each data point and a central "
"value, usually the mean or median, providing a straightforward "
"understanding of dispersion in the dataset."

msgid ""
"A measure of how far a data point deviates from the median, using the "
"median absolute deviation instead of the standard deviation, making it "
"robust against outliers."
msgstr ""
"A measure of how far a data point deviates from the median, using the "
"median absolute deviation instead of the standard deviation, making it "
"robust against outliers."

msgid "Median"
msgstr "Median"

msgid ""
"The middle value in a dataset when the values are arranged in ascending or "
"descending order. It's a robust measure of central tendency that is less "
"affected by outliers compared to the mean."
msgstr ""
"The middle value in a dataset when the values are arranged in ascending or "
"descending order. It's a robust measure of central tendency that is less "
"affected by outliers compared to the mean."

msgid "Median absolute deviation"
msgstr "Median absolute deviation"

msgid ""
"A robust measure of variability, found by calculating the median of the "
"absolute differences between each data point and the overall median. It's "
"less influenced by outliers compared to other measures like the standard "
"deviation."
msgstr ""
"A robust measure of variability, found by calculating the median of the "
"absolute differences between each data point and the overall median. It's "
"less influenced by outliers compared to other measures like the standard "
"deviation."

msgid "Z-score"
msgstr "Z-score"

msgid ""
"A measure of how many standard deviations a data point is from the mean of "
"a dataset, providing insight into how unusual or typical that data point is "
"relative to the rest of the distribution."
msgstr ""
"A measure of how many standard deviations a data point is from the mean of "
"a dataset, providing insight into how unusual or typical that data point is "
"relative to the rest of the distribution."

msgid "Mean"
msgstr "Mean"

msgid "Average of the value over time."
msgstr "Average of the value over time."

msgid ""
"A measure of how dispersed the data is in relation to the mean. Low "
"standard deviation indicates data are clustered tightly around the mean, "
"and high standard deviation indicates data are more spread out."
msgstr ""
"A measure of how dispersed the data is in relation to the mean. Low "
"standard deviation indicates data are clustered tightly around the mean, "
"and high standard deviation indicates data are more spread out."

msgid "Minimum score threshold"
msgstr "Minimum score threshold"

msgid "Maximum score threshold"
msgstr "Maximum score threshold"

msgid "Not supported when using cumulative values"
msgstr "Not supported when using cumulative values"

Expand Down Expand Up @@ -855,6 +964,12 @@ msgstr ""
msgid "There's a syntax problem with the analytics request."
msgstr "There's a syntax problem with the analytics request."

msgid "No outliers found"
msgstr "No outliers found"

msgid "There were no outliers found for the selected data items and options."
msgstr "There were no outliers found for the selected data items and options."

msgid "or"
msgstr "or"

Expand Down Expand Up @@ -1111,11 +1226,14 @@ msgid "Display a single value. Recommend relative period to show latest data."
msgstr "Display a single value. Recommend relative period to show latest data."

msgid ""
"View the relationship between two data items at a place or time. "
"Recommended for finding outliers."
"Compare the relationship between two data items across multiple places. "
"Recommended for visualizing outliers."
msgstr ""
"View the relationship between two data items at a place or time. "
"Recommended for finding outliers."
"Compare the relationship between two data items across multiple places. "
"Recommended for visualizing outliers."

msgid "Automatically identify extreme outliers based on historical data."
msgstr "Automatically identify extreme outliers based on historical data."

msgid "Weeks per year"
msgstr "Weeks per year"
Expand Down
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,12 @@
"start-server-and-test": "^2.0.0"
},
"dependencies": {
"@dhis2/analytics": "^26.3.0",
"@dhis2/analytics": "999.9.9-outlier-table.alpha.4",
"@dhis2/app-runtime": "^3.7.0",
"@dhis2/app-runtime-adapter-d2": "^1.1.0",
"@dhis2/app-service-datastore": "^1.0.0-beta.3",
"@dhis2/d2-i18n": "^1.1.0",
"@dhis2/ui": "^8.7.6",
"@dhis2/ui": "^9.2.0",
"@krakenjs/post-robot": "^11.0.0",
"d2": "^31.9.1",
"decode-uri-component": "^0.2.2",
Expand All @@ -66,5 +66,8 @@
"reselect": "^4.1.7",
"styled-jsx": "^4",
"whatwg-fetch": "^3.6.2"
},
"resolutions": {
"@dhis2/ui": "^9.2.0"
}
}
7 changes: 5 additions & 2 deletions src/PluginWrapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import postRobot from '@krakenjs/post-robot'
import debounce from 'lodash-es/debounce'
import PropTypes from 'prop-types'
import React, { useEffect, useLayoutEffect, useState } from 'react'
import { VisualizationPlugin } from './components/VisualizationPlugin/VisualizationPlugin.js'
import { VisualizationPluginWrapper } from './components/VisualizationPlugin/VisualizationPluginWrapper.js'
import { getPWAInstallationStatus } from './modules/getPWAInstallationStatus.js'

const LoadingMask = () => {
Expand Down Expand Up @@ -128,7 +128,10 @@ const PluginWrapper = () => {
cacheNow={propsFromParent.recordOnNextLoad}
isParentCached={propsFromParent.isParentCached}
>
<VisualizationPlugin id={renderId} {...propsFromParent} />
<VisualizationPluginWrapper
id={renderId}
{...propsFromParent}
/>
</CacheableSectionWrapper>
<CssVariables colors spacers elevations />
</div>
Expand Down
11 changes: 11 additions & 0 deletions src/actions/ui.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { getDisabledOptions } from '../modules/disabledOptions.js'
import {
SET_UI,
CLEAR_UI,
CLEAR_UI_DATA_SORTING,
SET_UI_FROM_VISUALIZATION,
SET_UI_TYPE,
SET_UI_DISABLED_OPTIONS,
Expand All @@ -23,6 +24,7 @@ import {
UPDATE_UI_SERIES_ITEM,
SET_UI_OPTION,
SET_UI_OPTION_FONT_STYLE,
SET_UI_DATA_SORTING,
sGetUiType,
sGetUiOptions,
} from '../reducers/ui.js'
Expand Down Expand Up @@ -67,6 +69,15 @@ export const acSetUiOptionFontStyle = (value) => ({
value,
})

export const acClearUiDataSorting = () => ({
type: CLEAR_UI_DATA_SORTING,
})

export const acSetUiDataSorting = (value) => ({
type: SET_UI_DATA_SORTING,
value,
})

export const acUpdateUiSeriesItem = (value) => ({
type: UPDATE_UI_SERIES_ITEM,
value,
Expand Down
91 changes: 89 additions & 2 deletions src/api/analytics.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,25 @@
import {
Analytics,
VIS_TYPE_PIVOT_TABLE,
layoutGetDimensionItems,
VIS_TYPE_PIVOT_TABLE,
DIMENSION_ID_DATA,
DIMENSION_ID_PERIOD,
DAILY,
WEEKLY,
WEEKS_THIS_YEAR,
} from '@dhis2/analytics'
import { getRelativePeriodTypeUsed } from '../modules/analytics.js'
import {
METHOD_MODIFIED_Z_SCORE,
METHOD_STANDARD_Z_SCORE,
OUTLIER_METHOD_PROP,
OUTLIER_THRESHOLD_PROP,
} from '../components/VisualizationOptions/Options/OutliersForOutlierTable.js'
import { OUTLIER_MAX_RESULTS_PROP } from '../components/VisualizationOptions/Options/OutliersMaxResults.js'
import {
getRelativePeriodTypeUsed,
getOutlierTableDimensionIdHeaderMap,
} from '../modules/analytics.js'
import { getSortingFromVisualization } from '../modules/ui.js'

const periodId = DIMENSION_ID_PERIOD

Expand All @@ -24,6 +36,81 @@ export const apiFetchAnalytics = async (dataEngine, visualization, options) => {
return [new analyticsEngine.response(rawResponse)]
}

export const getAnalyticsRequestForOutlierTable = ({
analyticsEngine,
visualization,
options,
forDownload = false,
}) => {
const dimensionIdHeaderMap = getOutlierTableDimensionIdHeaderMap(options)

const parameters = {
...options,
maxResults: visualization.outlierAnalysis[OUTLIER_MAX_RESULTS_PROP],
algorithm:
visualization.outlierAnalysis[OUTLIER_METHOD_PROP] ===
METHOD_STANDARD_Z_SCORE
? 'Z_SCORE'
: visualization.outlierAnalysis[OUTLIER_METHOD_PROP],
threshold: visualization.outlierAnalysis[OUTLIER_THRESHOLD_PROP],
}

const columns = visualization.columns || []
const headers = []

columns.forEach(({ dimension, items }) => {
parameters[dimension] = items.map(({ id }) => id).join(',')

headers.push(forDownload ? dimension : dimensionIdHeaderMap[dimension])

if (dimension === DIMENSION_ID_DATA) {
headers.push('cocname')
}
})

headers.push('value')

switch (visualization.outlierAnalysis.outlierMethod) {
case METHOD_MODIFIED_Z_SCORE:
headers.push('median', 'modifiedzscore', 'medianabsdeviation')
break
case METHOD_STANDARD_Z_SCORE:
headers.push('mean', 'zscore', 'stddev')
}

headers.push('lowerbound', 'upperbound')

parameters.headers = headers.join(',')

// sorting
const sorting = getSortingFromVisualization(visualization)

if (sorting) {
parameters.orderBy = sorting.dimension
parameters.sortOrder = sorting.direction
}

return new analyticsEngine.request().withParameters(parameters)
}

export const apiFetchAnalyticsForOutlierTable = async (
dataEngine,
visualization,
options
) => {
const analyticsEngine = Analytics.getAnalytics(dataEngine)

const req = getAnalyticsRequestForOutlierTable({
analyticsEngine,
visualization,
options,
})

const rawResponse = await analyticsEngine.aggregate.getOutliersData(req)

return [new analyticsEngine.response(rawResponse)]
}

export const apiFetchAnalyticsForYearOverYear = async (
dataEngine,
visualization,
Expand Down
Loading
Loading