Skip to content

Commit

Permalink
feat(UI): Add harmonization text and style
Browse files Browse the repository at this point in the history
  • Loading branch information
Rapsssito committed Nov 29, 2023
1 parent efd2e8b commit c67d1c7
Show file tree
Hide file tree
Showing 9 changed files with 118 additions and 65 deletions.
8 changes: 6 additions & 2 deletions modules/oncoliner_ui/src/ui/harmonization_tab.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
from .utils import flatten_dict, flatten_dict_keys
from .plots.harmonization_plot import HarmonizationPlot

from .model.harmonization.harmonization_dao import HarmonizationDAO

class HarmonizationTab():
def __init__(self, env, dao):
def __init__(self, env, dao: HarmonizationDAO):
self._env = env
self._harmonization_dao = dao
self._harmonization_tree_dict = self._harmonization_dao.get_tree()
Expand All @@ -21,11 +22,14 @@ def render_panel(self):
def render_table(self, id_, data):
template = self._env.get_template(os.path.join("harmonization_tab", "harmonization_table.html"))
# Build the default order of the columns
columns_order = [[data.columns.get_loc('h_score'), 'asc'], [data.columns.get_loc('gdr'), 'asc'], [data.columns.get_loc('f1_score_avg'), 'desc'], [data.columns.get_loc('added_callers_sum'), 'asc']]
columns_order = list(map(lambda x: [data.columns.get_loc(x[0]), x[1]], self._harmonization_dao.get_default_order()))
# Get the index of the row with all names 'baseline'
pipelines_names = self._harmonization_dao.get_pipelines_names()
baseline_index = data[data[pipelines_names].apply(lambda x: all(x == 'baseline'), axis=1)].index[0]
return template.render(ctrl=self, id=f'table_{id_}', data=data, fixed_index=baseline_index, default_order=columns_order)

def get_best_harmonization_names(self, variant_type: str):
return self._harmonization_dao.get_best_harmonization_names(variant_type)

def get_flatten_tree(self):
return flatten_dict(self._harmonization_tree_dict, 'id')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,29 +45,23 @@
id="metricspaneltab_snv_indel_sv_{{id}}_"
aria-labelledby="metricspaneltab_snv_indel_sv_{{id}}"
>
<div class="viz-inline-plots">
{{ ctrl.render_metrics_plot(metrics_table, id, 'snv_indel_sv') }}
</div>
{{ ctrl.render_metrics_plot(metrics_table, id, 'snv_indel_sv') }}
{{ ctrl.render_metrics_table(metrics_table, id, 'snv_indel_sv', sample) }}
</div>
<div
class="tab-pane fade show active"
id="metricspaneltab_by-type_{{id}}_"
aria-labelledby="metricspaneltab_by-type_{{id}}"
>
<div class="viz-inline-plots">
{{ ctrl.render_metrics_plot(metrics_table, id, 'sv_subtypes') }}
</div>
{{ ctrl.render_metrics_plot(metrics_table, id, 'sv_subtypes') }}
{{ ctrl.render_metrics_table(metrics_table, id, 'sv_subtypes', sample) }}
</div>
<div
class="tab-pane fade"
id="metricspaneltab_by-type-size_{{id}}_"
aria-labelledby="metricspaneltab_by-type-size_{{id}}"
>
<div class="viz-inline-plots">
{{ ctrl.render_metrics_plot(metrics_table, id, 'sv_subtypes_sizes') }}
</div>
{{ ctrl.render_metrics_plot(metrics_table, id, 'sv_subtypes_sizes') }}
{{ ctrl.render_metrics_table(metrics_table, id, 'sv_subtypes_sizes', sample) }}
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
<h4 class="viz-plot-title">Performance metrics ({{conf.names[plot_type]}})</h4>
<div class="metrics-chart-container" id="metrics-chart-container-{{id}}">
{{include_cooked('shared/export_chart.html', chart_js_var_name=id+'MetricsChart', filenames=[id+'_metrics_plot'], filename=id+'_metrics_plot')}}
<canvas></canvas>
<div class="metrics-chart-container" >
<div id="metrics-chart-container-{{id}}" style="margin-left: auto; margin-right: auto;">
{{include_cooked('shared/export_chart.html', chart_js_var_name=id+'MetricsChart', filenames=[id+'_metrics_plot'], filename=id+'_metrics_plot')}}
<canvas></canvas>
</div>
</div>

