diff --git a/.gitignore b/.gitignore index 1318c41..b3f8f39 100644 --- a/.gitignore +++ b/.gitignore @@ -34,3 +34,4 @@ doc/examples/.bash_history **/.bash_history test_results/ +src/jupyter/tmp diff --git a/CHANGELOG.md b/CHANGELOG.md index d85a72f..9f99450 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Added new endpoint 'csv' to return a query as a CSV text object. +- Added new `all_X` endpoints for indicators, categories, spatial, and temporal resolutions which return all of them even if no datasets exist that are accessible only with `admin` scope. ### Changed diff --git a/src/api.json b/src/api.json index 933ff4d..fb80043 100644 --- a/src/api.json +++ b/src/api.json @@ -222,6 +222,23 @@ } } }, + "/all_categories": { + "get": { + "operationId": "list_all_categories", + "tags": ["data"], + "description":"Gets all available categories currently ingested in this flowkit-ui-backend instance", + "security": [{ + "auth0": ["admin"] + }], + "responses": { + "200": { "$ref": "#/components/responses/categories" }, + "401": { "$ref": "#/components/responses/unauthorized" }, + "429": { "$ref": "#/components/responses/too_many_requests" }, + "500": { "$ref": "#/components/responses/internal_server_error" }, + "503": { "$ref": "#/components/responses/service_unavailable" } + } + } + }, "/categories/{category_id}": { "parameters": [ {"$ref": "#/components/parameters/category_id"} @@ -347,6 +364,22 @@ } } }, + "/all_indicators": { + "get": { + "operationId": "list_all_indicators", + "tags": ["data"], + "description":"Gets all available indicators currently ingested in this flowkit-ui-backend instance", + "security": [{ + "auth0": ["admin"] + }], + "responses": { + "200": { "$ref": "#/components/responses/indicators" }, + "401": { "$ref": "#/components/responses/unauthorized" }, + "429": { "$ref": "#/components/responses/too_many_requests" }, + "500": { "$ref": "#/components/responses/internal_server_error" }, + "503": { "$ref": "#/components/responses/service_unavailable" } + } + }}, "/indicators/{indicator_id}": { "parameters": [ {"$ref": "#/components/parameters/indicator_id"} @@ -490,6 +523,22 @@ } } }, + "/all_spatial_resolutions": { + "get": { + "operationId": "list_all_spatial_resolutions", + "tags": ["data"], + "description":"Gets all available spatial resolutions currently ingested in this flowkit-ui-backend instance. This excludes the boundaries, which are typically quite large and should be retrieved individually.", + "security": [{ + "auth0": ["admin"] + }], + "responses": { + "200": { "$ref": "#/components/responses/spatial_resolutions" }, + "401": { "$ref": "#/components/responses/unauthorized" }, + "429": { "$ref": "#/components/responses/too_many_requests" }, + "500": { "$ref": "#/components/responses/internal_server_error" }, + "503": { "$ref": "#/components/responses/service_unavailable" } + } + }}, "/spatial_resolutions/{srid}": { "parameters": [ {"$ref": "#/components/parameters/srid"} @@ -642,6 +691,22 @@ } } }, + "/all_temporal_resolutions": { + "get": { + "operationId": "list_all_temporal_resolutions", + "tags": ["data"], + "description":"Gets all available temporal resolutions currently ingested in this flowkit-ui-backend instance", + "security": [{ + "auth0": ["admin"] + }], + "responses": { + "200": { "$ref": "#/components/responses/temporal_resolutions" }, + "401": { "$ref": "#/components/responses/unauthorized" }, + "429": { "$ref": "#/components/responses/too_many_requests" }, + "500": { "$ref": "#/components/responses/internal_server_error" }, + "503": { "$ref": "#/components/responses/service_unavailable" } + } + }}, "/temporal_resolutions/{trid}": { "parameters": [ {"$ref": "#/components/parameters/trid"} diff --git a/src/impl/apis/data_api_impl.py b/src/impl/apis/data_api_impl.py index 1430ae7..c8302f5 100644 --- a/src/impl/apis/data_api_impl.py +++ b/src/impl/apis/data_api_impl.py @@ -45,6 +45,10 @@ async def list_categories(pool: Pool, token_model: TokenModel) -> Optional[Categ return Categories(categories=categories) +async def list_all_categories(pool: Pool, token_model: TokenModel) -> Optional[Categories]: + return await list_categories(pool=pool, token_model=None) + + async def get_category(category_id: str, pool: Pool, token_model: TokenModel) -> Category: categories = await db.select_data( base_model=Category, @@ -63,6 +67,10 @@ async def list_indicators(pool: Pool, token_model: TokenModel) -> Optional[Indic return Indicators(indicators=indicators) +async def list_all_indicators(pool: Pool, token_model: TokenModel) -> Optional[Indicators]: + return await list_indicators(pool=pool, token_model=None) + + async def get_indicator(indicator_id: str, pool: Pool, token_model: TokenModel) -> Indicator: indicators = await db.select_data( base_model=Indicator, @@ -101,6 +109,12 @@ async def list_spatial_resolutions( return SpatialResolutions(spatial_resolutions=spatial_resolutions) +async def list_all_spatial_resolutions( + pool: Pool, token_model: TokenModel +) -> Optional[SpatialResolutions]: + return await list_spatial_resolutions(pool=pool, token_model=None) + + async def get_spatial_resolution( srid: int, pool: Pool, token_model: TokenModel ) -> SpatialResolution: @@ -154,6 +168,12 @@ async def list_temporal_resolutions( return TemporalResolutions(temporal_resolutions=temporal_resolutions) +async def list_all_temporal_resolutions( + pool: Pool, token_model: TokenModel +) -> Optional[TemporalResolutions]: + return await list_temporal_resolutions(pool=pool, token_model=None) + + async def get_temporal_resolution( trid: int, pool: Pool, token_model: TokenModel ) -> TemporalResolution: diff --git a/src/impl/resources/config.json b/src/impl/resources/config.json index 053c51d..b318f58 100644 --- a/src/impl/resources/config.json +++ b/src/impl/resources/config.json @@ -75,11 +75,11 @@ "order": 1, "flowgeek_url": "https://www.flowgeek.org/methods/calculating-mobility-indicators/residents-indicators#residents", "label": "Residents", - "description": "Estimates the number of people residing in an area during the month selected by the user.", - "method": "The residents indicator estimates the number of people residing in each area during the month selected by the user.\n\nThe indicator is calculated from the net inflow indicator and the baseline number of residents in the area during a reference period.\n\nA subscriber's home location is determined by the area containing the cell tower which most frequently routed the subscriber's last network event (e.g. call, SMS message, or mobile data) of the day over the previous four weeks, updated monthly.", + "description": "The estimated number of residents per communal section for the current month.", + "method": "The estimated number of residents per communal section for the current month. Residents per communal section, per month, are conceptualised as the population that spent the majority of the month in that communal section (“de facto” residents).\n\nTo obtain the estimate of residents in a communal section for a month, we use CDRs to estimate the number of people who relocated within the country in and out of the communal section (giving the change in residents due to internal mobility), then we use estimated population change rate from the UN to account for other population changes (births, deaths, international migrations), and add these changes to the estimate of residents for the previous month. The start month is January 2020 for which the estimate of residents is based on existing population estimates.\n\nResidents are derived from changes in subscribers’ home location (relocations) and a subscriber’s home location is determined by the area containing the cell tower which most frequently routed the subscriber's last call of the day over the previous four weeks, updated monthly.\n\nNOTE: We use the term ‘subscriber’ to refer to pseudonymised MSISDNs (hashed phone numbers). This means that two ‘subscribers’ (phone numbers) may be the same individual, if that person uses more than one phone number, or one ‘subscriber’ may represent several individuals, if a phone number is actively used by several people.", "label_fr": "Résidents", - "description_fr": "Estime le nombre de personnes résidant dans une zone pendant le mois sélectionné par l'utilisateur.", - "method_fr": "L'indicateur des résidents estime le nombre de personnes résidant dans chaque zone pendant le mois sélectionné par l'utilisateur.\n\nL'indicateur est calculé à partir de l'indicateur d'afflux net et du nombre de base de résidents dans la zone pendant une période de référence.\n\nL'emplacement du domicile d'un abonné est déterminé par la zone dans laquelle se trouve la tour de téléphonie cellulaire qui a acheminé le plus fréquemment le dernier événement réseau de l'abonné (par exemple, un appel, un message SMS, ou des données mobiles) de la journée au cours des quatre semaines précédentes, avec une mise à jour mensuelle.", + "description_fr": "The estimated number of residents per communal section for the current month.", + "method_fr": "The estimated number of residents per communal section for the current month. Residents per communal section, per month, are conceptualised as the population that spent the majority of the month in that communal section (“de facto” residents).\n\nTo obtain the estimate of residents in a communal section for a month, we use CDRs to estimate the number of people who relocated within the country in and out of the communal section (giving the change in residents due to internal mobility), then we use estimated population change rate from the UN to account for other population changes (births, deaths, international migrations), and add these changes to the estimate of residents for the previous month. The start month is January 2020 for which the estimate of residents is based on existing population estimates.\n\nResidents are derived from changes in subscribers’ home location (relocations) and a subscriber’s home location is determined by the area containing the cell tower which most frequently routed the subscriber's last call of the day over the previous four weeks, updated monthly.\n\nNOTE: We use the term ‘subscriber’ to refer to pseudonymised MSISDNs (hashed phone numbers). This means that two ‘subscribers’ (phone numbers) may be the same individual, if that person uses more than one phone number, or one ‘subscriber’ may represent several individuals, if a phone number is actively used by several people.", "scale": "sequential", "decimals": 0, "min_value": 0, @@ -92,11 +92,11 @@ "order": 2, "flowgeek_url": "https://www.flowgeek.org/methods/calculating-mobility-indicators/residents-indicators#residents-km2", "label": "Residents per square km", - "description": "Estimates the average number of people residing per square kilometre of an area during the month selected by the user.", - "method": "The residents per square kilometre indicator estimates the average number of people residing per square kilometre of each area during the month selected by the user.\n\nThe indicator is calculated from the residents indicator and the geographic size of the area.\n\nA subscriber's home location is determined by the area containing the cell tower which most frequently routed the subscriber's last network event (e.g. call, SMS message, or mobile data) of the day over the previous four weeks, updated monthly.", + "description": "The number of estimated residents per communal section for the current month, divided by the area of that communal section.", + "method": "Residents per km² (per month) is the number of estimated residents per communal section for the current month, divided by the area of that communal section, giving the spatial density of residents.\n\nThe indicator is calculated from the residents indicator and the geographic size of the communal section.\n\nResidents are derived from changes in subscribers’ home location (relocations) and a subscriber’s home location is determined by the area containing the cell tower which most frequently routed the subscriber's last call of the day over the previous four weeks, updated monthly.", "label_fr": "Habitants par km²", - "description_fr": "Estime le nombre moyen de personnes résidant par kilomètre carré d'une zone pendant le mois sélectionné par l'utilisateur.", - "method_fr": "L'indicateur de résidents par kilomètre carré estime le nombre moyen de personnes résidant par kilomètre carré d'une zone pendant le mois sélectionné par l'utilisateur.\n\nL'indicateur est calculé à partir de l'indicateur des résidents et de la taille géographique de la zone.\n\nL'emplacement du domicile d'un abonné est déterminé par la zone dans laquelle se trouve la tour de téléphonie cellulaire qui a acheminé le plus fréquemment le dernier événement réseau de l'abonné (par exemple, un appel, un message SMS, ou des données mobiles) de la journée au cours des quatre semaines précédentes, avec une mise à jour mensuelle.", + "description_fr": "The number of estimated residents per communal section for the current month, divided by the area of that communal section.", + "method_fr": "Residents per km² (per month) is the number of estimated residents per communal section for the current month, divided by the area of that communal section, giving the spatial density of residents.\n\nThe indicator is calculated from the residents indicator and the geographic size of the communal section.\n\nResidents are derived from changes in subscribers’ home location (relocations) and a subscriber’s home location is determined by the area containing the cell tower which most frequently routed the subscriber's last call of the day over the previous four weeks, updated monthly.", "scale": "sequential", "decimals": 2, "min_value": 0, @@ -107,12 +107,12 @@ "indicator_id": "residents.residents_diffwithref", "order": 3, "flowgeek_url": "https://www.flowgeek.org/methods/calculating-mobility-indicators/residents-indicators#residents-difference", - "label": "Residents difference", - "description": "Estimates the difference in the number of residents between a reference period and the month selected by the user.", - "method": "For each area, the residents difference indicator estimates the difference in the number of residents between a reference period and the month selected by the user.\n\nThe indicator is calculated from residents indicator and the baseline number of residents in the area during a reference period.\n\nIf the number of residents has increased, the indicator will have a positive value; if the number of residents has decreased, the value will be negative.\n\nA subscriber's home location is determined by the area containing the cell tower which most frequently routed the subscriber's last network event (e.g. call, SMS message, or mobile data) of the day over the previous four weeks, updated monthly.", - "label_fr": "Différence entre les résidents", - "description_fr": "Estime la différence du nombre de résidents entre une période de référence et le mois sélectionné par l'utilisateur.", - "method_fr": "Pour chaque zone, l'indicateur de différence de résidents estime la différence du nombre de résidents entre une période de référence et le mois sélectionné par l'utilisateur.\n\nL'indicateur est calculé à partir de l'indicateur de résidents et du nombre de résidents de référence dans la zone pendant une période de référence.\n\nSi le nombre de résidents a augmenté, l'indicateur aura une valeur positive ; si le nombre de résidents a diminué, la valeur sera négative.\n\nL'emplacement du domicile d'un abonné est déterminé par la zone dans laquelle se trouve la tour de téléphonie cellulaire qui a acheminé le plus fréquemment le dernier événement réseau de l'abonné (par exemple, un appel, un message SMS, ou des données mobiles) de la journée au cours des quatre semaines précédentes, avec une mise à jour mensuelle.", + "label": "Change in residents", + "description": "The absolute change in estimated residents per communal section between January 2020 (corresponding to existing population estimates) and the selected month.", + "method": "For each communal section, the change in residents indicator is an estimate of the difference in the number of residents between January 2020 (corresponding to existing population estimates) and the selected month. \n\nThe indicator is calculated from residents indicator and the number of residents in the communal section in January 2020 (corresponding to existing population estimates).\n\nIf the number of residents has increased, the indicator will have a positive value; if the number of residents has decreased, the value will be negative.\n\nResidents are derived from changes in subscribers’ home location (relocations) and a subscriber’s home location is determined by the area containing the cell tower which most frequently routed the subscriber's last call of the day over the previous four weeks, updated monthly.", + "label_fr": "Change in residents", + "description_fr": "The absolute change in estimated residents per communal section between January 2020 (corresponding to existing population estimates) and the selected month.", + "method_fr": "For each communal section, the change in residents indicator is an estimate of the difference in the number of residents between January 2020 (corresponding to existing population estimates) and the selected month. \n\nThe indicator is calculated from residents indicator and the number of residents in the communal section in January 2020 (corresponding to existing population estimates).\n\nIf the number of residents has increased, the indicator will have a positive value; if the number of residents has decreased, the value will be negative.\n\nResidents are derived from changes in subscribers’ home location (relocations) and a subscriber’s home location is determined by the area containing the cell tower which most frequently routed the subscriber's last call of the day over the previous four weeks, updated monthly.", "scale": "diverging", "decimals": 0, "min_value": null, @@ -123,30 +123,32 @@ "indicator_id": "residents.residents_pctchangewithref", "order": 4, "flowgeek_url": "https://www.flowgeek.org/methods/calculating-mobility-indicators/residents-indicators#residents-difference-percentage-change", - "label": "Percent change in residents difference", - "description": "Estimates the change in the number of residents between a reference period and the month selected by the user, expressed as a percentage of the baseline number of residents.", - "method": "The percentage change in residents indicator estimates the change in the number of residents between a reference period and a given period of time, relative to the number of residents in the reference period. The difference is expressed as a percentage of a baseline value calculated for the reference period.\n\nThe indicator is calculated from the residents indicator and the baseline number of residents in the area during a reference period.\n\nIf the number of residents have increased, the indicator will have a positive value; if the number of residents has decreased, the value will be negative.\n\nA subscriber's home location is determined by the area containing the cell tower which most frequently routed the subscriber's last network event (e.g. call, SMS message, or mobile data) of the day over the previous four weeks, updated monthly.", - "label_fr": "Variation en pourcentage de la différence de résidents", - "description_fr": "Estime la variation du nombre de résidents entre une période de référence et le mois sélectionné par l'utilisateur, exprimée en pourcentage du nombre de résidents de référence.", - "method_fr": "L'indicateur de variation en pourcentage du nombre de résidents estime la variation du nombre de résidents entre une période de référence et une période donnée, par rapport au nombre de résidents de la période de référence. La différence est exprimée en pourcentage d'une valeur de référence calculée pour la période de référence.\n\nL'indicateur est calculé à partir de l'indicateur de résidents et du nombre de résidents de référence dans la zone pendant une période de référence.\n\nSi le nombre de résidents a augmenté, l'indicateur aura une valeur positive ; si le nombre de résidents a diminué, la valeur sera négative.\n\nL'emplacement du domicile d'un abonné est déterminé par la zone dans laquelle se trouve la tour de téléphonie cellulaire qui a acheminé le plus fréquemment le dernier événement réseau de l'abonné (par exemple, un appel, un message SMS, ou des données mobiles) de la journée au cours des quatre semaines précédentes, avec une mise à jour mensuelle.", + "label": "Relative change in residents (%)", + "description": "The change in estimated residents per communal section, between existing population estimate (January 2020) and the selected month, expressed as a percentage of each communal section’s existing population estimate (January 2020).", + "method": "The relative change in residents (%) indicator is an estimate of the change in the number of residents between January 2020 (existing population estimate) and the selected month, relative to the number of residents in January 2020 (existing population estimate). The difference is expressed as a percentage of a baseline value calculated for January 2020.\n\nThe indicator is calculated from the residents indicator and the baseline number of residents in the communal section in January 2020.\n\nIf the number of residents have increased, the indicator will have a positive value; if the number of residents has decreased, the value will be negative.\n\nResidents are derived from changes in subscribers’ home location (relocations) and a subscriber’s home location is determined by the area containing the cell tower which most frequently routed the subscriber's last call of the day over the previous four weeks, updated monthly.", + "label_fr": "Relative change in residents (%)", + "description_fr": "The change in estimated residents per communal section, between existing population estimate (January 2020) and the selected month, expressed as a percentage of each communal section’s existing population estimate (January 2020).", + "method_fr": "The relative change in residents (%) indicator is an estimate of the change in the number of residents between January 2020 (existing population estimate) and the selected month, relative to the number of residents in January 2020 (existing population estimate). The difference is expressed as a percentage of a baseline value calculated for January 2020.\n\nThe indicator is calculated from the residents indicator and the baseline number of residents in the communal section in January 2020.\n\nIf the number of residents have increased, the indicator will have a positive value; if the number of residents has decreased, the value will be negative.\n\nResidents are derived from changes in subscribers’ home location (relocations) and a subscriber’s home location is determined by the area containing the cell tower which most frequently routed the subscriber's last call of the day over the previous four weeks, updated monthly.", "scale": "diverging", "decimals": 2, - "min_value": -100, - "max_value": 100 + "min_value": -50, + "max_value": 50 }, { "category_id": "residents", "indicator_id": "residents.abnormality", - "order": 5, + "order": 8, "flowgeek_url": "https://www.flowgeek.org/methods/calculating-mobility-indicators/residents-indicators#residents-abnormality", - "label": "Abnormality", - "description": "Measures the deviation of the estimated number of people residing in a given area during the month selected by the user from the numbers of residents estimated during a reference period, expressed as an abnormality score (z-score).", - "method": "The residents abnormality indicator measures the deviation of the estimated number of people residing in a given area during the month selected by the user from the numbers of residents estimated during a reference period, expressed as a z-score.\n\nThe indicator is calculated from the residents difference indicator and the mean absolute deviation in the number of residents in the area during a reference period.\n\nFor this indicator, a positive value greater than 3 indicates a statistically significant increase in the number of residents in a given area; a value less than -3 indicates a statistically significant decrease in residents. Values between 3 and -3 are within the bounds of normal variation based on the reference period.\n\nThis indicator describes how unusual the number of residents in an area is, given the amount of variation observed during the reference period. Higher absolute values indicate greater deviation from the normal variation in population, and therefore greater probability that the change is meaningful. Such changes may be associated with specific events or may be caused by technical issues. Very large abnormalities (absolute values greater than 6), however, may also be indicative of a technical issue.\n\nA subscriber's home location is determined by the area containing the cell tower which most frequently routed the subscriber's last network event (e.g. call, SMS message, or mobile data) of the day over the previous four weeks, updated monthly.", - "label_fr": "Anomalie", - "description_fr": "Mesure l'écart entre le nombre estimé de personnes résidant dans une zone donnée pendant le mois sélectionné par l'utilisateur et le nombre de résidents estimé pendant la période de référence, exprimé sous la forme d'un score d'anomalie (score z).", - "method_fr": "L'indicateur d'anomalie des résidents mesure l'écart entre le nombre estimé de personnes résidant dans une zone donnée pendant le mois sélectionné par l'utilisateur et le nombre de résidents estimé pendant la période de référence, exprimé sous la forme d'un score z.\n\nL'indicateur est calculé à partir de l'indicateur de différence de résidents et de l'écart absolu moyen du nombre de résidents dans la zone pendant une période de référence.\n\nPour cet indicateur, une valeur positive supérieure à 3 indique une augmentation statistiquement significative du nombre de résidents dans une zone donnée ; une valeur inférieure à -3 indique une diminution statistiquement significative des résidents. Les valeurs entre 3 et -3 se situent dans les limites de la variation normale basée sur la période de référence.\n\nCet indicateur décrit l'ampleur du caractère inhabituel du nombre de résidents dans une zone, compte tenu de l'ampleur de la variation observée pendant la période de référence. Des valeurs absolues plus élevées indiquent un plus grand écart par rapport à la variation normale de la population, et donc une plus grande probabilité que le changement soit significatif. Des changements de la sorte pourraient être associés à des événements spécifiques ou causés par des problèmes techniques. Toutefois, des anomalies très importantes (valeurs absolues supérieures à 6) pourraient également indiquer un problème technique.\n\nL'emplacement du domicile d'un abonné est déterminé par la zone dans laquelle se trouve la tour de téléphonie cellulaire qui a acheminé le plus fréquemment le dernier événement réseau de l'abonné (par exemple, un appel, un message SMS, ou des données mobiles) de la journée au cours des quatre semaines précédentes, avec une mise à jour mensuelle.", + "label": "Abnormality score", + "description": "Describes how unusual the last monthly change in the number of residents in the communal section is, compared to the monthly changes estimated during the 12 preceding months.", + "method": "The abnormality score indicates how different the last monthly change of residents per communal section (between the current month and the previous month) is, compared to the median monthly change of residents estimated during the 12 preceding months (the baseline period), measured in median absolute deviations (i.e. it is the modified z-score of the resident monthly change). It describes how unusual the last monthly change in the number of residents in a communal section is, compared to the monthly changes estimated during the 12 preceding months. \n\nFor this indicator, a positive value greater than 3 indicates an abnormal increase in the number of residents in the communal section (a statistical outlier); a value less than -3 indicates an abnormal decrease in residents. Values between 3 and -3 are within the bounds of normal v ariation based on the reference period. Abnormality scores above 6 in absolute value are more likely to correspond to technical issues, particularly in the absence of known disrupting events (disruption of mobility and/or phone usage).\n\nThe abnormality score is not available for January to March 2020 included due to a too short baseline period to be reliable.", + "label_fr": "Abnormality score", + "description_fr": "Describes how unusual the last monthly change in the number of residents in the communal section is, compared to the monthly changes estimated during the 12 preceding months.", + "method_fr": "The abnormality score indicates how different the last monthly change of residents per communal section (between the current month and the previous month) is, compared to the median monthly change of residents estimated during the 12 preceding months (the baseline period), measured in median absolute deviations (i.e. it is the modified z-score of the resident monthly change). It describes how unusual the last monthly change in the number of residents in a communal section is, compared to the monthly changes estimated during the 12 preceding months. \n\nFor this indicator, a positive value greater than 3 indicates an abnormal increase in the number of residents in the communal section (a statistical outlier); a value less than -3 indicates an abnormal decrease in residents. Values between 3 and -3 are within the bounds of normal v ariation based on the reference period. Abnormality scores above 6 in absolute value are more likely to correspond to technical issues, particularly in the absence of known disrupting events (disruption of mobility and/or phone usage).\n\nThe abnormality score is not available for January to March 2020 included due to a too short baseline period to be reliable.", "scale": "diverging", "decimals": 2, + "min_value": -25, + "max_value": 25, "bins": [ { "min": -3, "max": 3, "width": "10%" }, { "min": -6, "max": -3, "width": "30%" }, @@ -158,14 +160,14 @@ { "category_id": "residents", "indicator_id": "residents.arrived", - "order": 6, + "order": 5, "flowgeek_url": "https://www.flowgeek.org/methods/calculating-mobility-indicators/residents-indicators#arrived-residents", - "label": "Arrived residents", - "description": "Estimates the total number of people who relocated into an area during the month selected by the user.", + "label": "Total incoming", + "description": "The estimated number of people who moved into the communal section (from all other communal sections) between the previous and the currently selected month.", "method": "For each area, the arrived residents indicator estimates the total number of people who relocated to an area from any other area within the country during the month selected by the user.\n\nThe indicator is calculated from the sum of the counts of subscribers whose home location changed from one area to another area each month.\n\nA subscriber's home location is determined by the area containing the cell tower which most frequently routed the subscriber's last network event (e.g. call, SMS message, or mobile data) of the day over the previous four weeks, updated monthly.", - "label_fr": "Résidents arrivés", - "description_fr": "Estime le nombre total de personnes qui ont déménagé dans une zone pendant le mois sélectionné par l'utilisateur.", - "method_fr": "Pour chaque zone, l'indicateur des résidents arrivés estime le nombre total de personnes qui ont déménagé vers une zone à partir de toute autre zone du pays pendant le mois sélectionné par l'utilisateur.\n\nL'indicateur est calculé à partir de la somme des comptages des abonnés dont le lieu de résidence a changé d'une zone à une autre chaque mois.\n\nL'emplacement du domicile d'un abonné est déterminé par la zone dans laquelle se trouve la tour de téléphonie cellulaire qui a acheminé le plus fréquemment le dernier événement réseau de l'abonné (par exemple, un appel, un message SMS, ou des données mobiles) de la journée au cours des quatre semaines précédentes, avec une mise à jour mensuelle.", + "label_fr": "Total incoming", + "description_fr": "The estimated number of people who moved into the communal section (from all other communal sections) between the previous and the currently selected month.", + "method_fr": "or each area, the arrived residents indicator estimates the total number of people who relocated to an area from any other area within the country during the month selected by the user.\n\nThe indicator is calculated from the sum of the counts of subscribers whose home location changed from one area to another area each month.\n\nA subscriber's home location is determined by the area containing the cell tower which most frequently routed the subscriber's last network event (e.g. call, SMS message, or mobile data) of the day over the previous four weeks, updated monthly.", "scale": "sequential", "decimals": 0, "min_value": 0, @@ -175,14 +177,14 @@ { "category_id": "residents", "indicator_id": "residents.departed", - "order": 7, + "order": 6, "flowgeek_url": "https://www.flowgeek.org/methods/calculating-mobility-indicators/residents-indicators#departed-residents", - "label": "Departed residents", - "description": "Estimates the total number of people who relocated out of an area during the month selected by the user.", - "method": "For each area, the departed residents indicator estimates the total number of people who relocated from an area to any other area within the country during the month selected by the user.\n\nThe indicator is calculated from the sum of the counts of subscribers whose home location changed from one area to another area during each month.\n\nA subscriber's home location is determined by the area containing the cell tower which most frequently routed the subscriber's last network event (e.g. call, SMS message, or mobile data) of the day over the previous four weeks, updated monthly.", + "label": "Total outgoing", + "description": "The estimated number of people who relocated (moved home) out of the communal section (to any communal section) between the previous and the current month.", + "method": "This estimate is calculated as the sum of the estimated number of people who relocated out of the communal section (change in home location) to all other communal sections between the previous and the current month. This sum is the total of outgoing relocations for the current month.\n\nResidents are derived from changes in subscribers’ home location (relocations) and a subscriber’s home location is determined by the area containing the cell tower which most frequently routed the subscriber's last call of the day over the previous four weeks, updated monthly.", "label_fr": "Résidents déplacés", - "description_fr": "Estime le nombre total de personnes qui ont déménagé hors d'une zone pendant le mois sélectionné par l'utilisateur.", - "method_fr": "Pour chaque zone, l'indicateur des résidents déplacés estime le nombre total de personnes qui ont déménagé vers une zone à partir de toute autre zone du pays pendant le mois sélectionné par l'utilisateur.\n\nL'indicateur est calculé à partir de la somme des comptages des abonnés dont le lieu de résidence a changé d'une zone à une autre chaque mois.\n\nL'emplacement du domicile d'un abonné est déterminé par la zone dans laquelle se trouve la tour de téléphonie cellulaire qui a acheminé le plus fréquemment le dernier événement réseau de l'abonné (par exemple, un appel, un message SMS, ou des données mobiles) de la journée au cours des quatre semaines précédentes, avec une mise à jour mensuelle.", + "description_fr": "The estimated number of people who relocated (moved home) out of the communal section (to any communal section) between the previous and the current month.", + "method_fr": "This estimate is calculated as the sum of the estimated number of people who relocated out of the communal section (change in home location) to all other communal sections between the previous and the current month. This sum is the total of outgoing relocations for the current month.\n\nResidents are derived from changes in subscribers’ home location (relocations) and a subscriber’s home location is determined by the area containing the cell tower which most frequently routed the subscriber's last call of the day over the previous four weeks, updated monthly.", "scale": "sequential", "decimals": 0, "min_value": 0, @@ -191,14 +193,14 @@ { "category_id": "residents", "indicator_id": "residents.delta_arrived", - "order": 8, + "order": 7, "flowgeek_url": "https://www.flowgeek.org/methods/calculating-mobility-indicators/residents-indicators#net-inflow", - "label": "Net inflow", - "description": "Estimates the difference between the number of people relocating into and out of an area during the month selected by the user.", - "method": "For each area, the net inflow residents indicator estimates the difference between the number of people relocating into (arrived residents) and out of (departed residents) an area during the month selected by the user.\n\nThe indicator is calculated from the arrived and departed residents indicators.\n\nIf more people relocate into the area than out, the indicator will have a positive value; if more people relocate out of the area, the value will be negative.\n\nA subscriber's home location is determined by the area containing the cell tower which most frequently routed the subscriber's last network event (e.g. call, SMS message, or mobile data) of the day over the previous four weeks, updated monthly.", - "label_fr": "Afflux net", - "description_fr": "Estime la différence entre le nombre de personnes déménageant vers et hors d'une zone pendant le mois sélectionné par l'utilisateur.", - "method_fr": "Pour chaque zone, l'indicateur d'afflux net de résidents estime la différence entre le nombre de personnes ayant déménagé dans (résidents arrivés) et hors (résidents partis) d'une zone pendant le mois sélectionné par l'utilisateur.\n\nCet indicateur est calculé à partir des indicateurs relatifs aux résidents arrivés et partis.\n\nSi les personnes qui s'installent dans la zone sont plus nombreuses que celles qui la quittent, l'indicateur aura une valeur positive ; si les personnes qui quittent la zone sont plus nombreuses, la valeur sera négative.\n\nL'emplacement du domicile d'un abonné est déterminé par la zone dans laquelle se trouve la tour de téléphonie cellulaire qui a acheminé le plus fréquemment le dernier événement réseau de l'abonné (par exemple, un appel, un message SMS, ou des données mobiles) de la journée au cours des quatre semaines précédentes, avec une mise à jour mensuelle.", + "label": "Incoming minus outgoing", + "description": "The net change in the number of people residing in a communal section between two months, due to internal migration.", + "method": "The difference between the number of people relocating (moving) into (total incoming) and out of (total outgoing) a communal section between the previous and the current month. It describes the net change in the number of people residing in a communal section between two months, due to internal migration. This indicator can also be referred to as ‘net relocations'.\n\nThe incoming minus outgoing indicator (net estimated relocations) for a communal section is the sum of all estimated relocations to that communal section (incoming) minus the sum of all estimated relocations from that communal section between the previous and the currently selected month.\n\nIf more people move into the communal section than out, the indicator will have a positive value; if more people move out of the area, the value will be negative.\n\nResidents are derived from changes in subscribers’ home location (relocations) and a subscriber’s home location is determined by the area containing the cell tower which most frequently routed the subscriber's last call of the day over the previous four weeks, updated monthly.", + "label_fr": "Incoming minus outgoing", + "description_fr": "The net change in the number of people residing in a communal section between two months, due to internal migration.", + "method_fr": "The difference between the number of people relocating (moving) into (total incoming) and out of (total outgoing) a communal section between the previous and the current month. It describes the net change in the number of people residing in a communal section between two months, due to internal migration. This indicator can also be referred to as ‘net relocations'.\n\nThe incoming minus outgoing indicator (net estimated relocations) for a communal section is the sum of all estimated relocations to that communal section (incoming) minus the sum of all estimated relocations from that communal section between the previous and the currently selected month.\n\nIf more people move into the communal section than out, the indicator will have a positive value; if more people move out of the area, the value will be negative.\n\nResidents are derived from changes in subscribers’ home location (relocations) and a subscriber’s home location is determined by the area containing the cell tower which most frequently routed the subscriber's last call of the day over the previous four weeks, updated monthly.", "scale": "diverging", "decimals": 0, "min_value": null, @@ -211,11 +213,11 @@ "order": 1, "flowgeek_url": "https://www.flowgeek.org/methods/calculating-mobility-indicators/relocation-indicators#relocations", "label": "Relocations", - "description": "Estimates the number of people who relocate from area A to area B during the month selected by the user.", - "method": "For each pair of areas, the relocations indicator estimates the number of people who relocate from area A to area B during the month selected by the user.\n\nThe indicator is calculated from the number of subscribers whose home location changed from area A to area B during a given period or time.\n\nA subscriber's home location is determined by the area containing the cell tower which most frequently routed the subscriber's last network event (e.g. call, SMS message, or mobile data) of the day over the previous four weeks, updated monthly.", + "description": "The estimated number of persons relocating (i.e. changing their home location) from a communal section to another between the current and the previous month.", + "method": "The relocation estimate is an estimate of the number of persons relocating (i.e. changing their home location) from one communal section to another between the current and the previous month.\n\nThe estimate is calculated from CDR aggregates of relocations, the number of subscribers changing their home locations from communal section a to communal section b between those months. A home location is determined as the communal section containing those cell towers which most frequently (and in at least 3 separate weeks) routed the last call of the day of a subscriber over a calendar month. For each subscriber, relocations are detected as a change in the communal section of the home location from one month to the next. Then CDR aggregates of relocations from communal section a to communal section b between the previous and the current months are multiplied by survey-derived adjustment factors and scaling factors.\n\nNOTE: We use the term ‘subscriber’ to refer to pseudonymised MSISDNs (hashed phone numbers). This means that two ‘subscribers’ (phone numbers) may be the same individual, if that person uses more than one phone number, or one ‘subscriber’ may represent several individuals, if a phone number is actively used by several people.\n\nNOTE: Relocations refer to directional bilateral relocations, from communal section a to communal section b. This is not usually equal to the number of relocations from b to a.", "label_fr": "Changement de résidence", - "description_fr": "Estime le nombre de personnes qui ont déménagé de la zone A à la zone B pendant le mois sélectionné par l'utilisateur.", - "method_fr": "Pour chaque paire de zones, l'indicateur de changement de résidence estime le nombre de personnes qui déménagent de la zone A à la zone B pendant le mois sélectionné par l'utilisateur.\n\nL'indicateur est calculé à partir du nombre d'abonnés dont le lieu de résidence est passé de la zone A à la zone B pendant une période donnée.\n\nL'emplacement du domicile d'un abonné est déterminé par la zone dans laquelle se trouve la tour de téléphonie cellulaire qui a acheminé le plus fréquemment le dernier événement réseau de l'abonné (par exemple, un appel, un message SMS, ou des données mobiles) de la journée au cours des quatre semaines précédentes, avec une mise à jour mensuelle.", + "description_fr": "The estimated number of persons relocating (i.e. changing their home location) from a communal section to another between the current and the previous month.", + "method_fr": "The relocation estimate is an estimate of the number of persons relocating (i.e. changing their home location) from one communal section to another between the current and the previous month.\n\nThe estimate is calculated from CDR aggregates of relocations, the number of subscribers changing their home locations from communal section a to communal section b between those months. A home location is determined as the communal section containing those cell towers which most frequently (and in at least 3 separate weeks) routed the last call of the day of a subscriber over a calendar month. For each subscriber, relocations are detected as a change in the communal section of the home location from one month to the next. Then CDR aggregates of relocations from communal section a to communal section b between the previous and the current months are multiplied by survey-derived adjustment factors and scaling factors.\n\nNOTE: We use the term ‘subscriber’ to refer to pseudonymised MSISDNs (hashed phone numbers). This means that two ‘subscribers’ (phone numbers) may be the same individual, if that person uses more than one phone number, or one ‘subscriber’ may represent several individuals, if a phone number is actively used by several people.\n\nNOTE: Relocations refer to directional bilateral relocations, from communal section a to communal section b. This is not usually equal to the number of relocations from b to a.", "scale": "sequential", "decimals": 2, "min_value": 0, @@ -226,12 +228,12 @@ "indicator_id": "relocations.relocations_diffwithref", "order": 2, "flowgeek_url": "https://www.flowgeek.org/methods/calculating-mobility-indicators/relocation-indicators#relocations-difference", - "label": "Relocations difference", - "description": "Estimates the change in the number of relocations from area A to area B between a reference period and the month selected by the user.", - "method": "The relocations difference indicator estimates the difference in number of relocations from area A to area B between a reference period and the month selected by the user.\n\nThe indicator is calculated from the relocations indicator and the baseline number of relocations during a reference period.\n\nIf the number of relocations has increased, the indicator will have a positive value; if the number has decreased, the value will be negative.\n\nA subscriber's home location is determined by the area containing the cell tower which most frequently routed the subscriber's last network event (e.g. call, SMS message, or mobile data) of the day over the previous four weeks, updated monthly.", - "label_fr": "Différence de changements de résidence", - "description_fr": "Estime la variation du nombre de changements de résidence de la zone A vers la zone B entre une période de référence et le mois choisi par l'utilisateur.", - "method_fr": "L'indicateur de différence de changements de résidence estime la variation du nombre de changements de résidence de la zone A vers la zone B entre une période de référence et le mois sélectionné par l'utilisateur.\n\nL'indicateur est calculé à partir de l'indicateur de changement de résidence et du nombre de changements de résidence de référence pendant une période de référence.\n\nSi le nombre de changements de résidence a augmenté, l'indicateur aura une valeur positive ; si le nombre de changements de résidence a diminué, la valeur sera négative.\n\nL'emplacement du domicile d'un abonné est déterminé par la zone dans laquelle se trouve la tour de téléphonie cellulaire qui a acheminé le plus fréquemment le dernier événement réseau de l'abonné (par exemple, un appel, un message SMS, ou des données mobiles) de la journée au cours des quatre semaines précédentes, avec une mise à jour mensuelle.", + "label": "Change in relocations", + "description": "An estimate of the difference in the number of relocations from communal section a to communal section b for the current and previous month, in comparison to the baseline months (generally relocations from January 2020 to February 2020).", + "method": "An estimate of the difference (absolute change) in the number of relocations from communal section a to communal section b for the current and previous month, in comparison to the baseline months (generally relocations from January 2020 to February 2020).\n\nThe indicator is calculated from the relocations indicator and the baseline number of relocations during the baseline months. \n\nThe baseline relocations’ estimate is usually relocations from January to February 2020. If no relocations’ estimate is available for these months, the baseline relocations’ estimate is the first available estimate in the time series. This indicator will be updated to use a longer baseline in our next release.\n\nIf the number of relocations has increased, the indicator will have a positive value; if the number of relocations has decreased, the value will be negative.\n\nNOTE: This indicator will be updated to use a longer baseline in our next release.", + "label_fr": "Change in relocations", + "description_fr": "An estimate of the difference in the number of relocations from communal section a to communal section b for the current and previous month, in comparison to the baseline months (generally relocations from January 2020 to February 2020).", + "method_fr": "An estimate of the difference (absolute change) in the number of relocations from communal section a to communal section b for the current and previous month, in comparison to the baseline months (generally relocations from January 2020 to February 2020).\n\nThe indicator is calculated from the relocations indicator and the baseline number of relocations during the baseline months. \n\nThe baseline relocations’ estimate is usually relocations from January to February 2020. If no relocations’ estimate is available for these months, the baseline relocations’ estimate is the first available estimate in the time series. This indicator will be updated to use a longer baseline in our next release.\n\nIf the number of relocations has increased, the indicator will have a positive value; if the number of relocations has decreased, the value will be negative.\n\nNOTE: This indicator will be updated to use a longer baseline in our next release.", "scale": "diverging", "decimals": 0, "min_value": null, @@ -242,32 +244,32 @@ "indicator_id": "relocations.relocations_pctchangewithref", "order": 3, "flowgeek_url": "https://www.flowgeek.org/methods/calculating-mobility-indicators/relocation-indicators#relocations-difference-percentage-change", - "label": "Percent change in relocations difference", - "description": "Estimates the change in the number of relocations from area A to area B between a reference period and the month selected by the user, expressed as a percentage of the baseline number of relocations.", - "method": "The percentage change in relocations difference indicator estimates the change in relocations from area A to area B relative to the number of relocations between these areas during the reference period. The difference is expressed as a percentage of a baseline value calculated for the reference period.\n\nThe indicator is calculated from the relocations indicator and the baseline number of relocations during a reference period.\n\nIf the number of relocations has increased, the indicator will have a positive value; if the number of relocations has decreased, the value will be negative.\n\nA subscriber's home location is determined by the area containing the cell tower which most frequently routed the subscriber's last network event (e.g. call, SMS message, or mobile data) of the day over the previous four weeks, updated monthly.", - "label_fr": "Variation en pourcentage de la différence de changements de résidence", - "description_fr": "Estime la variation du nombre de changements de résidence de la zone A vers la zone B entre une période de référence et le mois choisi par l'utilisateur, exprimée en pourcentage du nombre de changements de résidence de référence.", - "method_fr": "L'indicateur de variation en pourcentage de la différence de changements de résidence estime la variation des changements de résidence de la zone A vers la zone B par rapport au nombre de changements de résidence entre ces zones pendant la période de référence. La différence est exprimée en pourcentage d'une valeur de référence calculée pour la période de référence.\n\nL'indicateur est calculé à partir de l'indicateur de changements de résidence et du nombre de changements de résidence de référence pendant une période de référence.\n\nSi le nombre de changements de résidence a augmenté, l'indicateur aura une valeur positive ; si le nombre de changements de résidence a diminué, la valeur sera négative.\n\nL'emplacement du domicile d'un abonné est déterminé par la zone dans laquelle se trouve la tour de téléphonie cellulaire qui a acheminé le plus fréquemment le dernier événement réseau de l'abonné (par exemple, un appel, un message SMS, ou des données mobiles) de la journée au cours des quatre semaines précédentes, avec une mise à jour mensuelle.", + "label": "Relative change in relocations (%)", + "description": "Estimates the change in the number of relocations from a communal section to another, for the current and previous month, in comparison to the baseline months, expressed as a percentage of the baseline number of relocations.", + "method": "Estimates the change in the number of relocations from a communal section to another, for the current and previous month, in comparison to the baseline months, expressed as a percentage of the baseline number of relocations.\n\nThe indicator provides the percentage change in relocations difference (relative change) in estimated relocations between communal section a and communal section b for the current and previous month, in comparison to the baseline months. It is expressed as a percentage of the number of relocations estimated for the baseline months (generally January 2020 to February 2020). This indicator will be updated to use a longer baseline in our next release.\n\nThe indicator is calculated from the relocations indicator and the baseline number of relocations during the baseline months.\n\nIf the number of relocations has increased, the indicator will have a positive value; if the number of relocations has decreased, the value will be negative.\n\nNOTE: This indicator will be updated to use a longer baseline in our next release.", + "label_fr": "Relative change in relocations (%)", + "description_fr": "Estimates the change in the number of relocations from a communal section to another, for the current and previous month, in comparison to the baseline months, expressed as a percentage of the baseline number of relocations.", + "method_fr": "Estimates the change in the number of relocations from a communal section to another, for the current and previous month, in comparison to the baseline months, expressed as a percentage of the baseline number of relocations.\n\nThe indicator provides the percentage change in relocations difference (relative change) in estimated relocations between communal section a and communal section b for the current and previous month, in comparison to the baseline months. It is expressed as a percentage of the number of relocations estimated for the baseline months (generally January 2020 to February 2020). This indicator will be updated to use a longer baseline in our next release.\n\nThe indicator is calculated from the relocations indicator and the baseline number of relocations during the baseline months.\n\nIf the number of relocations has increased, the indicator will have a positive value; if the number of relocations has decreased, the value will be negative.\n\nNOTE: This indicator will be updated to use a longer baseline in our next release.", "scale": "diverging", "decimals": 2, - "min_value": null, - "max_value": null + "min_value": -50, + "max_value": 50 }, { "category_id": "relocations", "indicator_id": "relocations.abnormality", "order": 4, "flowgeek_url": "https://www.flowgeek.org/methods/calculating-mobility-indicators/relocation-indicators#relocations-abnormality", - "label": "Abnormality", - "description": "Measures the deviation in the estimated number of people relocating from area A to area B during the time period of interest from the numbers of relocations estimated during a reference period, expressed as an abnormality score (z-score).", - "method": "The relocations abnormality indicator measures the deviation in the estimated number of relocating from area A to area B during the month selected by the user from the numbers of relocations estimated during a reference period, expressed as a z-score.\n\nA positive value for this indicator greater than 3 indicates a statistically significant increase in the number of relocations; a value less than -3 indicates a statistically significant decrease in relocations.\n\nThis indicator describes how unusual the number of relocations from area A to area B is, given the amount of variation observed during the reference period. Higher absolute values indicate greater deviation from the normal variation in relocations, and therefore greater probability that the change is meaningful. Such changes may be associated with specific events or may be caused by technical issues. Very large abnormalities (absolute values greater than 6), however, may also be indicative of a technical issue.\n\nWe calculate the relocations abnormality indicator using the relocations difference indicator and the mean absolute deviation in the number of relocations during a reference period.\n\nA subscriber's home location is determined by the area containing the cell tower which most frequently routed the subscriber's last network event (e.g. call, SMS message, or mobile data) of the day over the previous four weeks, updated monthly.", - "label_fr": "Anomalie des changements de résidence", - "description_fr": "Mesure l'écart du nombre estimé de changements de résidence de la zone A vers la zone B pendant la période d'intérêt par rapport au nombre de changements de résidence estimé pendant la période de référence, exprimé sous la forme d'un score d'anomalie (score z).", - "method_fr": "L'indicateur d'anomalie des changements de résidence mesure l'écart entre le nombre estimé de changements de résidence de la zone A vers la zone B pendant le mois sélectionné par l'utilisateur et le nombre de changements de résidence estimé pendant une période de référence, exprimé sous la forme d'un score z.\n\nPour cet indicateur, une valeur positive supérieure à 3 indique une augmentation statistiquement significative du nombre de changements de résidence ; une valeur inférieure à -3 indique une diminution statistiquement significative des changements de résidence.\n\nCet indicateur décrit l'ampleur du caractère inhabituel du nombre de changements de résidence de la zone A vers la zone B, compte tenu de l'ampleur de la variation observée pendant la période de référence. Des valeurs absolues plus élevées indiquent un plus grand écart par rapport à la variation normale des changements de résidence , et donc une plus grande probabilité que le changement soit significatif. Des changements de la sorte pourraient être associés à des événements spécifiques ou causés par des problèmes techniques. Toutefois, des anomalies très importantes (valeurs absolues supérieures à 6) pourraient également indiquer un problème technique.\n\nNous calculons l'indicateur d'anomalie des changements de résidence en utilisant l'indicateur de différence des changements de résidence et l'écart absolu moyen du nombre de changements de résidence pendant une période de référence.\n\nL'emplacement du domicile d'un abonné est déterminé par la zone dans laquelle se trouve la tour de téléphonie cellulaire qui a acheminé le plus fréquemment le dernier événement réseau de l'abonné (par exemple, un appel, un message SMS, ou des données mobiles) de la journée au cours des quatre semaines précédentes, avec une mise à jour mensuelle.", + "label": "Abnormality score", + "description": "Describes how unusual the last monthly change in the number of relocations from a communal section to another is, compared to the monthly changes estimated during the 12 preceding months.", + "method": "The abnormality score indicates how different the last monthly change of relocations (from communal section a to a communal section b) is, compared to the median monthly change of relocations estimated during the 12 preceding months (baseline period), measured in median absolute deviations (i.e. it is the modified z-score of the relocation monthly change). It describes how unusual the last monthly change in the number of relocations from a communal section a to a communal section b is, compared to the monthly changes estimated during the 12 preceding months.\n\nA positive value for this indicator greater than 3 indicates an abnormal increase in the number of relocations (a statistical outlier); a value less than -3 indicates an abnormal decrease in relocations. Abnormality scores above 6 in absolute value are more likely to correspond to technical issues, particularly in the absence of known disrupting events (disruption of mobility and/or phone usage).\n\nThe abnormality score is not available for January to March 2020 included due to a too short baseline period to be reliable.", + "label_fr": "Abnormality score", + "description_fr": "Describes how unusual the last monthly change in the number of relocations from a communal section to another is, compared to the monthly changes estimated during the 12 preceding months.", + "method_fr": "The abnormality score indicates how different the last monthly change of relocations (from communal section a to a communal section b) is, compared to the median monthly change of relocations estimated during the 12 preceding months (baseline period), measured in median absolute deviations (i.e. it is the modified z-score of the relocation monthly change). It describes how unusual the last monthly change in the number of relocations from a communal section a to a communal section b is, compared to the monthly changes estimated during the 12 preceding months.\n\nA positive value for this indicator greater than 3 indicates an abnormal increase in the number of relocations (a statistical outlier); a value less than -3 indicates an abnormal decrease in relocations. Abnormality scores above 6 in absolute value are more likely to correspond to technical issues, particularly in the absence of known disrupting events (disruption of mobility and/or phone usage).\n\nThe abnormality score is not available for January to March 2020 included due to a too short baseline period to be reliable.", "scale": "diverging", "decimals": 2, - "min_value": -6, - "max_value": 6, + "min_value": -25, + "max_value": 25, "bins": [ { "min": -3, "max": 3, "width": "2%" }, { "min": -6, "max": -3, "width": "20%" }, @@ -283,11 +285,11 @@ "order": 1, "flowgeek_url": "https://www.flowgeek.org/methods/calculating-mobility-indicators/presence-indicators#presence", "label": "Presence", - "description": "Estimates the number of people who are present in a given area on the day(s) selected by the user.", - "method": "The presence indicator estimates the number of people who are present in a given area at some point on the day(s) selected by the user.\n\nWe calculate the presence indicator from the number of unique subscribers who have been active in a given area on the day(s) selected by the user.\n\nSubscribers are determined to have been present in an area on a given day if they have a network event (e.g. a call) routed by a cell tower in that area.", + "description": "The estimated number of people present in each communal section on the current day (residents + travellers).", + "method": "The estimated number of people present in each communal section on the current day. It includes residents present in their own communal section as well as travellers, and people can be present in several communal sections during the same day.\n\nWe calculate the presence indicator from the difference in the count of Digicel subscribers whose call(s) were routed by a cell tower in a communal section on the current day and the median estimated presence during the baseline period (August 2020 to September 2021). We then scale this change in presence and add it to existing population estimates. \n\nNOTE: We use the term ‘subscriber’ to refer to pseudonymised MSISDNs (hashed phone numbers). This means that two ‘subscribers’ (phone numbers) may be the same individual, if that person uses more than one phone number, or one ‘subscriber’ may represent several individuals, if a phone number is actively used by several people.\n\nSubscribers are determined to have been present in a communal section on the selected day if they have a call routed by a cell tower in that area. The presence estimate is derived from changes in the number of subscribers present compared to a baseline, rather than from the count of subscribers present.", "label_fr": "Présence", - "description_fr": "Estime le nombre de personnes présentes dans une zone donnée le ou les jours sélectionnés par l'utilisateur.", - "method_fr": "L'indicateur de présence estime le nombre de personnes présentes dans une zone donnée à un moment donné du ou des jours sélectionnés par l'utilisateur.\n\nNous calculons l'indicateur de présence à partir du nombre d'abonnés uniques qui ont été actifs dans une zone donnée le ou les jours choisis par l'utilisateur.\n\nLes abonnés sont considérés comme ayant été présents dans une zone un jour donné lorsqu'un événement réseau (par exemple un appel) est acheminé par une tour de téléphonie cellulaire dans cette zone.", + "description_fr": "The estimated number of people present in each communal section on the current day (residents + travellers).", + "method_fr": "The estimated number of people present in each communal section on the current day. It includes residents present in their own communal section as well as travellers, and people can be present in several communal sections during the same day.\n\nWe calculate the presence indicator from the difference in the count of Digicel subscribers whose call(s) were routed by a cell tower in a communal section on the current day and the median estimated presence during the baseline period (August 2020 to September 2021). We then scale this change in presence and add it to existing population estimates. \n\nNOTE: We use the term ‘subscriber’ to refer to pseudonymised MSISDNs (hashed phone numbers). This means that two ‘subscribers’ (phone numbers) may be the same individual, if that person uses more than one phone number, or one ‘subscriber’ may represent several individuals, if a phone number is actively used by several people.\n\nSubscribers are determined to have been present in a communal section on the selected day if they have a call routed by a cell tower in that area. The presence estimate is derived from changes in the number of subscribers present compared to a baseline, rather than from the count of subscribers present.", "scale": "sequential", "decimals": 0, "min_value": 0, @@ -298,12 +300,12 @@ "indicator_id": "presence.presence_perKm2", "order": 2, "flowgeek_url": "https://www.flowgeek.org/methods/calculating-mobility-indicators/presence-indicators#presence-km2", - "label": "Presence per square km", - "description": "Estimates the average number of people present per square kilometre of an area during the day(s) selected by the user.", - "method": "The presence per square km estimates the average number of people present per square kilometre of an area during the day(s) selected by the user.\n\nThe indicator is calculated from the presence indicator and the geographic size of the area.\n\nSubscribers are determined to have been present in an area on a given day if they have a network event (e.g. a call) routed by a cell tower in that area.", + "label": "Presence per km²", + "description": "The estimated number of people present in the communal section on the current day, per square kilometre.", + "method": "We estimate the presence per km2 by dividing the number of people present in the communal section a for the current day d by the area of that communal section, giving the spatial density of people present. \n\nSubscribers are determined to have been present in a communal section on the selected day if they have a call routed by a cell tower in that area. The presence estimate is derived from changes in the number of subscribers present compared to a baseline, rather than from the count of subscribers present.", "label_fr": "Présence par km²", - "description_fr": "Estime le nombre moyen de personnes présentes par kilomètre carré d'une zone pendant le ou les jours sélectionnés par l'utilisateur.", - "method_fr": "La présence par km² estime le nombre moyen de personnes présentes par kilomètre carré d'une zone pendant le ou les jours sélectionnés par l'utilisateur.\n\nL'indicateur est calculé à partir de l'indicateur de présence et de la taille géographique de la zone.\n\nLes abonnés sont considérés comme ayant été présents dans une zone un jour donné lorsqu'un événement réseau (par exemple un appel) est acheminé par une tour de téléphonie cellulaire dans cette zone.", + "description_fr": "The estimated number of people present in the communal section on the current day, per square kilometre.", + "method_fr": "We estimate the presence per km2 by dividing the number of people present in the communal section a for the current day d by the area of that communal section, giving the spatial density of people present. \n\nSubscribers are determined to have been present in a communal section on the selected day if they have a call routed by a cell tower in that area. The presence estimate is derived from changes in the number of subscribers present compared to a baseline, rather than from the count of subscribers present.", "scale": "sequential", "decimals": 2, "min_value": 0, @@ -314,12 +316,12 @@ "indicator_id": "presence.presence_diffwithref", "order": 3, "flowgeek_url": "https://www.flowgeek.org/methods/calculating-mobility-indicators/presence-indicators#presence-difference", - "label": "Presence difference", - "description": "Estimates the difference in the number of people who are present in an area during the day(s) selected by the user compared to the number present during a reference period.", - "method": "The presence difference indicator estimates the difference in the number of people who are present in an area during the day(s) selected by the user compared to the number present during a reference period.\n\nThe indicator is calculated from the presence indicator and the baseline number of people during a reference period.\n\nIf the number of people present in the area has increased, the indicator will have a positive value; if the number has decreased, the value will be negative.\n\nSubscribers are determined to have been present in an area on a given day if they have a network event (e.g. a call) routed by a cell tower in that area.", + "label": "Change in presence", + "description": "Difference in the number of people present in the communal section, on the current day, and the number of people present on the first day of available data. (Trial metric soon to be updated.)", + "method": "Difference in the number of people present in the communal section, on the current day, and the number of people present on the first day of available data.\n\nThe change in presence is calculated as the difference in the number of people present in the communal section a on the current day d with the first day of available data.\n\nIf the number of people present in the area has increased, the indicator will have a positive value; if the number has decreased, the value will be negative.\n\nThis is a trial metric. It will soon be replaced by a metric comparing the number of people present in the communal section on the current day, with the median number of people present during a relevant baseline period (such as the preceding calendar year). This will help contextualise and interpret the presence value on a given day.\n\nSubscribers are determined to have been present in a communal section on the selected day if they have a call routed by a cell tower in that area. The presence estimate is derived from changes in the number of subscribers present compared to a baseline, rather than from the count of subscribers present.", "label_fr": "Différence de présence", - "description_fr": "Estime la différence entre le nombre de personnes présentes dans une zone pendant le ou les jours sélectionnés par l'utilisateur et le nombre de personnes présentes pendant une période de référence.", - "method_fr": "L'indicateur de différence de présence estime la différence entre le nombre de personnes présentes dans une zone pendant le ou les jours sélectionnés par l'utilisateur et le nombre de personnes présentes pendant une période de référence.\n\nL'indicateur est calculé à partir de l'indicateur de présence et du nombre de référence de personnes pendant une période de référence.\n\nSi le nombre de personnes présentes dans la zone a augmenté, l'indicateur aura une valeur positive ; si le nombre a diminué, la valeur sera négative.\n\nLes abonnés sont considérés comme ayant été présents dans une zone un jour donné lorsqu'un événement réseau (par exemple un appel) est acheminé par une tour de téléphonie cellulaire dans cette zone.", + "description_fr": "Difference in the number of people present in the communal section, on the current day, and the number of people present on the first day of available data. (Trial metric soon to be updated.)", + "method_fr": "Difference in the number of people present in the communal section, on the current day, and the number of people present on the first day of available data.\n\nThe change in presence is calculated as the difference in the number of people present in the communal section a on the current day d with the first day of available data.\n\nIf the number of people present in the area has increased, the indicator will have a positive value; if the number has decreased, the value will be negative.\n\nThis is a trial metric. It will soon be replaced by a metric comparing the number of people present in the communal section on the current day, with the median number of people present during a relevant baseline period (such as the preceding calendar year). This will help contextualise and interpret the presence value on a given day.\n\nSubscribers are determined to have been present in a communal section on the selected day if they have a call routed by a cell tower in that area. The presence estimate is derived from changes in the number of subscribers present compared to a baseline, rather than from the count of subscribers present.", "scale": "diverging", "decimals": 0, "min_value": null, @@ -330,44 +332,44 @@ "indicator_id": "presence.presence_pctchangewithref", "order": 4, "flowgeek_url": "https://www.flowgeek.org/methods/calculating-mobility-indicators/presence-indicators#presence-difference-percentage-change", - "label": "Percent change in presence difference", - "description": "Estimates the change in the number of people present in an area during the day(s) selected by the user relative to the number of people present in the area in the reference period, expressed as a percentage.", - "method": "The percentage change in presence indicator estimates the change in the number of people present in an area during the day(s) selected by the user relative to the number of people present in the area in the reference period. The difference is expressed as a percentage of a baseline value calculated for the reference period.\n\nThe indicator is calculated from the presence indicator and the baseline number of people during a reference period.\n\nIf the number of people present in the area has increased, the indicator will have a positive value; if the number of people present in the area has decreased, the value will be negative.\n\nSubscribers are determined to have been present in an area on a given day if they have a network event (e.g. a call) routed by a cell tower in that area.", - "label_fr": "Variation en pourcentage de la différence de présence", - "description_fr": "Estime la variation du nombre de personnes présentes dans une zone au cours du ou des jours sélectionnés par l'utilisateur par rapport au nombre de personnes présentes dans la zone pendant la période de référence, exprimée en pourcentage.", - "method_fr": "L'indicateur de variation de présence en pourcentage estime la variation du nombre de personnes présentes dans une zone pendant le ou les jours sélectionnés par l'utilisateur par rapport au nombre de personnes présentes dans la zone pendant la période de référence. La différence est exprimée en pourcentage d'une valeur de référence calculée pour la période de référence.\n\nL'indicateur est calculé à partir de l'indicateur de présence et du nombre de référence de personnes pendant une période de référence.\n\nSi le nombre de personnes présentes dans la zone a augmenté, l'indicateur aura une valeur positive ; si le nombre de personnes présentes dans la zone a diminué, la valeur sera négative.\n\nLes abonnés sont considérés comme ayant été présents dans une zone un jour donné lorsqu'un événement réseau (par exemple un appel) est acheminé par une tour de téléphonie cellulaire dans cette zone.", + "label": "Relative change in presence (%)", + "description": "Percent change in the number of people present in the communal section, on the current day, compared to the number of people present on the first day of available data. (Trial metric soon to be updated.)", + "method": "Percent change in the number of people present in the communal section, on the current day, compared to the number of people present on the first day for which we have a presence estimate for that communal section \n\nIf the number of people present in the area has increased, the indicator will have a positive value; if the number of people present in the area has decreased, the value will be negative.\n\nThis is a trial metric. It will soon be updated with a metric on the percent change between presence on the current day and the median presence during a baseline period (such as the preceding calendar year). This will help contextualise and interpret the presence value on a given day.\n\n\nSubscribers are determined to have been present in a communal section on the selected day if they have a call routed by a cell tower in that area. The presence estimate is derived from changes in the number of subscribers present compared to a baseline, rather than from the count of subscribers present.", + "label_fr": "Relative change in presence (%)", + "description_fr": "Percent change in the number of people present in the communal section, on the current day, compared to the number of people present on the first day of available data. (Trial metric soon to be updated.)", + "method_fr": "Percent change in the number of people present in the communal section, on the current day, compared to the number of people present on the first day for which we have a presence estimate for that communal section \n\nIf the number of people present in the area has increased, the indicator will have a positive value; if the number of people present in the area has decreased, the value will be negative.\n\nThis is a trial metric. It will soon be updated with a metric on the percent change between presence on the current day and the median presence during a baseline period (such as the preceding calendar year). This will help contextualise and interpret the presence value on a given day.\n\n\nSubscribers are determined to have been present in a communal section on the selected day if they have a call routed by a cell tower in that area. The presence estimate is derived from changes in the number of subscribers present compared to a baseline, rather than from the count of subscribers present.", "scale": "diverging", "decimals": 2, - "min_value": null, - "max_value": null + "min_value": -50, + "max_value": 50 }, { "category_id": "presence", "indicator_id": "presence.abnormality", "order": 5, "flowgeek_url": "https://www.flowgeek.org/methods/calculating-mobility-indicators/presence-indicators#presence-abnormality", - "label": "Abnormality", - "description": "Measures the deviation of the number of people present in a given area during the day(s) selected by the user relative to a reference period, expressed as an abnormality score (z-score).", - "method": "The presence abnormality indicator measures the deviation of the number of people present in a given area during the day(s) selected by the user relative to a reference period, expressed as a z-score.\n\nA positive value for this indicator greater than 3 indicates a statistically significant increase in the number of people present in a given area; a value less than -3 indicates a statistically significant decrease in presence.\n\nThis indicator describes how unusual the number of people in an area is, given the amount of variation observed during the reference period. Higher absolute values indicate greater deviation from the normal variation in presence, and therefore greater probability that the change is meaningful. Such changes may be associated with specific events or may be caused by technical issues. Very large abnormalities (absolute values greater than 6), however, may also be indicative of a technical issue.\n\nThe indicator is calculated from the presence difference indicator and the mean absolute deviation in presence during a reference period.\n\nSubscribers are determined to have been present in an area on a given day if they have a network event (e.g. a call) routed by a cell tower in that area.", - "label_fr": "Anomalie", - "description_fr": "Mesure l'écart du nombre de personnes présentes dans une zone donnée pendant le ou les jours sélectionnés par l'utilisateur par rapport à une période de référence, exprimé sous la forme d'un score d'anomalie (score z).", - "method_fr": "L'indicateur d'anomalie de présence mesure l'écart du nombre de personnes présentes dans une zone donnée pendant le ou les jours sélectionnés par l'utilisateur par rapport à une période de référence, exprimé sous la forme d'un score z.\n\nPour cet indicateur, une valeur positive supérieure à 3 indique une augmentation statistiquement significative du nombre de personnes présentes dans une zone donnée ; une valeur inférieure à -3 indique une diminution statistiquement significative de la présence.\n\nCet indicateur décrit l'ampleur du caractère inhabituel du nombre de personnes dans une zone, compte tenu de l'ampleur de la variation observée pendant la période de référence. Des valeurs absolues plus élevées indiquent un plus grand écart par rapport à la variation normale de présence, et donc une plus grande probabilité que le changement soit significatif. Des changements de la sorte pourraient être associés à des événements spécifiques ou causés par des problèmes techniques. Toutefois, des anomalies très importantes (valeurs absolues supérieures à 6) pourraient également indiquer un problème technique.\n\nL'indicateur est calculé à partir de l'indicateur de différence de présence et de l'écart absolu moyen de présence pendant une période de référence.\n\nLes abonnés sont considérés comme ayant été présents dans une zone un jour donné lorsqu'un événement réseau (par exemple un appel) est acheminé par une tour de téléphonie cellulaire dans cette zone.", + "label": "Abnormality score", + "description": "Describes how unusual the last daily change in presence in a communal section is, compared to the daily changes estimated during the 365 preceding days.", + "method": "TThe abnormality score indicates how different the last daily change in presence per communal section (between the current day and the previous day) is, compared to the median daily change of presence estimated during the 365 preceding days (the baseline period), measured in median absolute deviations.\n\nIt describes how unusual the last daily change in presence in a communal section is, compared to the daily changes estimated during the 365 preceding days. \n\nA positive value for this indicator greater than 3 indicates an abnormal increase in the number of people present in a given area; a value less than -3 indicates an abnormal decrease in presence. Abnormality scores above 6 in absolute value are more likely to correspond to technical issues, particularly in the absence of known disrupting events (disruption of mobility and/or phone usage).\n\nSubscribers are determined to have been present in a communal section on the selected day if they have a call routed by a cell tower in that area. The presence estimate is derived from changes in the number of subscribers present compared to a baseline, rather than from the count of subscribers present.", + "label_fr": "Abnormality score", + "description_fr": "Describes how unusual the last daily change in presence in a communal section is, compared to the daily changes estimated during the 365 preceding days.", + "method_fr": "The abnormality score indicates how different the last daily change in presence per communal section (between the current day and the previous day) is, compared to the median daily change of presence estimated during the 365 preceding days (the baseline period), measured in median absolute deviations.\n\nIt describes how unusual the last daily change in presence in a communal section is, compared to the daily changes estimated during the 365 preceding days. \n\nA positive value for this indicator greater than 3 indicates an abnormal increase in the number of people present in a given area; a value less than -3 indicates an abnormal decrease in presence. Abnormality scores above 6 in absolute value are more likely to correspond to technical issues, particularly in the absence of known disrupting events (disruption of mobility and/or phone usage).\n\nSubscribers are determined to have been present in a communal section on the selected day if they have a call routed by a cell tower in that area. The presence estimate is derived from changes in the number of subscribers present compared to a baseline, rather than from the count of subscribers present.", "scale": "diverging", "decimals": 2, - "min_value": null, - "max_value": null + "min_value": -25, + "max_value": 25 }, { "category_id": "presence", "indicator_id": "presence.trips_in", "order": 6, "flowgeek_url": "https://www.flowgeek.org/methods/calculating-mobility-indicators/presence-indicators#trips-in", - "label": "Trips in", - "description": "Estimates the number of trips into an area from any other areas during the day(s) selected by the user.", - "method": "The trips in indicator estimates the number of trips into an area from any other areas during the day(s) selected by the user. When data shows multiple trips between areas in a single day for a given subscriber (from A to B, then B to C), then the indicator captures all trips (AB, BC).\n\nUnlike the travellers in indicator, which only counts each unique subscriber once, this indicator includes multiple trips into an area by the same subscriber.\n\nWe calculate the trips in indicator from the sum of the counts of subscribers who were present in an area of interest after being present in any other area during the day(s) selected by the user.\n\nSubscribers are determined to have been present in an area on a given day if they have a network event (e.g. a call) routed by a cell tower in that area.", - "label_fr": "Déplacements entrants", - "description_fr": "Estime le nombre de déplacements dans une zone à partir d'autres zones pendant le ou les jours sélectionnés par l'utilisateur.", - "method_fr": "L'indicateur des déplacements entrants estime le nombre de déplacements dans une zone à partir d'autres zones pendant le ou les jours sélectionnés par l'utilisateur. Lorsque les données indiquent des déplacements multiples entre les zones au cours d'une même journée pour un abonné donné (de A à B, puis de B à C), l'indicateur prend en compte tous les déplacements (AB, BC).\n\nÀ la différence de l'indicateur des voyageurs entrants, qui ne compte qu'une seule fois chaque abonné unique, cet indicateur inclut les déplacements multiples dans une zone par le même abonné.\n\nNous calculons l'indicateur des déplacements entrants à partir de la somme des comptages des abonnés qui étaient présents dans une zone d'intérêt après avoir été présents dans une autre zone pendant le ou les jours sélectionnés par l'utilisateur.\n\nLes abonnés sont considérés comme ayant été présents dans une zone un jour donné lorsqu'un événement réseau (par exemple un appel) est acheminé par une tour de téléphonie cellulaire dans cette zone.", + "label": "Total incoming", + "description": "The estimated number of incoming travellers to a communal section a, from any other communal section, during the current day.", + "method": "The estimated number of incoming travellers to a communal section a, from any other communal section, during the current day.\n\nThe estimated number of travellers to a communal section per day is derived from the count of Digicel subscribers (MSISDNs) who made a call from a different communal section from the one selected, and then made an immediately subsequent call from the selected communal section during the day. This is then scaled to the population, however not in a representative manner. (See About the indicators PDF)\n\nNOTE: Travellers to a communal section per day may be counted several times if they have entered the communal section from several other communal sections. However, travellers doing multiple trips to the communal section from a single communal section are only counted once. This is another issue with this type of experimental indicator which we are working to resolve. \n\nNOTE: We use the term ‘subscriber’ to refer to pseudonymised MSISDNs (hashed phone numbers). This means that two ‘subscribers’ (phone numbers) may be the same individual, if that person uses more than one phone number, or one ‘subscriber’ may represent several individuals, if a phone number is actively used by several people.", + "label_fr": "Total incoming", + "description_fr": "The estimated number of incoming travellers to a communal section a, from any other communal section, during the current day.", + "method_fr": "The estimated number of incoming travellers to a communal section a, from any other communal section, during the current day.\n\nThe estimated number of travellers to a communal section per day is derived from the count of Digicel subscribers (MSISDNs) who made a call from a different communal section from the one selected, and then made an immediately subsequent call from the selected communal section during the day. This is then scaled to the population, however not in a representative manner. (See About the indicators PDF)\n\nNOTE: Travellers to a communal section per day may be counted several times if they have entered the communal section from several other communal sections. However, travellers doing multiple trips to the communal section from a single communal section are only counted once. This is another issue with this type of experimental indicator which we are working to resolve. \n\nNOTE: We use the term ‘subscriber’ to refer to pseudonymised MSISDNs (hashed phone numbers). This means that two ‘subscribers’ (phone numbers) may be the same individual, if that person uses more than one phone number, or one ‘subscriber’ may represent several individuals, if a phone number is actively used by several people.", "scale": "sequential", "decimals": 0, "min_value": 0, @@ -378,12 +380,12 @@ "indicator_id": "presence.trips_out", "order": 7, "flowgeek_url": "https://www.flowgeek.org/methods/calculating-mobility-indicators/presence-indicators#trips-out", - "label": "Trips out", - "description": "Estimates the number of trips from an area to any other area during the day(s) selected by the user.", - "method": "The trips out indicator estimates the number of trips from an area to any other area during the day(s) selected by the user. When data shows multiple trips in a single day for a given subscriber (from A to B, then B to C), then the indicator captures all trips (AB, BC).\n\nUnlike the travellers out indicator which only counts each unique subscriber once, this indicator also includes multiple trips out of an area by the same subscriber.\n\nWe calculate the trips in indicator from the sum of the counts of subscribers who were present in any other area after being present in an area of interest during the day(s) selected by the user.\n\nSubscribers are determined to have been present in an area on a given day if they have a network event (e.g. a call) routed by a cell tower in that area.", - "label_fr": "Déplacements sortants", - "description_fr": "Estime le nombre de déplacements d'une zone vers une autre zone pendant le ou les jours sélectionnés par l'utilisateur.", - "method_fr": "L'indicateur de déplacements sortants estime le nombre de déplacements d'une zone vers une autre zone au cours du ou des jours sélectionnés par l'utilisateur. Lorsque les données indiquent plusieurs déplacements dans une même journée pour un abonné donné (de A à B, puis de B à C), l'indicateur prend en compte tous les déplacements (AB, BC).\n\nÀ la différence de l'indicateur de voyageurs sortants qui ne compte qu'une seule fois chaque abonné unique, cet indicateur inclut également les déplacements multiples d'un même abonné hors d'une zone.\n\nNous calculons l'indicateur des déplacements entrants à partir de la somme des comptages des abonnés qui étaient présents dans une autre zone après avoir été présents dans une zone d'intérêt pendant le ou les jours sélectionnés par l'utilisateur.\n\nLes abonnés sont considérés comme ayant été présents dans une zone un jour donné lorsqu'un événement réseau (par exemple un appel) est acheminé par une tour de téléphonie cellulaire dans cette zone.", + "label": "Total outgoing", + "description": "The estimated number of outgoing travellers from communal section a to any other communal section, during the current day.", + "method": "The estimated number of outgoing travellers from communal section a to any other communal section, during the current day.\n\nThe estimated number of travellers from a communal section, per day, is derived from the count of Digicel subscribers (MSISDNs) who made a call from the selected communal section and made an immediately subsequent call from another communal section, during the day.\n\nNOTE: Travellers from a communal section per day may be counted several times if they have left the communal section to go to several other communal sections. However travellers doing multiple trips from the communal section to a single communal section are only counted once. This is another issue with this type of experimental indicator which we are working to resolve.\n\nNOTE: We use the term ‘subscriber’ to refer to pseudonymised MSISDNs (hashed phone numbers). This means that two ‘subscribers’ (phone numbers) may be the same individual, if that person uses more than one phone number, or one ‘subscriber’ may represent several individuals, if a phone number is actively used by several people.", + "label_fr": "Total outgoing", + "description_fr": "The estimated number of outgoing travellers from communal section a to any other communal section, during the current day.", + "method_fr": "The estimated number of outgoing travellers from communal section a to any other communal section, during the current day.\n\nThe estimated number of travellers from a communal section, per day, is derived from the count of Digicel subscribers (MSISDNs) who made a call from the selected communal section and made an immediately subsequent call from another communal section, during the day.\n\nNOTE: Travellers from a communal section per day may be counted several times if they have left the communal section to go to several other communal sections. However travellers doing multiple trips from the communal section to a single communal section are only counted once. This is another issue with this type of experimental indicator which we are working to resolve.\n\nNOTE: We use the term ‘subscriber’ to refer to pseudonymised MSISDNs (hashed phone numbers). This means that two ‘subscribers’ (phone numbers) may be the same individual, if that person uses more than one phone number, or one ‘subscriber’ may represent several individuals, if a phone number is actively used by several people.", "scale": "sequential", "decimals": 0, "min_value": 0, @@ -396,11 +398,11 @@ "order": 1, "flowgeek_url": "https://www.flowgeek.org/methods/calculating-mobility-indicators/movement-indicators#travellers", "label": "Travellers", - "description": "Estimates the number of people visiting area B after being present in area A during the day(s) selected by the user.", - "method": "The travellers indicator estimates the number of people visiting area B after being present in area A (i.e. travelled from A to B) during the day(s) selected by the user.\n\nWe calculate the travellers indicator from the number of subscribers who were present in area B after being present in area A during the day(s) selected by the user.\n\nSubscribers are determined to have been present in an area on a given day if they have a network event (e.g. a call) routed by a cell tower in that area.", + "description": "Estimated number of people who visited communal section a then communal section b within the same day.", + "method": "Estimated number of people who visited communal section a then communal section b within the same day.\n\nWe calculate the estimated number of people travelling from a to b per day from the count of Digicel subscribers (MSISDNs) who made a call from the communal section a and made an immediately subsequent call from the communal section b, during the day d. This is then scaled to the population, however not in a representative manner. (See About the indicators PDF)\n\nA subscriber travelling (and calling) from A to B to C during the same day will be counted as a traveller from A to B and from B to C but not from A to C, therefore long travels may not be captured by this estimate (if calls are made along the way). \n\nNOTE: We use the term ‘subscriber’ to refer to pseudonymised MSISDNs (hashed phone numbers). This means that two ‘subscribers’ (phone numbers) may be the same individual, if that person uses more than one phone number, or one ‘subscriber’ may represent several individuals, if a phone number is actively used by several people.", "label_fr": "Voyageurs", - "description_fr": "Estime le nombre de personnes qui visitent la zone B après avoir été présentes dans la zone A pendant le ou les jours sélectionnés par l'utilisateur.", - "method_fr": "L'indicateur de voyageurs estime le nombre de personnes qui visitent la zone B après avoir été présentes dans la zone A (c'est-à-dire avoir voyagé de A à B) pendant le ou les jours sélectionnés par l'utilisateur.\n\nNous calculons l'indicateur de voyageurs à partir du nombre d'abonnés qui étaient présents dans la zone B après avoir été présents dans la zone A au cours du ou des jours sélectionnés par l'utilisateur.\n\nLes abonnés sont considérés comme ayant été présents dans une zone un jour donné lorsqu'un événement réseau (par exemple un appel) est acheminé par une tour de téléphonie cellulaire dans cette zone.", + "description_fr": "Estimated number of people who visited communal section a then communal section b within the same day.", + "method_fr": "Estimated number of people who visited communal section a then communal section b within the same day.\n\nWe calculate the estimated number of people travelling from a to b per day from the count of Digicel subscribers (MSISDNs) who made a call from the communal section a and made an immediately subsequent call from the communal section b, during the day d. This is then scaled to the population, however not in a representative manner. (See About the indicators PDF)\n\nA subscriber travelling (and calling) from A to B to C during the same day will be counted as a traveller from A to B and from B to C but not from A to C, therefore long travels may not be captured by this estimate (if calls are made along the way). \n\nNOTE: We use the term ‘subscriber’ to refer to pseudonymised MSISDNs (hashed phone numbers). This means that two ‘subscribers’ (phone numbers) may be the same individual, if that person uses more than one phone number, or one ‘subscriber’ may represent several individuals, if a phone number is actively used by several people.", "scale": "sequential", "decimals": 0, "min_value": 0, @@ -411,12 +413,12 @@ "indicator_id": "movements.travellers_diffwithref", "order": 2, "flowgeek_url": "https://www.flowgeek.org/methods/calculating-mobility-indicators/movement-indicators#travellers-difference", - "label": "Travellers difference", - "description": "Estimates the change in the number of people travelling from area A to B during a period of time compared to the baseline number of travellers from A to B during a reference period.", - "method": "The travellers indicator estimates the number of people visiting area B after being present in area A (i.e. travelled from A to B) during the day(s) selected by the user.\n\nWe calculate the travellers indicator from the number of subscribers who were present in area B after being present in area A during the day(s) selected by the user.\n\nSubscribers are determined to have been present in an area on a given day if they have a network event (e.g. a call) routed by a cell tower in that area.", + "label": "Change in travellers", + "description": "Difference in the number of people who travelled from communal section a to communal section b during the current day and the number of travellers from a to b during the first day of available data (trial metric soon to be updated)", + "method": "Difference in the number of people who travelled from communal section a to communal section b during the current day and the number of travellers from a to b during the first day of available data.\n\nThis is a trial metric - it will soon be updated with a metric on the change between travellers during the current day and the median travellers during a baseline period (such as the preceding calendar year).", "label_fr": "Différence de voyageurs", - "description_fr": "Estime la variation du nombre de personnes voyageant de la zone A à B pendant une période donnée par rapport au nombre de base de voyageurs de A à B pendant une période de référence.", - "method_fr": "L'indicateur de différence de voyageurs estime la variation du nombre de personnes voyageant de la zone A à la zone B pendant une période donnée par rapport au nombre de voyageurs de référence pendant une période de référence.\n\nSi le nombre de voyageurs a augmenté, l'indicateur aura une valeur positive ; si le nombre de voyageurs a diminué, la valeur sera négative.\n\nNous calculons l'indicateur de différence de voyageurs à partir de l'indicateur de voyageurs et du nombre de référence de voyageurs entre des paires de zones pendant une période de référence.\n\nLes abonnés sont considérés comme ayant été présents dans une zone un jour donné lorsqu'un événement réseau (par exemple un appel) est acheminé par une tour de téléphonie cellulaire dans cette zone.", + "description_fr": "Difference in the number of people who travelled from communal section a to communal section b during the current day and the number of travellers from a to b during the first day of available data (trial metric soon to be updated)", + "method_fr": "Difference in the number of people who travelled from communal section a to communal section b during the current day and the number of travellers from a to b during the first day of available data.\n\nThis is a trial metric - it will soon be updated with a metric on the change between travellers during the current day and the median travellers during a baseline period (such as the preceding calendar year).", "scale": "diverging", "decimals": 0, "min_value": null, @@ -427,32 +429,32 @@ "indicator_id": "movements.travellers_pctchangewithref", "order": 3, "flowgeek_url": "https://www.flowgeek.org/methods/calculating-mobility-indicators/movement-indicators#travellers-difference-percentage-change", - "label": "Percent change in travellers difference", - "description": "Estimates the change in the number of people travelling from area A to B during the day(s) selected by the user relative to the baseline number of travellers from A to B in the reference period, expressed as a percentage.", - "method": "The percentage change in travellers indicator estimates the change in the number of people travelling from area A to area B during the day(s) selected by the user relative to the baseline number of travellers from A to B in the reference period. The difference is expressed as a percentage of a baseline value calculated for the reference period.\n\nIf the number of travellers has increased, the indicator will have a positive value; if the number of travellers has decreased, the value will be negative.\n\nWe calculate the percentage change in travellers difference indicator from the travellers indicator and the baseline number of travellers between pairs of areas during the day(s) selected by the user.\n\nSubscribers are determined to have been present in an area on a given day if they have a network event (e.g. a call) routed by a cell tower in that area.", - "label_fr": "Variation en pourcentage de la différence de voyageurs", - "description_fr": "Estime la variation du nombre de personnes voyageant de la zone A à B pendant le ou les jours sélectionnés par l'utilisateur par rapport au nombre de référence de voyageurs de A à B pendant la période de référence, exprimée en pourcentage.", - "method_fr": "La variation en pourcentage de l'indicateur de voyageurs estime la variation du nombre de personnes voyageant de la zone A à B pendant le ou les jours sélectionnés par l'utilisateur par rapport au nombre de référence de voyageurs de A à B pendant la période de référence. La différence est exprimée en pourcentage d'une valeur de référence calculée pour la période de référence.\n\nSi le nombre de voyageurs a augmenté, l'indicateur aura une valeur positive ; si le nombre de voyageurs a diminué, la valeur sera négative.\n\nNous calculons le pourcentage de variation de l'indicateur de différence de voyageurs à partir de l'indicateur de voyageurs et du nombre de voyageurs de référence entre les paires de zones pendant le ou les jours sélectionnés par l'utilisateur.\n\nLes abonnés sont considérés comme ayant été présents dans une zone un jour donné lorsqu'un événement réseau (par exemple un appel) est acheminé par une tour de téléphonie cellulaire dans cette zone.", + "label": "Relative change in travellers (%)", + "description": "Percent change in the number of people who travelled from communal section a to communal section b during the current day and the number of travellers from a to b during the first day of available data (trial metric soon to be updated).", + "method": "Percent change in the number of people who travelled from communal section a to communal section b during the current day and the number of travellers from a to b during the first day of available data.\n\nThis is a trial metric - it will soon be updated with a metric on the change between travellers during the current day and the median travellers during a baseline period (such as the preceding calendar year).", + "label_fr": "Relative change in travellers (%)", + "description_fr": "Percent change in the number of people who travelled from communal section a to communal section b during the current day and the number of travellers from a to b during the first day of available data (trial metric soon to be updated).", + "method_fr": "Percent change in the number of people who travelled from communal section a to communal section b during the current day and the number of travellers from a to b during the first day of available data.\n\nThis is a trial metric - it will soon be updated with a metric on the change between travellers during the current day and the median travellers during a baseline period (such as the preceding calendar year).", "scale": "diverging", "decimals": 2, - "min_value": null, - "max_value": null + "min_value": -50, + "max_value": 50 }, { "category_id": "movements", "indicator_id": "movements.abnormality", "order": 4, "flowgeek_url": "https://www.flowgeek.org/methods/calculating-mobility-indicators/movement-indicators#travellers-abnormality", - "label": "Abnormality", - "description": "Measures the deviation in the estimated number of people travelling from area A to B during the day(s) selected by the user from the numbers of travellers from A to B estimated during a reference period, expressed as a z-score.", - "method": "The travellers abnormality indicator measures the deviation in the estimated number of people travelling from area A to area B during the day(s) selected by the user from the numbers of travellers from A to B estimated during a reference period, expressed as a z-score.\n\nA positive value for this indicator greater than 3 indicates a statistically significant increase in the number of travellers; a value less than -3 indicates a statistically significant decrease.\n\nThis indicator describes how unusual the number of travellers from area A to area B is, given the amount of variation observed during the reference period. Higher absolute values indicate greater deviation from the normal variation in numbers of travellers, and therefore greater probability that the change is meaningful. Such changes may be associated with specific events or may be caused by technical issues. Very large abnormalities (absolute values greater than 6), however, may also be indicative of a technical issue.\n\nWe calculate the travellers abnormality indicator using the travellers difference indicator and the mean absolute deviation in the number of travellers between pairs of areas during a reference period.\n\nSubscribers are determined to have been present in an area on a given day if they have a network event (e.g. a call) routed by a cell tower in that area.", - "label_fr": "Anomalie", - "description_fr": "Mesure l'écart entre le nombre estimé de personnes voyageant de la zone A à B pendant le ou les jours sélectionnés par l'utilisateur et le nombre de voyageurs de A à B estimé pendant une période de référence, exprimé sous la forme d'un score z.", - "method_fr": "L'indicateur d'anomalie des voyageurs mesure l'écart entre le nombre estimé de personnes voyageant de la zone A à la zone B pendant le ou les jours sélectionnés par l'utilisateur et le nombre de voyageurs de A à B estimé pendant une période de référence, exprimé sous la forme d'un score z. \n\nPour cet indicateur, une valeur positive supérieure à 3 indique une augmentation statistiquement significative du nombre de voyageurs ; une valeur inférieure à -3 indique une diminution statistiquement significative.\n\nCet indicateur décrit l'ampleur du caractère inhabituel du nombre de voyageurs de la zone A vers la zone B, compte tenu de l'ampleur de la variation observée pendant la période de référence. Des valeurs absolues plus élevées indiquent un plus grand écart par rapport à la variation normale du nombre de voyageurs, et donc une plus grande probabilité que le changement soit significatif. Des changements de la sorte pourraient être associés à des événements spécifiques ou causés par des problèmes techniques. Toutefois, des anomalies très importantes (valeurs absolues supérieures à 6) pourraient également indiquer un problème technique.\n\nNous calculons l'indicateur d'anomalie des voyageurs en combinant l'indicateur de différence des voyageurs et l'écart absolu moyen du nombre de voyageurs entre des paires de zones pendant une période de référence.\n\nLes abonnés sont considérés comme ayant été présents dans une zone un jour donné lorsqu'un événement réseau (par exemple un appel) est acheminé par une tour de téléphonie cellulaire dans cette zone.", + "label": "Abnormality score", + "description": "Describes how unusual the last daily change in travellers from communal section a to communal section b is, compared to the daily changes estimated during the 365 preceding days.", + "method": "The abnormality score indicates how different the last daily change in travellers from communal section a to communal section b (comparing number of travellers during the current day to numbers of travellers during the previous day) is, compared to the median daily change of travellers from a to b estimated during the 365 preceding days (the baseline period), measured in median absolute deviations. It describes how unusual the last daily change in travellers from communal section a to communal section b is, compared to the daily changes estimated during the 365 preceding days. \n\nA positive value for this indicator greater than 3 indicates an abnormal increase in the number of travellers; a value less than -3 indicates an abnormal decrease. Abnormality scores above 6 in absolute value are more likely to correspond to technical issues, particularly in the absence of known disrupting events (disruption of mobility and/or phone usage).", + "label_fr": "Abnormality score", + "description_fr": "Describes how unusual the last daily change in travellers from communal section a to communal section b is, compared to the daily changes estimated during the 365 preceding days.", + "method_fr": "The abnormality score indicates how different the last daily change in travellers from communal section a to communal section b (comparing number of travellers during the current day to numbers of travellers during the previous day) is, compared to the median daily change of travellers from a to b estimated during the 365 preceding days (the baseline period), measured in median absolute deviations. It describes how unusual the last daily change in travellers from communal section a to communal section b is, compared to the daily changes estimated during the 365 preceding days. \n\nA positive value for this indicator greater than 3 indicates an abnormal increase in the number of travellers; a value less than -3 indicates an abnormal decrease. Abnormality scores above 6 in absolute value are more likely to correspond to technical issues, particularly in the absence of known disrupting events (disruption of mobility and/or phone usage).", "scale": "diverging", "decimals": 2, - "min_value": -6, - "max_value": 6, + "min_value": -25, + "max_value": 25, "bins": [ { "min": -3, "max": 3, "width": "2%" }, { "min": -6, "max": -3, "width": "20%" }, diff --git a/src/jupyter/.env b/src/jupyter/.env new file mode 120000 index 0000000..c7360fb --- /dev/null +++ b/src/jupyter/.env @@ -0,0 +1 @@ +../../.env \ No newline at end of file diff --git a/src/jupyter/Pipfile b/src/jupyter/Pipfile new file mode 100644 index 0000000..5f56bc4 --- /dev/null +++ b/src/jupyter/Pipfile @@ -0,0 +1,16 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[packages] +jupyterlab = "*" +pandas = "*" +httpx = "*" +python-dateutil = "*" +tqdm = "*" + +[dev-packages] + +[requires] +python_version = "3.8" diff --git a/src/jupyter/Pipfile.lock b/src/jupyter/Pipfile.lock new file mode 100644 index 0000000..0a3655b --- /dev/null +++ b/src/jupyter/Pipfile.lock @@ -0,0 +1,1172 @@ +{ + "_meta": { + "hash": { + "sha256": "0d4952d5f569b5e010c711c5ca7a3b269aba684176e7a45192acd8d3cde2047b" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.8" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "anyio": { + "hashes": [ + "sha256:275d9973793619a5374e1c89a4f4ad3f4b0a5510a2b5b939444bee8f4c4d37ce", + "sha256:eddca883c4175f14df8aedce21054bfca3adb70ffe76a9f607aef9d7fa2ea7f0" + ], + "markers": "python_version >= '3.7'", + "version": "==3.7.0" + }, + "appnope": { + "hashes": [ + "sha256:02bd91c4de869fbb1e1c50aafc4098827a7a54ab2f39d9dcba6c9547ed920e24", + "sha256:265a455292d0bd8a72453494fa24df5a11eb18373a60c7c0430889f22548605e" + ], + "markers": "platform_system == 'Darwin'", + "version": "==0.1.3" + }, + "argon2-cffi": { + "hashes": [ + "sha256:8c976986f2c5c0e5000919e6de187906cfd81fb1c72bf9d88c01177e77da7f80", + "sha256:d384164d944190a7dd7ef22c6aa3ff197da12962bd04b17f64d4e93d934dba5b" + ], + "markers": "python_version >= '3.6'", + "version": "==21.3.0" + }, + "argon2-cffi-bindings": { + "hashes": [ + "sha256:20ef543a89dee4db46a1a6e206cd015360e5a75822f76df533845c3cbaf72670", + "sha256:2c3e3cc67fdb7d82c4718f19b4e7a87123caf8a93fde7e23cf66ac0337d3cb3f", + "sha256:3b9ef65804859d335dc6b31582cad2c5166f0c3e7975f324d9ffaa34ee7e6583", + "sha256:3e385d1c39c520c08b53d63300c3ecc28622f076f4c2b0e6d7e796e9f6502194", + "sha256:58ed19212051f49a523abb1dbe954337dc82d947fb6e5a0da60f7c8471a8476c", + "sha256:5e00316dabdaea0b2dd82d141cc66889ced0cdcbfa599e8b471cf22c620c329a", + "sha256:603ca0aba86b1349b147cab91ae970c63118a0f30444d4bc80355937c950c082", + "sha256:6a22ad9800121b71099d0fb0a65323810a15f2e292f2ba450810a7316e128ee5", + "sha256:8cd69c07dd875537a824deec19f978e0f2078fdda07fd5c42ac29668dda5f40f", + "sha256:93f9bf70084f97245ba10ee36575f0c3f1e7d7724d67d8e5b08e61787c320ed7", + "sha256:9524464572e12979364b7d600abf96181d3541da11e23ddf565a32e70bd4dc0d", + "sha256:b2ef1c30440dbbcba7a5dc3e319408b59676e2e039e2ae11a8775ecf482b192f", + "sha256:b746dba803a79238e925d9046a63aa26bf86ab2a2fe74ce6b009a1c3f5c8f2ae", + "sha256:bb89ceffa6c791807d1305ceb77dbfacc5aa499891d2c55661c6459651fc39e3", + "sha256:bd46088725ef7f58b5a1ef7ca06647ebaf0eb4baff7d1d0d177c6cc8744abd86", + "sha256:ccb949252cb2ab3a08c02024acb77cfb179492d5701c7cbdbfd776124d4d2367", + "sha256:d4966ef5848d820776f5f562a7d45fdd70c2f330c961d0d745b784034bd9f48d", + "sha256:e415e3f62c8d124ee16018e491a009937f8cf7ebf5eb430ffc5de21b900dad93", + "sha256:ed2937d286e2ad0cc79a7087d3c272832865f779430e0cc2b4f3718d3159b0cb", + "sha256:f1152ac548bd5b8bcecfb0b0371f082037e47128653df2e8ba6e914d384f3c3e", + "sha256:f9f8b450ed0547e3d473fdc8612083fd08dd2120d6ac8f73828df9b7d45bb351" + ], + "markers": "python_version >= '3.6'", + "version": "==21.2.0" + }, + "arrow": { + "hashes": [ + "sha256:3934b30ca1b9f292376d9db15b19446088d12ec58629bc3f0da28fd55fb633a1", + "sha256:5a49ab92e3b7b71d96cd6bfcc4df14efefc9dfa96ea19045815914a6ab6b1fe2" + ], + "markers": "python_version >= '3.6'", + "version": "==1.2.3" + }, + "asttokens": { + "hashes": [ + "sha256:4622110b2a6f30b77e1473affaa97e711bc2f07d3f10848420ff1898edbe94f3", + "sha256:6b0ac9e93fb0335014d382b8fa9b3afa7df546984258005da0b9e7095b3deb1c" + ], + "version": "==2.2.1" + }, + "async-lru": { + "hashes": [ + "sha256:3b87ec4f2460c52cc7916a0138cc606b584c75d1ef7d661853c95d1d3acb869a", + "sha256:d7c2b873e9af5c5a1f0a87a6c145e7e0b4eb92342b7235dda9dd5b10e950d6e2" + ], + "markers": "python_version >= '3.8'", + "version": "==2.0.2" + }, + "attrs": { + "hashes": [ + "sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04", + "sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015" + ], + "markers": "python_version >= '3.7'", + "version": "==23.1.0" + }, + "babel": { + "hashes": [ + "sha256:b4246fb7677d3b98f501a39d43396d3cafdc8eadb045f4a31be01863f655c610", + "sha256:cc2d99999cd01d44420ae725a21c9e3711b3aadc7976d6147f622d8581963455" + ], + "markers": "python_version >= '3.7'", + "version": "==2.12.1" + }, + "backcall": { + "hashes": [ + "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e", + "sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255" + ], + "version": "==0.2.0" + }, + "beautifulsoup4": { + "hashes": [ + "sha256:492bbc69dca35d12daac71c4db1bfff0c876c00ef4a2ffacce226d4638eb72da", + "sha256:bd2520ca0d9d7d12694a53d44ac482d181b4ec1888909b035a3dbf40d0f57d4a" + ], + "markers": "python_full_version >= '3.6.0'", + "version": "==4.12.2" + }, + "bleach": { + "hashes": [ + "sha256:1a1a85c1595e07d8db14c5f09f09e6433502c51c595970edc090551f0db99414", + "sha256:33c16e3353dbd13028ab4799a0f89a83f113405c766e9c122df8a06f5b85b3f4" + ], + "markers": "python_version >= '3.7'", + "version": "==6.0.0" + }, + "certifi": { + "hashes": [ + "sha256:0f0d56dc5a6ad56fd4ba36484d6cc34451e1c6548c61daad8c320169f91eddc7", + "sha256:c6c2e98f5c7869efca1f8916fed228dd91539f9f1b444c314c06eef02980c716" + ], + "markers": "python_version >= '3.6'", + "version": "==2023.5.7" + }, + "cffi": { + "hashes": [ + "sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5", + "sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef", + "sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104", + "sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426", + "sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405", + "sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375", + "sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a", + "sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e", + "sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc", + "sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf", + "sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185", + "sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497", + "sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3", + "sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35", + "sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c", + "sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83", + "sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21", + "sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca", + "sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984", + "sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac", + "sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd", + "sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee", + "sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a", + "sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2", + "sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192", + "sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7", + "sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585", + "sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f", + "sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e", + "sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27", + "sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b", + "sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e", + "sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e", + "sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d", + "sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c", + "sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415", + "sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82", + "sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02", + "sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314", + "sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325", + "sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c", + "sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3", + "sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914", + "sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045", + "sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d", + "sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9", + "sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5", + "sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2", + "sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c", + "sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3", + "sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2", + "sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8", + "sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d", + "sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d", + "sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9", + "sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162", + "sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76", + "sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4", + "sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e", + "sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9", + "sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6", + "sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b", + "sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01", + "sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0" + ], + "version": "==1.15.1" + }, + "charset-normalizer": { + "hashes": [ + "sha256:04afa6387e2b282cf78ff3dbce20f0cc071c12dc8f685bd40960cc68644cfea6", + "sha256:04eefcee095f58eaabe6dc3cc2262f3bcd776d2c67005880894f447b3f2cb9c1", + "sha256:0be65ccf618c1e7ac9b849c315cc2e8a8751d9cfdaa43027d4f6624bd587ab7e", + "sha256:0c95f12b74681e9ae127728f7e5409cbbef9cd914d5896ef238cc779b8152373", + "sha256:0ca564606d2caafb0abe6d1b5311c2649e8071eb241b2d64e75a0d0065107e62", + "sha256:10c93628d7497c81686e8e5e557aafa78f230cd9e77dd0c40032ef90c18f2230", + "sha256:11d117e6c63e8f495412d37e7dc2e2fff09c34b2d09dbe2bee3c6229577818be", + "sha256:11d3bcb7be35e7b1bba2c23beedac81ee893ac9871d0ba79effc7fc01167db6c", + "sha256:12a2b561af122e3d94cdb97fe6fb2bb2b82cef0cdca131646fdb940a1eda04f0", + "sha256:12d1a39aa6b8c6f6248bb54550efcc1c38ce0d8096a146638fd4738e42284448", + "sha256:1435ae15108b1cb6fffbcea2af3d468683b7afed0169ad718451f8db5d1aff6f", + "sha256:1c60b9c202d00052183c9be85e5eaf18a4ada0a47d188a83c8f5c5b23252f649", + "sha256:1e8fcdd8f672a1c4fc8d0bd3a2b576b152d2a349782d1eb0f6b8e52e9954731d", + "sha256:20064ead0717cf9a73a6d1e779b23d149b53daf971169289ed2ed43a71e8d3b0", + "sha256:21fa558996782fc226b529fdd2ed7866c2c6ec91cee82735c98a197fae39f706", + "sha256:22908891a380d50738e1f978667536f6c6b526a2064156203d418f4856d6e86a", + "sha256:3160a0fd9754aab7d47f95a6b63ab355388d890163eb03b2d2b87ab0a30cfa59", + "sha256:322102cdf1ab682ecc7d9b1c5eed4ec59657a65e1c146a0da342b78f4112db23", + "sha256:34e0a2f9c370eb95597aae63bf85eb5e96826d81e3dcf88b8886012906f509b5", + "sha256:3573d376454d956553c356df45bb824262c397c6e26ce43e8203c4c540ee0acb", + "sha256:3747443b6a904001473370d7810aa19c3a180ccd52a7157aacc264a5ac79265e", + "sha256:38e812a197bf8e71a59fe55b757a84c1f946d0ac114acafaafaf21667a7e169e", + "sha256:3a06f32c9634a8705f4ca9946d667609f52cf130d5548881401f1eb2c39b1e2c", + "sha256:3a5fc78f9e3f501a1614a98f7c54d3969f3ad9bba8ba3d9b438c3bc5d047dd28", + "sha256:3d9098b479e78c85080c98e1e35ff40b4a31d8953102bb0fd7d1b6f8a2111a3d", + "sha256:3dc5b6a8ecfdc5748a7e429782598e4f17ef378e3e272eeb1340ea57c9109f41", + "sha256:4155b51ae05ed47199dc5b2a4e62abccb274cee6b01da5b895099b61b1982974", + "sha256:49919f8400b5e49e961f320c735388ee686a62327e773fa5b3ce6721f7e785ce", + "sha256:53d0a3fa5f8af98a1e261de6a3943ca631c526635eb5817a87a59d9a57ebf48f", + "sha256:5f008525e02908b20e04707a4f704cd286d94718f48bb33edddc7d7b584dddc1", + "sha256:628c985afb2c7d27a4800bfb609e03985aaecb42f955049957814e0491d4006d", + "sha256:65ed923f84a6844de5fd29726b888e58c62820e0769b76565480e1fdc3d062f8", + "sha256:6734e606355834f13445b6adc38b53c0fd45f1a56a9ba06c2058f86893ae8017", + "sha256:6baf0baf0d5d265fa7944feb9f7451cc316bfe30e8df1a61b1bb08577c554f31", + "sha256:6f4f4668e1831850ebcc2fd0b1cd11721947b6dc7c00bf1c6bd3c929ae14f2c7", + "sha256:6f5c2e7bc8a4bf7c426599765b1bd33217ec84023033672c1e9a8b35eaeaaaf8", + "sha256:6f6c7a8a57e9405cad7485f4c9d3172ae486cfef1344b5ddd8e5239582d7355e", + "sha256:7381c66e0561c5757ffe616af869b916c8b4e42b367ab29fedc98481d1e74e14", + "sha256:73dc03a6a7e30b7edc5b01b601e53e7fc924b04e1835e8e407c12c037e81adbd", + "sha256:74db0052d985cf37fa111828d0dd230776ac99c740e1a758ad99094be4f1803d", + "sha256:75f2568b4189dda1c567339b48cba4ac7384accb9c2a7ed655cd86b04055c795", + "sha256:78cacd03e79d009d95635e7d6ff12c21eb89b894c354bd2b2ed0b4763373693b", + "sha256:80d1543d58bd3d6c271b66abf454d437a438dff01c3e62fdbcd68f2a11310d4b", + "sha256:830d2948a5ec37c386d3170c483063798d7879037492540f10a475e3fd6f244b", + "sha256:891cf9b48776b5c61c700b55a598621fdb7b1e301a550365571e9624f270c203", + "sha256:8f25e17ab3039b05f762b0a55ae0b3632b2e073d9c8fc88e89aca31a6198e88f", + "sha256:9a3267620866c9d17b959a84dd0bd2d45719b817245e49371ead79ed4f710d19", + "sha256:a04f86f41a8916fe45ac5024ec477f41f886b3c435da2d4e3d2709b22ab02af1", + "sha256:aaf53a6cebad0eae578f062c7d462155eada9c172bd8c4d250b8c1d8eb7f916a", + "sha256:abc1185d79f47c0a7aaf7e2412a0eb2c03b724581139193d2d82b3ad8cbb00ac", + "sha256:ac0aa6cd53ab9a31d397f8303f92c42f534693528fafbdb997c82bae6e477ad9", + "sha256:ac3775e3311661d4adace3697a52ac0bab17edd166087d493b52d4f4f553f9f0", + "sha256:b06f0d3bf045158d2fb8837c5785fe9ff9b8c93358be64461a1089f5da983137", + "sha256:b116502087ce8a6b7a5f1814568ccbd0e9f6cfd99948aa59b0e241dc57cf739f", + "sha256:b82fab78e0b1329e183a65260581de4375f619167478dddab510c6c6fb04d9b6", + "sha256:bd7163182133c0c7701b25e604cf1611c0d87712e56e88e7ee5d72deab3e76b5", + "sha256:c36bcbc0d5174a80d6cccf43a0ecaca44e81d25be4b7f90f0ed7bcfbb5a00909", + "sha256:c3af8e0f07399d3176b179f2e2634c3ce9c1301379a6b8c9c9aeecd481da494f", + "sha256:c84132a54c750fda57729d1e2599bb598f5fa0344085dbde5003ba429a4798c0", + "sha256:cb7b2ab0188829593b9de646545175547a70d9a6e2b63bf2cd87a0a391599324", + "sha256:cca4def576f47a09a943666b8f829606bcb17e2bc2d5911a46c8f8da45f56755", + "sha256:cf6511efa4801b9b38dc5546d7547d5b5c6ef4b081c60b23e4d941d0eba9cbeb", + "sha256:d16fd5252f883eb074ca55cb622bc0bee49b979ae4e8639fff6ca3ff44f9f854", + "sha256:d2686f91611f9e17f4548dbf050e75b079bbc2a82be565832bc8ea9047b61c8c", + "sha256:d7fc3fca01da18fbabe4625d64bb612b533533ed10045a2ac3dd194bfa656b60", + "sha256:dd5653e67b149503c68c4018bf07e42eeed6b4e956b24c00ccdf93ac79cdff84", + "sha256:de5695a6f1d8340b12a5d6d4484290ee74d61e467c39ff03b39e30df62cf83a0", + "sha256:e0ac8959c929593fee38da1c2b64ee9778733cdf03c482c9ff1d508b6b593b2b", + "sha256:e1b25e3ad6c909f398df8921780d6a3d120d8c09466720226fc621605b6f92b1", + "sha256:e633940f28c1e913615fd624fcdd72fdba807bf53ea6925d6a588e84e1151531", + "sha256:e89df2958e5159b811af9ff0f92614dabf4ff617c03a4c1c6ff53bf1c399e0e1", + "sha256:ea9f9c6034ea2d93d9147818f17c2a0860d41b71c38b9ce4d55f21b6f9165a11", + "sha256:f645caaf0008bacf349875a974220f1f1da349c5dbe7c4ec93048cdc785a3326", + "sha256:f8303414c7b03f794347ad062c0516cee0e15f7a612abd0ce1e25caf6ceb47df", + "sha256:fca62a8301b605b954ad2e9c3666f9d97f63872aa4efcae5492baca2056b74ab" + ], + "markers": "python_full_version >= '3.7.0'", + "version": "==3.1.0" + }, + "comm": { + "hashes": [ + "sha256:16613c6211e20223f215fc6d3b266a247b6e2641bf4e0a3ad34cb1aff2aa3f37", + "sha256:a61efa9daffcfbe66fd643ba966f846a624e4e6d6767eda9cf6e993aadaab93e" + ], + "markers": "python_version >= '3.6'", + "version": "==0.1.3" + }, + "debugpy": { + "hashes": [ + "sha256:0679b7e1e3523bd7d7869447ec67b59728675aadfc038550a63a362b63029d2c", + "sha256:279d64c408c60431c8ee832dfd9ace7c396984fd7341fa3116aee414e7dcd88d", + "sha256:33edb4afa85c098c24cc361d72ba7c21bb92f501104514d4ffec1fb36e09c01a", + "sha256:38ed626353e7c63f4b11efad659be04c23de2b0d15efff77b60e4740ea685d07", + "sha256:5224eabbbeddcf1943d4e2821876f3e5d7d383f27390b82da5d9558fd4eb30a9", + "sha256:53f7a456bc50706a0eaabecf2d3ce44c4d5010e46dfc65b6b81a518b42866267", + "sha256:9cd10cf338e0907fdcf9eac9087faa30f150ef5445af5a545d307055141dd7a4", + "sha256:aaf6da50377ff4056c8ed470da24632b42e4087bc826845daad7af211e00faad", + "sha256:b3e7ac809b991006ad7f857f016fa92014445085711ef111fdc3f74f66144096", + "sha256:bae1123dff5bfe548ba1683eb972329ba6d646c3a80e6b4c06cd1b1dd0205e9b", + "sha256:c0ff93ae90a03b06d85b2c529eca51ab15457868a377c4cc40a23ab0e4e552a3", + "sha256:c4c2f0810fa25323abfdfa36cbbbb24e5c3b1a42cb762782de64439c575d67f2", + "sha256:d71b31117779d9a90b745720c0eab54ae1da76d5b38c8026c654f4a066b0130a", + "sha256:dbe04e7568aa69361a5b4c47b4493d5680bfa3a911d1e105fbea1b1f23f3eb45", + "sha256:de86029696e1b3b4d0d49076b9eba606c226e33ae312a57a46dca14ff370894d", + "sha256:e3876611d114a18aafef6383695dfc3f1217c98a9168c1aaf1a02b01ec7d8d1e", + "sha256:ed6d5413474e209ba50b1a75b2d9eecf64d41e6e4501977991cdc755dc83ab0f", + "sha256:f90a2d4ad9a035cee7331c06a4cf2245e38bd7c89554fe3b616d90ab8aab89cc" + ], + "markers": "python_version >= '3.7'", + "version": "==1.6.7" + }, + "decorator": { + "hashes": [ + "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330", + "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186" + ], + "markers": "python_version >= '3.5'", + "version": "==5.1.1" + }, + "defusedxml": { + "hashes": [ + "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69", + "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==0.7.1" + }, + "executing": { + "hashes": [ + "sha256:0314a69e37426e3608aada02473b4161d4caf5a4b244d1d0c48072b8fee7bacc", + "sha256:19da64c18d2d851112f09c287f8d3dbbdf725ab0e569077efb6cdcbd3497c107" + ], + "version": "==1.2.0" + }, + "fastjsonschema": { + "hashes": [ + "sha256:4b90b252628ca695280924d863fe37234eebadc29c5360d322571233dc9746e0", + "sha256:f4eeb8a77cef54861dbf7424ac8ce71306f12cbb086c45131bcba2c6a4f726e3" + ], + "version": "==2.17.1" + }, + "fqdn": { + "hashes": [ + "sha256:105ed3677e767fb5ca086a0c1f4bb66ebc3c100be518f0e0d755d9eae164d89f", + "sha256:3a179af3761e4df6eb2e026ff9e1a3033d3587bf980a0b1b2e1e5d08d7358014" + ], + "version": "==1.5.1" + }, + "h11": { + "hashes": [ + "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d", + "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761" + ], + "markers": "python_version >= '3.7'", + "version": "==0.14.0" + }, + "httpcore": { + "hashes": [ + "sha256:125f8375ab60036db632f34f4b627a9ad085048eef7cb7d2616fea0f739f98af", + "sha256:5581b9c12379c4288fe70f43c710d16060c10080617001e6b22a3b6dbcbefd36" + ], + "markers": "python_version >= '3.7'", + "version": "==0.17.2" + }, + "httpx": { + "hashes": [ + "sha256:06781eb9ac53cde990577af654bd990a4949de37a28bdb4a230d434f3a30b9bd", + "sha256:5853a43053df830c20f8110c5e69fe44d035d850b2dfe795e196f00fdb774bdd" + ], + "index": "pypi", + "version": "==0.24.1" + }, + "idna": { + "hashes": [ + "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4", + "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2" + ], + "markers": "python_version >= '3.5'", + "version": "==3.4" + }, + "ipykernel": { + "hashes": [ + "sha256:7ccb6e2d32fd958c21453db494c914f3474908a2fdefd99ab548a5375b548d1f", + "sha256:fcfb67c5b504aa1bfcda1c5b3716636239e0f7b9290958f1c558c79b4c0e7ed5" + ], + "markers": "python_version >= '3.8'", + "version": "==6.23.2" + }, + "ipython": { + "hashes": [ + "sha256:1d197b907b6ba441b692c48cf2a3a2de280dc0ac91a3405b39349a50272ca0a1", + "sha256:248aca623f5c99a6635bc3857677b7320b9b8039f99f070ee0d20a5ca5a8e6bf" + ], + "markers": "python_version >= '3.9'", + "version": "==8.14.0" + }, + "isoduration": { + "hashes": [ + "sha256:ac2f9015137935279eac671f94f89eb00584f940f5dc49462a0c4ee692ba1bd9", + "sha256:b2904c2a4228c3d44f409c8ae8e2370eb21a26f7ac2ec5446df141dde3452042" + ], + "version": "==20.11.0" + }, + "jedi": { + "hashes": [ + "sha256:203c1fd9d969ab8f2119ec0a3342e0b49910045abe6af0a3ae83a5764d54639e", + "sha256:bae794c30d07f6d910d32a7048af09b5a39ed740918da923c6b780790ebac612" + ], + "markers": "python_version >= '3.6'", + "version": "==0.18.2" + }, + "jinja2": { + "hashes": [ + "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852", + "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61" + ], + "markers": "python_version >= '3.7'", + "version": "==3.1.2" + }, + "json5": { + "hashes": [ + "sha256:740c7f1b9e584a468dbb2939d8d458db3427f2c93ae2139d05f47e453eae964f", + "sha256:9ed66c3a6ca3510a976a9ef9b8c0787de24802724ab1860bc0153c7fdd589b02" + ], + "version": "==0.9.14" + }, + "jsonpointer": { + "hashes": [ + "sha256:51801e558539b4e9cd268638c078c6c5746c9ac96bc38152d443400e4f3793e9", + "sha256:97cba51526c829282218feb99dab1b1e6bdf8efd1c43dc9d57be093c0d69c99a" + ], + "version": "==2.3" + }, + "jsonschema": { + "hashes": [ + "sha256:0f864437ab8b6076ba6707453ef8f98a6a0d512a80e93f8abdb676f737ecb60d", + "sha256:a870ad254da1a8ca84b6a2905cac29d265f805acc57af304784962a2aa6508f6" + ], + "markers": "python_version >= '3.7'", + "version": "==4.17.3" + }, + "jupyter-client": { + "hashes": [ + "sha256:9fe233834edd0e6c0aa5f05ca2ab4bdea1842bfd2d8a932878212fc5301ddaf0", + "sha256:b18219aa695d39e2ad570533e0d71fb7881d35a873051054a84ee2a17c4b7389" + ], + "markers": "python_version >= '3.8'", + "version": "==8.2.0" + }, + "jupyter-core": { + "hashes": [ + "sha256:5ba5c7938a7f97a6b0481463f7ff0dbac7c15ba48cf46fa4035ca6e838aa1aba", + "sha256:ae9036db959a71ec1cac33081eeb040a79e681f08ab68b0883e9a676c7a90dce" + ], + "markers": "python_version >= '3.8'", + "version": "==5.3.1" + }, + "jupyter-events": { + "hashes": [ + "sha256:57a2749f87ba387cd1bfd9b22a0875b889237dbf2edc2121ebb22bde47036c17", + "sha256:9a6e9995f75d1b7146b436ea24d696ce3a35bfa8bfe45e0c33c334c79464d0b3" + ], + "markers": "python_version >= '3.7'", + "version": "==0.6.3" + }, + "jupyter-lsp": { + "hashes": [ + "sha256:8ebbcb533adb41e5d635eb8fe82956b0aafbf0fd443b6c4bfa906edeeb8635a1", + "sha256:9e06b8b4f7dd50300b70dd1a78c0c3b0c3d8fa68e0f2d8a5d1fbab62072aca3f" + ], + "markers": "python_version >= '3.8'", + "version": "==2.2.0" + }, + "jupyter-server": { + "hashes": [ + "sha256:19525a1515b5999618a91b3e99ec9f6869aa8c5ba73e0b6279fcda918b54ba36", + "sha256:ae4af349f030ed08dd78cb7ac1a03a92d886000380c9ea6283f3c542a81f4b06" + ], + "markers": "python_version >= '3.8'", + "version": "==2.6.0" + }, + "jupyter-server-terminals": { + "hashes": [ + "sha256:57ab779797c25a7ba68e97bcfb5d7740f2b5e8a83b5e8102b10438041a7eac5d", + "sha256:75779164661cec02a8758a5311e18bb8eb70c4e86c6b699403100f1585a12a36" + ], + "markers": "python_version >= '3.8'", + "version": "==0.4.4" + }, + "jupyterlab": { + "hashes": [ + "sha256:0a77898aebb55da391e5f57022774c089fb075e98803ff3d514a79b727dc934d", + "sha256:201b4f729a7dc5e22ca6c4dd8944cde792f1cb008d7c6b821e0a48d2502205c8" + ], + "index": "pypi", + "version": "==4.0.2" + }, + "jupyterlab-pygments": { + "hashes": [ + "sha256:2405800db07c9f770863bcf8049a529c3dd4d3e28536638bd7c1c01d2748309f", + "sha256:7405d7fde60819d905a9fa8ce89e4cd830e318cdad22a0030f7a901da705585d" + ], + "markers": "python_version >= '3.7'", + "version": "==0.2.2" + }, + "jupyterlab-server": { + "hashes": [ + "sha256:83c01aa4ad9451cd61b383e634d939ff713850f4640c0056b2cdb2b6211a74c7", + "sha256:a5ea2c839336a8ba7c38c8e7b2f24cedf919f0d439f4d2e606d9322013a95788" + ], + "markers": "python_version >= '3.7'", + "version": "==2.23.0" + }, + "markupsafe": { + "hashes": [ + "sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e", + "sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e", + "sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431", + "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686", + "sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559", + "sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc", + "sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c", + "sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0", + "sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4", + "sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9", + "sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575", + "sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba", + "sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d", + "sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3", + "sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00", + "sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155", + "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac", + "sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52", + "sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f", + "sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8", + "sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b", + "sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24", + "sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea", + "sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198", + "sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0", + "sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee", + "sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be", + "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2", + "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707", + "sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6", + "sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58", + "sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779", + "sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636", + "sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c", + "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad", + "sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee", + "sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc", + "sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2", + "sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48", + "sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7", + "sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e", + "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b", + "sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa", + "sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5", + "sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e", + "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb", + "sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9", + "sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57", + "sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc", + "sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2" + ], + "markers": "python_version >= '3.7'", + "version": "==2.1.3" + }, + "matplotlib-inline": { + "hashes": [ + "sha256:f1f41aab5328aa5aaea9b16d083b128102f8712542f819fe7e6a420ff581b311", + "sha256:f887e5f10ba98e8d2b150ddcf4702c1e5f8b3a20005eb0f74bfdbd360ee6f304" + ], + "markers": "python_version >= '3.5'", + "version": "==0.1.6" + }, + "mistune": { + "hashes": [ + "sha256:0246113cb2492db875c6be56974a7c893333bf26cd92891c85f63151cee09d34", + "sha256:bad7f5d431886fcbaf5f758118ecff70d31f75231b34024a1341120340a65ce8" + ], + "version": "==2.0.5" + }, + "nbclient": { + "hashes": [ + "sha256:25e861299e5303a0477568557c4045eccc7a34c17fc08e7959558707b9ebe548", + "sha256:f9b179cd4b2d7bca965f900a2ebf0db4a12ebff2f36a711cb66861e4ae158e55" + ], + "markers": "python_full_version >= '3.8.0'", + "version": "==0.8.0" + }, + "nbconvert": { + "hashes": [ + "sha256:852e44392d5650ef217a5ce3a8050747051d4e6ba75f0574cb5435049ee6c0d9", + "sha256:f78fd22fd2410b960d5d9bcecf3e1d6c7bdc5fec2c865964c84aa4e74e6e88da" + ], + "markers": "python_version >= '3.7'", + "version": "==7.5.0" + }, + "nbformat": { + "hashes": [ + "sha256:8c8fa16d6d05062c26177754bfbfac22de644888e2ef69d27ad2a334cf2576e5", + "sha256:e98ebb6120c3efbafdee2a40af2a140cadee90bb06dd69a2a63d9551fcc7f976" + ], + "markers": "python_version >= '3.8'", + "version": "==5.9.0" + }, + "nest-asyncio": { + "hashes": [ + "sha256:b9a953fb40dceaa587d109609098db21900182b16440652454a146cffb06e8b8", + "sha256:d267cc1ff794403f7df692964d1d2a3fa9418ffea2a3f6859a439ff482fef290" + ], + "markers": "python_version >= '3.5'", + "version": "==1.5.6" + }, + "notebook-shim": { + "hashes": [ + "sha256:a83496a43341c1674b093bfcebf0fe8e74cbe7eda5fd2bbc56f8e39e1486c0c7", + "sha256:f69388ac283ae008cd506dda10d0288b09a017d822d5e8c7129a152cbd3ce7e9" + ], + "markers": "python_version >= '3.7'", + "version": "==0.2.3" + }, + "numpy": { + "hashes": [ + "sha256:0ec87a7084caa559c36e0a2309e4ecb1baa03b687201d0a847c8b0ed476a7187", + "sha256:1a7d6acc2e7524c9955e5c903160aa4ea083736fde7e91276b0e5d98e6332812", + "sha256:202de8f38fc4a45a3eea4b63e2f376e5f2dc64ef0fa692838e31a808520efaf7", + "sha256:210461d87fb02a84ef243cac5e814aad2b7f4be953b32cb53327bb49fd77fbb4", + "sha256:2d926b52ba1367f9acb76b0df6ed21f0b16a1ad87c6720a1121674e5cf63e2b6", + "sha256:352ee00c7f8387b44d19f4cada524586f07379c0d49270f87233983bc5087ca0", + "sha256:35400e6a8d102fd07c71ed7dcadd9eb62ee9a6e84ec159bd48c28235bbb0f8e4", + "sha256:3c1104d3c036fb81ab923f507536daedc718d0ad5a8707c6061cdfd6d184e570", + "sha256:4719d5aefb5189f50887773699eaf94e7d1e02bf36c1a9d353d9f46703758ca4", + "sha256:4749e053a29364d3452c034827102ee100986903263e89884922ef01a0a6fd2f", + "sha256:5342cf6aad47943286afa6f1609cad9b4266a05e7f2ec408e2cf7aea7ff69d80", + "sha256:56e48aec79ae238f6e4395886b5eaed058abb7231fb3361ddd7bfdf4eed54289", + "sha256:76e3f4e85fc5d4fd311f6e9b794d0c00e7002ec122be271f2019d63376f1d385", + "sha256:7776ea65423ca6a15255ba1872d82d207bd1e09f6d0894ee4a64678dd2204078", + "sha256:784c6da1a07818491b0ffd63c6bbe5a33deaa0e25a20e1b3ea20cf0e43f8046c", + "sha256:8535303847b89aa6b0f00aa1dc62867b5a32923e4d1681a35b5eef2d9591a463", + "sha256:9a7721ec204d3a237225db3e194c25268faf92e19338a35f3a224469cb6039a3", + "sha256:a1d3c026f57ceaad42f8231305d4653d5f05dc6332a730ae5c0bea3513de0950", + "sha256:ab344f1bf21f140adab8e47fdbc7c35a477dc01408791f8ba00d018dd0bc5155", + "sha256:ab5f23af8c16022663a652d3b25dcdc272ac3f83c3af4c02eb8b824e6b3ab9d7", + "sha256:ae8d0be48d1b6ed82588934aaaa179875e7dc4f3d84da18d7eae6eb3f06c242c", + "sha256:c91c4afd8abc3908e00a44b2672718905b8611503f7ff87390cc0ac3423fb096", + "sha256:d5036197ecae68d7f491fcdb4df90082b0d4960ca6599ba2659957aafced7c17", + "sha256:d6cc757de514c00b24ae8cf5c876af2a7c3df189028d68c0cb4eaa9cd5afc2bf", + "sha256:d933fabd8f6a319e8530d0de4fcc2e6a61917e0b0c271fded460032db42a0fe4", + "sha256:ea8282b9bcfe2b5e7d491d0bf7f3e2da29700cec05b49e64d6246923329f2b02", + "sha256:ecde0f8adef7dfdec993fd54b0f78183051b6580f606111a6d789cd14c61ea0c", + "sha256:f21c442fdd2805e91799fbe044a7b999b8571bb0ab0f7850d0cb9641a687092b" + ], + "markers": "python_version >= '3.10'", + "version": "==1.24.3" + }, + "overrides": { + "hashes": [ + "sha256:6187d8710a935d09b0bcef8238301d6ee2569d2ac1ae0ec39a8c7924e27f58ca", + "sha256:8b97c6c1e1681b78cbc9424b138d880f0803c2254c5ebaabdde57bb6c62093f2" + ], + "markers": "python_version >= '3.6'", + "version": "==7.3.1" + }, + "packaging": { + "hashes": [ + "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61", + "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f" + ], + "markers": "python_version >= '3.7'", + "version": "==23.1" + }, + "pandas": { + "hashes": [ + "sha256:02755de164da6827764ceb3bbc5f64b35cb12394b1024fdf88704d0fa06e0e2f", + "sha256:0a1e0576611641acde15c2322228d138258f236d14b749ad9af498ab69089e2d", + "sha256:1eb09a242184092f424b2edd06eb2b99d06dc07eeddff9929e8667d4ed44e181", + "sha256:30a89d0fec4263ccbf96f68592fd668939481854d2ff9da709d32a047689393b", + "sha256:50e451932b3011b61d2961b4185382c92cc8c6ee4658dcd4f320687bb2d000ee", + "sha256:51a93d422fbb1bd04b67639ba4b5368dffc26923f3ea32a275d2cc450f1d1c86", + "sha256:598e9020d85a8cdbaa1815eb325a91cfff2bb2b23c1442549b8a3668e36f0f77", + "sha256:66d00300f188fa5de73f92d5725ced162488f6dc6ad4cecfe4144ca29debe3b8", + "sha256:69167693cb8f9b3fc060956a5d0a0a8dbfed5f980d9fd2c306fb5b9c855c814c", + "sha256:6d6d10c2142d11d40d6e6c0a190b1f89f525bcf85564707e31b0a39e3b398e08", + "sha256:713f2f70abcdade1ddd68fc91577cb090b3544b07ceba78a12f799355a13ee44", + "sha256:7376e13d28eb16752c398ca1d36ccfe52bf7e887067af9a0474de6331dd948d2", + "sha256:77550c8909ebc23e56a89f91b40ad01b50c42cfbfab49b3393694a50549295ea", + "sha256:7b21cb72958fc49ad757685db1919021d99650d7aaba676576c9e88d3889d456", + "sha256:9ebb9f1c22ddb828e7fd017ea265a59d80461d5a79154b49a4207bd17514d122", + "sha256:a18e5c72b989ff0f7197707ceddc99828320d0ca22ab50dd1b9e37db45b010c0", + "sha256:a6b5f14cd24a2ed06e14255ff40fe2ea0cfaef79a8dd68069b7ace74bd6acbba", + "sha256:b42b120458636a981077cfcfa8568c031b3e8709701315e2bfa866324a83efa8", + "sha256:c4af689352c4fe3d75b2834933ee9d0ccdbf5d7a8a7264f0ce9524e877820c08", + "sha256:c7319b6e68de14e6209460f72a8d1ef13c09fb3d3ef6c37c1e65b35d50b5c145", + "sha256:cf3f0c361a4270185baa89ec7ab92ecaa355fe783791457077473f974f654df5", + "sha256:dd46bde7309088481b1cf9c58e3f0e204b9ff9e3244f441accd220dd3365ce7c", + "sha256:dd5476b6c3fe410ee95926873f377b856dbc4e81a9c605a0dc05aaccc6a7c6c6", + "sha256:e69140bc2d29a8556f55445c15f5794490852af3de0f609a24003ef174528b79", + "sha256:f908a77cbeef9bbd646bd4b81214cbef9ac3dda4181d5092a4aa9797d1bc7774" + ], + "index": "pypi", + "version": "==2.0.2" + }, + "pandocfilters": { + "hashes": [ + "sha256:0b679503337d233b4339a817bfc8c50064e2eff681314376a47cb582305a7a38", + "sha256:33aae3f25fd1a026079f5d27bdd52496f0e0803b3469282162bafdcbdf6ef14f" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.5.0" + }, + "parso": { + "hashes": [ + "sha256:8c07be290bb59f03588915921e29e8a50002acaf2cdc5fa0e0114f91709fafa0", + "sha256:c001d4636cd3aecdaf33cbb40aebb59b094be2a74c556778ef5576c175e19e75" + ], + "markers": "python_version >= '3.6'", + "version": "==0.8.3" + }, + "pexpect": { + "hashes": [ + "sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937", + "sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c" + ], + "markers": "sys_platform != 'win32'", + "version": "==4.8.0" + }, + "pickleshare": { + "hashes": [ + "sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca", + "sha256:9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56" + ], + "version": "==0.7.5" + }, + "platformdirs": { + "hashes": [ + "sha256:0ade98a4895e87dc51d47151f7d2ec290365a585151d97b4d8d6312ed6132fed", + "sha256:e48fabd87db8f3a7df7150a4a5ea22c546ee8bc39bc2473244730d4b56d2cc4e" + ], + "markers": "python_version >= '3.7'", + "version": "==3.5.3" + }, + "prometheus-client": { + "hashes": [ + "sha256:9c3b26f1535945e85b8934fb374678d263137b78ef85f305b1156c7c881cd11b", + "sha256:a77b708cf083f4d1a3fb3ce5c95b4afa32b9c521ae363354a4a910204ea095ce" + ], + "markers": "python_version >= '3.6'", + "version": "==0.17.0" + }, + "prompt-toolkit": { + "hashes": [ + "sha256:23ac5d50538a9a38c8bde05fecb47d0b403ecd0662857a86f886f798563d5b9b", + "sha256:45ea77a2f7c60418850331366c81cf6b5b9cf4c7fd34616f733c5427e6abbb1f" + ], + "markers": "python_full_version >= '3.7.0'", + "version": "==3.0.38" + }, + "psutil": { + "hashes": [ + "sha256:104a5cc0e31baa2bcf67900be36acde157756b9c44017b86b2c049f11957887d", + "sha256:3c6f686f4225553615612f6d9bc21f1c0e305f75d7d8454f9b46e901778e7217", + "sha256:4aef137f3345082a3d3232187aeb4ac4ef959ba3d7c10c33dd73763fbc063da4", + "sha256:5410638e4df39c54d957fc51ce03048acd8e6d60abc0f5107af51e5fb566eb3c", + "sha256:5b9b8cb93f507e8dbaf22af6a2fd0ccbe8244bf30b1baad6b3954e935157ae3f", + "sha256:7a7dd9997128a0d928ed4fb2c2d57e5102bb6089027939f3b722f3a210f9a8da", + "sha256:89518112647f1276b03ca97b65cc7f64ca587b1eb0278383017c2a0dcc26cbe4", + "sha256:8c5f7c5a052d1d567db4ddd231a9d27a74e8e4a9c3f44b1032762bd7b9fdcd42", + "sha256:ab8ed1a1d77c95453db1ae00a3f9c50227ebd955437bcf2a574ba8adbf6a74d5", + "sha256:acf2aef9391710afded549ff602b5887d7a2349831ae4c26be7c807c0a39fac4", + "sha256:b258c0c1c9d145a1d5ceffab1134441c4c5113b2417fafff7315a917a026c3c9", + "sha256:be8929ce4313f9f8146caad4272f6abb8bf99fc6cf59344a3167ecd74f4f203f", + "sha256:c607bb3b57dc779d55e1554846352b4e358c10fff3abf3514a7a6601beebdb30", + "sha256:ea8518d152174e1249c4f2a1c89e3e6065941df2fa13a1ab45327716a23c2b48" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==5.9.5" + }, + "ptyprocess": { + "hashes": [ + "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", + "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220" + ], + "markers": "os_name != 'nt'", + "version": "==0.7.0" + }, + "pure-eval": { + "hashes": [ + "sha256:01eaab343580944bc56080ebe0a674b39ec44a945e6d09ba7db3cb8cec289350", + "sha256:2b45320af6dfaa1750f543d714b6d1c520a1688dec6fd24d339063ce0aaa9ac3" + ], + "version": "==0.2.2" + }, + "pycparser": { + "hashes": [ + "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9", + "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206" + ], + "version": "==2.21" + }, + "pygments": { + "hashes": [ + "sha256:8ace4d3c1dd481894b2005f560ead0f9f19ee64fe983366be1a21e171d12775c", + "sha256:db2db3deb4b4179f399a09054b023b6a586b76499d36965813c71aa8ed7b5fd1" + ], + "markers": "python_version >= '3.7'", + "version": "==2.15.1" + }, + "pyrsistent": { + "hashes": [ + "sha256:016ad1afadf318eb7911baa24b049909f7f3bb2c5b1ed7b6a8f21db21ea3faa8", + "sha256:1a2994773706bbb4995c31a97bc94f1418314923bd1048c6d964837040376440", + "sha256:20460ac0ea439a3e79caa1dbd560344b64ed75e85d8703943e0b66c2a6150e4a", + "sha256:3311cb4237a341aa52ab8448c27e3a9931e2ee09561ad150ba94e4cfd3fc888c", + "sha256:3a8cb235fa6d3fd7aae6a4f1429bbb1fec1577d978098da1252f0489937786f3", + "sha256:3ab2204234c0ecd8b9368dbd6a53e83c3d4f3cab10ecaf6d0e772f456c442393", + "sha256:42ac0b2f44607eb92ae88609eda931a4f0dfa03038c44c772e07f43e738bcac9", + "sha256:49c32f216c17148695ca0e02a5c521e28a4ee6c5089f97e34fe24163113722da", + "sha256:4b774f9288dda8d425adb6544e5903f1fb6c273ab3128a355c6b972b7df39dcf", + "sha256:4c18264cb84b5e68e7085a43723f9e4c1fd1d935ab240ce02c0324a8e01ccb64", + "sha256:5a474fb80f5e0d6c9394d8db0fc19e90fa540b82ee52dba7d246a7791712f74a", + "sha256:64220c429e42a7150f4bfd280f6f4bb2850f95956bde93c6fda1b70507af6ef3", + "sha256:878433581fc23e906d947a6814336eee031a00e6defba224234169ae3d3d6a98", + "sha256:99abb85579e2165bd8522f0c0138864da97847875ecbd45f3e7e2af569bfc6f2", + "sha256:a2471f3f8693101975b1ff85ffd19bb7ca7dd7c38f8a81701f67d6b4f97b87d8", + "sha256:aeda827381f5e5d65cced3024126529ddc4289d944f75e090572c77ceb19adbf", + "sha256:b735e538f74ec31378f5a1e3886a26d2ca6351106b4dfde376a26fc32a044edc", + "sha256:c147257a92374fde8498491f53ffa8f4822cd70c0d85037e09028e478cababb7", + "sha256:c4db1bd596fefd66b296a3d5d943c94f4fac5bcd13e99bffe2ba6a759d959a28", + "sha256:c74bed51f9b41c48366a286395c67f4e894374306b197e62810e0fdaf2364da2", + "sha256:c9bb60a40a0ab9aba40a59f68214eed5a29c6274c83b2cc206a359c4a89fa41b", + "sha256:cc5d149f31706762c1f8bda2e8c4f8fead6e80312e3692619a75301d3dbb819a", + "sha256:ccf0d6bd208f8111179f0c26fdf84ed7c3891982f2edaeae7422575f47e66b64", + "sha256:e42296a09e83028b3476f7073fcb69ffebac0e66dbbfd1bd847d61f74db30f19", + "sha256:e8f2b814a3dc6225964fa03d8582c6e0b6650d68a232df41e3cc1b66a5d2f8d1", + "sha256:f0774bf48631f3a20471dd7c5989657b639fd2d285b861237ea9e82c36a415a9", + "sha256:f0e7c4b2f77593871e918be000b96c8107da48444d57005b6a6bc61fb4331b2c" + ], + "markers": "python_version >= '3.7'", + "version": "==0.19.3" + }, + "python-dateutil": { + "hashes": [ + "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86", + "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9" + ], + "index": "pypi", + "version": "==2.8.2" + }, + "python-json-logger": { + "hashes": [ + "sha256:23e7ec02d34237c5aa1e29a070193a4ea87583bb4e7f8fd06d3de8264c4b2e1c", + "sha256:f380b826a991ebbe3de4d897aeec42760035ac760345e57b812938dc8b35e2bd" + ], + "markers": "python_version >= '3.6'", + "version": "==2.0.7" + }, + "pytz": { + "hashes": [ + "sha256:1d8ce29db189191fb55338ee6d0387d82ab59f3d00eac103412d64e0ebd0c588", + "sha256:a151b3abb88eda1d4e34a9814df37de2a80e301e68ba0fd856fb9b46bfbbbffb" + ], + "version": "==2023.3" + }, + "pyyaml": { + "hashes": [ + "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf", + "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293", + "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b", + "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57", + "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b", + "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4", + "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07", + "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba", + "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9", + "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287", + "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513", + "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0", + "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782", + "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0", + "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92", + "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f", + "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2", + "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc", + "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1", + "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c", + "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86", + "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4", + "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c", + "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34", + "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b", + "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d", + "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c", + "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb", + "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7", + "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737", + "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3", + "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d", + "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358", + "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53", + "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78", + "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803", + "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a", + "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f", + "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174", + "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5" + ], + "markers": "python_version >= '3.6'", + "version": "==6.0" + }, + "pyzmq": { + "hashes": [ + "sha256:01f06f33e12497dca86353c354461f75275a5ad9eaea181ac0dc1662da8074fa", + "sha256:0b6b42f7055bbc562f63f3df3b63e3dd1ebe9727ff0f124c3aa7bcea7b3a00f9", + "sha256:0c4fc2741e0513b5d5a12fe200d6785bbcc621f6f2278893a9ca7bed7f2efb7d", + "sha256:108c96ebbd573d929740d66e4c3d1bdf31d5cde003b8dc7811a3c8c5b0fc173b", + "sha256:13bbe36da3f8aaf2b7ec12696253c0bf6ffe05f4507985a8844a1081db6ec22d", + "sha256:154bddda2a351161474b36dba03bf1463377ec226a13458725183e508840df89", + "sha256:19d0383b1f18411d137d891cab567de9afa609b214de68b86e20173dc624c101", + "sha256:1a6169e69034eaa06823da6a93a7739ff38716142b3596c180363dee729d713d", + "sha256:1fc56a0221bdf67cfa94ef2d6ce5513a3d209c3dfd21fed4d4e87eca1822e3a3", + "sha256:2a21fec5c3cea45421a19ccbe6250c82f97af4175bc09de4d6dd78fb0cb4c200", + "sha256:2b15247c49d8cbea695b321ae5478d47cffd496a2ec5ef47131a9e79ddd7e46c", + "sha256:2f5efcc29056dfe95e9c9db0dfbb12b62db9c4ad302f812931b6d21dd04a9119", + "sha256:2f666ae327a6899ff560d741681fdcdf4506f990595201ed39b44278c471ad98", + "sha256:332616f95eb400492103ab9d542b69d5f0ff628b23129a4bc0a2fd48da6e4e0b", + "sha256:33d5c8391a34d56224bccf74f458d82fc6e24b3213fc68165c98b708c7a69325", + "sha256:3575699d7fd7c9b2108bc1c6128641a9a825a58577775ada26c02eb29e09c517", + "sha256:3830be8826639d801de9053cf86350ed6742c4321ba4236e4b5568528d7bfed7", + "sha256:3a522510e3434e12aff80187144c6df556bb06fe6b9d01b2ecfbd2b5bfa5c60c", + "sha256:3bed53f7218490c68f0e82a29c92335daa9606216e51c64f37b48eb78f1281f4", + "sha256:414b8beec76521358b49170db7b9967d6974bdfc3297f47f7d23edec37329b00", + "sha256:442d3efc77ca4d35bee3547a8e08e8d4bb88dadb54a8377014938ba98d2e074a", + "sha256:47b915ba666c51391836d7ed9a745926b22c434efa76c119f77bcffa64d2c50c", + "sha256:48e5e59e77c1a83162ab3c163fc01cd2eebc5b34560341a67421b09be0891287", + "sha256:4a82faae00d1eed4809c2f18b37f15ce39a10a1c58fe48b60ad02875d6e13d80", + "sha256:4a983c8694667fd76d793ada77fd36c8317e76aa66eec75be2653cef2ea72883", + "sha256:4c2fc7aad520a97d64ffc98190fce6b64152bde57a10c704b337082679e74f67", + "sha256:4cb27ef9d3bdc0c195b2dc54fcb8720e18b741624686a81942e14c8b67cc61a6", + "sha256:4d67609b37204acad3d566bb7391e0ecc25ef8bae22ff72ebe2ad7ffb7847158", + "sha256:5482f08d2c3c42b920e8771ae8932fbaa0a67dff925fc476996ddd8155a170f3", + "sha256:5489738a692bc7ee9a0a7765979c8a572520d616d12d949eaffc6e061b82b4d1", + "sha256:5693dcc4f163481cf79e98cf2d7995c60e43809e325b77a7748d8024b1b7bcba", + "sha256:58416db767787aedbfd57116714aad6c9ce57215ffa1c3758a52403f7c68cff5", + "sha256:5873d6a60b778848ce23b6c0ac26c39e48969823882f607516b91fb323ce80e5", + "sha256:5af31493663cf76dd36b00dafbc839e83bbca8a0662931e11816d75f36155897", + "sha256:5e7fbcafa3ea16d1de1f213c226005fea21ee16ed56134b75b2dede5a2129e62", + "sha256:65346f507a815a731092421d0d7d60ed551a80d9b75e8b684307d435a5597425", + "sha256:6581e886aec3135964a302a0f5eb68f964869b9efd1dbafdebceaaf2934f8a68", + "sha256:69511d604368f3dc58d4be1b0bad99b61ee92b44afe1cd9b7bd8c5e34ea8248a", + "sha256:7018289b402ebf2b2c06992813523de61d4ce17bd514c4339d8f27a6f6809492", + "sha256:71c7b5896e40720d30cd77a81e62b433b981005bbff0cb2f739e0f8d059b5d99", + "sha256:75217e83faea9edbc29516fc90c817bc40c6b21a5771ecb53e868e45594826b0", + "sha256:7e23a8c3b6c06de40bdb9e06288180d630b562db8ac199e8cc535af81f90e64b", + "sha256:80c41023465d36280e801564a69cbfce8ae85ff79b080e1913f6e90481fb8957", + "sha256:831ba20b660b39e39e5ac8603e8193f8fce1ee03a42c84ade89c36a251449d80", + "sha256:851fb2fe14036cfc1960d806628b80276af5424db09fe5c91c726890c8e6d943", + "sha256:8751f9c1442624da391bbd92bd4b072def6d7702a9390e4479f45c182392ff78", + "sha256:8b45d722046fea5a5694cba5d86f21f78f0052b40a4bbbbf60128ac55bfcc7b6", + "sha256:8b697774ea8273e3c0460cf0bba16cd85ca6c46dfe8b303211816d68c492e132", + "sha256:90146ab578931e0e2826ee39d0c948d0ea72734378f1898939d18bc9c823fcf9", + "sha256:9301cf1d7fc1ddf668d0abbe3e227fc9ab15bc036a31c247276012abb921b5ff", + "sha256:95bd3a998d8c68b76679f6b18f520904af5204f089beebb7b0301d97704634dd", + "sha256:968b0c737797c1809ec602e082cb63e9824ff2329275336bb88bd71591e94a90", + "sha256:97d984b1b2f574bc1bb58296d3c0b64b10e95e7026f8716ed6c0b86d4679843f", + "sha256:9e68ae9864d260b18f311b68d29134d8776d82e7f5d75ce898b40a88df9db30f", + "sha256:adecf6d02b1beab8d7c04bc36f22bb0e4c65a35eb0b4750b91693631d4081c70", + "sha256:af56229ea6527a849ac9fb154a059d7e32e77a8cba27e3e62a1e38d8808cb1a5", + "sha256:b324fa769577fc2c8f5efcd429cef5acbc17d63fe15ed16d6dcbac2c5eb00849", + "sha256:b5a07c4f29bf7cb0164664ef87e4aa25435dcc1f818d29842118b0ac1eb8e2b5", + "sha256:bad172aba822444b32eae54c2d5ab18cd7dee9814fd5c7ed026603b8cae2d05f", + "sha256:bdca18b94c404af6ae5533cd1bc310c4931f7ac97c148bbfd2cd4bdd62b96253", + "sha256:be24a5867b8e3b9dd5c241de359a9a5217698ff616ac2daa47713ba2ebe30ad1", + "sha256:be86a26415a8b6af02cd8d782e3a9ae3872140a057f1cadf0133de685185c02b", + "sha256:c66b7ff2527e18554030319b1376d81560ca0742c6e0b17ff1ee96624a5f1afd", + "sha256:c8398a1b1951aaa330269c35335ae69744be166e67e0ebd9869bdc09426f3871", + "sha256:cad9545f5801a125f162d09ec9b724b7ad9b6440151b89645241d0120e119dcc", + "sha256:cb6d161ae94fb35bb518b74bb06b7293299c15ba3bc099dccd6a5b7ae589aee3", + "sha256:d40682ac60b2a613d36d8d3a0cd14fbdf8e7e0618fbb40aa9fa7b796c9081584", + "sha256:d6128d431b8dfa888bf51c22a04d48bcb3d64431caf02b3cb943269f17fd2994", + "sha256:dbc466744a2db4b7ca05589f21ae1a35066afada2f803f92369f5877c100ef62", + "sha256:ddbef8b53cd16467fdbfa92a712eae46dd066aa19780681a2ce266e88fbc7165", + "sha256:e21cc00e4debe8f54c3ed7b9fcca540f46eee12762a9fa56feb8512fd9057161", + "sha256:eb52e826d16c09ef87132c6e360e1879c984f19a4f62d8a935345deac43f3c12", + "sha256:f0d9e7ba6a815a12c8575ba7887da4b72483e4cfc57179af10c9b937f3f9308f", + "sha256:f1e931d9a92f628858a50f5bdffdfcf839aebe388b82f9d2ccd5d22a38a789dc", + "sha256:f45808eda8b1d71308c5416ef3abe958f033fdbb356984fabbfc7887bed76b3f", + "sha256:f6d39e42a0aa888122d1beb8ec0d4ddfb6c6b45aecb5ba4013c27e2f28657765", + "sha256:fc34fdd458ff77a2a00e3c86f899911f6f269d393ca5675842a6e92eea565bae" + ], + "markers": "python_version >= '3.6'", + "version": "==25.1.0" + }, + "requests": { + "hashes": [ + "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f", + "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1" + ], + "markers": "python_version >= '3.7'", + "version": "==2.31.0" + }, + "rfc3339-validator": { + "hashes": [ + "sha256:138a2abdf93304ad60530167e51d2dfb9549521a836871b88d7f4695d0022f6b", + "sha256:24f6ec1eda14ef823da9e36ec7113124b39c04d50a4d3d3a3c2859577e7791fa" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==0.1.4" + }, + "rfc3986-validator": { + "hashes": [ + "sha256:2f235c432ef459970b4306369336b9d5dbdda31b510ca1e327636e01f528bfa9", + "sha256:3d44bde7921b3b9ec3ae4e3adca370438eccebc676456449b145d533b240d055" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==0.1.1" + }, + "send2trash": { + "hashes": [ + "sha256:a384719d99c07ce1eefd6905d2decb6f8b7ed054025bb0e618919f945de4f679", + "sha256:c132d59fa44b9ca2b1699af5c86f57ce9f4c5eb56629d5d55fbb7a35f84e2312" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==1.8.2" + }, + "six": { + "hashes": [ + "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", + "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", + "version": "==1.16.0" + }, + "sniffio": { + "hashes": [ + "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101", + "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384" + ], + "markers": "python_version >= '3.7'", + "version": "==1.3.0" + }, + "soupsieve": { + "hashes": [ + "sha256:1c1bfee6819544a3447586c889157365a27e10d88cde3ad3da0cf0ddf646feb8", + "sha256:89d12b2d5dfcd2c9e8c22326da9d9aa9cb3dfab0a83a024f05704076ee8d35ea" + ], + "markers": "python_version >= '3.7'", + "version": "==2.4.1" + }, + "stack-data": { + "hashes": [ + "sha256:32d2dd0376772d01b6cb9fc996f3c8b57a357089dec328ed4b6553d037eaf815", + "sha256:cbb2a53eb64e5785878201a97ed7c7b94883f48b87bfb0bbe8b623c74679e4a8" + ], + "version": "==0.6.2" + }, + "terminado": { + "hashes": [ + "sha256:6ccbbcd3a4f8a25a5ec04991f39a0b8db52dfcd487ea0e578d977e6752380333", + "sha256:8650d44334eba354dd591129ca3124a6ba42c3d5b70df5051b6921d506fdaeae" + ], + "markers": "python_version >= '3.7'", + "version": "==0.17.1" + }, + "tinycss2": { + "hashes": [ + "sha256:2b80a96d41e7c3914b8cda8bc7f705a4d9c49275616e886103dd839dfc847847", + "sha256:8cff3a8f066c2ec677c06dbc7b45619804a6938478d9d73c284b29d14ecb0627" + ], + "markers": "python_version >= '3.7'", + "version": "==1.2.1" + }, + "tornado": { + "hashes": [ + "sha256:05615096845cf50a895026f749195bf0b10b8909f9be672f50b0fe69cba368e4", + "sha256:0c325e66c8123c606eea33084976c832aa4e766b7dff8aedd7587ea44a604cdf", + "sha256:29e71c847a35f6e10ca3b5c2990a52ce38b233019d8e858b755ea6ce4dcdd19d", + "sha256:4b927c4f19b71e627b13f3db2324e4ae660527143f9e1f2e2fb404f3a187e2ba", + "sha256:5b17b1cf5f8354efa3d37c6e28fdfd9c1c1e5122f2cb56dac121ac61baa47cbe", + "sha256:6a0848f1aea0d196a7c4f6772197cbe2abc4266f836b0aac76947872cd29b411", + "sha256:7efcbcc30b7c654eb6a8c9c9da787a851c18f8ccd4a5a3a95b05c7accfa068d2", + "sha256:834ae7540ad3a83199a8da8f9f2d383e3c3d5130a328889e4cc991acc81e87a0", + "sha256:b46a6ab20f5c7c1cb949c72c1994a4585d2eaa0be4853f50a03b5031e964fc7c", + "sha256:c2de14066c4a38b4ecbbcd55c5cc4b5340eb04f1c5e81da7451ef555859c833f", + "sha256:c367ab6c0393d71171123ca5515c61ff62fe09024fa6bf299cd1339dc9456829" + ], + "markers": "python_version >= '3.8'", + "version": "==6.3.2" + }, + "traitlets": { + "hashes": [ + "sha256:9e6ec080259b9a5940c797d58b613b5e31441c2257b87c2e795c5228ae80d2d8", + "sha256:f6cde21a9c68cf756af02035f72d5a723bf607e862e7be33ece505abf4a3bad9" + ], + "markers": "python_version >= '3.7'", + "version": "==5.9.0" + }, + "typing-extensions": { + "hashes": [ + "sha256:88a4153d8505aabbb4e13aacb7c486c2b4a33ca3b3f807914a9b4c844c471c26", + "sha256:d91d5919357fe7f681a9f2b5b4cb2a5f1ef0a1e9f59c4d8ff0d3491e05c0ffd5" + ], + "markers": "python_version >= '3.7'", + "version": "==4.6.3" + }, + "tzdata": { + "hashes": [ + "sha256:11ef1e08e54acb0d4f95bdb1be05da659673de4acbd21bf9c69e94cc5e907a3a", + "sha256:7e65763eef3120314099b6939b5546db7adce1e7d6f2e179e3df563c70511eda" + ], + "markers": "python_version >= '2'", + "version": "==2023.3" + }, + "uri-template": { + "hashes": [ + "sha256:934e4d09d108b70eb8a24410af8615294d09d279ce0e7cbcdaef1bd21f932b06", + "sha256:f1699c77b73b925cf4937eae31ab282a86dc885c333f2e942513f08f691fc7db" + ], + "version": "==1.2.0" + }, + "urllib3": { + "hashes": [ + "sha256:48e7fafa40319d358848e1bc6809b208340fafe2096f1725d05d67443d0483d1", + "sha256:bee28b5e56addb8226c96f7f13ac28cb4c301dd5ea8a6ca179c0b9835e032825" + ], + "markers": "python_version >= '3.7'", + "version": "==2.0.3" + }, + "wcwidth": { + "hashes": [ + "sha256:795b138f6875577cd91bba52baf9e445cd5118fd32723b460e30a0af30ea230e", + "sha256:a5220780a404dbe3353789870978e472cfe477761f06ee55077256e509b156d0" + ], + "version": "==0.2.6" + }, + "webcolors": { + "hashes": [ + "sha256:29bc7e8752c0a1bd4a1f03c14d6e6a72e93d82193738fa860cbff59d0fcc11bf", + "sha256:c225b674c83fa923be93d235330ce0300373d02885cef23238813b0d5668304a" + ], + "version": "==1.13" + }, + "webencodings": { + "hashes": [ + "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78", + "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923" + ], + "version": "==0.5.1" + }, + "websocket-client": { + "hashes": [ + "sha256:3566f8467cd350874c4913816355642a4942f6c1ed1e9406e3d42fae6d6c072a", + "sha256:b96f3bce3e54e3486ebe6504bc22bd4c140392bd2eb71764db29be8f2639aa65" + ], + "markers": "python_version >= '3.7'", + "version": "==1.5.3" + } + }, + "develop": {} +} diff --git a/src/jupyter/PopulateDatabase.ipynb b/src/jupyter/PopulateDatabase.ipynb index 00c89d5..4b0081b 100644 --- a/src/jupyter/PopulateDatabase.ipynb +++ b/src/jupyter/PopulateDatabase.ipynb @@ -27,38 +27,13 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "id": "92716416-e32a-4944-9af2-23b9ac53d576", "metadata": { - "execution": { - "iopub.execute_input": "2023-03-20T12:48:01.774830Z", - "iopub.status.busy": "2023-03-20T12:48:01.774489Z", - "iopub.status.idle": "2023-03-20T12:48:02.229789Z", - "shell.execute_reply": "2023-03-20T12:48:02.229117Z", - "shell.execute_reply.started": "2023-03-20T12:48:01.774776Z" - }, + "scrolled": true, "tags": [] }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Welcome to flowkit-ui-backend!\n", - "{\n", - " \"datetime\": \"2023-03-20T12:48:02.225106+00:00\",\n", - " \"docker_image\": \"flowminder/flowkit-ui-backend:890c0e0\",\n", - " \"git_branch\": \"feature-scope-mapping\",\n", - " \"git_commit\": \"890c0e0\",\n", - " \"git_tag\": null,\n", - " \"python_package\": \"flowkit-ui-backend\",\n", - " \"python_version\": \"3.9.15\",\n", - " \"api_version_url_appendix\": \"v1\",\n", - " \"api_version\": \"1.2.1\"\n", - "}\n" - ] - } - ], + "outputs": [], "source": [ "import httpx\n", "import csv\n", @@ -73,7 +48,7 @@ "from dateutil import parser\n", "\n", "# whether to ingest synthetic data or real data\n", - "SYNTHETIC = True\n", + "SYNTHETIC = False\n", "\n", "AUDIENCE = os.getenv(\"AUTH0_AUDIENCE\")\n", "BASE_URL = os.getenv(\"INGESTION_BASE_URL\")\n", @@ -112,28 +87,23 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, + "id": "ec8fa850-9ae2-44e2-9629-7efce6b90603", + "metadata": {}, + "outputs": [], + "source": [ + "AUTH0_DOMAIN" + ] + }, + { + "cell_type": "code", + "execution_count": null, "id": "fc4b2bfe-8ec6-4d6e-80d8-d1a047d0a185", "metadata": { - "execution": { - "iopub.execute_input": "2023-03-20T12:48:04.419141Z", - "iopub.status.busy": "2023-03-20T12:48:04.418755Z", - "iopub.status.idle": "2023-03-20T12:48:05.273750Z", - "shell.execute_reply": "2023-03-20T12:48:05.273262Z", - "shell.execute_reply.started": "2023-03-20T12:48:04.419109Z" - }, + "scrolled": true, "tags": [] }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "\n" - ] - } - ], + "outputs": [], "source": [ "response = httpx.post(\n", " url=f\"https://{AUTH0_DOMAIN}/oauth/token\",\n", @@ -165,29 +135,12 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "id": "19a726e7-34fc-4625-890c-4ab07e76c638", "metadata": { - "execution": { - "iopub.execute_input": "2023-03-20T12:48:06.584818Z", - "iopub.status.busy": "2023-03-20T12:48:06.584581Z", - "iopub.status.idle": "2023-03-20T12:48:06.874410Z", - "shell.execute_reply": "2023-03-20T12:48:06.873615Z", - "shell.execute_reply.started": "2023-03-20T12:48:06.584799Z" - }, "tags": [] }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{\n", - " \"categories\": []\n", - "}\n" - ] - } - ], + "outputs": [], "source": [ "response = httpx.get(\n", " url=f\"{BASE_URL}/categories\", headers={\"Authorization\": f\"Bearer {admin_token}\"}\n", @@ -218,32 +171,27 @@ }, { "cell_type": "code", - "execution_count": 4, - "id": "5de63f9f-22e7-430a-9865-b0eb69dd3a23", + "execution_count": null, + "id": "118a5f52-a7a6-471a-adfd-0b4547fec0ea", "metadata": { - "execution": { - "iopub.execute_input": "2023-03-20T12:48:08.653418Z", - "iopub.status.busy": "2023-03-20T12:48:08.653215Z", - "iopub.status.idle": "2023-03-20T12:48:11.872822Z", - "shell.execute_reply": "2023-03-20T12:48:11.872075Z", - "shell.execute_reply.started": "2023-03-20T12:48:08.653403Z" - }, "tags": [] }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "204: \n" - ] - } - ], + "outputs": [], "source": [ "# get config directly from the resources\n", - "with open(f\"{os.getenv('PACKAGE_NAME')}/src/impl/resources/config.json\") as json_data:\n", - " config = json.load(json_data)\n", - "\n", + "with open(f\"../impl/resources/config.json\") as json_data:\n", + " config = json.load(json_data)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5b2bf5b6-88f6-457b-af2e-7de3a50882e6", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ "response = httpx.post(\n", " url=f\"{BASE_URL}/setup\",\n", " headers={\n", @@ -264,81 +212,95 @@ "source": [ "Either way, the db should now have a basic setup.\n", "Let's check if we have all the metadata we need before we proceed.\n", - "While we're at it, we save the categories so we can use them for the ingestion in the next step." + "While we're at it, we save the categories so we can use them for the ingestion in the next step. We'll do the same for the indicators, and spatial and temporal resolutions as well." ] }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "id": "a3971755-2d36-44c4-a36a-f2d612fd2642", "metadata": { - "execution": { - "iopub.execute_input": "2023-03-20T12:48:13.449918Z", - "iopub.status.busy": "2023-03-20T12:48:13.449631Z", - "iopub.status.idle": "2023-03-20T12:48:13.470302Z", - "shell.execute_reply": "2023-03-20T12:48:13.469341Z", - "shell.execute_reply.started": "2023-03-20T12:48:13.449899Z" - }, + "scrolled": true, "tags": [] }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{\n", - " \"categories\": [\n", - " {\n", - " \"category_id\": \"residents\",\n", - " \"type\": \"single_location\",\n", - " \"order\": 1,\n", - " \"flowgeek_url\": \"https://www.flowgeek.org/methods/calculating-mobility-indicators/residents-indicators\",\n", - " \"label\": \"Residents\",\n", - " \"description\": \"Residents-class indicators describe long-term (monthly) changes in the number of people whose home location is within each area.\",\n", - " \"label_fr\": \"R\\u00e9sidents\",\n", - " \"description_fr\": \"Les indicateurs relatifs aux r\\u00e9sidents d\\u00e9crivent les variations (mensuelles) \\u00e0 long terme du nombre de personnes dont le lieu de r\\u00e9sidence se trouve dans chaque zone.\"\n", - " },\n", - " {\n", - " \"category_id\": \"relocations\",\n", - " \"type\": \"flow\",\n", - " \"order\": 2,\n", - " \"flowgeek_url\": \"https://www.flowgeek.org/methods/calculating-mobility-indicators/relocation-indicators/\",\n", - " \"label\": \"Relocation\",\n", - " \"description\": \"Relocation-class indicators describe long-term (monthly) changes in the number of people changing their home location between pairs of areas.\",\n", - " \"label_fr\": \"Changement de r\\u00e9sidence\",\n", - " \"description_fr\": \"Les indicateurs relatifs au changement de r\\u00e9sidence d\\u00e9crivent les variations (mensuelles) \\u00e0 long terme du nombre de personnes qui changent de lieu de r\\u00e9sidence entre des paires de zones.\"\n", - " },\n", - " {\n", - " \"category_id\": \"presence\",\n", - " \"type\": \"single_location\",\n", - " \"order\": 3,\n", - " \"flowgeek_url\": \"https://www.flowgeek.org/methods/calculating-mobility-indicators/presence-indicators/\",\n", - " \"label\": \"Presence\",\n", - " \"description\": \"Presence-class indicators describe short-term (daily) changes in the number of people who are present within each area.\",\n", - " \"label_fr\": \"Pr\\u00e9sence journali\\u00e8re\",\n", - " \"description_fr\": \"Les indicateurs relatifs \\u00e0 la pr\\u00e9sence d\\u00e9crivent les variations \\u00e0 court terme du nombre de personnes pr\\u00e9sentes dans chaque zone.\"\n", - " },\n", - " {\n", - " \"category_id\": \"movements\",\n", - " \"type\": \"flow\",\n", - " \"order\": 4,\n", - " \"flowgeek_url\": \"https://www.flowgeek.org/methods/calculating-mobility-indicators/movement-indicators\",\n", - " \"label\": \"Movements\",\n", - " \"description\": \"Movements-class indicators describe short-term changes in the number of people who are travelling into, out of and between areas.\",\n", - " \"label_fr\": \"Mouvements journaliers\",\n", - " \"description_fr\": \"Les indicateurs relatifs aux mouvements d\\u00e9crivent les variations \\u00e0 court terme du nombre de personnes qui se d\\u00e9placent vers, depuis et entre les zones.\"\n", - " }\n", - " ]\n", - "}\n" - ] - } - ], + "outputs": [], "source": [ "response = httpx.get(\n", " url=f\"{BASE_URL}/categories\", headers={\"Authorization\": f\"Bearer {admin_token}\"}\n", ")\n", "log(response)\n", - "categories = json.loads(response.content)[\"categories\"]" + "categories = json.loads(response.content)[\"categories\"]\n", + "category_type_lookup = {ct[\"category_id\"]: ct[\"type\"] for ct in categories}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fa51b9e3-969b-4f86-acb7-cdec51712f53", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "response = httpx.get(\n", + " url=f\"{BASE_URL}/indicators\", headers={\"Authorization\": f\"Bearer {admin_token}\"}\n", + ")\n", + "log(response)\n", + "indicators = json.loads(response.content)[\"indicators\"]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f05b9612-da09-407c-a3c3-ee4dd63120ac", + "metadata": {}, + "outputs": [], + "source": [ + "# Update indicators\n", + "\n", + "indicators = config['indicators']\n", + "for indicator in indicators:\n", + " response = httpx.patch(\n", + " url=f\"{BASE_URL}/indicators/{indicator['indicator_id']}\",\n", + " headers={\n", + " \"Content-Type\": \"application/json\",\n", + " \"Content-Encoding\": \"gzip\",\n", + " \"Authorization\": f\"Bearer {admin_token}\",\n", + " },\n", + " data=gzip.compress(json.dumps(indicator).encode(\"utf-8\")),\n", + " timeout=3600,\n", + " )\n", + " log(response)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4137b9c8-aece-417b-bdab-fd7ea33cafe0", + "metadata": {}, + "outputs": [], + "source": [ + "response = httpx.get(\n", + " url=f\"{BASE_URL}/spatial_resolutions\", headers={\"Authorization\": f\"Bearer {admin_token}\"}\n", + ")\n", + "log(response)\n", + "spatial_resolutions = json.loads(response.content)[\"spatial_resolutions\"]\n", + "srid_lookup = {f\"adm{sr['index']}\": sr[\"srid\"] for sr in spatial_resolutions}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "415b5ae3-919a-463e-a79d-f457add0b065", + "metadata": {}, + "outputs": [], + "source": [ + "response = httpx.get(\n", + " url=f\"{BASE_URL}/temporal_resolutions\", headers={\"Authorization\": f\"Bearer {admin_token}\"}\n", + ")\n", + "log(response)\n", + "temporal_resolutions = json.loads(response.content)[\"temporal_resolutions\"]\n", + "trid_lookup = {tr[\"relativedelta_unit\"]: tr[\"trid\"] for tr in temporal_resolutions}" ] }, { @@ -348,213 +310,203 @@ "source": [ "## Data cleaning\n", "\n", - "The data format - although agreed upon in principle - is not well-defined enough to guarantee successful insertion.\n", - "Before we can ingest it, we need to pre-process it in order to\n", - "\n", - "- remove empty/invalid data\n", - "- correctly format the dates\n", - "- check all expected fields are present\n", - "- columns are named/ordered correctly\n", - "- data is sorted (which helps increase ingestion speed)" + "Each file is a csv containing indicators for multiple dates for one category, at one spatial resolution and one temporal resolution. At present, there are not multiple resolutions per indicator, so we're assuming the files are just named for the category, e.g. `residents.csv`.\n", + "\n", + "We're going to rename the date and spatial columns, then create dataset files for them, which are a json representation structured:\n", + "\n", + "```\n", + "{\n", + "\"metadata\": {\n", + " \"revision\": ,\n", + " # adding a date here which will be overwritten later when it is actually added to the db\n", + " # this is to avoid a fastapi.exceptions.RequestValidationError for checking the length of a \"None\" type\n", + " \"date_added\": ,\n", + " \"category_id\": category_id,\n", + " \"indicator_id\": indicator_id,\n", + " \"srid\": ,\n", + " \"trid\": ,\n", + " \"dt\": ,\n", + " },\n", + " \"data_type\": ,\n", + " \"data_input\": [\n", + " {\n", + " \"spatial_unit_ids\": ,\n", + " \"data\": ,\n", + " }\n", + " ],\n", + "}\n", + "```" ] }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, + "id": "9b12a97d-bd7e-4897-b497-e9384ce56427", + "metadata": {}, + "outputs": [], + "source": [ + "import pathlib" + ] + }, + { + "cell_type": "code", + "execution_count": null, "id": "11e9568f-7066-4be0-992a-5fc6a2aeb1bf", "metadata": { - "execution": { - "iopub.execute_input": "2023-03-20T12:48:16.820959Z", - "iopub.status.busy": "2023-03-20T12:48:16.820590Z", - "iopub.status.idle": "2023-03-20T12:48:17.025361Z", - "shell.execute_reply": "2023-03-20T12:48:17.024752Z", - "shell.execute_reply.started": "2023-03-20T12:48:16.820925Z" - }, + "scrolled": true, "tags": [] }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Saved CSV to /tmp/residents_admin3_monthly_small_preprocessed.csv\n", - "Saved CSV to /tmp/relocations_admin3_monthly_small_preprocessed.csv\n", - "Saved CSV to /tmp/presence_admin3_daily_small_preprocessed.csv\n", - "Saved CSV to /tmp/movements_admin3_daily_small_preprocessed.csv\n" - ] - } - ], + "outputs": [], "source": [ "real_data_files = {\n", - " \"residents\": {\"category_id\": \"residents\", \"srid\": 3, \"trid\": 2},\n", - " \"relocations\": {\"category_id\": \"relocations\", \"srid\": 3, \"trid\": 2},\n", - " \"presence\": {\"category_id\": \"presence\", \"srid\": 3, \"trid\": 4},\n", - " \"movements\": {\"category_id\": \"movements\", \"srid\": 3, \"trid\": 4},\n", + " \"residents\": {\n", + " \"category_id\": \"residents\",\n", + " \"srid\": srid_lookup[\"adm3\"],\n", + " \"trid\": trid_lookup[\"months\"],\n", + " },\n", + " \"relocations\": {\n", + " \"category_id\": \"relocations\",\n", + " \"srid\": srid_lookup[\"adm3\"],\n", + " \"trid\": trid_lookup[\"months\"],\n", + " },\n", + " \"presence\": {\n", + " \"category_id\": \"presence\",\n", + " \"srid\": srid_lookup[\"adm3\"],\n", + " \"trid\": trid_lookup[\"days\"],\n", + " },\n", + " \"movements\": {\n", + " \"category_id\": \"movements\",\n", + " \"srid\": srid_lookup[\"adm3\"],\n", + " \"trid\": trid_lookup[\"days\"],\n", + " },\n", "}\n", "synthetic_files = {\n", - " \"residents_admin3_monthly_small\": {\"category_id\": \"residents\", \"srid\": 3, \"trid\": 2},\n", - " \"relocations_admin3_monthly_small\": {\"category_id\": \"relocations\", \"srid\": 3, \"trid\": 2},\n", - " \"presence_admin3_daily_small\": {\"category_id\": \"presence\", \"srid\": 3, \"trid\": 4},\n", - " \"movements_admin3_daily_small\": {\"category_id\": \"movements\", \"srid\": 3, \"trid\": 4},\n", + " \"residents_admin3_monthly_small\": {\n", + " \"category_id\": \"residents\",\n", + " \"srid\": srid_lookup[\"adm3\"],\n", + " \"trid\": trid_lookup[\"months\"],\n", + " },\n", + " \"relocations_admin3_monthly_small\": {\n", + " \"category_id\": \"relocations\",\n", + " \"srid\": srid_lookup[\"adm3\"],\n", + " \"trid\": trid_lookup[\"months\"],\n", + " },\n", + " \"presence_admin3_daily_small\": {\n", + " \"category_id\": \"presence\",\n", + " \"srid\": srid_lookup[\"adm3\"],\n", + " \"trid\": trid_lookup[\"days\"],\n", + " },\n", + " \"movements_admin3_daily_small\": {\n", + " \"category_id\": \"movements\",\n", + " \"srid\": srid_lookup[\"adm3\"],\n", + " \"trid\": trid_lookup[\"days\"],\n", + " },\n", "}\n", + "\n", + "data_version = \"v1.0.2\"\n", "files = synthetic_files if SYNTHETIC else real_data_files\n", "\n", - "parent_dir = f\"{os.getenv('PACKAGE_NAME')}/src/impl/resources\"\n", + "parent_dir = f\"../impl/resources\"\n", "data_dir = f\"{parent_dir}/data/synthetic\" if SYNTHETIC else f\"{parent_dir}/data\"\n", "\n", - "for file_name in files.keys():\n", + "# Discard inf as well as na\n", + "pd.set_option(\"use_inf_as_na\", True)\n", + "\n", + "\n", + "def to_su_list(val):\n", + " if isinstance(val, tuple):\n", + " return [*val]\n", + " else:\n", + " return [val]\n", + "\n", + "\n", + "for file_name, meta in files.items():\n", " file_path = f\"{data_dir}/{file_name}.csv\"\n", " preprocessed_path = f\"/tmp/{file_name}_preprocessed.csv\"\n", - " df = pd.read_csv(file_path)\n", - "\n", - " # make sure only rows with data are kept\n", - " # then sort by date, and spatial unit(s) if applicable\n", - " # finally rename columns\n", + " df = pd.read_csv(file_path) # First column is the date\n", " if file_name in [\"residents\", \"presence\"]:\n", " # min columns: date, spatial unit, one data column\n", - " df = df.dropna(thresh=3)\n", - " df = df.sort_values(by=[df.columns[0], df.columns[1]])\n", - " df = df.rename(columns={df.columns[0]: \"date\", df.columns[1]: \"spatial_unit\"})\n", + " df = df.rename(columns={\"pcod\": \"spatial_unit\"})\n", + " df[\"date\"] = pd.to_datetime(df.date)\n", + " df = df.set_index([\"date\", \"spatial_unit\"])\n", " elif file_name in [\"relocations\", \"movements\"]:\n", " # min columns: date, 2 spatial units, one data column\n", - " df = df.dropna(thresh=4)\n", - " df = df.sort_values(by=[df.columns[0], df.columns[1], df.columns[2]])\n", - " df = df.rename(\n", - " columns={df.columns[0]: \"date\", df.columns[1]: \"origin\", df.columns[1]: \"destination\"}\n", - " )\n", - "\n", - " df.to_csv(preprocessed_path, index=False)\n", - " print(f\"Saved CSV to {preprocessed_path}\")" + " df = df.rename(columns={\"month\": \"date\", \"pcod_from\": \"origin\", \"pcod_to\": \"destination\"})\n", + " df[\"date\"] = pd.to_datetime(df.date)\n", + " df = df.set_index([\"date\", \"origin\", \"destination\"])\n", + " df = df.sort_index()\n", + " for column in df.columns:\n", + " indicator_df = df[[column]].dropna()\n", + " dates = indicator_df.index.levels[0]\n", + " for dt in dates:\n", + " fname = f\"./tmp/{meta['category_id']}_{column}_{meta['srid']}_{meta['trid']}_{dt.strftime('%Y-%m-%dT%H:%M:%S')}_{data_version}.json\"\n", + " if pathlib.Path(fname).exists():\n", + " continue\n", + " try:\n", + " dataset = {\n", + " \"metadata\": {\n", + " \"revision\": data_version,\n", + " # adding a date here which will be overwritten later when it is actually added to the db\n", + " # this is to avoid a fastapi.exceptions.RequestValidationError for checking the length of a \"None\" type\n", + " \"date_added\": datetime.utcnow().strftime(\"%Y-%m-%dT%H:%M:%S\"),\n", + " \"category_id\": meta[\"category_id\"],\n", + " \"indicator_id\": f\"{meta['category_id']}.{column}\",\n", + " \"srid\": meta[\"srid\"],\n", + " \"trid\": meta[\"trid\"],\n", + " \"dt\": dt.strftime(\"%Y-%m-%dT%H:%M:%S\"),\n", + " },\n", + " \"data_type\": category_type_lookup[meta[\"category_id\"]],\n", + " \"data_input\": [\n", + " {\n", + " \"spatial_unit_ids\": to_su_list(rw[0]),\n", + " \"data\": rw[1],\n", + " }\n", + " for rw in indicator_df.loc[dt].itertuples()\n", + " ],\n", + " }\n", + " fname = f\"./tmp/{meta['category_id']}_{column}_{meta['srid']}_{meta['trid']}_{dt.strftime('%Y-%m-%dT%H:%M:%S')}_{data_version}.json\"\n", + " with open(fname, \"w\") as fout:\n", + " json.dump(dataset, fout)\n", + " print(f\"Wrote {fname}\")\n", + " except KeyError:\n", + " pass" ] }, { "cell_type": "markdown", - "id": "5e7396ae-a7b9-4ffd-a244-dad08121cd61", + "id": "7b3d0db6-9296-431b-a9aa-a22c6a1c360e", "metadata": {}, "source": [ - "We can check the files before starting the ingestion:" + "## Data ingestion\n", + "\n", + "Now we can load the data we want to ingest. We'll glob all the files for the data version, and post them up. (In fact, we're going to send a PATCH so we replace what's there.)\n", + "\n", + "\n", + "It's still recommended to compress the request body using `gzip`." ] }, { "cell_type": "code", - "execution_count": 7, - "id": "766b7455-ed80-442d-bed6-dc0faa739699", - "metadata": { - "execution": { - "iopub.execute_input": "2023-03-20T12:48:31.746606Z", - "iopub.status.busy": "2023-03-20T12:48:31.746422Z", - "iopub.status.idle": "2023-03-20T12:48:31.760791Z", - "shell.execute_reply": "2023-03-20T12:48:31.760105Z", - "shell.execute_reply.started": "2023-03-20T12:48:31.746592Z" - }, - "tags": [] - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "3129 /tmp/residents_admin3_monthly_small_preprocessed.csv\n", - "--------------------\n", - "month,pcod,residents,residents_perKm2,arrived,departed,delta_arrived,residents_diffwithref,abnormality,residents_pctchangewithref\n", - "2020-02-01,HT0111-01,544650,29650,446860,427110,19760,-880.0,-0.68,-0.16\n", - "2020-02-01,HT0111-02,75340,10880,33420,31480,1940,1950.0,0.86,2.65\n", - "--------------------\n", - "2020-07-01,HT1031-05,9630,170,1040,1040,0,0.0,0.0,0.0\n", - "2020-07-01,HT1032-01,1770,60,160,160,0,0.0,0.0,0.0\n", - "2020-07-01,HT1032-02,3030,220,420,420,0,0.0,0.0,0.0\n" - ] - } - ], - "source": [ - "%%bash -s /tmp/residents_admin3_monthly_small_preprocessed.csv\n", - "# check the file\n", - "wc -l \"$1\"\n", - "echo '--------------------'\n", - "head -n 3 \"$1\"\n", - "echo '--------------------'\n", - "tail -n 3 \"$1\"" - ] - }, - { - "cell_type": "markdown", - "id": "7b3d0db6-9296-431b-a9aa-a22c6a1c360e", + "execution_count": null, + "id": "dcd22e42-3fcf-4738-8f17-3369a94536b1", "metadata": {}, + "outputs": [], "source": [ - "## Data ingestion\n", - "\n", - "Now we can load the data we want to ingest.\n", - "We need to process the CSV files, which contain all indicators and dates for one category but the API ingests data in smaller chunks (one API call per indicator per date).\n", - "It's still recommended to compress the request body using `gzip`." + "len(list(pathlib.Path(\"/tmp\").glob(f\"*_{data_version}.json\")))" ] }, { "cell_type": "code", - "execution_count": 8, - "id": "4eb65dfb-5e73-4cb4-8cbb-0339f6d9752f", + "execution_count": null, + "id": "fd8ecc8a-c468-4ea2-9ad1-8289513ae478", "metadata": { - "execution": { - "iopub.execute_input": "2023-03-20T12:48:37.960616Z", - "iopub.status.busy": "2023-03-20T12:48:37.960227Z", - "iopub.status.idle": "2023-03-20T12:49:04.574392Z", - "shell.execute_reply": "2023-03-20T12:49:04.573758Z", - "shell.execute_reply.started": "2023-03-20T12:48:37.960507Z" - }, "tags": [] }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Processing file residents_admin3_monthly_small.csv\n", - "Found 8 indicators for category residents\n", - "Prepared requests in 0.72s\n", - "Starting ingestion of data for 8 indicators...\n", - " Ingesting 6 datasets for indicator residents.residents.\n", - " Ingesting 6 datasets for indicator residents.residents_perKm2.\n", - " Ingesting 6 datasets for indicator residents.arrived.\n", - " Ingesting 6 datasets for indicator residents.departed.\n", - " Ingesting 6 datasets for indicator residents.delta_arrived.\n", - " Ingesting 6 datasets for indicator residents.residents_diffwithref.\n", - " Ingesting 6 datasets for indicator residents.abnormality.\n", - " Ingesting 6 datasets for indicator residents.residents_pctchangewithref.\n", - "Ingested 48/48 datasets (100.0%) in 1.93s\n", - "Processing file relocations_admin3_monthly_small.csv\n", - "Found 4 indicators for category relocations\n", - "Prepared requests in 4.98s\n", - "Starting ingestion of data for 4 indicators...\n", - " Ingesting 6 datasets for indicator relocations.relocations.\n", - " Ingesting 6 datasets for indicator relocations.relocations_diffwithref.\n", - " Ingesting 6 datasets for indicator relocations.abnormality.\n", - " Ingesting 6 datasets for indicator relocations.relocations_pctchangewithref.\n", - "Ingested 24/24 datasets (100.0%) in 5.63s\n", - "Processing file presence_admin3_daily_small.csv\n", - "Found 7 indicators for category presence\n", - "Prepared requests in 0.88s\n", - "Starting ingestion of data for 7 indicators...\n", - " Ingesting 7 datasets for indicator presence.presence.\n", - " Ingesting 7 datasets for indicator presence.presence_perKm2.\n", - " Ingesting 7 datasets for indicator presence.trips_in.\n", - " Ingesting 7 datasets for indicator presence.trips_out.\n", - " Ingesting 7 datasets for indicator presence.abnormality.\n", - " Ingesting 7 datasets for indicator presence.presence_diffwithref.\n", - " Ingesting 7 datasets for indicator presence.presence_pctchangewithref.\n", - "Ingested 49/49 datasets (100.0%) in 1.83s\n", - "Processing file movements_admin3_daily_small.csv\n", - "Found 4 indicators for category movements\n", - "Prepared requests in 4.98s\n", - "Starting ingestion of data for 4 indicators...\n", - " Ingesting 7 datasets for indicator movements.travellers.\n", - " Ingesting 7 datasets for indicator movements.abnormality.\n", - " Ingesting 7 datasets for indicator movements.travellers_diffwithref.\n", - " Ingesting 7 datasets for indicator movements.travellers_pctchangewithref.\n", - "Ingested 28/28 datasets (100.0%) in 5.57s\n" - ] - } - ], - "source": [ - "CHUNK_SIZE = 50\n", + "outputs": [], + "source": [ + "CHUNK_SIZE = 20\n", + "\n", + "import pathlib\n", "\n", "\n", "def chunked_iterable(iterable, size):\n", @@ -567,7 +519,7 @@ "\n", "\n", "async def post_async(ds, client):\n", - " return await client.post(\n", + " return await client.patch(\n", " url=f\"{BASE_URL}/data\",\n", " headers={\n", " \"Content-Type\": \"application/json\",\n", @@ -579,131 +531,47 @@ " )\n", "\n", "\n", - "async def ingest_data(file_name):\n", - " start_time = time.monotonic()\n", + "def yield_files_for_version(data_version):\n", + " files = pathlib.Path(\"tmp\").glob(f\"*_{data_version}.json\")\n", + " for fname in files:\n", + " with open(fname) as fin:\n", + " try:\n", + " yield json.load(fin)\n", + " except Exception as exc:\n", + " print(exc)\n", + " print(fname)\n", "\n", - " print(f\"Processing file {file_name}.csv\")\n", - " f = files[file_name]\n", "\n", - " # get the category object\n", - " category_id = f[\"category_id\"]\n", - " category = [c for c in categories if c[\"category_id\"] == category_id][0]\n", - " # get all indicators for that category\n", - " response = httpx.get(\n", - " url=f\"{BASE_URL}/indicators_for_category/{category_id}\",\n", - " headers={\"Authorization\": f\"Bearer {admin_token}\"},\n", - " )\n", - " indicators = json.loads(response.content)[\"indicators\"]\n", - " print(f\"Found {len(indicators)} indicators for category {category_id}\")\n", + "def count_files_for_version(data_version):\n", + " return len(list(pathlib.Path(\"tmp\").glob(f\"*_{data_version}.json\")))\n", "\n", - " # get column names and order from csv\n", - " columns = []\n", - " column_to_indicator_id = {}\n", "\n", - " with open(f\"/tmp/{file_name}_preprocessed.csv\") as csv_file:\n", - " csv_reader = csv.reader(csv_file, delimiter=\",\")\n", - " for row in csv_reader:\n", - " columns = row\n", - " break\n", - "\n", - " for col in columns:\n", - " column_to_indicator_id[col] = f\"{category_id}.{col}\"\n", - "\n", - " # sort data by ID for easier processing\n", - " indicators_by_id = {i[\"indicator_id\"]: i for i in indicators}\n", - "\n", - " # collect all datasets in a dict by indicator ID and date - that way it doesn't matter whether the CSV file is ordered\n", - " datasets = {}\n", - " total_num = 0\n", - " # we already consumed the first row so can continue here with the same reader\n", - " for row in csv_reader:\n", - " # check each column in each row\n", - " for col in columns:\n", - " if (\n", - " col in column_to_indicator_id\n", - " and column_to_indicator_id[col] in indicators_by_id\n", - " ):\n", - " value = row[columns.index(col)]\n", - " # skip \"None\" values\n", - " if value in [\"NaN\", \"Inf\", \"-Inf\", \"\"]:\n", - " continue\n", - "\n", - " # make sure to use the correct row for the date and the correct datetime format\n", - " date_string = row[0]\n", - " dt = parser.parse(date_string)\n", - "\n", - " # not one per indicator but one per indicator per date\n", - " indicator = indicators_by_id[column_to_indicator_id[col]]\n", - " indicator_id = indicator[\"indicator_id\"]\n", - " datasets.setdefault(indicator_id, {})\n", - "\n", - " if date_string not in datasets[indicator_id]:\n", - " total_num += 1\n", - "\n", - " datasets[indicator_id].setdefault(\n", - " date_string,\n", - " {\n", - " \"metadata\": {\n", - " \"revision\": \"v0.1-demo\",\n", - " # adding a date here which will be overwritten later when it is actually added to the db\n", - " # this is to avoid a fastapi.exceptions.RequestValidationError for checking the length of a \"None\" type\n", - " \"date_added\": datetime.utcnow().strftime(\"%Y-%m-%dT%H:%M:%S\"),\n", - " \"category_id\": category_id,\n", - " \"indicator_id\": indicator_id,\n", - " \"srid\": f[\"srid\"],\n", - " \"trid\": f[\"trid\"],\n", - " \"dt\": dt,\n", - " },\n", - " \"data_type\": category[\"type\"],\n", - " \"data_input\": [],\n", - " },\n", - " )\n", - "\n", - " datasets[indicator_id][date_string][\"data_input\"].append(\n", - " {\n", - " \"spatial_unit_ids\": [row[1]]\n", - " if category[\"type\"] == \"single_location\"\n", - " else [row[1], row[2]],\n", - " \"data\": value,\n", - " }\n", - " )\n", - "\n", - " print(f\"Prepared requests in {round(time.monotonic() - start_time, 2)}s\")\n", - " print(f\"Starting ingestion of data for {len(datasets)} indicators...\")\n", + "async def ingest_data_version(data_version, chunksize):\n", + " n_datasets = count_files_for_version(data_version)\n", + " print(f\"Starting ingestion of data for {count_files_for_version(data_version)} indicators...\")\n", + " num = 0\n", " async with httpx.AsyncClient() as client:\n", - " start_time = time.monotonic()\n", - " num = 0\n", - " for indicator_id in datasets:\n", - " print(\n", - " f\" Ingesting {len(datasets[indicator_id].values())} datasets for indicator {indicator_id}\",\n", - " end=\"\",\n", - " flush=True,\n", - " )\n", - "\n", - " for chunk in chunked_iterable(datasets[indicator_id].values(), size=CHUNK_SIZE):\n", - " print(\".\", end=\"\", flush=True)\n", - " responses = await asyncio.gather(*(post_async(ds, client) for ds in chunk))\n", - " for response in responses:\n", - " if response.status_code not in [201, 204]:\n", - " print(\"\")\n", - " log(response)\n", - " else:\n", - " num += 1\n", - " print(\"\")\n", - "\n", - " print(\n", - " f\"Ingested {num}/{total_num} datasets ({round(num/total_num*100, 2)}%) in {round(time.monotonic() - start_time, 2)}s\"\n", - " )\n", - "\n", - "\n", - "async def doit():\n", - " for file_name in files.keys():\n", - " # if file_name != 'residents':\n", - " # continue\n", - " await ingest_data(file_name)\n", - "\n", - "\n", - "await doit()\n", + " for chunk in chunked_iterable(yield_files_for_version(data_version), size=chunksize):\n", + " print(\".\", end=\"\", flush=True)\n", + " responses = await asyncio.gather(*(post_async(ds, client) for ds in chunk))\n", + " for response in responses:\n", + " if response.status_code not in [201, 204]:\n", + " print(\"\")\n", + " log(response)\n", + " else:\n", + " num += 1" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bb57b0b5-95f0-4772-8d2f-2d5a02e27af4", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "await ingest_data_version(data_version, CHUNK_SIZE)\n", "# loop = asyncio.get_event_loop()\n", "# task = loop.create_task(doit())\n", "# if not loop.is_running():\n", @@ -733,52 +601,35 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "id": "90ef4661-f5c1-485e-8600-59ec1a346bdd", "metadata": { - "execution": { - "iopub.execute_input": "2023-03-20T12:58:57.148578Z", - "iopub.status.busy": "2023-03-20T12:58:57.148318Z", - "iopub.status.idle": "2023-03-20T12:58:57.151690Z", - "shell.execute_reply": "2023-03-20T12:58:57.151203Z", - "shell.execute_reply.started": "2023-03-20T12:58:57.148558Z" - }, "tags": [] }, "outputs": [], "source": [ "data_access = {\n", - " \"read:free_data\": [\n", - " {\n", - " \"category_id\": \"residents\",\n", - " \"indicator_id\": \"residents.residents\",\n", - " \"srid\": 3,\n", - " \"trid\": 2,\n", - " \"start_date\": \"2020-02\",\n", - " \"duration\": 3,\n", - " }\n", - " ],\n", - " \"read:premium_data\": [\n", - " {\n", - " \"category_id\": \"residents\",\n", - " \"indicator_id\": \"residents.residents\",\n", - " \"srid\": 3,\n", - " \"trid\": 2,\n", - " \"start_date\": \"2020-02\",\n", - " \"duration\": 6,\n", - " },\n", - " {\n", - " \"category_id\": \"residents\",\n", - " \"indicator_id\": \"residents.residents_perKm2\",\n", - " \"srid\": 3,\n", - " \"trid\": 2,\n", - " \"start_date\": \"2020-02\",\n", - " \"duration\": 6,\n", - " },\n", - " ],\n", + " \"read:free_data\": {\n", + " \"start_date\": \"2020-01\",\n", + " \"duration\": 5,\n", + " },\n", + " \"read:premium_data\": {\n", + " \"start_date\": \"2020-01\",\n", + " \"duration\": 9999,\n", + " },\n", "}" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "0bb1fca3-a1aa-4b9a-9030-f6a33cc6ddbd", + "metadata": {}, + "outputs": [], + "source": [ + "trid_lookup" + ] + }, { "cell_type": "markdown", "id": "b69ac8e8-0491-4b76-a54b-58cf8c03fccb", @@ -789,33 +640,25 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "id": "85442e50-590c-4665-b45c-eb1579486aab", "metadata": { - "execution": { - "iopub.execute_input": "2023-03-20T12:59:04.220590Z", - "iopub.status.busy": "2023-03-20T12:59:04.220362Z", - "iopub.status.idle": "2023-03-20T12:59:04.594697Z", - "shell.execute_reply": "2023-03-20T12:59:04.594130Z", - "shell.execute_reply.started": "2023-03-20T12:59:04.220574Z" - }, + "scrolled": true, "tags": [] }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'read:free_data': ['4', '2', '3'], 'read:premium_data': ['4', '2', '3', '1', '6', '5', '7', '10', '12', '8', '11', '9']}\n" - ] - } - ], - "source": [ - "scope_mappings = {}\n", - "for scope in data_access:\n", - " scope_mappings[scope] = []\n", - " for query in data_access[scope]:\n", - " query[\"mdids_only\"] = True\n", + "outputs": [], + "source": [ + "scope_mappings = []\n", + "for scope, query in data_access.items():\n", + " for indicator in indicators:\n", + " query_to_sub = dict(**query)\n", + " query_to_sub[\"mdids_only\"] = True\n", + " query_to_sub[\"category_id\"] = indicator[\"category_id\"]\n", + " query_to_sub[\"indicator_id\"] = indicator[\"indicator_id\"]\n", + " query_to_sub[\"srid\"] = files[indicator[\"category_id\"]][\"srid\"]\n", + " query_to_sub[\"trid\"] = files[indicator[\"category_id\"]][\"trid\"]\n", + " if files[indicator[\"category_id\"]][\"trid\"] == trid_lookup[\"days\"]:\n", + " query_to_sub[\"duration\"] = query[\"duration\"] * 28\n", " response = httpx.post(\n", " url=f\"{BASE_URL}/query\",\n", " headers={\n", @@ -823,9 +666,9 @@ " \"Content-Encoding\": \"gzip\",\n", " \"Authorization\": f\"Bearer {admin_token}\",\n", " },\n", - " data=gzip.compress(json.dumps(query).encode(\"utf-8\")),\n", + " data=gzip.compress(json.dumps(query_to_sub).encode(\"utf-8\")),\n", " )\n", - " scope_mappings[scope] += json.loads(response.content)[\"mdids\"]\n", + " scope_mappings += [(scope, mdid) for mdid in json.loads(response.content)[\"mdids\"]]\n", "print(scope_mappings)" ] }, @@ -839,45 +682,89 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, + "id": "c509e64e-ff74-4860-93c8-19ef269312ae", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, "id": "de822c81-fca9-4504-b8f1-1c91504855fe", "metadata": { - "execution": { - "iopub.execute_input": "2023-03-20T14:41:04.091123Z", - "iopub.status.busy": "2023-03-20T14:41:04.090927Z", - "iopub.status.idle": "2023-03-20T14:41:04.277111Z", - "shell.execute_reply": "2023-03-20T14:41:04.276472Z", - "shell.execute_reply.started": "2023-03-20T14:41:04.091108Z" - }, + "scrolled": true, "tags": [] }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Done.\n" - ] - } - ], - "source": [ - "for scope in scope_mappings:\n", - " for mdid in scope_mappings[scope]:\n", - " scope_mapping = {\"scope\": scope, \"mdid\": mdid}\n", - " response = httpx.post(\n", - " url=f\"{BASE_URL}/scope_mapping\",\n", - " headers={\n", - " \"Content-Type\": \"application/json\",\n", - " \"Content-Encoding\": \"gzip\",\n", - " \"Authorization\": f\"Bearer {admin_token}\",\n", - " },\n", - " data=gzip.compress(json.dumps(scope_mapping).encode(\"utf-8\")),\n", - " )\n", - " if response.status_code not in [201, 204]:\n", - " log(response)\n", + "outputs": [], + "source": [ + "for scope, mdid in scope_mappings:\n", + " scope_mapping = {\"scope\": scope, \"mdid\": mdid}\n", + " response = httpx.post(\n", + " url=f\"{BASE_URL}/scope_mapping\",\n", + " headers={\n", + " \"Content-Type\": \"application/json\",\n", + " \"Content-Encoding\": \"gzip\",\n", + " \"Authorization\": f\"Bearer {admin_token}\",\n", + " },\n", + " data=gzip.compress(json.dumps(scope_mapping).encode(\"utf-8\")),\n", + " )\n", + " if response.status_code not in [201, 204, 303]:\n", + " log(response)\n", "print(\"Done.\")" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "da760278-811b-4c72-93e0-8be6321f5cb4", + "metadata": {}, + "outputs": [], + "source": [ + "response = httpx.post(\n", + " url=f\"{BASE_URL}/scope_mapping\",\n", + " headers={\n", + " \"Content-Type\": \"application/json\",\n", + " \"Content-Encoding\": \"gzip\",\n", + " \"Authorization\": f\"Bearer {admin_token}\",\n", + " },\n", + " data=gzip.compress(json.dumps(scope_mapping).encode(\"utf-8\")),\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c1dc7c67-1e45-4d4e-9e88-50ffcea62ffd", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "num = 0\n", + "async with httpx.AsyncClient() as client:\n", + " for chunk in chunked_iterable(scope_mappings, size=25):\n", + " print(\".\", end=\"\", flush=True)\n", + " responses = await asyncio.gather(\n", + " *(\n", + " client.post(\n", + " url=f\"{BASE_URL}/scope_mapping\",\n", + " headers={\n", + " \"Content-Type\": \"application/json\",\n", + " \"Authorization\": f\"Bearer {admin_token}\",\n", + " },\n", + " data=json.dumps({\"scope\": scope, \"mdid\": mdid}).encode(\"utf-8\"),\n", + " )\n", + " for scope, mdid in chunk\n", + " )\n", + " )\n", + " for response in responses:\n", + " if response.status_code not in [201, 204]:\n", + " pass\n", + " else:\n", + " num += 1" + ] + }, { "cell_type": "markdown", "id": "0360f81a-a785-4e69-8a06-203d712fb526", @@ -901,6 +788,71 @@ ")\n", "```" ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0f395782-ce21-4d6d-bbfd-bc5d40842dab", + "metadata": {}, + "outputs": [], + "source": [ + "for indicator in indicators:\n", + " for d\n", + " query_to_sub = {\n", + " \"start_date\": \"2020-01\",\n", + " \"duration\": 1,\n", + " }\n", + " query_to_sub[\"mdids_only\"] = True\n", + " query_to_sub['category_id'] = indicator['category_id']\n", + " query_to_sub['indicator_id'] = indicator['indicator_id']\n", + " query_to_sub['srid'] = files[indicator['category_id']]['srid']\n", + " query_to_sub['trid'] = files[indicator['category_id']]['trid']\n", + " if files[indicator['category_id']]['trid'] == trid_lookup['days']:\n", + " query_to_sub['duration'] = query['duration']*28\n", + " response = httpx.post(\n", + " url=f\"{BASE_URL}/query\",\n", + " headers={\n", + " \"Content-Type\": \"application/json\",\n", + " \"Content-Encoding\": \"gzip\",\n", + " \"Authorization\": f\"Bearer {admin_token}\",\n", + " },\n", + " data=gzip.compress(json.dumps(query_to_sub).encode(\"utf-8\")),\n", + " )\n", + " scope_mappings += [(scope, mdid) for mdid in json.loads(response.content)[\"mdids\"]]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "15558142-8be9-4cbe-96df-6a3e63e4cd14", + "metadata": {}, + "outputs": [], + "source": [ + "# Clean out non 1.0.2 data\n", + "\n", + "async with httpx.AsyncClient() as client:\n", + " for chunk in chunked_iterable(scope_mappings, size=30):\n", + " print(\".\", end=\"\", flush=True)\n", + " responses = await asyncio.gather(\n", + " *(\n", + " client.post(\n", + " url=f\"{BASE_URL}/scope_mapping\",\n", + " headers={\n", + " \"Content-Type\": \"application/json\",\n", + " \"Authorization\": f\"Bearer {admin_token}\",\n", + " },\n", + " data=json.dumps({\"scope\": scope, \"mdid\": mdid}).encode(\"utf-8\"),\n", + " )\n", + " for scope, mdid in chunk\n", + " )\n", + " )\n", + " for response in responses:\n", + " if response.status_code not in [201, 204]:\n", + " print(\"\")\n", + " log(response)\n", + " else:\n", + " num += 1" + ] } ], "metadata": { @@ -919,7 +871,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.6" + "version": "3.11.3" }, "vscode": { "interpreter": {