Skip to content

Commit 595172c

Browse files
added lots of comments; adjusted layout
1 parent 85bd8ef commit 595172c

File tree

1 file changed

+35
-25
lines changed

1 file changed

+35
-25
lines changed

doc/python/bar-charts.md

Lines changed: 35 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -593,53 +593,62 @@ fig.update_layout(
593593

594594
This bar-style pictogram allows readers to focus on the relative sizes of smaller entities by wrapping the bar for largest entries into multiple columns. You could make it even more of a pictogram by using fontawesome to replace the square markers we use below with icons like mortar boards for students.
595595

596-
```
596+
```python
597597
import plotly.graph_objects as go
598598
import pandas as pd
599-
600-
def pictogram_bar(data, title, icon_size, max_height=10, units_per_icon=1, column_spacing=.75,icon_spacing=0.005):
599+
def pictogram_bar(data, title, icon_size, max_icons_per_column=10, units_per_icon=1, unit_description="", inter_group_spacing=.8,icon_vertical_spacing=0.005):
601600

602601
fig = go.Figure()
603602
x_start = 1
604603
tick_locations = []
605-
604+
#loop through each group and create a trace with its icons
606605
for i, (category, value) in enumerate(data.items()):
606+
# compute the number of icons represent this category
607607
icon_count = round(value / units_per_icon)
608-
num_columns = -(-icon_count // max_height) # Ceiling division
609-
608+
# compute the number of columns in which to arrange this category
609+
# every category gets at least one column; we use integer division
610+
# to compute the number of additional columns
611+
num_columns = (icon_count // max_icons_per_column)+1
612+
613+
#create lists of coordinates and populate them
610614
x_coordinates, y_coordinates = [], []
611615
for col in range(num_columns):
612-
column_icons = min(max_height, icon_count - col * max_height)
616+
# the number of icons in this column is the lesser of the column height or
617+
# the number of icons remaining to place
618+
column_icons = min(max_icons_per_column, icon_count - col * max_icons_per_column)
619+
620+
# create a list element containing the x-coordinate of this column;
621+
# add column_icons copies of that coordinate to the list of icon x coordinates
622+
# normalizing the width of each within group column to 1 simplifies the code
623+
# we can adjust the visible space between columns by adjusting the total width below
613624
x_coordinates.extend([x_start + col] * column_icons)
614-
y_coordinates.extend([y + icon_spacing * y for y in range(1, column_icons + 1)])
615-
616-
625+
# create a list of sequentially increasing y-coordinates for icons
626+
y_coordinates.extend([y + icon_vertical_spacing * y for y in range(1, column_icons + 1)])
617627
# Add scatter plot for the category
618628
fig.add_trace(go.Scatter(
619629
x=x_coordinates,
620630
y=y_coordinates,
621631
mode='markers',
622632
marker=dict(size=icon_size, symbol="square", color= i),
623633
name=category,
634+
#suppress the x and y coordinates in the hover text, since they are meaningless to readers
624635
hoverinfo="text",
625636
text=[f"{category}: {value}" for _ in range(len(x_coordinates))]
626637
))
627638

628-
629-
# Add value annotations above the section
639+
# add an annotation above the center of each section showing its value
630640
fig.add_trace(go.Scatter(
631-
x=[x_start + (num_columns - 1) / 2],
632-
y=[max_height + 1.2],
641+
x=[x_start + (num_columns - 1) / 2], #center
642+
y=[max_icons_per_column + 1.2],
633643
mode="text",
634644
text=[f"{value}"],
635645
textfont=dict(size=14, color="black"),
636646
showlegend=False
637647
))
638-
639-
# Track tick locations
648+
# Track locations where we will put the text for each category
640649
tick_locations.append(x_start + (num_columns - 1) / 2)
641-
x_start += num_columns + column_spacing
642-
650+
#compute the left edge of the next category
651+
x_start += num_columns + inter_group_spacing
643652
# Update layout
644653
fig.update_layout(
645654
title=title,
@@ -651,18 +660,18 @@ def pictogram_bar(data, title, icon_size, max_height=10, units_per_icon=1, colum
651660
title="Categories"
652661
),
653662
yaxis=dict(
654-
title=f"Units (1 icon = {units_per_icon})",
663+
title=f"Units (1 icon = {units_per_icon:,g} {unit_description})",
655664
showgrid=False,
656665
zeroline=False,
657666
),
658-
showlegend=False,
659-
height=600,
660-
width=(len(data) * 200 + 200)
667+
# we've got all the labeling we need without a legend
668+
showlegend=False,
669+
height=700,
670+
# the x-coordinates get scales to fill available space, so adjusting the width is a good way to adjust spacing between columns
671+
width=(len(data) * 150 + 50)
661672
)
662-
663673
fig.show()
664674

665-
666675
df = pd.DataFrame({
667676
'School': ["Haverford College", "University of Mary Washington", "Brown University", "Arizona State University"],
668677
'Enrollment': [1421, 3611, 7226, 65174]
@@ -672,8 +681,9 @@ pictogram_bar(
672681
data={row['School']: row['Enrollment'] for _, row in df.iterrows()},
673682
title="Undergraduate Enrollment at Participating Schools",
674683
units_per_icon=1000,
684+
unit_description = "students",
675685
icon_size=27,
676-
icon_spacing=0.05
686+
icon_vertical_spacing=0.05
677687
)
678688
```
679689

0 commit comments

Comments
 (0)