{% block javascript %}
<script>
{{id}}MetricsChart = createMetricsPlot('metrics-chart-container-{{id}}', {{chart_data}});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,28 @@
<div class="viz-width-limited">
<p>Listing of the harmonization options based on the improvement possibilities of the pipelines: <b>{{ ctrl.get_pipelines_names()|join(', ') }}</b>.</p>
<p>Use the table below to explore all harmonization options. <i>baseline</i> refers to the pipeline without any modification. Overall, the following combinations have the lowest heterogeneity score (H<sub>score</sub>):</p>
<ul>
<li>SNV:</li>
<ul>
{% for pipeline_name, harmonization_op in ctrl.get_best_harmonization_names('SNV').items() %}
<li><b>{{ pipeline_name }}</b>: <i>{{ harmonization_op }}</i></li>
{% endfor %}
</ul>
<li>INDEL:</li>
<ul>
{% for pipeline_name, harmonization_op in ctrl.get_best_harmonization_names('INDEL').items() %}
<li><b>{{ pipeline_name }}</b>: <i>{{ harmonization_op }}</i></li>
{% endfor %}
</ul>
<li>SV:</li>
<ul>
{% for pipeline_name, harmonization_op in ctrl.get_best_harmonization_names('SV').items() %}
<li><b>{{ pipeline_name }}</b>: <i>{{ harmonization_op }}</i></li>
{% endfor %}
</ul>
</ul>
</div>

<div class="sub-tab-content tab-content" id="harmonizations_panel_content">
<div class="nav nav-tabs" id="nav-tab" role="tablist">
<div class="nav viz-nav-tabs-container viz-width-limited">
Expand All @@ -8,25 +33,22 @@
</div>
<div class="viz-bordered-tab-container">
<div class="viz-width-limited-large">
<h4 class="viz-plot-title">Performance metrics (baseline vs harmonization)</h4>
<div class="radar-chart-container">
{{include_cooked('shared/export_chart.html', chart_js_var_name='harmonizationPlot', filenames='harmonizationPlotData[\'titles\'].map((a) => `harmonization_plot_${a}`)', filename='harmonizationPlot')}}
<div id="chart_container_harmonization"></div>
</div>
<div id="harmonizationPlotInfo" class="viz-plot-info"></div>
</div>
</div>
<div class="viz-width-limited">
<label>Select variant type and size</label>

<div id="ddat_harmonization" style="margin:20px;">
<div class="dropdown viz-dropdown-tree">
<button class="form-select" type="button" id="ddat_dropdownMenuButton_harmonization" aria-expanded="false" style="text-align: left" data-bs-toggle="dropdown" data-bs-auto-close="outside">
{{ctrl.get_tree().keys() | first}}
</button>
<div class="dropdown-menu scrollbar" aria-labelledby="ddat_dropdownMenuButton_harmonization" id="ddat_dropdownMenuButton_harmonization_menu">
<div class="tab-pane" role="tablist" aria-orientation="vertical" id="harmonization_size_type">
{{ ctrl.render_tree_branch(ctrl.get_tree(), 'harmonization', 'harmonizations_panel_content', click_callback={'function':'hideMenuAndUpdateSelected', 'params':['ddat_dropdownMenuButton_harmonization_menu', 'ddat_dropdownMenuButton_harmonization']}) }}
</div>
<div class="viz-width-limited" style="margin-top: 1rem;">
<p>Explore the harmonization options by selecting any row from the table below. <i>baseline</i> represents a pipeline without any combination with other callers. Use the dropdown below to check the harmonization options for specific variant types and sizes. The selected harmonization will be displayed in the plot above.</p>
<div class="dropdown viz-dropdown-tree">
<button class="form-select" type="button" id="ddat_dropdownMenuButton_harmonization" aria-expanded="false" style="text-align: left" data-bs-toggle="dropdown" data-bs-auto-close="outside">
{{ctrl.get_tree().keys() | first}}
</button>
<div class="dropdown-menu scrollbar" aria-labelledby="ddat_dropdownMenuButton_harmonization" id="ddat_dropdownMenuButton_harmonization_menu">
<div class="tab-pane" role="tablist" aria-orientation="vertical" id="harmonization_size_type">
{{ ctrl.render_tree_branch(ctrl.get_tree(), 'harmonization', 'harmonizations_panel_content', click_callback={'function':'hideMenuAndUpdateSelected', 'params':['ddat_dropdownMenuButton_harmonization_menu', 'ddat_dropdownMenuButton_harmonization']}) }}
</div>
</div>
</div>
Expand Down Expand Up @@ -72,17 +94,11 @@
});
const operationHarmonizationData = pipelinesNames.map((pipelineName, j) => harmonizationPlotData['operation_values'][pipelineName][pipelinesSelected[j]]);
harmonizationPlot.setHarmonizationData(operationHarmonizationData);

