From 0f83170d6f348a3b2ea09a60934833bd3ca1e2e8 Mon Sep 17 00:00:00 2001 From: Anto Stupak Date: Thu, 25 Apr 2013 13:55:22 +0300 Subject: [PATCH] word cloud: return percents. Additional attribute and labels for text on hover are added --- .../js/src/word_cloud/word_cloud_main.js | 59 ++++++++++++++----- .../lib/xmodule/xmodule/word_cloud_module.py | 18 ++++-- 2 files changed, 57 insertions(+), 20 deletions(-) diff --git a/common/lib/xmodule/xmodule/js/src/word_cloud/word_cloud_main.js b/common/lib/xmodule/xmodule/js/src/word_cloud/word_cloud_main.js index 57457bd04d..4020fe2471 100644 --- a/common/lib/xmodule/xmodule/js/src/word_cloud/word_cloud_main.js +++ b/common/lib/xmodule/xmodule/js/src/word_cloud/word_cloud_main.js @@ -214,7 +214,13 @@ define('WordCloudMain', ['logme'], function (logme) { studentWordsStr, // By default we do not scale. - scale = 1; + scale = 1, + + // Caсhing of DOM element + cloudSectionEl = this.wordCloudEl.find('.result_cloud_section'), + + // Needed for caсhing of d3 group elements + groupEl; // If bounding rectangle is given, scale based on the bounding box of all the words. if (bounds) { @@ -227,26 +233,47 @@ define('WordCloudMain', ['logme'], function (logme) { } $.each(response.student_words, function (word, stat) { - studentWordsKeys.push('' + word + ' (' + (100 * (stat / response.total_count)).toFixed(2) + '%)'); + var percent = (response.display_percents) ? ' ' + (Math.round(100 * (stat / response.total_count))) + '%' : ''; + + studentWordsKeys.push('' + word + '' + percent); }); studentWordsStr = '' + studentWordsKeys.join(', '); - this.wordCloudEl.find('.result_cloud_section').addClass('active'); + cloudSectionEl + .addClass('active') + .find('.your_words').html(studentWordsStr) + .find('.total_num_words').html(response.total_count); - this.wordCloudEl.find('.result_cloud_section').find('.your_words').html(studentWordsStr); - this.wordCloudEl.find('.result_cloud_section').find('.total_num_words').html(response.total_count); - - $(this.wordCloudEl.find('.result_cloud_section').attr('id') + ' .word_cloud').empty(); + $(cloudSectionEl.attr('id') + ' .word_cloud').empty(); // Actual drawing of word cloud. - d3.select('#' + this.wordCloudEl.find('.result_cloud_section').attr('id') + ' .word_cloud').append('svg') - .attr('width', this.width) - .attr('height', this.height) - .append('g') - .attr('transform', 'translate(' + (0.5 * this.width) + ',' + (0.5 * this.height) + ')') - .selectAll('text') - .data(words) - .enter().append('text') + groupEl = d3.select('#' + cloudSectionEl.attr('id') + ' .word_cloud').append('svg') + .attr('width', this.width) + .attr('height', this.height) + .append('g') + .attr('transform', 'translate(' + (0.5 * this.width) + ',' + (0.5 * this.height) + ')') + .selectAll('text') + .data(words) + .enter().append('g'); + + groupEl + .append('title') + .text(function (d) { + var res = ''; + + $.each(response.top_words, function(index, value){ + if (value.text === d.text) { + res = value.percent + '%'; + + return; + } + }); + + return res; + }); + + groupEl + .append('text') .style('font-size', function (d) { return d.size + 'px'; }) @@ -258,7 +285,7 @@ define('WordCloudMain', ['logme'], function (logme) { .attr('transform', function (d) { return 'translate(' + [d.x, d.y] + ')rotate(' + d.rotate + ')scale(' + scale + ')'; }) - .text(function (d) { + .text(function (d) { return d.text; }); }; // End-of: WordCloudMain.prototype.drawWordCloud = function (words, bounds) { diff --git a/common/lib/xmodule/xmodule/word_cloud_module.py b/common/lib/xmodule/xmodule/word_cloud_module.py index efb5dc755e..dc9eca0cd6 100644 --- a/common/lib/xmodule/xmodule/word_cloud_module.py +++ b/common/lib/xmodule/xmodule/word_cloud_module.py @@ -20,11 +20,17 @@ from xblock.core import Scope, String, Object, Boolean, List, Integer log = logging.getLogger(__name__) +def pretty_bool(value): + BOOL_DICT = [True, "True", "true", "T", "t", "1"] + return value in BOOL_DICT + + class WordCloudFields(object): # Name of poll to use in links to this poll display_name = String(help="Display name for this module", scope=Scope.settings) num_inputs = Integer(help="Number of inputs", scope=Scope.settings, default=5) num_top_words = Integer(help="Number of max words, which will be displayed.", scope=Scope.settings, default=250) + display_percents = Boolean(help="Dispaly usage percents for each word.", scope=Scope.settings, default=True) submitted = Boolean(help="Whether this student has posted words to the cloud", scope=Scope.user_state, default=False) student_words = List(help="Student answer", scope=Scope.user_state, default=[]) @@ -49,19 +55,22 @@ class WordCloudModule(WordCloudFields, XModule): def get_state(self): """Return success json answer for client.""" if self.submitted: + total_count = sum(self.all_words.itervalues()) return json.dumps({ 'status': 'success', 'submitted': True, + 'display_percents': pretty_bool(self.display_percents), 'student_words': { word: self.all_words[word] for word in self.student_words }, - 'total_count': sum(self.all_words.itervalues()), - 'top_words': self.prepare_words(self.top_words) + 'total_count': total_count, + 'top_words': self.prepare_words(self.top_words, total_count) }) else: return json.dumps({ 'status': 'success', 'submitted': False, + 'display_percents': False, 'student_words': {}, 'total_count': 0, 'top_words': {} @@ -71,10 +80,10 @@ class WordCloudModule(WordCloudFields, XModule): """Convert raw word to suitable word.""" return word.strip().lower() - def prepare_words(self, words): + def prepare_words(self, words, total_count): """Convert words dictionary for client API.""" return [ - {'text': word, 'size': count} for + {'text': word, 'size': count, 'percent': round(100 * (count / float(total_count)))} for word, count in words.iteritems() ] @@ -185,5 +194,6 @@ class WordCloudDescriptor(WordCloudFields, MakoModuleDescriptor, XmlDescriptor): xml_object.set('display_name', self.display_name) xml_object.set('num_inputs', self.num_inputs) xml_object.set('num_top_words', self.num_top_words) + xml_object.set('display_percents', pretty_bool(self.display_percents)) return xml_object