From 8f8d233af7e78a613e2d3443934dab4603a7dfd6 Mon Sep 17 00:00:00 2001 From: Chloe Herman <60228108+cherman2@users.noreply.github.com> Date: Thu, 11 May 2023 16:09:38 -0700 Subject: [PATCH 01/50] intial peds-bootstrap --- q2_fmt/_peds.py | 42 ++++++++++++++++++++++++++++++++++++++++++ q2_fmt/plugin_setup.py | 41 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 82 insertions(+), 1 deletion(-) diff --git a/q2_fmt/_peds.py b/q2_fmt/_peds.py index a89475e..d2b6cac 100644 --- a/q2_fmt/_peds.py +++ b/q2_fmt/_peds.py @@ -10,6 +10,7 @@ import pandas as pd import numpy as np import warnings +from scipy.stats import mannwhitneyu def sample_peds(table: pd.DataFrame, metadata: qiime2.Metadata, @@ -329,3 +330,44 @@ def _create_masking(time_metadata, donor_df, recip_df, reference_column): def _mask_recipient(donor_mask, recip_df): maskedrecip = donor_mask & recip_df return maskedrecip + + +def peds_bootstrap(table: pd.DataFrame, metadata: qiime2.Metadata, + time_column: str, reference_column: str, + subject_column: str, + filter_missing_references: bool = False, + drop_incomplete_subjects: bool = False, + bootstrap_replicates: int = 999): + fake_donor = [] + for i in range(0, bootstrap_replicates): + if i == 0: + peds, = \ + sample_peds( + table=table, + metadata=metadata, + time_column=time_column, + subject_column=subject_column, + reference_column=reference_column, + drop_incomplete_subjects=drop_incomplete_subjects, + filter_missing_references=filter_missing_references) + peds = peds.view(pd.DataFrame).set_index("id") + real_donor = peds["measure"].to_list() + else: + recipient = metadata[reference_column].dropna() + donor = metadata[metadata[reference_column].isna()] + shifted_list = recipient[reference_column].sample(frac=1).to_list() + recipient[reference_column] = shifted_list + metadata_df = pd.concat([recipient, donor]) + metadata = qiime2.Metadata(metadata_df) + peds, = \ + sample_peds( + table=table, + metadata=metadata, + time_column=time_column, + subject_column=subject_column, + reference_column=reference_column, + drop_incomplete_subjects=drop_incomplete_subjects, + filter_missing_references=filter_missing_references) + peds = peds.view(pd.DataFrame).set_index("id") + fake_donor = fake_donor + peds["measure"].to_list() + s, p = mannwhitneyu(real_donor, fake_donor, alternative='greater') diff --git a/q2_fmt/plugin_setup.py b/q2_fmt/plugin_setup.py index 7abf839..7cd64e9 100644 --- a/q2_fmt/plugin_setup.py +++ b/q2_fmt/plugin_setup.py @@ -9,7 +9,8 @@ import importlib from qiime2.plugin import (Str, Plugin, Metadata, TypeMap, - Bool, Choices, Visualization, Properties, Citations) + Bool, Choices, Visualization, Properties, Citations, + Int, Range) from q2_types.sample_data import SampleData, AlphaDiversity from q2_types.distance_matrix import DistanceMatrix @@ -264,6 +265,44 @@ } ) +plugin.methods.register_function( + function=q2_fmt.peds_bootstrap, + inputs={'table': FeatureTable[Frequency | RelativeFrequency | + PresenceAbsence]}, + parameters={'metadata': Metadata, 'time_column': Str, + 'reference_column': Str, 'subject_column': T_subject, + 'filter_missing_references': Bool, + 'drop_incomplete_subjects': Bool, + 'bootstrap_replicates': Int % Range(999, None)}, + outputs=[('peds_dists', GroupDist[Ordered, Matched] % Properties("peds"))], + parameter_descriptions={ + 'metadata': 'The sample metadata.', + 'time_column': 'The column within the `metadata` that the' + ' `table` should be grouped by. This column' + ' should contain simple integer values.', + 'reference_column': 'The column within the `metadata` that contains' + ' the sample to use as a reference' + ' for a given `table`.' + ' For example, this may be the relevant donor' + ' sample to compare against.', + 'subject_column': 'The column within the `metadata` that contains the' + ' subject ID to be tracked against timepoints.', + 'filter_missing_references': 'Filter out references contained within' + ' the metadata that are not present' + ' in the table.' + ' Default behavior is to raise an error.', + 'drop_incomplete_subjects': 'Filter out subjects that do not have' + ' a sample at every timepoint.' + ' Default behavior is to raise an error.', + }, + output_descriptions={ + # TODO: I dont know what it is going to output yet? + }, + name='', + description='', + citations=[citations['aggarwala_precise_2021']] +) + plugin.visualizers.register_function( function=q2_fmt.plot_heatmap, inputs={'data': GroupDist[Ordered, Matched] % Properties('peds')}, From 2a3aa9dadc39e00dd06a6e67fec08622d1c60e40 Mon Sep 17 00:00:00 2001 From: Chloe Herman <60228108+cherman2@users.noreply.github.com> Date: Wed, 8 May 2024 10:00:21 -0700 Subject: [PATCH 02/50] updates from EMC paper to peds-bootstrap --- q2_fmt/_peds.py | 42 +++++++++------------ q2_fmt/tests/test_engraftment.py | 64 +++++++++++++++++++++++++++++++- 2 files changed, 80 insertions(+), 26 deletions(-) diff --git a/q2_fmt/_peds.py b/q2_fmt/_peds.py index d2b6cac..6ba0843 100644 --- a/q2_fmt/_peds.py +++ b/q2_fmt/_peds.py @@ -338,36 +338,28 @@ def peds_bootstrap(table: pd.DataFrame, metadata: qiime2.Metadata, filter_missing_references: bool = False, drop_incomplete_subjects: bool = False, bootstrap_replicates: int = 999): + metadata_df = metadata.to_dataframe + ## TODO: Grab Donor in a more logic way + donor = metadata_df.loc[metadata_df['Location'] == body_site] + recipient = metadata_df.loc[metadata_df['Location'] != body_site] fake_donor = [] - for i in range(0, bootstrap_replicates): + for i in range(0, bootstrap_replicates+1): if i == 0: - peds, = \ - sample_peds( - table=table, - metadata=metadata, - time_column=time_column, - subject_column=subject_column, - reference_column=reference_column, - drop_incomplete_subjects=drop_incomplete_subjects, - filter_missing_references=filter_missing_references) + peds, = sample_peds(table=table, metadata=metadata, + time_column=time_column, + reference_column=reference_column, + subject_column=subject_column) peds = peds.view(pd.DataFrame).set_index("id") - real_donor = peds["measure"].to_list() + real_temp = peds["measure"].to_list() else: - recipient = metadata[reference_column].dropna() - donor = metadata[metadata[reference_column].isna()] shifted_list = recipient[reference_column].sample(frac=1).to_list() - recipient[reference_column] = shifted_list - metadata_df = pd.concat([recipient, donor]) + recipient.loc[:, reference_column] = shifted_list + metadata_df = pd.concat([donor, recipient]) metadata = qiime2.Metadata(metadata_df) - peds, = \ - sample_peds( - table=table, - metadata=metadata, - time_column=time_column, - subject_column=subject_column, - reference_column=reference_column, - drop_incomplete_subjects=drop_incomplete_subjects, - filter_missing_references=filter_missing_references) + peds, = sample_peds(table=table, metadata=metadata, + time_column=time_column, + reference_column=reference_column, + subject_column=subject_column) peds = peds.view(pd.DataFrame).set_index("id") fake_donor = fake_donor + peds["measure"].to_list() - s, p = mannwhitneyu(real_donor, fake_donor, alternative='greater') + s, p = mannwhitneyu(real_temp, fake_donor, alternative='greater') diff --git a/q2_fmt/tests/test_engraftment.py b/q2_fmt/tests/test_engraftment.py index b63a5dd..d29df21 100644 --- a/q2_fmt/tests/test_engraftment.py +++ b/q2_fmt/tests/test_engraftment.py @@ -18,7 +18,7 @@ _filter_associated_reference, _check_reference_column, _check_for_time_column, _check_subject_column, _check_column_type, - feature_peds) + feature_peds, peds_bootstrap) class TestBase(TestPluginBase): @@ -1022,3 +1022,65 @@ def test_reference_column_name_is_ID(self): " not be the same as the index of" " metadata: `id`"): _check_reference_column(metadata_df, "id") + + +class TestBoot(TestBase): + def test_high_donor_overlap(self): + metadata_df = pd.DataFrame({ + 'id': ['sample1', 'sample2', 'sample3', + 'donor1', 'donor2', 'donor3'], + 'Ref': ['donor1', 'donor2', 'donor3', float("Nan"), float("Nan"), + float("Nan")], + 'subject': ['sub1', 'sub2', 'sub3', float("Nan"), float("Nan"), + float("Nan")], + 'group': [1, 1, 1, float("Nan"), float("Nan"), + float("Nan")], + "Location": [float("Nan"), float("Nan"), + float("Nan"), 'test', 'test', + 'test']}).set_index('id') + + table_df = pd.DataFrame({ + 'id': ['sample1', 'sample2', 'sample3', + 'donor1', 'donor2', 'donor3'], + 'Feature1': [1, 0, 0, 1, 0, 0], + 'Feature2': [0, 1, 0, 0, 1, 0], + 'Feature3': [0, 0, 1, 0, 0, 1]}).set_index('id') + + p, real_mean, fake_mean = peds_bootstrap(metadata_df=metadata_df, + table=table_df, + time_column="group", + reference_column="Ref", + subject_column="subject", + iters=999) + self.assertGreater(real_mean, fake_mean) + + def test_low_donor_overlap(self): + metadata_df = pd.DataFrame({ + 'id': ['sample1', 'sample2', 'sample3', + 'donor1', 'donor2', 'donor3'], + 'Ref': ['donor1', 'donor2', 'donor3', float("Nan"), float("Nan"), + float("Nan")], + 'subject': ['sub1', 'sub2', 'sub3', float("Nan"), float("Nan"), + float("Nan")], + 'group': [1, 1, 1, float("Nan"), float("Nan"), + float("Nan")], + "Location": [float("Nan"), float("Nan"), + float("Nan"), 'test', 'test', + 'test']}).set_index('id') + + table_df = pd.DataFrame({ + 'id': ['sample1', 'sample2', 'sample3', + 'donor1', 'donor2', 'donor3'], + 'Feature1': [1, 0, 0, 0, 0, 1], + 'Feature2': [0, 1, 0, 1, 0, 0], + 'Feature3': [0, 0, 1, 0, 1, 0]}).set_index('id') + + p, real_median, fake_median = peds_bootstrap(metadata_df=metadata_df, + table=table_df, + time_column="group", + reference_column="Ref", + subject_column="subject", + iters=999) + self.assertGreater(fake_median, real_median) + + From 82a2e53154730f272c9d2a47466c289717241731 Mon Sep 17 00:00:00 2001 From: Chloe Herman <60228108+cherman2@users.noreply.github.com> Date: Wed, 8 May 2024 10:47:20 -0700 Subject: [PATCH 03/50] lint from merging --- q2_fmt/_peds.py | 8 ++++---- q2_fmt/tests/test_engraftment.py | 5 ++--- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/q2_fmt/_peds.py b/q2_fmt/_peds.py index 70af2f9..641e6c0 100644 --- a/q2_fmt/_peds.py +++ b/q2_fmt/_peds.py @@ -478,13 +478,13 @@ def peds_bootstrap(table: pd.DataFrame, metadata: qiime2.Metadata, drop_incomplete_subjects: bool = False, bootstrap_replicates: int = 999): metadata_df = metadata.to_dataframe - ## TODO: Grab Donor in a more logic way - donor = metadata_df.loc[metadata_df['Location'] == body_site] - recipient = metadata_df.loc[metadata_df['Location'] != body_site] + # TODO: Grab Donor in a more logic way + # donor = metadata_df.loc[metadata_df['Location'] == body_site] + # recipient = metadata_df.loc[metadata_df['Location'] != body_site] fake_donor = [] for i in range(0, bootstrap_replicates+1): if i == 0: - peds, = sample_peds(table=table, metadata=metadata, + peds, = sample_peds(table=table, metadata=metadata, time_column=time_column, reference_column=reference_column, subject_column=subject_column) diff --git a/q2_fmt/tests/test_engraftment.py b/q2_fmt/tests/test_engraftment.py index 98725a1..dac2324 100644 --- a/q2_fmt/tests/test_engraftment.py +++ b/q2_fmt/tests/test_engraftment.py @@ -19,8 +19,8 @@ _check_reference_column, _check_for_time_column, _check_subject_column, _check_column_type, _drop_incomplete_timepoints, feature_peds, - _check_column_missing, _rename_features, peds_bootstrap) - + _check_column_missing, _rename_features, + peds_bootstrap) class TestBase(TestPluginBase): @@ -1189,4 +1189,3 @@ def test_low_donor_overlap(self): subject_column="subject", iters=999) self.assertGreater(fake_median, real_median) - From 8370ad89fc5e239fb008eceec6f62064117b4f5c Mon Sep 17 00:00:00 2001 From: Chloe Herman <60228108+cherman2@users.noreply.github.com> Date: Wed, 8 May 2024 10:51:04 -0700 Subject: [PATCH 04/50] add bootstrap to init --- q2_fmt/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/q2_fmt/__init__.py b/q2_fmt/__init__.py index 87dc12f..4b8ce33 100644 --- a/q2_fmt/__init__.py +++ b/q2_fmt/__init__.py @@ -14,4 +14,4 @@ del get_versions __all__ = ['engraftment', 'sample_peds', 'feature_peds', - 'peds', 'peds_heatmap', 'group_timepoints'] + 'peds', 'peds_heatmap', 'group_timepoints', 'peds_bootstrap'] From 0be6145bb484079ade78218080049c506efec6f4 Mon Sep 17 00:00:00 2001 From: Chloe Herman <60228108+cherman2@users.noreply.github.com> Date: Fri, 10 May 2024 08:53:09 -0700 Subject: [PATCH 05/50] updates --- q2_fmt/_peds.py | 6 ++++-- q2_fmt/plugin_setup.py | 5 +---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/q2_fmt/_peds.py b/q2_fmt/_peds.py index 641e6c0..633f420 100644 --- a/q2_fmt/_peds.py +++ b/q2_fmt/_peds.py @@ -479,8 +479,10 @@ def peds_bootstrap(table: pd.DataFrame, metadata: qiime2.Metadata, bootstrap_replicates: int = 999): metadata_df = metadata.to_dataframe # TODO: Grab Donor in a more logic way - # donor = metadata_df.loc[metadata_df['Location'] == body_site] - # recipient = metadata_df.loc[metadata_df['Location'] != body_site] + donor = metadata_df[metadata.index.isin( + _check_reference_column(metadata=metadata_df, + reference_column=reference_column))] + recipient = metadata_df.loc[metadata_df[reference_column].notnull()] fake_donor = [] for i in range(0, bootstrap_replicates+1): if i == 0: diff --git a/q2_fmt/plugin_setup.py b/q2_fmt/plugin_setup.py index 1a52bbb..063f838 100644 --- a/q2_fmt/plugin_setup.py +++ b/q2_fmt/plugin_setup.py @@ -299,7 +299,7 @@ } ) -plugin.methods.register_function( +plugin.visualizers.register_function( function=q2_fmt.peds_bootstrap, inputs={'table': FeatureTable[Frequency | RelativeFrequency | PresenceAbsence]}, @@ -329,9 +329,6 @@ ' a sample at every timepoint.' ' Default behavior is to raise an error.', }, - output_descriptions={ - # TODO: I dont know what it is going to output yet? - }, name='', description='', citations=[citations['aggarwala_precise_2021']] From 89306772380f762f8e21da608646671bd4468c1c Mon Sep 17 00:00:00 2001 From: Chloe Herman <60228108+cherman2@users.noreply.github.com> Date: Mon, 13 May 2024 17:07:18 -0700 Subject: [PATCH 06/50] code dump --- q2_fmt/__init__.py | 3 +- q2_fmt/_peds.py | 112 +++++++++++++++++++++++++++++++-------- q2_fmt/assets/index.html | 61 +++++++++++++++++---- q2_fmt/plugin_setup.py | 23 ++++---- 4 files changed, 151 insertions(+), 48 deletions(-) diff --git a/q2_fmt/__init__.py b/q2_fmt/__init__.py index 4b8ce33..7e18587 100644 --- a/q2_fmt/__init__.py +++ b/q2_fmt/__init__.py @@ -8,7 +8,8 @@ from ._version import get_versions from ._engraftment import engraftment, group_timepoints -from ._peds import sample_peds, feature_peds, peds, peds_heatmap +from ._peds import (sample_peds, feature_peds, peds, peds_heatmap, + peds_bootstrap) __version__ = get_versions()['version'] del get_versions diff --git a/q2_fmt/_peds.py b/q2_fmt/_peds.py index 633f420..11c3f80 100644 --- a/q2_fmt/_peds.py +++ b/q2_fmt/_peds.py @@ -18,6 +18,7 @@ import json from q2_fmt._util import json_replace +from q2_stats._visualizer import _make_stats def peds(ctx, table, metadata, peds_metric, time_column, reference_column, @@ -31,6 +32,7 @@ def peds(ctx, table, metadata, peds_metric, time_column, reference_column, if peds_metric == 'sample': sample_peds = ctx.get_action('fmt', 'sample_peds') + peds_bootstrap = ctx.get_action('fmt', 'peds_bootstrap') peds_dist = sample_peds( table=table, metadata=metadata, time_column=time_column, subject_column=subject_column, reference_column=reference_column, @@ -38,6 +40,15 @@ def peds(ctx, table, metadata, peds_metric, time_column, reference_column, drop_incomplete_timepoint=drop_incomplete_timepoint, filter_missing_references=filter_missing_references) + peds_stats = peds_bootstrap( + table=table, metadata=metadata, time_column=time_column, + subject_column=subject_column, + reference_column=reference_column, + drop_incomplete_subjects=drop_incomplete_subjects, + drop_incomplete_timepoint=drop_incomplete_timepoint, + filter_missing_references=filter_missing_references) + stat = peds_stats[0] + else: if drop_incomplete_subjects or drop_incomplete_timepoint: warnings.warn('Feature PEDS was selected as the PEDS metric, which' @@ -51,15 +62,18 @@ def peds(ctx, table, metadata, peds_metric, time_column, reference_column, table=table, metadata=metadata, time_column=time_column, subject_column=subject_column, reference_column=reference_column, filter_missing_references=filter_missing_references) - results += peds_heatmap(data=peds_dist[0], level_delimiter=level_delimiter) + stat = None + results += peds_heatmap(data=peds_dist[0], stats=stat, + level_delimiter=level_delimiter) return tuple(results) def peds_heatmap(output_dir: str, data: pd.DataFrame, - level_delimiter: str = None): + level_delimiter: str = None, stats: pd.DataFrame = None): _rename_features(data=data, level_delimiter=level_delimiter) - + if stats is not None: + table1, stats = _make_stats(stats) J_ENV = jinja2.Environment( loader=jinja2.PackageLoader('q2_fmt', 'assets') ) @@ -89,9 +103,10 @@ def peds_heatmap(output_dir: str, data: pd.DataFrame, title=title, measure=gradient, measure_name=measure_name, order=order) - with open(os.path.join(output_dir, "index.html"), "w") as fh: + with open(os.path.join(output_dir, 'index.html'), 'w') as fh: spec_string = json.dumps(full_spec) - fh.write(index.render(spec=spec_string)) + fh.write(index.render(spec=spec_string, stats=stats, + table1=table1)) def sample_peds(table: pd.DataFrame, metadata: qiime2.Metadata, @@ -476,31 +491,82 @@ def peds_bootstrap(table: pd.DataFrame, metadata: qiime2.Metadata, subject_column: str, filter_missing_references: bool = False, drop_incomplete_subjects: bool = False, - bootstrap_replicates: int = 999): - metadata_df = metadata.to_dataframe - # TODO: Grab Donor in a more logic way - donor = metadata_df[metadata.index.isin( + drop_incomplete_timepoint: list = None, + bootstrap_replicates: int = 999) -> (pd.DataFrame): + + metadata_df = metadata.to_dataframe() + donor = metadata_df[metadata_df.index.isin( _check_reference_column(metadata=metadata_df, reference_column=reference_column))] + recipient = metadata_df.loc[metadata_df[reference_column].notnull()] - fake_donor = [] + fake_donor = pd.DataFrame([]) for i in range(0, bootstrap_replicates+1): if i == 0: - peds, = sample_peds(table=table, metadata=metadata, - time_column=time_column, - reference_column=reference_column, - subject_column=subject_column) - peds = peds.view(pd.DataFrame).set_index("id") - real_temp = peds["measure"].to_list() + peds =\ + sample_peds(table=table, metadata=metadata, + time_column=time_column, + reference_column=reference_column, + subject_column=subject_column, + filter_missing_references=filter_missing_references, + drop_incomplete_subjects=drop_incomplete_subjects, + drop_incomplete_timepoint=drop_incomplete_timepoint) + real_temp = peds["measure"] else: shifted_list = recipient[reference_column].sample(frac=1).to_list() recipient.loc[:, reference_column] = shifted_list metadata_df = pd.concat([donor, recipient]) metadata = qiime2.Metadata(metadata_df) - peds, = sample_peds(table=table, metadata=metadata, - time_column=time_column, - reference_column=reference_column, - subject_column=subject_column) - peds = peds.view(pd.DataFrame).set_index("id") - fake_donor = fake_donor + peds["measure"].to_list() - s, p = mannwhitneyu(real_temp, fake_donor, alternative='greater') + peds =\ + sample_peds(table=table, metadata=metadata, + time_column=time_column, + reference_column=reference_column, + subject_column=subject_column, + filter_missing_references=filter_missing_references, + drop_incomplete_subjects=drop_incomplete_subjects, + drop_incomplete_timepoint=drop_incomplete_timepoint) + fake_donor[i] = peds["measure"] + fake_donor_series = fake_donor.median(axis=1) + # Common Langauge effect size calcs in prep for stats refactor. + # These are not being used currently but will be soon + fake_donors_CLES = fake_donor.median(axis=0) + agree = ((fake_donors_CLES < + real_temp.median()).sum())/bootstrap_replicates + disagree = 1 - agree + cles = agree - disagree + cles + + s, p = mannwhitneyu(real_temp, fake_donor_series.to_list(), + alternative='greater') + + stats_df = pd.DataFrame([["real_values", real_temp.size, + real_temp.median(), "fake_values", + fake_donor_series.size, + fake_donor_series.median(), + fake_donor_series.size, + s, p, np.nan]]) + stats_df.columns = ['A:group', 'A:n', 'A:measure', 'B:group', 'B:n', + 'B:measure', 'n', 'test-statistic', 'p-value', + 'q-value'] + + stats_df['A:group'].attrs.update({'title': 'real_values', + 'description': '...'}) + stats_df['B:group'].attrs.update({'title': 'randomized_values', + 'description': '...'}) + n = {'title': 'count', 'description': '...'} + stats_df['A:n'].attrs.update(n) + stats_df['B:n'].attrs.update(n) + measure = { + 'title': 'Median PEDS Value', + 'description': '...' + } + stats_df['A:measure'].attrs.update(measure) + stats_df['B:measure'].attrs.update(measure) + stats_df['n'].attrs.update(dict(title='count', description='...')) + stats_df['test-statistic'].attrs.update(dict(title='Mann-Whitney U', + description='...')) + stats_df['p-value'].attrs.update(dict(title='one-tail', description='...')) + stats_df['q-value'].attrs.update( + dict(title='Benjamini–Hochberg', description='...')) + + return stats_df diff --git a/q2_fmt/assets/index.html b/q2_fmt/assets/index.html index 209dce4..8e2b81a 100644 --- a/q2_fmt/assets/index.html +++ b/q2_fmt/assets/index.html @@ -13,36 +13,77 @@ width: 100%; box-sizing: border-box; margin: 0px; - padding: 10px; - /* padding: 50px 212px 0px 50px; */ + padding: 50px 212px 0px 50px; } #viz { - margin: 100px auto; + margin: 0 auto; + display: block; + width: 100%; position: relative; } .vega-bindings { - top: 25px; - left: 25px; - display: flex; + top: 90px; + right: 50px; + width: 200px; position: fixed; font-family: monospace; } .vega-bind { - margin-right: 50px; - vertical-align: middle + margin-right: 15px; + } + .vega-bind-name { + margin-right: 5px; + } + .vega-embed summary { + position: fixed !important; + top: 50px !important; + right: 222px !important; + } + .vega-embed .vega-actions { + position: fixed !important; + right: 212px !important; + top: 85px !important; + } + #stats table { + margin-top: 50px; + width: 100%; + text-align: right; + border-collapse: collapse; + border: 0px; + font-family: monospace; } - .vega-bind span { - display: flex; + #stats thead tr { + border: none; } + #stats tr th { + border: none; + padding-right: 10px; + } + + #stats td { + border: none; + padding-right: 10px; + } + #stats tr { + border-top: 1px solid; + }
+ +{% if stats %} +Table 1. {{ table1 }}
+{% endif %} +