File size: 4,538 Bytes
d6661a1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
from collections import Counter
from typing import List
import numpy as np
import streamlit as st  # pylint: disable=import-error
import pandas as pd


class Collapsable:
    """
    Creates a collapsable text composed of a preamble (clickable section of text)
    and epilogue (collapsable text).
    """

    def __init__(self, preamble="", epilogue=""):
        self.preamble = preamble
        self.epilogue = epilogue
        self.small_font = 18
        self.large_font = 18
        self.sections = []

    def add_section(self, heading, text):
        # Convert text to bullet points if it is a list
        if isinstance(text, list):
            text = (
                "<ul>"
                + "".join(
                    [
                        f'<li style="font-size:{self.small_font}px;" align="justify">{x}</li>'
                        for x in text
                    ]
                )
                + "</ul>"
            )

        # Append section
        self.sections.append((heading, text))

    def deploy(self):

        secs = "".join(
            [
                (
                    "<details>"
                    f"<summary style='font-size:{self.large_font}px;'>{heading}</summary>"
                    f"<blockquote style='font-size:{self.small_font}px;max-width: 80%;'"
                    f"align='justify'>{text}</details>"
                )
                for heading, text in self.sections
            ]
        )
        collapsable_sec = f"""
        <ol>
        {self.preamble}
        {secs}
        {self.epilogue}
        </ol>
        """
        st.markdown(collapsable_sec, unsafe_allow_html=True)


def add_filter(
    data_frame_list: List[pd.DataFrame],
    name: str,
    label: str,
    options: List[str] = None,
    num_cols: int = 1,
    last_is_others: bool = True,
):
    """
    Creates a filter on the side bar using checkboxes
    """

    # Get list of all options and return if no options are available
    all_options = set(data_frame_list[-1][label])
    if "-" in all_options:
        all_options.remove("-")
    if len(all_options) == 0:
        return data_frame_list

    st.markdown(f"#### {name}")

    # Create list of options if selectable options are not provided
    if options is None:
        options_dict = Counter(data_frame_list[-1][label])
        sorted_options = sorted(options_dict, key=options_dict.get, reverse=True)
        if "-" in sorted_options:
            sorted_options.remove("-")
        if len(sorted_options) > 8:
            options = list(sorted_options[:7]) + ["others"]
            last_is_others = True
        else:
            options = list(sorted_options)
            last_is_others = False

    cols = st.columns(num_cols)
    instantiated_checkbox = []
    for idx in range(len(options)):
        with cols[idx % num_cols]:
            instantiated_checkbox.append(
                st.checkbox(options[idx], False, key=f"{label}_{options[idx]}")
            )

    selected_options = [
        options[idx] for idx, checked in enumerate(instantiated_checkbox) if checked
    ]

    # The last checkbox will always correspond to "other"
    if instantiated_checkbox[-1] and last_is_others:
        selected_options = selected_options[:-1]
        other_options = [x for x in all_options if x not in options]
        selected_options = set(selected_options + other_options)

    if len(selected_options) > 0:
        for idx, _ in enumerate(data_frame_list):
            data_frame_list[idx] = data_frame_list[idx][
                [
                    any([x == model_entry for x in selected_options])
                    for model_entry in data_frame_list[idx][label]
                ]
            ]
    return data_frame_list


def slider_filter(
    data_frame_list: List[pd.DataFrame],
    title: str,
    filter_by: str,
    max_val: int = 1000,
):
    """
    Creates slider to filter dataframes according to a given label.
    label must be numeric. Values are in millions.
    """

    start_val, end_val = st.select_slider(
        title,
        options=[str(x) for x in np.arange(0, max_val + 1, 10, dtype=int)],
        value=("0", str(max_val)),
    )

    for idx in range(len(data_frame_list)):
        data_frame_list[idx] = data_frame_list[idx][
            [
                int(model_entry) >= int(start_val) * 1000000
                and int(model_entry) <= int(end_val) * 1000000
                for model_entry in data_frame_list[idx][filter_by]
            ]
        ]

    return data_frame_list