Public
Edited
Sep 7, 2023
Insert cell
Insert cell
irisURL = "https://raw.githubusercontent.com/plotly/datasets/master/iris-id.csv"
Insert cell
// iris data set
irisData = d3.csv(irisURL)
Insert cell
Insert cell
{
// dimensions and set up

const margin = {top: 40, right: 40, bottom: 40, left: 90};

const visWidth = 500;
const visHeight = 500;
const svg = d3.create('svg')
.attr('width', visWidth + margin.left + margin.right)
.attr('height', visHeight + margin.top + margin.bottom);

const g = svg.append('g')
.attr('transform', `translate(${margin.left},${margin.top})`)
.attr('font-family', 'sans-serif');

// title

g.append('text')
.attr('x', visWidth / 2)
.attr('y', -10)
.attr('font-size', 14)
.attr('text-anchor', 'middle')
.text('sepal length vs sepal width')

// scales

const x = d3.scaleLinear()
.domain(d3.extent(irisData, d => d.sepal_length))
.range([0, visWidth]);

const y = d3.scaleLinear()
.domain(d3.extent(irisData, d => d.sepal_width))
.range([visHeight, 0]);


// axis generators

const xAxis = d3.axisBottom(x);
const yAxis = d3.axisLeft(y);

// draw axes and grid

// x-axis and vertical grid lines

g.append('g')
.attr('transform', `translate(0,${visHeight})`)
.call(xAxis)
.call(
// add grid lines
g => g.selectAll('.tick line').clone()
.attr('y1', 0)
.attr('y2', -visHeight)
.attr('stroke', 'gray')
.attr('stroke-width', 1)
)
.call(g => g.select('.domain').remove())
.append('text')
.attr('x', visWidth / 2)
.attr('y', 30)
.attr('fill', 'black')
.attr('text-anchor', 'center')
.text('sepal length');

// y-axis and horizontal grid lines
g.append('g')
.call(yAxis)
.call(
// add grid lines
g => g.selectAll('.tick line').clone()
.attr('x1', 0)
.attr('x2', visWidth)
.attr('stroke', 'gray')
.attr('stroke-width', 1)
)
.call(g => g.select('.domain').remove())
.append('text')
.attr('x', -35)
.attr('y', visHeight / 2)
.attr('fill', 'black')
.attr('dominant-baseline', 'center')
.attr('text-anchor', 'end')
.text('sepal width');

// draw circles
const colors = ["#1b9e77", "#d95f02", "#7570b3"]
const radius = d3.scaleLinear()
.domain(d3.extent(irisData, d => d.petal_length))
.range([3, 15]);
const opacity = d3.scaleLinear()
.domain(d3.extent(irisData, d => d.petal_width))
.range([0.2, 1]);

g.selectAll('circle')
.data(irisData)
.join('circle')
.attr('cx', d => x(d.sepal_length))
.attr('cy', d => y(d.sepal_width))
.attr('r', d => radius(d.petal_length))
.attr('fill', d => colors[d.species_id - 1])
.attr('fill-opacity', d => opacity(d.petal_width));

return svg.node();
}
Insert cell
Insert cell
{
// dimensions and set up

const margin = {top: 40, right: 40, bottom: 40, left: 90};

const visWidth = 500;
const visHeight = 500;
const svg = d3.create('svg')
.attr('width', visWidth + margin.left + margin.right)
.attr('height', visHeight + margin.top + margin.bottom);

const g = svg.append('g')
.attr('transform', `translate(${margin.left},${margin.top})`)
.attr('font-family', 'sans-serif');

// title

g.append('text')
.attr('x', visWidth / 2)
.attr('y', -10)
.attr('font-size', 14)
.attr('text-anchor', 'middle')
.text('sepal length vs sepal width')

// scales

const x = d3.scaleLinear()
.domain(d3.extent(irisData, d => d.sepal_length))
.range([0, visWidth]);

const y = d3.scaleLinear()
.domain(d3.extent(irisData, d => d.sepal_width))
.range([visHeight, 0]);


// axis generators

const xAxis = d3.axisBottom(x);
const yAxis = d3.axisLeft(y);

// draw axes and grid

// x-axis and vertical grid lines

g.append('g')
.attr('transform', `translate(0,${visHeight})`)
.call(xAxis)
.call(
// add grid lines
g => g.selectAll('.tick line').clone()
.attr('y1', 0)
.attr('y2', -visHeight)
.attr('stroke', 'gray')
.attr('stroke-width', 1)
)
.call(g => g.select('.domain').remove())
.append('text')
.attr('x', visWidth / 2)
.attr('y', 30)
.attr('fill', 'black')
.attr('text-anchor', 'center')
.text('sepal length');

// y-axis and horizontal grid lines
g.append('g')
.call(yAxis)
.call(
// add grid lines
g => g.selectAll('.tick line').clone()
.attr('x1', 0)
.attr('x2', visWidth)
.attr('stroke', 'gray')
.attr('stroke-width', 1)
)
.call(g => g.select('.domain').remove())
.append('text')
.attr('x', -35)
.attr('y', visHeight / 2)
.attr('fill', 'black')
.attr('dominant-baseline', 'center')
.attr('text-anchor', 'end')
.text('sepal width');

// draw ellipse
const ellipse_height = d3.scaleLinear()
.domain(d3.extent(irisData, d => d.petal_width))
.range([1, 20]);
const ellipse_width = d3.scaleLinear()
.domain(d3.extent(irisData, d => d.petal_length))
.range([1, 20]);

g.selectAll('ellipse')
.data(irisData)
.join('ellipse')
.attr('cx', d => x(d.sepal_length))
.attr('cy', d => y(d.sepal_width))
.attr('rx', d => ellipse_width(d.petal_length))
.attr('ry', d => ellipse_height(d.petal_width))
.attr('fill', "#7570b3")
.attr('opacity', 0.5);

return svg.node();
}
Insert cell
Insert cell
{
// dimensions and set up

const margin = {top: 40, right: 40, bottom: 40, left: 90};

const visWidth = 500;
const visHeight = 500;
const svg = d3.create('svg')
.attr('width', visWidth + margin.left + margin.right)
.attr('height', visHeight + margin.top + margin.bottom);

const g = svg.append('g')
.attr('transform', `translate(${margin.left},${margin.top})`)
.attr('font-family', 'sans-serif');

// title

g.append('text')
.attr('x', visWidth / 2)
.attr('y', -10)
.attr('font-size', 14)
.attr('text-anchor', 'middle')
.text('sepal length vs sepal width')

// scales

const x = d3.scaleLinear()
.domain(d3.extent(irisData, d => d.sepal_length))
.range([0, visWidth]);

const y = d3.scaleLinear()
.domain(d3.extent(irisData, d => d.sepal_width))
.range([visHeight, 0]);


// axis generators

const xAxis = d3.axisBottom(x);
const yAxis = d3.axisLeft(y);

// draw axes and grid

// x-axis and vertical grid lines

g.append('g')
.attr('transform', `translate(0,${visHeight})`)
.call(xAxis)
.call(
// add grid lines
g => g.selectAll('.tick line').clone()
.attr('y1', 0)
.attr('y2', -visHeight)
.attr('stroke', 'gray')
.attr('stroke-width', 1)
)
.call(g => g.select('.domain').remove())
.append('text')
.attr('x', visWidth / 2)
.attr('y', 30)
.attr('fill', 'black')
.attr('text-anchor', 'center')
.text('sepal length');

// y-axis and horizontal grid lines
g.append('g')
.call(yAxis)
.call(
// add grid lines
g => g.selectAll('.tick line').clone()
.attr('x1', 0)
.attr('x2', visWidth)
.attr('stroke', 'gray')
.attr('stroke-width', 1)
)
.call(g => g.select('.domain').remove())
.append('text')
.attr('x', -35)
.attr('y', visHeight / 2)
.attr('fill', 'black')
.attr('dominant-baseline', 'center')
.attr('text-anchor', 'end')
.text('sepal width');

// draw circle
const color = d3.scaleSequential()
.domain(d3.extent(irisData, d => d.petal_length))
.interpolator(d3.interpolateReds);

g.selectAll('circle')
.data(irisData)
.join('circle')
.attr('cx', d => x(d.sepal_length))
.attr('cy', d => y(d.sepal_width))
.attr('r', 5)
.attr('fill', d => color(d.petal_length));

return svg.node();
}
Insert cell
Insert cell
viewof type = Inputs.radio(["sepal", "petal"], {label: "Plot Type"})
Insert cell
reactivechart = {
// dimensions and set up

const margin = {top: 40, right: 40, bottom: 40, left: 90};

const visWidth = 500;
const visHeight = 500;
const svg = d3.create('svg')
.attr('width', visWidth + margin.left + margin.right)
.attr('height', visHeight + margin.top + margin.bottom);

const g = svg.append('g')
.attr('transform', `translate(${margin.left},${margin.top})`)
.attr('font-family', 'sans-serif');

svg.node().drawData = function(input_state) {
g.append('text')
.attr("class", "title")
// scales
const x = d3.scaleLinear()
.domain(d3.extent(irisData, d => d[input_state + "_length"]))
.range([0, visWidth]);
const y = d3.scaleLinear()
.domain(d3.extent(irisData, d => d[input_state + "_width"]))
.range([visHeight, 0]);


// axis generators
const xAxis = d3.axisBottom(x);
const yAxis = d3.axisLeft(y);

// draw axes and grid
// x-axis and vertical grid lines
g.append('g')
.attr('transform', `translate(0,${visHeight})`)
.attr("class", "xAxis")
.append("text")
.attr("class", "xtext")
// y-axis and horizontal grid lines
g.append('g')
.attr("class", "yAxis")
.append("text")
.attr("class", "ytext")

g.selectAll('circle')
.data(irisData)
.join(enter => enterFunc(enter),
update => updateFunc(update),
exit => exitFunc(exit))


function enterFunc(enterSel){
enterSel.append('circle')
.transition().duration(1000)
.attr('cx', d => x(d[input_state + "_length"]))
.attr('cy', d => y(d[input_state + "_width"]))
.attr('r', 5)
.attr('fill', "red");
}

function updateFunc(toUpdate) {
g.select('.title')
.attr('x', visWidth / 2)
.attr('y', -10)
.attr('font-size', 14)
.attr('text-anchor', 'middle')
.text(input_state + ' length vs ' + input_state + ' width')
g.select('.xAxis')
.call(xAxis)
.call(
// add grid lines
g => g.selectAll('.tick line').clone()
.attr('y1', 0)
.attr('y2', -visHeight)
.attr('stroke', 'gray')
.attr('stroke-width', 1)
)
.call(g => g.select('.domain').remove())
.select('.xtext')
.attr('x', visWidth / 2)
.attr('y', 30)
.attr('fill', 'black')
.attr('text-anchor', 'center')
.text(input_state + ' length');
// y-axis and horizontal grid lines
g.select('.yAxis')
.call(yAxis)
.call(
// add grid lines
g => g.selectAll('.tick line').clone()
.attr('x1', 0)
.attr('x2', visWidth)
.attr('stroke', 'gray')
.attr('stroke-width', 1)
)
.call(g => g.select('.domain').remove())
.select('.ytext')
.attr('x', -35)
.attr('y', visHeight / 2)
.attr('fill', 'black')
.attr('dominant-baseline', 'center')
.attr('text-anchor', 'end')
.text(input_state + ' width');
toUpdate.transition().duration(1000)
.attr('cx', d => x(d[input_state + "_length"]))
.attr('cy', d => y(d[input_state + "_width"]))
}
function exitFunc(dissapearingEls){
dissapearingEls
.transition().duration(1000)
.style("opacity", 0)
.remove()
}
}
return svg.node();
}
Insert cell
reactivechart.drawData(type)
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more