Public
Edited
Mar 29, 2023
Importers
Insert cell
Insert cell
class ComitData {
/**
* Returns the list of available datasources as objects; each datasource will have a label property.
@return {Array} datasources - the array of available datasources.
*/
static get dataSources() {
return [
{
label: "production",
url: "https://www.comitglobal.org/data/comit-v1.min.json"
},
{
label: "beta",
url: "https://beta.comitglobal.org/data/comit-v1.min.json"
},
{
label: "local file",
attachment: FileAttachment("comit-v1.min.json").json()
}
];
}
/**
* Returns the raw data from the specified datasource
* @param {dataSource} dataSource - one of the data sources provided by ComitData.dataSources
* @return {Object} data - the raw data returned by the API call or local data file
*/
static async getRawData(dataSource) {
if (dataSource.url) {
return await d3.json(dataSource.url);
} else if (dataSource.attachment) {
return await dataSource.attachment;
} else {
return undefined;
}
}

/**
* Returns data with nested objects representing the COMIT data. When provided with an optional codingType, each policy record will have an additional attribute labeled 'policyCoding' with the selected coding based upon the provided codingType.
* @param {dataSource} dataSource - one of the data sources provided by ComitData.dataSources
* @param {codingType} codingType - one of the coding types provided by ComitData.codingTypes
* @return {Array} data - an array of country objects with nested authority objects; authority objects have nested policy objects.
*/
static async getReconstructedData(dataSource, codingType = undefined) {
const comitData = await this.getRawData(dataSource);
const countryMap = new Map(
comitData.countries.map((c, i) => [
c.id,
Object.assign({}, c, { countryNumericId: i })
])
);
const authorityMap = new Map(
comitData.authorities.map((a) => [a.id, Object.assign({}, a)])
);
const policyMap = new Map(
comitData.policies.map((p) => {
if (codingType) {
const policyEntity = p[codingType.policyField];
const policyCoding = policyEntity
? codingType.codeLookup[policyEntity[0].rank]
: undefined;
return [p.id, { ...p, policyCoding }];
} else {
return [p.id, Object.assign({}, p)];
}
})
);
const vaccineMap = new Map(
comitData.vaccines.map((v) => [v.id, Object.assign({}, v)])
);

const comitCountries = [];
for (const c of countryMap.values()) {
if (c.authorities) {
c.authorities = c.authorities.map((a) => authorityMap.get(a));
c.authorities.forEach((a) => {
if (a.policies) {
a.policies = a.policies.map((p) => policyMap.get(p));
}
if (a.policyPositionEvents) {
a.policyPositionEvents = a.policyPositionEvents
.map((ppe) => {
const newPpe = Object.assign({}, ppe);
if (newPpe.authority)
newPpe.authority = authorityMap.get(newPpe.authority);
if (newPpe.policy) newPpe.policy = policyMap.get(newPpe.policy);
if (newPpe.previousPolicy)
newPpe.previousPolicy = policyMap.get(newPpe.previousPolicy);
if (newPpe.vaccines)
newPpe.vaccines = newPpe.vaccines.map((v) =>
vaccineMap.get(v)
);
return newPpe;
})
.sort((a, b) => a.date.localeCompare(b.date));
}
});
}
if (c.vaccines) {
c.vaccines = c.vaccines.map((v) => vaccineMap.get(v));
}
if (c.vaccineEvents) {
c.vaccineEvents = c.vaccineEvents.map((ve) => {
const newVe = Object.assign({}, ve);
if (newVe.vaccineId) {
newVe.vaccine = vaccineMap.get(newVe.vaccineId);
}
return newVe;
});
}
if (c.policyPositionEvents) {
c.policyPositionEvents = c.policyPositionEvents
.map((ppe) => {
const newPpe = Object.assign({}, ppe);
if (newPpe.authority)
newPpe.authority = authorityMap.get(newPpe.authority);
if (newPpe.policy) newPpe.policy = policyMap.get(newPpe.policy);
if (newPpe.previousPolicy)
newPpe.previousPolicy = policyMap.get(newPpe.previousPolicy);
return newPpe;
})
.sort((a, b) => a.date.localeCompare(b.date));
}
comitCountries.push(c);
}

return comitCountries;
}

/**
* Returns the list of available codingTypes. Each codingType has a label property.
* @return {Array} codingTypes - the array of available codingTypes
*/
static get codingTypes() {
const pregnancyCodes = {
recommended: {
label: "1-Recommended for some or all",
shortLabel: "1",
description:
"An explicit recommendation that some or all pregnant people should receive vaccine.",
rank: 1,
color: "#3d7632"
},
permitted: {
label: "2-Permitted",
shortLabel: "2",
description:
"All pregnant people can receive, may receive, or can choose to receive vaccine.",
rank: 2,
color: "#54bcd6"
},
permittedWithQualifications: {
label: "3-Permitted with qualifications",
shortLabel: "3",
description:
"Only certain groups of pregnant people, e.g., pregnant health workers, pregnant people with underlying conditions, can, may, or can choose to receive vaccine.",
rank: 3,
color: "#fdb430"
},
notRecommendedButWithExceptions: {
label: "4-Not recommended but with exceptions",
shortLabel: "4",
description:
"A statement stating pregnant people should not receive vaccine, with certain exceptions.",
rank: 4,
color: "#fa774a"
},
notRecommended: {
label: "5-Not recommended",
shortLabel: "5",
description:
"People who are pregnant should not receive the vaccine or vaccine is contraindicated.",
rank: 5,
color: "#9b002d"
},
noPosition: {
label: "999-No position",
shortLabel: "6",
description:
"No positions regarding vaccinating pregnant people could be found, or where no position was clearly established.",
color: "#a9a9a9",
rank: 6,
isUnknown: true
},
recommendedOrPermittedOrPermittedWithQualifications: {
label: "1 or 2 or 3",
shortLabel: "1 or 2 or 3",
description:
"An explicit recommendation that some or all pregnant people should receive vaccine OR All pregnant people can receive, may receive, or can choose to receive vaccine OR only certain groups of pregnant people, e.g., pregnant health workers, pregnant people with underlying conditions, can, may, or can choose to receive vaccine",
rank: 1,
color: "#54bcd6"
},
notRecommendedButWithExceptionsOrNotRecommended: {
label: "4 or 5",
shortLabel: "4 or 5",
description:
"A statement stating pregnant people should not receive vaccine, with certain exceptions OR People who are pregnant should not receive the vaccine or vaccine is contraindicated.",
rank: 5,
color: "#fa774a"
}
// recommendedOrPermitted: {
// label: '1 or 2',
// description: 'An explicit recommendation that some or all pregnant people should receive vaccine OR All pregnant people can receive, may receive, or can choose to receive vaccine.',
// rank: 1,
// color: '#3d7632'
// },
// permittedWithQualificationsOrNotRecommendedWithExceptions: {
// label: '3 or 4',
// description: 'Only certain groups of pregnant people, e.g., pregnant health workers, pregnant people with underlying conditions, can, may, or can choose to receive vaccine OR a statement stating pregnant people should not receive vaccine, with certain exceptions.',
// rank: 3,
// color: '#fdb430'
// },
// notRecommended: {
// label: '5',
// description: 'People who are pregnant should not receive the vaccine or vaccine is contraindicated.',
// rank: 5,
// color: '#9b002d'
// },
// noPosition: {
// label: 'No position',
// description: 'No positions regarding vaccinating pregnant people could be found, or where no position was clearly established.',
// color: '#a9a9a9',
// rank: 6
// }
};
const lactationCodes = {
recommendedOrPermitted: {
label: "1 or 2",
description:
"An explicit recommendation that some or all lactating people should receive vaccine OR All lactating people can receive, may receive, or can choose to receive vaccine.",
rank: 1,
color: "#3d7632"
},
permittedWithQualificationsOrNotRecommendedWithExceptions: {
label: "3 or 4",
description:
"Only certain groups of lactating people, e.g., pregnant health workers, lactating people with underlying conditions, can, may, or can choose to receive vaccine OR a statement stating lactating people should not receive vaccine, with certain exceptions.",
rank: 3,
color: "#fdb430"
},
notRecommended: {
label: "5",
description:
"People who are lactating should not receive the vaccine or vaccine is contraindicated.",
rank: 5,
color: "#9b002d"
},
noPosition: {
label: "No position",
description:
"No positions regarding vaccinating lactating people could be found, or where no position was clearly established.",
color: "#a9a9a9",
rank: 6,
isUnknown: true
}
};
return [
{
codeLookup: {
1: pregnancyCodes.recommended,
2: pregnancyCodes.permitted,
3: pregnancyCodes.permittedWithQualifications,
4: pregnancyCodes.notRecommendedButWithExceptions,
5: pregnancyCodes.notRecommended,
6: pregnancyCodes.noPosition,
999: pregnancyCodes.noPosition,
unknown: pregnancyCodes.noPosition
},
codes: [
pregnancyCodes.recommended,
pregnancyCodes.permitted,
pregnancyCodes.permittedWithQualifications,
pregnancyCodes.notRecommendedButWithExceptions,
pregnancyCodes.notRecommended,
pregnancyCodes.noPosition
],
eventsFilter: "pregnancyPolicyPositionChange",
label: "pregnancy",
policyField: "pregnancyCode"
},
{
codeLookup: {
1: pregnancyCodes.recommendedOrPermittedOrPermittedWithQualifications,
2: pregnancyCodes.recommendedOrPermittedOrPermittedWithQualifications,
3: pregnancyCodes.recommendedOrPermittedOrPermittedWithQualifications,
4: pregnancyCodes.notRecommendedButWithExceptionsOrNotRecommended,
5: pregnancyCodes.notRecommendedButWithExceptionsOrNotRecommended,
6: undefined,
999: undefined,
unknown: undefined
},
codes: [
pregnancyCodes.recommendedOrPermittedOrPermittedWithQualifications,
pregnancyCodes.notRecommendedButWithExceptionsOrNotRecommended
],
eventsFilter: "pregnancyPolicyPositionChange",
label: "grouped pregnancy",
policyField: "pregnancyCode"
},
{
codeLookup: {
1: pregnancyCodes.recommendedOrPermittedOrPermittedWithQualifications,
2: pregnancyCodes.recommendedOrPermittedOrPermittedWithQualifications,
3: pregnancyCodes.recommendedOrPermittedOrPermittedWithQualifications,
4: pregnancyCodes.notRecommendedButWithExceptionsOrNotRecommended,
5: pregnancyCodes.notRecommendedButWithExceptionsOrNotRecommended,
6: pregnancyCodes.noPosition,
999: pregnancyCodes.noPosition,
unknown: pregnancyCodes.noPosition
},
codes: [
pregnancyCodes.recommendedOrPermittedOrPermittedWithQualifications,
pregnancyCodes.notRecommendedButWithExceptionsOrNotRecommended,
pregnancyCodes.noPosition
],
eventsFilter: "pregnancyPolicyPositionChange",
label: "grouped pregnancy with unknowns",
policyField: "pregnancyCode"
},
{
codeLookup: {
1: lactationCodes.recommendedOrPermitted,
2: lactationCodes.recommendedOrPermitted,
3: lactationCodes.permittedWithQualificationsOrNotRecommendedWithExceptions,
4: lactationCodes.permittedWithQualificationsOrNotRecommendedWithExceptions,
5: lactationCodes.notRecommended,
6: lactationCodes.noPosition,
999: lactationCodes.noPosition,
unknown: lactationCodes.noPosition
},
codes: [
lactationCodes.recommendedOrPermitted,
lactationCodes.permittedWithQualificationsOrNotRecommendedWithExceptions,
lactationCodes.notRecommended,
lactationCodes.noPosition
],
eventsFilter: "lactationPolicyPositionChange",
label: "lactation",
policyField: "lactationCode"
}
];
}
/**
* Returns the policy position as a coding (from codingType.lookup), given a country, date, and codingType.
* @param {object} country - the country for which you want to know the policy position
* @param {string | number | Date} date - the date for which you want to know the policy position
* @param {codingType} codingType - one of the coding types provided by ComitData.codingTypes
* @return {object} coding - an object which contains the resulting coding.
*/
static getPositionAtDate(country, date, codingType) {
// coerce date to the right format:
const _date = new Date(date).toISOString().slice(0, 10);
const filteredPolicyPositions = (country.policyPositionEvents || [])
.filter(
(ppe) => ppe.type === codingType.eventsFilter && ppe.date <= _date
)
.sort((a, b) => a.date.localeCompare(b.date));
const mostRecentPolicy = filteredPolicyPositions.pop()?.policy;
if (mostRecentPolicy) {
return codingType.codeLookup[
mostRecentPolicy[codingType.policyField]?.[0].rank
];
}
return codingType.codeLookup.unknown; //comitDisplayConfig.pregnancyCode.lookup.unknown
}

/**
* Given arrays of countries and dates, along with a codingType, will produce the corresponding coding for each country and date
* @param {Array} countries - the countries for which you want to know the policy position
* @param {Array} date - the dates for which you want to know the policy positions
* @param {codingType} codingType - one of the coding types provided by ComitData.codingTypes
* @return {Array} positionsAtDates - an array of objects, each containing a country object and an array of dates and positions
*/
static getPositionsAtDates(countries, dates, codingType) {
return countries.map((c) => {
const result = { country: c, positions: [] };
dates.forEach((date) => {
const policyPosition = this.getPositionAtDate(c, date, codingType);
result.positions.push({
date,
policyPosition,
isUnknown: !policyPosition
});
});
return result;
});
}
}
Insert cell
Insert cell
ComitData.dataSources
Insert cell
ComitData.codingTypes
Insert cell
ComitData.getRawData(ComitData.dataSources[0])
Insert cell
countriesWithoutCodings = ComitData.getReconstructedData(
ComitData.dataSources[2]
)
Insert cell
countriesWithCodings = ComitData.getReconstructedData(
ComitData.dataSources[2],
ComitData.codingTypes[0]
)
Insert cell
ComitData.getPositionAtDate(
countriesWithoutCodings[0],
"2021-09-01",
ComitData.codingTypes[0]
)
Insert cell
ComitData.getPositionAtDate(
countriesWithCodings[0],
"2021-09-01",
ComitData.codingTypes[0]
)
Insert cell
ComitData.getPositionAtDate(
countriesWithCodings[0],
new Date("2021-09-01"),
ComitData.codingTypes[0]
)
Insert cell
ComitData.getPositionsAtDates(
[countriesWithCodings[0], countriesWithCodings[1]],
["2021-09-01", "2022-01-01"],
ComitData.codingTypes[0]
)
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more