Skip to content

Commit 87857cb

Browse files
authored
Merge pull request #18 from NRCan/dev
bugs and small fixes
2 parents 7860f93 + 5a0e2ce commit 87857cb

File tree

385 files changed

+1414
-187
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

385 files changed

+1414
-187
lines changed

cancurve/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#===============================================================================
22
# plugin metadata
33
#===============================================================================
4-
__version__='0.1.0'
4+
__version__='0.1.3'
55

66
#===============================================================================
77
# plugin entry point

cancurve/bldgs/assertions.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ def assert_proj_db_fp(fp, **kwargs):
6767
assert_proj_db(conn, **kwargs)
6868

6969
except Exception as e:
70-
raise AssertionError(f'project DB connection failed w/\n {e}')
70+
raise ValueError(f'project DB connection failed w/\n {e}')
7171

7272

7373

cancurve/bldgs/bldg_meta_rqmts.csv

-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
varName_core,varName_ui,varName_canflood,type,required_core,required_canflood,default_canflood,widgetName,case1,case2,case3,case4_R2,case5_crawl
22
,,tag,str,FALSE,TRUE,?,,test_case1,test_case2,heather_0509,R_2-L-BD-CU_ABCA,R_1-L-C-ST_ABCA
3-
,,location,str,FALSE,FALSE,?,,,,,,
4-
,,date,str,FALSE,FALSE,?,,,,,,
5-
,,source,str,FALSE,FALSE,?,,,,,,
63
,currency,impact_units,str,FALSE,TRUE,$CAD,currency_ComboBox,,,,,
74
,costBasis,impact_var,str,FALSE,FALSE,damage,costBasis_ComboBox,,,Depreciated Costs,,
85
,,exposure_units,str,FALSE,FALSE,m,comboBox_tab3dataInput_expoUnits,,,,,

cancurve/bldgs/cc_bldgs_dialog.ui

