Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
181 changes: 181 additions & 0 deletions database/joint_map.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
from .models import SolarProjectData, CountyData, StorageProjectData
import pandas as pd
import numpy as np
import plotly.express as px
from plotly.offline import plot
import requests
from django_plotly_dash import DjangoDash
from dash import dcc
from dash import html
from dash.dependencies import Input, Output
import dash_bootstrap_components as dbc
import os

solarData = SolarProjectData.objects.values('data_id',
'locality',
'unit_of_government',
'project_name',
'project_mw',
'local_permit_status',
'latitude',
'longitude',
'energy_storage_onsite',
'energy_storage_mw')
storageData = StorageProjectData.objects.values('data_id',
'locality',
'unit_of_government',
'project_name',
'project_bess_mw',
'project_bess_capacity',
'local_permit_status',
'latitude',
'longitude',
'project_type')
solar_df = pd.DataFrame.from_records(solarData)
bess_df = pd.DataFrame.from_records(storageData)

#join the datasets on their common columns
joint_df = pd.merge(solar_df,bess_df,how='outer',on=['data_id',"locality",'unit_of_government','project_name','local_permit_status','latitude','longitude'])

#locate the Solar + Storage duplicate IDs
duplicate_ids = joint_df[joint_df['data_id'].duplicated()==True].data_id.to_list()

column_names = joint_df.columns.to_list()
for i in range(0,len(duplicate_ids)):
#get the indices where a data_id value is duplicated because of mismatched names between Solar and BESS for Solar+Storage projects
project_rows = joint_df[joint_df.data_id==duplicate_ids[i]].index
#it will always be two project rows, project_row[0] and project_row[1]
#pick ONE of the names, don't care which right now
joint_df.loc[project_rows[0],'project_name'] = joint_df.loc[project_rows[1],'project_name']
#go through the rest of the values and fill in the blanks to make duplicate rows
for name in column_names:
if pd.isna(joint_df.iloc[project_rows[0],][name]) == True and pd.isna(joint_df.iloc[project_rows[1],][name]) == False:
joint_df.loc[project_rows[0],name] = joint_df.loc[project_rows[1],name]
if pd.isna(joint_df.iloc[project_rows[0],][name]) == False and pd.isna(joint_df.iloc[project_rows[1],][name]) == True:
joint_df.loc[project_rows[1],name] = joint_df.loc[project_rows[0],name]
#now that the rows have been made identical, drop the duplicated IDs
joint_df.drop_duplicates(inplace=True)

#filling in the missing values for project_type with 'Solar'
joint_df.project_type.replace(np.nan,'Solar',inplace=True)
#give a text description for where the bess MW is none
joint_df.project_bess_mw.replace(np.nan,'Not Applicable',inplace=True)
#give a text description for where the storage MW is none
joint_df.project_mw.replace(np.nan,'Not Applicable',inplace=True)

#set up the plotly Dash container
jointapp = DjangoDash(name='JointDash',add_bootstrap_links=True, external_stylesheets=[dbc.themes.BOOTSTRAP,dbc.themes.FLATLY,'/static/css/styles.css'])

jointapp.layout = dbc.Container([
#buid the state overview page
html.Div([
html.Br(),
html.Br(),
html.H2("Virginia Solar and Battery Energy Storage Status Map"),
html.P("View the current status of Solar and Battery Energy Storage projects across Virginia"),
html.Div(
#dashboard
[
#developing reactive graph display based on Solar or Storage view selection
# html.H2("Select a Project Type to Graph",style={"margin-left":8}),
#html.Div(dbc.RadioItems(
# id='sourceButtons',
# className='btn-group',
# inputClassName='btn-check',
# labelClassName="btn btn--blue-d",
# options=[
#],
#value="solarMaps",
#),style={'margin-left':4,}),
html.Br(),
html.Div(dbc.RadioItems(
id='mapButtons',
className='btn-group',
inputClassName='btn-check',
labelClassName="btn--dash",
options=[
{"label": "Approved", "value": 'Approved'},
{"label": "Approved/Amended","value":"Approved/Amended"},
{"label": "By-right", "value": 'By-right'},
{"label": "Denied", "value": 'Denied'},
{"label": "Withdrawn","value":'Withdrawn'},
{"label": "Pending","value":'Pending'}
],
value='Approved',
),style={'margin-left':4,}),
#switchable maps
html.Div(dcc.Graph(id='jointStatusMap',config={'responsive':False,
'displayModeBar':True}),
style={
'margin-left':9,
'width':1184,}), #close the map div
]), #close the content div
]
)], #close the container contents list
fluid=True,
style={'display': 'flex',
'background-color':'#F2F4F8'},
className='dashboard-container') #close the container div



#this will go in a callback function
@jointapp.callback(
Output("jointStatusMap", "figure"),
Input("mapButtons","value"))

