One of the distinct pieces of functionality we identified earlier was a so called tag cloud.
The tag cloud that is present in the navigation section of all pages shows an alphabetically sorted list of tags. The styling of the individual tags represents the relative number of topics that are marked with this tag. Clicking on the tags will show the list of associated topics. In this implementation, we vary just the font size but we could have opted for additional impact by varying the color as well.
Before we implement a tag cloud, we should take a step back and take a good look at what we need to implement:
The last requirement is again a matter of separating structure from representation. It is easier to adapt a specific style by changing a style sheet than to alter structural markup.
If we look at the HTML that represents an example tag cloud, we notice that the tags are represented by<span>
elements with a class
attribute that indicates its weight. In this case, we divide the range of weights in five parts, giving us classes from weight0
for the least important tag to weight4
for the most important one:
<span class="weight1"><a href="http://searchtags?tags=Intro">Intro</a></span> <span class="weight1"><a href="http://searchtags?tags=Main">Main</a></span> <span class="weight4"><a href="http://searchtags?tags=Python">Python</a></ span> <span class="weight2"><a href="http://searchtags?tags=Tutorial">Tutorial</a></ span>
The actual font size we use to represent these weights is determined by the styles in wiki.css:
.weight0 { font-size:60%; } .weight1 { font-size:70%; } .weight2 { font-size:80%; } .weight3 { font-size:90%; } .weight4 { font-size:100%; }
The tag cloud itself is delivered by the tagcloud()
method in wikiweb.py
.
Chapter6/wikiweb.py
@cherrypy.expose def tagcloud(self,_=None): for tag,weight in wiki.tagcloud(): yield ''' <span class="weight%s"> <a href="http://searchtags?tags=%s">%s</a> </span>'''%(weight,tag,tag)
This method iterates over all tuples retrieved from wiki.tagcloud()
(highlighted). These tuples consist of a weight and a tag name and these are transformed to links and encapsulated in a<span>
element with a fitting class
attribute:
Chapter6/wiki.py
def tagcloud(): tags = sorted([wikidb.Tag(id=t) for t in wikidb.Tag.list()], key=attrgetter('tag')) totaltopics=0 tagrank = [] for t in tags: topics = wikidb.TopicTag.list(t) if len(topics): totaltopics += len(topics) tagrank.append((t.tag,len(topics))) maxtopics = max(topics for tag,topics in tagrank) for tag,topics in tagrank: yield tag, int(5.0*topics/(maxtopics+1)) # map to 0 - 4
The tagcloud()
function in wiki.py
starts off by retrieving a list of all Tag
objects and sorts them based on their tag
attribute. Next, it iterates over all these tags and retrieves their associated topics (highlighted). It then checks if there really are topics by checking the length of the list of topics. Some tags may not have any associated topics and are not counted in this ranking operation.
When a tag is removed from a topic, we do not actually delete the tag itself if it no longer has any associated topics. This might lead to a buildup of unused tags and, if necessary, you might want to implement some clean-up scheme.
If a tag does have associated topics, the number of topics is added to the total and a tuple consisting of the tag name and the number of topics is appended to the tagrank
list. Because our list of Tag
objects was sorted, tagrank
will be sorted as well when we have finished counting the topics.
In order to determine the relative weight of the tags, we iterate again, this time over the tagrank
list to find the maximum number of topics associated with any tag. Then, in a final iteration, we yield a tuple consisting of the tag name and it relative weight, where the relative weight is computed by dividing the number of topics by the maximum number we encountered (plus one, to prevent divide by zero errors). This weight will then be between zero and one (exclusive) and by multiplying this by 5 and rounding down to an integer, a whole number between 0 and 4 (inclusive) is obtained.
3.133.128.145