Published
Edited
Aug 15, 2019
Insert cell
Insert cell
html`<svg width="120" height="120">
<rect class="box" x="10" y="10" width="100" height="100" fill="cornflowerblue">
<animate
attributeName="x"
values="0;20;0"
dur="2s"
repeatCount="indefinite"
/>
<animate
attributeName="fill"
values="cornflowerBlue;maroon;cornflowerBlue"
dur="6s"
repeatCount="indefinite"
/>
</rect>
</svg>`
Insert cell
html`<div class="box"></div>`
Insert cell
html`<style>
.box {
background: cornflowerblue;
height: 100px;
width: 100px;
transition-duration: 1s;
transition-property: transform;
}

.box:hover {
background: yellowgreen;
transform: translateX(30px);
}

</style>`
Insert cell
Insert cell
Insert cell
d3 = require("d3@5")
Insert cell
dataset = await d3.json("https://gist.githubusercontent.com/chekos/7ee802ef53ba4bbd10a3b8161116d638/raw/e0d655473a57fae5ba54e648429bfd01ca698e12/tijuana_weather_data.json")
Insert cell
histograma = metric => {
// Accessors
const metricAccessor = d=> d[metric]
const yAccessor = d => d.length
// dimensiones
const height = width * 0.50
const dimensions = ({
width: width,
height: height,
margin: ({
top: 30,
right: 20,
bottom: 50,
left: 20
})
})
dimensions.boundedHeight = dimensions.height - dimensions.margin.top - dimensions.margin.bottom
dimensions.boundedWidth = dimensions.width - dimensions.margin.left - dimensions.margin.right
// Escalas
const xScale = d3.scaleLinear()
.domain(d3.extent(dataset, metricAccessor))
.range([0, dimensions.boundedWidth])
.nice()
// bins
const binsGenerator = d3.histogram()
.domain(xScale.domain())
.value(metricAccessor)
.thresholds(12)
const bins = binsGenerator(dataset)
// tenemos que hacer `bins` antes de la escala Y
const yScale = d3.scaleLinear()
.domain([0, d3.max(bins, yAccessor)])
.range([dimensions.boundedHeight, 0])
.nice()

// detalles
const barPadding = 1
const mean = d3.mean(dataset, metricAccessor)
const exitTransition = d3.transition().duration(600)
const updateTransition = exitTransition.transition().duration(600)
// viz
const wrapper = d3.select(DOM.svg(width,height))
// donde ponemos la grafica
const bounds = wrapper.append("g")
.style("transform", `translate(${dimensions.margin.left}px, ${dimensions.margin.top}px)`)
// agregamos figuras
const binGroup = bounds.append("g")
let binGroups = binGroup.selectAll("g")
.data(bins)
const oldBinGroups = binGroups.exit()
oldBinGroups.selectAll("rect")
.style("fill", "red")
.transition(exitTransition)
.attr("y", dimensions.boundedHeight)
.attr("height", 0)
oldBinGroups.selectAll("text")
.transition(exitTransition)
.attr("y", dimensions.boundedHeight)
oldBinGroups.transition(exitTransition).remove()
const newBinGroups = binGroups.enter().append("g")
newBinGroups.append("rect")
.attr("height", 0)
.attr("x", d => xScale(d.x0) + barPadding)
.attr("y", dimensions.boundedHeight)
.attr("width", d => d3.max([0, xScale(d.x1) - xScale(d.x0) - barPadding]))
.style("fill", "yellowgreen")
newBinGroups.append("text")
.attr("x", d => xScale(d.x0) + (xScale(d.x1) - xScale(d.x0)) / 2)
.attr("y", dimensions.boundedHeight)
// update
binGroups = newBinGroups.merge(binGroups)

// rectangulos
const barRects = binGroups.append("rect")
.transition(updateTransition)
.attr("x", d => xScale(d.x0) + barPadding / 2)
.attr("y", d => yScale(yAccessor(d)))
.attr("width", d => d3.max([0, xScale(d.x1) - xScale(d.x0) - barPadding]))
.attr("height", d => dimensions.boundedHeight - yScale(yAccessor(d)))
.transition()
.attr("fill", "#19267C")

// etiquetas
const barText = binGroups.select("text")
.transition(updateTransition)
.attr("x", d => xScale(d.x0) + (xScale(d.x1) - xScale(d.x0)) / 2)
.attr("y", d => yScale(yAccessor(d)) - 5)
.text(d => yAccessor(d) || "")
.style("text-anchor", "middle")
.attr("fill", "darkgrey")
.attr("font-size", "12px")
.attr("font-family", "sans-serif")
// promedio
const meanLine = bounds.append("line")
.transition(updateTransition)
.attr("x1", xScale(mean))
.attr("x2", xScale(mean))
.attr("y1", -15)
.attr("y2", dimensions.boundedHeight)
.attr("stroke", "maroon")
.attr("stroke-dasharray", "2px 4px")
const meanLabel = bounds.append("text")
.attr("x", xScale(mean) + 3)
.attr("y", -1)
.text("promedio")
.attr("fill", "maroon")
.style("font-size", "12px")
.style("text-anchor", "left")
// Ejes
const xAxisGenerator = d3.axisBottom()
.scale(xScale)
const xAxis = bounds.append("g")
// .transition(updateTransition)
.call(xAxisGenerator)
.style("transform", `translate(0,${dimensions.boundedHeight}px)`)
const xAxisLabel = xAxis.append("text")
.attr("x", dimensions.boundedWidth / 2)
.attr("y", dimensions.margin.bottom - 10)
.attr("fill", "black")
.attr("font-size", "1.4em")
.text(`${metric}`)
.style("text-transform", "capitalize")
return wrapper.node()
}
Insert cell
histograma("humidity")
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