I have a dataframe df and I want to draw a radial bar/column chart with the values mapped against the cities.
The dataframe looks like:
City | Counts |
---|---|
Leeds | 5 |
Liverpool | 7 |
Birmingham | 8 |
Nottingham | 14 |
I am able to get the horizontal bar chart but not the radial one
colors = ["red","green","blue","yellow","magenta","cyan"]
plt.barh("state", "counts", data = m, color = colors)
plt.xlabel("Number of Firearm Incidents per head")
plt.ylabel("LSOA Region")
plt.title("Firearm Incidents vs LSOA per head")
plt.show()
I want something like these two 1 2
CodePudding user response:
This is a possible approach:
# import pandas for data wrangling
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# Build a dataset
df = pd.DataFrame({'City': ['Leeds', 'Liverpool', 'Birmingham', 'Nottingham'],
'Counts': [5, 7, 8, 14]})
# Reorder the dataframe
df = df.sort_values(by=['Counts'])
# initialize the figure
plt.figure(figsize=(20,10))
ax = plt.subplot(111, polar=True)
plt.axis('off')
# Constants = parameters controling the plot layout:
upperLimit = 100
lowerLimit = 30
labelPadding = 4
# Compute max and min in the dataset
max = df['Counts'].max()
# Let's compute heights: they are a conversion of each item value in those new coordinates
# In our example, 0 in the dataset will be converted to the lowerLimit (10)
# The maximum will be converted to the upperLimit (100)
slope = (max - lowerLimit) / max
heights = slope * df.Counts lowerLimit
# Compute the width of each bar. In total we have 2*Pi = 360°
width = 2*np.pi / len(df.index)
# Compute the angle each bar is centered on:
indexes = list(range(1, len(df.index) 1))
angles = [element * width for element in indexes]
angles
# Draw bars
bars = ax.bar(
x=angles,
height=heights,
width=width,
bottom=lowerLimit,
linewidth=2,
edgecolor="white",
color="#61a4b2",
)
# Add labels
for bar, angle, height, label in zip(bars,angles, heights, df["City"]):
# Labels are rotated. Rotation must be specified in degrees :(
rotation = np.rad2deg(angle)
# Flip some labels upside down
alignment = ""
if angle >= np.pi/2 and angle < 3*np.pi/2:
alignment = "right"
rotation = rotation 180
else:
alignment = "left"
# Finally add the labels
ax.text(
x=angle,
y=lowerLimit bar.get_height() labelPadding,
s=label,
ha=alignment,
va='center',
rotation=rotation,
rotation_mode="anchor")