Skip to content

Commit a074efa

Browse files
author
toddkarin
committed
Adding photovoltaic climate zones to main page
1 parent 5f61942 commit a074efa

File tree

5 files changed

+155
-84
lines changed

5 files changed

+155
-84
lines changed

assets/pvcz_screenshow2.jpg

272 KB
Loading

home.py

+20-13
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@
6666
),
6767
dbc.Col(
6868
[
69-
html.H2(["String Length Calculator ", dbc.Badge("New!", color="success")]),
69+
html.H2(["String Length Calculator "]),
7070
html.P(
7171
"""The string length calculator is an industry
7272
standard tool for calculating the maximum string
@@ -80,19 +80,26 @@
8080
src=app.get_asset_url(
8181
'string_length_screenshot.png'),
8282
style={'width': '100%'}),
83-
# html.H2("Photovoltaic Climate Zones"),
84-
# html.P(
85-
# """Photovoltaic climate zones provides climate
86-
# zones using climate-related stressors specific to
87-
# photovoltaic degradation.
88-
#
89-
# """
90-
# ),
83+
html.H2([
84+
"Photovoltaic Climate Zones ",
85+
dbc.Badge("New!", color="success")]
86+
),
87+
html.P(
88+
"""Explore the geographic distribution of
89+
environmental stress on solar photovoltaics.
90+
91+
"""
92+
),
9193
# html.A( dbc.Button("Launch Tool", color="secondary"),
92-
# href='pvcz'),
93-
# dcc.Graph(
94-
# figure={"data": [{"x": [1, 2, 3], "y": [1, 4, 9]}]}
95-
# ),
94+
# href='pv-climate-stressors'),
95+
html.P(''),
96+
html.A(
97+
html.Img(
98+
src=app.get_asset_url(
99+
'pvcz_screenshow2.jpg'),
100+
style={'width': '100%'}),
101+
href='pv-climate-stressors'
102+
),
96103
]
97104
),
98105
]

index.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@
7373
label="Tools",
7474
children=[
7575
dbc.DropdownMenuItem("String Length Calculator",href='/string-length-calculator'),
76-
# dbc.DropdownMenuItem("Photovoltaic Climate Zones"),
76+
dbc.DropdownMenuItem("Photovoltaic Climate Stressors",href='/pv-climate-stressors'),
7777
# dbc.DropdownMenuItem(divider=True),
7878
# dbc.DropdownMenuItem("Documentation"),
7979
],

pv_climate_stressors.py

