Skip to content

Commit

Permalink
Merge pull request #125 from earthrise-media/colorblind-palette-2
Browse files Browse the repository at this point in the history
Add colorblind friendly mode
  • Loading branch information
Martin Bernard authored Dec 14, 2023
2 parents f926c85 + 3cf929f commit 17874d2
Show file tree
Hide file tree
Showing 156 changed files with 691 additions and 134 deletions.
451 changes: 437 additions & 14 deletions vacs-map-app/package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions vacs-map-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"mapbox-gl": "^3.0.1",
"pinia": "^2.1.7",
"qs": "^6.11.2",
"sharp": "^0.32.6",
"slugify": "^1.6.6",
"topojson-client": "^3.1.0",
"topojson-server": "^3.0.1",
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
55 changes: 44 additions & 11 deletions vacs-map-app/scripts/generate-minimaps.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as d3 from 'd3';
import fs from 'fs';
import sharp from 'sharp';
import { JSDOM } from 'jsdom';
import { geoChamberlinAfrica } from 'd3-geo-projection';
import * as topojsonClient from 'topojson-client';
Expand All @@ -8,14 +9,27 @@ import * as topojsonServer from 'topojson-server';
const geo_filename = 'public/data/world-110m-2020.json';
const data_filename = 'public/data/crop-yields-mean-models.csv';
const grid_filename = 'public/data/grid.csv';
const output_folder = 'src/assets/img/minimaps/';
const output_folder = 'public/minimaps/';

const divergingScheme = {
name: 'default',
min: "#FFA31A",
center: "#424242",
max: "#13F364",
}

const colorblindDivergingScheme = {
name: 'colorblindFriendly',
min: '#E7EB2A',
center: '#424242',
max: '#D156F0'
}

// running for both schemes at once is too much for JS, so uncomment the line below that you want
// const colorSchemes = [divergingScheme, colorblindDivergingScheme]
const colorSchemes = [divergingScheme]
// const colorSchemes = [colorblindDivergingScheme]

const getGeoData = () => {
return JSON.parse(fs.readFileSync(geo_filename));
}
Expand Down Expand Up @@ -94,7 +108,7 @@ const getModels = (data) => {
)).filter(m => m.startsWith('future')).sort();
}

