d3-scale#scaleBand JavaScript Examples
The following examples show how to use
d3-scale#scaleBand.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: horizontal-bar-chart.js From website with Apache License 2.0 | 5 votes |
HorizontalBarChart = ({
data,
fill,
height,
marginBottom = 0,
marginLeft = 0,
marginRight = 0,
marginTop = 0,
xTicks,
width,
xMax = null,
}) => {
const totalXMargin = marginLeft + marginRight
const totalYMargin = marginTop + marginBottom
const yScale = scaleBand()
.domain(data.map(d => d.name))
.range([0, height - totalYMargin])
.padding(0.2)
const formatTick = format('~s')
const xScale = scaleLinear()
.domain([120, xMax || max(data, d => d.value)])
.nice()
.range([0, width - totalXMargin])
return (
<svg
className={chartStyles.chart}
viewBox={`0 0 ${width} ${height}`}
aria-hidden
>
<g transform={`translate(${marginLeft} ${marginTop})`}>
{xScale.ticks(xTicks).map(tick => (
<g key={tick}>
<text
className={`${chartStyles.label} ${chartStyles.xTickLabel}`}
x={xScale(tick)}
y={height - marginBottom}
>
{formatTick(tick)}
</text>
<line
className={chartStyles.gridLine}
x1={xScale(tick)}
x2={xScale(tick)}
y1={0}
y2={height - totalYMargin}
/>
</g>
))}
</g>
<g transform={`translate(0, ${marginTop})`}>
{data.map(d => (
/* Do not remove nested svg. See https://github.com/COVID19Tracking/website/pull/645#discussion_r411676987 */
<svg
y={yScale(d.name) + 20}
x={marginLeft - 10}
className={chartStyles.yTickLabel}
key={d.name}
>
<text className={chartStyles.label}>{`${d.name}`}</text>
</svg>
))}
</g>
<g transform={`translate(${marginLeft}, ${marginTop})`}>
{data.map(d => (
<rect
key={d.name}
x={0}
y={yScale(d.name)}
height={yScale.bandwidth()}
width={xScale(d.value)}
fill={fill}
/>
))}
</g>
</svg>
)
}
Example #2
Source File: node-networks-overlay.js From ThreatMapper with Apache License 2.0 | 5 votes |
x = scaleBand()
Example #3
Source File: bar-chart.js From website with Apache License 2.0 | 4 votes |
BarChart = ({
data,
lineData,
refLineData,
annotations,
handleAnnotationClick,
fill,
lineColor,
marginBottom,
marginLeft,
marginRight,
marginTop,
showTicks,
width,
height,
yMax,
yTicks,
lastXTick,
renderTooltipContents,
perCapLabel,
}) => {
const chartRef = useRef()
const [tooltip, setTooltip] = useState(null)
// Used for tooltip optimization
const [timeoutRef, setTimeoutRef] = useState(null)
const [keyboardFocus, setKeyboardFocus] = useState(false)
// Used when placing annotations
const getValueForDate = date => {
const dateData = data.find(d => d.date.getTime() === date.getTime())
return dateData && dateData.value
}
const totalXMargin = marginLeft + marginRight
const totalYMargin = marginTop + marginBottom
// The x range is over the area in which the chart should be displaying.
// We don't use an X transform to place it in the correct spot, we use range
// instead
const xScale = scaleBand()
.domain(data.map(d => d.date))
.range([marginLeft, width - marginRight])
.padding(0.1)
const dateDomain = extent(data, d => d.date)
// Should probably refactor to use a single x-axis scale
// but the bars make use of the band.
const xScaleTime = scaleTime()
.domain(dateDomain)
.range([marginLeft, width - marginRight])
const yMaxEffective =
yMax || max([...data, ...(refLineData || [])], d => d.value)
const yScale = scaleLinear()
.domain([0, yMaxEffective])
.nice()
.range([height - totalYMargin, 0])
const msInOneMonth = 2628000000
const monthlyTickInterval = Math.ceil(
Math.abs((dateDomain[1] - dateDomain[0]) / (msInOneMonth * 6)),
)
const xTickAmount = timeMonth.every(monthlyTickInterval)
const yTicksThreshold = 4
const yTicksEffective =
yTicks || yMaxEffective < yTicksThreshold ? yMaxEffective : yTicksThreshold
const lastTime = xScaleTime.ticks(timeDay.every(1)).pop()
let lineFn = null
if (lineData) {
lineFn = line()
.defined(d => !Number.isNaN(d.value) && d.value !== null)
.curve(curveCardinal)
.x(d => xScaleTime(d.date))
.y(d => yScale(d.value))
}
const hover = (event, d) => {
// Ensure that tooltip doesn't flash when transitioning between bars
if (timeoutRef) {
clearTimeout(timeoutRef)
}
const isTouchEvent = !event.clientX
const eventX = isTouchEvent ? event.touches[0].clientX : event.clientX
const eventY = isTouchEvent ? event.touches[0].clientY : event.clientY
setTooltip({
top: isTouchEvent ? eventY - 130 : eventY + 10,
left: isTouchEvent ? eventX - 80 : eventX + 5,
d,
})
}
const mouseOut = () => {
if (timeoutRef) {
clearTimeout(timeoutRef)
}
setTimeoutRef(setTimeout(() => setTooltip(null), 200))
}
useEffect(() => {
if (keyboardFocus === false || typeof data[keyboardFocus] === 'undefined') {
return
}
const column = data[keyboardFocus]
setTooltip({
top: chartRef.current.getBoundingClientRect().top,
left: chartRef.current.getBoundingClientRect().left,
d: column,
})
}, [keyboardFocus])
return (
<>
<svg
className={classnames(chartStyles.chart, styles.chart)}
viewBox={`0 0 ${width} ${height}`}
tabIndex="0"
aria-hidden
ref={chartRef}
onBlur={() => {
setTooltip(null)
setKeyboardFocus(false)
}}
onKeyDown={event => {
if (event.key === 'Escape') {
setTooltip(null)
setKeyboardFocus(false)
chartRef.current.blur()
}
if (event.key === 'ArrowRight') {
setKeyboardFocus(
keyboardFocus < data.length ? keyboardFocus + 1 : data.length,
)
}
if (
(event.shiftKey && event.key === 'Tab') ||
event.key === 'ArrowLeft'
) {
setKeyboardFocus(keyboardFocus > 0 ? keyboardFocus - 1 : 0)
}
}}
>
<g transform={`translate(${marginLeft} ${marginTop})`}>
<text className={classnames(chartStyles.label, styles.directions)}>
Use arrows to move, Escape to leave.
</text>
</g>
{/* y ticks */}
<g transform={`translate(${marginLeft} ${marginTop})`}>
{yScale.ticks(yTicksEffective).map(
(tick, i) =>
i < showTicks && (
<g key={tick}>
{/* Do not remove nested svg. See https://github.com/COVID19Tracking/website/pull/645#discussion_r411676987 */}
<svg
y={yScale(tick) + 6}
x="-10"
className={chartStyles.yTickLabel}
>
<text className={chartStyles.label}>
{formatNumber(tick)}
{tick > 0 &&
perCapLabel /* this only displays if passed */}
</text>
</svg>
<line
className={chartStyles.gridLine}
x1={0}
x2={width - totalXMargin}
y1={yScale(tick)}
y2={yScale(tick)}
/>
</g>
),
)}
</g>
{/* x ticks (dates) */}
<g transform={`translate(0, ${height - marginBottom})`}>
{xScaleTime.ticks(xTickAmount).map(d => (
<Fragment key={`x-${d}`}>
<text
className={`${chartStyles.label} ${chartStyles.xTickLabel}`}
key={d}
x={xScaleTime(d)}
y="20"
>{`${formatDate(d)}`}</text>
<line
className={chartStyles.label}
stroke={colors.colorSlate500}
x1={xScaleTime(d)}
y1="0"
x2={xScaleTime(d)}
y2="5"
/>
</Fragment>
))}
{lastXTick && (
<>
<text
className={`${chartStyles.label} ${chartStyles.xTickLabel}`}
x={xScaleTime(lastTime)}
y="20"
>{`${formatDate(lastTime)}`}</text>
<line
className={chartStyles.label}
stroke={colors.colorSlate500}
x1={xScaleTime(lastTime)}
y1="0"
x2={xScaleTime(lastTime)}
y2="5"
/>
</>
)}
</g>
<mask id="dataMask">
<rect
x="0"
y="0"
width={width - marginRight}
height={height - totalYMargin}
fill="white"
/>
</mask>
{/* data */}
<g transform={`translate(0 ${marginTop})`} mask="url(#dataMask)">
{/* bars (data) */}
{data.map((d, key) => (
<rect
key={d.date + d.value}
x={xScale(d.date)}
y={yScale(d.value)}
height={yScale(0) - yScale(d.value)}
width={xScale.bandwidth()}
fillOpacity={lineData ? 1 : 0.8}
fill={fill}
className={classnames(
renderTooltipContents && styles.interactiveBar,
key === keyboardFocus && styles.selected,
)}
onMouseOver={event => hover(event, d)}
onFocus={event => hover(event, d)}
onMouseOut={mouseOut}
onBlur={mouseOut}
/>
))}
{/* line */}
{lineData && (
<path
d={lineFn(lineData)}
stroke={lineColor}
strokeWidth="3"
fill="none"
/>
)}
{/* reference line */}
{refLineData && (
<path
d={lineFn(refLineData)}
stroke="black"
strokeWidth="2"
strokeDasharray="4"
fill="none"
/>
)}
</g>
{/* annotations */}
{annotations && (
<g transform={`translate(0 ${marginTop})`}>
{annotations
.filter(
annotation =>
xScaleTime(annotation.date) >= xScaleTime(dateDomain[0]) &&
xScaleTime(annotation.date) <= xScaleTime(dateDomain[1]),
)
.map(d => (
<AnnotationBubble
content={d}
xScaleTime={xScaleTime}
yScale={yScale}
handleAnnotationClick={handleAnnotationClick}
getValueForDate={getValueForDate}
/>
))}
</g>
)}
</svg>
{renderTooltipContents && tooltip && (
<Tooltip {...tooltip}>{renderTooltipContents(tooltip.d)} </Tooltip>
)}
</>
)
}
Example #4
Source File: county-chart.js From website with Apache License 2.0 | 4 votes |
CountyChart = ({ data, field, label, increments }) => {
const height = 400
const width = 400
const labelOffset = 150
const heightOffset = 50
const yScale = scaleBand()
.domain(data.map((d, index) => index))
.range([0, height])
const xScale = scaleLinear()
.domain([0, max(data, d => d[field])])
.nice()
.range([0, width])
const verticalLines = []
for (let i = 0; i < max(data, d => d[field]); i += increments) {
verticalLines.push(i)
}
return (
<svg
className={countyChartStyles.chart}
viewBox={`0 0 ${width + labelOffset} ${height + heightOffset}`}
>
<g
transform={`translate(${labelOffset} ${heightOffset})`}
height={height - heightOffset}
width={width - labelOffset}
>
{data.map((d, index) => (
<rect
key={`${field}-${d.name}-${d.state}`}
x={0}
y={yScale(index)}
height={10}
width={xScale(d[field])}
className={`${countyChartStyles.bar} ${
countyChartStyles[groupClasses[d.demographics.largestRace1]]
}`}
fill="#000"
/>
))}
</g>
{verticalLines.map(tick => (
<g key={`${field}-${tick}`}>
<svg y={20} x={xScale(tick) + labelOffset} width={1}>
<line
x1="0"
y1="0"
x2="0"
y2={height + heightOffset}
className={countyChartStyles.verticalTick}
style={{ height }}
/>
</svg>
</g>
))}
<g transform="translate(0, 15)">
<svg
y={0}
x={labelOffset}
width={labelOffset}
className={countyChartStyles.tick}
>
<text className={countyChartStyles.label}>{label}</text>
</svg>
{xScale.ticks(3).map(
(tick, i) =>
i < 3 && (
<g key={`${field}-${tick}`}>
<svg
y={20}
x={xScale(tick) + labelOffset}
width={labelOffset}
className={countyChartStyles.tick}
>
<text
className={classnames(
countyChartStyles.label,
countyChartStyles.centered,
)}
>
{tick.toLocaleString()}
</text>
</svg>
</g>
),
)}
</g>
{data.map((d, index) => (
<g
key={`${d.field}-${d.county}`}
transform={`translate(0, ${heightOffset})`}
>
<svg
y={yScale(index) + 10}
x={labelOffset - 10}
width={labelOffset}
className={countyChartStyles.countyLabel}
>
<text className={countyChartStyles.label}>
{d.name}, {d.demographics.abbreviation}
</text>
</svg>
</g>
))}
</svg>
)
}
Example #5
Source File: DeltaBarGraph.js From covid19india-react with MIT License | 4 votes |
function DeltaBarGraph({timeseries, statistic, lookback}) { const svgRef = useRef(); const [wrapperRef, {width, height}] = useMeasure(); const pastDates = Object.keys(timeseries || {}).filter( (date) => date <= getIndiaDateYesterdayISO() ); const dates = pastDates.slice(-lookback); const getDeltaStatistic = useCallback( (date, statistic) => { return getStatistic(timeseries?.[date], 'delta', statistic); }, [timeseries] ); useEffect(() => { if (!width) return; const svg = select(svgRef.current); const chartRight = width - margin.right; const chartBottom = height - margin.bottom; const r = 5; // const formatTime = timeFormat('%e %b'); const xScale = scaleBand() .domain(dates) .range([margin.left, chartRight]) .paddingInner(width / 1000); const [statisticMin, statisticMax] = extent(dates, (date) => getDeltaStatistic(date, statistic) ); const yScale = scaleLinear() .domain([Math.min(0, statisticMin || 0), Math.max(1, statisticMax || 0)]) .range([chartBottom, margin.top]); const xAxis = axisBottom(xScale) .tickSize(0) .tickFormat((date) => formatDate(date, 'dd MMM')); const t = svg.transition().duration(D3_TRANSITION_DURATION); const statisticConfig = STATISTIC_CONFIGS[statistic]; svg .select('.x-axis') .transition(t) .style('transform', `translate3d(0, ${yScale(0)}px, 0)`) .call(xAxis) .on('start', () => svg.select('.domain').remove()) .selectAll('text') .attr('y', 0) .attr('dy', (date, i) => getDeltaStatistic(date, statistic) < 0 ? '-1em' : '1.5em' ) .style('text-anchor', 'middle') .attr('fill', statisticConfig.color); svg .selectAll('.bar') .data(dates) .join((enter) => enter .append('path') .attr('class', 'bar') .attr('d', (date) => roundedBar(xScale(date), yScale(0), xScale.bandwidth(), 0, r) ) ) .transition(t) .attr('d', (date) => roundedBar( xScale(date), yScale(0), xScale.bandwidth(), yScale(0) - yScale(getDeltaStatistic(date, statistic)), r ) ) .attr('fill', (date, i) => { return i < dates.length - 1 ? statisticConfig.color + '90' : statisticConfig.color; }); const textSelection = svg .selectAll('.label') .data(dates) .join('text') .attr('class', 'label') .attr('x', (date) => xScale(date) + xScale.bandwidth() / 2) .text((date) => formatNumber( getDeltaStatistic(date, statistic), statisticConfig?.showDelta || statisticConfig?.nonLinear ? statisticConfig.format : 'short' ) ); textSelection .transition(t) .attr('fill', statisticConfig.color) .attr('y', (date) => { const val = getDeltaStatistic(date, statistic); return yScale(val) + (val < 0 ? 15 : -6); }); textSelection .append('tspan') .attr( 'dy', (date) => `${getDeltaStatistic(date, statistic) < 0 ? 1.2 : -1.2}em` ) .attr('x', (date) => xScale(date) + xScale.bandwidth() / 2) .text((date, i) => { if (i === 0) return ''; const prevVal = getDeltaStatistic(dates[i - 1], statistic); if (!prevVal) return ''; const delta = getDeltaStatistic(date, statistic) - prevVal; return `${delta > 0 ? '+' : ''}${formatNumber( (100 * delta) / Math.abs(prevVal), '%' )}`; }) .transition(t) .attr('fill', statisticConfig.color + '90'); }, [dates, height, statistic, width, getDeltaStatistic]); return ( <div className="DeltaBarGraph" ref={wrapperRef}> <svg ref={svgRef} width={width} height={250} viewBox={`0 0 ${width} ${height}`} preserveAspectRatio="xMidYMid meet" > <g className="x-axis" /> <g className="y-axis" /> </svg> </div> ); }
Example #6
Source File: MapLegend.js From covid19india-react with MIT License | 4 votes |
function legend({
svg,
color,
title,
tickSize = 6,
width = 320,
height = 44 + tickSize,
marginTop = 18,
marginRight = 0,
marginBottom = 16 + tickSize,
marginLeft = 0,
ticks = width / 64,
tickFormat,
tickValues,
ordinalWeights,
} = {}) {
const t = svg.transition().duration(D3_TRANSITION_DURATION);
let tickAdjust = (g) => {
const ticks = g.selectAll('.tick line');
ticks.attr('y1', marginTop + marginBottom - height);
// select(ticks.nodes()[ticks.size() - 1]).remove();
};
let x;
// Continuous
if (color.interpolate) {
const n = Math.min(color.domain().length, color.range().length);
x = color
.copy()
.rangeRound(quantize(interpolate(marginLeft, width - marginRight), n));
svg
.select('.ramp')
.attr('x', marginLeft)
.attr('y', marginTop)
.attr('width', width - marginLeft - marginRight)
.attr('height', height - marginTop - marginBottom)
.attr(
'xlink:href',
ramp(color.copy().domain(quantize(interpolate(0, 1), n))).toDataURL()
);
}
// Sequential
else if (color.interpolator) {
svg
.select('.bars')
.selectAll('rect')
.transition(t)
.attr('opacity', 0)
.remove();
x = Object.assign(
color
.copy()
.interpolator(interpolateRound(marginLeft, width - marginRight)),
{
range() {
return [marginLeft, width - marginRight];
},
}
);
svg
.select('.ramp')
.attr('x', marginLeft)
.attr('y', marginTop)
.attr('width', width - marginLeft - marginRight)
.attr('height', height - marginTop - marginBottom)
.attr('xlink:href', ramp(color.interpolator()).toDataURL())
.attr('display', 'visible')
.transition(t)
.attr('opacity', 1);
// scaleSequentialQuantile doesn’t implement ticks or tickFormat.
if (!x.ticks) {
if (tickValues === undefined) {
const n = Math.round(ticks + 1);
tickValues = range(n).map((i) => quantile(color.domain(), i / (n - 1)));
}
if (typeof tickFormat !== 'function') {
tickFormat = format(tickFormat === undefined ? ',f' : tickFormat);
}
}
}
// Threshold
else if (color.invertExtent) {
const thresholds = color.thresholds
? color.thresholds() // scaleQuantize
: color.quantiles
? color.quantiles() // scaleQuantile
: color.domain(); // scaleThreshold
const thresholdFormat =
tickFormat === undefined
? (d) => d
: typeof tickFormat === 'string'
? format(tickFormat)
: tickFormat;
x = scaleLinear()
.domain([-1, color.range().length - 1])
.rangeRound([marginLeft, width - marginRight]);
svg
.append('g')
.selectAll('rect')
.data(color.range())
.join('rect')
.attr('x', (d, i) => x(i - 1))
.attr('y', marginTop)
.attr('width', (d, i) => x(i) - x(i - 1))
.attr('height', height - marginTop - marginBottom)
.attr('fill', (d) => d);
tickValues = range(-1, thresholds.length);
tickFormat = (i) => {
if (i === -1) return thresholdFormat(1);
else if (i === thresholds.length - 1) return;
else if (i === thresholds.length - 2)
return thresholdFormat(thresholds[i] + '+', i);
return thresholdFormat(thresholds[i], i);
};
}
// Ordinal
else {
svg
.select('.ramp')
.transition(t)
.attr('opacity', 0)
.attr('xlink:href', null);
if (!ordinalWeights) {
x = scaleBand()
.domain(color.domain().filter((d) => d))
.rangeRound([marginLeft, width - marginRight]);
svg
.select('.bars')
.selectAll('rect')
.data(color.domain().filter((d) => d))
.join('rect')
.attr('x', x)
.attr('y', marginTop)
.attr('width', Math.max(0, x.bandwidth() - 1))
.attr('height', height - marginTop - marginBottom)
.attr('fill', color);
} else {
const widthScale = scaleLinear()
.domain([0, ordinalWeights.reduce((a, b) => a + b)])
.rangeRound([0, width - marginLeft - marginRight]);
const xPos = ordinalWeights.map((w, i) =>
ordinalWeights
.slice(0, i)
.reduce((acc, w) => acc + widthScale(w), marginLeft)
);
x = scaleOrdinal().domain(color.domain()).range(xPos);
svg
.select('.bars')
.selectAll('rect')
.data(color.domain())
.join((enter) =>
enter
.append('rect')
.attr('x', x)
.attr('width', (d, i) => widthScale(ordinalWeights[i]))
)
.attr('y', marginTop)
.attr('height', height - marginTop - marginBottom)
.attr('fill', color)
.transition(t)
.attr('x', x)
.attr('width', (d, i) => widthScale(ordinalWeights[i]))
.attr('opacity', 1);
}
tickAdjust = () => {};
}
svg
.select('.axis')
.attr('transform', `translate(0,${height - marginBottom})`)
.transition(t)
.attr('class', 'axis')
.call(
axisBottom(x)
.ticks(ticks, typeof tickFormat === 'string' ? tickFormat : undefined)
.tickFormat(typeof tickFormat === 'function' ? tickFormat : undefined)
.tickSize(tickSize)
.tickValues(tickValues)
)
.on('start', () => {
svg.call(tickAdjust).call((svg) => svg.select('.domain').remove());
})
.call((g) =>
g
.select('.axistext')
.attr('class', 'axistext')
.attr('x', marginLeft)
.attr('y', marginTop + marginBottom - height - 6)
.attr('fill', 'currentColor')
.attr('text-anchor', 'start')
.attr('font-weight', 'bold')
.text(title)
);
return svg.node();
}