文档章节

简单标签云的实现

typeorigin
 typeorigin
发布于 2012/12/09 17:04
字数 1526
阅读 681
收藏 2

原文地址: http://typeorigin.com/2015/12/27/20151227-tagcloud-diy/    


        标签云是数据可视化的有效方法。标签云中根据标签的衡量指标,呈现时设置不同的字体大小或者颜色来表达标签的重要性,能够方便的表达博客的关注点。

       下面是我自己实现一个简单标签云的过程,在我的标签云中,实现了用不同的字体大小来表达标签被引用的次数。当然其实有很多现成的工具可以用,不过自己对于实现原理比较好奇,也就想自己实现个,最后效果是有了,也不知道是不是常规手段。

       在开工的时候我考虑了这么个问题:标签的被引用次数我很容易得到,我只需要几个简单的SQL就可以统计出各标签的的使用次数,但是问题在于难道我的标签’Java’被引用了100, 标签切糕仅仅被引用1次,在显示的时候就让’Java’切糕大一百倍?那切糕肯定不满意了,好歹切糕也很火啊。而且更实际的问题是,我们的页面在展示标签时的空间是有大小的,不可能任由字体任意大。

       那么现在缕缕思路,实现标签云,我先要做下面的工作:

1、  统计出各标签的引用次数

2、  合理的显示标签大小

哦,前面忘记说了,基于标签云的实现,我的数据模型是这样的:1Post, 1Tag表,还有一张 Post Tag 的关联表


    统计标签的引用次数

    统计很简单,一句SQL就可以实现,我使用的Django,查询的话就这样:

tag_list = Tag.objects.annotate(num_post=Count('post_tag'))

    合理显示标签大小

    什么叫做合理呢?起码不能太大吧,起码也不能小的看不见吧。那么就只能规定一个取值的范围。

    标签的引用次数可能会差别很大,如果直接用引用次数来作为最终标签的字体大小的话,也不是不可以,只不过有的字体会特别大,有的呢又特别小

       如果直接表示大小不行,那么我就是用倍数来表示。比如我只能接受最大的字体是最小字体的3倍,那么如何将差别很大的引用次数映射到 1 ~ 3 的范围之间呢?

       首先来个假设,假设现在我有一组标签的引用次数 A = [1, 3, 5, 6, 10], 接下来的过程其实也就是找到一个合适的函数来完成这个映射。思路就是讲我们的数字逐步的往 [1, 3]上靠。

       先找出 A 中的最大值 maxA, 然后将 A 中的每个数值除以 maxA, 结果也就是

        A’ = [0.1, 0.3, 0.5, 0.6, 1], 现在已经成功的将值域缩小到 [0, 1] 之间,继续向 [1, 3] 上靠。

       现在对于 A’ 中的每个数字n, 都满足 0 <= n <= 1, 不等式两边同时乘以 2,则取值范围变为 0 <= 2n <= 2, 再将不等式两边同时加上1则等于, 1 <= 2n + 1 < = 3

       现在我数组A中原来的引用次数已经转化为 [1, 3] 之间。但是这只是个特例,我还需要更通用的公式才能满足不同区间的需求。

       根据上面的步骤,可以抽象为一下步骤

       A’*x + y

       假设目标区间是[L, U], 那么利用两个端点值,可以得到两个方程:

              A’max * x + y = U

              A’min * x + y = L

       解方程组的:

              x = ( U – L ) / (A’max – A’min) (注意分母为 0 的情况)

              y = U – x

       公式有了,接下来实现就方便了。再用前面的例子 A = [1, 3, 5, 6, 10] 来总结下计算过程:

1、  A中每个元素除以 A中最大值 的A’ [0.1, 0.3, 0.5, 0.6, 1]

2、  求出A’ 中最大最小值 A’max, A’min

3、  运用公式 x = ( U – L ) / (A’max – A’min) , y = U – x 计算两个变量x, y 的值

4、  A’ 中每个元素运用公式 A’*x + y 计算换算后的倍数 M

