From 03b1a1e589fa3bec29d236a20e54f8f4142ba6a9 Mon Sep 17 00:00:00 2001 From: Eike Cochu <eike@cochu.com> Date: Tue, 8 Mar 2016 23:19:12 +0100 Subject: [PATCH] added chart to topics, added similar page to articles --- .../de/vipra/rest/resource/InfoResource.java | 1 + .../java/de/vipra/cmd/lda/DTMAnalyzer.java | 18 +++++++---- vipra-ui/app/html/about.html | 12 +++++++- vipra-ui/app/html/articles/show.html | 5 ++++ vipra-ui/app/html/articles/similar.html | 14 +++++++++ vipra-ui/app/html/topics/show.html | 25 +++++++++++++++- vipra-ui/app/js/app.js | 9 ++++++ vipra-ui/app/js/controllers.js | 30 +++++++++++++++++++ .../main/java/de/vipra/util/Constants.java | 6 ++++ 9 files changed, 113 insertions(+), 7 deletions(-) create mode 100644 vipra-ui/app/html/articles/similar.html diff --git a/vipra-backend/src/main/java/de/vipra/rest/resource/InfoResource.java b/vipra-backend/src/main/java/de/vipra/rest/resource/InfoResource.java index 9f1b8025..818444c1 100644 --- a/vipra-backend/src/main/java/de/vipra/rest/resource/InfoResource.java +++ b/vipra-backend/src/main/java/de/vipra/rest/resource/InfoResource.java @@ -75,6 +75,7 @@ public class InfoResource { info.put("const.ktopics", Constants.K_TOPICS); info.put("const.ktopicwords", Constants.K_TOPIC_WORDS); info.put("const.minrelprob", Constants.MINIMUM_RELATIVE_PROB); + info.put("constminshare", Constants.MINIMUM_SHARE); info.put("const.dynminiter", Constants.DYNAMIC_MIN_ITER); info.put("const.dynmaxiter", Constants.DYNAMIC_MAX_ITER); info.put("const.statiter", Constants.STATIC_ITER); diff --git a/vipra-cmd/src/main/java/de/vipra/cmd/lda/DTMAnalyzer.java b/vipra-cmd/src/main/java/de/vipra/cmd/lda/DTMAnalyzer.java index c209d580..5ac5d474 100644 --- a/vipra-cmd/src/main/java/de/vipra/cmd/lda/DTMAnalyzer.java +++ b/vipra-cmd/src/main/java/de/vipra/cmd/lda/DTMAnalyzer.java @@ -316,17 +316,25 @@ public class DTMAnalyzer extends Analyzer { final double[] topicDistribution = topicDistributions[idxArticle++]; // create topic references + double reducedShare = 0; final List<TopicRef> newTopicRefs = new ArrayList<>(Constants.K_TOPICS); for (int idxTopic = 0; idxTopic < Constants.K_TOPICS; idxTopic++) { - final TopicRef newTopicRef = new TopicRef(); - final TopicFull topicFull = newTopics.get(idxTopic); - newTopicRef.setTopic(new Topic(topicFull.getId())); - newTopicRef.setShare(topicDistribution[idxTopic]); - newTopicRefs.add(newTopicRef); + if (topicDistribution[idxTopic] > 0.01) { + reducedShare += topicDistribution[idxTopic]; + final TopicRef newTopicRef = new TopicRef(); + final TopicFull topicFull = newTopics.get(idxTopic); + newTopicRef.setTopic(new Topic(topicFull.getId())); + newTopicRef.setShare(topicDistribution[idxTopic]); + newTopicRefs.add(newTopicRef); + } } // update article if (!newTopicRefs.isEmpty()) { + // renormalize share + for (TopicRef newTopicRef : newTopicRefs) + newTopicRef.setShare(newTopicRef.getShare() / reducedShare); + Collections.sort(newTopicRefs, Comparator.reverseOrder()); // update article with topic references (partial update) diff --git a/vipra-ui/app/html/about.html b/vipra-ui/app/html/about.html index 1a5b2502..15ba8404 100644 --- a/vipra-ui/app/html/about.html +++ b/vipra-ui/app/html/about.html @@ -153,7 +153,17 @@ </tr> <tr class="well"> <td colspan="2"> - The minimum relative probability of topic words. Words are accepted into a topic, if their probability exceeds <it>maximum_probability * minimum_relative_probability</it>. + The minimum relative probability of topic words. Words are accepted into a topic, if their probability exceeds + <it>maximum_probability * minimum_relative_probability</it>. + </td> + </tr> + <tr> + <th>Minimum share</th> + <td ng-bind-template="{{::info.const.minshare}}"></td> + </tr> + <tr class="well"> + <td colspan="2"> + The minimum share of a topic to be accepted for an article. Topic shares are renormalized after rejecting topics below this threshold. </td> </tr> <tr> diff --git a/vipra-ui/app/html/articles/show.html b/vipra-ui/app/html/articles/show.html index 3d0c7e94..d450d474 100644 --- a/vipra-ui/app/html/articles/show.html +++ b/vipra-ui/app/html/articles/show.html @@ -8,6 +8,11 @@ Network graph </a> </td> + <td> + <a class="btn btn-default" ui-sref="articles.show.similar({id:article.id})"> + Similar + </a> + </td> </tr> </table> </div> diff --git a/vipra-ui/app/html/articles/similar.html b/vipra-ui/app/html/articles/similar.html new file mode 100644 index 00000000..dc2fb061 --- /dev/null +++ b/vipra-ui/app/html/articles/similar.html @@ -0,0 +1,14 @@ +<div ng-cloak ng-hide="$state.current.name !== 'articles.show.similar'"> + <div class="page-header"> + <h1 ng-bind="::article.title"></h1> + <table class="item-actions"> + <tr> + <td> + <a class="btn btn-default" ui-sref="articles.show({id:article.id})"> + Back + </a> + </td> + </tr> + </table> + </div> +</div> \ No newline at end of file diff --git a/vipra-ui/app/html/topics/show.html b/vipra-ui/app/html/topics/show.html index b94a2078..292542a1 100644 --- a/vipra-ui/app/html/topics/show.html +++ b/vipra-ui/app/html/topics/show.html @@ -54,7 +54,7 @@ </table> </div> </div> - <div ng-show="topic.dynamic"> + <div ng-if="!topic.dynamic"> <h3>Words <hide-link target="#words"/></h3> <div class="row" id="words"> <div class="col-md-12"> @@ -81,5 +81,28 @@ </div> </div> </div> + <div ng-if="topic.dynamic"> + <h3>Relevance over time <hide-link target="#relevance"/></h3> + <div id="relevance"> + <div class="row"> + <div class="col-md-12"> + <div class="well well-sm"> + <label class="radio-inline"> + <input type="radio" name="seqstyle" ng-model="seqstyle" value="absolute" ng-model-store="seqStyle" ng-model-default="'absolute'">Absolute + </label> + <label class="radio-inline"> + <input type="radio" name="seqstyle" ng-model="seqstyle" value="relative" ng-model-store="seqStyle">Relative + </label> + </div> + </div> + </div> + <br> + <div class="row"> + <div class="col-md-12"> + <div class="area-chart" id="topic-seq" highcharts="topicSeq"></div> + </div> + </div> + </div> + </div> </div> <div ng-cloak ui-view></div> diff --git a/vipra-ui/app/js/app.js b/vipra-ui/app/js/app.js index df507477..fe5fbd1c 100644 --- a/vipra-ui/app/js/app.js +++ b/vipra-ui/app/js/app.js @@ -74,6 +74,15 @@ } }); + $stateProvider.state('articles.show.similar', { + url: '/similar', + templateUrl: 'html/articles/similar.html', + controller: 'ArticlesSimilarController', + ncyBreadcrumb: { + label: 'Similar' + } + }); + // states: topics $stateProvider.state('topics', { diff --git a/vipra-ui/app/js/controllers.js b/vipra-ui/app/js/controllers.js index b74f7791..0658190d 100644 --- a/vipra-ui/app/js/controllers.js +++ b/vipra-ui/app/js/controllers.js @@ -418,6 +418,36 @@ $scope.topic = data; $scope.topicCreated = Vipra.formatDateTime($scope.topic.created); $scope.topicModified = Vipra.formatDateTime($scope.topic.modified); + + if($scope.topic.dynamic) { + var relevances = []; + for(var i = 0, s; i < $scope.topic.sequences.length; i++) { + s = $scope.topic.sequences[i]; + relevances.push([new Date(s.window.startDate).getTime(), s.relevance]); + } + $scope.topicSeq = { + chart: { + type: 'areaspline', + zoomType: 'x', + spacingLeft: 0, + spacingRight: 0 + }, + title: { text: '' }, + xAxis: { + type: 'datetime', + title: { text: '' } + }, + yAxis: { title: { text: 'Relevance' } }, + tooltip: { + headerFormat: '', + pointFormat: '{point.x:%Y}: {point.y:.4f}' + }, + legend: { enabled: false }, + credits: { enabled: false }, + plotOptions: { areaspline: { fillOpacity: 0.5 } }, + series: [ { name: $scope.topic.name, data: relevances } ] + }; + } }, function(err) { $scope.errors = err; }); diff --git a/vipra-util/src/main/java/de/vipra/util/Constants.java b/vipra-util/src/main/java/de/vipra/util/Constants.java index dac5d0e5..d245aa3e 100644 --- a/vipra-util/src/main/java/de/vipra/util/Constants.java +++ b/vipra-util/src/main/java/de/vipra/util/Constants.java @@ -84,6 +84,12 @@ public class Constants { */ public static final double MINIMUM_RELATIVE_PROB = 0.01; + /** + * The minimum share of a topic to be accepted for an article. Topic shares + * are renormalized after rejecting topics below this threshold. + */ + public static final double MINIMUM_SHARE = 0.01; + /** * Dynamic minimum iterations. Used for dynamic topic modeling. Default 100. */ -- GitLab