diff --git a/app/static/js/CorpusAnalysis/CorpusAnalysisApp.js b/app/static/js/CorpusAnalysis/CorpusAnalysisApp.js
index 7f0462d5..25f58a65 100644
--- a/app/static/js/CorpusAnalysis/CorpusAnalysisApp.js
+++ b/app/static/js/CorpusAnalysis/CorpusAnalysisApp.js
@@ -1,11 +1,6 @@
class CorpusAnalysisApp {
constructor(corpusId) {
- this.data = {
- stopwords: undefined,
- originalStopwords: {},
- stopwordCache: {},
- promises: {getStopwords: undefined}
- };
+ this.data = {};
// HTML elements
this.elements = {
@@ -27,24 +22,6 @@ class CorpusAnalysisApp {
};
}
- getStopwords() {
- this.data.promises.getStopwords = new Promise((resolve, reject) => {
- Requests.corpora.entity.getStopwords()
- .then((response) => {
- response.json()
- .then((json) => {
- this.data.originalStopwords = structuredClone(json);
- this.data.stopwords = structuredClone(json);
- resolve(this.data.stopwords);
- })
- .catch((error) => {
- reject(error);
- });
- });
- });
- return this.data.promises.getStopwords;
- }
-
init() {
this.disableActionElements();
this.elements.m.initModal.open();
@@ -57,11 +34,12 @@ 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();
+ // this.renderGeneralCorpusInfo();
+ // this.renderTextInfoList();
+ // this.renderTextProportionsGraphic()
+ // this.renderFrequenciesGraphic();
+ // this.renderBoundsGraphic();
+
// TODO: Don't do this hgere
this.data.corpus.o.updateDb();
this.enableActionElements();
@@ -78,7 +56,6 @@ class CorpusAnalysisApp {
progressElement.classList.add('hide');
}
);
-
// Add event listeners
for (let extensionSelectorElement of this.elements.overview.querySelectorAll('.extension-selector')) {
@@ -86,25 +63,6 @@ class CorpusAnalysisApp {
this.elements.m.extensionTabs.select(extensionSelectorElement.dataset.target);
});
}
-
- let frequenciesStopwordSettingModal = document.querySelector('#frequencies-stopwords-setting-modal');
- let frequenciesStopwordSettingModalButton = document.querySelector('#frequencies-stopwords-setting-modal-button');
- frequenciesStopwordSettingModalButton.addEventListener('click', () => {
- this.data.stopwordCache = structuredClone(this.data.stopwords);
- this.renderStopwordSettingsModal(this.data.stopwords);
- M.Modal.init(frequenciesStopwordSettingModal, {dismissible: false});
- });
-
- 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;
- if (action === 'submit') {
- this.renderFrequenciesGraphic();
- } else if (action === 'cancel') {
- this.data.stopwords = structuredClone(this.data.stopwordCache);
- }
- });
- }
}
registerExtension(extension) {
@@ -141,306 +99,4 @@ class CorpusAnalysisApp {
}
}
}
-
- renderGeneralCorpusInfo() {
- let corpusData = this.data.corpus.o.staticData;
- document.querySelector('.corpus-num-tokens').innerHTML = corpusData.corpus.counts.token;
- document.querySelector('.corpus-num-s').innerHTML = corpusData.corpus.counts.s;
- document.querySelector('.corpus-num-unique-words').innerHTML = Object.entries(corpusData.corpus.freqs.word).length;
- document.querySelector('.corpus-num-unique-lemmas').innerHTML = Object.entries(corpusData.corpus.freqs.lemma).length;
- document.querySelector('.corpus-num-unique-pos').innerHTML = Object.entries(corpusData.corpus.freqs.pos).length;
- document.querySelector('.corpus-num-unique-simple-pos').innerHTML = Object.entries(corpusData.corpus.freqs.simple_pos).length;
- }
-
- renderTextInfoList() {
- let corpusData = this.data.corpus.o.staticData;
- let corpusTextInfoListElement = document.querySelector('.corpus-text-info-list');
- let corpusTextInfoList = new CorpusTextInfoList(corpusTextInfoListElement);
- let texts = corpusData.s_attrs.text.lexicon;
- let textData = [];
- for (let i = 0; i < Object.entries(texts).length; i++) {
- let resource = {
- title: corpusData.values.s_attrs.text[i].title,
- publishing_year: corpusData.values.s_attrs.text[i].publishing_year,
- num_tokens: corpusData.s_attrs.text.lexicon[i].counts.token,
- num_sentences: corpusData.s_attrs.text.lexicon[i].counts.s,
- num_unique_words: Object.entries(corpusData.s_attrs.text.lexicon[i].freqs.word).length,
- num_unique_lemmas: Object.entries(corpusData.s_attrs.text.lexicon[i].freqs.lemma).length,
- num_unique_pos: Object.entries(corpusData.s_attrs.text.lexicon[i].freqs.pos).length,
- num_unique_simple_pos: Object.entries(corpusData.s_attrs.text.lexicon[i].freqs.simple_pos).length
- };
-
- textData.push(resource);
- }
-
- corpusTextInfoList.add(textData);
-
- let textCountChipElement = document.querySelector('.text-count-chip');
- textCountChipElement.innerHTML = `Text count: ${corpusData.corpus.counts.text}`;
- }
-
- renderTextProportionsGraphic() {
- 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 graphLayout = {
- showlegend: true,
- height: 486,
- margin: {
- l: 10,
- r: 10,
- b: 10,
- t: 10
- },
- legend: {
- "orientation": "h",
- font: {
- size: 10
- }
- }
- };
- let config = {
- responsive: true,
- displaylogo: false
- };
-
- Plotly.newPlot(textProportionsGraphicElement, graphData, graphLayout, config);
- }
-
- 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 graphLayout = {
- barmode: graphtype === 'bar' ? 'stack' : '',
- margin: {
- t: 20,
- l: 50
- },
- yaxis: {
- showticklabels: graphtype === 'markers' ? false : true
- },
- };
- let config = {
- responsive: true,
- modeBarButtonsToRemove: ['zoom2d', 'select2d', 'lasso2d', 'zoomIn2d', 'zoomOut2d', 'autoScale2d', 'resetScale2d'],
- displaylogo: false
- };
- Plotly.newPlot(frequenciesGraphicElement, graphData, graphLayout, config);
- }
-
- async createFrequenciesGraphData(category, texts, corpusData, graphtype) {
- 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])
- .sort((a, b) => b[1] - a[1])
- .filter(item => !stopwordList.includes(corpusData.values.p_attrs[category][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]]}
${text[1].freqs[category][item[0]] || 0}`),
- mode: 'markers',
- marker: {
- size: size,
- sizeref: 0.4
- }
- };
- graphData.push(data);
- }
- }
- return graphData;
- }
-
- renderStopwordSettingsModal(stopwords) {
- let stopwordInputField = document.querySelector('#stopword-input-field');
- let userStopwordListContainer = document.querySelector('#user-stopword-list-container');
- let stopwordLanguageSelection = document.querySelector('#stopword-language-selection');
- let stopwordLanguageChipList = document.querySelector('#stopword-language-chip-list');
- let deleteLanguageStopwordListEntriesButton = document.querySelector('#delete-language-stopword-list-entries-button');
- let resetLanguageStopwordListEntriesButton = document.querySelector('#reset-language-stopword-list-entries-button');
-
- stopwordLanguageChipList.innerHTML = '';
- userStopwordListContainer.innerHTML = '';
- stopwordInputField.value = '';
-
- // Render stopword language selection. Set english as default language. Filter out user_stopwords.
- if (stopwordLanguageSelection.children.length === 0) {
- Object.keys(stopwords).forEach(language => {
- if (language !== 'user_stopwords') {
- let optionElement = Utils.HTMLToElement(``);
- stopwordLanguageSelection.appendChild(optionElement);
- }
- });
- }
-
- // Render user stopwords over input field.
- if (this.data.stopwords['user_stopwords'].length > 0) {
- for (let word of this.data.stopwords['user_stopwords']) {
- let chipElement = Utils.HTMLToElement(`
${word}close
`);
- chipElement.addEventListener('click', (event) => {
- let removedListItem = event.target.closest('.chip').firstChild.textContent;
- this.data.stopwords['user_stopwords'] = structuredClone(this.data.stopwords['user_stopwords'].filter(item => item !== removedListItem));
- });
- userStopwordListContainer.appendChild(chipElement);
- }
- }
-
- // Render english stopwords as default ...
- let selectedLanguage = document.querySelector('#stopword-language-selection').value;
- this.renderStopwordLanguageChipList(selectedLanguage, stopwords[selectedLanguage]);
-
- // ... or render selected language stopwords.
- stopwordLanguageSelection.addEventListener('change', (event) => {
- this.renderStopwordLanguageChipList(event.target.value, stopwords[event.target.value]);
- });
-
- // Eventlistener for deleting all stopwords of a language.
- deleteLanguageStopwordListEntriesButton.addEventListener('click', (event) => {
- let selectedLanguage = stopwordLanguageSelection.value;
- this.data.stopwords[selectedLanguage] = [];
- stopwordLanguageChipList.innerHTML = '';
- this.buttonRendering();
- });
-
- // Eventlistener for resetting all stopwords of a language to the original stopwords.
- resetLanguageStopwordListEntriesButton.addEventListener('click', () => {
- let selectedLanguage = stopwordLanguageSelection.value;
- this.data.stopwords[selectedLanguage] = structuredClone(this.data.originalStopwords[selectedLanguage]);
- this.renderStopwordLanguageChipList(selectedLanguage, this.data.stopwords[selectedLanguage]);
- });
-
- // Initialize Materialize components.
- M.Chips.init(
- stopwordInputField,
- {
- placeholder: 'Add stopwords',
- onChipAdd: (event) => {
- for (let word of event[0].M_Chips.chipsData) {
- if (!this.data.stopwords['user_stopwords'].includes(word.tag.toLowerCase())) {
- this.data.stopwords['user_stopwords'].push(word.tag.toLowerCase());
- }
- }
- }
- }
- );
- M.FormSelect.init(stopwordLanguageSelection);
-
- }
-
- buttonRendering() {
- let deleteLanguageStopwordListEntriesButton = document.querySelector('#delete-language-stopword-list-entries-button');
- let resetLanguageStopwordListEntriesButton = document.querySelector('#reset-language-stopword-list-entries-button');
- let selectedLanguage = document.querySelector('#stopword-language-selection').value;
- let stopwordLength = this.data.stopwords[selectedLanguage].length;
- let originalStopwordListLength = this.data.originalStopwords[selectedLanguage].length;
-
- deleteLanguageStopwordListEntriesButton.classList.toggle('disabled', stopwordLength === 0);
- resetLanguageStopwordListEntriesButton.classList.toggle('disabled', stopwordLength === originalStopwordListLength);
- }
-
- renderStopwordLanguageChipList(language, stopwords) {
- let stopwordLanguageChipList = document.querySelector('#stopword-language-chip-list');
- stopwordLanguageChipList.innerHTML = '';
- for (let word of stopwords) {
- let chipElement = Utils.HTMLToElement(`${word}close
`);
- chipElement.addEventListener('click', (event) => {
- let removedListItem = event.target.closest('.chip').firstChild.textContent;
- this.data.stopwords[language] = structuredClone(this.data.stopwords[language].filter(item => item !== removedListItem));
- this.buttonRendering();
- });
- stopwordLanguageChipList.appendChild(chipElement);
- }
- 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}
%{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/CorpusAnalysis/CorpusAnalysisStaticVisualization.js b/app/static/js/CorpusAnalysis/CorpusAnalysisStaticVisualization.js
new file mode 100644
index 00000000..81e1d466
--- /dev/null
+++ b/app/static/js/CorpusAnalysis/CorpusAnalysisStaticVisualization.js
@@ -0,0 +1,364 @@
+class CorpusAnalysisStaticVisualization {
+ name = 'Static Visualization';
+
+ constructor(app) {
+ this.app = app;
+ this.data = {
+ stopwords: undefined,
+ originalStopwords: {},
+ stopwordCache: {},
+ promises: {getStopwords: undefined}
+ };
+
+ this.app.registerExtension(this);
+ }
+
+ init() {
+ // Init data
+ this.data.corpus = this.app.data.corpus;
+ this.renderGeneralCorpusInfo();
+ this.renderTextInfoList();
+ this.renderTextProportionsGraphic()
+ this.renderFrequenciesGraphic();
+ this.renderBoundsGraphic();
+ // Add event listeners
+ let frequenciesStopwordSettingModal = document.querySelector('#frequencies-stopwords-setting-modal');
+ let frequenciesStopwordSettingModalButton = document.querySelector('#frequencies-stopwords-setting-modal-button');
+ frequenciesStopwordSettingModalButton.addEventListener('click', () => {
+ this.data.stopwordCache = structuredClone(this.data.stopwords);
+ this.renderStopwordSettingsModal(this.data.stopwords);
+ M.Modal.init(frequenciesStopwordSettingModal, {dismissible: false});
+ });
+
+ 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;
+ if (action === 'submit') {
+ this.renderFrequenciesGraphic();
+ } else if (action === 'cancel') {
+ this.data.stopwords = structuredClone(this.data.stopwordCache);
+ }
+ });
+ }
+ }
+
+ getStopwords() {
+ this.data.promises.getStopwords = new Promise((resolve, reject) => {
+ Requests.corpora.entity.getStopwords()
+ .then((response) => {
+ response.json()
+ .then((json) => {
+ this.data.originalStopwords = structuredClone(json);
+ this.data.stopwords = structuredClone(json);
+ resolve(this.data.stopwords);
+ })
+ .catch((error) => {
+ reject(error);
+ });
+ });
+ });
+ return this.data.promises.getStopwords;
+ }
+
+ renderGeneralCorpusInfo() {
+ let corpusData = this.data.corpus.o.staticData;
+ document.querySelector('.corpus-num-tokens').innerHTML = corpusData.corpus.counts.token;
+ document.querySelector('.corpus-num-s').innerHTML = corpusData.corpus.counts.s;
+ document.querySelector('.corpus-num-unique-words').innerHTML = Object.entries(corpusData.corpus.freqs.word).length;
+ document.querySelector('.corpus-num-unique-lemmas').innerHTML = Object.entries(corpusData.corpus.freqs.lemma).length;
+ document.querySelector('.corpus-num-unique-pos').innerHTML = Object.entries(corpusData.corpus.freqs.pos).length;
+ document.querySelector('.corpus-num-unique-simple-pos').innerHTML = Object.entries(corpusData.corpus.freqs.simple_pos).length;
+ }
+
+ renderTextInfoList() {
+ let corpusData = this.data.corpus.o.staticData;
+ let corpusTextInfoListElement = document.querySelector('.corpus-text-info-list');
+ let corpusTextInfoList = new CorpusTextInfoList(corpusTextInfoListElement);
+ let texts = corpusData.s_attrs.text.lexicon;
+ let textData = [];
+ for (let i = 0; i < Object.entries(texts).length; i++) {
+ let resource = {
+ title: corpusData.values.s_attrs.text[i].title,
+ publishing_year: corpusData.values.s_attrs.text[i].publishing_year,
+ num_tokens: corpusData.s_attrs.text.lexicon[i].counts.token,
+ num_sentences: corpusData.s_attrs.text.lexicon[i].counts.s,
+ num_unique_words: Object.entries(corpusData.s_attrs.text.lexicon[i].freqs.word).length,
+ num_unique_lemmas: Object.entries(corpusData.s_attrs.text.lexicon[i].freqs.lemma).length,
+ num_unique_pos: Object.entries(corpusData.s_attrs.text.lexicon[i].freqs.pos).length,
+ num_unique_simple_pos: Object.entries(corpusData.s_attrs.text.lexicon[i].freqs.simple_pos).length
+ };
+
+ textData.push(resource);
+ }
+
+ corpusTextInfoList.add(textData);
+
+ let textCountChipElement = document.querySelector('.text-count-chip');
+ textCountChipElement.innerHTML = `Text count: ${corpusData.corpus.counts.text}`;
+ }
+
+ renderTextProportionsGraphic() {
+ 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 graphLayout = {
+ showlegend: true,
+ height: 486,
+ margin: {
+ l: 10,
+ r: 10,
+ b: 10,
+ t: 10
+ },
+ legend: {
+ "orientation": "h",
+ font: {
+ size: 10
+ }
+ }
+ };
+ let config = {
+ responsive: true,
+ displaylogo: false
+ };
+
+ Plotly.newPlot(textProportionsGraphicElement, graphData, graphLayout, config);
+ }
+
+ 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 graphLayout = {
+ barmode: graphtype === 'bar' ? 'stack' : '',
+ margin: {
+ t: 20,
+ l: 50
+ },
+ yaxis: {
+ showticklabels: graphtype === 'markers' ? false : true
+ },
+ };
+ let config = {
+ responsive: true,
+ modeBarButtonsToRemove: ['zoom2d', 'select2d', 'lasso2d', 'zoomIn2d', 'zoomOut2d', 'autoScale2d', 'resetScale2d'],
+ displaylogo: false
+ };
+ Plotly.newPlot(frequenciesGraphicElement, graphData, graphLayout, config);
+ }
+
+ async createFrequenciesGraphData(category, texts, corpusData, graphtype) {
+ 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])
+ .sort((a, b) => b[1] - a[1])
+ .filter(item => !stopwordList.includes(corpusData.values.p_attrs[category][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]]}
${text[1].freqs[category][item[0]] || 0}`),
+ mode: 'markers',
+ marker: {
+ size: size,
+ sizeref: 0.4
+ }
+ };
+ graphData.push(data);
+ }
+ }
+ return graphData;
+ }
+
+ renderStopwordSettingsModal(stopwords) {
+ let stopwordInputField = document.querySelector('#stopword-input-field');
+ let userStopwordListContainer = document.querySelector('#user-stopword-list-container');
+ let stopwordLanguageSelection = document.querySelector('#stopword-language-selection');
+ let stopwordLanguageChipList = document.querySelector('#stopword-language-chip-list');
+ let deleteLanguageStopwordListEntriesButton = document.querySelector('#delete-language-stopword-list-entries-button');
+ let resetLanguageStopwordListEntriesButton = document.querySelector('#reset-language-stopword-list-entries-button');
+
+ stopwordLanguageChipList.innerHTML = '';
+ userStopwordListContainer.innerHTML = '';
+ stopwordInputField.value = '';
+
+ // Render stopword language selection. Set english as default language. Filter out user_stopwords.
+ if (stopwordLanguageSelection.children.length === 0) {
+ Object.keys(stopwords).forEach(language => {
+ if (language !== 'user_stopwords') {
+ let optionElement = Utils.HTMLToElement(``);
+ stopwordLanguageSelection.appendChild(optionElement);
+ }
+ });
+ }
+
+ // Render user stopwords over input field.
+ if (this.data.stopwords['user_stopwords'].length > 0) {
+ for (let word of this.data.stopwords['user_stopwords']) {
+ let chipElement = Utils.HTMLToElement(`${word}close
`);
+ chipElement.addEventListener('click', (event) => {
+ let removedListItem = event.target.closest('.chip').firstChild.textContent;
+ this.data.stopwords['user_stopwords'] = structuredClone(this.data.stopwords['user_stopwords'].filter(item => item !== removedListItem));
+ });
+ userStopwordListContainer.appendChild(chipElement);
+ }
+ }
+
+ // Render english stopwords as default ...
+ let selectedLanguage = document.querySelector('#stopword-language-selection').value;
+ this.renderStopwordLanguageChipList(selectedLanguage, stopwords[selectedLanguage]);
+
+ // ... or render selected language stopwords.
+ stopwordLanguageSelection.addEventListener('change', (event) => {
+ this.renderStopwordLanguageChipList(event.target.value, stopwords[event.target.value]);
+ });
+
+ // Eventlistener for deleting all stopwords of a language.
+ deleteLanguageStopwordListEntriesButton.addEventListener('click', (event) => {
+ let selectedLanguage = stopwordLanguageSelection.value;
+ this.data.stopwords[selectedLanguage] = [];
+ stopwordLanguageChipList.innerHTML = '';
+ this.buttonRendering();
+ });
+
+ // Eventlistener for resetting all stopwords of a language to the original stopwords.
+ resetLanguageStopwordListEntriesButton.addEventListener('click', () => {
+ let selectedLanguage = stopwordLanguageSelection.value;
+ this.data.stopwords[selectedLanguage] = structuredClone(this.data.originalStopwords[selectedLanguage]);
+ this.renderStopwordLanguageChipList(selectedLanguage, this.data.stopwords[selectedLanguage]);
+ });
+
+ // Initialize Materialize components.
+ M.Chips.init(
+ stopwordInputField,
+ {
+ placeholder: 'Add stopwords',
+ onChipAdd: (event) => {
+ for (let word of event[0].M_Chips.chipsData) {
+ if (!this.data.stopwords['user_stopwords'].includes(word.tag.toLowerCase())) {
+ this.data.stopwords['user_stopwords'].push(word.tag.toLowerCase());
+ }
+ }
+ }
+ }
+ );
+ M.FormSelect.init(stopwordLanguageSelection);
+
+ }
+
+ buttonRendering() {
+ let deleteLanguageStopwordListEntriesButton = document.querySelector('#delete-language-stopword-list-entries-button');
+ let resetLanguageStopwordListEntriesButton = document.querySelector('#reset-language-stopword-list-entries-button');
+ let selectedLanguage = document.querySelector('#stopword-language-selection').value;
+ let stopwordLength = this.data.stopwords[selectedLanguage].length;
+ let originalStopwordListLength = this.data.originalStopwords[selectedLanguage].length;
+
+ deleteLanguageStopwordListEntriesButton.classList.toggle('disabled', stopwordLength === 0);
+ resetLanguageStopwordListEntriesButton.classList.toggle('disabled', stopwordLength === originalStopwordListLength);
+ }
+
+ renderStopwordLanguageChipList(language, stopwords) {
+ let stopwordLanguageChipList = document.querySelector('#stopword-language-chip-list');
+ stopwordLanguageChipList.innerHTML = '';
+ for (let word of stopwords) {
+ let chipElement = Utils.HTMLToElement(`${word}close
`);
+ chipElement.addEventListener('click', (event) => {
+ let removedListItem = event.target.closest('.chip').firstChild.textContent;
+ this.data.stopwords[language] = structuredClone(this.data.stopwords[language].filter(item => item !== removedListItem));
+ this.buttonRendering();
+ });
+ stopwordLanguageChipList.appendChild(chipElement);
+ }
+ 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}
%{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/templates/_scripts.html.j2 b/app/templates/_scripts.html.j2
index d8dfa6d1..772a0596 100644
--- a/app/templates/_scripts.html.j2
+++ b/app/templates/_scripts.html.j2
@@ -29,6 +29,7 @@
'js/CorpusAnalysis/CorpusAnalysisApp.js',
'js/CorpusAnalysis/CorpusAnalysisConcordance.js',
'js/CorpusAnalysis/CorpusAnalysisReader.js',
+ 'js/CorpusAnalysis/CorpusAnalysisStaticVisualization.js',
'js/CorpusAnalysis/QueryBuilder.js',
'js/XMLtoObject.js'
%}
diff --git a/app/templates/corpora/_analysis/static_visualization.html.j2 b/app/templates/corpora/_analysis/static_visualization.html.j2
new file mode 100644
index 00000000..3e6cfcff
--- /dev/null
+++ b/app/templates/corpora/_analysis/static_visualization.html.j2
@@ -0,0 +1,157 @@
+{% set name = 'Static Visualization' %}
+
+{% set description = '' %}
+
+{% set id_prefix = name.lower().replace(' ', '-') + '-extension' %}
+
+{% set tab_content = '' %}
+
+{% set container_content %}
+
+
+
query_stats{{ name }}
+
+
+
+
+
+
+
+
Text Information Overview
+
+
+
+
+
+
+
+
+
+
+
Proportions
+
of texts within the corpus
+
+
+
+
+
+
+
+
+{% endset %}
+
+{% set modals %}
+
@@ -165,38 +62,6 @@
-