File size: 4,208 Bytes
c47a6e2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import duckdb
import solara
from dashboard_helpers import (
    build_bivariate_map,
    build_bivariate_legend,
    build_summary_stats,
    build_need_chart,
    build_need_map,
)

# 1. Connect to database
con = duckdb.connect("processed_dashboard.db", read_only=True)

baseline_df       = con.sql("SELECT * FROM city_baselines").df()
baseline_ndvi     = float(baseline_df["baseline_ndvi"].iloc[0])
baseline_income   = float(baseline_df["baseline_income"].iloc[0])
baseline_minority = float(baseline_df["baseline_minority_pct"].iloc[0])
# 2. Reactive state

# X axis:
x_col = solara.reactive("ndvi_mean")

X_OPTIONS = {
    "ndvi_mean":          "NDVI (Vegetation)",
    "tree_equity_score":  "Tree Equity Score",
}

# Y axis:
y_col = solara.reactive("median_income")

Y_OPTIONS = {
    "median_income": "Median Income",
    "pct_minority":  "% Minority",
}

# 3. Components

@solara.component
def BivariateMapCard():
    x_label = X_OPTIONS[x_col.value]
    y_label = Y_OPTIONS[y_col.value]
    m       = build_bivariate_map(con, x_col.value, x_label, y_col.value, y_label)
    solara.Markdown(f"#### Bivariate Choropleth — {x_label} × {y_label}")
    solara.display(m)

@solara.component
def LegendCard():
    x_label = X_OPTIONS[x_col.value]
    y_label = Y_OPTIONS[y_col.value]
    fig     = build_bivariate_legend(x_label, y_label, y_col.value)
    with solara.Card(title="Legend"):
        solara.FigureMatplotlib(fig, dependencies=[x_col.value, y_col.value])

@solara.component
def SummaryStatsCard():
    x_label = X_OPTIONS[x_col.value]
    y_label = Y_OPTIONS[y_col.value]
    styled  = build_summary_stats(con, x_col.value, y_col.value)
    with solara.Card(title=f"Summary Stats — {x_label} × {y_label}"):
        solara.display(styled)

@solara.component
def NeedChartCard():
    fig = build_need_chart(con, y_col.value)
    with solara.Card(title="Top 15 Block Groups by Tree Program Need"):
        solara.FigureMatplotlib(fig, dependencies=[y_col.value])

@solara.component
def NeedMapCard():
    m = build_need_map(con, y_col.value)
    with solara.Card(title="Top 15 Block Groups — Location"):
        solara.display(m)

# 4. Page

@solara.component
def Page():
    solara.Title("Urban Vegetation Dashboard — Phoenix, AZ")

    with solara.Column():

        # Header
        with solara.Column(align="center"):
            solara.Markdown("# Understanding Urban Vegetation and Socioeconomic Demographics in Maricopa County",
                            style={"text-align": "center"})
            solara.Markdown(
                "<div style='text-align:center;color:#8b949e'>"
                "Exploring tree equity across Maricopa County block groups using NDVI, "
                "Tree Equity Scores, and Census demographics.<br>"
                "Data: Google Earth Engine · U.S. Census ACS 5-Year · American Forests"
                "</div>"
            )

        with solara.GridFixed(columns=2):
            with solara.Card(title="Maricopa County Baselines"):
                with solara.Row():
                    solara.Markdown(f"**Avg NDVI:** `{baseline_ndvi:.3f}`")
                    solara.Markdown(f"**Median income:** `${baseline_income:,.0f}`")
                    solara.Markdown(f"**% Minority:** `{baseline_minority:.1f}%`")

            with solara.Card(title="Map Controls"):
                with solara.Row():
                    with solara.Column():
                        solara.Select(
                            label="X axis",
                            value=x_col,
                            values=list(X_OPTIONS.keys()),
                        )
                    with solara.Column():
                        solara.Select(
                            label="Y axis",
                            value=y_col,
                            values=list(Y_OPTIONS.keys()),
                        )

        # Bivariate map (full width)
        BivariateMapCard()

        # Legend + stats side by side
        with solara.GridFixed(columns=2):
            LegendCard()
            SummaryStatsCard()

        # Need chart + map full width
        with solara.GridFixed(columns=2):
            NeedChartCard()
            NeedMapCard()