Published
Edited
Nov 22, 2019
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
speciesResponse = d3.json('https://rest.ensembl.org/info/species?content-type=application/json')
Insert cell
Insert cell
species = speciesResponse.species.map(d => ({
id: d.name,
name: d.display_name,
taxonomyId: d.taxon_id
}));
Insert cell
Insert cell
table(species, {
sortable: true,
paged: 10,
columns: {
id: { title: 'Species ID' },
name: { title: 'Name' },
taxonomyId: { title: 'Taxonomy ID' },
}
})
Insert cell
Insert cell
Insert cell
speciesFiltered = species.filter(d => d.name.toLowerCase().includes(search))
Insert cell
Insert cell
Insert cell
Insert cell
selectedSpecies = d3.json(`https://rest.ensembl.org/info/assembly/${selectedSpeciesId}?content-type=application/json`)
Insert cell
Insert cell
chromosomes = selectedSpecies.top_level_region.filter(d => d.coord_system === 'chromosome')
Insert cell
Insert cell
Insert cell
chromosomesSortByComparator = {
switch (chromosomesSortBy) {
case 'name':
return (a, b) => d3.ascending(
chromosomesOrderByName.indexOf(a.name),
chromosomesOrderByName.indexOf(b.name)
);
case 'length':
default:
return (a, b) => d3.descending(a.length, b.length);
}
}
Insert cell
chromosomesSorted = chromosomes.sort(chromosomesSortByComparator)
Insert cell
Insert cell
Insert cell
Insert cell
x = d3.scaleBand()
.domain(chromosomesSorted.map(d => d.name))
.range([margin.left, width - margin.right])
.padding(0.1)
Insert cell
Insert cell
y = {
switch(chromosomesLengthScale) {
case 'log':
return d3.scaleLog()
.domain([1, d3.max(chromosomes, d => d.length)])
.range([height - margin.bottom, margin.top]);
case 'linear':
default:
return d3.scaleLinear()
.domain([0, d3.max(chromosomes, d => d.length)]).nice()
.range([height - margin.bottom, margin.top])
}
}
Insert cell
// g is an svg group element here, which d3.axisBottom fills with the axis content
xAxis = g => g
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(x)
.tickSizeOuter(0))
Insert cell
yAxis = g => g
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(y).tickSizeInner(-width).tickSizeOuter(0))
.call(g => g.selectAll(".tick line").attr('stroke', '#bbb'))
Insert cell
updateChart = {
// this cell is automatically run by observable when any of the cells
// that it depends on change, so it updates the chart as needed
// select the parent elements in the chart above and control their
// content programmatically using d3 methods
const gX = d3.select(chart).select('.x-axis')
const gY = d3.select(chart).select('.y-axis')
const gBars = d3.select(chart).select('.bars')
// bottom of the chart
const y0 = height - margin.bottom
// set up a transition to animate smoothly between states
const t = d3.transition().duration(2000)

// create the bars (each as a rect element) using d3 update pattern
const bars = gBars
.selectAll('rect')
.data(
chromosomesSorted,
d => d.name
)
.join(
enter => enter // new elements (on first render)
.append('rect')
.attr('x', d => x(d.name))
.attr('y', y0)
.attr('height', 0)
.attr('width', x.bandwidth())
.call(
// transitions are a complex topic, but you can read about them here:
// https://github.com/d3/d3-transition
enter => enter
.transition(t)
.attr('y', d => y(d.length))
.attr('height', d => y0 - y(d.length))
),
update => update // updating elements (on subsequent renders)
.call(
update => update
.transition(t)
.attr('x', d => x(d.name))
.attr('y', d => y(d.length))
.attr('height', d => y0 - y(d.length))
.attr('width', x.bandwidth())
),
exit => exit // removing elements (on subsequent renders)
.call(
exit => exit
.transition(t)
.attr('y', height - margin.bottom)
.attr('height', 0)
.remove()
)
);

// render the axes (d3 generates ticks and labels for you)
gX.transition(t).call(xAxis);
gY.transition(t).call(yAxis);
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
chart = {
// create a new svg element
const svg = d3.select(DOM.svg(width, height));
// append a group element inside the svg to contain the x axis
const gX = svg.append("g").classed('x-axis', true)
// append a group element inside the svg to contain the y axis
const gY = svg.append("g").classed('y-axis', true)
// append a group element inside the svg to contain the bars of the chart
// and set the fill attribute, which will be inherited by each bar
const gBars = svg
.append("g")
.classed('bars', true)
.attr("fill", "steelblue")

// return the chart (so that the cell renders it)
return svg.node();
}
Insert cell
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more