栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

基于Python和d3的squarified treemap实现

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

基于Python和d3的squarified treemap实现

squarified treemap实现 1 A brief introduction to treemap 1.1 example

treemap 适合展现具有层级关系的数据 能够直观的体现同级之间的比较。例如下列原始的Android设备手机占有率用原始的分叉树实现效果不是很好 看不出比例关系。

使用下面的treemap来展示效果好得多 可以清楚的看到每个品牌占有的份额 也能看见同一品牌下各个型号的份额 份额信息通过矩形面积表示。

1.2 history

Treemap由马里兰大学教授Ben Shneiderman于上个世纪90年代提出 起初是为了找到一种有效了解磁盘空间使用情况的方法

Treemap最早用的是Slice and Dice算法 在上图中出现了非常狭长的矩形带 对人眼观察不太友好。后来提出了矩形正方化(squarified)的思想使得可视化出来的矩形长宽比尽量接近1 以正方形展示。大致如下

采用此种布局方法有效减少了狭长矩形的数量。

所以squarified rectangles有以下好处

可以更加充分的利用空间。因为采用正方形布局 矩形周长和可达到最小 因为代表所有文件大小的最终面积是固定的 边界长度即矩形周长 squarify可以较少边界长度狭长的矩形容易产生混叠错误 正方形容易观察矩形长宽比趋近1时人眼可以方便比较它们的面积squarify可以提升可视化精度 2 python实现 2.1 代码说明

利用python的matplotlib编程实现squarified treemap算法。

程序指定窗口大小 将给定数据根据窗口大小进行缩放并按面积降序排序。各部分函数功能如下

**normal_sort_size(size_list) **返回经过规范化且按面积降序排序的原始数据list**worst_ratio(size_list,w) **计算并返回当前绘图区域内矩形的最大纵横比 其中w是当前绘图矩形区域较小的一边的长度layout(render_list, layout_side, start_point) 以start_point为基点 绘制render_list内的所有矩形squarify(current_fixed_rec_list, rec_to_layout, layout_side, start_point, screen_width, screen_height) current_fixed_rec_list保存当前绘制区域已选定绘制的矩形 rec_to_layout保存等待绘制的矩形 layout_side为元组tuple 保存当前区域矩形绘制的叠加方向以及区域在该方向上的长度 start_point, screen_width, screen_height分别保存当前绘制区域的左下角对应的坐标 区域的宽和长。该函数是算法的核心函数 判断下一个矩形是绘制在当前子区域 还是绘制在另一个子区域。render(list_to_layout) 接受原始的待可视化的数据 函数内调用squarify()函数
import matplotlib.pyplot as plt
import numpy as np
#规定展示区域的窗口大小
Width 6
Height 4
data [6,4,6,3,2,2,1]
ratio np.sum(data)/(Width*Height)
color_alpha 1
#将原始的大小数组通过窗口正则化
def normal_sort_size(size_list):
 new_size_list []
 target_area Width*Height
 original_area np.sum(size_list)
 for size in size_list:
 new_size_list.append(size*(target_area/original_area))
 #降序排序
 new_size_list sorted(new_size_list,reverse True)
 return new_size_list
#w is the length of the side along which the latest rectangle is layouted
#size_list 当前渲染区域的矩形
def worst_ratio(size_list,w):
 sum_area np.sum(size_list)
 buttom_length sum_area / float(w)
 #计算最大长宽比
 min_area min(size_list)
 ratio1 max(min_area/pow(buttom_length,2), pow(buttom_length,2)/min_area) 
 max_area max(size_list)
 ratio2 max(max_area/pow(buttom_length,2), pow(buttom_length,2)/max_area)
 return max(ratio1,ratio2)
#定义绘图区域
fig1 plt.figure()
ax1 fig1.add_subplot(111, aspect equal )
#绘制图形
#layout_direction 为矩形叠加方向 即
def layout(render_list, layout_side, start_point):
 global color_alpha
 sum_area np.sum(render_list)
 buttom_length sum_area / layout_side[0]
 if layout_side[1] y :#沿着y轴增长
 for rec in render_list:
 print( y: ,start_point,buttom_length, rec/buttom_length)
 ax1.add_patch( plt.Rectangle(start_point, buttom_length, rec/buttom_length, color steelblue , alpha color_alpha) )
 color_alpha color_alpha/1.2
 #添加文字注释
 plt.text(start_point[0] buttom_length/2, start_point[1] rec/(2*buttom_length), str(rec*ratio))
 start_point (start_point[0], start_point[1] rec/buttom_length)
 else:#沿着x轴增长
 for rec in render_list:
 print( x: ,start_point,buttom_length, rec/buttom_length)
 ax1.add_patch( plt.Rectangle(start_point, rec/buttom_length, buttom_length, color steelblue , alpha color_alpha) )
 color_alpha color_alpha/1.2
 #添加文字注释
 plt.text(start_point[0] rec/(2*buttom_length), start_point[1] buttom_length/2, str(rec*ratio))
 start_point (start_point[0] rec/buttom_length, start_point[1])
#布局所有矩形
#start_point 当前绘制区域的左下角坐标
#layout_side是一个元组 (width_of_layout_side,direction_of_layout_side)
def squarify(current_fixed_rec_list, rec_to_layout, layout_side, start_point, screen_width, screen_height):
 #取出下一个待放置矩形并从未防止矩形列表中删除
 if rec_to_layout []:
 layout(current_fixed_rec_list, layout_side, start_point)
 return
 next_rec rec_to_layout[0]
 tmp current_fixed_rec_list.copy()
 tmp.append(next_rec)
 if current_fixed_rec_list []:
 rec_to_layout.pop(0)
 squarify(tmp, rec_to_layout, layout_side, start_point, screen_width, screen_height)
 else:
 #判断当前区域渲染
 buttom_length np.sum(current_fixed_rec_list) / layout_side[0]
 #当前区域不能再放置矩形 寻找下一个区域
 if worst_ratio(current_fixed_rec_list, layout_side[0]) worst_ratio(tmp, layout_side[0]):
 layout(current_fixed_rec_list, layout_side, start_point)
 if layout_side[1] y :#原先沿着y轴生长
 screen_width - buttom_length#新窗口的width
 new_start_point (start_point[0] buttom_length, start_point[1])
 else:#layout[1] x 原来是沿着x轴生长
 screen_height - buttom_length#新窗口的height
 new_start_point (start_point[0], start_point[1] buttom_length)
 #判断当前区域走向
 if screen_width screen_height:
 #沿着x轴生长
 squarify([], rec_to_layout, [screen_width, x ], new_start_point,screen_width,screen_height)
 else:#smaller_side(screen_width, screen_height) screen_height
 squarify([], rec_to_layout, [screen_height, y ], new_start_point,screen_width,screen_height)
 #当前区域继续放置矩形
 else:
 rec_to_layout.pop(0)
 squarify(tmp, rec_to_layout, layout_side, start_point, screen_width, screen_height)
#调用API
def render(list_to_layout):
 to_layout_list normal_sort_size(list_to_layout)
 if Width Height:
 squarify([], to_layout_list, [Height, y ], (0,0), Width, Height)
 else:
 squarify([], to_layout_list, [Width, x ], (0,0), Width, Height)
if __name__ __main__ :
 render(data) 
 plt.xlim(0, Width)
 plt.ylim(0, Height)
 plt.show()
 plt.axis( off )
 fig1.savefig( rect1.png , dpi 90, bbox_inches tight )
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/267285.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号