+93-28
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ QTabBar::tab:selected { /* Style for selected tabs */
140140
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
141141
p, li { white-space: pre-wrap; }
142142
</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:14px; font-weight:400; font-style:normal;">
143-
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:12pt;">Welcome to the CanCurve </span><span style=" font-size:12pt; font-weight:600;">Buildings Tool.</span><span style=" font-size:12pt;"> This tool is designed to create </span><span style=" font-size:12pt; font-style:italic;">Depth Damage Functions</span><span style=" font-size:12pt;"> (DDF) for Canadian buildings.</span></p>
143+
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:12pt;">Welcome to the CanCurve </span><span style=" font-size:12pt; font-weight:600;">Buildings Tool.</span><span style=" font-size:12pt;"> This tool is designed to create </span><span style=" font-size:12pt; font-style:italic;">Depth Damage Functions</span><span style=" font-size:12pt;"> (DDF) for Canadian buildings. To get started or to learn more, see the </span><a href="https://github.com/NRCan/CanCurve"><span style=" font-size:12pt; text-decoration: underline; color:#0000ff;">Documentation</span></a><span style=" font-size:12pt;">.</span></p>
144144
<p align="center" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><img src=":/plugins/cancurve/img/icon.png" /></p>
145145
<p align="center" style="-qt-paragraph-type:empty; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
146146
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:12pt;">The following inputs are required:</span></p>
@@ -149,7 +149,7 @@ p, li { white-space: pre-wrap; }
149149
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:12pt;">The following inputs are optional:</span></p>
150150
<p style=" margin-top:12px; margin-bottom:12px; margin-left:16px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:12pt; font-weight:600;">Depth Replacement-Factor (DRF) dataset</span><span style=" font-size:12pt;">: This dataset relates flood depth to the percentage loss or damage of a restoration item and is specified on the </span><span style=" font-size:12pt; font-style:italic;">Data Input</span><span style=" font-size:12pt;"> tab. By default, the DRF dataset shipped with CanCurve will be used.</span></p>
151151
<p style="-qt-paragraph-type:empty; margin-top:12px; margin-bottom:12px; margin-left:16px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:12pt;"><br /></p>
152-
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;Navigate through the tabs at the top of the window from left-to-right to create your own DDF.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
152+
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;Navigate through the tabs at the top of the window from left-to-right to create your own DDF. For help and support, see the &lt;/span&gt;&lt;a href=&quot;https://github.com/NRCan/CanCurve/issues&quot;&gt;&lt;span style=&quot; font-size:12pt; text-decoration: underline; color:#0000ff;&quot;&gt;CanCurve Project GitHub Issues Page&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
153153
</property>
154154
<property name="openExternalLinks">
155155
<bool>true</bool>
@@ -160,39 +160,98 @@ p, li { white-space: pre-wrap; }
160160
</widget>
161161
</item>
162162
<item alignment="Qt::AlignHCenter">
163-
<widget class="QGroupBox" name="groupBox_dev">
164-
<property name="styleSheet">
165-
<string notr="true">QPushButton {
166-
background-color: red;
167-
color: black;
168-
}</string>
163+
<widget class="QgsCollapsibleGroupBox" name="mGroupBox">
164+
<property name="minimumSize">
165+
<size>
166+
<width>750</width>
167+
<height>0</height>
168+
</size>
169169
</property>
170170
<property name="title">
171-
<string>!DEVELOPMENT ONLY! EASY PARAMETER LOADING OF TEST CASES</string>
171+
<string>Tutorials</string>
172+
</property>
173+
<property name="collapsed">
174+
<bool>true</bool>
172175
</property>
173-
<layout class="QHBoxLayout" name="horizontalLayout_12">
176+
<layout class="QVBoxLayout" name="verticalLayout_22">
174177
<item>
175-
<widget class="QComboBox" name="comboBox_dev">
176-
<property name="sizePolicy">
177-
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
178-
<horstretch>0</horstretch>
179-
<verstretch>0</verstretch>
180-
</sizepolicy>
178+
<widget class="QLabel" name="label_10">
179+
<property name="text">
180+
<string>Use this box to load tutorial data into the Buildings Tool. Note this will overwrite all fields.</string>
181181
</property>
182182
</widget>
183183
</item>
184184
<item>
185-
<widget class="QPushButton" name="pushButton_dev">
186-
<property name="sizePolicy">
187-
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
188-
<horstretch>0</horstretch>
189-
<verstretch>0</verstretch>
190-
</sizepolicy>
191-
</property>
192-
<property name="text">
193-
<string>Load Testing Values</string>
194-
</property>
195-
</widget>
185+
<layout class="QHBoxLayout" name="horizontalLayout_12">
186+
<item>
187+
<spacer name="horizontalSpacer_7">
188+
<property name="orientation">
189+
<enum>Qt::Horizontal</enum>
190+
</property>
191+
<property name="sizeHint" stdset="0">
192+
<size>
193+
<width>40</width>
194+
<height>20</height>
195+
</size>
196+
</property>
197+
</spacer>
198+
</item>
199+
<item>
200+
<widget class="QLabel" name="label_9">
201+
<property name="sizePolicy">
202+
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
203+
<horstretch>0</horstretch>
204+
<verstretch>0</verstretch>
205+
</sizepolicy>
206+
</property>
207+
<property name="text">
208+
<string>Name:</string>
209+
</property>
210+
</widget>
211+
</item>
212+
<item>
213+
<widget class="QComboBox" name="comboBox_dev">
214+
<property name="sizePolicy">
215+
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
216+
<horstretch>0</horstretch>
217+
<verstretch>0</verstretch>
218+
</sizepolicy>
219+
</property>
220+
<property name="minimumSize">
221+
<size>
222+
<width>100</width>
223+
<height>0</height>
224+
</size>
225+
</property>
226+
</widget>
227+
</item>
228+
<item>
229+
<widget class="QPushButton" name="pushButton_dev">
230+
<property name="sizePolicy">
231+
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
232+
<horstretch>0</horstretch>
233+
<verstretch>0</verstretch>
234+
</sizepolicy>
235+
</property>
236+
<property name="text">
237+
<string>Load</string>
238+
</property>
239+
</widget>
240+
</item>
241+
<item>
242+
<spacer name="horizontalSpacer_6">
243+
<property name="orientation">
244+
<enum>Qt::Horizontal</enum>
245+
</property>
246+
<property name="sizeHint" stdset="0">
247+
<size>
248+
<width>40</width>
249+
<height>20</height>
250+
</size>
251+
</property>
252+
</spacer>
253+
</item>
254+
</layout>
196255
</item>
197256
</layout>
198257
</widget>
@@ -908,6 +967,9 @@ QGroupBox {
908967
<layout class="QHBoxLayout" name="horizontalLayout_10">
909968
<item>
910969
<widget class="QRadioButton" name="radioButton_6">
970+
<property name="toolTip">
971+
<string>The resulting DDF will reflect the total restoration costs for the archetype as a function of depth</string>
972+
</property>
911973
<property name="text">
912974
<string>Total ($/structure)</string>
913975
</property>
@@ -918,6 +980,9 @@ QGroupBox {
918980
</item>
919981
<item>
920982
<widget class="QRadioButton" name="radioButton_tab3dataInput_rcvm2">
983+
<property name="toolTip">
984+
<string>The resulting DDF will reflect the restoration costs per area of the structure as a function of depth</string>
985+
</property>
921986
<property name="text">
922987
<string>Area-based ($/area)</string>
923988
</property>
@@ -1957,7 +2022,7 @@ QLabel {
19572022
</resources>
19582023
<connections/>
19592024
<buttongroups>
1960-
<buttongroup name="buttonGroup_costbasis"/>
19612025
<buttongroup name="buttonGroup_runControl"/>
2026+
<buttongroup name="buttonGroup_costbasis"/>
19622027
</buttongroups>
19632028
</ui>

cancurve/bldgs/core.py

+13-6
Original file line numberDiff line numberDiff line change
@@ -806,14 +806,17 @@ def c00_setup_project(
806806
bx = np.invert(ci_df.index.isin(drf_df2.index))
807807
if bx.any():
808808
"""TODO: add some support for populating missing entries into the DRF"""
809-
msg = f'DRF ({os.path.basename(drf_db_fp)}) is missing {bx.sum()}/{len(bx)} entries from the cost-items'
809+
msg = f'The specified DRF ({os.path.basename(drf_db_fp)}) is missing {bx.sum()}/{len(bx)} entries found in the Cost-Item Table. '
810810

811811
ofp1 = os.path.join(out_dir, f'missing_DRF.csv')
812812
ci_df[bx].to_csv(ofp1)
813813

814-
msg+=f'\noutput missing entries {ci_df[bx].shape} to:\n {ofp1}'
815-
816-
msg+=f'\nupdate the DRF and re-run this step before proceeding'
814+
msg+=f'For reference, the missing entries have been written to file:\n\n{ofp1}'
815+
msg+=f'\n\nTo proceed, update the DRF to provide factors for the missing cost items' + \
816+
' (or remove the entries from the Cost Items table). '+\
817+
'Typically, this is done by editing the Project Database with a third-party SQLite3 editor. '+\
818+
'Once the tables are corrected, proceed with \'Step 2\'.'
819+
817820

818821
log.warning(msg)
819822

@@ -954,9 +957,13 @@ def c01_join_drf(proj_db_fp,
954957
drf_df = pd.read_sql('SELECT * FROM c00_drf', conn, index_col=['cat', 'sel'])
955958

956959
#check
957-
bx = ~ci_df['drf_intersect'].astype(bool)
960+
bx = np.invert(ci_df.index.isin(drf_df.index))
961+
962+
#no... this flag is just for helping the user to fix the intersect
963+
#need to re-calc the intersect to allow the user to update the database
964+
#bx = ~ci_df['drf_intersect'].astype(bool)
958965
if bx.any():
959-
msg = f'missing {bx.sum()}/{len(bx)} cost-item keys in DRF... update your DRF and re-run step 1'
966+
msg = f'missing {bx.sum()}/{len(bx)} cost-item keys in DRF\n add keys to DRF or remove from cost-items'
960967
log.error(msg)
961968
raise KeyError(msg)
962969

cancurve/bldgs/plots.py

+18-5
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ def plot_c00_costitems(df_raw,
8282
#sum and pivot
8383
ser1 = ser.groupby(['group_code', 'story', 'drf_intersect']).sum() #.unstack('group_code')
8484

85-
85+
log.debug(f'groupby.sum to {len(ser1)}')
8686

8787
#===========================================================================
8888
# plot
@@ -108,10 +108,23 @@ def plot_c00_costitems(df_raw,
108108

109109

110110
#create two axijs side by side
111-
stories_l = ser1.index.unique('story').to_list()
112-
ax_d = dict(zip(stories_l, figure.subplots(nrows=1, ncols=len(stories_l), sharey=True)))
111+
story_l = ser1.index.unique('story').to_list()
112+
log.debug(f'on storys: {story_l}')
113+
114+
# Create subplots based on the number of stories
115+
if len(story_l) == 1:
116+
# When there's only one story, subplots returns a single Axes object
117+
ax_d = {story_l[0]: figure.subplots(nrows=1, ncols=1, sharey=True)}
118+
else:
119+
# When there are multiple stories, subplots returns a list of Axes
120+
ax_list = figure.subplots(nrows=1, ncols=len(story_l), sharey=True)
121+
# Ensure ax_list is iterable, even if it contains just one element
122+
ax_d = dict(zip(story_l, ax_list))
123+
124+
113125
ymax = max(ser1.groupby('story').sum())
114126

127+
log.debug(f'plotting on {len(ax_d)}')
115128
for k0, ax in ax_d.items():
116129
gser = ser1.xs(k0, level='story')
117130

@@ -165,7 +178,7 @@ def plot_c00_costitems(df_raw,
165178
ha=next(ha_l), va='bottom',
166179
arrowprops=dict(arrowstyle="->", connectionstyle="arc3"))
167180
else:
168-
ax.bar_label(container, labels = [f'{group_name} {100*(val/gser.sum()):.0f}% ({val:,.0f})'], label_type='center')
181+
ax.bar_label(container, labels = [f'{group_name}: {100*(val/gser.sum()):.0f}% ({val:,.0f})'], label_type='center')
169182

170183

171184

@@ -197,7 +210,7 @@ def plot_c00_costitems(df_raw,
197210
#ax.set_xlabel(f'story \'{k0}\'')
198211

199212
#left-most
200-
if k0==stories_l[0]:
213+
if k0==story_l[0]:
201214
ax.yaxis.set_major_formatter(plt.matplotlib.ticker.StrMethodFormatter('{x:,.0f}'))
202215
ax.set_ylabel('Replacement Cost (Sum)')
203216

docs/source/03_tutorials.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ This tutorial will demonstrate how to create a :ref:`CanFlood format DDF <sec02-
1616
Step 1: Download the example Cost-Item Table
1717
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1818

19-
From the project repository, download the `example Cost-Item Table <https://github.com/NRCan/CanCurve/blob/main/tutorial/case1/R_1-L-BD-CU_ABCA.csv>`_ somewhere easy to find.
19+
From the project repository, download the `example Cost-Item Table <https://github.com/NRCan/CanCurve/blob/main/tutorial/01/R_1-L-BD-CU_ABCA.csv>`_ somewhere easy to find.
2020

2121
Step 2: Enter Metadata
2222
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

tests/bldgs/conftest.py

+23-27
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,16 @@
2020
from tests.data.bldgs_data_scripts import fixed_costs_master_d, test_data_dir_master#, bldg_meta_rqmt_df_test
2121

2222

23+
#these cases are setup for unit tests
24+
#end-to-end test cases are in bldgs_data_scripts.test_cases_l
25+
cases_l = [
26+
'case1',
27+
'case2',
28+
'case3',
29+
'AB-Calgary_R_1-L-C-ST_ABCA'
30+
]
31+
32+
2333
#===============================================================================
2434
# fixtrues--------
2535
#===============================================================================
@@ -33,7 +43,8 @@ def proj_db_fp(testCase, testPhase, tmp_path):
3343

3444
#get the target directory
3545
tdata_dir = os.path.join(test_data_dir_master, testCase, testPhase)
36-
assert os.path.exists(tdata_dir), tdata_dir
46+
if not os.path.exists(tdata_dir):
47+
raise FileNotFoundError(tdata_dir)
3748

3849
#get the project db file
3950
fp = find_single_file_by_extension(tdata_dir, '.cancurve')
@@ -51,6 +62,15 @@ def ci_fp(testCase):
5162

5263
@pytest.fixture(scope='function')
5364
def fixed_costs_d(testCase):
65+
"""retrieve fixed_costs_d from master
66+
67+
normally, fixed_costs_master_d is hard-coded and kept in
68+
bldgs.dialog_test_scripts.fixed_costs_master_d
69+
70+
However, this can also be updated using pickels by calling
71+
tests.data.bldgs_data_scripts.load_tests_cases_from_file()
72+
"""
73+
5474
if not testCase in fixed_costs_master_d:
5575
raise AssertionError(f'test case \'{testCase}\' missing from fixed_costs_master_d')
5676
return fixed_costs_master_d[testCase]
@@ -66,29 +86,5 @@ def bldg_meta_d(testCase):
6686
d = _get_bldg_meta_d(testCase, df=bldg_meta_rqmt_df_test)
6787
return d
6888

69-
#===============================================================================
70-
# @pytest.fixture(scope='function')
71-
# def bldg_meta_d_ui(testCase):
72-
# """full set of parameters for the UI"""
73-
#
74-
# if testCase=='case1':
75-
# #just take first from parameters
76-
# d = {k:v[0] for k,v in building_details_options_d.items()}
77-
#
78-
# elif testCase=='case2':
79-
#
80-
# #random choice
81-
# d = {k: random.choice(v) for k, v in building_details_options_d.items()}
82-
#
83-
# """
84-
# for k,v in d.items():
85-
# print(f'{k}\n {v} ({type(v)})')
86-
# """
87-
# return d
88-
#
89-
#
90-
# @pytest.fixture(scope='function')
91-
# def bldg_meta_d_strict(testCase):
92-
# """strict building meta parameters needed by core"""
93-
# return {'basement_height_m':1.8, 'scale_value_m2':232.0, 'bldg_layout':'default'}
94-
#===============================================================================
89+
90+

0 commit comments

Comments
 (0)