const getColorGenerator = (data, crop) => {
const getColorGenerator = (data, crop, scheme) => {
const columnNames = getModels(data).map(m => `yieldratio_${crop}_${m}`);
const extents = columnNames.map(d => getExtent(data, d));
const extent = [
Expand All @@ -104,7 +118,7 @@ const getColorGenerator = (data, crop) => {

return d3.scaleLinear()
.domain([extent[0], 0, extent[1]])
.range([divergingScheme.min, divergingScheme.center, divergingScheme.max]);
.range([scheme.min, scheme.center, scheme.max]);
};

const generateMapSvg = (crop, model, data, world, Africa, AfricanCountries, Africa0, color) => {
Expand Down Expand Up @@ -226,16 +240,35 @@ const generateMaps = () => {

const Africa = topojsonClient.merge(Africa0, Africa0.objects.countries.geometries);

crops.forEach(crop => {
models.forEach(model => {
const color = getColorGenerator(data, crop);

const svg = generateMapSvg(crop, model, data, world, Africa, AfricanCountries, Africa0, color);

fs.writeFileSync(`${output_folder}${crop}_${model}.svg`, svg.html());
console.log("Generating maps...")

colorSchemes.forEach(scheme => {
crops.forEach(crop => {
models.forEach(model => {
const color = getColorGenerator(data, crop, scheme);

const svg = generateMapSvg(crop, model, data, world, Africa, AfricanCountries, Africa0, color);

const fileName = `${output_folder}${scheme.name}/${crop}_${model}`

fs.writeFileSync(fileName + '.svg', svg.html());

sharp(fileName + '.svg')
.png()
.toFile(fileName + '.png')
.catch((err) => {
console.log(err);
})
.then(() => {
fs.unlink(fileName + '.svg', (err) => {
if (err) {
console.log(err);
}
})
});
})
})
})

}

generateMaps();
Expand Down
15 changes: 9 additions & 6 deletions vacs-map-app/src/LandingPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,14 @@
<br />
<p>
The program has brought together experts in various fields, including climate adaptation,
plant breeding, nutrition, and food composition. <a href="https://agmip.org/" target="_blank"> AgMIP</a> was chosen to lead the initial phase of crop-climate modeling work, the results of which are visualized on this website. The selection process for crops was
informed by scientific data and expert opinions, ensuring a balance of priorities across
different scientific disciplines and stakeholder interests. This collaborative approach is
critical for developing an inclusive and effective strategy to address the nutritional
needs and environmental challenges in Africa.
plant breeding, nutrition, and food composition.
<a href="https://agmip.org/" target="_blank"> AgMIP</a> was chosen to lead the initial
phase of crop-climate modeling work, the results of which are visualized on this website.
The selection process for crops was informed by scientific data and expert opinions,
ensuring a balance of priorities across different scientific disciplines and stakeholder
interests. This collaborative approach is critical for developing an inclusive and
effective strategy to address the nutritional needs and environmental challenges in
Africa.
</p>
<br />
<p>
Expand Down Expand Up @@ -338,8 +341,8 @@ a {
</style>

<style>
.overlay .disclaimer-wrapper {
justify-content: center;
background: var(--black-80);
}
</style>
3 changes: 3 additions & 0 deletions vacs-map-app/src/assets/img/colorblind-active.svg
3 changes: 3 additions & 0 deletions vacs-map-app/src/assets/img/colorblind.svg
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
1 change: 0 additions & 1 deletion vacs-map-app/src/assets/img/minimaps/tef_future_ssp126.svg
Diff not rendered.
1 change: 0 additions & 1 deletion vacs-map-app/src/assets/img/minimaps/tef_future_ssp370.svg
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
27 changes: 23 additions & 4 deletions vacs-map-app/src/components/CardWrapper.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@
<div class="title" :class="{ bold: boldTitle }">{{ title }}</div>
<div v-if="indicator" class="indicator">
<span class="indicator-category"> {{ indicator.key }} </span>
<span class="indicator-level" :style="{ background: indicatorColor }">
<span
class="indicator-level"
:class="{ 'dark-text': useDarkIndicatorText }"
:style="{ background: indicatorColor }"
>
{{ indicatorLevel }}
</span>
</div>
Expand All @@ -22,7 +26,8 @@

<script setup>
import { toRefs, computed } from 'vue'
import { stopLightScheme } from '@/utils/colors'
import { storeToRefs } from 'pinia'
import { useColorStore } from '@/stores/colors'
defineEmits(['showInfo'])
const props = defineProps({
Expand Down Expand Up @@ -63,6 +68,9 @@ const props = defineProps({
})
const { title, description, handleClick, indicator } = toRefs(props)
const colorStore = useColorStore()
const { stopLight: stopLightScheme, colorblindFriendly } = storeToRefs(colorStore)
const indicatorLevel = computed(() => {
if (indicator?.value.val === null) return 'no data'
if (indicator.value.val < 3) return 'low'
Expand All @@ -71,8 +79,15 @@ const indicatorLevel = computed(() => {
})
const indicatorColor = computed(() => {
if (indicatorLevel.value === 'no data') return stopLightScheme.default
return stopLightScheme[indicatorLevel.value]
if (indicatorLevel.value === 'no data') return stopLightScheme.value.default
return stopLightScheme.value[indicatorLevel.value]
})
const useDarkIndicatorText = computed(() => {
return (
(indicatorLevel.value === 'low' && colorblindFriendly.value) ||
(indicatorLevel.value === 'medium' && !colorblindFriendly.value)
)
})
</script>
Expand Down Expand Up @@ -152,6 +167,10 @@ const indicatorColor = computed(() => {
font-weight: 600;
}
.dark-text {
color: var(--gray);
}
.active {
border-color: var(--ui-blue);
}
Expand Down
15 changes: 14 additions & 1 deletion vacs-map-app/src/components/CropCards.vue
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import { storeToRefs } from 'pinia'
import * as d3 from 'd3'
import { useFiltersStore } from '@/stores/filters'
import { useCropInformationStore } from '../stores/cropInformation'
import { useColorStore } from '@/stores/colors'
import CardWrapper from './CardWrapper.vue'
import DataDisclaimer from './DataDisclaimer.vue'
Expand All @@ -38,6 +39,9 @@ const { selectedCrop, selectedModel, selectedCropGroup, cropSortBy, cropSortOrde
storeToRefs(filtersStore)
const { data: cropInformation } = storeToRefs(cropInformationStore)
const colorStore = useColorStore()
const { colorblindFriendly } = storeToRefs(colorStore)
const filteredCrops = computed(() => {
if (!selectedCropGroup.value) return cropInformation.value
return cropInformation.value.filter((d) => d.crop_group === selectedCropGroup.value)
Expand All @@ -59,7 +63,10 @@ const navigate = (crop) => {
}
const getUrl = (crop) => {
return new URL(`../assets/img/minimaps/${crop}_${selectedModel.value}.svg`, import.meta.url).href
const schemeFolder = colorblindFriendly.value ? 'colorblindFriendly/' : 'default/'
const url = `/minimaps/${schemeFolder}${crop}_${selectedModel.value}.png`
return new URL(url, import.meta.url).href
}
</script>
Expand All @@ -82,3 +89,9 @@ img {
aspect-ratio: 1/1;
}
</style>
<style>
.crop-cards .card-wrapper {
background: #3b4650;
}
</style>
42 changes: 21 additions & 21 deletions vacs-map-app/src/components/CropFingerprint.vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<template>
<div class="fingerprint-wrapper">
<div class="legend">
<span class="benchmark-message">
*As compared to benchmark crop {{ benchmarkCropObject?.label }}</span
<span class="reference-message">
*As compared to reference crop {{ referenceCropObject?.label }}</span
>

<div class="responsive-legend">
Expand All @@ -14,8 +14,8 @@
>
{{ selectedCropObject?.label }}
</span>
<span v-if="showBenchmark" class="category-label benchmark-label">
{{ benchmarkCropObject?.label }}
<span v-if="showReference" class="category-label reference-label">
{{ referenceCropObject?.label }}
</span>
</div>
<div v-else class="hovered-label">
Expand All @@ -30,12 +30,12 @@
{{ cat }}
</span>
<span
v-if="showBenchmark"
class="category-label benchmark-label"
@mouseenter="hoveredCategory = 'benchmark'"
v-if="showReference"
class="category-label reference-label"
@mouseenter="hoveredCategory = 'reference'"
@mouseleave="hoveredCategory = null"
>
Benchmark
Reference
</span>
</div>
</div>
Expand Down Expand Up @@ -66,9 +66,9 @@
<circle v-for="d in d3.range(11)" :key="d" :r="y(d)" />
</g>

<g v-if="showBenchmark">
<g v-if="showReference">
<path
v-for="indicator in benchmarkIndicators"
v-for="indicator in referenceIndicators"
:key="indicator.key"
fill="#ffffff01"
stroke="#DAB967"
Expand All @@ -78,12 +78,12 @@
highlighted:
hovered?.key === indicator.key ||
hoveredCategory === indicator.category ||
hoveredCategory === 'benchmark',
hoveredCategory === 'reference',
unhighlighted:
(hovered && hovered.key !== indicator.key && hoveredCategory !== 'benchmark') ||
(hovered && hovered.key !== indicator.key && hoveredCategory !== 'reference') ||
(hoveredCategory &&
hoveredCategory !== indicator.category &&
hoveredCategory !== 'benchmark')
hoveredCategory !== 'reference')
}"
/>
</g>
Expand Down Expand Up @@ -154,22 +154,22 @@ const hoverIndicators = computed(() => {
})
})
const benchmarkCropObject = computed(() => {
const referenceCropObject = computed(() => {
if (!cropInformation.value) return null
return cropInformation.value.find(
(d) => d.crop_group === selectedCropObject.value.crop_group && d.benchmark
)
})
const benchmarkIndicators = computed(() => {
return getIndicators(benchmarkCropObject.value).filter(
const referenceIndicators = computed(() => {
return getIndicators(referenceCropObject.value).filter(
(d, i) => selectedIndicators.value[i].value
)
})
const showBenchmark = computed(() => {
if (!benchmarkCropObject.value) return false
return benchmarkCropObject.value !== selectedCropObject.value
const showReference = computed(() => {
if (!referenceCropObject.value) return false
return referenceCropObject.value !== selectedCropObject.value
})
const getIndicators = (crop) => {
Expand Down Expand Up @@ -262,7 +262,7 @@ svg {
color: var(--white);
}
.benchmark-message {
.reference-message {
color: var(--gray);
font-size: 0.8125rem;
font-style: italic;
Expand Down Expand Up @@ -300,7 +300,7 @@ svg {
text-transform: uppercase;
}
.benchmark-label {
.reference-label {
color: #dab967;
border: 1px solid #dab967;
}
Expand Down
1 change: 0 additions & 1 deletion vacs-map-app/src/components/DataDisclaimer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ const { copy } = storeToRefs(contentStore)
<style scoped>
.disclaimer-wrapper {
width: 100%;
background: var(--black-80);
display: flex;
padding: 0.3rem 2rem;
}
Expand Down
Loading

0 comments on commit 17874d2

Please sign in to comment.