def update_joint_amap(permit_status):
jointMap = px.scatter_map(
#mapDataClean[mapDataClean['final_action_year'] <= slide_year],
joint_df[joint_df.local_permit_status==permit_status],
color='project_type',
custom_data=['project_name','project_type','locality','local_permit_status','project_mw','project_bess_mw'],
color_discrete_sequence=['rgb(40, 67, 118)','rgb(98, 187, 70)','rgb(229, 114, 0)', 'rgb(253, 218, 36)'],
category_orders={"project_type": ["Solar", "Solar + Storage", "Colocated with Solar", "Non-Solar BESS"]},
labels={'locality':'Locality',
'local_permit_status':'Local Permit Status',
'project_type':"Project Type",
'project_mw':'Project Megawatts',
'project_bess_mw':"BESS Project Megawatts",
'project_name':'Project Name',
'locality': 'Locality'},
hover_name='project_name',
hover_data={
'project_mw': True,
'locality': True,
'latitude':False,
'longitude':False},
lat='latitude',
lon='longitude',
zoom=6.57,
center = {"lat": 38.00692, "lon": -79.40695},
)
jointMap.update_layout(
font=dict(color='#242e4c'),
legend=dict(font=dict(size=12,
color='#242e4c'),
orientation='h',
yanchor='bottom',y=1),
legend2=dict(font=dict(size=12,
color='#242e4c'),
title='Project Size'),
margin={"r":0,"t":10,"l":0,"b":0},
width=1155,
height=600,
map_style='carto-positron-nolabels',
paper_bgcolor='#F2F4F8',
xaxis=dict(showgrid=False,
zeroline=False,
visible=False),
yaxis=dict(showgrid=False,
zeroline=False,
visible=False),
)
jointMap.update_traces(marker=dict(size=10),
hovertemplate="<b>%{customdata[0]}</b><br>Project Type : %{customdata[1]}<br>Locality: %{customdata[2]}<br>Local Permit Status: %{customdata[3]}<br>Solar Project Megawatts: %{customdata[4]}<br>BESS Project Megawatts: %{customdata[5]}<extra></extra>")
jointMap.add_annotation(text='<i>Source: Weldon Cooper Center Virginia Solar and Storage Database</i>',x=0,y=0,xref="paper", yref="paper",font=dict(size=8),showarrow=False)

return jointMap

if __name__ == '__main__':
jointapp.run_server(host='0.0.0.0', port=int(os.environ.get('PORT', 8050)))
61 changes: 2 additions & 59 deletions database/templates/database/home.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{% extends "database/base.html" %}
{% load static %}
{% load plotly_dash %}

{% block content %}
<br><br>
Expand Down Expand Up @@ -70,69 +71,11 @@ <h1>Virginia Solar and Storage Database</h1>
</div>
</div>
</div>
<div>{% plotly_app_bootstrap name='JointDash' aspect='1by1' %}</div>

<div class="image-holder">
<img src="{% static 'images/map-placeholder.png' %}" class="centered-img" alt="Solar screenshot">
</div>


<!--
<article class = "node node--page node--teaser card">
<div class="card__image"> <img src="{% static 'images/solar_dashboard_screenshot.png' %}" style="max-width: 425px;"></img></div>
<div class="card__title"><a href="/solar/">Solar Database and Dashboard</a></div>
</article>
<article class = "node node--page node--teaser card">
<div class="card__image"> <img src="{% static 'images/solar_dashboard_screenshot.png' %}" style="max-width: 425px;"></img></div>
<div class="card__title"><a href="/battery_storage/">Battery Energy Storage Database and Dashboard</a></div>
</article>
</div> -->
</div>
</div>




<!-- <div class="card">
<div class="card-body" style="background-color:#F2F4F8">
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 0px; width: 100%;">
<div>
{% autoescape off %}
{{ mwPieChart_div }}
{% endautoescape %}
<br>
{% autoescape off %}
{{ projectsAnnualLine_div }}
{% endautoescape %}
<br>
{% autoescape off %}
{{ mwAnnualLine_div }}
{% endautoescape %}
<br>
{% autoescape off %}
{{ sizeMWBar_div }}
{% endautoescape %}
</div>
<div>
{% autoescape off %}
{{ acrePieChart_div }}
{% endautoescape %}
<br>
{% autoescape off %}
{{ rateAnnualLine_div }}
{% endautoescape %}
<br>
{% autoescape off %}
{{ mwRegionalBar_div }}
{% endautoescape %}
<br>
{% autoescape off %}
{{ sizeProjectsBar_div }}
{% endautoescape %}
</div>
</div>

</div>
</div> -->

<br>

Expand Down
1 change: 1 addition & 0 deletions database/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from django.urls import path, include
from .plotly_dash import dashapp
from .plotly_dash_bat import dashappbat
from .joint_map import jointapp

urlpatterns = [
path('', views.home, name='database-home'),
Expand Down