laserson / squarify

Pure Python implementation of the squarify treemap layout algorithm
Other
297 stars 37 forks source link

Resize/wrap text label #24

Closed mattiasu96 closed 4 years ago

mattiasu96 commented 4 years ago

I'm building a simple treemap using the library. Is there a way to automatically resize/wrap the label of the single square? I'm using the following line of code: squarify.plot(label=labels,sizes=dataGoals.Streams, color = colors, alpha=.7, bar_kwargs=dict(linewidth=0.5, edgecolor="#222222"),text_kwargs={'fontsize':20}) The fontsize unfortunately is fixed, and my labels will overlap between the smaller squares: plot

Is there a way to resize the labels?

laserson commented 4 years ago

The plot function returns a matplotlib.axes.Axes, so check with their documentation about how to manipulate text sizes etc. You can also look at the code for the plot function if you want to customize further....it just makes some Matplotlib calls.

hp0404 commented 4 months ago

I had this issue also and solved it like this:

import matplotlib.pyplot as plt
import pandas as pd
import squarify
from matplotlib import cm
from textwrap import fill

# Sample data
field_counts = pd.DataFrame(
    {
        "Field": ["Science", "Math", "History", "Art", "Geography"],
        "Count": [120, 80, 60, 30, 10],
    }
)
field_counts["Percentage"] = (field_counts["Count"] / field_counts["Count"].sum()) * 100

colormap = cm.get_cmap("tab20c")
colors = [
    colormap(count / field_counts["Count"].max()) for count in field_counts["Count"]
]

# Create label with field, count, and percentage
field_counts["Label"] = field_counts.apply(
    lambda row: f"{row['Field']}\n{row['Count']:,} ({row['Percentage']:.1f}%)", axis=1
)

# Wrap text so that it fits within the box
field_counts["Wrapped_Label"] = field_counts["Label"].apply(lambda x: fill(x, width=16))

def get_font_size(count, max_count, min_font_size=8, max_font_size=20):
    """Determines font size based on count"""
    return min_font_size + (max_font_size - min_font_size) * (count / max_count)

# Calculate font sizes for each label
field_counts["Font_Size"] = field_counts["Count"].apply(
    lambda x: get_font_size(x, field_counts["Count"].max())
)

fig, ax = plt.subplots()

# Plot the rectangles
squarify.plot(
    sizes=field_counts["Count"],
    label=field_counts["Wrapped_Label"].str.title(),
    alpha=0.8,
    color=colors,
    edgecolor="black",
    linewidth=1.25,
    ax=ax,
)

# Modify the text elements directly
for text, font_size in zip(ax.texts, field_counts["Font_Size"]):
    text.set_fontsize(font_size)

plt.show()
image