Skip to content

Instantly share code, notes, and snippets.

@borgar
Last active January 1, 2020 09:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save borgar/48bd747202396807cbbbbc5e984bdd9e to your computer and use it in GitHub Desktop.
Save borgar/48bd747202396807cbbbbc5e984bdd9e to your computer and use it in GitHub Desktop.
FIFA World Cup Appearances
license: gpl-3.0
height: 560
border: no

Anticipating the 2010 FIFA World Cup, DataMarket decided the tournament was a great excuse to spend a little time cooking up something fun. Someone suggested going with a World Cup riff on Ben Fry's Fortune 500 visualization. Lacking a better suggestion we ran with it.

The result is a schoolbook example of how a simple thing can scale in complexity incredibly quickly. It should have been immediately obvious that this wasn't going to work.

Ignoring the fact that the visualization doesn't suit the data at all. The data, once we starting really looking at it, was way too complicated:

  • Countries fragment and even rejoin (in the case of Germany). FIFA has official decisions on what happens where. This fragmentation needed to be shown, however, somehow.

  • The final order of the teams may have joint seat placing. Because no one really cares about anything other than the first 3-4 places.

  • We prepared flags for all countries, this takes time for 81 countries (some of which no longer exist). Unless you have a system to do so (we didn't).

  • At the time, we had not properly solved vector graphics for Internet Explorer. I can't remember what our plan was for that (we ended up with only text highlighting).

Things like this can cost you a lot of time to work around. In order to show the history of Yugoslavia, you first need to understand the breakup of Yugoslavia. And then you need to annotate the data.

So the short of it is that we simply ran out of the time we had to spend on it. We pushed what we had managed to do live. Despite having had fun working on it, I guess none of us felt super proud of it. At least, it always bothered me that the thing never looked anything like our original vision for it.

So I've finally gone back and finished it. Not great, but at least it looks closer to how we envisioned it. For many of us, what it really ended up being was a harsh lesson in effort estimation.

/* globals d3 */
const svg = d3.select('svg');
const margin = { top: 10, right: 0, bottom: 0, left: 0 };
const width = +svg.attr('width') - margin.left - margin.right;
const height = +svg.attr('height') - margin.top - margin.bottom;
const g = svg.append('g').attr('transform', `translate(${margin.left},${margin.top})`);
const plot = g.append('g').attr('transform', `translate(${margin.left},${margin.top + 100})`);
const table = g.append('g').attr('transform', `translate(${margin.left},${margin.top + 100})`);
g.append('text')
.attr('class', 'hint')
.text('Hover the mouse cursor on a country code to see the history of the country\'s World Cup participation. Click to compare two countries.')
.attr('y', height - 5);
const parseRow = row => {
row.host = row.host.split(' ');
row.tags = row.tags.split(' ');
row.year = +row.year;
row.place = +row.place;
return row;
};
function updatePanels (team1, team2) {
const teams = g.selectAll('.team')
.data([ team1, team2 ], d => d ? d.team : '--');
teams.exit().remove();
const teamsEnter = teams.enter()
.append('g')
.attr('class', 'team')
.attr('transform', (d, i) => `translate(${i * width / 2},0)`);
teamsEnter.append('image')
.attr('x', 1)
.attr('height', 50)
.attr('width', 76);
teams.merge(teamsEnter)
.transition()
.attr('transform', (d, i) => `translate(${i * width / 2},0)`)
.selectAll('image')
.attr('href', d => {
return d ? `https://upload.wikimedia.org/wikipedia/commons${d.flag}` : '';
});
const textLines = teamsEnter.merge(teams)
.selectAll('text')
.data(d => {
if (d) {
return [
{ text: d.name, size: 24, y: 0 },
{ text: `${d.year}${d._tied ? 'Joint ' : ''}${d.place}. place`, size: 18, y: 28 }
].concat(
d.note
? d.note.split('\n').map((t, i) => ({ text: t, y: 52 + i * 15 }))
: []
);
}
return [];
});
textLines.exit().remove();
textLines.enter()
.append('text')
.attr('font-size', d => d.size)
.attr('dy', '.8em')
.attr('y', d => d.y)
.attr('x', 85)
.merge(textLines)
.text(d => d.text);
}
d3.json('./teams.json', (err, teamList) => {
if (err) { throw err; }
d3.csv('./fifa.csv', parseRow, (err, allResults) => {
if (err) { throw err; }
// console.log(allResults);
allResults.forEach(d => {
Object.assign(d, teamList.find(s => d.team === s.id));
// turn all "formerly" props into arrays to simplify things later on
if (!Array.isArray(d.formerly)) {
d.formerly = [ d.formerly ].filter(Boolean);
}
});
// order entries but shuffle tied teams
const ties = d3.nest()
.key(d => [ d.year, d.place ].join('/'))
.entries(allResults)
.filter(d => d.values.length > 1);
ties.forEach(g => g.values.forEach(d => { d._tied = true; }));
const byYear = d3.nest()
.key(d => d.year)
.entries(d3.shuffle(allResults));
byYear.forEach(d => {
d.values = d.values.sort((a, b) => a.place - b.place);
d.values.forEach((d, i) => { d.rowIndex = i; });
});
const maxPlaces = d3.max(byYear, d => d.values.length);
const places = d3.range(maxPlaces);
const years = Array.from(new Set(allResults.map(d => d.year))).sort(d3.ascending);
const x = d3.scaleBand()
.domain(years)
.range([ 0, width ]);
const tableHeight = 426;
const cellHeight = tableHeight / maxPlaces;
const cellWidth = width / years.length;
const y = d3.scaleBand()
.domain(places)
.range([ 18, 18 + tableHeight ]);
const xBand = x.bandwidth() / 2;
const last_year = d3.max(years);
// current champion starts selected
let selected_item = allResults.find(d => d.year === last_year && d.place === 1);
let current_item = null;
const path = d3.line()
.curve(d3.curveCardinal.tension(0.5))
.y(d => y(d.rowIndex))
.x(d => x(d.year) + xBand);
const current_line = plot.append('g').attr('stroke', 'rgba(150,40,0,0.3)');
const selected_line = plot.append('g').attr('stroke', 'rgba(0,50,150,0.3)');
const xAx = table.append('g')
.attr('class', 'axis x');
xAx.selectAll('text')
.data(years).enter()
.append('text')
.attr('text-anchor', 'middle')
.attr('alignment-baseline', 'middle')
.attr('x', d => x(d) + xBand)
.text(String);
table.selectAll('.tie')
.data(ties).enter()
.append('rect')
.attr('class', 'tie')
.attr('rx', 3)
.attr('x', d => x(d.values[0].year) + cellWidth * 0.05)
.attr('y', d => y(d3.min(d.values, d => d.rowIndex)) - cellHeight / 2 - 1)
.attr('width', cellWidth * 0.9)
.attr('height', d => cellHeight * d.values.length);
function update () {
updateLine(current_line, current_item);
updateLine(selected_line, selected_item);
updateTable(current_item, selected_item);
updatePanels(current_item, selected_item);
}
let leaveTimer;
const column = table.selectAll('.cell')
.data(allResults).enter()
.append('g')
.attr('class', 'cell')
.attr('transform', d => `translate(${x(d.year) + xBand},${y(d.rowIndex)})`)
.on('mouseenter', d => {
clearTimeout(leaveTimer);
if (selected_item && d.team === selected_item.team) {
current_item = null;
update();
}
else {
current_item = d;
update();
}
})
.on('mouseleave', () => {
clearTimeout(leaveTimer);
leaveTimer = setTimeout(() => {
current_item = null;
update();
}, 50);
})
.on('click', d => {
if (current_item) {
selected_item = current_item;
current_item = null;
}
update();
});
column.append('text')
.attr('text-anchor', 'middle')
.attr('alignment-baseline', 'middle')
.text(d => d.team);
function updateTable (team1, team2) {
const tags = new Set((team1 ? team1.tags : []).concat(team2 ? team2.tags : []));
table.selectAll('.cell').attr('class', d => `cell ${tags.has(d.team) ? 'active' : ''}`);
}
function updateLine (line, team) {
line.html(null);
if (!team) { return; }
const tags = new Set(team.tags);
const relevant = allResults
.filter(d => tags.has(d.team))
.sort((a, b) => d3.ascending(a.year, b.year) || d3.ascending(a.place, b.place));
const lines = [];
function link (prev, next) {
if (!prev || !next) { return; }
// can connect to a prior line?
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
if (line[line.length - 1] === prev) {
line.push(next);
return;
}
}
// start a new one
lines.push([ prev, next ]);
}
years.forEach(year => {
// this year's teams
const dt = relevant.filter(d => d.year === year);
if (!dt.length) { return; } // skip non-present years
dt.forEach(item => {
const teamId = item.team;
const former = new Set([ item.team ].concat(item.formerly));
// find what passed items we can link to
const prior = relevant.reduce((a, c) => {
if (c.year < year && former.has(c.team) && (!a[c.team] || a[c.team].year < c.year)) {
a[c.team] = c;
}
return a;
}, {});
// if we have a more recent occurence of "former" than latest of team, preclude linking to team again
if (teamId in prior) {
for (const key in prior) {
if (key !== teamId && prior[key].year >= prior[teamId].year) {
delete prior[teamId];
break;
}
}
}
const opts = Object.keys(prior);
// can link to a prior occurence of team
if (teamId in prior) {
link(prior[teamId], item);
}
else if (opts.length) {
opts.forEach(key => link(prior[key], item));
}
});
});
line.selectAll('.track')
.data(lines).enter()
.append('path')
.attr('class', 'track')
.attr('d', path);
}
update();
});
});
year host team place tags
1930 URU URU 1 URU
1930 URU ARG 2 ARG
1930 URU USA 3 USA
1930 URU YUG 4 YUG CRO SRB SCG SVN BIH
1930 URU CHI 5 CHI
1930 URU BRA 6 BRA
1930 URU FRA 7 FRA
1930 URU ROU 8 ROU
1930 URU PAR 9 PAR
1930 URU PER 10 PER
1930 URU BEL 11 BEL
1930 URU BOL 12 BOL
1930 URU MEX 13 MEX
1934 ITA ITA 1 ITA
1934 ITA TCH 2 TCH CZE SVK
1934 ITA GER 3 GER FRG DDR
1934 ITA AUT 4 AUT
1934 ITA ESP 5 ESP
1934 ITA HUN 6 HUN
1934 ITA SUI 7 SUI
1934 ITA SWE 8 SWE
1934 ITA FRA 9 FRA
1934 ITA NED 9 NED
1934 ITA ARG 9 ARG
1934 ITA ROU 12 ROU
1934 ITA EGY 13 EGY
1934 ITA BRA 14 BRA
1934 ITA BEL 15 BEL
1934 ITA USA 16 USA
1938 FRA ITA 1 ITA
1938 FRA HUN 2 HUN
1938 FRA BRA 3 BRA
1938 FRA SWE 4 SWE
1938 FRA TCH 5 TCH CZE SVK
1938 FRA FRA 6 FRA
1938 FRA SUI 7 SUI
1938 FRA CUB 8 CUB
1938 FRA ROU 9 ROU
1938 FRA GER 10 GER FRG DDR
1938 FRA POL 11 POL
1938 FRA NOR 12 NOR
1938 FRA BEL 13 BEL
1938 FRA NED 14 NED
1938 FRA DEI 15 DEI IDN
1950 BRA URU 1 URU
1950 BRA BRA 2 BRA
1950 BRA SWE 3 SWE
1950 BRA ESP 4 ESP
1950 BRA YUG 5 YUG CRO SRB SCG SVN BIH
1950 BRA SUI 6 SUI
1950 BRA ITA 7 ITA
1950 BRA ENG 8 ENG
1950 BRA CHI 9 CHI
1950 BRA USA 10 USA
1950 BRA PAR 11 PAR
1950 BRA MEX 12 MEX
1950 BRA BOL 13 BOL
1954 SUI FRG 1 FRG GER
1954 SUI HUN 2 HUN
1954 SUI AUT 3 AUT
1954 SUI URU 4 URU
1954 SUI BRA 5 BRA
1954 SUI ENG 6 ENG
1954 SUI YUG 7 YUG CRO SRB SCG SVN BIH
1954 SUI SUI 8 SUI
1954 SUI TUR 9 TUR
1954 SUI ITA 10 ITA
1954 SUI FRA 11 FRA
1954 SUI BEL 12 BEL
1954 SUI MEX 13 MEX
1954 SUI TCH 14 TCH CZE SVK
1954 SUI SCO 15 SCO
1954 SUI KOR 16 KOR
1958 SWE BRA 1 BRA
1958 SWE SWE 2 SWE
1958 SWE FRA 3 FRA
1958 SWE FRG 4 FRG GER
1958 SWE YUG 5 YUG CRO SRB SCG SVN BIH
1958 SWE WAL 6 WAL
1958 SWE URS 7 URS RUS UKR
1958 SWE NIR 8 NIR
1958 SWE TCH 9 TCH CZE SVK
1958 SWE HUN 10 HUN
1958 SWE ENG 11 ENG
1958 SWE PAR 12 PAR
1958 SWE ARG 13 ARG
1958 SWE SCO 14 SCO
1958 SWE AUT 15 AUT
1958 SWE MEX 16 MEX
1962 CHI BRA 1 BRA
1962 CHI TCH 2 TCH CZE SVK
1962 CHI CHI 3 CHI
1962 CHI YUG 4 YUG CRO SRB SCG SVN BIH
1962 CHI HUN 5 HUN
1962 CHI URS 6 URS RUS UKR
1962 CHI FRG 7 FRG GER
1962 CHI ENG 8 ENG
1962 CHI ITA 9 ITA
1962 CHI ARG 10 ARG
1962 CHI MEX 11 MEX
1962 CHI ESP 12 ESP
1962 CHI URU 13 URU
1962 CHI COL 14 COL
1962 CHI BUL 15 BUL
1962 CHI SUI 16 SUI
1966 ENG ENG 1 ENG
1966 ENG FRG 2 FRG GER
1966 ENG POR 3 POR
1966 ENG URS 4 URS RUS UKR
1966 ENG ARG 5 ARG
1966 ENG HUN 6 HUN
1966 ENG URU 7 URU
1966 ENG PRK 8 PRK
1966 ENG ITA 9 ITA
1966 ENG ESP 10 ESP
1966 ENG BRA 11 BRA
1966 ENG MEX 12 MEX
1966 ENG CHI 13 CHI
1966 ENG FRA 13 FRA
1966 ENG BUL 15 BUL
1966 ENG SUI 16 SUI
1970 MEX BRA 1 BRA
1970 MEX ITA 2 ITA
1970 MEX FRG 3 FRG GER
1970 MEX URU 4 URU
1970 MEX URS 5 URS RUS UKR
1970 MEX MEX 6 MEX
1970 MEX PER 7 PER
1970 MEX ENG 8 ENG
1970 MEX SWE 9 SWE
1970 MEX BEL 10 BEL
1970 MEX ROU 10 ROU
1970 MEX ISR 12 ISR
1970 MEX BUL 13 BUL
1970 MEX MAR 14 MAR
1970 MEX TCH 15 TCH CZE SVK
1970 MEX SLV 16 SLV
1974 GER FRG 1 FRG GER
1974 GER NED 2 NED
1974 GER POL 3 POL
1974 GER BRA 4 BRA
1974 GER SWE 5 SWE
1974 GER DDR 6 DDR GER
1974 GER YUG 7 YUG CRO SRB SCG SVN BIH
1974 GER ARG 8 ARG
1974 GER SCO 9 SCO
1974 GER ITA 10 ITA
1974 GER CHI 11 CHI
1974 GER URU 12 URU
1974 GER BUL 12 BUL
1974 GER AUS 14 AUS
1974 GER HAI 15 HAI
1974 GER ZAI 16 ZAI COD
1978 ARG ARG 1 ARG
1978 ARG NED 2 NED
1978 ARG BRA 3 BRA
1978 ARG ITA 4 ITA
1978 ARG POL 5 POL
1978 ARG FRG 6 FRG GER
1978 ARG AUT 7 AUT
1978 ARG PER 8 PER
1978 ARG TUN 9 TUN
1978 ARG ESP 10 ESP
1978 ARG SCO 11 SCO
1978 ARG FRA 12 FRA
1978 ARG SWE 13 SWE
1978 ARG IRN 14 IRN
1978 ARG HUN 15 HUN
1978 ARG MEX 16 MEX
1982 ESP ITA 1 ITA
1982 ESP FRG 2 FRG GER
1982 ESP POL 3 POL
1982 ESP FRA 4 FRA
1982 ESP BRA 5 BRA
1982 ESP ENG 6 ENG
1982 ESP URS 7 URS RUS UKR
1982 ESP AUT 8 AUT
1982 ESP NIR 9 NIR
1982 ESP BEL 10 BEL
1982 ESP ARG 11 ARG
1982 ESP ESP 12 ESP
1982 ESP ALG 13 ALG
1982 ESP HUN 14 HUN
1982 ESP SCO 15 SCO
1982 ESP YUG 16 YUG CRO SRB SCG SVN BIH
1982 ESP CMR 17 CMR
1982 ESP HON 18 HON
1982 ESP TCH 19 TCH CZE SVK
1982 ESP PER 20 PER
1982 ESP KUW 21 KUW
1982 ESP CHI 22 CHI
1982 ESP NZL 23 NZL
1982 ESP SLV 24 SLV
1986 MEX ARG 1 ARG
1986 MEX FRG 2 FRG GER
1986 MEX FRA 3 FRA
1986 MEX BEL 4 BEL
1986 MEX BRA 5 BRA
1986 MEX MEX 6 MEX
1986 MEX ESP 7 ESP
1986 MEX ENG 8 ENG
1986 MEX DEN 9 DEN
1986 MEX URS 10 URS RUS UKR
1986 MEX MAR 11 MAR
1986 MEX ITA 12 ITA
1986 MEX PAR 13 PAR
1986 MEX POL 14 POL
1986 MEX BUL 15 BUL
1986 MEX URU 16 URU
1986 MEX POR 17 POR
1986 MEX HUN 18 HUN
1986 MEX SCO 19 SCO
1986 MEX KOR 20 KOR
1986 MEX NIR 21 NIR
1986 MEX ALG 22 ALG
1986 MEX IRQ 23 IRQ
1986 MEX CAN 24 CAN
1990 ITA FRG 1 FRG GER
1990 ITA ARG 2 ARG
1990 ITA ITA 3 ITA
1990 ITA ENG 4 ENG
1990 ITA YUG 5 YUG CRO SRB SCG SVN BIH
1990 ITA TCH 6 TCH CZE SVK
1990 ITA CMR 7 CMR
1990 ITA IRL 8 IRL
1990 ITA BRA 9 BRA
1990 ITA ESP 10 ESP
1990 ITA BEL 11 BEL
1990 ITA ROU 12 ROU
1990 ITA CRC 13 CRC
1990 ITA COL 14 COL
1990 ITA NED 15 NED
1990 ITA URU 16 URU
1990 ITA URS 17 URS RUS UKR
1990 ITA AUT 18 AUT
1990 ITA SCO 18 SCO
1990 ITA EGY 20 EGY
1990 ITA SWE 21 SWE
1990 ITA KOR 22 KOR
1990 ITA USA 23 USA
1990 ITA UAE 24 UAE
1994 USA BRA 1 BRA
1994 USA ITA 2 ITA
1994 USA SWE 3 SWE
1994 USA BUL 4 BUL
1994 USA GER 5 GER FRG DDR
1994 USA ROU 6 ROU
1994 USA NED 7 NED
1994 USA ESP 8 ESP
1994 USA NGA 9 NGA
1994 USA ARG 10 ARG
1994 USA BEL 11 BEL
1994 USA KSA 12 KSA
1994 USA MEX 13 MEX
1994 USA USA 14 USA
1994 USA SUI 15 SUI
1994 USA IRL 16 IRL
1994 USA NOR 17 NOR
1994 USA RUS 18 RUS URS
1994 USA COL 19 COL
1994 USA KOR 20 KOR
1994 USA BOL 21 BOL
1994 USA CMR 22 CMR
1994 USA MAR 23 MAR
1994 USA GRE 24 GRE
1998 FRA FRA 1 FRA
1998 FRA BRA 2 BRA
1998 FRA CRO 3 CRO YUG
1998 FRA NED 4 NED
1998 FRA ITA 5 ITA
1998 FRA ARG 6 ARG
1998 FRA GER 7 GER FRG DDR
1998 FRA DEN 8 DEN
1998 FRA ENG 9 ENG
1998 FRA SCG 10 SCG SRB YUG
1998 FRA ROU 11 ROU
1998 FRA NGA 12 NGA
1998 FRA MEX 13 MEX
1998 FRA PAR 14 PAR
1998 FRA NOR 15 NOR
1998 FRA CHI 16 CHI
1998 FRA ESP 17 ESP
1998 FRA MAR 18 MAR
1998 FRA BEL 19 BEL
1998 FRA IRN 20 IRN
1998 FRA COL 21 COL
1998 FRA JAM 22 JAM
1998 FRA AUT 23 AUT
1998 FRA RSA 24 RSA
1998 FRA CMR 25 CMR
1998 FRA TUN 26 TUN
1998 FRA SCO 27 SCO
1998 FRA KSA 28 KSA
1998 FRA BUL 29 BUL
1998 FRA KOR 30 KOR
1998 FRA JPN 31 JPN
1998 FRA USA 32 USA
2002 JPN KOR BRA 1 BRA
2002 JPN KOR GER 2 GER FRG DDR
2002 JPN KOR TUR 3 TUR
2002 JPN KOR KOR 4 KOR
2002 JPN KOR ESP 5 ESP
2002 JPN KOR ENG 6 ENG
2002 JPN KOR SEN 7 SEN
2002 JPN KOR USA 8 USA
2002 JPN KOR JPN 9 JPN
2002 JPN KOR DEN 10 DEN
2002 JPN KOR MEX 11 MEX
2002 JPN KOR IRL 12 IRL
2002 JPN KOR SWE 13 SWE
2002 JPN KOR BEL 14 BEL
2002 JPN KOR ITA 15 ITA
2002 JPN KOR PAR 16 PAR
2002 JPN KOR RSA 17 RSA
2002 JPN KOR ARG 18 ARG
2002 JPN KOR CRC 19 CRC
2002 JPN KOR CMR 20 CMR
2002 JPN KOR POR 21 POR
2002 JPN KOR RUS 22 RUS URS
2002 JPN KOR CRO 23 CRO YUG
2002 JPN KOR ECU 24 ECU
2002 JPN KOR POL 25 POL
2002 JPN KOR URU 26 URU
2002 JPN KOR NGA 27 NGA
2002 JPN KOR FRA 28 FRA
2002 JPN KOR TUN 29 TUN
2002 JPN KOR SVN 30 SVN YUG
2002 JPN KOR CHN 31 CHN
2002 JPN KOR KSA 32 KSA
2006 GER ITA 1 ITA
2006 GER FRA 2 FRA
2006 GER GER 3 GER FRG DDR
2006 GER POR 4 POR
2006 GER BRA 5 BRA
2006 GER ARG 6 ARG
2006 GER ENG 7 ENG
2006 GER UKR 8 UKR URS
2006 GER ESP 9 ESP
2006 GER SUI 10 SUI
2006 GER NED 11 NED
2006 GER ECU 12 ECU
2006 GER GHA 13 GHA
2006 GER SWE 14 SWE
2006 GER MEX 15 MEX
2006 GER AUS 16 AUS
2006 GER KOR 17 KOR
2006 GER PAR 18 PAR
2006 GER CIV 19 CIV
2006 GER CZE 20 CZE TCH
2006 GER POL 21 POL
2006 GER CRO 22 CRO YUG
2006 GER ANG 23 ANG
2006 GER TUN 24 TUN
2006 GER IRN 25 IRN
2006 GER USA 25 USA
2006 GER TRI 27 TRI
2006 GER JPN 28 JPN
2006 GER KSA 28 KSA
2006 GER TOG 30 TOG
2006 GER CRC 31 CRC
2006 GER SCG 32 SCG SRB YUG
2010 RSA ESP 1 ESP
2010 RSA NED 2 NED
2010 RSA GER 3 GER FRG DDR
2010 RSA URU 4 URU
2010 RSA ARG 5 ARG
2010 RSA BRA 6 BRA
2010 RSA GHA 7 GHA
2010 RSA PAR 8 PAR
2010 RSA JPN 9 JPN
2010 RSA CHI 10 CHI
2010 RSA POR 11 POR
2010 RSA USA 12 USA
2010 RSA ENG 13 ENG
2010 RSA MEX 14 MEX
2010 RSA KOR 15 KOR
2010 RSA SVK 16 SVK TCH
2010 RSA CIV 17 CIV
2010 RSA SVN 18 SVN YUG
2010 RSA SUI 19 SUI
2010 RSA RSA 20 RSA
2010 RSA AUS 21 AUS
2010 RSA NZL 22 NZL
2010 RSA SRB 23 SRB YUG SCG
2010 RSA DEN 24 DEN
2010 RSA GRE 25 GRE
2010 RSA ITA 26 ITA
2010 RSA NGA 27 NGA
2010 RSA ALG 28 ALG
2010 RSA FRA 29 FRA
2010 RSA HON 30 HON
2010 RSA CMR 31 CMR
2010 RSA PRK 32 PRK
2014 BRA GER 1 GER FRG DDR
2014 BRA ARG 2 ARG
2014 BRA NED 3 NED
2014 BRA BRA 4 BRA
2014 BRA COL 5 COL
2014 BRA BEL 6 BEL
2014 BRA FRA 7 FRA
2014 BRA CRC 8 CRC
2014 BRA CHI 9 CHI
2014 BRA MEX 10 MEX
2014 BRA SUI 11 SUI
2014 BRA URU 12 URU
2014 BRA GRE 13 GRE
2014 BRA ALG 14 ALG
2014 BRA USA 15 USA
2014 BRA NGA 16 NGA
2014 BRA ECU 17 ECU
2014 BRA POR 18 POR
2014 BRA CRO 19 CRO YUG
2014 BRA BIH 20 BIH YUG
2014 BRA CIV 21 CIV
2014 BRA ITA 22 ITA
2014 BRA ESP 23 ESP
2014 BRA RUS 24 RUS URS
2014 BRA GHA 25 GHA
2014 BRA ENG 26 ENG
2014 BRA KOR 27 KOR
2014 BRA IRN 28 IRN
2014 BRA JPN 29 JPN
2014 BRA AUS 30 AUS
2014 BRA HON 31 HON
2014 BRA CMR 32 CMR
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset=utf-8 />
<title>FIFA World Cup team appearances</title>
</head>
<body>
<style>
body {
background: white;
}
svg {
font-family: sans-serif;
font-size: 10px;
}
.tie {
fill: none;
stroke: #999;
}
.cell {
cursor: pointer;
}
.cell text {
fill: #999;
}
.active text {
fill: #000;
}
.x text {
font-size: 14px;
}
.hint {
font-size: 11px;
fill: #999;
}
.track {
fill: none;
stroke-width: 2;
}
</style>
<script src="//cdnjs.cloudflare.com/ajax/libs/babel-polyfill/6.16.0/polyfill.js"></script>
<script src="//d3js.org/d3.v4.min.js"></script>
<svg width="960" height="560"></svg>
<script src="driver.js"></script>
</body>
</html>
[
{ "id": "ALG",
"name": "Algeria",
"flag": "/7/77/Flag_of_Algeria.svg" },
{ "id": "ANG",
"name": "Angola",
"flag": "/9/9d/Flag_of_Angola.svg" },
{ "id": "ARG",
"name": "Argentina",
"flag": "/1/1a/Flag_of_Argentina.svg" },
{ "id": "AUS",
"name": "Australia",
"flag": "/b/b9/Flag_of_Australia.svg" },
{ "id": "AUT",
"name": "Austria",
"flag": "/4/41/Flag_of_Austria.svg" },
{ "id": "BEL",
"name": "Belgium",
"flag": "/9/92/Flag_of_Belgium_%28civil%29.svg" },
{ "id": "BIH",
"name": "Bosnia and Herzegovina",
"note": "Bosnia and Herzegovina became independent from Yugoslavia in 1991\n and is considereda distinct team by FIFA.",
"flag": "/b/bf/Flag_of_Bosnia_and_Herzegovina.svg",
"formerly": "YUG" },
{ "id": "BOL",
"name": "Bolivia",
"flag": "/4/48/Flag_of_Bolivia.svg" },
{ "id": "BRA",
"name": "Brazil",
"note": "Brazil is only country to have played in every World Cup.",
"flag": "/0/05/Flag_of_Brazil.svg" },
{ "id": "BUL",
"name": "Bulgaria",
"flag": "/9/9a/Flag_of_Bulgaria.svg" },
{ "id": "CMR",
"name": "Cameroon",
"flag": "/4/4f/Flag_of_Cameroon.svg" },
{ "id": "CAN",
"name": "Canada",
"flag": "/c/cf/Flag_of_Canada.svg" },
{ "id": "CHI",
"name": "Chile",
"flag": "/7/78/Flag_of_Chile.svg" },
{ "id": "CHN",
"name": "People's Republic of China",
"flag": "/f/fa/Flag_of_the_People%27s_Republic_of_China.svg" },
{ "id": "COL",
"name": "Colombia",
"flag": "/2/21/Flag_of_Colombia.svg" },
{ "id": "COD",
"name": "Democratic Republic of Congo",
"note": "Formerly competed as Zaire in 1974.",
"flag": "/6/6f/Flag_of_the_Democratic_Republic_of_the_Congo.svg" },
{ "id": "CRC",
"name": "Costa Rica",
"flag": "/f/f2/Flag_of_Costa_Rica.svg" },
{ "id": "CIV",
"name": "Côte d'Ivoire",
"flag": "/f/fe/Flag_of_Côte_d%27Ivoire.svg" },
{ "id": "CRO",
"name": "Croatia",
"note": "Croatia became independent from Yugoslavia in 1991 and is considered\na distinct team by FIFA.",
"flag": "/1/1b/Flag_of_Croatia.svg",
"formerly": "YUG" },
{ "id": "CUB",
"name": "Cuba",
"flag": "/b/bd/Flag_of_Cuba.svg" },
{ "id": "TCH",
"name": "Czechoslovakia",
"note": "Czechoslovakia was divided into Slovakia and the Czech Republic in 1993.",
"flag": "/7/7f/Flag_of_Czechoslovakia.png" },
{ "id": "CZE",
"name": "Czech Republic",
"note": "Czechoslovakia was divided into Slovakia and the Czech Republic in 1993.",
"formerly": "TCH",
"flag": "/c/cb/Flag_of_the_Czech_Republic.svg" },
{ "id": "DEN",
"name": "Denmark",
"flag": "/9/9c/Flag_of_Denmark.svg" },
{ "id": "DEI",
"name": "Dutch East Indies",
"note": "The Dutch East Indies became modern Indonesia in 1949.",
"flag": "/2/20/Flag_of_the_Netherlands.svg" },
{ "id": "DDR",
"name": "East Germany",
"note": "Germany was divided into East and West halves between 1949–1990.",
"formerly": "GER",
"flag": "/a/a1/Flag_of_East_Germany.svg" },
{ "id": "ECU",
"name": "Ecuador",
"flag": "/e/e8/Flag_of_Ecuador.svg" },
{ "id": "EGY",
"name": "Egypt",
"flag": "/f/fe/Flag_of_Egypt.svg" },
{ "id": "SLV",
"name": "El Salvador",
"flag": "/3/34/Flag_of_El_Salvador.svg" },
{ "id": "ENG",
"name": "England",
"flag": "/b/be/Flag_of_England.svg" },
{ "id": "FRA",
"name": "France",
"flag": "/c/c3/Flag_of_France.svg" },
{ "id": "GER",
"name": "Germany",
"note": "Germany was divided into East and West halves between 1949–1990.\nFIFA attributes results of the West Germany team to current day Germany.",
"formerly": [ "DDR", "FRG" ],
"flag": "/b/ba/Flag_of_Germany.svg" },
{ "id": "GHA",
"name": "Ghana",
"flag": "/1/19/Flag_of_Ghana.svg" },
{ "id": "GRE",
"name": "Greece",
"flag": "/5/5c/Flag_of_Greece.svg" },
{ "id": "HAI",
"name": "Haiti",
"flag": "/5/56/Flag_of_Haiti.svg" },
{ "id": "HON",
"name": "Honduras",
"flag": "/8/82/Flag_of_Honduras.svg" },
{ "id": "HUN",
"name": "Hungary",
"flag": "/c/c1/Flag_of_Hungary.svg" },
{ "id": "IDN",
"name": "Indonesia",
"note": "Indonesia competed as the Dutch East Indies in 1938.",
"formerly": "DEI",
"flag": "/9/9f/Flag_of_Indonesia.svg" },
{ "id": "IRN",
"name": "Iran",
"flag": "/c/ca/Flag_of_Iran.svg" },
{ "id": "IRQ",
"name": "Iraq",
"flag": "/f/f6/Flag_of_Iraq.svg" },
{ "id": "ISR",
"name": "Israel",
"flag": "/d/d4/Flag_of_Israel.svg" },
{ "id": "ITA",
"name": "Italy",
"flag": "/0/03/Flag_of_Italy.svg" },
{ "id": "JAM",
"name": "Jamaica",
"flag": "/0/0a/Flag_of_Jamaica.svg" },
{ "id": "JPN",
"name": "Japan",
"flag": "/9/9e/Flag_of_Japan.svg" },
{ "id": "PRK",
"name": "Korea DPR",
"flag": "/5/51/Flag_of_North_Korea.svg" },
{ "id": "KOR",
"name": "Korea Republic",
"flag": "/0/09/Flag_of_South_Korea.svg" },
{ "id": "KUW",
"name": "Kuwait",
"flag": "/a/aa/Flag_of_Kuwait.svg" },
{ "id": "MEX",
"name": "Mexico",
"flag": "/f/fc/Flag_of_Mexico.svg" },
{ "id": "MAR",
"name": "Morocco",
"flag": "/e/ea/Flag_of_Monaco.svg" },
{ "id": "NED",
"name": "Netherlands",
"flag": "/2/20/Flag_of_the_Netherlands.svg" },
{ "id": "NZL",
"name": "New Zealand",
"flag": "/3/3e/Flag_of_New_Zealand.svg" },
{ "id": "NGA",
"name": "Nigeria",
"flag": "/7/79/Flag_of_Nigeria.svg" },
{ "id": "NIR",
"name": "Northern Ireland",
"flag": "/f/f6/Flag_of_Northern_Ireland.svg" },
{ "id": "NOR",
"name": "Norway",
"flag": "/d/d9/Flag_of_Norway.svg" },
{ "id": "PAR",
"name": "Paraguay",
"flag": "/2/27/Flag_of_Paraguay.svg" },
{ "id": "PER",
"name": "Peru",
"flag": "/c/cf/Flag_of_Peru.svg" },
{ "id": "POL",
"name": "Poland",
"flag": "/1/12/Flag_of_Poland.svg" },
{ "id": "POR",
"name": "Portugal",
"flag": "/5/5c/Flag_of_Portugal.svg" },
{ "id": "IRL",
"name": "Republic of Ireland",
"flag": "/4/45/Flag_of_Ireland.svg" },
{ "id": "ROU",
"name": "Romania",
"flag": "/7/73/Flag_of_Romania.svg" },
{ "id": "RUS",
"name": "Russia",
"note": "FIFA considers Russian team the successor team of the USSR.",
"formerly": "URS",
"flag": "/f/f3/Flag_of_Russia.svg" },
{ "id": "KSA",
"name": "Saudi Arabia",
"flag": "/0/0d/Flag_of_Saudi_Arabia.svg" },
{ "id": "SCO",
"name": "Scotland",
"flag": "/1/10/Flag_of_Scotland.svg" },
{ "id": "SEN",
"name": "Senegal",
"flag": "/f/fd/Flag_of_Senegal.svg" },
{ "id": "SRB",
"name": "Serbia",
"note": "FIFA considers Serbia the successor to the Serbia and Montenegro team\nwhich succeded the Yugoslavian team.",
"formerly": "SCG",
"flag": "/f/ff/Flag_of_Serbia.svg" },
{ "id": "SCG",
"name": "Serbia and Montenegro",
"note": "FIFA considers Serbia and Montenegro the successor team to Yugoslavia.\nIt is in turn succeded by the Serbian team.",
"formerly": "YUG",
"flag": "/9/90/Flag_of_Serbia_and_Montenegro.svg" },
{ "id": "SVK",
"name": "Slovakia",
"note": "Czechoslovakia was divided into Slovakia and the Czech Republic in 1993.",
"formerly": "TCH",
"flag": "/e/e6/Flag_of_Slovakia.svg" },
{ "id": "SVN",
"name": "Slovenia",
"note": "Slovenia became independent from Yugoslavia in 1992 and is considered\na distinct team by FIFA.",
"flag": "/f/f0/Flag_of_Slovenia.svg",
"formerly": "YUG" },
{ "id": "RSA",
"name": "South Africa",
"flag": "/a/af/Flag_of_South_Africa.svg" },
{ "id": "URS",
"name": "Soviet Union",
"note": "The Soviet Union was dissolved in 1991. FIFA considers Russian team the\nsuccessor team of USSR.",
"flag": "/a/a9/Flag_of_the_Soviet_Union.svg" },
{ "id": "ESP",
"name": "Spain",
"note": "Spain are the current world champions.",
"flag": "/9/9a/Flag_of_Spain.svg" },
{ "id": "SWE",
"name": "Sweden",
"flag": "/4/4c/Flag_of_Sweden.svg" },
{ "id": "SUI",
"name": "Switzerland",
"flag": "/f/f3/Flag_of_Switzerland.svg" },
{ "id": "TOG",
"name": "Togo",
"flag": "/6/68/Flag_of_Togo.svg" },
{ "id": "TRI",
"name": "Trinidad and Tobago",
"flag": "/6/64/Flag_of_Trinidad_and_Tobago.svg" },
{ "id": "TUN",
"name": "Tunisia",
"flag": "/c/ce/Flag_of_Tunisia.svg" },
{ "id": "TUR",
"name": "Turkey",
"flag": "/b/b4/Flag_of_Turkey.svg" },
{ "id": "UKR",
"name": "Ukraine",
"note": "FIFA considers Russian team the successor team of USSR.",
"formerly": "URS",
"flag": "/4/49/Flag_of_Ukraine.svg" },
{ "id": "UAE",
"name": "United Arab Emirates",
"flag": "/c/cb/Flag_of_the_United_Arab_Emirates.svg" },
{ "id": "USA",
"name": "United States",
"flag": "/a/a4/Flag_of_the_United_States.svg" },
{ "id": "URU",
"name": "Uruguay",
"flag": "/f/fe/Flag_of_Uruguay.svg" },
{ "id": "WAL",
"name": "Wales",
"flag": "/5/59/Flag_of_Wales_2.svg" },
{ "id": "FRG",
"name": "West Germany",
"note": "FIFA attributes results of the West Germany team to current day Germany.",
"formerly": "GER",
"flag": "/b/ba/Flag_of_Germany.svg" },
{ "id": "YUG",
"name": "Yugoslavia",
"note": "Yugoslavia was formally dissolved in 1992. FIFA considers the Serbia and\nMontenegro team, and subsequenty the Serbian team the current successor.",
"flag": "/7/71/Flag_of_SFR_Yugoslavia.svg" },
{ "id": "ZAI",
"name": "Zaire",
"note": "Zaire became The Democratic Republic of Congo on 1997.",
"flag": "/5/5c/Flag_of_Zaire.svg" },
{ "id": "???",
"name": "???"
}
]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment