猿问

Squarify - 自动调整树状图中标签的大小

我正在使用Squarify在 Python 中实现一个简单的树形图。

我正在绘制艺术家姓名及其在所考虑的歌曲图表中的流百分比,正方形越大/越暗,值越高。

我的代码如下:

dataGoals = sort_by_streams[sort_by_streams["Streams"]>1]


#Utilise matplotlib to scale our stream number between the min and max, then assign this scale to our values.

norm = matplotlib.colors.Normalize(vmin=min(dataGoals.Streams), vmax=max(dataGoals.Streams))

colors = [matplotlib.cm.Blues(norm(value)) for value in dataGoals.Streams]


#Create our plot and resize it.

fig1 = plt.figure()

ax = fig1.add_subplot()

fig1.set_size_inches(16, 4.5)


#Use squarify to plot our data, label it and add colours. We add an alpha layer to ensure black labels show through

labels = ["%s\n%.2f" % (label) for label in zip(dataGoals.Artist, dataGoals.Streams)]


squarify.plot(label=labels,sizes=dataGoals.Streams, color = colors, alpha=.7, bar_kwargs=dict(linewidth=0.5, edgecolor="#222222"),text_kwargs={'fontsize':15})

plt.title("Streams Percentage",fontsize=23,fontweight="bold")


#Remove our axes and display the plot

plt.axis('off')

plt.show()

这是结果:

您可能会注意到,较小方块的标签重叠并超出边界。有没有办法自动调整标签大小以适应正方形?

编辑:我尝试使用以下代码实现 matplotlib 的自动换行功能:squarify.plot(label=labels,sizes=dataGoals.Streams, color = colors, alpha=.7, bar_kwargs=dict(linewidth=0.5, edgecolor="#222222"),text_kwargs={'fontsize':20, 'wrap':True})但这并不能解决我的问题,我的文本标签仍然超出范围。


临摹微笑
浏览 295回答 1
1回答

慕妹3242003

尝试使用 绘制树状图时我遇到了同样的问题squarify。经过一番搜索,我想出了一个解决方案,它似乎按预期工作。import matplotlib.patches as mpatchesimport matplotlib.text as mtext# Refrence https://stackoverflow.com/questions/48079364/wrapping-text-not-working-in-matplotlib# and https://stackoverflow.com/questions/50742503/how-do-i-get-the-height-of-a-wrapped-text-in-matplotlibclass WrapText(mtext.Text):&nbsp; &nbsp; def __init__(self,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;x=0, y=0, text='',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;width=0,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;**kwargs):&nbsp; &nbsp; &nbsp; &nbsp; mtext.Text.__init__(self,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;x=x, y=y, text=text,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;wrap=True,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;**kwargs)&nbsp; &nbsp; &nbsp; &nbsp; self.width = width&nbsp; # in screen pixels. You could do scaling first&nbsp; &nbsp; def _get_wrap_line_width(self):&nbsp; &nbsp; &nbsp; &nbsp; return self.width&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; def get_lines_num(self):&nbsp; &nbsp; &nbsp; &nbsp; return len(self._get_wrapped_text().split('\n'))&nbsp; &nbsp;&nbsp;class WrapAnnotation(mtext.Annotation):&nbsp; &nbsp; def __init__(self,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;text, xy,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;width, **kwargs):&nbsp; &nbsp; &nbsp; &nbsp; mtext.Annotation.__init__(self,&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; text=text,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; xy=xy,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; wrap=True,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; **kwargs)&nbsp; &nbsp; &nbsp; &nbsp; self.width = width&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; &nbsp; def _get_wrap_line_width(self):&nbsp; &nbsp; &nbsp; &nbsp; return self.width&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; def get_lines_num(self):&nbsp; &nbsp; &nbsp; &nbsp; return len(self._get_wrapped_text().split('\n'))def text_with_autofit(self, txt, xy, width, height, *,&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; transform=None,&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ha='center', va='center',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; wrap=False, show_rect=False,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; min_size=1, adjust=0,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; **kwargs):&nbsp; &nbsp; if transform is None:&nbsp; &nbsp; &nbsp; &nbsp; if isinstance(self, Axes):&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; transform = self.transData&nbsp; &nbsp; &nbsp; &nbsp; if isinstance(self, Figure):&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; transform = self.transFigure&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; &nbsp; x_data = {'center': (xy[0] - width/2, xy[0] + width/2),&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 'left': (xy[0], xy[0] + width),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 'right': (xy[0] - width, xy[0])}&nbsp; &nbsp; y_data = {'center': (xy[1] - height/2, xy[1] + height/2),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 'bottom': (xy[1], xy[1] + height),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 'top': (xy[1] - height, xy[1])}&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; (x0, y0) = transform.transform((x_data[ha][0], y_data[va][0]))&nbsp; &nbsp; (x1, y1) = transform.transform((x_data[ha][1], y_data[va][1]))&nbsp; &nbsp; # rectange region size to constrain the text&nbsp; &nbsp; rect_width = x1 - x0&nbsp; &nbsp; rect_height = y1- y0&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; fig = self.get_figure() if isinstance(self, Axes) else self&nbsp; &nbsp; dpi = fig.dpi&nbsp; &nbsp; rect_height_inch = rect_height / dpi&nbsp; &nbsp; fontsize = rect_height_inch * 72&nbsp; &nbsp; if isinstance(self, Figure):&nbsp; &nbsp; &nbsp; &nbsp; if not wrap:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; text = self.text(*xy, txt, ha=ha, va=va, transform=transform,&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;fontsize=min_size,&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;**kwargs)&nbsp; &nbsp; &nbsp; &nbsp; else:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fontsize /= 2&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; text = WrapText(*xy, txt, width=rect_width, ha=ha, va=va,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; transform=transform, fontsize=fontsize,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; **kwargs)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self.add_artist(text)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; &nbsp; if isinstance(self, Axes):&nbsp; &nbsp; &nbsp; &nbsp; if not wrap:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; text = self.annotate(txt, xy, ha=ha, va=va, xycoords=transform,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;fontsize=min_size,&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;**kwargs)&nbsp; &nbsp; &nbsp; &nbsp; else:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fontsize /= 2&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; text = WrapAnnotation(txt, xy, ha=ha, va=va, xycoords=transform,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fontsize=fontsize, width=rect_width,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; **kwargs)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self.add_artist(text)&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; while fontsize > min_size:&nbsp; &nbsp; &nbsp; &nbsp; text.set_fontsize(fontsize)&nbsp; &nbsp; &nbsp; &nbsp; bbox = text.get_window_extent(fig.canvas.get_renderer())&nbsp; &nbsp; &nbsp; &nbsp; bbox_width = bbox.width / text.get_lines_num() if wrap else bbox.width&nbsp; &nbsp; &nbsp; &nbsp; if bbox_width <= rect_width:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; while bbox_width <= rect_width:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fontsize += 1&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; text.set_fontsize(fontsize)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; bbox = text.get_window_extent(fig.canvas.get_renderer())&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; bbox_width = bbox.width / text.get_lines_num() if wrap else bbox.width&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; else:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fontsize = fontsize - 1&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; text.set_fontsize(fontsize)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; fontsize /= 2&nbsp; &nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; if fig.get_constrained_layout():&nbsp; &nbsp; &nbsp; &nbsp; c_fontsize = fontsize + adjust + 0.5&nbsp; &nbsp; &nbsp; &nbsp; text.set_fontsize(c_fontsize if c_fontsize > min_size else min_size)&nbsp; &nbsp; if fig.get_tight_layout():&nbsp; &nbsp; &nbsp; &nbsp; c_fontsize = fontsize + adjust&nbsp; &nbsp; &nbsp; &nbsp; text.set_fontsize(c_fontsize if c_fontsize > min_size else min_size)&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; if show_rect and isinstance(self, Axes):&nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; rect = mpatches.Rectangle((x_data[ha][0], y_data[va][0]),&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; width, height, fill=False, ls='--')&nbsp; &nbsp; &nbsp; &nbsp; self.add_patch(rect)&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; &nbsp; return text此功能支持将文本自动调整到框中。如果wrap是True,则文本将根据框的大小自动换行。grow=True下图是自动调整( )和自动换行(wrap=True)的图数据是来自treemapify的 G20 ,这是一个用于绘制树形图的优秀 R 包。自动拟合的图:自动调整和自动换行的图形:&nbsp;自动调整的基本过程是根据框的高度设置字体大小,将文本宽度与框的宽度进行比较,然后减小字体大小,直到文本宽度小于框的宽度。至于自动换行,底层过程依赖于 matplotlib 中内置的自动换行,通过设置wrap=True.&nbsp;自动调整字体大小的过程是相同的。然而,自动适配的过程有点慢。我希望有人能够找出一些更有效的自动拟合算法。希望这个功能可以帮助到您。
随时随地看视频慕课网APP

相关分类

Python
我要回答