File size: 6,697 Bytes
dfb33ee
b2381d4
 
a36b8fb
15d578c
b2381d4
7b24758
b2381d4
15d578c
 
 
b2381d4
15d578c
 
 
a36b8fb
15d578c
 
 
 
 
 
a36b8fb
 
 
45dcae3
 
 
 
 
 
 
 
 
 
 
 
 
15d578c
09a9428
15d578c
5337a31
15d578c
 
09a9428
15d578c
21c8b1d
15d578c
 
 
a36b8fb
15d578c
 
 
 
a36b8fb
15d578c
 
 
a36b8fb
15d578c
 
 
a36b8fb
 
15d578c
 
 
a36b8fb
15d578c
 
 
 
 
 
a36b8fb
 
 
 
 
15d578c
 
 
09a9428
15d578c
 
09a9428
15d578c
 
 
 
4566dcf
5337a31
15d578c
 
 
4479d60
15d578c
 
 
 
 
 
 
 
 
dfb33ee
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15d578c
 
 
 
 
09a9428
15d578c
 
 
 
 
 
 
 
 
 
09a9428
15d578c
09a9428
15d578c
09a9428
15d578c
09a9428
15d578c
 
09a9428
15d578c
09a9428
15d578c
 
 
09a9428
15d578c
 
 
09a9428
15d578c
 
 
09a9428
 
15d578c
09a9428
15d578c
 
09a9428
15d578c
 
 
09a9428
 
15d578c
09a9428
15d578c
 
 
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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
from typing import Callable
import streamlit as st
import pandas as pd
import plotly.graph_objects as go
import datetime


class UserView:
    """
    A class to handle all user interface elements.
    """

    def show_current_data(self, merged_data_df: pd.DataFrame) -> None:
        """
        Show the current pollutant concentrations along with WHO guidelines.

        Args:
            merged_data_df (pd.DataFrame): A pandas DataFrame containing the current pollutant concentrations and WHO guidelines.
        """
        st.sidebar.markdown(
            f"Today's Date: **{datetime.date.today().strftime('%B %d, %Y')}**"
        )
        st.sidebar.markdown("### Current Pollutant Concentrations and WHO Guidelines")
        st.sidebar.dataframe(merged_data_df, hide_index=True)

    def data_not_available(self) -> None:
        """
        Show an error message indicating that data is not available.

        This is shown when the current time is between 00:00 and 04:15, when the measurements aren't accurate enough to produce a prediction.
        The data will be automatically updated at 04:15 with the prediction for the next three days.
        """
        st.markdown("### Data Not Available")

        error_message = "🚨 Between 00:00 and 04:15, the measurements aren't accurate enough to produce a prediction or have an informative summary for today's air pollution. The data will be automatically updated at 04:15 with the prediction for the next three days."

        self.two_columns_layout(0.7, lambda: st.error(error_message), lambda: None)

    def success(self, message: str) -> None:
        """
        Show a success message.

        Args:
            message (str): The message to be displayed.
        """
        st.success(message)

    def error(self, message: str) -> None:
        """
        Show an error message.

        Args:
            message (str): The message to be displayed.
        """
        st.error(message)

    def display_predictions_lineplot(self, fig: go.Figure) -> None:
        """
        Show a line plot of the predictions.

        Args:
            fig (go.Figure): The plotly figure to be displayed.
        """
        st.plotly_chart(fig)

    def display_predictions_gaugeplot(self, gauge_plots: list) -> None:
        """
        Show a gauge plot of the predictions.

        Args:
            gauge_plots (list): A list of tuples containing the day, formatted date, and two plotly figures (for NO2 and O3).
        """
        for day, formatted_date, fig_no2, fig_o3 in gauge_plots:
            st.markdown(f"#### Day {day}: {formatted_date}")
            col1, col2 = st.columns([1, 1])
            with col1:
                st.plotly_chart(fig_no2)
            with col2:
                st.plotly_chart(fig_o3)

    def view_option_selection(self, plot_type: list) -> str:
        """
        Ask the user to select a plot type.

        Args:
            plot_type (list): A list of strings containing the options to be displayed.

        Returns:
            str: The selected option.
        """
        st.markdown("### Visualizing Air Quality Predictions")
        return st.selectbox("Select a plot type:", plot_type)

    def compare_to_who(self, warnings: list) -> None:
        """
        Compare the current pollutant concentrations with WHO guidelines and display the results.

        Args:
            warnings (list): A list of tuples containing the pollutant, message, and level (error or success) of the warning.
        """
        for pollutant, message, level in warnings:
            if level == "error":
                st.sidebar.error(message)
            elif level == "success":
                st.sidebar.success(message)

    def two_columns_layout(
        self, ratio: float, left_function: Callable, right_function: Callable
    ) -> None:
        """
        Divide the page into two columns and call the left and right functions within them.

        Parameters
        ----------
        ratio : float
            The ratio of the left to the right column.
        left_function : Callable
            The function to be called in the left column.
        right_function : Callable
            The function to be called in the right column.
        """
        left, right = st.columns([ratio, 1 - ratio], gap="large")

        with left:
            left_function()

        with right:
            right_function()

    def raise_awareness(
        self, random_fact: str, awareness_expanders: list, health_message: dict
    ) -> None:
        """
        Raise awareness about air quality issues and provide health recommendations.

        Args:
            random_fact (str): A random fact about air quality.
            awareness_expanders (list): A list of tuples containing the title and content of the expanders.
            health_message (dict): A dictionary containing the health recommendation message and type (error or success).
        """
        st.markdown("### Air Quality Awareness")
        # Awareness sections
        for expander_title, expander_content in awareness_expanders:
            with st.expander(expander_title):
                st.write(expander_content)

        # Fact section
        st.markdown("### Did You Know?")
        st.info(random_fact)

        # Health recommendation section
        st.markdown("### Health Recommendations Based on Current Levels")
        if health_message["type"] == "error":
            st.error(health_message["message"])
        else:
            st.success(health_message["message"])

    def quiz(self, question: str, options: list) -> tuple:
        """
        Ask a quiz question and return the answer and whether the answer was correct.

        Args:
            question (str): The question to be asked.
            options (list): A list of strings containing the options.

        Returns:
            tuple: A tuple containing the answer and a boolean indicating whether the answer was correct.
        """
        st.markdown("### Quick Quiz: How Much Do You Know About Air Pollution?")
        with st.form(key="quiz_form"):
            st.write(question)
            answer = st.radio("Choose an option:", options)
            submit_button = st.form_submit_button("Submit Answer")
        return submit_button, answer

    def print_sources(self, sources: list) -> None:
        """
        Print the sources used in the application.

        Args:
            sources (list): A list of tuples containing the source text and URL.
        """
        st.markdown("### Learn More")
        for source_text, source_url in sources:
            st.markdown(f"[{source_text}]({source_url})")