From 52aacabe9fdf5b676e0bccc1cf1dea381253ba3b Mon Sep 17 00:00:00 2001 From: mwbernard Date: Wed, 22 Nov 2023 17:08:48 -0800 Subject: [PATCH 1/6] Add crop information files and store --- .../public/data/crop-info-biophysical.csv | 24 +++++++++++ .../public/data/crop-info-general.csv | 24 +++++++++++ .../public/data/crop-info-genetic.csv | 24 +++++++++++ .../public/data/crop-info-nutritional.csv | 24 +++++++++++ vacs-map-app/src/stores/cropInformation.js | 42 +++++++++++++++++++ vacs-map-app/src/stores/filters.js | 34 ++++++++++++++- 6 files changed, 171 insertions(+), 1 deletion(-) create mode 100644 vacs-map-app/public/data/crop-info-biophysical.csv create mode 100644 vacs-map-app/public/data/crop-info-general.csv create mode 100644 vacs-map-app/public/data/crop-info-genetic.csv create mode 100644 vacs-map-app/public/data/crop-info-nutritional.csv create mode 100644 vacs-map-app/src/stores/cropInformation.js diff --git a/vacs-map-app/public/data/crop-info-biophysical.csv b/vacs-map-app/public/data/crop-info-biophysical.csv new file mode 100644 index 0000000..fa99003 --- /dev/null +++ b/vacs-map-app/public/data/crop-info-biophysical.csv @@ -0,0 +1,24 @@ +id,Heat Tolerance,Drought Tolerance,Yield % Change,Yield Under Current Conditions +maize,2,5,2,8 +fonio,8,3,8,3 +tef,6,1,9,3 +fingermillet,8,3,,2 +sorghum,4,3,6,2 +soybean,3,3,6, +cowpea,2,3,0, +grasspea,,,, +mungbean,1,3,, +pigeonpea,3,3,, +lablab,,,, +bambaragroundnut,3,3,, +groundnut,3,7,7, +sesame,8,3,7, +cassava,4,3,5, +cocoyam,,,, +taro,3,3,5, +sweetpotato,,,, +yams,4,4,, +tomato,1,8,, +okra,3,1,, +africaneggplant,,,, +josephscoat,3,1,, \ No newline at end of file diff --git a/vacs-map-app/public/data/crop-info-general.csv b/vacs-map-app/public/data/crop-info-general.csv new file mode 100644 index 0000000..4f4580e --- /dev/null +++ b/vacs-map-app/public/data/crop-info-general.csv @@ -0,0 +1,24 @@ +id,label,crop_group,benchmark,description +grasspea,Grass Pea,Legumes,0,"A resilient legume known for its tolerance to drought and poor soil conditions, grass pea produces small, edible seeds that are high in protein but can be toxic if consumed in large quantities." +pigeonpea,Pigeon Pea,Legumes,0,"This perennial legume is valued for its drought-resistant qualities and nutritious seeds, which are commonly used in Indian and African cuisines." +bambaragroundnut,Bambara Groundnut,Legumes,0,"Native to Africa, this legume grows underground like peanuts, offering high protein and carbohydrate content, and is resilient to harsh environmental conditions." +lablab,Lablab,Legumes,0,"A versatile legume with edible leaves, flowers, pods, and beans, it's often used as a cover crop to improve soil fertility and is a staple in African and Asian diets." +cowpea,Cowpea,Legumes,0,"Known for its ability to improve soil fertility through nitrogen fixation, cowpea is a nutritious legume with versatile uses in both human and animal diets." +mungbean,Mung Bean,Legumes,0,"Also known as green gram, this legume is a staple in Asian cuisine, known for its small green seeds and sprouts, both high in protein and nutrients." +groundnut,Groundnut,Seeds & Nuts,0,"Commonly known as peanut, this crop produces edible seeds in underground pods and is valued for its high oil and protein content." +soybean,Soy Bean,Legumes,1,"A globally important legume, soybeans are a major source of protein and oil, used in a variety of food products and animal feeds." +maize,Maize,Cereals,1, +fonio,Fonio,Cereals,0,"A staple food and primary crop worldwide, maize is versatile in its uses, from direct human consumption to animal feed and industrial products." +tef,Tef,Cereals,0,"An Ethiopian staple, tef is a small grain known for its high nutritional value, gluten-free status, and ability to grow in various environmental conditions." +fingermillet,Finger Millet,Cereals,0,"Highly nutritious and gluten-free, finger millet is valued for its high calcium content and ability to thrive in arid conditions." +sorghum,Sorghum,Cereals,0,"A versatile and drought-resistant grain, sorghum is used for food, fodder, and biofuels, especially in arid regions." +sesame,Sesame,Seeds & Nuts,0,"Known for its oil-rich seeds, sesame is a flowering plant used in various cuisines and traditional medicines." +cocoyam,Cocoyam,Roots & Tubers,0,"This tropical tuber crop produces large, starchy roots and leaves, both of which are edible and commonly used in African and Caribbean cuisines." +taro,Taro,Roots & Tubers,0,"Taro is a root vegetable known for its large, starchy corms and heart-shaped leaves, commonly used in Asian, African, and Pacific Island cuisines." +yams,Yams,Roots & Tubers,0,"A staple in many tropical regions, yams are tuberous root vegetables known for their high carbohydrate content and cultural significance in African and Asian diets" +sweetpotato,Sweet Potato,Roots & Tubers,0,"Sweet potatoes are root vegetables with nutritious, sweet-tasting tubers, widely grown in tropical and subtropical regions." +cassava,Cassava,Roots & Tubers,1,"A major source of carbohydrates, cassava is a tropical root crop known for its long, starchy tubers and leaves, both edible with proper preparation." +tomato,Tomato,Vegetables,1,"A widely cultivated fruit, tomatoes are versatile in culinary uses and valued for their rich flavor and nutritional content." +okra,Okra,Vegetables,0,"Known for its edible green seed pods, okra is commonly used in soups, stews, and as a thickening agent, particularly in African and Asian cuisines." +josephscoat,Joseph's Coat,Vegetables,0,"A nutritious leafy green, amaranth is known for its colorful foliage and grain-like seeds, used in various cultural dishes worldwide." +africaneggplant,African Eggplant,Vegetables,0, \ No newline at end of file diff --git a/vacs-map-app/public/data/crop-info-genetic.csv b/vacs-map-app/public/data/crop-info-genetic.csv new file mode 100644 index 0000000..1520f4c --- /dev/null +++ b/vacs-map-app/public/data/crop-info-genetic.csv @@ -0,0 +1,24 @@ +id,Ranking # of Accessions,Ranking # of Accessions Continent Wide,Ranking Scale of Programs +fonio,4,3,6 +tef,7,0,4 +fingermillet,8,6,10 +sorghum,10,8,10 +grasspea,6,3,10 +pigeonpea,8,6,10 +bambaragroundnut,6,6,10 +lablab,6,5,6 +cowpea,9,8,10 +mungbean,8,4,10 +cocoyam,2,1,4 +taro,6,4,6 +africaneggplant,5,4,8 +josephscoat,6,4,10 +okra,7,5,10 +yams,7,7,10 +sweetpotato,0,0,10 +sesame,7,6,4 +groundnut,3,3,10 +tomato,9,5,10 +cassava,8,6,10 +maize,10,7,10 +soybean,9,7,10 \ No newline at end of file diff --git a/vacs-map-app/public/data/crop-info-nutritional.csv b/vacs-map-app/public/data/crop-info-nutritional.csv new file mode 100644 index 0000000..951f7c9 --- /dev/null +++ b/vacs-map-app/public/data/crop-info-nutritional.csv @@ -0,0 +1,24 @@ +id,Protein,Calcium,Iron,Zinc,Vitamin A,Folate,Storage Potential +grasspea,7,1,5,5,5,3, +pigeonpea,3,4,3,2,8,5, +bambaragroundnut,2,1,0,1,0,0, +lablab,4,1,8,2,0,0, +cowpea,4,2,6,5,1,7,5 +mungbean,6,6,9,2,9,10, +groundnut,4,0,2,3,3,2, +soybean,8,10,10,9,0,6, +maize,0,1,10,5,,5, +fonio,9,5,2,9,,9, +tef,1,1,0,0,,0, +okra,,,,,,, +fingermillet,6,0,2,2,7,0, +sorghum,,,,,,, +sesame,,,,,,, +cocoyam,8,1,1,1,0,8, +taro,7,3,7,3,0,7, +yams,5,1,2,1,0,4, +sweetpotato,2,9,3,3,10,1, +cassava,3,5,7,10,0,8, +tomato,2,0,0,3,2,0, +africaneggplant,3,0,1,3,0,0, +josephscoat,8,10,7,9,10,1, \ No newline at end of file diff --git a/vacs-map-app/src/stores/cropInformation.js b/vacs-map-app/src/stores/cropInformation.js new file mode 100644 index 0000000..8cd3bca --- /dev/null +++ b/vacs-map-app/src/stores/cropInformation.js @@ -0,0 +1,42 @@ +import * as d3 from 'd3' +import { ref } from 'vue' +import { defineStore } from 'pinia' +import { getDataUrl } from '@/constants/data-load' + +export const useCropInformationStore = defineStore('cropInformation', () => { + const data = ref(null) + const loading = ref(false) + + const load = async () => { + if (loading.value || data.value) return false; + loading.value = true; + + let general = await d3.csv(getDataUrl('crop-info-general.csv'), d3.autoType); + let genetic = await d3.csv(getDataUrl('crop-info-genetic.csv'), d3.autoType); + let nutritional = await d3.csv(getDataUrl('crop-info-nutritional.csv'), d3.autoType); + let biophysical = await d3.csv(getDataUrl('crop-info-biophysical.csv'), d3.autoType); + + const getIndicators = (array, id) => { + return Object.fromEntries(Object.entries(array.find(d => d.id === id)).slice(1)); + } + + general = general.map((d) => { + const indicators = { + genetic: getIndicators(genetic, d.id), + nutritional: getIndicators(nutritional, d.id), + biophysical: getIndicators(biophysical, d.id), + } + return { + ...d, + indicators: indicators + } + }) + data.value = Object.freeze(general); + } + + return { + data, + loading, + load + } +}) \ No newline at end of file diff --git a/vacs-map-app/src/stores/filters.js b/vacs-map-app/src/stores/filters.js index 570ed08..1909507 100644 --- a/vacs-map-app/src/stores/filters.js +++ b/vacs-map-app/src/stores/filters.js @@ -1,6 +1,7 @@ import { computed, ref, watch } from 'vue' import { defineStore, storeToRefs } from 'pinia' import { useCropYieldsStore } from '@/stores/cropYields' +import { useCropInformationStore } from './cropInformation' export const useFiltersStore = defineStore('filters', () => { const availableCrops = ref([]) @@ -12,6 +13,13 @@ export const useFiltersStore = defineStore('filters', () => { const availableModels = ref([]) const selectedModel = ref('') + const availableCropGroups = ref([]) + const selectedCropGroup = ref('') + + const cropSortByOptions = ref([]) + const cropSortBy = ref('') + const cropSortOrder = ref('descending') + const cropYieldsStore = useCropYieldsStore() const { data: cropData } = storeToRefs(cropYieldsStore) @@ -50,6 +58,23 @@ export const useFiltersStore = defineStore('filters', () => { selectedModel.value = availableModels.value[0] }) + const cropInformationStore = useCropInformationStore() + const { data: cropInfo } = storeToRefs(cropInformationStore) + + watch(cropInfo, () => { + + availableCropGroups.value = Array.from( + new Set(cropInfo.value?.map(d => d.crop_group)) + ); + + cropSortByOptions.value = Array.from(Object.keys( + cropInfo.value?.[0].indicators?.nutritional + )); + + cropSortBy.value = cropSortByOptions.value[0]; + + }) + return { availableCrops, selectedCrop, @@ -58,6 +83,13 @@ export const useFiltersStore = defineStore('filters', () => { selectedMetric, availableModels, - selectedModel + selectedModel, + + availableCropGroups, + selectedCropGroup, + + cropSortByOptions, + cropSortBy, + cropSortOrder } }) From b8ef0689a9436f9f832ce39364a18549d230c744 Mon Sep 17 00:00:00 2001 From: mwbernard Date: Wed, 22 Nov 2023 17:09:08 -0800 Subject: [PATCH 2/6] Add crop filters and sorting --- vacs-map-app/src/App.vue | 5 +- vacs-map-app/src/components/CropCards.vue | 44 +++++++++--- vacs-map-app/src/components/CropFilters.vue | 76 +++++++++++++++++++-- 3 files changed, 109 insertions(+), 16 deletions(-) diff --git a/vacs-map-app/src/App.vue b/vacs-map-app/src/App.vue index 61e70ef..3edf837 100644 --- a/vacs-map-app/src/App.vue +++ b/vacs-map-app/src/App.vue @@ -8,11 +8,14 @@ import { onMounted } from 'vue' import { RouterView } from 'vue-router' import { useCropYieldsStore } from '@/stores/cropYields' +import { useCropInformationStore } from './stores/cropInformation'; const cropYieldsStore = useCropYieldsStore() +const cropInformationStore = useCropInformationStore(); onMounted(() => { - cropYieldsStore.load() + cropYieldsStore.load(); + cropInformationStore.load(); }) diff --git a/vacs-map-app/src/components/CropCards.vue b/vacs-map-app/src/components/CropCards.vue index c6afc5a..aa8dfc8 100644 --- a/vacs-map-app/src/components/CropCards.vue +++ b/vacs-map-app/src/components/CropCards.vue @@ -2,13 +2,13 @@
- +
@@ -19,15 +19,37 @@ import slugify from 'slugify' import { computed } from 'vue' import { useRouter } from 'vue-router' import { storeToRefs } from 'pinia' +import * as d3 from 'd3' import { useFiltersStore } from '@/stores/filters' +import { useCropInformationStore } from '../stores/cropInformation' import CardWrapper from './CardWrapper.vue' -const router = useRouter() -const filtersStore = useFiltersStore() -const { availableCrops, selectedCrop, selectedModel } = storeToRefs(filtersStore) +const router = useRouter(); +const filtersStore = useFiltersStore(); +const cropInformationStore = useCropInformationStore(); +const { + selectedCrop, + selectedModel, + selectedCropGroup, + cropSortBy, + cropSortOrder, +} = storeToRefs(filtersStore) +const { data: cropInformation } = storeToRefs(cropInformationStore); -// TODO actually filter -const filteredCrops = computed(() => availableCrops.value) +const filteredCrops = computed(() => { + if (!selectedCropGroup.value) return cropInformation.value; + return cropInformation.value.filter(d => d.crop_group === selectedCropGroup.value); +}) + +const sortedCrops = computed(() => { + if (!cropSortBy.value) return filteredCrops.value; + return [...filteredCrops.value].sort( + (a, b) => d3[cropSortOrder.value]( + a.indicators.nutritional[cropSortBy.value], + b.indicators.nutritional[cropSortBy.value] + ) + ); +}) const navigate = (crop) => { selectedCrop.value = crop diff --git a/vacs-map-app/src/components/CropFilters.vue b/vacs-map-app/src/components/CropFilters.vue index 093fb3b..e035763 100644 --- a/vacs-map-app/src/components/CropFilters.vue +++ b/vacs-map-app/src/components/CropFilters.vue @@ -12,6 +12,50 @@ {{ scenario }} + +
+
+ All crops +
+
+ {{ group }} +
+
+ +
+
+
+ + +
+
+ + +
+
+ + +
@@ -20,8 +64,16 @@ import { computed } from 'vue' import { storeToRefs } from 'pinia' import { useFiltersStore } from '@/stores/filters' -const filtersStore = useFiltersStore() -const { availableModels, selectedModel } = storeToRefs(filtersStore) +const filtersStore = useFiltersStore(); +const { + availableModels, + selectedModel, + availableCropGroups, + selectedCropGroup, + cropSortByOptions, + cropSortBy, + cropSortOrder, +} = storeToRefs(filtersStore); const futureScenarios = computed(() => { return availableModels.value.filter((d) => d.startsWith('future')) @@ -31,10 +83,10 @@ const futureScenarios = computed(() => { From e0c269f4b96183d3dd3ce5c9660dcbb7382886bd Mon Sep 17 00:00:00 2001 From: mwbernard Date: Wed, 22 Nov 2023 17:09:24 -0800 Subject: [PATCH 3/6] Add grouped select and crops in explore sidebar --- .../src/components/ExploreSidebar.vue | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/vacs-map-app/src/components/ExploreSidebar.vue b/vacs-map-app/src/components/ExploreSidebar.vue index 1101c06..29576db 100644 --- a/vacs-map-app/src/components/ExploreSidebar.vue +++ b/vacs-map-app/src/components/ExploreSidebar.vue @@ -2,10 +2,19 @@