1. 1 : /**
  2. 2 : * The Correlations tool enables an exploration of the extent to which term frequencies vary in sync (terms whose frequencies rise and fall together or inversely).
  3. 3 : *
  4. 4 : * @example
  5. 5 : *
  6. 6 : * let config = {
  7. 7 : * columns: null,
  8. 8 : * dir: null,
  9. 9 : * docId: null,
  10. 10 : * docIndex: null,
  11. 11 : * minInDocumentsCountRatio: null,
  12. 12 : * query: null,
  13. 13 : * sort: null,
  14. 14 : * stopList: null,
  15. 15 : * termColors: null,
  16. 16 : * withDistributions: null
  17. 17 : * };
  18. 18 : *
  19. 19 : * loadCorpus("austen").tool("correlations", config);
  20. 20 : *
  21. 21 : *
  22. 22 : * @class Correlations
  23. 23 : * @tutorial correlations
  24. 24 : * @memberof Tools
  25. 25 : */
  26. 26 : Ext.define('Voyant.panel.Correlations', {
  27. 27 : extend: 'Ext.grid.Panel',
  28. 28 : mixins: ['Voyant.panel.Panel'],
  29. 29 : alias: 'widget.correlations',
  30. 30 : statics: {
  31. 31 : i18n: {
  32. 32 : },
  33. 33 : api: {
  34. 34 : /**
  35. 35 : * @memberof Tools.Correlations
  36. 36 : * @instance
  37. 37 : * @property {query}
  38. 38 : */
  39. 39 : query: undefined,
  40. 40 :
  41. 41 : /**
  42. 42 : * @memberof Tools.Correlations
  43. 43 : * @instance
  44. 44 : * @property {docId}
  45. 45 : */
  46. 46 : docId: undefined,
  47. 47 :
  48. 48 : /**
  49. 49 : * @memberof Tools.Correlations
  50. 50 : * @instance
  51. 51 : * @property {docIndex}
  52. 52 : */
  53. 53 : docIndex: undefined,
  54. 54 :
  55. 55 : /**
  56. 56 : * @memberof Tools.Correlations
  57. 57 : * @instance
  58. 58 : * @property {stopList}
  59. 59 : * @default
  60. 60 : */
  61. 61 : stopList: 'auto',
  62. 62 :
  63. 63 : /**
  64. 64 : * @memberof Tools.Correlations
  65. 65 : * @instance
  66. 66 : * @property {Number} minInDocumentsCountRatio The minimum coverage (as a percentage) for terms. For instance, if a corpus has 10 documents and the minimum coverage is 20%, at least two of the documents must contain the term or it will be ignored.
  67. 67 : * @default
  68. 68 : */
  69. 69 : minInDocumentsCountRatio: 100,
  70. 70 :
  71. 71 : /**
  72. 72 : * @memberof Tools.Correlations
  73. 73 : * @instance
  74. 74 : * @property {withDistributions}
  75. 75 : * @default
  76. 76 : */
  77. 77 : withDistributions: 'relative',
  78. 78 :
  79. 79 : /**
  80. 80 : * @memberof Tools.Correlations
  81. 81 : * @instance
  82. 82 : * @property {columns} columns 'sourceTerm', 'source-distributions', 'target-distributions', 'targetTerm', 'correlation', 'significance'
  83. 83 : */
  84. 84 : columns: undefined,
  85. 85 :
  86. 86 : /**
  87. 87 : * @memberof Tools.Correlations
  88. 88 : * @instance
  89. 89 : * @property {sort}
  90. 90 : */
  91. 91 : sort: undefined,
  92. 92 :
  93. 93 : /**
  94. 94 : * @memberof Tools.Correlations
  95. 95 : * @instance
  96. 96 : * @property {dir}
  97. 97 : */
  98. 98 : dir: undefined,
  99. 99 :
  100. 100 : /**
  101. 101 : * @memberof Tools.Correlations
  102. 102 : * @instance
  103. 103 : * @property {termColors}
  104. 104 : * @default
  105. 105 : */
  106. 106 : termColors: 'categories'
  107. 107 : },
  108. 108 : glyph: 'xf0ce@FontAwesome'
  109. 109 : },
  110. 110 : config: {
  111. 111 : options: [{xtype: 'stoplistoption'}, {xtype: 'categoriesoption'}, {xtype: 'termcolorsoption'}]
  112. 112 : },
  113. 113 : constructor: function() {
  114. 114 : this.callParent(arguments);
  115. 115 : this.mixins['Voyant.panel.Panel'].constructor.apply(this, arguments);
  116. 116 : },
  117. 117 :
  118. 118 : initComponent: function() {
  119. 119 : var me = this;
  120. 120 :
  121. 121 : Ext.apply(me, {
  122. 122 : title: this.localize('title'),
  123. 123 : emptyText: this.localize("emptyText"),
  124. 124 : store: Ext.create("Voyant.data.store.TermCorrelationsBuffered", {
  125. 125 : parentPanel: this,
  126. 126 : leadingBufferZone: 100 // since these calls are expensive reduce buffer to 1 page
  127. 127 : }),
  128. 128 :
  129. 129 : columns: [{
  130. 130 : text: this.localize("source"),
  131. 131 : tooltip: this.localize("sourceTip"),
  132. 132 : dataIndex: 'sourceTerm',
  133. 133 : sortable: false,
  134. 134 : xtype: 'coloredtermfield'
  135. 135 : },{
  136. 136 : xtype: 'widgetcolumn',
  137. 137 : tooltip: this.localize("trendTip"),
  138. 138 : width: 100,
  139. 139 : dataIndex: 'source-distributions',
  140. 140 : widget: {
  141. 141 : xtype: 'sparklineline'
  142. 142 : },
  143. 143 : text: '←'
  144. 144 : },{
  145. 145 : xtype: 'widgetcolumn',
  146. 146 : tooltip: this.localize("trendTip"),
  147. 147 : width: 100,
  148. 148 : dataIndex: 'target-distributions',
  149. 149 : widget: {
  150. 150 : xtype: 'sparklineline'
  151. 151 : },
  152. 152 : text: '→',
  153. 153 : align: 'right'
  154. 154 : },{
  155. 155 : text: this.localize("target"),
  156. 156 : tooltip: this.localize("targetTip"),
  157. 157 : dataIndex: 'targetTerm',
  158. 158 : sortable: false,
  159. 159 : xtype: 'coloredtermfield'
  160. 160 : },{
  161. 161 : text: this.localize("correlation"),
  162. 162 : tooltip: this.localize("correlationTip"),
  163. 163 : dataIndex: 'correlation'
  164. 164 : },{
  165. 165 : text: this.localize("significance"),
  166. 166 : tooltip: this.localize("significanceTip"),
  167. 167 : dataIndex: 'significance'
  168. 168 : }],
  169. 169 :
  170. 170 :
  171. 171 : listeners: {
  172. 172 : scope: this,
  173. 173 : corpusSelected: function() {
  174. 174 : this.setApiParams({docIndex: undefined, docId: undefined});
  175. 175 : this.getStore().getProxy().setExtraParam('tool', 'corpus.CorpusTermCorrelations');
  176. 176 : this.getStore().load();
  177. 177 : },
  178. 178 :
  179. 179 : documentsSelected: function(src, docs) {
  180. 180 : var docIds = [];
  181. 181 : var corpus = this.getStore().getCorpus();
  182. 182 : docs.forEach(function(doc) {
  183. 183 : docIds.push(corpus.getDocument(doc).getId())
  184. 184 : }, this);
  185. 185 : this.setApiParams({docId: docIds, docIndex: undefined})
  186. 186 : this.getStore().getProxy().setExtraParam('tool', 'corpus.DocumentTermCorrelations');
  187. 187 : this.getStore().load();
  188. 188 : }
  189. 189 :
  190. 190 : },
  191. 191 : dockedItems: [{
  192. 192 : dock: 'bottom',
  193. 193 : xtype: 'toolbar',
  194. 194 : overflowHandler: 'scroller',
  195. 195 : items: [{
  196. 196 : xtype: 'querysearchfield'
  197. 197 : },{
  198. 198 : xtype: 'totalpropertystatus'
  199. 199 : }, {
  200. 200 : xtype: 'tbspacer'
  201. 201 : }, {
  202. 202 : xtype: 'tbtext',
  203. 203 : itemId: 'minInDocumentsCountRatioLabel',
  204. 204 : text: me.localize('minInDocumentsCountRatioLabel')
  205. 205 : }, {
  206. 206 : xtype: 'slider',
  207. 207 : increment: 5,
  208. 208 : minValue: 0,
  209. 209 : maxValue: 100,
  210. 210 : width: 75,
  211. 211 : listeners: {
  212. 212 : afterrender: function(slider) {
  213. 213 : slider.setValue(this.getApiParam("minInDocumentsCountRatio"))
  214. 214 : slider.up('toolbar').getComponent("minInDocumentsCountRatioLabel").setText(new Ext.XTemplate(me.localize("minInDocumentsCountRatioLabel")).apply([this.getApiParam("minInDocumentsCountRatio")]));
  215. 215 : },
  216. 216 : changecomplete: function(slider, newvalue) {
  217. 217 : this.setApiParams({minInDocumentsCountRatio: newvalue});
  218. 218 : slider.up('toolbar').getComponent("minInDocumentsCountRatioLabel").setText(new Ext.XTemplate(me.localize("minInDocumentsCountRatioLabel")).apply([newvalue]));
  219. 219 : this.getStore().load();
  220. 220 : },
  221. 221 : scope: this
  222. 222 : }
  223. 223 : },{
  224. 224 : xtype: 'corpusdocumentselector'
  225. 225 : }]
  226. 226 : }]
  227. 227 : });
  228. 228 :
  229. 229 : me.on("loadedCorpus", function(src, corpus) {
  230. 230 : if (corpus.getDocumentsCount()==1) { // switch to documents mode
  231. 231 : this.getStore().getProxy().setExtraParam('tool', 'corpus.DocumentTermCorrelations');
  232. 232 : }
  233. 233 : if (this.isVisible()) {
  234. 234 : this.getStore().load();
  235. 235 : }
  236. 236 : });
  237. 237 :
  238. 238 : me.on("activate", function() { // load after tab activate (if we're in a tab panel)
  239. 239 : if (this.getStore().getCorpus()) {this.getStore().load();}
  240. 240 : }, this)
  241. 241 :
  242. 242 : me.on("query", function(src, query) {
  243. 243 : this.setApiParam("query", query);
  244. 244 : this.getStore().load();
  245. 245 : }, me);
  246. 246 :
  247. 247 : me.callParent(arguments);
  248. 248 : }
  249. 249 :
  250. 250 : });