mirror of
https://gitlab.ub.uni-bielefeld.de/sfb1288inf/nopaque.git
synced 2024-11-14 16:55:42 +00:00
Outsource Static Viz to extensions logic
This commit is contained in:
parent
572fdf3a00
commit
c3834ca400
@ -1,11 +1,6 @@
|
|||||||
class CorpusAnalysisApp {
|
class CorpusAnalysisApp {
|
||||||
constructor(corpusId) {
|
constructor(corpusId) {
|
||||||
this.data = {
|
this.data = {};
|
||||||
stopwords: undefined,
|
|
||||||
originalStopwords: {},
|
|
||||||
stopwordCache: {},
|
|
||||||
promises: {getStopwords: undefined}
|
|
||||||
};
|
|
||||||
|
|
||||||
// HTML elements
|
// HTML elements
|
||||||
this.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() {
|
init() {
|
||||||
this.disableActionElements();
|
this.disableActionElements();
|
||||||
this.elements.m.initModal.open();
|
this.elements.m.initModal.open();
|
||||||
@ -57,11 +34,12 @@ class CorpusAnalysisApp {
|
|||||||
.then((cqiCorpora) => {
|
.then((cqiCorpora) => {
|
||||||
this.data.corpus = {o: cqiCorpora[0]};
|
this.data.corpus = {o: cqiCorpora[0]};
|
||||||
console.log(this.data.corpus.o.staticData);
|
console.log(this.data.corpus.o.staticData);
|
||||||
this.renderGeneralCorpusInfo();
|
// this.renderGeneralCorpusInfo();
|
||||||
this.renderTextInfoList();
|
// this.renderTextInfoList();
|
||||||
this.renderTextProportionsGraphic()
|
// this.renderTextProportionsGraphic()
|
||||||
this.renderFrequenciesGraphic();
|
// this.renderFrequenciesGraphic();
|
||||||
this.renderBoundsGraphic();
|
// this.renderBoundsGraphic();
|
||||||
|
|
||||||
// TODO: Don't do this hgere
|
// TODO: Don't do this hgere
|
||||||
this.data.corpus.o.updateDb();
|
this.data.corpus.o.updateDb();
|
||||||
this.enableActionElements();
|
this.enableActionElements();
|
||||||
@ -78,7 +56,6 @@ class CorpusAnalysisApp {
|
|||||||
progressElement.classList.add('hide');
|
progressElement.classList.add('hide');
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
// Add event listeners
|
// Add event listeners
|
||||||
for (let extensionSelectorElement of this.elements.overview.querySelectorAll('.extension-selector')) {
|
for (let extensionSelectorElement of this.elements.overview.querySelectorAll('.extension-selector')) {
|
||||||
@ -86,25 +63,6 @@ class CorpusAnalysisApp {
|
|||||||
this.elements.m.extensionTabs.select(extensionSelectorElement.dataset.target);
|
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) {
|
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]]}<br>${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(`<option value="${language}" ${language === 'english' ? 'selected' : ''}>${language}</option>`);
|
|
||||||
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(`<div class="chip">${word}<i class="close material-icons">close</i></div>`);
|
|
||||||
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(`<div class="chip">${word}<i class="close material-icons">close</i></div>`);
|
|
||||||
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} <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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -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]]}<br>${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(`<option value="${language}" ${language === 'english' ? 'selected' : ''}>${language}</option>`);
|
||||||
|
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(`<div class="chip">${word}<i class="close material-icons">close</i></div>`);
|
||||||
|
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(`<div class="chip">${word}<i class="close material-icons">close</i></div>`);
|
||||||
|
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} <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);
|
||||||
|
}
|
||||||
|
}
|
@ -29,6 +29,7 @@
|
|||||||
'js/CorpusAnalysis/CorpusAnalysisApp.js',
|
'js/CorpusAnalysis/CorpusAnalysisApp.js',
|
||||||
'js/CorpusAnalysis/CorpusAnalysisConcordance.js',
|
'js/CorpusAnalysis/CorpusAnalysisConcordance.js',
|
||||||
'js/CorpusAnalysis/CorpusAnalysisReader.js',
|
'js/CorpusAnalysis/CorpusAnalysisReader.js',
|
||||||
|
'js/CorpusAnalysis/CorpusAnalysisStaticVisualization.js',
|
||||||
'js/CorpusAnalysis/QueryBuilder.js',
|
'js/CorpusAnalysis/QueryBuilder.js',
|
||||||
'js/XMLtoObject.js'
|
'js/XMLtoObject.js'
|
||||||
%}
|
%}
|
||||||
|
157
app/templates/corpora/_analysis/static_visualization.html.j2
Normal file
157
app/templates/corpora/_analysis/static_visualization.html.j2
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
{% set name = 'Static Visualization' %}
|
||||||
|
|
||||||
|
{% set description = '' %}
|
||||||
|
|
||||||
|
{% set id_prefix = name.lower().replace(' ', '-') + '-extension' %}
|
||||||
|
|
||||||
|
{% set tab_content = '' %}
|
||||||
|
|
||||||
|
{% set container_content %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col s12">
|
||||||
|
<h4><i class="material-icons left">query_stats</i>{{ name }}</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col s2">
|
||||||
|
<div class="card hoverable" style="border-radius: 10px !important; background-color:#6b3f89; color:white">
|
||||||
|
<div class="card-content" style="padding:10px !important; text-align:center;">
|
||||||
|
<p><b>Tokens</b></p>
|
||||||
|
<span class="card-title corpus-num-tokens"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col s2">
|
||||||
|
<div class="card hoverable" style="border-radius: 10px !important; background-color:#6b3f89; color:white">
|
||||||
|
<div class="card-content" style="padding:10px !important; text-align:center">
|
||||||
|
<p><b>Sentences</b></p>
|
||||||
|
<span class="card-title corpus-num-s"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col s2">
|
||||||
|
<div class="card hoverable" style="border-radius: 10px !important; background-color:#6b3f89; color:white">
|
||||||
|
<div class="card-content" style="padding:10px !important; text-align:center">
|
||||||
|
<p><b>Unique words</b></p>
|
||||||
|
<span class="card-title corpus-num-unique-words"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col s2">
|
||||||
|
<div class="card hoverable" style="border-radius: 10px !important; background-color:#6b3f89; color:white">
|
||||||
|
<div class="card-content" style="padding:10px !important; text-align:center">
|
||||||
|
<p><b>Unique lemmas</b></p>
|
||||||
|
<span class="card-title corpus-num-unique-lemmas"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col s2">
|
||||||
|
<div class="card hoverable" style="border-radius: 10px !important; background-color:#6b3f89; color:white">
|
||||||
|
<div class="card-content" style="padding:10px !important; text-align:center">
|
||||||
|
<p><b>Unique pos</b></p>
|
||||||
|
<span class="card-title corpus-num-unique-pos"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col s2">
|
||||||
|
<div class="card hoverable" style="border-radius: 10px !important; background-color:#6b3f89; color:white">
|
||||||
|
<div class="card-content" style="padding:10px !important; text-align:center">
|
||||||
|
<p><b>Unique simple_pos</b></p>
|
||||||
|
<span class="card-title corpus-num-unique-simple-pos"></span>
|
||||||
|
</div>
|
||||||
|
</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>
|
||||||
|
<p>of texts within the corpus</p>
|
||||||
|
<div id="text-proportions-graphic" style="width:100"></div>
|
||||||
|
</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>
|
||||||
|
</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>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endset %}
|
||||||
|
|
||||||
|
{% set modals %}
|
||||||
|
<div class="modal modal-fixed-footer" id="frequencies-stopwords-setting-modal">
|
||||||
|
<div class="modal-content">
|
||||||
|
<h4>Settings</h4>
|
||||||
|
<div class="row">
|
||||||
|
<p>Here you can change the stopword-lists. Stopwords are common words in a language,
|
||||||
|
like "the" or "and," that carry little meaning and are often removed in text analysis
|
||||||
|
to improve efficiency and accuracy.</p>
|
||||||
|
<div id="user-stopword-list-container"></div>
|
||||||
|
<div class="chips col s8 no-autoinit input-field" id="stopword-input-field">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<p>Below you can find a list of all stopwords that are always filtered out.
|
||||||
|
The lists are sorted by language, you can remove single words or remove
|
||||||
|
whole languages via the settings on the right.</p>
|
||||||
|
<div class="input-field col s3">
|
||||||
|
<select id="stopword-language-selection"></select>
|
||||||
|
<label>Stopword language select</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="chip btn white-text red" id="delete-language-stopword-list-entries-button">Delete all below<i class="material-icons right">delete</i></div>
|
||||||
|
<div class="chip btn white-text blue" id="reset-language-stopword-list-entries-button">Reset stopword list<i class="material-icons right">refresh</i></div>
|
||||||
|
</div>
|
||||||
|
<div id="stopword-language-chip-list"></div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<a class="modal-close waves-effect waves-green btn frequencies-stopword-setting-modal-action-buttons" data-action="cancel">Cancel</a>
|
||||||
|
<a class="modal-close waves-effect waves-green btn frequencies-stopword-setting-modal-action-buttons" data-action="submit">Submit</a>
|
||||||
|
</div>
|
||||||
|
{% endset %}
|
||||||
|
|
||||||
|
{% set scripts %}
|
||||||
|
<script>
|
||||||
|
const corpusAnalysisStaticVisualization = new CorpusAnalysisStaticVisualization(corpusAnalysisApp);
|
||||||
|
</script>
|
||||||
|
{% endset %}
|
@ -2,8 +2,9 @@
|
|||||||
{% import "materialize/wtf.html.j2" as wtf %}
|
{% import "materialize/wtf.html.j2" as wtf %}
|
||||||
{% import 'corpora/_analysis/concordance.html.j2' as concordance_extension %}
|
{% import 'corpora/_analysis/concordance.html.j2' as concordance_extension %}
|
||||||
{% import 'corpora/_analysis/reader.html.j2' as reader_extension %}
|
{% import 'corpora/_analysis/reader.html.j2' as reader_extension %}
|
||||||
|
{% import 'corpora/_analysis/static_visualization.html.j2' as static_visualization_extension%}
|
||||||
|
|
||||||
{% set extensions = [concordance_extension, reader_extension] %}
|
{% set extensions = [concordance_extension, reader_extension, static_visualization_extension] %}
|
||||||
{% block main_attribs %} class="service-scheme" data-service="corpus-analysis" id="corpus-analysis-app-container"{% endblock main_attribs %}
|
{% block main_attribs %} class="service-scheme" data-service="corpus-analysis" id="corpus-analysis-app-container"{% endblock main_attribs %}
|
||||||
|
|
||||||
|
|
||||||
@ -12,7 +13,9 @@
|
|||||||
<ul class="row tabs no-autoinit" id="corpus-analysis-app-extension-tabs">
|
<ul class="row tabs no-autoinit" id="corpus-analysis-app-extension-tabs">
|
||||||
<li class="tab col s3"><a class="active" href="#corpus-analysis-app-overview"><i class="nopaque-icons service-icons left" data-service="corpus-analysis"></i>Corpus analysis</a></li>
|
<li class="tab col s3"><a class="active" href="#corpus-analysis-app-overview"><i class="nopaque-icons service-icons left" data-service="corpus-analysis"></i>Corpus analysis</a></li>
|
||||||
{% for extension in extensions %}
|
{% for extension in extensions %}
|
||||||
|
{% if extension.name != 'Static Visualization' %}
|
||||||
<li class="tab col s3"><a href="#{{ extension.id_prefix }}-container">{{ extension.tab_content }}</a></li>
|
<li class="tab col s3"><a href="#{{ extension.id_prefix }}-container">{{ extension.tab_content }}</a></li>
|
||||||
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
@ -21,6 +24,7 @@
|
|||||||
<h1>{{ title }}</h1>
|
<h1>{{ title }}</h1>
|
||||||
|
|
||||||
{% for extension in extensions %}
|
{% for extension in extensions %}
|
||||||
|
{% if extension.name != 'Static Visualization' %}
|
||||||
<div class="col s3">
|
<div class="col s3">
|
||||||
<div class="card extension-selector hoverable" data-target="{{ extension.id_prefix }}-container">
|
<div class="card extension-selector hoverable" data-target="{{ extension.id_prefix }}-container">
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
@ -29,116 +33,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col s12">
|
|
||||||
<h4><i class="material-icons left">query_stats</i>Visualizations</h4>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col s2">
|
|
||||||
<div class="card hoverable" style="border-radius: 10px !important; background-color:#6b3f89; color:white">
|
|
||||||
<div class="card-content" style="padding:10px !important; text-align:center;">
|
|
||||||
<p><b>Tokens</b></p>
|
|
||||||
<span class="card-title corpus-num-tokens"></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col s2">
|
|
||||||
<div class="card hoverable" style="border-radius: 10px !important; background-color:#6b3f89; color:white">
|
|
||||||
<div class="card-content" style="padding:10px !important; text-align:center">
|
|
||||||
<p><b>Sentences</b></p>
|
|
||||||
<span class="card-title corpus-num-s"></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col s2">
|
|
||||||
<div class="card hoverable" style="border-radius: 10px !important; background-color:#6b3f89; color:white">
|
|
||||||
<div class="card-content" style="padding:10px !important; text-align:center">
|
|
||||||
<p><b>Unique words</b></p>
|
|
||||||
<span class="card-title corpus-num-unique-words"></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col s2">
|
|
||||||
<div class="card hoverable" style="border-radius: 10px !important; background-color:#6b3f89; color:white">
|
|
||||||
<div class="card-content" style="padding:10px !important; text-align:center">
|
|
||||||
<p><b>Unique lemmas</b></p>
|
|
||||||
<span class="card-title corpus-num-unique-lemmas"></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col s2">
|
|
||||||
<div class="card hoverable" style="border-radius: 10px !important; background-color:#6b3f89; color:white">
|
|
||||||
<div class="card-content" style="padding:10px !important; text-align:center">
|
|
||||||
<p><b>Unique pos</b></p>
|
|
||||||
<span class="card-title corpus-num-unique-pos"></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col s2">
|
|
||||||
<div class="card hoverable" style="border-radius: 10px !important; background-color:#6b3f89; color:white">
|
|
||||||
<div class="card-content" style="padding:10px !important; text-align:center">
|
|
||||||
<p><b>Unique simple_pos</b></p>
|
|
||||||
<span class="card-title corpus-num-unique-simple-pos"></span>
|
|
||||||
</div>
|
|
||||||
</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>
|
|
||||||
<p>of texts within the corpus</p>
|
|
||||||
<div id="text-proportions-graphic" style="width:100"></div>
|
|
||||||
</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>
|
|
||||||
</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>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -165,38 +62,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="modal modal-fixed-footer" id="frequencies-stopwords-setting-modal">
|
|
||||||
<div class="modal-content">
|
|
||||||
<h4>Settings</h4>
|
|
||||||
<div class="row">
|
|
||||||
<p>Here you can change the stopword-lists. Stopwords are common words in a language,
|
|
||||||
like "the" or "and," that carry little meaning and are often removed in text analysis
|
|
||||||
to improve efficiency and accuracy.</p>
|
|
||||||
<div id="user-stopword-list-container"></div>
|
|
||||||
<div class="chips col s8 no-autoinit input-field" id="stopword-input-field">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<p>Below you can find a list of all stopwords that are always filtered out.
|
|
||||||
The lists are sorted by language, you can remove single words or remove
|
|
||||||
whole languages via the settings on the right.</p>
|
|
||||||
<div class="input-field col s3">
|
|
||||||
<select id="stopword-language-selection"></select>
|
|
||||||
<label>Stopword language select</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="chip btn white-text red" id="delete-language-stopword-list-entries-button">Delete all below<i class="material-icons right">delete</i></div>
|
|
||||||
<div class="chip btn white-text blue" id="reset-language-stopword-list-entries-button">Reset stopword list<i class="material-icons right">refresh</i></div>
|
|
||||||
</div>
|
|
||||||
<div id="stopword-language-chip-list"></div>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<a class="modal-close waves-effect waves-green btn frequencies-stopword-setting-modal-action-buttons" data-action="cancel">Cancel</a>
|
|
||||||
<a class="modal-close waves-effect waves-green btn frequencies-stopword-setting-modal-action-buttons" data-action="submit">Submit</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
{% for extension in extensions %}
|
{% for extension in extensions %}
|
||||||
{{ extension.modals }}
|
{{ extension.modals }}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
Loading…
Reference in New Issue
Block a user