diff --git a/end-to-end-test/local/screenshots/reference/does_not_show_ascn_columns_study_with_no_ascn_data_element_chrome_1600x1000.png b/end-to-end-test/local/screenshots/reference/does_not_show_ascn_columns_study_with_no_ascn_data_element_chrome_1600x1000.png index 863093d6ca1..d36724250ae 100644 Binary files a/end-to-end-test/local/screenshots/reference/does_not_show_ascn_columns_study_with_no_ascn_data_element_chrome_1600x1000.png and b/end-to-end-test/local/screenshots/reference/does_not_show_ascn_columns_study_with_no_ascn_data_element_chrome_1600x1000.png differ diff --git a/end-to-end-test/local/screenshots/reference/shows_ascn_columns_for_study_where_some_samples_have_ascn_data_and_some_do_not_element_chrome_1600x1000.png b/end-to-end-test/local/screenshots/reference/shows_ascn_columns_for_study_where_some_samples_have_ascn_data_and_some_do_not_element_chrome_1600x1000.png index e736a5449b3..0875acfebc8 100644 Binary files a/end-to-end-test/local/screenshots/reference/shows_ascn_columns_for_study_where_some_samples_have_ascn_data_and_some_do_not_element_chrome_1600x1000.png and b/end-to-end-test/local/screenshots/reference/shows_ascn_columns_for_study_where_some_samples_have_ascn_data_and_some_do_not_element_chrome_1600x1000.png differ diff --git a/end-to-end-test/remote/screenshots/reference/download_tab_-_msk_impact_2017_with_alk_and_sos1_-_sos1_should_be_not_sequenced_element_chrome_1600x1000.png b/end-to-end-test/remote/screenshots/reference/download_tab_-_msk_impact_2017_with_alk_and_sos1_-_sos1_should_be_not_sequenced_element_chrome_1600x1000.png index 120dee6297d..8b3a0ee40d9 100644 Binary files a/end-to-end-test/remote/screenshots/reference/download_tab_-_msk_impact_2017_with_alk_and_sos1_-_sos1_should_be_not_sequenced_element_chrome_1600x1000.png and b/end-to-end-test/remote/screenshots/reference/download_tab_-_msk_impact_2017_with_alk_and_sos1_-_sos1_should_be_not_sequenced_element_chrome_1600x1000.png differ diff --git a/end-to-end-test/remote/screenshots/reference/download_tab_-_nsclc_tcga_broad_2016_for_query_egfr:_mut=t790m_amp_element_chrome_1600x1000.png b/end-to-end-test/remote/screenshots/reference/download_tab_-_nsclc_tcga_broad_2016_for_query_egfr:_mut=t790m_amp_element_chrome_1600x1000.png index b6bb129a45f..dabdf50111a 100644 Binary files a/end-to-end-test/remote/screenshots/reference/download_tab_-_nsclc_tcga_broad_2016_for_query_egfr:_mut=t790m_amp_element_chrome_1600x1000.png and b/end-to-end-test/remote/screenshots/reference/download_tab_-_nsclc_tcga_broad_2016_for_query_egfr:_mut=t790m_amp_element_chrome_1600x1000.png differ diff --git a/end-to-end-test/remote/screenshots/reference/download_tab_-_nsclc_tcga_broad_2016_with_cdkn2a_mdm2_and_merged_track_mdm4_tp53_element_chrome_1600x1000.png b/end-to-end-test/remote/screenshots/reference/download_tab_-_nsclc_tcga_broad_2016_with_cdkn2a_mdm2_and_merged_track_mdm4_tp53_element_chrome_1600x1000.png index c8373875715..3ec246bf8c2 100644 Binary files a/end-to-end-test/remote/screenshots/reference/download_tab_-_nsclc_tcga_broad_2016_with_cdkn2a_mdm2_and_merged_track_mdm4_tp53_element_chrome_1600x1000.png and b/end-to-end-test/remote/screenshots/reference/download_tab_-_nsclc_tcga_broad_2016_with_cdkn2a_mdm2_and_merged_track_mdm4_tp53_element_chrome_1600x1000.png differ diff --git a/end-to-end-test/remote/screenshots/reference/download_tab_-_nsclc_tcga_broad_2016_with_overlapping_tp53_element_chrome_1600x1000.png b/end-to-end-test/remote/screenshots/reference/download_tab_-_nsclc_tcga_broad_2016_with_overlapping_tp53_element_chrome_1600x1000.png index 917fccad67d..3fd85d41002 100644 Binary files a/end-to-end-test/remote/screenshots/reference/download_tab_-_nsclc_tcga_broad_2016_with_overlapping_tp53_element_chrome_1600x1000.png and b/end-to-end-test/remote/screenshots/reference/download_tab_-_nsclc_tcga_broad_2016_with_overlapping_tp53_element_chrome_1600x1000.png differ diff --git a/end-to-end-test/remote/screenshots/reference/download_tab_-_nsclc_tcga_broad_2016_with_tp53_element_chrome_1600x1000.png b/end-to-end-test/remote/screenshots/reference/download_tab_-_nsclc_tcga_broad_2016_with_tp53_element_chrome_1600x1000.png index dc2c0bdda8c..e7fd958f315 100644 Binary files a/end-to-end-test/remote/screenshots/reference/download_tab_-_nsclc_tcga_broad_2016_with_tp53_element_chrome_1600x1000.png and b/end-to-end-test/remote/screenshots/reference/download_tab_-_nsclc_tcga_broad_2016_with_tp53_element_chrome_1600x1000.png differ diff --git a/end-to-end-test/remote/screenshots/reference/enrichments_tab_coadread_tcga_pub_mrna_profile_element_chrome_1600x1000.png b/end-to-end-test/remote/screenshots/reference/enrichments_tab_coadread_tcga_pub_mrna_profile_element_chrome_1600x1000.png index ccc195d34ac..1a6aeae6d21 100644 Binary files a/end-to-end-test/remote/screenshots/reference/enrichments_tab_coadread_tcga_pub_mrna_profile_element_chrome_1600x1000.png and b/end-to-end-test/remote/screenshots/reference/enrichments_tab_coadread_tcga_pub_mrna_profile_element_chrome_1600x1000.png differ diff --git a/end-to-end-test/remote/screenshots/reference/excluding_unprofiled_samples_comparison_tab_clinical_element_chrome_1600x1000.png b/end-to-end-test/remote/screenshots/reference/excluding_unprofiled_samples_comparison_tab_clinical_element_chrome_1600x1000.png index 54f2d889247..040cf0290fc 100644 Binary files a/end-to-end-test/remote/screenshots/reference/excluding_unprofiled_samples_comparison_tab_clinical_element_chrome_1600x1000.png and b/end-to-end-test/remote/screenshots/reference/excluding_unprofiled_samples_comparison_tab_clinical_element_chrome_1600x1000.png differ diff --git a/end-to-end-test/remote/screenshots/reference/excluding_unprofiled_samples_comparison_tab_mutation_enrichments_element_chrome_1600x1000.png b/end-to-end-test/remote/screenshots/reference/excluding_unprofiled_samples_comparison_tab_mutation_enrichments_element_chrome_1600x1000.png index 6ada97a30b7..27fba2d85c1 100644 Binary files a/end-to-end-test/remote/screenshots/reference/excluding_unprofiled_samples_comparison_tab_mutation_enrichments_element_chrome_1600x1000.png and b/end-to-end-test/remote/screenshots/reference/excluding_unprofiled_samples_comparison_tab_mutation_enrichments_element_chrome_1600x1000.png differ diff --git a/end-to-end-test/remote/screenshots/reference/excluding_unprofiled_samples_mutation_tab_element_chrome_1600x1000.png b/end-to-end-test/remote/screenshots/reference/excluding_unprofiled_samples_mutation_tab_element_chrome_1600x1000.png index 9a5ada8e91d..3b6ae93a59f 100644 Binary files a/end-to-end-test/remote/screenshots/reference/excluding_unprofiled_samples_mutation_tab_element_chrome_1600x1000.png and b/end-to-end-test/remote/screenshots/reference/excluding_unprofiled_samples_mutation_tab_element_chrome_1600x1000.png differ diff --git a/end-to-end-test/remote/screenshots/reference/excluding_unprofiled_samples_mutex_tab_element_chrome_1600x1000.png b/end-to-end-test/remote/screenshots/reference/excluding_unprofiled_samples_mutex_tab_element_chrome_1600x1000.png index d1d9f1dc13e..0c0deb03ab7 100644 Binary files a/end-to-end-test/remote/screenshots/reference/excluding_unprofiled_samples_mutex_tab_element_chrome_1600x1000.png and b/end-to-end-test/remote/screenshots/reference/excluding_unprofiled_samples_mutex_tab_element_chrome_1600x1000.png differ diff --git a/end-to-end-test/remote/screenshots/reference/excluding_unprofiled_samples_survival_tab_element_chrome_1600x1000.png b/end-to-end-test/remote/screenshots/reference/excluding_unprofiled_samples_survival_tab_element_chrome_1600x1000.png index a3c69e5fd79..efe2909aeee 100644 Binary files a/end-to-end-test/remote/screenshots/reference/excluding_unprofiled_samples_survival_tab_element_chrome_1600x1000.png and b/end-to-end-test/remote/screenshots/reference/excluding_unprofiled_samples_survival_tab_element_chrome_1600x1000.png differ diff --git a/end-to-end-test/remote/screenshots/reference/group_comparison_page_cna_enrichments_tab_patient_mode_element_chrome_1600x1000.png b/end-to-end-test/remote/screenshots/reference/group_comparison_page_cna_enrichments_tab_patient_mode_element_chrome_1600x1000.png index bdf4f886ef7..8b82bfa0c51 100644 Binary files a/end-to-end-test/remote/screenshots/reference/group_comparison_page_cna_enrichments_tab_patient_mode_element_chrome_1600x1000.png and b/end-to-end-test/remote/screenshots/reference/group_comparison_page_cna_enrichments_tab_patient_mode_element_chrome_1600x1000.png differ diff --git a/end-to-end-test/remote/screenshots/reference/group_comparison_page_cna_enrichments_tab_two_groups_element_chrome_1600x1000.png b/end-to-end-test/remote/screenshots/reference/group_comparison_page_cna_enrichments_tab_two_groups_element_chrome_1600x1000.png index f34345d743a..91434cbd24e 100644 Binary files a/end-to-end-test/remote/screenshots/reference/group_comparison_page_cna_enrichments_tab_two_groups_element_chrome_1600x1000.png and b/end-to-end-test/remote/screenshots/reference/group_comparison_page_cna_enrichments_tab_two_groups_element_chrome_1600x1000.png differ diff --git a/end-to-end-test/remote/screenshots/reference/group_comparison_page_methylation_enrichments_tab_several_groups_element_chrome_1600x1000.png b/end-to-end-test/remote/screenshots/reference/group_comparison_page_methylation_enrichments_tab_several_groups_element_chrome_1600x1000.png index 8891719ad73..cd82b3366ea 100644 Binary files a/end-to-end-test/remote/screenshots/reference/group_comparison_page_methylation_enrichments_tab_several_groups_element_chrome_1600x1000.png and b/end-to-end-test/remote/screenshots/reference/group_comparison_page_methylation_enrichments_tab_several_groups_element_chrome_1600x1000.png differ diff --git a/end-to-end-test/remote/screenshots/reference/group_comparison_page_methylation_enrichments_tab_two_groups_element_chrome_1600x1000.png b/end-to-end-test/remote/screenshots/reference/group_comparison_page_methylation_enrichments_tab_two_groups_element_chrome_1600x1000.png index 753a0be6f3e..5f04e0cc58c 100644 Binary files a/end-to-end-test/remote/screenshots/reference/group_comparison_page_methylation_enrichments_tab_two_groups_element_chrome_1600x1000.png and b/end-to-end-test/remote/screenshots/reference/group_comparison_page_methylation_enrichments_tab_two_groups_element_chrome_1600x1000.png differ diff --git a/end-to-end-test/remote/screenshots/reference/group_comparison_page_microbiome_signature_tab_several_groups_element_chrome_1600x1000.png b/end-to-end-test/remote/screenshots/reference/group_comparison_page_microbiome_signature_tab_several_groups_element_chrome_1600x1000.png index 9167fcbd796..ec1829e8035 100644 Binary files a/end-to-end-test/remote/screenshots/reference/group_comparison_page_microbiome_signature_tab_several_groups_element_chrome_1600x1000.png and b/end-to-end-test/remote/screenshots/reference/group_comparison_page_microbiome_signature_tab_several_groups_element_chrome_1600x1000.png differ diff --git a/end-to-end-test/remote/screenshots/reference/group_comparison_page_microbiome_signature_tab_two_groups_element_chrome_1600x1000.png b/end-to-end-test/remote/screenshots/reference/group_comparison_page_microbiome_signature_tab_two_groups_element_chrome_1600x1000.png index 944d463da82..838ea58ed3e 100644 Binary files a/end-to-end-test/remote/screenshots/reference/group_comparison_page_microbiome_signature_tab_two_groups_element_chrome_1600x1000.png and b/end-to-end-test/remote/screenshots/reference/group_comparison_page_microbiome_signature_tab_two_groups_element_chrome_1600x1000.png differ diff --git a/end-to-end-test/remote/screenshots/reference/group_comparison_page_mrna_enrichments_tab_several_groups_element_chrome_1600x1000.png b/end-to-end-test/remote/screenshots/reference/group_comparison_page_mrna_enrichments_tab_several_groups_element_chrome_1600x1000.png index b12ddd1d1f3..8049174dbec 100644 Binary files a/end-to-end-test/remote/screenshots/reference/group_comparison_page_mrna_enrichments_tab_several_groups_element_chrome_1600x1000.png and b/end-to-end-test/remote/screenshots/reference/group_comparison_page_mrna_enrichments_tab_several_groups_element_chrome_1600x1000.png differ diff --git a/end-to-end-test/remote/screenshots/reference/group_comparison_page_mrna_enrichments_tab_two_groups_element_chrome_1600x1000.png b/end-to-end-test/remote/screenshots/reference/group_comparison_page_mrna_enrichments_tab_two_groups_element_chrome_1600x1000.png index fe01f649843..ea034a2b438 100644 Binary files a/end-to-end-test/remote/screenshots/reference/group_comparison_page_mrna_enrichments_tab_two_groups_element_chrome_1600x1000.png and b/end-to-end-test/remote/screenshots/reference/group_comparison_page_mrna_enrichments_tab_two_groups_element_chrome_1600x1000.png differ diff --git a/end-to-end-test/remote/screenshots/reference/group_comparison_page_protein_enrichments_tab_several_groups_element_chrome_1600x1000.png b/end-to-end-test/remote/screenshots/reference/group_comparison_page_protein_enrichments_tab_several_groups_element_chrome_1600x1000.png index 2074a176b07..c017590ab85 100644 Binary files a/end-to-end-test/remote/screenshots/reference/group_comparison_page_protein_enrichments_tab_several_groups_element_chrome_1600x1000.png and b/end-to-end-test/remote/screenshots/reference/group_comparison_page_protein_enrichments_tab_several_groups_element_chrome_1600x1000.png differ diff --git a/end-to-end-test/remote/screenshots/reference/group_comparison_page_protein_enrichments_tab_two_groups_element_chrome_1600x1000.png b/end-to-end-test/remote/screenshots/reference/group_comparison_page_protein_enrichments_tab_two_groups_element_chrome_1600x1000.png index cb213aa55e4..90634b53bc2 100644 Binary files a/end-to-end-test/remote/screenshots/reference/group_comparison_page_protein_enrichments_tab_two_groups_element_chrome_1600x1000.png and b/end-to-end-test/remote/screenshots/reference/group_comparison_page_protein_enrichments_tab_two_groups_element_chrome_1600x1000.png differ diff --git a/end-to-end-test/remote/screenshots/reference/no_session_comparison_tab_mrna_enrichments_element_chrome_1600x1000.png b/end-to-end-test/remote/screenshots/reference/no_session_comparison_tab_mrna_enrichments_element_chrome_1600x1000.png index 7d7e59d0cb4..ef9c9522388 100644 Binary files a/end-to-end-test/remote/screenshots/reference/no_session_comparison_tab_mrna_enrichments_element_chrome_1600x1000.png and b/end-to-end-test/remote/screenshots/reference/no_session_comparison_tab_mrna_enrichments_element_chrome_1600x1000.png differ diff --git a/end-to-end-test/remote/screenshots/reference/no_session_comparison_tab_mutation_enrichments_element_chrome_1600x1000.png b/end-to-end-test/remote/screenshots/reference/no_session_comparison_tab_mutation_enrichments_element_chrome_1600x1000.png index 76015bf9bc9..5a921a0485a 100644 Binary files a/end-to-end-test/remote/screenshots/reference/no_session_comparison_tab_mutation_enrichments_element_chrome_1600x1000.png and b/end-to-end-test/remote/screenshots/reference/no_session_comparison_tab_mutation_enrichments_element_chrome_1600x1000.png differ diff --git a/end-to-end-test/remote/screenshots/reference/no_session_mutation_tab_element_chrome_1600x1000.png b/end-to-end-test/remote/screenshots/reference/no_session_mutation_tab_element_chrome_1600x1000.png index c9e25c9e2e5..fb7bd990452 100644 Binary files a/end-to-end-test/remote/screenshots/reference/no_session_mutation_tab_element_chrome_1600x1000.png and b/end-to-end-test/remote/screenshots/reference/no_session_mutation_tab_element_chrome_1600x1000.png differ diff --git a/end-to-end-test/remote/screenshots/reference/no_session_mutex_tab_element_chrome_1600x1000.png b/end-to-end-test/remote/screenshots/reference/no_session_mutex_tab_element_chrome_1600x1000.png index 15d970517e2..3e30f695a4d 100644 Binary files a/end-to-end-test/remote/screenshots/reference/no_session_mutex_tab_element_chrome_1600x1000.png and b/end-to-end-test/remote/screenshots/reference/no_session_mutex_tab_element_chrome_1600x1000.png differ diff --git a/end-to-end-test/remote/screenshots/reference/patient_view_lgg_ucsf_2014_p04_element_chrome_1600x1000.png b/end-to-end-test/remote/screenshots/reference/patient_view_lgg_ucsf_2014_p04_element_chrome_1600x1000.png index e205967b4f1..72dd937a165 100644 Binary files a/end-to-end-test/remote/screenshots/reference/patient_view_lgg_ucsf_2014_p04_element_chrome_1600x1000.png and b/end-to-end-test/remote/screenshots/reference/patient_view_lgg_ucsf_2014_p04_element_chrome_1600x1000.png differ diff --git a/end-to-end-test/remote/screenshots/reference/pvge_heatmap_with_two_mutations_selected_from_before_element_chrome_1600x1000.png b/end-to-end-test/remote/screenshots/reference/pvge_heatmap_with_two_mutations_selected_from_before_element_chrome_1600x1000.png index f268453ef75..d84f540d65f 100644 Binary files a/end-to-end-test/remote/screenshots/reference/pvge_heatmap_with_two_mutations_selected_from_before_element_chrome_1600x1000.png and b/end-to-end-test/remote/screenshots/reference/pvge_heatmap_with_two_mutations_selected_from_before_element_chrome_1600x1000.png differ diff --git a/end-to-end-test/remote/screenshots/reference/pvge_hover_a_mutation_with_heatmap_element_chrome_1600x1000.png b/end-to-end-test/remote/screenshots/reference/pvge_hover_a_mutation_with_heatmap_element_chrome_1600x1000.png index a860338cfa0..a9a6b8008d3 100644 Binary files a/end-to-end-test/remote/screenshots/reference/pvge_hover_a_mutation_with_heatmap_element_chrome_1600x1000.png and b/end-to-end-test/remote/screenshots/reference/pvge_hover_a_mutation_with_heatmap_element_chrome_1600x1000.png differ diff --git a/end-to-end-test/remote/screenshots/reference/pvge_hover_a_mutation_with_line_chart_element_chrome_1600x1000.png b/end-to-end-test/remote/screenshots/reference/pvge_hover_a_mutation_with_line_chart_element_chrome_1600x1000.png index ed213a6549d..02c068fef5c 100644 Binary files a/end-to-end-test/remote/screenshots/reference/pvge_hover_a_mutation_with_line_chart_element_chrome_1600x1000.png and b/end-to-end-test/remote/screenshots/reference/pvge_hover_a_mutation_with_line_chart_element_chrome_1600x1000.png differ diff --git a/end-to-end-test/remote/screenshots/reference/pvge_initial_view_with_line_chart_element_chrome_1600x1000.png b/end-to-end-test/remote/screenshots/reference/pvge_initial_view_with_line_chart_element_chrome_1600x1000.png index cff9a55a53f..f334b927b97 100644 Binary files a/end-to-end-test/remote/screenshots/reference/pvge_initial_view_with_line_chart_element_chrome_1600x1000.png and b/end-to-end-test/remote/screenshots/reference/pvge_initial_view_with_line_chart_element_chrome_1600x1000.png differ diff --git a/end-to-end-test/remote/screenshots/reference/pvge_one_mutation_selected_with_heatmap_element_chrome_1600x1000.png b/end-to-end-test/remote/screenshots/reference/pvge_one_mutation_selected_with_heatmap_element_chrome_1600x1000.png index 8cb8369eeae..c0f4ac02414 100644 Binary files a/end-to-end-test/remote/screenshots/reference/pvge_one_mutation_selected_with_heatmap_element_chrome_1600x1000.png and b/end-to-end-test/remote/screenshots/reference/pvge_one_mutation_selected_with_heatmap_element_chrome_1600x1000.png differ diff --git a/end-to-end-test/remote/screenshots/reference/pvge_one_mutation_selected_with_line_chart_element_chrome_1600x1000.png b/end-to-end-test/remote/screenshots/reference/pvge_one_mutation_selected_with_line_chart_element_chrome_1600x1000.png index 719e4799cc1..007435d7a71 100644 Binary files a/end-to-end-test/remote/screenshots/reference/pvge_one_mutation_selected_with_line_chart_element_chrome_1600x1000.png and b/end-to-end-test/remote/screenshots/reference/pvge_one_mutation_selected_with_line_chart_element_chrome_1600x1000.png differ diff --git a/end-to-end-test/remote/screenshots/reference/pvge_show_timeline_element_chrome_1600x1000.png b/end-to-end-test/remote/screenshots/reference/pvge_show_timeline_element_chrome_1600x1000.png index 7a052003482..87d77cba047 100644 Binary files a/end-to-end-test/remote/screenshots/reference/pvge_show_timeline_element_chrome_1600x1000.png and b/end-to-end-test/remote/screenshots/reference/pvge_show_timeline_element_chrome_1600x1000.png differ diff --git a/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_clinical_tab_bar_chart_chi_squared_test_element_chrome_1600x1000.png b/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_clinical_tab_bar_chart_chi_squared_test_element_chrome_1600x1000.png index e9a288101c4..66d613ef4d5 100644 Binary files a/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_clinical_tab_bar_chart_chi_squared_test_element_chrome_1600x1000.png and b/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_clinical_tab_bar_chart_chi_squared_test_element_chrome_1600x1000.png differ diff --git a/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_clinical_tab_include_overlapping_samples_kruskal_wallis_test_element_chrome_1600x1000.png b/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_clinical_tab_include_overlapping_samples_kruskal_wallis_test_element_chrome_1600x1000.png index 46ba343e492..c645c65b937 100644 Binary files a/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_clinical_tab_include_overlapping_samples_kruskal_wallis_test_element_chrome_1600x1000.png and b/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_clinical_tab_include_overlapping_samples_kruskal_wallis_test_element_chrome_1600x1000.png differ diff --git a/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_clinical_tab_log_scale__kruskal_wallis_test_element_chrome_1600x1000.png b/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_clinical_tab_log_scale__kruskal_wallis_test_element_chrome_1600x1000.png index cb618c998df..b4e6641c412 100644 Binary files a/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_clinical_tab_log_scale__kruskal_wallis_test_element_chrome_1600x1000.png and b/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_clinical_tab_log_scale__kruskal_wallis_test_element_chrome_1600x1000.png differ diff --git a/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_clinical_tab_percentage_stacked_bar_chart_exclude_overlapping_samples_chi_squared_test_element_chrome_1600x1000.png b/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_clinical_tab_percentage_stacked_bar_chart_exclude_overlapping_samples_chi_squared_test_element_chrome_1600x1000.png index 60fdf63145f..2d36e1d7eec 100644 Binary files a/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_clinical_tab_percentage_stacked_bar_chart_exclude_overlapping_samples_chi_squared_test_element_chrome_1600x1000.png and b/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_clinical_tab_percentage_stacked_bar_chart_exclude_overlapping_samples_chi_squared_test_element_chrome_1600x1000.png differ diff --git a/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_clinical_tab_stacked_bar_chart_chi_squared_test_element_chrome_1600x1000.png b/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_clinical_tab_stacked_bar_chart_chi_squared_test_element_chrome_1600x1000.png index 23970415d57..07c3d5f3669 100644 Binary files a/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_clinical_tab_stacked_bar_chart_chi_squared_test_element_chrome_1600x1000.png and b/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_clinical_tab_stacked_bar_chart_chi_squared_test_element_chrome_1600x1000.png differ diff --git a/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_clinical_tab_stacked_bar_chart_horizontal_bars_chi_squared_test_element_chrome_1600x1000.png b/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_clinical_tab_stacked_bar_chart_horizontal_bars_chi_squared_test_element_chrome_1600x1000.png index bb4d22a5da4..2b4d0046bf4 100644 Binary files a/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_clinical_tab_stacked_bar_chart_horizontal_bars_chi_squared_test_element_chrome_1600x1000.png and b/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_clinical_tab_stacked_bar_chart_horizontal_bars_chi_squared_test_element_chrome_1600x1000.png differ diff --git a/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_clinical_tab_stacked_bar_chart_swaped_axes_chi_squared_test_element_chrome_1600x1000.png b/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_clinical_tab_stacked_bar_chart_swaped_axes_chi_squared_test_element_chrome_1600x1000.png index 3007c33d7be..0c63d545373 100644 Binary files a/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_clinical_tab_stacked_bar_chart_swaped_axes_chi_squared_test_element_chrome_1600x1000.png and b/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_clinical_tab_stacked_bar_chart_swaped_axes_chi_squared_test_element_chrome_1600x1000.png differ diff --git a/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_clinical_tab_swaped_axes_kruskal_wallis_test_element_chrome_1600x1000.png b/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_clinical_tab_swaped_axes_kruskal_wallis_test_element_chrome_1600x1000.png index 62d5dee88dc..e8254165d13 100644 Binary files a/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_clinical_tab_swaped_axes_kruskal_wallis_test_element_chrome_1600x1000.png and b/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_clinical_tab_swaped_axes_kruskal_wallis_test_element_chrome_1600x1000.png differ diff --git a/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_methylation_enrichments_tab_several_groups_element_chrome_1600x1000.png b/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_methylation_enrichments_tab_several_groups_element_chrome_1600x1000.png index 049088e08f1..1391ec838ac 100644 Binary files a/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_methylation_enrichments_tab_several_groups_element_chrome_1600x1000.png and b/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_methylation_enrichments_tab_several_groups_element_chrome_1600x1000.png differ diff --git a/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_methylation_enrichments_tab_two_groups_element_chrome_1600x1000.png b/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_methylation_enrichments_tab_two_groups_element_chrome_1600x1000.png index 2afec1d3aa2..7ac0cfc8b53 100644 Binary files a/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_methylation_enrichments_tab_two_groups_element_chrome_1600x1000.png and b/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_methylation_enrichments_tab_two_groups_element_chrome_1600x1000.png differ diff --git a/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_mrna_enrichments_tab_several_groups_element_chrome_1600x1000.png b/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_mrna_enrichments_tab_several_groups_element_chrome_1600x1000.png index 9e94ec2abde..d85eed607dd 100644 Binary files a/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_mrna_enrichments_tab_several_groups_element_chrome_1600x1000.png and b/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_mrna_enrichments_tab_several_groups_element_chrome_1600x1000.png differ diff --git a/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_mrna_enrichments_tab_two_groups_element_chrome_1600x1000.png b/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_mrna_enrichments_tab_two_groups_element_chrome_1600x1000.png index ed61e878f71..e69fc9457ac 100644 Binary files a/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_mrna_enrichments_tab_two_groups_element_chrome_1600x1000.png and b/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_mrna_enrichments_tab_two_groups_element_chrome_1600x1000.png differ diff --git a/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_protein_enrichments_tab_several_groups_element_chrome_1600x1000.png b/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_protein_enrichments_tab_several_groups_element_chrome_1600x1000.png index de288d4f20f..bef6072e736 100644 Binary files a/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_protein_enrichments_tab_several_groups_element_chrome_1600x1000.png and b/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_protein_enrichments_tab_several_groups_element_chrome_1600x1000.png differ diff --git a/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_protein_enrichments_tab_two_groups_element_chrome_1600x1000.png b/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_protein_enrichments_tab_two_groups_element_chrome_1600x1000.png index a27c164597e..38252a624aa 100644 Binary files a/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_protein_enrichments_tab_two_groups_element_chrome_1600x1000.png and b/end-to-end-test/remote/screenshots/reference/results_view_comparison_tab_protein_enrichments_tab_two_groups_element_chrome_1600x1000.png differ diff --git a/end-to-end-test/remote/screenshots/reference/session_comparison_tab_clinical_element_chrome_1600x1000.png b/end-to-end-test/remote/screenshots/reference/session_comparison_tab_clinical_element_chrome_1600x1000.png index 528a3024a30..d4a2965aaf6 100644 Binary files a/end-to-end-test/remote/screenshots/reference/session_comparison_tab_clinical_element_chrome_1600x1000.png and b/end-to-end-test/remote/screenshots/reference/session_comparison_tab_clinical_element_chrome_1600x1000.png differ diff --git a/end-to-end-test/remote/screenshots/reference/session_comparison_tab_mrna_enrichments_element_chrome_1600x1000.png b/end-to-end-test/remote/screenshots/reference/session_comparison_tab_mrna_enrichments_element_chrome_1600x1000.png index 7d7e59d0cb4..ef9c9522388 100644 Binary files a/end-to-end-test/remote/screenshots/reference/session_comparison_tab_mrna_enrichments_element_chrome_1600x1000.png and b/end-to-end-test/remote/screenshots/reference/session_comparison_tab_mrna_enrichments_element_chrome_1600x1000.png differ diff --git a/end-to-end-test/remote/screenshots/reference/session_comparison_tab_mutation_enrichments_element_chrome_1600x1000.png b/end-to-end-test/remote/screenshots/reference/session_comparison_tab_mutation_enrichments_element_chrome_1600x1000.png index 76015bf9bc9..5a921a0485a 100644 Binary files a/end-to-end-test/remote/screenshots/reference/session_comparison_tab_mutation_enrichments_element_chrome_1600x1000.png and b/end-to-end-test/remote/screenshots/reference/session_comparison_tab_mutation_enrichments_element_chrome_1600x1000.png differ diff --git a/end-to-end-test/remote/screenshots/reference/session_mutation_tab_element_chrome_1600x1000.png b/end-to-end-test/remote/screenshots/reference/session_mutation_tab_element_chrome_1600x1000.png index c9e25c9e2e5..fb7bd990452 100644 Binary files a/end-to-end-test/remote/screenshots/reference/session_mutation_tab_element_chrome_1600x1000.png and b/end-to-end-test/remote/screenshots/reference/session_mutation_tab_element_chrome_1600x1000.png differ diff --git a/end-to-end-test/remote/screenshots/reference/session_mutex_tab_element_chrome_1600x1000.png b/end-to-end-test/remote/screenshots/reference/session_mutex_tab_element_chrome_1600x1000.png index 15d970517e2..3e30f695a4d 100644 Binary files a/end-to-end-test/remote/screenshots/reference/session_mutex_tab_element_chrome_1600x1000.png and b/end-to-end-test/remote/screenshots/reference/session_mutex_tab_element_chrome_1600x1000.png differ diff --git a/packages/cbioportal-frontend-commons/src/components/TableCellStatus.tsx b/packages/cbioportal-frontend-commons/src/components/TableCellStatus.tsx index af8f30324ae..66dfd61a61a 100644 --- a/packages/cbioportal-frontend-commons/src/components/TableCellStatus.tsx +++ b/packages/cbioportal-frontend-commons/src/components/TableCellStatus.tsx @@ -32,7 +32,7 @@ export default class TableCellStatusIndicator extends React.Component< break; case TableCellStatus.NA: alt = this.props.naAlt || 'Data not available.'; - text = ''; + text = 'n/a'; break; } return ( diff --git a/src/pages/resultsView/ResultsViewPageStore.ts b/src/pages/resultsView/ResultsViewPageStore.ts index e9cc7c89f09..4bb8eb5a8bd 100644 --- a/src/pages/resultsView/ResultsViewPageStore.ts +++ b/src/pages/resultsView/ResultsViewPageStore.ts @@ -3442,6 +3442,9 @@ export class ResultsViewPageStore { this.uniqueSampleKeyToTumorType.result!, this.generateGenomeNexusHgvsgUrl, this.clinicalDataGroupedBySampleMap, + this.mutationsTabClinicalAttributes, + this.clinicalAttributeIdToAvailableSampleCount, + this.sampleCount, this.genomeNexusClient, this.genomeNexusInternalClient, () => this.urlWrapper.query.mutations_transcript_id @@ -3586,6 +3589,25 @@ export class ResultsViewPageStore { {} ); + readonly mutationsTabClinicalAttributes = remoteData({ + await: () => [this.studyIds], + invoke: async () => { + const clinicalAttributes = await client.fetchClinicalAttributesUsingPOST( + { + studyIds: this.studyIds.result!, + } + ); + const excludeList = ['CANCER_TYPE_DETAILED', 'MUTATION_COUNT']; + + return _.uniqBy( + clinicalAttributes.filter( + x => !excludeList.includes(x.clinicalAttributeId) + ), + x => x.clinicalAttributeId + ); + }, + }); + private getClinicalData( clinicalDataType: 'SAMPLE' | 'PATIENT', studies: any[], @@ -3647,6 +3669,11 @@ export class ResultsViewPageStore { [] ); + readonly sampleCount = remoteData({ + await: () => [this.samples], + invoke: () => Promise.resolve(this.samples.result!.length), + }); + readonly samples = remoteData( { await: () => [this.studyToDataQueryFilter], diff --git a/src/pages/resultsView/mutation/AddColumns.tsx b/src/pages/resultsView/mutation/AddColumns.tsx new file mode 100644 index 00000000000..8ad2ca2d253 --- /dev/null +++ b/src/pages/resultsView/mutation/AddColumns.tsx @@ -0,0 +1,270 @@ +import * as React from 'react'; +import * as _ from 'lodash'; +import { Checkbox } from 'react-bootstrap'; +import { observer } from 'mobx-react'; +import { action, computed, makeObservable, observable } from 'mobx'; +import { remoteData, getTextWidth } from 'cbioportal-frontend-commons'; +import { ClinicalAttribute } from 'cbioportal-ts-api-client'; +import { IColumnVisibilityControlsProps } from 'shared/components/columnVisibilityControls/ColumnVisibilityControls'; +import { MSKTab, MSKTabs } from 'shared/components/MSKTabs/MSKTabs'; +import CustomDropdown from 'shared/components/oncoprint/controls/CustomDropdown'; +import AddChartByType from '../../studyView/addChartButton/addChartByType/AddChartByType'; +import { ChartDataCountSet } from '../../studyView/StudyViewUtils'; + +export interface IAddColumnsProps extends IColumnVisibilityControlsProps { + clinicalAttributes: ClinicalAttribute[]; + clinicalAttributeIdToAvailableSampleCount: { [id: string]: number }; + sampleCount: number; +} + +enum Tab { + MUTATIONS = 'Mutations', + CLINICAL = 'Clinical', +} + +type Option = { + key: string; + label: string; + selected: boolean; +}; + +// Copied these constants from oncoprint/AddTracks.tsx +// since importing them results in errors during testing +// due to a separate import in that file. +const MIN_DROPDOWN_WIDTH = 400; +const CONTAINER_PADDING_WIDTH = 20; +const TAB_PADDING_WIDTH = 14; +const COUNT_PADDING_WIDTH = 17; +@observer +export default class AddColumns extends React.Component { + @observable tabId: Tab = Tab.MUTATIONS; + + constructor(props: IAddColumnsProps) { + super(props); + makeObservable(this); + } + + @action.bound + private updateTabId(newId: Tab) { + this.tabId = newId; + } + + @action.bound + private addAll(ids: string[], options: Option[] | undefined) { + if (this.props.onColumnToggled && options) { + for (let option of options) { + if (!option.selected && ids.includes(option.key)) { + this.props.onColumnToggled(option.key); + } + } + } + } + + @action.bound + private clearAll(ids: string[], options: Option[] | undefined) { + if (this.props.onColumnToggled && options) { + for (let option of options) { + if (option.selected && ids.includes(option.key)) { + this.props.onColumnToggled(option.key); + } + } + } + } + + @action.bound + private toggle(id: string) { + if (this.props.onColumnToggled && id) { + this.props.onColumnToggled(id); + } + } + + readonly emptyPromise = remoteData({ + invoke: () => + new Promise(() => { + return; + }), + }); + + readonly clinicalAttributeIdToAvailableFrequencyPromise = remoteData({ + invoke: () => + Promise.resolve( + _.mapValues( + this.props.clinicalAttributeIdToAvailableSampleCount, + count => (100 * count) / this.props.sampleCount + ) + ), + }); + + @computed get clinicalAttributeIds(): Set { + let ids: Set = new Set(); + this.props.clinicalAttributes.forEach(x => + ids.add(x.clinicalAttributeId) + ); + return ids.add('CANCER_TYPE_DETAILED').add('MUTATION_COUNT'); + } + + @computed get mutationsOptions(): Option[] | undefined { + return this.props.columnVisibility + ?.filter(col => !this.clinicalAttributeIds.has(col.id)) + .map(col => ({ + key: col.id, + label: col.name, + selected: col.visible, + })); + } + + @computed get mutationsTabContent() { + return ( +
+ {this.mutationsOptions && ( + + this.addAll(ids, this.mutationsOptions) + } + onClearAll={(ids: string[]) => + this.clearAll(ids, this.mutationsOptions) + } + onToggleOption={this.toggle} + optionsGivenInSortedOrder={true} + width={this.dropdownWidth} + excludeFrequency={true} + /> + )} +
+ ); + } + + @computed get clinicalOptions(): Option[] | undefined { + if (!this.props.columnVisibility) return undefined; + + return this.props.columnVisibility + .filter(col => this.clinicalAttributeIds.has(col.id)) + .map(col => ({ + key: col.id, + label: col.name, + selected: col.visible, + })); + } + + @computed get clinicalTabContent() { + return ( +
+ {this.props.columnVisibility && this.clinicalOptions && ( + + this.addAll(ids, this.clinicalOptions) + } + onClearAll={(ids: string[]) => + this.clearAll(ids, this.clinicalOptions) + } + onToggleOption={this.toggle} + optionsGivenInSortedOrder={false} + width={this.dropdownWidth} + /> + )} +
+ ); + } + + @computed get mutationsTabText() { + return ( +
+ {Tab.MUTATIONS} + + + {this.mutationsOptions?.length} + + +
+ ); + } + + @computed get clinicalTabText() { + return ( +
+ {Tab.CLINICAL} + + + {this.clinicalOptions?.length} + + +
+ ); + } + + private getTextPixel(text: string | undefined, fontSize: string) { + // This is a very specified function to calculate the text length in Add Tracks dropdown + const FRONT_FAMILY = 'Helvetica Neue'; + return Math.floor( + getTextWidth(text ? text : '', FRONT_FAMILY, fontSize) + ); + } + + @computed get dropdownWidth() { + let width = 2 * CONTAINER_PADDING_WIDTH; + const HEADER_FONT_SIZE = '14px'; + const COUNT_FONT_SIZE = '11px'; + + const textWidth = + this.getTextPixel(Tab.CLINICAL, HEADER_FONT_SIZE) + + TAB_PADDING_WIDTH; + const countTextWidth = + this.getTextPixel( + this.clinicalOptions?.length.toString(), + COUNT_FONT_SIZE + ) + COUNT_PADDING_WIDTH; + width += textWidth + countTextWidth; + + return Math.max(width, MIN_DROPDOWN_WIDTH); + } + + render() { + return ( +
+ +
+ + + {this.mutationsTabContent} + + + {this.clinicalTabContent} + + +
+
+
+ ); + } +} diff --git a/src/pages/resultsView/mutation/ResultsViewMutationMapper.tsx b/src/pages/resultsView/mutation/ResultsViewMutationMapper.tsx index 02090041071..8d4139981cf 100644 --- a/src/pages/resultsView/mutation/ResultsViewMutationMapper.tsx +++ b/src/pages/resultsView/mutation/ResultsViewMutationMapper.tsx @@ -88,7 +88,10 @@ export default class ResultsViewMutationMapper extends MutationMapper< this.props.store.mutationData, this.props.store.indexedVariantAnnotations, this.props.store.activeTranscript, - this.props.store.clinicalDataGroupedBySampleMap + this.props.store.clinicalDataGroupedBySampleMap, + this.props.store.mutationsTabClinicalAttributes, + this.props.store.clinicalAttributeIdToAvailableSampleCount, + this.props.store.sampleCount ) === 'pending' ); } @@ -164,6 +167,13 @@ export default class ResultsViewMutationMapper extends MutationMapper< existsSomeMutationWithAscnProperty={ this.props.existsSomeMutationWithAscnProperty } + mutationsTabClinicalAttributes={ + this.props.store.mutationsTabClinicalAttributes + } + clinicalAttributeIdToAvailableSampleCount={ + this.props.store.clinicalAttributeIdToAvailableSampleCount + } + sampleCount={this.props.store.sampleCount} /> ); } diff --git a/src/pages/resultsView/mutation/ResultsViewMutationMapperStore.ts b/src/pages/resultsView/mutation/ResultsViewMutationMapperStore.ts index e3b010cc22e..c4dcabd7c3d 100644 --- a/src/pages/resultsView/mutation/ResultsViewMutationMapperStore.ts +++ b/src/pages/resultsView/mutation/ResultsViewMutationMapperStore.ts @@ -2,6 +2,7 @@ import { IHotspotIndex } from 'cbioportal-utils'; import { Mutation, Gene, + ClinicalAttribute, ClinicalData, CancerStudy, MolecularProfile, @@ -69,6 +70,11 @@ export default class ResultsViewMutationMapperStore extends MutationMapperStore public clinicalDataGroupedBySampleMap: MobxPromise<{ [sampleId: string]: ClinicalData[]; }>, + public mutationsTabClinicalAttributes: MobxPromise, + public clinicalAttributeIdToAvailableSampleCount: MobxPromise<{ + [id: string]: number; + }>, + public sampleCount: MobxPromise, protected genomenexusClient?: GenomeNexusAPI, protected genomenexusInternalClient?: GenomeNexusAPIInternal, public getTranscriptId?: () => string diff --git a/src/pages/resultsView/mutation/ResultsViewMutationTable.tsx b/src/pages/resultsView/mutation/ResultsViewMutationTable.tsx index 62ee8f7352b..d5d4541a558 100644 --- a/src/pages/resultsView/mutation/ResultsViewMutationTable.tsx +++ b/src/pages/resultsView/mutation/ResultsViewMutationTable.tsx @@ -1,5 +1,7 @@ import * as React from 'react'; +import * as _ from 'lodash'; import { observer } from 'mobx-react'; +import MobxPromise from 'mobxpromise'; import { IMutationTableProps, MutationTableColumnType, @@ -7,15 +9,23 @@ import { } from 'shared/components/mutationTable/MutationTable'; import CancerTypeColumnFormatter from 'shared/components/mutationTable/column/CancerTypeColumnFormatter'; import TumorAlleleFreqColumnFormatter from 'shared/components/mutationTable/column/TumorAlleleFreqColumnFormatter'; -import { Mutation, ClinicalData } from 'cbioportal-ts-api-client'; +import { Mutation, ClinicalAttribute } from 'cbioportal-ts-api-client'; import ExonColumnFormatter from 'shared/components/mutationTable/column/ExonColumnFormatter'; +import ClinicalAttributeColumnFormatter from 'shared/components/mutationTable/column/ClinicalAttributeColumnFormatter'; import { ASCNAttributes } from 'shared/enums/ASCNEnums'; +import { IColumnVisibilityControlsProps } from 'shared/components/columnVisibilityControls/ColumnVisibilityControls'; +import AddColumns from './AddColumns'; export interface IResultsViewMutationTableProps extends IMutationTableProps { // add results view specific props here if needed totalNumberOfExons?: string; isCanonicalTranscript: boolean | undefined; existsSomeMutationWithAscnProperty: { [property: string]: boolean }; + mutationsTabClinicalAttributes: MobxPromise; + clinicalAttributeIdToAvailableSampleCount: MobxPromise<{ + [id: string]: number; + }>; + sampleCount: MobxPromise; } // export default class ResultsViewMutationTable extends MutationTable< @@ -53,7 +63,7 @@ export default class ResultsViewMutationTable extends MutationTable< MutationTableColumnType.COSMIC, MutationTableColumnType.TUMOR_ALLELE_FREQ, MutationTableColumnType.NORMAL_ALLELE_FREQ, - MutationTableColumnType.CANCER_TYPE, + MutationTableColumnType.CANCER_TYPE_DETAILED, MutationTableColumnType.NUM_MUTATIONS, MutationTableColumnType.EXON, MutationTableColumnType.HGVSC, @@ -62,8 +72,31 @@ export default class ResultsViewMutationTable extends MutationTable< MutationTableColumnType.DBSNP, MutationTableColumnType.SIGNAL, ], + columnVisibilityProps: {}, }; + constructor(props: IResultsViewMutationTableProps) { + super(props); + this.props.columnVisibilityProps!.customDropdown = ( + columnVisibilityControlsProps: IColumnVisibilityControlsProps + ) => ( + + ); + } + componentWillUpdate(nextProps: IResultsViewMutationTableProps) { this._columns[MutationTableColumnType.STUDY].visible = !!( nextProps.studyIdToStudy && @@ -74,9 +107,41 @@ export default class ResultsViewMutationTable extends MutationTable< protected generateColumns() { super.generateColumns(); + // generate clinical attribute columns + let clinicalAttributes = this.props.mutationsTabClinicalAttributes + .result!; + for (let i = 0; i < clinicalAttributes.length; i++) { + const attributeId = clinicalAttributes[i].clinicalAttributeId; + if ( + this.props.columns && + !this.props.columns.includes(attributeId) + ) { + this.props.columns.push(attributeId); + } + + this._columns[attributeId] = { + id: attributeId, + name: clinicalAttributes[i].displayName, + render: ClinicalAttributeColumnFormatter.makeRenderFunction( + clinicalAttributes[i] + ), + download: (d: Mutation[]) => + ClinicalAttributeColumnFormatter.getTextValue( + d, + clinicalAttributes[i] + ), + sortBy: (d: Mutation[]) => + ClinicalAttributeColumnFormatter.sortBy( + d, + clinicalAttributes[i] + ), + visible: false, + }; + } + // override default visibility for some columns this._columns[ - MutationTableColumnType.CANCER_TYPE + MutationTableColumnType.CANCER_TYPE_DETAILED ].visible = CancerTypeColumnFormatter.isVisible( this.props.dataStore ? this.props.dataStore.allData @@ -98,7 +163,7 @@ export default class ResultsViewMutationTable extends MutationTable< // order columns this._columns[MutationTableColumnType.STUDY].order = 0; this._columns[MutationTableColumnType.SAMPLE_ID].order = 10; - this._columns[MutationTableColumnType.CANCER_TYPE].order = 15; + this._columns[MutationTableColumnType.CANCER_TYPE_DETAILED].order = 15; this._columns[MutationTableColumnType.PROTEIN_CHANGE].order = 20; this._columns[MutationTableColumnType.ANNOTATION].order = 30; @@ -137,7 +202,7 @@ export default class ResultsViewMutationTable extends MutationTable< // exclude this._columns[ - MutationTableColumnType.CANCER_TYPE + MutationTableColumnType.CANCER_TYPE_DETAILED ].shouldExclude = () => { return !this.props.uniqueSampleKeyToTumorType; }; diff --git a/src/pages/staticPages/tools/mutationMapper/StandaloneMutationTable.tsx b/src/pages/staticPages/tools/mutationMapper/StandaloneMutationTable.tsx index e0f5149189c..d10666b4c04 100644 --- a/src/pages/staticPages/tools/mutationMapper/StandaloneMutationTable.tsx +++ b/src/pages/staticPages/tools/mutationMapper/StandaloneMutationTable.tsx @@ -23,7 +23,7 @@ export default class StandaloneMutationTable extends MutationTable< ...MutationTable.defaultProps, columns: [ MutationTableColumnType.SAMPLE_ID, - MutationTableColumnType.CANCER_TYPE, + MutationTableColumnType.CANCER_TYPE_DETAILED, MutationTableColumnType.ANNOTATION, MutationTableColumnType.HGVSG, MutationTableColumnType.FUNCTIONAL_IMPACT, @@ -65,7 +65,7 @@ export default class StandaloneMutationTable extends MutationTable< : this.props.data ); this._columns[ - MutationTableColumnType.CANCER_TYPE + MutationTableColumnType.CANCER_TYPE_DETAILED ].visible = CancerTypeColumnFormatter.isVisible( this.props.dataStore ? this.props.dataStore.allData @@ -77,7 +77,7 @@ export default class StandaloneMutationTable extends MutationTable< // order columns //this._columns[MutationTableColumnType.STUDY].order = 0; this._columns[MutationTableColumnType.SAMPLE_ID].order = 10; - this._columns[MutationTableColumnType.CANCER_TYPE].order = 15; + this._columns[MutationTableColumnType.CANCER_TYPE_DETAILED].order = 15; this._columns[MutationTableColumnType.PROTEIN_CHANGE].order = 20; this._columns[MutationTableColumnType.ANNOTATION].order = 30; this._columns[MutationTableColumnType.FUNCTIONAL_IMPACT].order = 38; diff --git a/src/pages/studyView/addChartButton/addChartByType/AddChartByType.tsx b/src/pages/studyView/addChartButton/addChartByType/AddChartByType.tsx index 9af40e4d21a..ffa498823d7 100644 --- a/src/pages/studyView/addChartButton/addChartByType/AddChartByType.tsx +++ b/src/pages/studyView/addChartButton/addChartByType/AddChartByType.tsx @@ -36,6 +36,7 @@ export interface IAddChartByTypeProps { deleteChart?: (chartId: string) => void; restoreChart?: (chartId: string) => void; markedForDeletion?: string[]; + excludeFrequency?: boolean; } class AddChartTableComponent extends FixedHeaderTable {} @@ -114,7 +115,7 @@ export default class AddChartByType extends React.Component< } @computed get columns() { - const columns: Column[] = [ + let columns: Column[] = [ { name: this.props.firstColumnHeaderName!, render: (option: AddChartOption) => { @@ -183,7 +184,9 @@ export default class AddChartByType extends React.Component< (this.props.shareCharts || this.props.deleteChart ? 70 : 0), defaultSortDirection: 'asc' as 'asc', }, - { + ]; + if (!this.props.excludeFrequency) { + columns.push({ name: 'Freq', tooltip: ( @@ -214,8 +217,8 @@ export default class AddChartByType extends React.Component< sortBy: (d: AddChartOption) => d.freq, defaultSortDirection: 'desc' as 'desc', width: 60, - }, - ]; + }); + } if (this.props.shareCharts || this.props.deleteChart) { columns.push({ @@ -358,7 +361,8 @@ export default class AddChartByType extends React.Component< style={{ display: 'flex', flexDirection: 'column' }} data-test="add-by-type" > - {this.props.freqPromise.isComplete && ( + {(this.props.freqPromise.isComplete || + this.props.excludeFrequency) && ( )} - {this.props.freqPromise.isPending && ( -
- -
- Calculating data availability... -
- )} + {this.props.freqPromise.isPending && + !this.props.excludeFrequency && ( +
+ +
+ Calculating data availability... +
+ )} ); } diff --git a/src/pages/studyView/table/FixedHeaderTable.tsx b/src/pages/studyView/table/FixedHeaderTable.tsx index 2ed9e4f9007..218fe858a98 100644 --- a/src/pages/studyView/table/FixedHeaderTable.tsx +++ b/src/pages/studyView/table/FixedHeaderTable.tsx @@ -364,12 +364,13 @@ export default class FixedHeaderTable extends React.Component< const showDeselectAll = !noneSelected && this.props.removeAll; return ( - <> +
{showSelectAll && ( @@ -377,13 +378,14 @@ export default class FixedHeaderTable extends React.Component< {showDeselectAll && ( )} - +
); } diff --git a/src/shared/cache/ClinicalAttributeCache.ts b/src/shared/cache/ClinicalAttributeCache.ts new file mode 100644 index 00000000000..cc44411f347 --- /dev/null +++ b/src/shared/cache/ClinicalAttributeCache.ts @@ -0,0 +1,82 @@ +import client from '../api/cbioportalClientInstance'; +import LazyMobXCache from '../lib/LazyMobXCache'; +import { + ClinicalData, + ClinicalAttribute, + ClinicalDataMultiStudyFilter, +} from 'cbioportal-ts-api-client'; +import _ from 'lodash'; + +type Query = { + clinicalAttribute: ClinicalAttribute; + entityId: string; + studyId: string; +}; + +function queryToKey(q: Query) { + return `${q.clinicalAttribute.clinicalAttributeId}~${q.entityId}~${q.studyId}`; +} +function dataToKey(d: ClinicalData) { + const entityId = d.hasOwnProperty('sampleId') ? d.sampleId : d.patientId; + return `${d.clinicalAttributeId}~${entityId}~${d.studyId}`; +} + +export async function fetch(queries: Query[]): Promise { + if (queries.length > 0) { + const patientQueries = queries.filter( + q => q.clinicalAttribute.patientAttribute + ); + const sampleQueries = queries.filter( + q => !q.clinicalAttribute.patientAttribute + ); + + const patientFilter: ClinicalDataMultiStudyFilter = { + attributeIds: patientQueries.map( + q => q.clinicalAttribute.clinicalAttributeId + ), + identifiers: patientQueries.map(q => ({ + entityId: q.entityId, + studyId: q.studyId, + })), + }; + const sampleFilter: ClinicalDataMultiStudyFilter = { + attributeIds: sampleQueries.map( + q => q.clinicalAttribute.clinicalAttributeId + ), + identifiers: sampleQueries.map(q => ({ + entityId: q.entityId, + studyId: q.studyId, + })), + }; + + let patientData = Promise.resolve(new Array()); + let sampleData = Promise.resolve(new Array()); + if (patientQueries.length > 0) { + patientData = client.fetchClinicalDataUsingPOST({ + clinicalDataType: 'PATIENT', + clinicalDataMultiStudyFilter: patientFilter, + }); + } + if (sampleQueries.length > 0) { + sampleData = client.fetchClinicalDataUsingPOST({ + clinicalDataType: 'SAMPLE', + clinicalDataMultiStudyFilter: sampleFilter, + }); + } + return Promise.all([patientData, sampleData]).then(both => + both[0].concat(both[1]) + ); + } else { + return Promise.resolve([]); + } +} + +export default class ClinicalAttributeCache extends LazyMobXCache< + ClinicalData, + Query, + string +> { + constructor() { + super(queryToKey, dataToKey, fetch); + } +} diff --git a/src/shared/components/columnVisibilityControls/ColumnVisibilityControls.tsx b/src/shared/components/columnVisibilityControls/ColumnVisibilityControls.tsx index 507d8bb464e..aa223abc5a4 100644 --- a/src/shared/components/columnVisibilityControls/ColumnVisibilityControls.tsx +++ b/src/shared/components/columnVisibilityControls/ColumnVisibilityControls.tsx @@ -19,6 +19,7 @@ export interface IColumnVisibilityControlsProps { columnId: string, columnVisibility?: IColumnVisibilityDef[] ) => void; + customDropdown?: (props: IColumnVisibilityControlsProps) => JSX.Element; } /** @@ -40,6 +41,16 @@ export class ColumnVisibilityControls extends React.Component< } public render() { + return ( +
+ {this.props.customDropdown + ? this.props.customDropdown(this.props) + : this.defaultDropdown} +
+ ); + } + + private get defaultDropdown() { return ( = { + id?: string; name: string; headerRender?: (name: string) => JSX.Element; headerDownload?: (name: string) => string; @@ -61,8 +62,10 @@ export type Column = { sortBy?: | ((data: T) => number | null) | ((data: T) => string | null) + | ((data: T) => string | number | null) | ((data: T) => (number | null)[]) - | ((data: T) => (string | null)[]); + | ((data: T) => (string | null)[]) + | ((data: T) => (string | number | null)[]); render: (data: T) => JSX.Element; download?: (data: T) => string | string[]; tooltip?: JSX.Element; @@ -503,9 +506,9 @@ export class LazyMobXTableStore { this.columns.forEach((column: Column) => { colVisProp.push({ - id: column.name, + id: column.hasOwnProperty('id') ? column.id! : column.name, name: column.name, - visible: this.columnVisibility[column.name], + visible: this.isVisible(column), togglable: column.hasOwnProperty('togglable') ? column.togglable : true, @@ -725,7 +728,8 @@ export class LazyMobXTableStore { } public isVisible(column: Column): boolean { - return this.columnVisibility[column.name] || false; + const index = column.hasOwnProperty('id') ? column.id! : column.name; + return this.columnVisibility[index] || false; } constructor(lazyMobXTableProps: LazyMobXTableProps) { diff --git a/src/shared/components/mutationTable/MutationTable.tsx b/src/shared/components/mutationTable/MutationTable.tsx index 4e8b44550f7..22b0dbce4b9 100644 --- a/src/shared/components/mutationTable/MutationTable.tsx +++ b/src/shared/components/mutationTable/MutationTable.tsx @@ -110,7 +110,7 @@ export interface IMutationTableProps { civicVariants?: RemoteData; mrnaExprRankMolecularProfileId?: string; discreteCNAMolecularProfileId?: string; - columns?: MutationTableColumnType[]; + columns?: MutationTableColumnTypes[]; data?: Mutation[][]; dataStore?: ILazyMobXTableApplicationDataStore; downloadDataFetcher?: ILazyMobXTableApplicationLazyDownloadDataFetcher; @@ -168,7 +168,7 @@ export enum MutationTableColumnType { VAR_READS_N, REF_READS, VAR_READS, - CANCER_TYPE, + CANCER_TYPE_DETAILED, NUM_MUTATIONS, EXON, HGVSC, @@ -179,6 +179,7 @@ export enum MutationTableColumnType { GENE_PANEL, SIGNAL, } +type MutationTableColumnTypes = MutationTableColumnType | string; type MutationTableColumn = Column & { order?: number; @@ -235,9 +236,10 @@ export function defaultFilter( export default class MutationTable< P extends IMutationTableProps > extends React.Component { - @observable protected _columns: { - [columnEnum: number]: MutationTableColumn; - }; + @observable protected _columns: Record< + MutationTableColumnTypes, + MutationTableColumn + >; @observable.ref public table: LazyMobXTable | null = null; public static defaultProps = { @@ -257,7 +259,10 @@ export default class MutationTable< constructor(props: P) { super(props); makeObservable(this); - this._columns = {}; + this._columns = {} as Record< + MutationTableColumnTypes, + MutationTableColumn + >; this.generateColumns(); } @@ -289,7 +294,10 @@ export default class MutationTable< } protected generateColumns() { - this._columns = {}; + this._columns = {} as Record< + MutationTableColumnTypes, + MutationTableColumn + >; this._columns[MutationTableColumnType.STUDY] = { name: 'Study', @@ -896,8 +904,9 @@ export default class MutationTable< align: 'left', }; - this._columns[MutationTableColumnType.CANCER_TYPE] = { - name: 'Cancer Type', + this._columns[MutationTableColumnType.CANCER_TYPE_DETAILED] = { + id: 'CANCER_TYPE_DETAILED', + name: 'Cancer Type Detailed', render: (d: Mutation[]) => CancerTypeColumnFormatter.render( d, @@ -927,6 +936,7 @@ export default class MutationTable< }; this._columns[MutationTableColumnType.NUM_MUTATIONS] = { + id: 'MUTATION_COUNT', name: '# Mut in Sample', render: MutationCountColumnFormatter.makeRenderFunction(this), headerRender: (name: string) => ( @@ -1157,10 +1167,11 @@ export default class MutationTable< }; } - @computed protected get orderedColumns(): MutationTableColumnType[] { - const columns = (this.props.columns || []) as MutationTableColumnType[]; + @computed protected get orderedColumns(): MutationTableColumnTypes[] { + const columns = (this.props.columns || + []) as MutationTableColumnTypes[]; - return _.sortBy(columns, (c: MutationTableColumnType) => { + return _.sortBy(columns, (c: MutationTableColumnTypes) => { let order: number = -1; if (this._columns[c] && this._columns[c].order) { @@ -1173,7 +1184,7 @@ export default class MutationTable< @computed protected get columns(): Column[] { return this.orderedColumns.reduce( - (columns: Column[], next: MutationTableColumnType) => { + (columns: Column[], next: MutationTableColumnTypes) => { let column = this._columns[next]; if ( diff --git a/src/shared/components/mutationTable/column/ClinicalAttributeColumnFormatter.tsx b/src/shared/components/mutationTable/column/ClinicalAttributeColumnFormatter.tsx new file mode 100644 index 00000000000..cb41e5463bd --- /dev/null +++ b/src/shared/components/mutationTable/column/ClinicalAttributeColumnFormatter.tsx @@ -0,0 +1,63 @@ +import * as React from 'react'; +import LazyLoadedTableCell from 'shared/lib/LazyLoadedTableCell'; +import ClinicalAttributeCache from '../../../cache/ClinicalAttributeCache'; +import { + Mutation, + ClinicalData, + ClinicalAttribute, +} from 'cbioportal-ts-api-client'; +import { TruncatedText } from 'cbioportal-frontend-commons'; + +/** + * @author Rajat Sirohi + */ +export default class ClinicalAttributeColumnFormatter { + static clinicalAttributeCache = new ClinicalAttributeCache(); + + public static getTextValue( + d: Mutation[], + attribute: ClinicalAttribute + ): string { + const clinicalDatum = this.clinicalAttributeCache.get({ + clinicalAttribute: attribute, + entityId: attribute.patientAttribute + ? d[0].patientId + : d[0].sampleId, + studyId: d[0].studyId, + })?.data; + return clinicalDatum ? clinicalDatum.value : ''; + } + + public static sortBy( + d: Mutation[], + attribute: ClinicalAttribute + ): string | number | null { + let textValue = this.getTextValue(d, attribute); + let sortValue = + attribute.datatype === 'NUMBER' ? +textValue : textValue; + + return textValue === '' ? null : sortValue; + } + + public static makeRenderFunction(attribute: ClinicalAttribute) { + return LazyLoadedTableCell( + (d: Mutation[]) => { + return this.clinicalAttributeCache.get({ + clinicalAttribute: attribute, + entityId: attribute.patientAttribute + ? d[0].patientId + : d[0].sampleId, + studyId: d[0].studyId, + }); + }, + (t: ClinicalData) => ( + {t.value}} + /> + ), + 'Clinical attribute not available for this sample.' + ); + } +} diff --git a/src/shared/components/oncoprint/controls/CustomDropdown.tsx b/src/shared/components/oncoprint/controls/CustomDropdown.tsx index 97358b58b10..3ea33ee0f25 100644 --- a/src/shared/components/oncoprint/controls/CustomDropdown.tsx +++ b/src/shared/components/oncoprint/controls/CustomDropdown.tsx @@ -9,14 +9,18 @@ import _ from 'lodash'; export interface ICustomDropdownProps extends ButtonProps { titleElement?: JSX.Element; styles?: any; + buttonClassName?: string; } class CustomButton extends React.Component { // cant type this more specifically because of some typing issues w ES6 classes not having component.replaceState render() { const { bsRole, title, ...props } = this.props; + const className = this.props.buttonClassName + ? this.props.buttonClassName + : 'btn btn-default'; return ( - ); diff --git a/src/shared/lib/ISortMetric.ts b/src/shared/lib/ISortMetric.ts index e4ddeca56b4..49a977c9382 100644 --- a/src/shared/lib/ISortMetric.ts +++ b/src/shared/lib/ISortMetric.ts @@ -1,5 +1,7 @@ export type SortMetric = | ((d: T) => number | null) - | ((d: T) => (number | null)[]) | ((d: T) => string | null) - | ((d: T) => (string | null)[]); + | ((d: T) => string | number | null) + | ((d: T) => (number | null)[]) + | ((d: T) => (string | null)[]) + | ((d: T) => (string | number | null)[]);