diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index ff889b6..58351a0 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -106,13 +106,13 @@ jobs:
auditwheel repair dist/*-${{ matrix.cp }}-linux_*.whl
TWINE_USERNAME=${{ secrets.PYPI_USERNAME }} TWINE_PASSWORD=${{ secrets.PYPI_PASSWORD }} /opt/python/${{ matrix.cp }}/bin/python -m twine upload wheelhouse/*.whl
- build_macos_11:
+ build_macos_13:
name: Build for macOS 13
runs-on: macOS-13
strategy:
max-parallel: 4
matrix:
- python-version: [3.8, 3.9, "3.10", 3.11]
+ python-version: [3.8, 3.9, "3.10", 3.11, 3.12]
cpu-arch: [x86_64, arm64]
steps:
@@ -123,7 +123,7 @@ jobs:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
- python -m pip install --upgrade pip
+ python -m pip install --upgrade pip setuptools
wget https://gitlab.com/libeigen/eigen/-/archive/3.4.0/eigen-3.4.0.tar.gz
tar -zxvf eigen-3.4.0.tar.gz
rm eigen-3.4.0.tar.gz
diff --git a/.github/workflows/deploy_test.yml b/.github/workflows/deploy_test.yml
index 157c2b9..0eb6efe 100644
--- a/.github/workflows/deploy_test.yml
+++ b/.github/workflows/deploy_test.yml
@@ -105,13 +105,13 @@ jobs:
auditwheel repair dist/*-${{ matrix.cp }}-linux_*.whl
TWINE_USERNAME=${{ secrets.TEST_PYPI_USERNAME }} TWINE_PASSWORD=${{ secrets.TEST_PYPI_PASSWORD }} /opt/python/${{ matrix.cp }}/bin/python -m twine upload --repository testpypi wheelhouse/*.whl
- build_macos_11:
+ build_macos_13:
name: Build for macOS 13
runs-on: macOS-13
strategy:
max-parallel: 4
matrix:
- python-version: [3.8, 3.9, "3.10", 3.11]
+ python-version: [3.8, 3.9, "3.10", 3.11, 3.12]
cpu-arch: [x86_64, arm64]
steps:
@@ -122,7 +122,7 @@ jobs:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
- python -m pip install --upgrade pip
+ python -m pip install --upgrade pip setuptools
wget https://gitlab.com/libeigen/eigen/-/archive/3.4.0/eigen-3.4.0.tar.gz
tar -zxvf eigen-3.4.0.tar.gz
rm eigen-3.4.0.tar.gz
diff --git a/.github/workflows/generate_documentation.yml b/.github/workflows/generate_documentation.yml
index 9faa18e..c6a792b 100644
--- a/.github/workflows/generate_documentation.yml
+++ b/.github/workflows/generate_documentation.yml
@@ -41,15 +41,15 @@ jobs:
mv variant/include/mapbox include/
- name: build
run: |
- /opt/python/cp38-cp38/bin/python -m pip install numpy==`/opt/python/cp38-cp38/bin/python .github/workflows/numpy_version.py`
- /opt/python/cp38-cp38/bin/python -m pip install pdoc3==0.8.4
+ /opt/python/cp39-cp39/bin/python -m pip install numpy==`/opt/python/cp39-cp39/bin/python .github/workflows/numpy_version.py`
+ /opt/python/cp39-cp3/bin/python -m pip install pdoc3==0.8.4
export TOMOTOPY_LANG=${{ matrix.language }}
- /opt/python/cp38-cp38/bin/python setup.py install
+ /opt/python/cp39-cp39/bin/python setup.py install
- name: gen doc
run: |
- export TOMOTOPY_VER="`/opt/python/cp38-cp38/bin/python -m pip show tomotopy | grep Version | cut -d' ' -f2`"
+ export TOMOTOPY_VER="`/opt/python/cp39-cp39/bin/python -m pip show tomotopy | grep Version | cut -d' ' -f2`"
export TOMOTOPY_LANG=${{ matrix.language }}
- /opt/python/cp38-cp38/bin/python -m pdoc --html tomotopy
+ /opt/python/cp39-cp39/bin/python -m pdoc --html tomotopy
sed -i -E "s/documentation<\/title>/documentation (v${TOMOTOPY_VER})<\/title>/" html/tomotopy/*.html
sed -i -E 's/<\/title>/<\/title>/' html/tomotopy/*.html
sed -i -E 's/(
<\/p>)/
+
Top words in each topic
-
-
More words...
+
+
+
+ {% set col = "col-md-6" if top1_topic_dist_by_metadata else "" %}
+
+
Distribution of Document Top1 Topics
+
+
+
+ {% if top1_topic_dist_by_metadata %}
+
+
Distribution of Document Top1 Topics by Metadata
+
+
+
+ {% end %}
+
+
+ {% elif action == 'topic-rel' %}
+
+
+
+
Word overlap between topics
+
+
+
+ |
+ {% for i in range(len(overlaps)) %}
+ {{i}} |
+ {% end %}
+
+ {% for j in range(len(overlaps)) %}
+
+ {{j}} |
+ {% for i in range(len(overlaps)) %}
+ |
+ {% end %}
+
+ {% end %}
+
+
+
+
+ {% for n, (i, j) in enumerate(similar_pairs) %}
+
= len(overlaps) else ""}}">
+
+ {{get_topic_label(i, id_suffix=True)}} - {{get_topic_label(j, id_suffix=True)}}: {{overlaps[i, j]:.2%}} |
+
+
+ {{get_topic_label(i, prefix="Topic ", id_suffix=True)}}:
+ {% for word, p in model.get_topic_words(i, top_n=10) %}
+ {{word}}({{p:.2%}})
+ {% end %}
+ |
+ {{get_topic_label(j, prefix="Topic ", id_suffix=True)}}:
+ {% for word, p in model.get_topic_words(j, top_n=10) %}
+ {{word}}({{p:.2%}})
+ {% end %}
+ |
+
+
+ {% end %}
+
+
+
+ {% elif action == 'metadata' %}
+
+
+ {% elif action == 'tdf-map' %}
+
+
Topic Distribution Function Map
+
+
+
+
+ {% for topic in range(model.k) %}
+
+
{{get_topic_label(topic, prefix="Topic ", id_suffix=True)}}
+
+
+ {% end %}
+
{% end %}
@@ -209,34 +556,62 @@ Topic #{{topic.topic_id}
(function(){
const tooltip_list = [...document.querySelectorAll('[data-bs-toggle="tooltip"]')].map(e => new bootstrap.Tooltip(e));
+ function view_document(doc_id) {
+ if (doc_id === null) {
+ // hide document view
+ document.getElementById('document-content').style.display = 'none';
+ document.getElementById('document-list').classList.remove('d-none');
+ return;
+ }
+ // remove active class
+ document.querySelectorAll('.doc-item').forEach((el) => {
+ el.classList.remove('active');
+ });
+ // add active class
+ document.getElementById(`doc-item-${doc_id}`).classList.add('active');
+ // show loading
+ document.getElementById('document-content-title').innerHTML = `Doc ${doc_id}`;
+ document.getElementById('document-metadata').innerHTML = '';
+ document.getElementById('document-content-body').innerHTML = '';
+ document.getElementById('document-content').style.display = 'block';
+ document.getElementById('document-list').classList.add('d-none');
+
+ fetch(`/api/document/${doc_id}`).then((res) => res.text()).then((html) => {
+ document.getElementById('document-content-body').innerHTML = html;
+ const tooltip_list = [...document.querySelectorAll('#document-content-body [data-bs-toggle="tooltip"]')].map(e => new bootstrap.Tooltip(e));
+ document.querySelectorAll('#document-content-body meta').forEach((el) => {
+ const key = el.getAttribute('name');
+ const value = el.getAttribute('content');
+ document.getElementById('document-metadata').innerHTML += `${key}: ${value} `;
+ });
+ }).catch((err) => {
+ document.getElementById('document-content-body').innerHTML = `
${err}
`;
+ })
+ }
+
document.querySelectorAll('.document-view').forEach((el) => {
el.addEventListener('click', (e) => {
//e.preventDefault();
- const doc_id = el.getAttribute('href').substring(5);
- // remove active class
- document.querySelectorAll('.doc-item').forEach((el) => {
- el.classList.remove('active');
- });
- // add active class
- document.getElementById(`doc-item-${doc_id}`).classList.add('active');
- // show loading
- document.getElementById('document-content-title').innerHTML = `Doc ${doc_id}`;
- document.getElementById('document-content-body').innerHTML = '';
- document.getElementById('document-content').style.display = 'block';
-
- fetch(`/api/document/${doc_id}`).then((res) => res.text()).then((html) => {
- document.getElementById('document-content-body').innerHTML = html;
- const tooltip_list = [...document.querySelectorAll('#document-content-body [data-bs-toggle="tooltip"]')].map(e => new bootstrap.Tooltip(e));
- }).catch((err) => {
- document.getElementById('document-content-body').innerHTML = `${err}
`;
- })
+ //const doc_id = el.getAttribute('href').substring(5);
+ //view_document(doc_id);
});
});
if (document.querySelector('#document-content-close')) {
document.querySelector('#document-content-close').addEventListener('click', (e) => {
e.preventDefault();
- document.getElementById('document-content').style.display = 'none';
+ //view_document(null);
+ location.hash = '';
+ });
+
+ // when user go history back
+ window.addEventListener('popstate', (e) => {
+ // test if #doc-xxx exists
+ if (location.hash.startsWith('#doc-')) {
+ view_document(location.hash.substring(5));
+ } else {
+ view_document(null);
+ }
});
}
@@ -266,6 +641,12 @@ Topic #{{topic.topic_id}
});
}
+ if (document.querySelector('#document-filter-metadata')) {
+ document.querySelector('#document-filter-metadata').addEventListener('change', (e) => {
+ document.querySelector('#document-filter').submit();
+ });
+ }
+
// attach event handler to element with .topic-action dynamically
document.addEventListener("click", function(e){
const target = e.target.closest(".topic-action");
@@ -282,6 +663,188 @@ Topic #{{topic.topic_id}
});
});
+ if (document.querySelector('.topic-title')) {
+ document.querySelectorAll('.topic-title').forEach((el) => {
+ const topic_id = el.getAttribute('data-id');
+ el.querySelector('button').addEventListener('click', (e) => {
+ const button = el.querySelector('button');
+ const label = el.querySelector('.topic-label');
+ const input = el.querySelector('.topic-label-editable');
+ button.style.display = 'none';
+ label.style.display = 'none';
+ input.style.display = '';
+ input.value = label.textContent;
+ input.focus();
+ });
+
+ function update_topic_label() {
+ const button = el.querySelector('button');
+ const label = el.querySelector('.topic-label');
+ const input = el.querySelector('.topic-label-editable');
+ button.style.display = '';
+ label.style.display = '';
+ input.style.display = 'none';
+ label.textContent = input.value;
+ fetch(`/api/topic/${topic_id}/label`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({label: input.value}),
+ }).then((res) => res.json()).then((json) => {
+ setTimeout(() => window.location.reload(), 50);
+ });
+ }
+ el.querySelector('.topic-label-editable').addEventListener('blur', update_topic_label);
+ el.querySelector('.topic-label-editable').addEventListener('keydown', (e) => {
+ if (e.key === 'Enter') {
+ update_topic_label();
+ }
+ });
+ });
+ }
+
+ if (document.querySelector('#topic-overlap-table')) {
+ const num_topics = document.querySelectorAll('#topic-overlap-table tr').length - 1;
+ document.querySelectorAll('#topic-overlap-table td').forEach((el) => {
+ el.addEventListener('click', (e) => {
+ const topic_i = el.getAttribute('data-i');
+ const topic_j = el.getAttribute('data-j');
+ if (topic_i == '-1' || topic_j == '-1') return;
+ const list = document.querySelector('#most-similar-topic-pairs');
+ [...list.children]
+ .sort((a, b) => {
+ const a_selected = a.getAttribute('data-j') == topic_j ? 1 : 0;
+ const b_selected = b.getAttribute('data-j') == topic_j ? 1 : 0;
+ if (b_selected > a_selected) return 1;
+ if (b_selected < a_selected) return -1;
+ return parseFloat(b.getAttribute('data-val')) - parseFloat(a.getAttribute('data-val'));
+ })
+ .forEach((node, idx) => {
+ if (node.getAttribute('data-j') == topic_j) {
+ node.classList.add('active');
+ } else {
+ node.classList.remove('active');
+ }
+ node.style.display = node.getAttribute('data-i') == topic_i ? '' : 'none';
+ list.appendChild(node);
+ });
+ });
+ });
+ document.querySelector('#topic-pair-reset').addEventListener('click', (e) => {
+ const list = document.querySelector('#most-similar-topic-pairs');
+ [...list.children]
+ .sort((a, b) => parseFloat(b.getAttribute('data-val')) - parseFloat(a.getAttribute('data-val')))
+ .forEach((node, idx) => {
+ const is_triu = parseInt(node.getAttribute('data-i')) < parseInt(node.getAttribute('data-j'));
+ node.style.display = idx < (num_topics - 1) * 2 && is_triu ? '' : 'none';
+ list.appendChild(node);
+ });
+ });
+ }
+
+ function get_confidence_interval_data(p, done, cid = 0) {
+ if (typeof tdf_ci_lb[cid] !== 'undefined' && tdf_ci_p[cid] == p) {
+ if (cid + 1 < category_labels.length) {
+ get_confidence_interval_data(p, done, cid + 1);
+ } else {
+ done();
+ }
+ return;
+ }
+
+ fetch(`/api/conf-interval/${cid}/${p}`).then((res) => res.json()).then((json) => {
+ const cid = json.data.cid;
+ const p = json.data.p;
+ const lbs = json.data.lbs;
+ const ubs = json.data.ubs;
+ tdf_ci_p[cid] = p;
+ tdf_ci_lb[cid] = lbs;
+ tdf_ci_ub[cid] = ubs;
+ if (cid + 1 < category_labels.length) {
+ get_confidence_interval_data(p, done, cid + 1);
+ } else {
+ done();
+ }
+ });
+ }
+
+ function updateConfInterval() {
+ const show_conf_interval = document.querySelector('#show-conf-interval').checked;
+ if (show_conf_interval) {
+ const p = parseFloat(document.querySelector('#confidence').value);
+ if (isNaN(p) || p <= 0 || p >= 1) {
+ alert('Confidence should be a number between 0 and 1.');
+ return;
+ }
+ get_confidence_interval_data(p, () => {
+ for (var i in charts) {
+ const chart = charts[i];
+ const data = chart.data;
+ const datasets = data.datasets;
+ datasets.splice(category_labels.length);
+ for (var cid in category_labels) {
+ const lb = tdf_ci_lb[cid][i];
+ const ub = tdf_ci_ub[cid][i];
+ for (var lv = 0; lv < 3; ++lv) {
+ const backgroundColor = datasets[cid].backgroundColor.replace(/, *0\.\d+\)/, lv > 0 ? ', 0.1)' : ', 0.15)');
+ datasets.push({
+ label: category_labels[cid] + ' LB',
+ data: lb.map((v, x) => (v * (3 - lv) + tdf_data[i][cid][x] * lv) / 3),
+ fill: cid,
+ backgroundColor: backgroundColor,
+ borderColor: 'transparent',
+ pointStyle: false,
+ });
+ datasets.push({
+ label: category_labels[cid] + ' UB',
+ data: ub.map((v, x) => (v * (3 - lv) + tdf_data[i][cid][x] * lv) / 3),
+ fill: cid,
+ backgroundColor: backgroundColor,
+ borderColor: 'transparent',
+ pointStyle: false,
+ });
+ }
+ }
+ chart.update();
+ }
+ });
+ } else {
+ for (var i in charts) {
+ const chart = charts[i];
+ const data = chart.data;
+ const datasets = data.datasets;
+ datasets.splice(category_labels.length);
+ chart.update();
+ }
+ }
+ }
+
+ if (document.querySelector('#show-conf-interval')) {
+ document.querySelector('#show-conf-interval').addEventListener('change', updateConfInterval);
+ document.querySelector('#confidence').addEventListener('change', updateConfInterval);
+ }
+
+ if (document.querySelector('#opacity')) {
+ document.querySelector('#opacity').addEventListener('change', (e) => {
+ for (var i in charts) {
+ const chart = charts[i];
+ chart.update();
+ }
+ });
+ }
+
+ if (document.querySelector('#numeric-metadata-range')) {
+ document.querySelector('#numeric-metadata-range').addEventListener('submit', (e) => {
+ const range_values = [];
+ document.querySelectorAll('.range-value').forEach((el) => {
+ range_values.push(el.value);
+ });
+ document.querySelector('#all-range-value').value = range_values.join(',');
+ return true;
+ });
+ }
+
}());