Skip to content

Commit 507ac12

Browse files
committed
used a similar gdp country instead for fairness
1 parent c1eac5d commit 507ac12

2 files changed

Lines changed: 117 additions & 67 deletions

File tree

website/js/fair-distribution.js

Lines changed: 92 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -351,24 +351,6 @@
351351
<span class="bottom">country GDP</span>
352352
</span>
353353
</div>
354-
355-
<p class="fair-slider-explanation">
356-
Use the sliders to adjust how much weight population and GDP have in the fair medal calculation.
357-
</p>
358-
359-
<div class="fair-sliders">
360-
<label class="fair-slider-control">
361-
<span>Population adjustment:</span>
362-
<input id="fair-pop-adjustment" type="range" min="0" max="200" value="100" step="10">
363-
<strong id="fair-pop-value">100%</strong>
364-
</label>
365-
366-
<label class="fair-slider-control">
367-
<span>GDP adjustment:</span>
368-
<input id="fair-gdp-adjustment" type="range" min="0" max="200" value="100" step="10">
369-
<strong id="fair-gdp-value">100%</strong>
370-
</label>
371-
</div>
372354
</div>
373355
`;
374356
}
@@ -741,8 +723,8 @@
741723
Number.isFinite(meanGDP) &&
742724
meanGDP > 0
743725
) {
744-
const populationFactor = Math.pow(meanPopulation / population, state.populationAdjustment / 100);
745-
const gdpFactor = Math.pow(meanGDP / gdp, state.gdpAdjustment / 100);
726+
const populationFactor = meanPopulation / population;
727+
const gdpFactor = meanGDP / gdp;
746728

747729
factor = populationFactor * gdpFactor;
748730
}
@@ -764,6 +746,63 @@
764746
};
765747
}
766748

749+
function getDisplayData(country, data) {
750+
const totalActual =
751+
data.actual.Gold + data.actual.Silver + data.actual.Bronze;
752+
753+
if (totalActual > 0) {
754+
return {
755+
...data,
756+
similarCountry: null
757+
};
758+
}
759+
760+
const similarCountry = findSimilarGdpMedalCountry(country);
761+
762+
if (!similarCountry) {
763+
return {
764+
...data,
765+
similarCountry: null
766+
};
767+
}
768+
769+
const similarData = computeFairCounts(similarCountry);
770+
771+
return {
772+
...data,
773+
fair: similarData.fair,
774+
similarCountry
775+
};
776+
}
777+
778+
function findSimilarGdpMedalCountry(country) {
779+
const base = getCountryIndicators(country);
780+
if (!base.gdp) return null;
781+
782+
const countries = getAvailableCountries(state.season, state.year);
783+
784+
const candidates = countries
785+
.filter(candidate => candidate !== country)
786+
.map(candidate => {
787+
const medals = getMedalCounts(candidate);
788+
const totalMedals = medals.Gold + medals.Silver + medals.Bronze;
789+
790+
if (totalMedals === 0) return null;
791+
792+
const indicators = getCountryIndicators(candidate);
793+
if (!indicators.gdp) return null;
794+
795+
return {
796+
country: candidate,
797+
distance: Math.abs(Math.log(indicators.gdp) - Math.log(base.gdp))
798+
};
799+
})
800+
.filter(Boolean)
801+
.sort((a, b) => d3.ascending(a.distance, b.distance));
802+
803+
return candidates[0]?.country || null;
804+
}
805+
767806
function render() {
768807
const grid = d3.select("#fair-grid");
769808

@@ -772,8 +811,11 @@
772811
return;
773812
}
774813

775-
const data1 = computeFairCounts(state.country1);
776-
const data2 = computeFairCounts(state.country2);
814+
const rawData1 = computeFairCounts(state.country1);
815+
const rawData2 = computeFairCounts(state.country2);
816+
817+
const data1 = getDisplayData(state.country1, rawData1);
818+
const data2 = getDisplayData(state.country2, rawData2);
777819

778820
const maxScale = d3.max([
779821
...medalOrder.map(medal => data1.actual[medal] || 0),
@@ -787,64 +829,34 @@
787829
grid.append("div").html(renderCountryCard(state.country1, data1, maxScale));
788830
grid.append("div").html(renderCountryCard(state.country2, data2, maxScale));
789831
renderRankingTable();
790-
791-
d3.selectAll(".fair-prediction-toggle").on("click", function () {
792-
const country = this.dataset.country;
793-
794-
state.expandedPredictionCountry =
795-
state.expandedPredictionCountry === country ? null : country;
796-
797-
render();
798-
});
799832
}
800833

801834
function renderCountryCard(country, data, maxScale) {
802835
const fairUnavailable = data.factor === null;
803836

804-
const allFairZero =
805-
!fairUnavailable &&
806-
medalOrder.every(medal => (data.fair[medal] || 0) === 0);
807-
808837
return `
809838
<div class="fair-country-card">
810839
<div class="fair-country-title">${country}</div>
840+
811841
<div class="fair-country-subtitle">
812842
Population: ${formatBig(data.population)} &nbsp;•&nbsp;
813843
GDP: ${formatBig(data.gdp)}
814844
</div>
815845
816-
${allFairZero ? `
817-
<div class="fair-prediction-wrapper">
818-
${state.expandedPredictionCountry === country ? `
819-
<div class="fair-whatif-panel">
820-
<div class="fair-whatif-title">What if conditions were different?</div>
821-
<div class="fair-whatif-text">
822-
Adjust the Population and GDP sliders below to explore how changes in resources could affect this country's expected medal performance.
823-
</div>
824-
825-
${renderWhatIfPrediction(country)}
826-
</div>
827-
` : `
828-
<button class="fair-prediction-banner fair-prediction-toggle"
829-
data-country="${country}">
830-
This country won no medals. Click to simulate a possible medal expectation.
831-
</button>
832-
`}
833-
</div>
834-
` : ""}
835-
836846
<div class="fair-box">
837847
<div class="fair-box-title">Actual medals</div>
848+
838849
${medalOrder.map(medal => {
839850
const value = data.actual[medal] || 0;
840-
const width = value === 0 ? 0 : Math.max(3, (100 * value) / maxScale);
851+
const width =
852+
value === 0 ? 0 : Math.max(3, (100 * value) / maxScale);
841853
842854
return `
843855
<div class="fair-medal-row">
844856
<div class="fair-medal-label">${medal}</div>
845857
<div class="fair-bar-bg">
846858
<div class="fair-bar-fill"
847-
style="width:${width}%; background:${medalColors[medal]}"></div>
859+
style="width:${width}%; background:${medalColors[medal]}"></div>
848860
</div>
849861
<div class="fair-medal-value">${value}</div>
850862
</div>
@@ -853,28 +865,41 @@
853865
</div>
854866
855867
<div class="fair-box">
856-
<div class="fair-box-title">Fair medals with average population and average GDP</div>
868+
<div class="fair-box-title">
869+
Fair medals with average population and average GDP
870+
</div>
871+
872+
${data.similarCountry ? `
873+
<div class="fair-warning">
874+
No medals for ${country}. Fair values are estimated from ${data.similarCountry},
875+
a medal-winning country with similar GDP.
876+
</div>
877+
` : ""}
878+
857879
${medalOrder.map(medal => {
858880
const value = data.fair[medal];
859-
const width = value === null || value === 0
860-
? 0
861-
: Math.max(3, (100 * value) / maxScale);
881+
const width =
882+
value === null || value === 0
883+
? 0
884+
: Math.max(3, (100 * value) / maxScale);
862885
863886
return `
864887
<div class="fair-medal-row">
865888
<div class="fair-medal-label">${medal}</div>
866889
<div class="fair-bar-bg">
867890
<div class="fair-bar-fill"
868-
style="width:${width}%; background:${medalColors[medal]}"></div>
891+
style="width:${width}%; background:${medalColors[medal]}"></div>
892+
</div>
893+
<div class="fair-medal-value">
894+
${value === null ? "n/a" : formatFair(value)}
869895
</div>
870-
<div class="fair-medal-value">${formatFair(value)}</div>
871896
</div>
872897
`;
873898
}).join("")}
874899
875-
${fairUnavailable ? `
900+
${fairUnavailable && !data.similarCountry ? `
876901
<div class="fair-warning">
877-
Fair values are unavailable because population or GDP data is missing for this selection.
902+
Missing population or GDP data.
878903
</div>
879904
` : ""}
880905
</div>
@@ -1044,12 +1069,12 @@
10441069

10451070
const populationRatio =
10461071
indicators.population && means.meanPopulation
1047-
? indicators.population / means.meanPopulation
1072+
? means.meanPopulation / indicators.population
10481073
: 1;
10491074

10501075
const gdpRatio =
10511076
indicators.gdp && means.meanGDP
1052-
? indicators.gdp / means.meanGDP
1077+
? means.meanGDP / indicators.gdp
10531078
: 1;
10541079

10551080
const populationEffect = Math.pow(populationRatio, state.populationAdjustment / 100);

website/styles.css

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1196,6 +1196,31 @@ p {
11961196
line-height: 1.25;
11971197
}
11981198

1199+
.fair-local-sliders {
1200+
display: flex;
1201+
flex-direction: column;
1202+
gap: 22px;
1203+
}
1204+
1205+
.fair-local-sliders .fair-slider-control {
1206+
justify-content: space-between;
1207+
}
1208+
1209+
.fair-local-sliders input {
1210+
width: 280px;
1211+
}
1212+
1213+
.fair-whatif-sliders {
1214+
margin-top: 14px;
1215+
display: flex;
1216+
flex-direction: column;
1217+
gap: 12px;
1218+
}
1219+
1220+
.fair-whatif-sliders .fair-slider-control {
1221+
justify-content: space-between;
1222+
}
1223+
11991224
/* =============================================
12001225
Footer
12011226
=========================================== */

0 commit comments

Comments
 (0)