// Set the info text
const matrixText = []
for (let i = 0; i < harmonizationPlotData['pipelines_names'].length; i++) {
matrixText.push([harmonizationPlotData['pipelines_names'][i], pipelinesSelected[i]]);
}
document.querySelector('#harmonizationPlotInfo').innerHTML = matrixText;
harmonizationPlot.setHarmonizationLegendNames(pipelinesSelected);
}

setHarmonizationLabelsVisible('sv_subtypes');
// Manually trigger the click event on baseline
setHarmonizationDataFromTable(harmonizationPlotData['pipelines_names'].map((pipelineName) => 'baseline'));
setHarmonizationDataFromTable(['{{ctrl.get_best_harmonization_names("SV").values()|join("\', \'")}}']);
</script>
{% endblock %}
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ <h4 class="viz-plot-title">Performance metrics (<i>baseline</i> vs <i><span id="
</div>
<div class="viz-width-limited" style="margin-top: 1rem;">
<p>Explore the improvement possibilities of <b>{{pipeline_name}}</b> by selecting a variant caller or combination of variant callers from the table below. <i>baseline</i> represents the <b>{{pipeline_name}}</b> without any combination with other callers. Use the dropdown below to check the improvements possibilities for specific variant types and sizes. The selected improvement will be displayed in the plot above.</p>
<div class="dropdown viz-dropdown-tree" style="max-width: 300px; margin-left: auto; margin-right: auto;">
<div class="dropdown viz-dropdown-tree">
<button class="form-select" type="button" id="ddat_dropdownMenuButton_improvement_{{pipeline_name}}" aria-expanded="false" style="text-align: left" data-bs-toggle="dropdown" data-bs-auto-close="outside">
{{ctrl.get_tree(pipeline_name).keys() | first}}
</button>
Expand Down
20 changes: 8 additions & 12 deletions modules/oncoliner_ui/src/ui/html_templates/index/css/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ h1, h2, h3, h4, h5, h6 {
margin-top: 30px;
}

.viz-dropdown-tree {
max-width: 300px;
margin-left: auto;
margin-right: auto;
}

.viz-dropdown-tree .dropdown-menu {
width: 100%;
max-height: 400px;
Expand Down Expand Up @@ -298,10 +304,6 @@ a[class^="icon-"].active {
background: transparent !important;
}

.viz-inline-plots {
height: 60vh;
}

.viz-fixed-row {
font-weight: bold;
}
Expand Down Expand Up @@ -344,18 +346,12 @@ a[class^="icon-"].active {
align-items: center;
}

.radar-chart-container {
width: 100%;
.radar-chart-container, .metrics-chart-container {
width: 100%;
height: 500px;
position: relative;
}

.metrics-chart-container {
position: relative;
margin-left: auto;
margin-right: auto;
}

canvas {
width: 100% !important;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
<div class="wrapper">
<main class="viz-content">
<h1 class="viz-width-limited">Harmonization</h1>
<p class="viz-width-limited">Listing of the harmonization possibilities based on the improvements possibilities of the pipelines: <b>{{ ctrl.get_pipelines_names()|join(', ') }}</b>.</p>
{{ ctrl.render_panel() }}
</main>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,19 @@ function createHarmonizationPlot(htmlContainerId, datasetNames, titles, labels,
}
}

/**
* @param {string[]} names
*/
function setHarmonizationLegendNames(names) {
for (const chart of charts) {
chart.setHarmonizationLegendNames(names);
}
}

return {
setLabelsVisible,
setHarmonizationData,
setHarmonizationLegendNames,
getBase64Images : () => charts.map(chart => chart.getBase64Image()),
getCanvas: () => concatCanvases(charts.map((chart) => chart.getCanvas()))
};
Expand All @@ -71,8 +81,6 @@ function createHarmonizationPlot(htmlContainerId, datasetNames, titles, labels,
*/
function _buildHarmonizationChart(ctx, index, datasetNames, titles, labels, baseValues) {
const COLORS = ["#228833", "#bc629f", "#4477AA", "#E3B505", "#95190C"];
const HARMONIZATION_SUFFIX = " (harmonization)";
const BASELINE_SUFFIX = " (baseline)";
// Create a dataset for the chartBaseData
/** @type {ChartDataset[]} */
const datasets = [];
Expand All @@ -81,7 +89,8 @@ function _buildHarmonizationChart(ctx, index, datasetNames, titles, labels, base
const datasetName = datasetNames[i];
const harmonizationValues = baseValues[i][index];
datasets.push({
label: `${datasetName}${BASELINE_SUFFIX}`,
customType: 'baseline',
label: `${datasetName}`,
data: harmonizationValues,
backgroundColor: `${COLORS[i % COLORS.length]}50`,
borderWidth: 0,
Expand All @@ -92,7 +101,8 @@ function _buildHarmonizationChart(ctx, index, datasetNames, titles, labels, base
},
});
datasets.push({
label: `${datasetName}${HARMONIZATION_SUFFIX}`,
customType: 'harmonization',
label: `${datasetName} (baseline)`,
data: harmonizationValues,
borderColor: COLORS[i % COLORS.length],
pointBackgroundColor: COLORS[i % COLORS.length],
Expand All @@ -113,27 +123,31 @@ function _buildHarmonizationChart(ctx, index, datasetNames, titles, labels, base

/**
* @param {string} datasetName
* @param {string} datasetType
* @param {number[]} values
*/
function applyValuesToDataset(datasetName, values) {
function applyValuesToDataset(datasetName, datasetType, values) {
const dataset = chart.data.datasets.find(
(dataset) => dataset.label === datasetName
(dataset) => dataset.label.split(' (')[0] === datasetName && dataset.customType === datasetType
);
if (!dataset) return;
if (!dataset) {
throw new Error(
`Could not find dataset with label ${datasetName} and type ${datasetType}`
);
}
dataset.data = values;
}

/**
* @param {number[][]} newValues
* @param {number[]} indexes
* @param {string} suffix
* @param {string} datasetType
*/
function updateDatasetValues(newValues, indexes, suffix) {
function updateDatasetValues(newValues, indexes, datasetType) {
for (let i = 0; i < newValues.length; i++) {
const datasetName = `${datasetNames[i]}${suffix}`;
const newValue = newValues[i];
const values = indexes.map((index) => newValue[index]);
applyValuesToDataset(datasetName, values);
applyValuesToDataset(datasetNames[i], datasetType, values);
}
}

Expand All @@ -151,7 +165,7 @@ function _buildHarmonizationChart(ctx, index, datasetNames, titles, labels, base
indexes.push(index);
}
// Get the values of the labels that are in the chart
updateDatasetValues(harmonizationValues, indexes, HARMONIZATION_SUFFIX);
updateDatasetValues(harmonizationValues, indexes, 'harmonization');
chart.update();
}

Expand All @@ -170,14 +184,32 @@ function _buildHarmonizationChart(ctx, index, datasetNames, titles, labels, base
indexes.sort((a, b) => a - b);
// Get the values of the labels that are in the chart
chart.data.labels = indexes.map((index) => originalLabels[index]);
updateDatasetValues(harmonizationValues, indexes, HARMONIZATION_SUFFIX);
updateDatasetValues(originalValues, indexes, BASELINE_SUFFIX);
updateDatasetValues(harmonizationValues, indexes, 'harmonization');
updateDatasetValues(originalValues, indexes, 'baseline');
chart.update();
}

/**
* @param {string[]} operationNames
*/
function setHarmonizationLegendNames(operationNames) {
// Get all the datasets that are harmonization
const harmonizationDatasets = chart.data.datasets.filter(
(dataset) => dataset.customType === 'harmonization'
);
// Change the text of the label between brackets
for (let i = 0; i < harmonizationDatasets.length; i++) {
const harmonizationDataset = harmonizationDatasets[i];
const pipelineName = harmonizationDataset.label.split(' (')[0];
harmonizationDataset.label = `${pipelineName} (${operationNames[i]})`;
}
chart.update();
}

return {
setHarmonizationData,
setLabelsVisible,
setHarmonizationLegendNames,
getBase64Image: () => getBase64Image(chart),
getCanvas: () => {return chart}
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from typing import List, Dict
from typing import List, Dict, Tuple

import os
from collections import OrderedDict
from ..shared.table_from_list_dao import TableFromListDAO
from ..shared.metrics_table import MetricsTable
from ...utils import path_to_pipeline_name
Expand Down Expand Up @@ -28,6 +29,16 @@ def __init__(self, harmonization_folder: str, pipelines_improvements_folder: Lis
# Sort the pipelines names
self._pipelines_names.sort()

def get_default_order(self) -> List[Tuple[str, str]]:
return [('h_score', 'asc'), ('gdr', 'asc'), ('f1_score_avg', 'desc'), ('added_callers_sum', 'asc')]

def get_best_harmonization_names(self, variant_type: str) -> Dict[str, str]:
first_row = self._table.get_first_from_ordered(variant_type, self.get_default_order())
result = OrderedDict()
for pipeline_name in self._pipelines_names:
result[pipeline_name] = first_row[pipeline_name]
return result

def get_pipelines_names(self):
return self._pipelines_names

Expand Down

0 comments on commit c67d1c7

Please sign in to comment.