diff --git a/dash_app/app.py b/dash_app/app.py index 4445486..f7a4bd6 100644 --- a/dash_app/app.py +++ b/dash_app/app.py @@ -162,13 +162,14 @@ def show_hide_element(feature, is_ccs, cooling, capacity_factor): Input(component_id="carbon-capture-select", component_property="value"), Input(component_id="cooling-type-select", component_property="value"), Input(component_id="capacity-factor-select", component_property="value"), - Input(component_id="layer-selector", component_property="value") + Input(component_id="layer-selector", component_property="value"), + Input('adjust-mode', 'value') ], ) def map(year, ssp, tech, subtech, feature, - is_ccs, coolingtype, capacity_factor, selected_layers): + is_ccs, coolingtype, capacity_factor, selected_layers, adjust_mode): # ----------------------------------------------------------------------------- # Creates and displays map by querying a "database" table of all pathways @@ -196,45 +197,139 @@ def map(year, ssp, # i += 1 # DeckGL - fig_div = plot_deckgl_map(COMPILED_DIR=COMPILED_DIR, fpaths=fpaths, selected_layers=selected_layers) + fig_div = plot_deckgl_map(COMPILED_DIR=COMPILED_DIR, fpaths=fpaths, selected_layers=selected_layers, adjust_mode=adjust_mode) return fig_div -@app.callback( - [ - Output(component_id='data_title', component_property='children'), - Output(component_id='tag_id', component_property='children'), - Output(component_id='source_type', component_property='children'), - Output(component_id='description', component_property='children'), - Output(component_id='date_updated', component_property='children'), - Output(component_id='date_accessed', component_property='children'), - Output(component_id='methodlogy', component_property='children'), - Output(component_id='citation', component_property='children'), - Output(component_id='data_link', component_property='children') - ], - [Input(component_id='table', component_property='active_cell')] - ) - -def output_string(active_cell): +# @app.callback( +# [ +# Output(component_id='data_title', component_property='children'), +# Output(component_id='tag_id', component_property='children'), +# Output(component_id='source_type', component_property='children'), +# Output(component_id='description', component_property='children'), +# Output(component_id='date_updated', component_property='children'), +# Output(component_id='date_accessed', component_property='children'), +# Output(component_id='methodlogy', component_property='children'), +# Output(component_id='citation', component_property='children'), +# Output(component_id='data_link', component_property='children') +# ], +# [Input(component_id='table', component_property='active_cell')] +# ) + +# def output_string(active_cell): + +# if active_cell is None: +# return "", "", "", "", "", "", "", "", "" + +# data_row = active_cell['row'] +# data_col_id = active_cell['column_id'] + +# title = src_meta.loc[data_row, "plain_language_layer_name"] +# tag_id = src_meta.loc[data_row, "source_tag_id"] +# src_type = src_meta.loc[data_row, "source_type"] +# desc = src_meta.loc[data_row, "source_data_description"] +# date_updated = src_meta.loc[data_row, "source_data_updated"] +# data_accessed = src_meta.loc[data_row, "source_data_accessed"] +# layer_methodology = src_meta.loc[data_row, "layer_methodology"] +# citation = src_meta.loc[data_row, "source_data_citation"] +# data_link = src_meta.loc[data_row, "source_data_link"] + +# return str(title), str(tag_id), str(src_type), str(desc), str(date_updated), str(data_accessed), str(layer_methodology), str(citation), str(data_link) + +# @app.callback( +# Output('adjust-mode', 'style'), +# Input('adjust-mode', 'value') +# ) +# def update_toggle_style(value): +# if value: # When the switch is "true" +# return { +# 'backgroundColor': '#ffdd57', # Sunny color +# 'border': '1px solid #f39c12', # Optional border color +# } +# else: # When the switch is "false" +# return { +# 'backgroundColor': 'transparent', # Keep transparent +# 'border': '1px solid #ccc', # Optional border color +# } + +# @app.callback( +# Output('adjust-mode', 'style'), +# Output('toggle-icon', 'style'), +# Output('moon-icon', 'style'), +# Output('sun-icon', 'style'), +# Input('adjust-mode', 'n_clicks'), +# ) +# def update_switch(n_clicks): +# if n_clicks % 2 == 1: # Odd clicks mean switch is "on" +# return ( +# {'backgroundColor': '#ffdd57'}, # Sunny color when "on" +# {'transform': 'translateX(30px)'}, # Move the icon to the right +# {'display': 'none'}, # Hide moon icon +# {'display': 'block'} # Show sun icon +# ) +# else: # Even clicks mean switch is "off" +# return ( +# {'backgroundColor': '#ccc'}, # Default color when "off" +# {'transform': 'translateX(0)'}, # Move the icon to the left +# {'display': 'block'}, # Show moon icon +# {'display': 'none'} # Hide sun icon +# ) - if active_cell is None: - return "", "", "", "", "", "", "", "", "" +@app.callback( + Output('adjust-mode', 'color'), + # Output('output', 'children'), + Input('adjust-mode', 'value') +) +def update_switch(value): + if value: # When the switch is "True" + return "#fce17c" + else: # When the switch is "False" + return 'blue' - data_row = active_cell['row'] - data_col_id = active_cell['column_id'] - - title = src_meta.loc[data_row, "plain_language_layer_name"] - tag_id = src_meta.loc[data_row, "source_tag_id"] - src_type = src_meta.loc[data_row, "source_type"] - desc = src_meta.loc[data_row, "source_data_description"] - date_updated = src_meta.loc[data_row, "source_data_updated"] - data_accessed = src_meta.loc[data_row, "source_data_accessed"] - layer_methodology = src_meta.loc[data_row, "layer_methodology"] - citation = src_meta.loc[data_row, "source_data_citation"] - data_link = src_meta.loc[data_row, "source_data_link"] +@app.callback( + Output('banner', 'style'), + Output('app-logo', 'style'), + Output('page-body', 'style'), + Input('adjust-mode', 'value') +) +def update_mode(value): + if value: # When the switch is "True" + header_banner = { + "width": "100%", + "background-color": "#2C7E9E", + "display": "inline-block", + "grid-area": "header", + "transition": "background-color 0.3s" + } + app_logo = { + "filter": "invert(108%) sepia(0%) saturate(3207%) hue-rotate(0deg) brightness(100%) contrast(100%)", + "transition": "filter 0.3s" + } + page_body = { + "background-color": "white", + # "background-color": "rgba(255, 255, 255, 0.1)" + } + return header_banner, app_logo, page_body - return str(title), str(tag_id), str(src_type), str(desc), str(date_updated), str(data_accessed), str(layer_methodology), str(citation), str(data_link) + else: # When the switch is "False" + header_banner = { + "width": "100%", + "background-color": "#1F244D", + "display": "inline-block", + "grid-area": "header", + "transition": "background-color 0.3s" + } + + app_logo = { + "filter": "invert(38%) sepia(13%) saturate(3207%) hue-rotate(0deg) brightness(100%) contrast(80%)", + "transition": "filter 0.3s" + } + page_body = { + "background-color": "black", + # "background-color": "rgba(0, 0, 0, 0.1)" # rgba(0, 0, 0, 0.5) + } + return header_banner, app_logo, page_body # ----------------------------------------------------------------------------- # App runs here. Define configurations, proxies, etc. diff --git a/dash_app/assets/banner.css b/dash_app/assets/banner.css index d0216b9..891f210 100644 --- a/dash_app/assets/banner.css +++ b/dash_app/assets/banner.css @@ -1,29 +1,3 @@ -/*CSS Across the App*/ - -:root { - /* Color styles */ - --space--blue: #1F244D; - --electric--blue: #0A8AD2; - --soft--grey: #F9F9F9; - --black: #000000; - --pnnl--orange: #F09326; - --pnnl--orange-img: invert(58%) sepia(13%) saturate(3207%) hue-rotate(0deg) brightness(100%) contrast(80%); - --pnnl--orange-img2: invert(38%) sepia(13%) saturate(3207%) hue-rotate(0deg) brightness(100%) contrast(80%); - --grey: #D9D9D9; - --white: #FFFFFF; - --hard--grey: #545454; - - /* Text-size styles */ - --font--footer: 16px; - --font--tag: 13px; - --font--name: 16px; - --font--title: 16px; - --font--namespace: 48px; - --font--number: 13px; - -} - - /* DISPLAY: FLEX put elements in a horizontal line */ /* FLOAT: LEFT OR RIGHT where elements go in div */ @@ -34,7 +8,8 @@ .bannerbar { /* height: 50px;*/ width: 100%; - background-color: var(--space--blue); + /* background-color: var(--space--blue); */ + background-color: #2C7E9E; color: var(--soft--grey); display: inline-block; grid-area: header; diff --git a/dash_app/assets/footer.css b/dash_app/assets/footer.css index 71fe7bb..9d0f35c 100644 --- a/dash_app/assets/footer.css +++ b/dash_app/assets/footer.css @@ -1,47 +1,11 @@ -/*CSS Across the App*/ - -:root { - /* Color styles */ - --space--blue: #1F244D; - --electric--blue: #0A8AD2; - --soft--grey: #F9F9F9; - --black: #000000; - --pnnl--orange: #F09326; - --pnnl--orange-img: invert(58%) sepia(13%) saturate(3207%) hue-rotate(0deg) brightness(100%) contrast(80%); - --pnnl--orange-img2: invert(38%) sepia(13%) saturate(3207%) hue-rotate(0deg) brightness(100%) contrast(80%); - --white-img: invert(108%) sepia(0%) saturate(3207%) hue-rotate(0deg) brightness(100%) contrast(100%); - --grey: #D9D9D9; - --white: #FFFFFF; - --hard--grey: #545454; - - /* Text-size styles */ - --font--footer: 16px; - --font--tag: 13px; - --font--name: 16px; - --font--title: 16px; - --font--namespace: 48px; - --font--number: 13px; - - --font--weight--footer: 5; - -} - - #footer { -/* maybe absolute is breaking it?*/ -/* position: absolute;*/ bottom: 0; width: 100%; height: 35px; grid-area: footer; - -/* 2.5rem*/ -/* 50px*/ } - .footerbar { -/* height: 50px;*/ width: 100%; background-color: var(--space--blue); color: var(--soft--grey); diff --git a/dash_app/assets/icons/map_icons/fuchsia_square.svg b/dash_app/assets/icons/map_icons/fuchsia_square.svg new file mode 100644 index 0000000..bd432d0 --- /dev/null +++ b/dash_app/assets/icons/map_icons/fuchsia_square.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/dash_app/assets/icons/map_icons/im3_blue_square.svg b/dash_app/assets/icons/map_icons/im3_blue_square.svg new file mode 100644 index 0000000..4bf3b01 --- /dev/null +++ b/dash_app/assets/icons/map_icons/im3_blue_square.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/dash_app/assets/layers.css b/dash_app/assets/layers.css new file mode 100644 index 0000000..964ca3f --- /dev/null +++ b/dash_app/assets/layers.css @@ -0,0 +1,14 @@ +#layer-selector { + z-index: 2; + overflow-y: scroll; + background-color: var(--soft--grey); + position: absolute; /* Positioning it relative to the parent */ + bottom: 0; + right: 0; + width: 190px; /* Set the desired width */ + margin-bottom: 10px; + margin-right: 270px; + flex-direction: column; + border-radius: 15px; + padding: 10px; +} \ No newline at end of file diff --git a/dash_app/assets/map.css b/dash_app/assets/map.css index d639322..24bdf8a 100644 --- a/dash_app/assets/map.css +++ b/dash_app/assets/map.css @@ -1,55 +1,24 @@ #deck-gl { - /* height: 50% !important; */ - /* width: 50% !important; */ - left: auto !important; - top: auto !important; + /* left: auto !important; */ + /* top: auto !important; */ } #deckgl-wrapper { - height: 50% !important; - width: 50% !important; + /* height: 50% !important; */ + /* width: 50% !important; */ left: auto !important; top: auto !important; position: relative !important; - /* position: relative !important; */ z-index: 1 !important; - height: calc(100vh - 85px) !important; - width: calc(150vh - 5px) !important; - margin-left: -100px !important; - /* width: 1300px; - /* background-color: white !important; */ -} - -#energy-map { - margin-top: -5px; - height: calc(100vh - 80px); - /* margin-left:; */ -/* margin-bottom: -5px !important;*/ -/* height: 700px; */ -/* 800*/ - width: 1300px; -} - -#energy-map2 { - margin-top: -5px; -/* height: 700px; */ -/* 800*/ - width: 1300px; -} - -#energy-map3 { - margin-top: -50px; - height: 1000px !important; - margin-right: -50px; - margin-left: -50px; - /* height: calc(100vh - 80px); */ - /* margin-left:; */ -/* margin-bottom: -5px !important;*/ -/* height: 700px; */ -/* 800*/ - /* width: 1300px; */ + height: var(--body--height) !important; /* Adjust width based on viewport height */ + width: calc(100vw - 0px) !important; /* Adjust width based on viewport width */ + /* width: 100% !important; */ + /* margin-left: -100px !important; */ + /* border: 1px solid red; */ + /* Can change "space" color: */ + /* background-color: black !important; */ } -/* .loader-wrapper > div { - visibility: visible !important; -} */ \ No newline at end of file +.dash-loading .dash-loading-content { + background-color: transparent; /* Make loading content background transparent */ +} \ No newline at end of file diff --git a/dash_app/assets/page.css b/dash_app/assets/page.css index f13bf61..afad1a3 100644 --- a/dash_app/assets/page.css +++ b/dash_app/assets/page.css @@ -1,45 +1,3 @@ -/*CSS Across the App*/ - -:root { - /* Color styles */ - --space--blue: #1F244D; - --electric--blue: #0A8AD2; - --soft--grey: #F9F9F9; - --black: #000000; - --pnnl--orange: #F09326; - --pnnl--orange-img: invert(58%) sepia(13%) saturate(3207%) hue-rotate(0deg) brightness(100%) contrast(80%); - --pnnl--orange-img2: invert(38%) sepia(13%) saturate(3207%) hue-rotate(0deg) brightness(100%) contrast(80%); - --white-img: invert(108%) sepia(0%) saturate(3207%) hue-rotate(0deg) brightness(100%) contrast(100%); - --grey: #D9D9D9; - --white: #FFFFFF; - --hard--grey: #545454; - --teal: #328054; - --green: #1fa65a; - - /* Text-size styles */ - --font--footer: 16px; - --font--tag: 13px; - --font--name: 16px; - --font--title: 16px; - --font--namespace: 48px; - --font--number: 13px; - --page-fontsize: 14px; - - --font--weight--footer: 5; - -} - -/* #map-select-container { - display: none; -} */ - -img.leaflet-tile { - image-rendering: pixelated; -} - -/* what does this mean? */ -/** { margin: 0; padding: 0 }*/ - body { background-color: var(--soft--grey); display: flex; @@ -54,82 +12,61 @@ body { } -/*html -{ - height: 100%; -} -*/ -/*header, -footer { - flex: none; -}*/ - #app-container { height: 100%; -/* min-height:calc(100% - 35px) !important;*/ - } #page-body { -/* min-height:calc(100% - 75px) !important;*/ - height: calc(100vh - 85px); - background: orange; -} - -.page { -/* min-height:calc(100% - 110px) !important;*/ - - + height: var(--body--height); + background: white; + /* background: rgba(255, 255, 255, 0.1); */ display: flex; -/* display: grid;*/ - grid-area: main; -/* height: 1000px;*/ - -/* flex-direction: column;*/ -/* border: 3px solid red;*/ -/* -webkit-box-sizing: border-box;*/ -/* -moz-box-sizing: border-box;*/ -/* box-sizing: border-box;*/ -/* height:100%;*/ -/* position: absolute;*/ -/* top: 50px; - bottom: 50px;*/ -/* overflow-y: scroll;*/ flex: auto; -webkit-overflow-scrolling: touch; -/* min-height: 100%; */ -/* height: auto !important; */ -/* height: 100%; */ - vertical-align: bottom; + /* vertical-align: bottom; */ margin-top: -6px; -/* margin-bottom: -5px;*/ - } .map-column { - flex-grow: 5; -/* border: 1px solid red;*/ -/* resize: horizontal;*/ + /* border: 3px solid red; */ + height: var(--body--height); + width: calc(100vw - 0px); overflow: auto; } +/* Right and Left Panels */ + .nav-column { background-color: var(--soft--grey); - /* flex-grow: 5; */ padding-left: 15px; padding-right: 15px; - width: 350px; + /* width: 350px; */ overflow-y: scroll; -/* border: 1px solid red;*/ + z-index: 2; + position: absolute; /* Positioning it relative to the parent */ + top: 0; + right: 0; + width: 250px; /* Set the desired width */ + height: 100%; /* Full height of the parent */ + /* background-color: coral; */ + margin-top: 50px; + height: var(--body--height); } -.dash-graph { - height: calc(100vh - 0px) !important; - overflow-y: hidden !important; - /* height: 1000px !important; */ +#about { + width: 310px; + z-index: 2; + overflow-y: scroll; + background-color: var(--soft--grey); + position: absolute; /* Positioning it relative to the parent */ + top: 0; + left: 0; + width: 250px; /* Set the desired width */ + margin-top: 50px; + height: var(--body--height); } -#information-tab, #insights-tab, #layers-tab { +#insights-tab, #layers-tab { background-color: var(--blue); font-size: var(--sub-fontsize); color: var(--teal); @@ -140,7 +77,7 @@ footer { border-bottom: 2px solid var(--grey); } -#information-tab:hover, #insights-tab:hover, #layers-tab:hover { +#insights-tab:hover, #layers-tab:hover { color: var(--green); border-bottom: 2px solid var(--green); } @@ -166,22 +103,29 @@ footer { line-height: 1.3; font-size: var(--page-fontsize); } + +.guidance-text { + padding-left: 15px; + padding-right: 15px; + line-height: 1.3; + font-size: var(--font--title); + margin: 0px; +} + .header-text { font-weight: 300; padding-left: 15px; padding-right: 15px; -/* padding-top: 5px;*/ -/* margin-bottom: -5px;*/ font-size: var(--font--title); } .dropdown-header-text { font-weight: 300; + margin: 0px; + padding-bottom: 10px; padding-top: 15px; padding-right: 15px; padding-left: 15px; -/* padding-top: 5px;*/ -/* margin-bottom: -5px;*/ font-size: var(--font--title); } @@ -194,27 +138,4 @@ footer { .hr { margin-left: 15px; margin-right: 15px; -/* margin: 19rem 0rem 0.3rem 0rem;*/ -} - -#about { - width: 310px; - overflow-y: scroll; - background-color: var(--soft--grey); -} - -/*#intro {*/ -/* overflow-y: scroll;*/ - -/* float: left;*/ -/* width: 50%;*/ -/*}*/ - -/*.page div:nth-child(1) { - float: left; -} - -.page div:nth-child(2) { - float: right; - width: 50%; -}*/ +} \ No newline at end of file diff --git a/dash_app/assets/root.css b/dash_app/assets/root.css new file mode 100644 index 0000000..73c6c1e --- /dev/null +++ b/dash_app/assets/root.css @@ -0,0 +1,34 @@ +/*CSS Across the App*/ + +:root { + /* Color styles */ + --space--blue: #1F244D; + --electric--blue: #0A8AD2; + --soft--grey: #F9F9F9; + --black: #000000; + --pnnl--orange: #F09326; + --pnnl--orange-img: invert(58%) sepia(13%) saturate(3207%) hue-rotate(0deg) brightness(100%) contrast(80%); + --pnnl--orange-img2: invert(38%) sepia(13%) saturate(3207%) hue-rotate(0deg) brightness(100%) contrast(80%); + --white-img: invert(108%) sepia(0%) saturate(3207%) hue-rotate(0deg) brightness(100%) contrast(100%); + --grey: #D9D9D9; + --white: #FFFFFF; + --hard--grey: #545454; + --teal: #328054; + --green: #1fa65a; + + /* Text-size styles */ + --font--footer: 16px; + --font--tag: 13px; + --font--name: 16px; + --font--title: 16px; + --font--namespace: 48px; + --font--number: 13px; + --page-fontsize: 14px; + + --font--weight--footer: 5; + --body--height: calc(100vh - 50px); +} + +a { + text-decoration: none; /* Removes underline */ +} \ No newline at end of file diff --git a/dash_app/assets/settings.css b/dash_app/assets/settings.css new file mode 100644 index 0000000..baf909c --- /dev/null +++ b/dash_app/assets/settings.css @@ -0,0 +1,16 @@ +#adjust-mode { + z-index: 2; + overflow-y: scroll; + background-color: var(--soft--grey); + position: absolute; /* Positioning it relative to the parent */ + top: 0; + right: 0; + margin-top: 60px; + margin-right: 270px; + background: transparent; +} + +/* #adjust-mode > div > div > div:nth-child(2) > button{ + background-color: white; + color: white; +} */ diff --git a/dash_app/assets/table.css b/dash_app/assets/table.css index 19ef9ac..f8b0ebc 100644 --- a/dash_app/assets/table.css +++ b/dash_app/assets/table.css @@ -1,59 +1,13 @@ -/*CSS Across the App*/ - -:root { - /* Color styles */ - --space--blue: #1F244D; - --electric--blue: #0A8AD2; - --soft--grey: #F9F9F9; - --black: #000000; - --pnnl--orange: #F09326; - --pnnl--orange-img: invert(58%) sepia(13%) saturate(3207%) hue-rotate(0deg) brightness(100%) contrast(80%); - --pnnl--orange-img2: invert(38%) sepia(13%) saturate(3207%) hue-rotate(0deg) brightness(100%) contrast(80%); - --grey: #D9D9D9; - --white: #FFFFFF; - --hard--grey: #545454; - - /* Text-size styles */ - --font--footer: 16px; - --font--tag: 13px; - --font--name: 16px; - --font--title: 16px; - --font--namespace: 48px; - --font--number: 13px; - -} - - -/* DISPLAY: FLEX put elements in a horizontal line */ -/* FLOAT: LEFT OR RIGHT where elements go in div */ -/* -#table-container { - height: 750px; - width: 100%; - overflow: scroll, - padding: 10px 10px 10px 20px; -} - -#table { - overflowY: scroll; -}*/ - #data_title { background: #b84427; color: white; } .metatext { padding: 0px 0px 5px 15px; -/* margin-top: 14px;*/ -/* text-align: center;*/ vertical-align: middle; - } .horizonal-text { -/* display: inline-block;*/ display: flex; -/* background: blue;*/ padding: 0px 0px 0px 0px; - } \ No newline at end of file diff --git a/dash_app/definitions.py b/dash_app/definitions.py index 82f8d58..c119b90 100644 --- a/dash_app/definitions.py +++ b/dash_app/definitions.py @@ -7,7 +7,7 @@ PORT = int(os.environ.get("PORT", 8060)) REQUESETS_PATHNAME_PREFIX = "/" -CONNECT_TO_LAMBDA = True +CONNECT_TO_LAMBDA = False # FILE PATHS if CONNECT_TO_LAMBDA: diff --git a/dash_app/layout.py b/dash_app/layout.py index 7bffd6c..b9e9265 100644 --- a/dash_app/layout.py +++ b/dash_app/layout.py @@ -22,6 +22,7 @@ import dash from dash import html, dcc import dash_bootstrap_components as dbc +import dash_daq as daq from dash import dash_table from flask_caching import Cache cache = Cache(config={'CACHE_TYPE': 'SimpleCache'}) @@ -97,7 +98,7 @@ def create_app(): "South Carolina", "South Dakota", "Tennessee", "Texas", "Utah", "Virginia", "Virgin Islands", "Vermont", "Washington", "Wisconsin", "West Virginia", "Wyoming"] - tabs = ["information-tab", "insights-tab", "layers-tab"] + tabs = ["", "insights-tab", "layers-tab"] section_headers = ["Overview", "Authors", "Funding"] @@ -116,7 +117,7 @@ def create_app(): overview_text2 = """ GRIDCERF data can be directly used with the power plant siting model CERF (Capacity Expansion Regional Feasibility) to site power plants at a 1km2 resolution.""" - overview_text3 = """Download GRIDCERF data from MSDLIVE.""" + overview_text3 = """Download the data.""" author_text = """GRIDCERF represents the extensive collection of data formatting, processing, and visualization created by the IM3 Group.""" @@ -129,7 +130,7 @@ def create_app(): "Select a year", "Select a technology", "Select a technology sub-type", - "Select a Carbon Capture Sequestration (CCS) method", + "Carbon Capture Sequestration (CCS)", "Select a Cooling Type", "Select a Shared Socioeconomic Pathway (SSP)", # Select a socioeconomic scenario "Select a feature", @@ -146,12 +147,18 @@ def create_app(): "feature-select" ] + def mode_switch(): + + return daq.ToggleSwitch( + id='adjust-mode', + className="daq-toggle-switch", + value=True, + ) def table_card(): return html.Div( id="table-container", - className="page", children=[dash_table.DataTable( id='table', row_selectable="multi", @@ -214,34 +221,7 @@ def tabs_card(): selected_className="active-tab", children=[ html.Br(), - # html.Div(id="map-select-container", - # className="select-container", - # children=[ - # html.P(select_headers[0], id='select-header0', className="dropdown-header-text"), - # dcc.Dropdown( - # id="map-select", - # className="dropdown-select", - # options=["Plotly-imshow","Plotly-datashader, mapbox", "Plotly-datashader, holoviews", "Leaflet and TiTiler", "Mapbox", "DeckGL"], - # value="DeckGL", # "Mapbox", # "Plotly-imshow", - # clearable=False, - # searchable=False, - # multi=False - # ), - - # ] - # ), - - # html.P(select_headers[1], id='select-header1', className="dropdown-header-text"), - # dcc.Dropdown( - # id="state-select", - # className="dropdown-select", - # options=state_names, - # value=state_names[0], - # clearable=False, - # searchable=False, - # multi=False - # ), - + html.P("Explore pre-compiled technology-specific siting suitability layers", className="guidance-text"), html.Div(id="tech-select-container", className="select-container", children=[ @@ -258,39 +238,6 @@ def tabs_card(): ] ), - html.Div(id="year-select-container", - className="select-container", - children=[ - html.P(select_headers[2], id='select-header2', className="dropdown-header-text"), - dcc.Dropdown( - id="year-select", - className="dropdown-select", - options=list(range(2025, 2105, 5)), - value=2025, - clearable=False, - searchable=False, - multi=False - ), - - ] - ), - - html.Div(id="ssp-select-container", - className="select-container", - children=[ - html.P(select_headers[7], id='select-header7', className="dropdown-header-text"), - dcc.Dropdown( - id="ssp-select", - className="dropdown-select", - options=tech_pathways_df["ui_ssp"].unique(), - value=list(tech_pathways_df["ui_ssp"].unique())[0], - clearable=False, - searchable=False, - multi=False - ), - ] - ), - html.Div(id="subtech-select-container", className="select-container", children=[ @@ -365,6 +312,38 @@ def tabs_card(): clearable=False, searchable=False, multi=False + ), + ] + ), + html.Div(id="year-select-container", + className="select-container", + children=[ + html.P(select_headers[2], id='select-header2', className="dropdown-header-text"), + dcc.Dropdown( + id="year-select", + className="dropdown-select", + options=list(range(2025, 2105, 5)), + value=2025, + clearable=False, + searchable=False, + multi=False + ), + + ] + ), + + html.Div(id="ssp-select-container", + className="select-container", + children=[ + html.P(select_headers[7], id='select-header7', className="dropdown-header-text"), + dcc.Dropdown( + id="ssp-select", + className="dropdown-select", + options=tech_pathways_df["ui_ssp"].unique(), + value=list(tech_pathways_df["ui_ssp"].unique())[0], + clearable=False, + searchable=False, + multi=False ), ] ), @@ -378,8 +357,21 @@ def tabs_card(): selected_className="active-tab", children=[ html.Br(), - table_card(), - layer_metadata_card() + html.P("Explore individual layers in the database", className="guidance-text"), + html.Br(), + dcc.Dropdown( + id='multi-layer-dropdown', + className="dropdown-select", + options=[ + {'label': 'Option 1', 'value': 'option1'}, + {'label': 'Option 2', 'value': 'option2'}, + {'label': 'Option 3', 'value': 'option3'} + ], + value=['option1'], # Initial selected values + multi=True + ), + # table_card(), + # layer_metadata_card() ] ) @@ -502,30 +494,33 @@ def map(): return html.Div( children=[ - dcc.Checklist( - id='layer-selector', - options=[ - {'label': 'Basemap Ocean', 'value': 'base-map-ocean'}, # AB: need to predfine the database - {'label': 'Basemap Land', 'value': 'base-map'}, - {'label': 'Feasibility Layer', 'value': 'feasibility-layer'}, - ], - value=["base-map-ocean", "base-map"], # Default selected layers - inline=True, - style={'display': 'none'} - ), - dcc.Loading( - id="loading", - type="circle", - # style={"backgroundColor": "transparent"}, - children=[ - html.Div( - id="map", - className="map-column", + dcc.Loading( + id="loading", + type="circle", + # style={"backgroundColor": "transparent"}, children=[ - ] - ) - ] - ) + html.Div( + id="map", + className="map-column", + children=[ + ] + ) + ] + ), + about(), + nav(), + mode_switch(), + dcc.Checklist( + id='layer-selector', + options=[ + {'label': 'Basemap Ocean', 'value': 'base-map-ocean'}, # AB: need to predfine the database + {'label': 'Basemap Land', 'value': 'base-map'}, + {'label': 'Feasibility Layer', 'value': 'feasibility-layer'}, + ], + value=["base-map-ocean", "base-map", "feasibility-layer"], # Default selected layers + inline=True, + # style={'display': 'none'} + ), ] ) @@ -583,9 +578,9 @@ def page_card(): className="page", children=[ - about(), + # about(), map(), - nav(), + # nav(), ] ) @@ -596,7 +591,7 @@ def page_card(): # dcc.Store(id='results'), header_card(), page_card(), - footer_card(), + # footer_card(), ], ) diff --git a/dash_app/src/deckgl.py b/dash_app/src/deckgl.py index 6065a70..aebf6ae 100644 --- a/dash_app/src/deckgl.py +++ b/dash_app/src/deckgl.py @@ -33,12 +33,19 @@ from definitions import OUTDIR @cache.memoize(timeout=7200) # Cache for 2 hours -def load_large_data(layer_name, COMPILED_DIR, fpaths): +def load_large_data(layer_name, COMPILED_DIR, fpaths, adjust_mode): if layer_name == "base-map-ocean": OCEANS = json.load(open('data/ne_50m_ocean.geojson', 'r', encoding='utf-8')) + # #D4DADC and RBG is 212, 218, 220 + + if adjust_mode: # When the switch is "True" + fill_color = [212, 218, 220] # light grey + else: + fill_color = [0, 31, 72] # dark blue + return pydeck.Layer( "GeoJsonLayer", id="base-map-ocean", @@ -48,29 +55,47 @@ def load_large_data(layer_name, COMPILED_DIR, fpaths): pickable=False, # False to remove tooltip over oceans auto_highlight=True, get_line_color=[60, 60, 60], # [134, 181, 209], [22, 36, 105], - get_fill_color=[0, 31, 72], + get_fill_color=fill_color, opacity=0.5, ) + if layer_name == "base-map": LAND = "https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_50m_admin_0_scale_rank.geojson" - return pydeck.Layer( - "GeoJsonLayer", - id="base-map", - data=LAND, - stroked=False, - filled=True, - get_line_color=[60, 60, 60], - get_fill_color=[66, 133, 55], # green [32, 145, 62], [200, 200, 200], [160, 160, 160] - ) + if adjust_mode: # When the switch is "True" + # fill_color = [250, 250, 248] # near white + return pydeck.Layer( + "GeoJsonLayer", + id="base-map", + data=LAND, + stroked=False, + filled=True, + get_line_color=[60, 60, 60], + get_fill_color=[250, 250, 248] # near white + ) + else: + return pydeck.Layer( + "GeoJsonLayer", + id="base-map", + data=LAND, + stroked=False, + filled=True, + get_line_color=[60, 60, 60], + get_fill_color=[66, 133, 55], # green [32, 145, 62], [200, 200, 200], [160, 160, 160] + ) if layer_name == "feasibility-layer": TIFPATH = os.path.join(COMPILED_DIR, fpaths[0]) data_df, array, source_crs, geo_crs, df_coors_long, boundingbox, img = open_as_raster(TIFPATH=TIFPATH, is_reproject=True, is_convert_to_png=False) + if adjust_mode: # When the switch is "True" + url_path = "/assets/icons/map_icons/im3_blue_square.svg" + else: + url_path = "/assets/icons/map_icons/fuchsia_square.svg" + icon_data = { "url": "/assets/icons/map_icons/blue_square.svg", # svg repo "width": 242, @@ -129,7 +154,7 @@ def load_large_data(layer_name, COMPILED_DIR, fpaths): ) -def plot_deckgl_map(COMPILED_DIR, fpaths, selected_layers): +def plot_deckgl_map(COMPILED_DIR, fpaths, selected_layers, adjust_mode): view_state = pydeck.ViewState(latitude=39.8283, longitude=-98.5795, # center U.S. zoom=2, @@ -141,7 +166,7 @@ def plot_deckgl_map(COMPILED_DIR, fpaths, selected_layers): deck_layers = [] for layer in selected_layers: - layer = load_large_data(layer, COMPILED_DIR, fpaths) # Load data, cached if previously loaded + layer = load_large_data(layer, COMPILED_DIR, fpaths, adjust_mode) # Load data, cached if previously loaded deck_layers.append(layer) r = pydeck.Deck( @@ -184,13 +209,23 @@ def plot_deckgl_map(COMPILED_DIR, fpaths, selected_layers): JavaScript JSON parser, but it can be parsed by Python's JSON engine. """ - mapgl = html.Div( + if adjust_mode: + mapgl = html.Div( + dash_deck.DeckGL( + json.loads(r.to_json()), + id="deck-gl", + style={"background-color": "white"}, + # tooltip={"text": "{IsFeasible} feasible, {LatitudeProj}, {LongitudeProj}"}, + ) + ) + else: + mapgl = html.Div( dash_deck.DeckGL( json.loads(r.to_json()), id="deck-gl", style={"background-color": "black"}, # tooltip={"text": "{IsFeasible} feasible, {LatitudeProj}, {LongitudeProj}"}, + ) ) - ) return mapgl diff --git a/dash_app/test.py b/dash_app/test.py new file mode 100644 index 0000000..e38f575 --- /dev/null +++ b/dash_app/test.py @@ -0,0 +1,116 @@ +import dash +from dash import html +from dash.dependencies import Input, Output + +app = dash.Dash(__name__) + +app.layout = html.Div([ + html.Div( + id="expandable-box", + style={ + "width": "20px", + "height": "20px", + "backgroundColor": "lightgray", + "cursor": "pointer", + "transition": "width 0.3s, height 0.3s", + "border": "1px solid black", + "position": "relative" # Position relative for the close button + }, + n_clicks=0, + children=[ + # Close button will be added here + html.Button("X", id="close-button", style={ + "position": "absolute", + "top": "5px", + "right": "5px", + "backgroundColor": "red", + "color": "white", + "border": "none", + "cursor": "pointer", + "display": "none" # Hidden initially + }) + ] + ), + html.Div("Click the box to expand!", style={"margin-top": "10px"}) +]) + +@app.callback( + Output("expandable-box", "style"), + Output("expandable-box", "children"), + Input("expandable-box", "n_clicks"), + Input("close-button", "n_clicks"), +) +def toggle_expand(expand_clicks, close_clicks): + # If the close button is clicked + if close_clicks: + return ( + { + "width": "20px", + "height": "20px", + "backgroundColor": "lightgray", + "cursor": "pointer", + "transition": "width 0.3s, height 0.3s", + "border": "1px solid black", + "position": "relative" + }, + [html.Button("X", id="close-button", style={ + "position": "absolute", + "top": "5px", + "right": "5px", + "backgroundColor": "red", + "color": "white", + "border": "none", + "cursor": "pointer", + "display": "none" # Hidden when collapsed + })] # Keep the button but hidden + ) + + # If the box is clicked to expand + if expand_clicks: + return ( + { + "width": "200px", + "height": "100px", + "backgroundColor": "lightgray", + "cursor": "pointer", + "transition": "width 0.3s, height 0.3s", + "border": "1px solid black", + "position": "relative" + }, + [html.Button("X", id="close-button", style={ + "position": "absolute", + "top": "5px", + "right": "5px", + "backgroundColor": "red", + "color": "white", + "border": "none", + "cursor": "pointer", + "display": "block" # Show the close button when expanded + })] # Close button in expanded state + ) + + # Keep the small size if not clicked + return ( + { + "width": "20px", + "height": "20px", + "backgroundColor": "lightgray", + "cursor": "pointer", + "transition": "width 0.3s, height 0.3s", + "border": "1px solid black", + "position": "relative" + }, + [html.Button("X", id="close-button", style={ + "position": "absolute", + "top": "5px", + "right": "5px", + "backgroundColor": "red", + "color": "white", + "border": "none", + "cursor": "pointer", + "display": "none" # Hidden when collapsed + })] # Keep the button but hidden + ) + +if __name__ == "__main__": + app.run_server(port=8070, debug=True) diff --git a/dash_app/test2.py b/dash_app/test2.py new file mode 100644 index 0000000..49e8e82 --- /dev/null +++ b/dash_app/test2.py @@ -0,0 +1,83 @@ +import dash +from dash import html +from dash.dependencies import Input, Output + +app = dash.Dash(__name__) + +app.layout = html.Div([ + html.Div( + id="toggle-switch", + style={ + "width": "50px", # Width set to 30px + "height": "20px", # Height set to 20px + "borderRadius": "10px", # Border radius set to 10px + "position": "relative", + "backgroundColor": "#ccc", + "cursor": "pointer", + "display": "flex", + "alignItems": "center", + "padding": "2px", # Padding adjusted for smaller size + "transition": "background-color 0.3s" + }, + n_clicks=0, + children=[ + html.Div(id="icon", style={ + "width": "16px", # Circle width set to fit + "height": "16px", # Circle height set to fit + "borderRadius": "50%", # Circular shape + "backgroundColor": "white", + "boxShadow": "0 0 2px rgba(0,0,0,0.5)", + "position": "absolute", + "transition": "transform 0.3s" + }, children=[ + html.Span("🌙", id="moon-icon", style={"display": "block"}), # Moon icon + html.Span("☀️", id="sun-icon", style={"display": "none"}) # Sun icon + ]) + ] + ), + html.Div(id="output", style={"margin-top": "20px"}) +]) + +@app.callback( + Output("toggle-switch", "style"), + Output("icon", "style"), + Output("moon-icon", "style"), + Output("sun-icon", "style"), + Input("toggle-switch", "n_clicks"), +) +def toggle_switch(n_clicks): + if n_clicks % 2 == 1: # Odd clicks mean switch is "on" + return ( + {"backgroundColor": "#ffdd57", + "height": "20px", # Height set to 20px + "borderRadius": "10px", # Border radius set to 10px + "position": "relative", + "cursor": "pointer", + "display": "flex", + "alignItems": "center", + "padding": "2px", # Padding adjusted for smaller size + "transition": "background-color 0.3s", + "width": "50px"}, # Background color when "on" + {"transform": "translateX(14px)"}, # Move the circle to the right + {"display": "none"}, # Hide moon icon + {"display": "block"} # Show sun icon + ) + else: # Even clicks mean switch is "off" + return ( + {"backgroundColor": "#ccc", + "height": "20px", # Height set to 20px + "borderRadius": "10px", # Border radius set to 10px + "position": "relative", + "cursor": "pointer", + "display": "flex", + "alignItems": "center", + "padding": "2px", # Padding adjusted for smaller size + "transition": "background-color 0.3s", + "width": "50px"}, # Background color when "off" + {"transform": "translateX(0)"}, # Move the circle to the left + {"display": "block"}, # Show moon icon + {"display": "none"} # Hide sun icon + ) + +if __name__ == "__main__": + app.run_server(port=8070, debug=True)