tag cloud
[Ultimately_Untrue_Thought.git] / plugins / tag_cloud.py
1 # from https://github.com/getpelican/pelican-plugins as of f4d717ff
2
3 # but with a fix to the alphabetical sorting
4
5 '''
6 tag_cloud
7 ===================================
8
9 This plugin generates a tag cloud from available tags
10 '''
11 from __future__ import unicode_literals
12
13 from collections import defaultdict
14 from operator import itemgetter
15
16 import logging
17 import math
18 import random
19
20 from pelican import signals
21
22 logger = logging.getLogger(__name__)
23
24
25 def set_default_settings(settings):
26     settings.setdefault('TAG_CLOUD_STEPS', 4)
27     settings.setdefault('TAG_CLOUD_MAX_ITEMS', 100)
28     settings.setdefault('TAG_CLOUD_SORTING', 'random')
29     settings.setdefault('TAG_CLOUD_BADGE', False)
30
31
32 def init_default_config(pelican):
33     from pelican.settings import DEFAULT_CONFIG
34     set_default_settings(DEFAULT_CONFIG)
35     if(pelican):
36             set_default_settings(pelican.settings)
37
38
39 def generate_tag_cloud(generator):
40     tag_cloud = defaultdict(int)
41     for article in generator.articles:
42         for tag in getattr(article, 'tags', []):
43             tag_cloud[tag] += 1
44
45     tag_cloud = sorted(tag_cloud.items(), key=itemgetter(1), reverse=True)
46     tag_cloud = tag_cloud[:generator.settings.get('TAG_CLOUD_MAX_ITEMS')]
47
48     tags = list(map(itemgetter(1), tag_cloud))
49     if tags:
50         max_count = max(tags)
51     steps = generator.settings.get('TAG_CLOUD_STEPS')
52
53     # calculate word sizes
54     def generate_tag(tag, count):
55         tag = (
56             tag,
57             int(math.floor(steps - (steps - 1) * math.log(count)
58                 / (math.log(max_count)or 1)))
59         )
60         if generator.settings.get('TAG_CLOUD_BADGE'):
61             tag += (count,)
62         return tag
63
64     tag_cloud = [
65         generate_tag(tag, count)
66         for tag, count in tag_cloud
67     ]
68
69     sorting = generator.settings.get('TAG_CLOUD_SORTING')
70
71     if sorting == 'alphabetically':
72         # `.lower()` to avoid putting all uppercase tags lexicographically
73         # before lowercase tags —ZMD
74         tag_cloud.sort(key=lambda elem: elem[0].name.lower())
75     elif sorting == 'alphabetically-rev':
76         tag_cloud.sort(key=lambda elem: elem[0].name, reverse=True)
77     elif sorting == 'size':
78         tag_cloud.sort(key=lambda elem: elem[1])
79     elif sorting == 'size-rev':
80         tag_cloud.sort(key=lambda elem: elem[1], reverse=True)
81     elif sorting == 'random':
82         random.shuffle(tag_cloud)
83     else:
84         logger.warning("setting for TAG_CLOUD_SORTING not recognized: %s, "
85                        "falling back to 'random'", sorting)
86         random.shuffle(tag_cloud)
87
88     # make available in context
89     generator.tag_cloud = tag_cloud
90     generator._update_context(['tag_cloud'])
91
92
93 def register():
94     signals.initialized.connect(init_default_config)
95     signals.article_generator_finalized.connect(generate_tag_cloud)