Radial Bar Chart
chartAlso known as: circular bar chart, radial column chart, polar bar chart
Description
A radial bar chart takes the familiar bar chart and wraps it around a central point, so bars extend outward like spokes of a wheel. Each bar occupies an equal angular slice and its length (radius) encodes the quantitative value. The result is a compact, visually distinctive display that can fit many categories into a roughly circular footprint.
The circular layout makes radial bar charts popular in dashboards, infographics, and data art, where visual impact and space efficiency are valued. The form also has a natural affinity with cyclical data: months of the year, hours of the day, or compass directions map naturally to angular positions around a circle, reinforcing the cyclical nature of the data with the cyclical shape of the chart.
However, the radial layout introduces a systematic perceptual distortion: outer bars (those farther from the center) span a longer arc than inner bars of the same radial length, making them appear larger. This means that bars of equal value look different depending on their angular position relative to the inner radius. For this reason, radial bar charts sacrifice some comparison accuracy compared to their linear counterparts. Designers can mitigate this by keeping the inner radius relatively large (reducing the proportional difference between inner and outer arc lengths) and providing tooltips for exact values.
When to Use
- Displaying cyclical data (12 months, 24 hours, 7 days) where the circular form reinforces the data’s nature
- Creating visually engaging dashboards or infographic displays with limited space
- When the number of categories is moderate (6-24) and fits well around a circle
- Showing rankings or comparisons where approximate rather than precise comparison suffices
- When the circular form is thematically appropriate (clock-like, compass-like, seasonal)
When NOT to Use
- When precise comparison of bar lengths is essential — a standard bar chart is more accurate
- When categories have no cyclical or circular relationship and the layout adds no meaning
- When there are very few categories (fewer than 4) and the circle looks sparse, or very many (more than 30) and wedges become too thin
- For showing trends or change over time — a line graph preserves temporal continuity better
- When the audience may be confused by the unfamiliar layout
Anatomy
- Bars (segments): Rectangular or arc-shaped marks radiating from the center, one per category. Length (radius) encodes the value.
- Inner radius: The starting radius of the bars. A larger inner radius reduces perceptual distortion between inner and outer arc lengths.
- Angular slices: Equal-width angular divisions, one per category, arranged around the circle.
- Radial gridlines: Concentric circles marking value scales (e.g., 0, 25, 50, 75, 100).
- Category labels: Text placed along the circumference or at the end of each bar.
- Color encoding: Bars filled with distinct colors per category or a gradient encoding the value.
Variations
- Radial stacked bar chart: Each bar is split into stacked segments showing sub-category composition.
- Radial grouped bar chart: Multiple bars per angular slice, arranged at different radii, for sub-group comparison.
- Radial progress chart: A single bar wraps partially around the circle to show progress toward a goal (common in fitness trackers and KPI dashboards).
- Nightingale rose chart: Wedge-shaped areas instead of bars; area rather than length encodes value.
- Radial lollipop chart: Thin lines with dots instead of full bars, reducing ink in the circular layout.
Code Reference
// D3 - radial bar chart
import * as d3 from "d3";
const angle = d3.scaleBand()
.domain(data.map(d => d.category))
.range([0, 2 * Math.PI])
.padding(0.1);
const radius = d3.scaleLinear()
.domain([0, d3.max(data, d => d.value)])
.range([innerRadius, outerRadius]);
const arc = d3.arc()
.innerRadius(innerRadius)
.outerRadius(d => radius(d.value))
.startAngle(d => angle(d.category))
.endAngle(d => angle(d.category) + angle.bandwidth())
.padAngle(0.02)
.padRadius(innerRadius);
const svg = d3.select("#chart").append("svg")
.attr("viewBox", [-width / 2, -height / 2, width, height]);
svg.selectAll("path").data(data).join("path")
.attr("d", arc)
.attr("fill", (d, i) => d3.schemeTableau10[i % 10]);
// Concentric gridlines
svg.selectAll(".grid").data(radius.ticks(4)).join("circle")
.attr("r", radius)
.attr("fill", "none").attr("stroke", "#ddd");