通过上面步骤, A = [1, 3, 5, 6, 10] 计算结果为 M = [1.0,1.21.41.82.13.0]

有了M 在前端展示的时候就可以设置style时使用 “font-size: M em;” 来设置字体大小了

       我的Python实现如下:

# coding=utf-8
 from tumblelog.tumbleutils import TumbleLogUtils
 
 class TagCloud(object):
 	''' 根据标签被引用次数计算标签最终的显示的字号'''
 	def __init__(self, tag_list):
 		self.tag_list = tag_list
 		self.MAX_FONT_RATE = 3.0
 		self.MIN_FONT_RATE = 1.0
 
 	def calculateTagFont(self):
 		maxE = self.maxElement()
 		minE = self.minElement()
 		normalizegList = self.normalize(maxE)
 		targetList = []
 		x = self.getBootFactor(maxE, minE)
 		y = self.getOffset(maxE, minE)
 
 		colorUtil = TumbleLogUtils() #一个工具类, 主要用于生成随机颜色
 		for i in range(0, len(normalizegList)):
 			normalizegList[i].num_post  = normalizegList[i].num_post * x + y
 			normalizegList[i].color = colorUtil.getRandomColor()
 			targetList.append(normalizegList[i])
 		return targetList
 
 
 	def normalize(self, maxE):
 		''' 预处理标签引用次数, 将标签次数的值域缩小到[0,1]'''
 		# 只有最大值非零时才进行此操作
 		if maxE:
 			for i in xrange(0, len(self.tag_list)):
 				self.tag_list[i].num_post = self.tag_list[i].num_post / maxE
 		return self.tag_list
 
 	def getBootFactor(self, maxE, minE):
 		''' 计算公式中的系数 x, 如果最大最小值相等, 就返回0, 否则返回按公式的计算结果'''
 		if not maxE - minE:
 			return 0
 		return (self.MAX_FONT_RATE - self.MIN_FONT_RATE) / (maxE - minE) * maxE
 
 	def getOffset(self, maxE, minE):
 		''' 计算公式中的系数 y, 如果最大最小值相等, 就返回1, 否则返回按公式的计算结果'''
 		if not maxE - minE:
 			return 1
 		return self.MAX_FONT_RATE - self.getBootFactor(maxE, minE)
 
 	def maxElement(self):
 		tmpTags = self.tag_list.order_by('-num_post')
 		return float(tmpTags[0].num_post)
 
 	def minElement(self):
 		tmpTags = self.tag_list.order_by('-num_post')
 		return float(tmpTags[len(tmpTags) - 1].num_post)
对应的模版中的代码
{% for tag in tag_list%}
       <font style="font-size: {{tag.num_post}}em;"><a href="/tag/{{ tag.slug }}" id="{{tag.slug}}" style="color:{{tag.color}}">{{ tag.title }}</a></font>
     {% endfor %}
效果图

   演示地址: hellofalcon.com

   拓展思考:

        1、除了用标签的引用次数来计算,还可以自己给标签一些权重,这样的话需要对公式进行调整。

        2、复杂的标签云,类似下面这样的还不知道怎么弄。


© 著作权归作者所有

typeorigin

typeorigin

粉丝 22
博文 19
码字总数 13325
作品 0
杭州
程序员
私信 提问
加载中

评论(5)

typeorigin
typeorigin 博主

引用来自“一刀”的评论

因为按照你的这个算法,如果我希望字体范围是8到24px,当标签数这样[1,1,1,2,2],会导致引用1篇和引用2篇文章数的标签相差太大了。这个太不和谐了。囧~
是的,单纯只考虑倍数在特殊情况会比较抓狂,你这个加个上限或者加上步长的方案是合理的
一刀
一刀
因为按照你的这个算法,如果我希望字体范围是8到24px,当标签数这样[1,1,1,2,2],会导致引用1篇和引用2篇文章数的标签相差太大了。这个太不和谐了。囧~
一刀
一刀
我的另一种算法:
MIN_TAG = 8
MAX_TAG = 24