+103-70
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,11 @@
5252
'textAlign': 'center'}),
5353
html.Hr(),
5454
html.H2('Overview'),
55-
dcc.Markdown("""This is a test deployment of a map showing the
56-
photovoltaic climate zones.
55+
dcc.Markdown("""Environmental stress determines the degradation rates and
56+
modes for a solar photovoltaic (PV) system. This page shows environmental
57+
stressors for PV. By choosing thresholds on temperature and humidity,
58+
we define photovoltaic climate zones (PVCZ), showing which locations are
59+
expected to show higher degradation rates for PV.
5760
5861
**We would highly appreciate any feedback** (praise, bug reports,
5962
suggestions, etc.). Please contact us at [email protected].
@@ -77,7 +80,8 @@
7780
dcc.Markdown("""
7881
7982
### Summary
80-
83+
The variable definitions and methods are described in
84+
a [conference manuscript](https://www.researchgate.net/publication/334401420_Photovoltaic_Degradation_Climate_Zones).
8185
8286
### Who we are
8387
@@ -117,8 +121,8 @@
117121
dbc.Input(id='pvcz-lat', value='37.88', type='text'),
118122
dbc.Label('Longitude'),
119123
dbc.Input(id='pvcz-lon', value='-122.25', type='text'),
120-
dbc.FormText(id='closest-message',
121-
children='Closest point shown on map'),
124+
# dbc.FormText(id='closest-message',
125+
# children='Closest point shown on map'),
122126
# html.P(''),
123127
# html.Div([
124128
# dbc.Button(id='get-weather', n_clicks=0,
@@ -135,72 +139,100 @@
135139
]),
136140
# html.H2('Simulation Input'),
137141
html.P(''),
138-
html.H2('Photovoltaic Equivalent Temperature'),
139-
dcc.Graph(id='pvcz-map',
140-
figure={
141-
'data': [
142-
go.Scattermapbox(
143-
lat=pvcz.get_pvcz_data()['lat'],
144-
lon=pvcz.get_pvcz_data()['lon'],
145-
mode='markers',
146-
marker=dict(
147-
color = pvcz.get_pvcz_data()['T_equiv_rack'],
148-
colorscale=[
149-
[0, "rgb(150,0,90)"],
150-
[0.125, "rgb(0, 0, 200)"],
151-
[0.25, "rgb(0, 25, 255)"],
152-
[0.375, "rgb(0, 152, 255)"],
153-
[0.5, "rgb(44, 255, 150)"],
154-
[0.625, "rgb(151, 255, 0)"],
155-
[0.75, "rgb(255, 234, 0)"],
156-
[0.875, "rgb(255, 111, 0)"],
157-
[1, "rgb(255, 0, 0)"]
158-
],
159-
size=6
160-
),
161-
text='T_equiv_rack: ' + np.round(pvcz.get_pvcz_data()['T_equiv_rack'],2).astype(str) + ' C',
162-
name='Database location'
163-
),
164-
],
165-
'layout': go.Layout(
166-
# autosize=True,
167-
width=1000,
168-
height=700,
169-
margin={'l': 10, 'b': 10, 't': 0, 'r': 0},
170-
hovermode='closest',
171-
mapbox=dict(
172-
accesstoken='pk.eyJ1IjoidG9kZGthcmluIiwiYSI6Ik1aSndibmcifQ.hwkbjcZevafx2ApulodXaw',
173-
bearing=0,
174-
center=dict(
175-
lat=float(40),
176-
lon=float(-100)
177-
),
178-
pitch=0,
179-
zoom=2,
180-
style='light'
181-
),
182-
legend=dict(
183-
x=0,
184-
y=1,
185-
traceorder='normal',
186-
font=dict(
187-
family='sans-serif',
188-
size=12,
189-
color='#000'
190-
),
191-
bgcolor='#E2E2E2',
192-
bordercolor='#FFFFFF',
193-
borderwidth=2
194-
)
195-
)}
196-
197-
)
198-
199-
])
142+
dbc.Card([
143+
dbc.CardHeader('PV Climate Stress Maps'),
144+
dbc.CardBody([
145+
html.P('Select stressor to plot'),
146+
dcc.Dropdown(
147+
id='pvcz-map-select',
148+
options=pvtoolslib.pvcz_stressor_dropdown_list,
149+
value='T_equiv_rack',
150+
style={'max-width': 500}
151+
),
152+
html.P(''),
153+
dcc.Loading(id="loading-1", children=[html.Div(id="loading-output-1")], type="default"),
154+
# dcc.Graph(id='pvcz-map')
155+
156+
])
157+
])
158+
])
200159

201160
# app.layout = layout
202161

203162

163+
@app.callback(
164+
Output("loading-output-1", "children"),
165+
[Input("pvcz-map-select", "value")]
166+
)
167+
def update_pvcz_map(param):
168+
# return
169+
170+
171+
172+
figure = {
173+
'data': [
174+
go.Scattermapbox(
175+
lat=pvtoolslib.pvcz_df['lat'],
176+
lon=pvtoolslib.pvcz_df['lon'],
177+
mode='markers',
178+
marker=dict(
179+
color=pvtoolslib.pvcz_df[param],
180+
colorscale=[
181+
[0, "rgb(150,0,90)"],
182+
[0.125, "rgb(0, 0, 200)"],
183+
[0.25, "rgb(0, 25, 255)"],
184+
[0.375, "rgb(0, 152, 255)"],
185+
[0.5, "rgb(44, 255, 150)"],
186+
[0.625, "rgb(151, 255, 0)"],
187+
[0.75, "rgb(255, 234, 0)"],
188+
[0.875, "rgb(255, 111, 0)"],
189+
[1, "rgb(255, 0, 0)"]
190+
],
191+
size=6,
192+
colorbar=dict(
193+
title=dict(
194+
text=pvtoolslib.pvcz_legend_str[param],
195+
side='right'),
196+
)
197+
),
198+
text= param + ': ' + np.round(pvtoolslib.pvcz_df[param], 2).astype(str) + ' C',
199+
name='Database location'
200+
),
201+
],
202+
'layout': go.Layout(
203+
autosize=True,
204+
# width=1000,
205+
# height=700,
206+
margin={'l': 10, 'b': 10, 't': 0, 'r': 0},
207+
hovermode='closest',
208+
mapbox=dict(
209+
accesstoken='pk.eyJ1IjoidG9kZGthcmluIiwiYSI6Ik1aSndibmcifQ.hwkbjcZevafx2ApulodXaw',
210+
bearing=0,
211+
center=dict(
212+
lat=float(40),
213+
lon=float(-100)
214+
),
215+
pitch=0,
216+
zoom=2,
217+
style='light'
218+
),
219+
legend=dict(
220+
x=0,
221+
y=1,
222+
traceorder='normal',
223+
font=dict(
224+
family='sans-serif',
225+
size=12,
226+
color='#000'
227+
),
228+
bgcolor='#E2E2E2',
229+
bordercolor='#FFFFFF',
230+
borderwidth=2
231+
)
232+
)}
233+
234+
return dcc.Graph(id='pvcz-map',figure=figure,config=dict(scrollZoom=True))
235+
204236
@app.callback(
205237
Output("pvcz-details-collapse", "is_open"),
206238
[Input("pvcz-details-button", "n_clicks")],
@@ -236,19 +268,20 @@ def get_stressors(lat,lon):
236268
df['lon'])
237269

238270
# Get the stressor data from this location
239-
location_df = pd.DataFrame(data={'Parameter': df.keys(),
271+
location_df = pd.DataFrame(data={'Parameter': [pvtoolslib.pvcz_legend_str[p] for p in df.keys()],
240272
'Value': df.iloc[closest_index]})
241273
for p in ['T_equiv_rack','T_equiv_roof','specific_humidity_mean','T_velocity','GHI_mean','wind_speed','T_ambient_min']:
242274
location_df['Value'][p] = '{:.2f}'.format(location_df['Value'][p])
243-
print(location_df)
275+
244276

245277
return dbc.Table.from_dataframe(location_df,
246278
striped=False,
247279
bordered=True,
248280
hover=True,
249281
index=False,
250282
size='sm',
251-
style={'font-size':'0.8rem'})
283+
# style={'font-size':'0.8rem'}
284+
)
252285

253286
#
254287
# if __name__ == '__main__':

pvtoolslib.py

+31
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import pandas as pd
1919
import pytz
2020
import glob
21+
import pvcz
2122

2223
# try:
2324
# import cPickle as pickle
@@ -41,6 +42,36 @@
4142
# Bucket for storing s3
4243
bucket = 'pvtools-nsrdb-pickle'
4344

45+
# Get pvcz data
46+
pvcz_df = pvcz.get_pvcz_data()
47+
pvcz_info = pvcz.get_pvcz_info()
48+
49+
pvcz_legend_str = {
50+
'lat': 'Latitude (degrees)',
51+
'lon': 'Longitude (degrees)',
52+
'T_equiv_rack': 'Equivalent Temperature, Rack Mount (C)',
53+
'T_equiv_roof': 'Equivalent Temperature, Roof Mount (C)',
54+
'specific_humidity_mean': 'Mean Specific Humidity (g/kg)',
55+
'T_velocity': 'Mean Temperature Velocity, Rack Mount (C/hr)',
56+
'GHI_mean' : 'GHI (kWh/m2/day)',
57+
'wind_speed': '25-year Mean Recurrence Interval wind speed (m/s)',
58+
'T_ambient_min': 'Min ambient temperature (C)',
59+
'KG_zone': 'Koppen-Geiger Zone',
60+
'T_equiv_rack_zone': 'Equivalent Temperature Zone, Rack',
61+
'T_equiv_roof_zone': 'Equivalent Temperature Zone, Roof',
62+
'specific_humidity_mean_zone': 'Mean Specific Humidity Zone',
63+
'wind_speed_zone': 'Wind Speed Zone',
64+
'pvcz': 'Photovoltaic Climate Zone',
65+
'pvcz_labeled': 'Photovoltaic Climate Zone (text)',
66+
}
67+
# Make list of options
68+
pvcz_stressor_dropdown_list = []
69+
for p in ['T_equiv_rack', 'T_equiv_roof', 'specific_humidity_mean',
70+
'T_velocity', 'GHI_mean', 'wind_speed', 'T_ambient_min',
71+
'T_equiv_rack_zone', 'T_equiv_roof_zone', 'specific_humidity_mean_zone',
72+
'wind_speed_zone', 'pvcz']:
73+
pvcz_stressor_dropdown_list.append({'label': pvcz_legend_str[p], 'value': p})
74+
4475

4576
def get_s3_files():
4677
"""

0 commit comments

Comments
 (0)