From 691d4757ff9b9b4cef3c6b88545d4c577fd2f477 Mon Sep 17 00:00:00 2001 From: Inga Kirschnick <inga.kirschnick@uni-bielefeld.de> Date: Tue, 18 Jul 2023 16:01:31 +0200 Subject: [PATCH] Token list first implementation+ query builder fix --- .../js/CorpusAnalysis/CorpusAnalysisApp.js | 5 - .../CorpusAnalysisStaticVisualization.js | 256 ++++++++------ .../js/ResourceLists/CorpusTextInfoList.js | 14 +- .../js/ResourceLists/CorpusTokenList.js | 121 +++++++ app/static/js/ResourceLists/ResourceList.js | 1 + app/templates/_scripts.html.j2 | 3 +- .../_analysis/static_visualization.html.j2 | 64 ++-- app/templates/corpora/analysis.html.j2 | 326 +----------------- 8 files changed, 319 insertions(+), 471 deletions(-) create mode 100644 app/static/js/ResourceLists/CorpusTokenList.js diff --git a/app/static/js/CorpusAnalysis/CorpusAnalysisApp.js b/app/static/js/CorpusAnalysis/CorpusAnalysisApp.js index 25f58a65..ea7aed3a 100644 --- a/app/static/js/CorpusAnalysis/CorpusAnalysisApp.js +++ b/app/static/js/CorpusAnalysis/CorpusAnalysisApp.js @@ -34,11 +34,6 @@ class CorpusAnalysisApp { .then((cqiCorpora) => { this.data.corpus = {o: cqiCorpora[0]}; console.log(this.data.corpus.o.staticData); - // this.renderGeneralCorpusInfo(); - // this.renderTextInfoList(); - // this.renderTextProportionsGraphic() - // this.renderFrequenciesGraphic(); - // this.renderBoundsGraphic(); // TODO: Don't do this hgere this.data.corpus.o.updateDb(); diff --git a/app/static/js/CorpusAnalysis/CorpusAnalysisStaticVisualization.js b/app/static/js/CorpusAnalysis/CorpusAnalysisStaticVisualization.js index 81e1d466..2d8f9002 100644 --- a/app/static/js/CorpusAnalysis/CorpusAnalysisStaticVisualization.js +++ b/app/static/js/CorpusAnalysis/CorpusAnalysisStaticVisualization.js @@ -18,9 +18,10 @@ class CorpusAnalysisStaticVisualization { this.data.corpus = this.app.data.corpus; this.renderGeneralCorpusInfo(); this.renderTextInfoList(); - this.renderTextProportionsGraphic() + this.renderTextProportionsGraphic(); + this.renderTokenList(); this.renderFrequenciesGraphic(); - this.renderBoundsGraphic(); + // Add event listeners let frequenciesStopwordSettingModal = document.querySelector('#frequencies-stopwords-setting-modal'); let frequenciesStopwordSettingModalButton = document.querySelector('#frequencies-stopwords-setting-modal-button'); @@ -30,6 +31,35 @@ class CorpusAnalysisStaticVisualization { M.Modal.init(frequenciesStopwordSettingModal, {dismissible: false}); }); + let textProportionsGraphModeButtons = document.querySelectorAll('.text-proportions-graph-mode-button'); + textProportionsGraphModeButtons.forEach(graphModeButton => { + graphModeButton.addEventListener('click', (event) => { + textProportionsGraphModeButtons.forEach(btn => { + btn.classList.remove('disabled'); + }); + event.target.closest('.text-proportions-graph-mode-button').classList.add('disabled'); + this.renderTextProportionsGraphic(); + }); + }); + + let frequenciesTokenCategoryDropdownElement = document.querySelector('[data-target="frequencies-token-category-dropdown"]'); + let frequenciesTokenCategoryDropdownListElement = document.querySelector("#frequencies-token-category-dropdown"); + frequenciesTokenCategoryDropdownListElement.addEventListener('click', (event) => { + frequenciesTokenCategoryDropdownElement.firstChild.textContent = event.target.innerHTML; + this.renderFrequenciesGraphic(); + }); + + let frequenciesGraphModeButtons = document.querySelectorAll('.frequencies-graph-mode-button'); + frequenciesGraphModeButtons.forEach(graphModeButton => { + graphModeButton.addEventListener('click', (event) => { + frequenciesGraphModeButtons.forEach(btn => { + btn.classList.remove('disabled'); + }); + event.target.closest('.frequencies-graph-mode-button').classList.add('disabled'); + this.renderFrequenciesGraphic(); + }); + }); + for (let actionButton of document.querySelectorAll('.frequencies-stopword-setting-modal-action-buttons')) { actionButton.addEventListener('click', (event) => { let action = event.target.closest('.frequencies-stopword-setting-modal-action-buttons').dataset.action; @@ -101,70 +131,121 @@ class CorpusAnalysisStaticVisualization { let corpusData = this.data.corpus.o.staticData; let textProportionsGraphicElement = document.querySelector('#text-proportions-graphic'); let texts = Object.entries(corpusData.s_attrs.text.lexicon); - let graphData = [ - { - values: texts.map(text => text[1].counts.token), - labels: texts.map(text => `${corpusData.values.s_attrs.text[text[0]].title} (${corpusData.values.s_attrs.text[text[0]].publishing_year})`), - type: 'pie' - } - ]; + let graphtype = document.querySelector('.text-proportions-graph-mode-button.disabled').dataset.graphType; + let textProportionsTitleElement = document.querySelector('#text-proportions-title-element'); + + if (graphtype === 'bar') { + textProportionsTitleElement.innerHTML = 'Bounds'; + } else if (graphtype === 'pie') { + textProportionsTitleElement.innerHTML = 'Proportions'; + } + + let graphData = this.createTextProportionsGraphData(texts, graphtype); let graphLayout = { - showlegend: true, - height: 486, + barmode: graphtype === 'bar' ? 'relative' : '', + type: graphtype, + showgrid: false, + height: 447, margin: { l: 10, r: 10, - b: 10, - t: 10 + b: graphtype === 'bar' ? 80 : 10, + t: graphtype === 'bar' ? 80 : 10, }, legend: { "orientation": "h", font: { size: 10 } + }, + xaxis: { + rangemode: 'nonnegative', + autorange: true + }, + yaxis: { + autorange: true, + showticklabels: false } }; let config = { responsive: true, + modeBarButtonsToRemove: ['zoom2d', 'select2d', 'lasso2d', 'zoomIn2d', 'zoomOut2d', 'autoScale2d', 'resetScale2d'], displaylogo: false }; Plotly.newPlot(textProportionsGraphicElement, graphData, graphLayout, config); } + createTextProportionsGraphData(texts, graphtype) { + let corpusData = this.data.corpus.o.staticData; + let graphData = []; + switch (graphtype) { + case 'bar': + for (let text of texts) { + let textData = { + type: 'bar', + orientation: 'h', + x: [text[1].bounds[1] - text[1].bounds[0]], + y: [0.5], + text: [`${text[1].bounds[0]} - ${text[1].bounds[1]}`], + name: `${corpusData.values.s_attrs.text[text[0]].title} (${corpusData.values.s_attrs.text[text[0]].publishing_year})`, + hovertemplate: `${text[1].bounds[0]} - ${text[1].bounds[1]}`, + }; + graphData.push(textData); + } + break; + default: + graphData = [ + { + values: texts.map(text => text[1].counts.token), + labels: texts.map(text => `${corpusData.values.s_attrs.text[text[0]].title} (${corpusData.values.s_attrs.text[text[0]].publishing_year})`), + type: graphtype + } + ]; + break; + } + return graphData; + } + + async renderTokenList() { + let corpusData = this.data.corpus.o.staticData; + let corpusTokenListElement = document.querySelector('.corpus-token-list'); + let corpusTokenList = new CorpusTokenList(corpusTokenListElement); + let stopwords = this.data.stopwords; + if (this.data.stopwords === undefined) { + stopwords = await this.getStopwords(); + } + stopwords = Object.values(stopwords).flat(); + let mostFrequent = Object.entries(corpusData.corpus.freqs.word) + .sort((a, b) => b[1] - a[1]) + .filter(item => !stopwords.includes(corpusData.values.p_attrs.word[item[0]].toLowerCase())) + .slice(0, 4) + .map(item => parseInt(item[0])); + let tokenData = []; + for (let i = 0; i < Object.values(corpusData.corpus.freqs.word).length; i++) { + let resource = { + term: corpusData.values.p_attrs.word[i].toLowerCase(), + count: corpusData.corpus.freqs.word[i], + mostFrequent: mostFrequent.includes(i) + }; + if (!Object.values(stopwords).includes(resource.term)) { + tokenData.push(resource); + } + } + corpusTokenList.add(tokenData); + } + async renderFrequenciesGraphic() { let corpusData = this.data.corpus.o.staticData; let frequenciesTokenCategoryDropdownElement = document.querySelector('[data-target="frequencies-token-category-dropdown"]'); - let frequenciesTokenCategoryDropdownListElement = document.querySelector("#frequencies-token-category-dropdown"); let frequenciesGraphicElement = document.querySelector('#frequencies-graphic'); let texts = Object.entries(corpusData.s_attrs.text.lexicon); let graphtype = document.querySelector('.frequencies-graph-mode-button.disabled').dataset.graphType; - let graphModeButtons = document.querySelectorAll('.frequencies-graph-mode-button'); - - frequenciesTokenCategoryDropdownListElement.addEventListener('click', (event) => { - frequenciesTokenCategoryDropdownElement.firstChild.textContent = event.target.innerHTML; - this.renderFrequenciesGraphic(corpusData); - }); - - graphModeButtons.forEach(graphModeButton => { - graphModeButton.addEventListener('click', (event) => { - graphModeButtons.forEach(btn => { - btn.classList.remove('disabled'); - }); - event.target.closest('.frequencies-graph-mode-button').classList.add('disabled'); - this.renderFrequenciesGraphic(corpusData); - }); - }); - let tokenCategory = frequenciesTokenCategoryDropdownElement.firstChild.textContent.toLowerCase(); - let graphData = await this.createFrequenciesGraphData(tokenCategory, texts, corpusData, graphtype); + let graphData = await this.createFrequenciesGraphData(tokenCategory, texts, graphtype); let graphLayout = { barmode: graphtype === 'bar' ? 'stack' : '', - margin: { - t: 20, - l: 50 - }, yaxis: { showticklabels: graphtype === 'markers' ? false : true }, @@ -177,44 +258,48 @@ class CorpusAnalysisStaticVisualization { Plotly.newPlot(frequenciesGraphicElement, graphData, graphLayout, config); } - async createFrequenciesGraphData(category, texts, corpusData, graphtype) { + async createFrequenciesGraphData(tokenCategory, texts, graphtype) { + let corpusData = this.data.corpus.o.staticData; let stopwords = this.data.stopwords; if (this.data.stopwords === undefined) { stopwords = await this.getStopwords(); } let stopwordList = Object.values(stopwords).flat(); let graphData = []; - let filteredData = Object.entries(corpusData.corpus.freqs[category]) + let filteredData = Object.entries(corpusData.corpus.freqs[tokenCategory]) .sort((a, b) => b[1] - a[1]) - .filter(item => !stopwordList.includes(corpusData.values.p_attrs[category][item[0]].toLowerCase())) + .filter(item => !stopwordList.includes(corpusData.values.p_attrs[tokenCategory][item[0]].toLowerCase())) .slice(0, 5); - if (graphtype !== 'markers') { - for (let item of filteredData) { - let data = { - x: texts.map(text => `${corpusData.values.s_attrs.text[text[0]].title} (${corpusData.values.s_attrs.text[text[0]].publishing_year})`), - y: texts.map(text => text[1].freqs[category][item[0]] || 0), - name: corpusData.values.p_attrs[category][item[0]], - type: graphtype - }; - graphData.push(data); - } - } else { - for (let item of filteredData) { - let size = texts.map(text => text[1].freqs[category][item[0]] || 0); - let data = { - x: texts.map(text => `${corpusData.values.s_attrs.text[text[0]].title} (${corpusData.values.s_attrs.text[text[0]].publishing_year})`), - y: texts.map(text => corpusData.values.p_attrs[category][item[0]]), - name: corpusData.values.p_attrs[category][item[0]], - text: texts.map(text => `${corpusData.values.p_attrs[category][item[0]]}<br>${text[1].freqs[category][item[0]] || 0}`), - mode: 'markers', - marker: { - size: size, - sizeref: 0.4 - } - }; - graphData.push(data); - } + switch (graphtype) { + case 'markers': + for (let item of filteredData) { + let size = texts.map(text => text[1].freqs[tokenCategory][item[0]] || 0); + let data = { + x: texts.map(text => `${corpusData.values.s_attrs.text[text[0]].title} (${corpusData.values.s_attrs.text[text[0]].publishing_year})`), + y: texts.map(text => corpusData.values.p_attrs[tokenCategory][item[0]]), + name: corpusData.values.p_attrs[tokenCategory][item[0]], + text: texts.map(text => `${corpusData.values.p_attrs[tokenCategory][item[0]]}<br>${text[1].freqs[tokenCategory][item[0]] || 0}`), + mode: 'markers', + marker: { + size: size, + sizeref: 0.4 + } + }; + graphData.push(data); + } + break; + default: + for (let item of filteredData) { + let data = { + x: texts.map(text => `${corpusData.values.s_attrs.text[text[0]].title} (${corpusData.values.s_attrs.text[text[0]].publishing_year})`), + y: texts.map(text => text[1].freqs[tokenCategory][item[0]] || 0), + name: corpusData.values.p_attrs[tokenCategory][item[0]], + type: graphtype + }; + graphData.push(data); + } + break; } return graphData; } @@ -320,45 +405,4 @@ class CorpusAnalysisStaticVisualization { } this.buttonRendering(); } - - renderBoundsGraphic() { - let corpusData = this.data.corpus.o.staticData; - let boundsGraphicElement = document.querySelector('#bounds-graphic'); - - let graphData = []; - let texts = Object.entries(corpusData.s_attrs.text.lexicon); - - graphData = [{ - type: 'bar', - x: texts.map(text => text[1].bounds[1] - text[1].bounds[0]), - y: texts.map(text => corpusData.values.s_attrs.text[text[0]].title), - base: texts.map(text => text[1].bounds[0]), - text: texts.map(text => `${corpusData.values.s_attrs.text[text[0]].title} (${corpusData.values.s_attrs.text[text[0]].publishing_year})`), - orientation: 'h', - hovertemplate: '%{base} - %{x} <br>%{y}', - showlegend: false - }]; - - let graphLayout = { - barmode: 'stack', - type: 'bar', - showgrid: false, - xaxis: { - rangemode: 'nonnegative', - autorange: true - }, - yaxis: { - autorange: true, - showticklabels: false - } - }; - - let config = { - responsive: true, - modeBarButtonsToRemove: ['zoom2d', 'select2d', 'lasso2d', 'zoomIn2d', 'zoomOut2d', 'autoScale2d', 'resetScale2d'], - displaylogo: false - }; - - Plotly.newPlot(boundsGraphicElement, graphData, graphLayout, config); - } } diff --git a/app/static/js/ResourceLists/CorpusTextInfoList.js b/app/static/js/ResourceLists/CorpusTextInfoList.js index 8338c70a..f1545d70 100644 --- a/app/static/js/ResourceLists/CorpusTextInfoList.js +++ b/app/static/js/ResourceLists/CorpusTextInfoList.js @@ -7,7 +7,7 @@ class CorpusTextInfoList extends ResourceList { } static defaultOptions = { - page: 4 + page: 5 }; constructor(listContainerElement, options = {}) { @@ -67,12 +67,12 @@ class CorpusTextInfoList extends ResourceList { <thead> <tr> <th>Text<span class="sort right material-icons" data-sort="title" style="cursor:pointer; color:#aa9cc9">arrow_drop_down</span></th> - <th>Number of tokens<span class="sort right material-icons" data-sort="num_tokens" style="cursor:pointer">arrow_drop_down</span></th> - <th>Number of sentences<span class="sort right material-icons" data-sort="num_sentences" style="cursor:pointer">arrow_drop_down</span></th> - <th>Number of unique words<span class="sort right material-icons" data-sort="num_unique_words" style="cursor:pointer">arrow_drop_down</span></th> - <th>Number of unique lemmas<span class="sort right material-icons" data-sort="num_unique_lemmas" style="cursor:pointer">arrow_drop_down</span></th> - <th>Number of unique pos<span class="sort right material-icons" data-sort="num_unique_pos" style="cursor:pointer">arrow_drop_down</span></th> - <th>Number of unique simple pos<span class="sort right material-icons" data-sort="num_unique_simple_pos" style="cursor:pointer">arrow_drop_down</span></th> + <th>Tokens<span class="sort right material-icons" data-sort="num_tokens" style="cursor:pointer">arrow_drop_down</span></th> + <th>Sentences<span class="sort right material-icons" data-sort="num_sentences" style="cursor:pointer">arrow_drop_down</span></th> + <th>Unique words<span class="sort right material-icons" data-sort="num_unique_words" style="cursor:pointer">arrow_drop_down</span></th> + <th>Unique lemmas<span class="sort right material-icons" data-sort="num_unique_lemmas" style="cursor:pointer">arrow_drop_down</span></th> + <th>Unique pos<span class="sort right material-icons" data-sort="num_unique_pos" style="cursor:pointer">arrow_drop_down</span></th> + <th>Unique simple pos<span class="sort right material-icons" data-sort="num_unique_simple_pos" style="cursor:pointer">arrow_drop_down</span></th> </tr> </thead> <tbody class="list"></tbody> diff --git a/app/static/js/ResourceLists/CorpusTokenList.js b/app/static/js/ResourceLists/CorpusTokenList.js new file mode 100644 index 00000000..1b992038 --- /dev/null +++ b/app/static/js/ResourceLists/CorpusTokenList.js @@ -0,0 +1,121 @@ +class CorpusTokenList extends ResourceList { + static autoInit() { + for (let corpusTokenListElement of document.querySelectorAll('.corpus-token-list:not(.no-autoinit)')) { + new CorpusTokenList(corpusTokenListElement); + } + } + + static defaultOptions = { + page: 100 + }; + + constructor(listContainerElement, options = {}) { + let _options = Utils.mergeObjectsDeep( + CorpusTokenList.defaultOptions, + options + ); + super(listContainerElement, _options); + this.listjs.list.addEventListener('click', (event) => {this.onClick(event)}); + this.selectedItemIds = new Set(); + + } + + get item() { + return (values) => { + return ` + <tr class="list-item clickable hoverable"> + <td> + <label class="list-action-trigger" data-list-action="select"> + <input class="select-checkbox" type="checkbox" ${values.mostFrequent ? 'checked="checked"' : ''}> + <span class="disable-on-click"></span> + </label> + </td> + <td><span class="term"></span></td> + <td><span class="count"></span></td> + <td><span class="frequency"></span></td> + </tr> + `.trim(); + } + } + + get valueNames() { + return [ + 'term', + 'count', + 'mostFrequent', + 'frequency' + ]; + } + + initListContainerElement() { + if (!this.listContainerElement.hasAttribute('id')) { + this.listContainerElement.id = Utils.generateElementId('corpus-token-list-'); + } + let listSearchElementId = Utils.generateElementId(`${this.listContainerElement.id}-search-`); + this.listContainerElement.innerHTML = ` + <div class="input-field"> + <i class="material-icons prefix">search</i> + <input id="${listSearchElementId}" class="search" type="text"></input> + <label for="${listSearchElementId}">Search token</label> + </div> + <div class="scrollable-list-container-wrapper" style="height:276px; overflow:scroll;"> + <div class="scrollable-list-container"> + <table> + <thead> + <tr> + <th></th> + <th>Term</th> + <th>Count</th> + <th>Frequency</th> + </tr> + </thead> + <tbody class="list"></tbody> + </table> + </div> + </div> + <ul class="pagination"></ul> + `.trim(); + this.listContainerElement.style.padding = '30px'; + } + + mapResourceToValue(corpusTokenData) { + return { + term: corpusTokenData.term, + count: corpusTokenData.count, + mostFrequent: corpusTokenData.mostFrequent, + frequency: '-' + }; + } + + sort() { + this.listjs.sort('count', {order: 'desc'}); + } + + onClick(event) { + let listItemElement = event.target.closest('.list-item[data-id]'); + if (listItemElement === null) {return;} + let itemId = listItemElement.dataset.id; + let listActionElement = event.target.closest('.list-action-trigger[data-list-action]'); + let listAction = listActionElement === null ? '' : listActionElement.dataset.listAction; + switch (listAction) { + case 'select': { + if (event.target.checked) { + this.selectedItemIds.add(itemId); + } else { + this.selectedItemIds.delete(itemId); + } + this.renderingItemSelection(); + break; + } + default: { + break; + } + } + } + + renderingItemSelection() { + + + } + +} diff --git a/app/static/js/ResourceLists/ResourceList.js b/app/static/js/ResourceLists/ResourceList.js index 959a5fe1..6bc6ac1f 100644 --- a/app/static/js/ResourceLists/ResourceList.js +++ b/app/static/js/ResourceLists/ResourceList.js @@ -16,6 +16,7 @@ class ResourceList { AdminUserList.autoInit(); CorpusFollowerList.autoInit(); CorpusTextInfoList.autoInit(); + CorpusTokenList.autoInit(); } static defaultOptions = { diff --git a/app/templates/_scripts.html.j2 b/app/templates/_scripts.html.j2 index 772a0596..dcf37513 100644 --- a/app/templates/_scripts.html.j2 +++ b/app/templates/_scripts.html.j2 @@ -70,7 +70,8 @@ 'js/ResourceLists/AdminUserList.js', 'js/ResourceLists/CorpusFollowerList.js', 'js/ResourceLists/CorpusTextInfoList.js', - 'js/ResourceLists/DetailledPublicCorpusList.js' + 'js/ResourceLists/DetailledPublicCorpusList.js', + 'js/ResourceLists/CorpusTokenList.js' %} <script src="{{ ASSET_URL }}"></script> {%- endassets %} diff --git a/app/templates/corpora/_analysis/static_visualization.html.j2 b/app/templates/corpora/_analysis/static_visualization.html.j2 index 3e6cfcff..70a0b605 100644 --- a/app/templates/corpora/_analysis/static_visualization.html.j2 +++ b/app/templates/corpora/_analysis/static_visualization.html.j2 @@ -62,58 +62,62 @@ </div> </div> </div> -<div class="row"> - <div class="col s12"> - <div class="card hoverable"> - <div class="card-content"> - <span class="card-title">Text Information Overview</span> - <div class="chip text-count-chip" style="background-color:#6b3f89; color:white""></div> - <div class="corpus-text-info-list no-autoinit"></div> - </div> - </div> - </div> -</div> <div class="row"> <div class="col s4"> <div class="card hoverable"> <div class="card-content"> - <span class="card-title">Proportions</span> + <span class="card-title" id="text-proportions-title-element">Proportions</span> <p>of texts within the corpus</p> - <div id="text-proportions-graphic" style="width:100"></div> + <div id="text-proportions-graphic"></div> + <a class="btn disabled text-proportions-graph-mode-button" data-graph-type="pie"><i class="material-icons">incomplete_circle</i></a> + <a class="btn text-proportions-graph-mode-button" data-graph-type="bar"><i class="material-icons">sort</i></a> </div> </div> </div> <div class="col s8"> <div class="card hoverable"> <div class="card-content"> - <span class="card-title">Frequencies</span> - <ul id="frequencies-token-category-dropdown" class="dropdown-content"> - <li><a data-token-category="word">Word</a></li> - <li><a data-token-category="lemma">Lemma</a></li> - <li><a data-token-category="pos">Pos</a></li> - <li><a data-token-category="simple_pos">Simple_pos</a></li> - </ul> - <p>within the texts of the 5 most frequent words in the corpus</p> - <div id="frequencies-graphic"></div> - <a class="dropdown-trigger btn" data-target="frequencies-token-category-dropdown">Word<i class="material-icons right">arrow_drop_down</i></a> - <a class="btn disabled frequencies-graph-mode-button" data-graph-type="bar"><i class="material-icons">equalizer</i></a> - <a class="btn frequencies-graph-mode-button" data-graph-type="scatter"><i class="material-icons">show_chart</i></a> - <a class="btn frequencies-graph-mode-button" data-graph-type="markers"><i class="material-icons">bubble_chart</i></a> - <a class="btn-flat modal-trigger no-autoinit" id="frequencies-stopwords-setting-modal-button" href="#frequencies-stopwords-setting-modal"><i class="material-icons grey-text text-darken-2">settings</i></a> + <span class="card-title">Text Information Overview</span> + <div class="chip text-count-chip" style="background-color:#6b3f89; color:white""></div> + <div class="corpus-text-info-list no-autoinit"></div> </div> </div> </div> </div> - <div class="row"> <div class="col s12"> <div class="card hoverable"> <div class="card-content"> - <span class="card-title">Text Bounds</span> - <div id="bounds-graphic"></div> + <span class="card-title">Frequencies</span> + <div class="row"> + {# <div class="col s1"></div> #} + <div class="col s5"> + <div class="corpus-token-list no-autoinit"></div> + <a class="dropdown-trigger btn" data-target="frequencies-token-category-dropdown">Word<i class="material-icons right">arrow_drop_down</i></a> + <a class="btn-flat modal-trigger no-autoinit" id="frequencies-stopwords-setting-modal-button" href="#frequencies-stopwords-setting-modal"> + <i class="material-icons grey-text text-darken-2">settings</i> + </a> + <ul id="frequencies-token-category-dropdown" class="dropdown-content"> + <li><a data-token-category="word">Word</a></li> + <li><a data-token-category="lemma">Lemma</a></li> + <li><a data-token-category="pos">Pos</a></li> + <li><a data-token-category="simple_pos">Simple_pos</a></li> + </ul> + </div> + {# <div class="col s1"></div> #} + <div class="col s7"> + <div id="frequencies-graphic"></div> + <a class="btn disabled frequencies-graph-mode-button" data-graph-type="bar"><i class="material-icons">stacked_bar_chart</i></a> + <a class="btn frequencies-graph-mode-button" data-graph-type="scatter"><i class="material-icons">show_chart</i></a> + <a class="btn frequencies-graph-mode-button" data-graph-type="markers"><i class="material-icons">bubble_chart</i></a> + </div> + </div> </div> </div> </div> +</div> +<div class="row"> + </div> {% endset %} diff --git a/app/templates/corpora/analysis.html.j2 b/app/templates/corpora/analysis.html.j2 index 6d7e9622..ee39be59 100644 --- a/app/templates/corpora/analysis.html.j2 +++ b/app/templates/corpora/analysis.html.j2 @@ -36,14 +36,18 @@ {% endif %} {% endfor %} + {{ static_visualization_extension.container_content }} + </div> </div> {% for extension in extensions %} +{% if extension.name != 'Static Visualization'%} <div id="{{ extension.id_prefix }}-container"> {{ extension.container_content }} </div> +{% endif %} {% endfor %} {% endblock page_content %} @@ -66,328 +70,6 @@ {{ extension.modals }} {% endfor %} -<div class="modal" id="concordance-query-builder"> - <div class="modal-content"> - <div> - <nav> - <div class="nav-wrapper" id="query-builder-nav"> - <a href="#!" class="brand-logo"><i class="material-icons">build</i>Query Builder (beta)</a> - <i class="material-icons close right" id="close-query-builder">close</i> - <a class="modal-trigger" data-manual-modal-chapter="manual-modal-query-builder" href="#manual-modal"> - <i class="material-icons right tooltipped" id="query-builder-tutorial-info-icon" data-position="bottom" data-tooltip="Click here if you are unsure how to use the Query Builder <br>and want to find out what other options it offers.">help</i> - </a> - </div> - </nav> - </div> - - <p></p> - - <div id="query-container" class="hide"> - - <div class="row"> - <h6 class="col s2">Your Query: - <a class="modal-trigger" data-manual-modal-chapter="manual-modal-query-builder" href="#manual-modal"> - <i class="material-icons left" id="general-options-query-builder-tutorial-info-icon">help_outline</i></a> - </h6> - </div> - <div class="row"> - <div class="col s10" id="your-query"></div> - <a class="btn-small waves-effect waves-teal col s1" id="insert-query-button"> - <i class="material-icons">send</i> - </a> - </div> - <p><i> Preview:</i></p> - <p id="query-preview"></p> - <br> - </div> - - - <h6>Use the following options to build your query. If you need help, click on the question mark in the upper right corner!</h6> - <p></p> - <a class="btn-large waves-effect waves-light tooltipped" id="positional-attr-button" data-position="bottom" data-tooltip="Search for any token, for example a word, a lemma or a part-of-speech tag">Add new token to your query</a> - <a class="btn-large waves-effect waves-light tooltipped" id="structural-attr-button" data-position="bottom" data-tooltip="Structure your query with structural attributes, for example sentences, entities or annotate the text">Add structural attributes to your query</a> - - <div id="structural-attr" class="hide"> - <p></p> - <h6>Which structural attribute do you want to add to your query?<a class="modal-trigger" data-manual-modal-chapter="manual-modal-query-builder" href="#manual-modal"><i class="material-icons left" id="add-structural-attribute-tutorial-info-icon">help_outline</i></a></h6> - <p></p> - <div class="row"> - <div class="col s12"> - <a class="btn-small waves-effect waves-light" id="sentence">sentence</a> - <a class="btn-small waves-effect waves-light" id="entity">entity</a> - <a class="btn-small waves-effect waves-light" id="text-annotation">Meta Data</a> - </div> - </div> - - - <div id="entity-builder" class="hide"> - <p></p> - <br> - <div class="row"> - <a class="btn waves-effect waves-light col s4" id="empty-entity">Add Entity of any type</a> - <p class="col s1 l1"></p> - <div class= "input-field col s3"> - <select name="englishenttype" id="english-ent-type"> - <option value="" disabled selected>English ent_type</option> - <option value="CARDINAL">CARDINAL</option> - <option value="DATE">DATE</option> - <option value="EVENT">EVENT</option> - <option value="FAC">FAC</option> - <option value="GPE">GPE</option> - <option value="LANGUAGE">LANGUAGE</option> - <option value="LAW">LAW</option> - <option value="LOC">LOC</option> - <option value="MONEY">MONEY</option> - <option value="NORP">NORP</option> - <option value="ORDINAL">ORDINAL</option> - <option value="ORG">ORG</option> - <option value="PERCENT">PERCENT</option> - <option value="PERSON">PERSON</option> - <option value="PRODUCT">PRODUCT</option> - <option value="QUANTITY">QUANTITY</option> - <option value="TIME">TIME</option> - <option value="WORK_OF_ART">WORK_OF_ART</option> - </select> - <label>Entity Type</label> - </div> - <div class= "input-field col s3"> - <select name="germanenttype" id="german-ent-type"> - <option value="" disabled selected>German ent_type</option> - <option value="LOC">LOC</option> - <option value="MISC">MISC</option> - <option value="ORG">ORG</option> - <option value="PER">PER</option> - </select> - </div> - </div> - </div> - - - <div id="text-annotation-builder" class="hide"> - <p></p> - <br> - <div class="row"> - <div class= "input-field col s4 l3"> - <select name="text-annotation-options" id="text-annotation-options"> - <option class="btn-small waves-effect waves-light" value="address">address</option> - <option class="btn-small waves-effect waves-light" value="author">author</option> - <option class="btn-small waves-effect waves-light" value="booktitle">booktitle</option> - <option class="btn-small waves-effect waves-light" value="chapter">chapter</option> - <option class="btn-small waves-effect waves-light" value="editor">editor</option> - <option class="btn-small waves-effect waves-light" value="institution">institution</option> - <option class="btn-small waves-effect waves-light" value="journal">journal</option> - <option class="btn-small waves-effect waves-light" value="pages">pages</option> - <option class="btn-small waves-effect waves-light" value="publisher">publisher</option> - <option class="btn-small waves-effect waves-light" value="publishing_year">publishing year</option> - <option class="btn-small waves-effect waves-light" value="school">school</option> - <option class="btn-small waves-effect waves-light" value="title">title</option> - </select> - <label>Meta data</label> - </div> - <div class= "input-field col s7 l5"> - <i class="material-icons prefix">mode_edit</i> - <input placeholder="Type in your text annotation" type="text" id="text-annotation-input"> - </div> - <div class="col s1 l1 center-align"> - <p class="btn-floating waves-effect waves-light" id="text-annotation-submit"> - <i class="material-icons right">send</i> - </p> - </div> - <div class="hide" id="no-value-metadata-message"><i>No value entered!</i></div> - </div> - </div> - </div> - - <div id="positional-attr" class="hide"> - <p></p> - <div class="row" id="token-kind-selector"> - <div class="col s5"> - <h6>Which kind of token are you looking for? <a class="modal-trigger" data-manual-modal-chapter="manual-modal-query-builder" href="#manual-modal"><i class="material-icons left" id="token-tutorial-info-icon">help_outline</i></a></h6> - </div> - <div class="input-field col s3"> - <select id="token-attr"> - <option value="word" selected>word</option> - <option value="lemma">lemma</option> - <option value="english-pos">english pos</option> - <option value="german-pos">german pos</option> - <option value="simple-pos-button">simple_pos</option> - <option value="empty-token">empty token</option> - </select> - </div> - </div> - <p></p> - <div id="token-builder-content"> - <div class="row" > - <div id="token-query"></div> - - <div id="word-builder"> - <div class= "input-field col s3 l4"> - <i class="material-icons prefix">mode_edit</i> - <input placeholder="Type in your word" type="text" id="word-input"> - </div> - </div> - - <div id="lemma-builder" class="hide" > - <div class= "input-field col s3 l4"> - <i class="material-icons prefix">mode_edit</i> - <input placeholder="Type in your lemma" type="text" id="lemma-input"> - </div> - </div> - - <div id="english-pos-builder" class="hide"> - <div class="col s6 m4 l4"> - <div class="row"> - <div class= "input-field col s12"> - <select name="englishpos" id="english-pos"> - <option value="default" disabled selected>English pos tagset</option> - <option value="ADD">email</option> - <option value="AFX">affix</option> - <option value="CC">conjunction, coordinating</option> - <option value="CD">cardinal number</option> - <option value="DT">determiner</option> - <option value="EX">existential there</option> - <option value="FW">foreign word</option> - <option value="HYPH">punctuation mark, hyphen</option> - <option value="IN">conjunction, subordinating or preposition</option> - <option value="JJ">adjective</option> - <option value="JJR">adjective, comparative</option> - <option value="JJS">adjective, superlative</option> - </select> - <label>Part-of-speech tags</label> - </div> - </div> - </div> - </div> - - <div id="german-pos-builder" class="hide"> - <div class="col s6 m4 l4"> - <div class="row"> - <div class= "input-field col s12"> - <select name="germanpos" id="german-pos"> - <option value="default" disabled selected>German pos tagset</option> - <option value="ADJA">adjective, attributive</option> - <option value="ADJD">adjective, adverbial or predicative</option> - <option value="ADV">adverb</option> - <option value="APPO">postposition</option> - <option value="APPR">preposition; circumposition left</option> - <option value="APPRART">preposition with article</option> - <option value="APZR">circumposition right</option> - <option value="ART">definite or indefinite article</option> - </select> - <label>Part-of-speech tags</label> - </div> - </div> - </div> - </div> - - <div id="simplepos-builder" class="hide"> - <div class="col s6 m4 l4"> - <div class="row"> - <div class= "input-field col s12"> - <select name="simplepos" id="simple-pos"> - <option value="default" disabled selected>simple_pos tagset</option> - <option value="ADJ">adjective</option> - <option value="ADP">adposition</option> - <option value="ADV">adverb</option> - <option value="AUX">auxiliary verb</option> - <option value="CONJ">coordinating conjunction</option> - <option value="DET">determiner</option> - <option value="INTJ">interjection</option> - <option value="NOUN">noun</option> - <option value="NUM">numeral</option> - <option value="PART">particle</option> - <option value="PRON">pronoun</option> - <option value="PROPN">proper noun</option> - <option value="PUNCT">punctuation</option> - <option value="SCONJ">subordinating conjunction</option> - <option value="SYM">symbol</option> - <option value="VERB">verb</option> - <option value="X">other</option> - </select> - <label>Simple part-of-speech tags</label> - </div> - </div> - </div> - </div> - <div class="col s1 l1 center-align"> - <p class="btn-floating waves-effect waves-light" id="token-submit"> - <i class="material-icons right">send</i> - </p> - </div> - <div class="hide" id="no-value-message"><i>No value entered!</i></div> - </div> - <div id="token-edit-options"> - <div class="row"> - <h6>Options to edit your token: <a class="modal-trigger" data-manual-modal-chapter="manual-modal-query-builder" href="#manual-modal"><i class="material-icons left" id="edit-options-tutorial-info-icon">help_outline</i></a></h6> - </div> - <p></p> - <div class="row"> - <div id="input-options" class="col s5 m5 l5 xl4"> - <a id="wildcard-char" class="btn-small waves-effect waves-light tooltipped" data-position="top" data-tooltip="Look for a variable character (also called wildcard character)">Wildcard character</a> - <a id="option-group" class="btn-small waves-effect waves-light tooltipped" data-position="top" data-tooltip="Find character sequences from a list of options">Option Group</a> - </div> - <div class="col s3 m3 l3 xl3" id="incidence-modifiers-button"> - <a class="dropdown-trigger btn-small waves-effect waves-light" href="#" data-target="incidence-modifiers" data-position="top" data-tooltip="Incidence Modifiers are special characters or patterns, <br>which determine how often a character represented previously should occur.">incidence modifiers</a> - </div> - - <ul id="incidence-modifiers" class="dropdown-content"> - <li><a id="one-or-more" data-token="+" class="tooltipped" data-position ="top" data-tooltip="...occurrences of the character/token before">one or more (+)</a></li> - <li><a id="zero-or-more" data-token="*" class="tooltipped" data-position ="top" data-tooltip="...occurrences of the character/token before">zero or more (*)</a></li> - <li><a id="zero-or-one" data-token="?" class="tooltipped" data-position ="top" data-tooltip="...occurrences of the character/token before">zero or one (?)</a></li> - <li><a id="exactly-n" class="modal-trigger tooltipped" href="#exactlyN" data-token="{n}" class="" data-position ="top" data-tooltip="...occurrences of the character/token before">exactly n ({n})</a></li> - <li><a id="between-n-m" class="modal-trigger tooltipped" href="#betweenNM" data-token="{n,m}" class="" data-position ="top" data-tooltip="...occurrences of the character/token before">between n and m ({n,m})</a></li> - </ul> - - <div id="ignore-case-checkbox" class="col s2 m2 l2 xl2"> - <p id="ignore-case"> - <label> - <input type="checkbox" class="filled-in" /> - <span>Ignore Case</span> - </label> - </p> - </div> - <div class="col s2 m2 l2 xl2" id="condition-container"> - <a class="btn-small tooltipped waves-effect waves-light" id="or" data-position="bottom" data-tooltip="You can add another condition to your token. <br>At least one must be fulfilled">or</a> - <a class="btn-small tooltipped waves-effect waves-light" id="and" data-position="bottom" data-tooltip="You can add another condition to your token. <br>Both must be fulfilled">and</a> - </div> - </div> - </div> - </div> - <div id="exactlyN" class="modal"> - <div class="row modal-content"> - <div class="input-field col s10"> - <i class="material-icons prefix">mode_edit</i> - <input placeholder="type in a number for 'n'" type="text" id="n-input"> - </div> - <div class="col s2"> - <p class="btn-floating waves-effect waves-light" id="n-submit"> - <i class="material-icons right">send</i> - </p> - </div> - </div> - </div> - - <div id="betweenNM" class="modal"> - <div class="row modal-content"> - <div class= "input-field col s5"> - <i class="material-icons prefix">mode_edit</i> - <input placeholder="number for 'n'" type="text" id="n-m-input"> - </div> - <div class= "input-field col s5"> - <i class="material-icons prefix">mode_edit</i> - <input placeholder="number for 'm'" type="text" id="m-input"> - </div> - <div class="col s2"> - <p class="btn-floating waves-effect waves-light" id="n-m-submit"> - <i class="material-icons right">send</i> - </p> - </div> - </div> - </div> - </div> - - </div> -</div> {% endblock modals %} {% block scripts %} -- GitLab