def tag_font(tags):
"""
标签云的字体大小算法
思路如下:最小字体为MIN_TAG,文章数每增加一个字体增加2px,但是到MAX_TAG后封顶
"""
return {k: MIN_TAG + (v - 1) * 2 if MIN_TAG + (v - 1) * 2 <= MAX_TAG else MAX_TAG
for k, v in tags.items()}

if __name__ == '__main__':
print(tag_font({'校园': 3, 'python': 9, 'java': 1, '哈哈': 2}))
typeorigin
typeorigin 博主

引用来自“leo-H”的评论

有js版本的吗

灰常抱歉,目前没有。不过也应该也容易,你获取到各标签的数量,然后用公司一算各自尺寸就可以了。
leo-H
leo-H
有js版本的吗
修改WordPress标签云显示数量、字体、大小

WordPress 自带的标签云是一个很实用的小工具。站长可以通过标签对具有相同关健词的文章进行检索分类,利于访客查找相关文章。WordPress 默认标签云的字体最小为8pt,最大为22pt,标签显示数量为...

Rhymo-Wu
2018/06/20
0
0
wordpress主题实现彩色标签云效果

怎样不用插件在wordpress中实现彩色标签云效果?使用wordpress的朋友大多都喜欢用插件来实现彩色标签云的效果,这样是比较方便,但是,如果插件用多了,会对系统产生拖累。所以,我这里跟大家...

hero2019
2018/07/04
0
0
Power BI 标签云可视化

网易云课堂帮我提取出了所有课程的评价信息,那么我们可以做一个文本分析,用标签云的方式进行可视化,看看各位学员们都是如何评价我们课程的。 1、分词与词频统计 要做标签云可视化,首先需...

刘万祥ExcelPro
2017/05/25
0
0
[jQuery]3D效果的标签云

刚才看了篇园友关于如何自定义标签云的文章,心痒痒自己也想弄一个,其实原理非常简单,就是动态load标签页里的标签,按需要的格式重新动态生成DOM结构,再通过第三方的js插件(他们用的是Goo...

吞吞吐吐的
2017/10/05
0
0
wordpress主题怎样在标签云效果中显示每个标签的文章数?

tag标签是wordpress程序所独特的一个模块,在国产的CMS程序(如:织梦)就很难见到它的踪迹。而标签以标签云来展示更是wordpress主题开发的一个常态。变化多样的标签云展示,给wordpress主题...

hero2019
2018/07/05
0
0

没有更多内容

加载失败,请刷新页面

加载更多

八、Docker Swarm

Docker Swarm有两件事:一个企业级的Docker主机安全集群,另一个是用于协调微服务应用程序的引擎。 在集群方面,它将一个或多个Docker节点组合在一起,并允许你将他们作为一个集群来管理。开...

倪伟伟
昨天
4
0
Fragment懒加载其实很简单

前言 记得去年面试的时候, 面了一家小公司, 那个面试官问我, fragment的懒加载做过吗?我说没做过(确实没做过).后来面试快结束了, 又问我, 懒加载没做过是吗?后来可想而知也没收到offer, (ಥ_...

天王盖地虎626
昨天
2
0
聊聊dubbo的TimeoutFilter

序 本文主要研究一下dubbo的TimeoutFilter ListenableFilter dubbo-2.7.2/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/ListenableFilter.java public abstract class Liste......

go4it
昨天
6
0
方法与数组

方法 方法就是完成特定功能的代码块;在很多语言里面都有函数的定义,函数在Java中被称为方法 格式: 修饰符 返回值类型 方法名(参数类型 参数名1,参数类型 参数名2…) throw 异常{ 函数体;...

凹凸凸
昨天
4
0
死磕 java同步系列之StampedLock源码解析

问题 (1)StampedLock是什么? (2)StampedLock具有什么特性? (3)StampedLock是否支持可重入? (4)StampedLock与ReentrantReadWriteLock的对比? 简介 StampedLock是java8中新增的类,...

彤哥读源码
昨天
16
1

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部