From 9d7d55ecff08fe21560f44635c83a2469a3efe21 Mon Sep 17 00:00:00 2001 From: Adam Erispaha Date: Wed, 18 Dec 2024 21:01:54 -0500 Subject: [PATCH] improvements to docstrings and doctests --- swmmio/core.py | 33 ++++++++++++++++++++----- swmmio/defs/sectionheaders.py | 4 ---- swmmio/reporting/serialize.py | 2 +- swmmio/utils/functions.py | 45 +++++++++++++++++++++++++++++++++-- swmmio/utils/spatial.py | 10 ++++---- 5 files changed, 75 insertions(+), 19 deletions(-) diff --git a/swmmio/core.py b/swmmio/core.py index 3dd4fe3..1a744c1 100644 --- a/swmmio/core.py +++ b/swmmio/core.py @@ -31,7 +31,7 @@ class Model(object): Class representing a complete SWMM model incorporating its INP and RPT files and data - initialize a swmmio.Model object by pointing it to a directory containing + Initialize a swmmio.Model object by pointing it to a directory containing a single INP (and optionally an RPT file with matching filename) or by pointing it directly to an .inp file. @@ -209,7 +209,7 @@ def rpt_warnings(self, verbose=False): warnings = 'RPT file is not valid' return warnings - + @property def conduits(self): """ collect all useful and available data related model conduits and @@ -380,8 +380,17 @@ def nodes(self, bbox=None): @property def subcatchments(self): """ - collect all useful and available data related subcatchments and organize - in one dataframe. + Retrieve and organize data related to subcatchments into ModelSection object + which provides pandas.DataFrame and GeoPandas.GeoDataFrame accessors. + + Returns + ------- + swmmio.elements.ModelSection + + Examples + -------- + >>> from swmmio.examples import jersey + >>> jersey.subcatchments.dataframe # doctest: +SKIP """ if self._subcatchments_df is not None: return self._subcatchments_df @@ -413,7 +422,8 @@ def to_crs(self, *args, **kwargs): :param target_crs: coordinate reference system to reproject :return: True - >>> import swmmio + Examples + -------- >>> m = swmmio.Model(MODEL_FULL_FEATURES_XY, crs="EPSG:2272") >>> m.to_crs("EPSG:4326") # convert to WGS84 web mercator >>> m.inp.coordinates.round(5) #doctest: +NORMALIZE_WHITESPACE @@ -485,7 +495,18 @@ def export_to_shapefile(self, shpdir, prj=None): spatial.write_shapefile(nodes, nodes_path, geomtype='point', prj=prj) @property - def summary(self): + def summary(self) -> dict: + """ + Summary statistics of the SWMM model. + + Returns + ------- + dict + + See Also + -------- + swmmio.utils.functions.summarize_model + """ if self._summary is None: model_summary = functions.summarize_model(self) self._summary = model_summary diff --git a/swmmio/defs/sectionheaders.py b/swmmio/defs/sectionheaders.py index 10dd3da..86277d9 100644 --- a/swmmio/defs/sectionheaders.py +++ b/swmmio/defs/sectionheaders.py @@ -9,9 +9,6 @@ def parse_inp_section_config(raw_conf): normalize the config information in the YAML :return: >>> from swmmio.defs import INP_OBJECTS - >>> conds_config = INP_OBJECTS['CONDUITS'] - >>> parse_inp_section_config(conds_config) - OrderedDict([('columns', ['Name', 'InletNode', 'OutletNode', 'Length', 'ManningN', 'InOffset', 'OutOffset', 'InitFlow', 'MaxFlow'])]) >>> parse_inp_section_config(INP_OBJECTS['LOSSES']) OrderedDict([('columns', ['Link', 'Inlet', 'Outlet', 'Average', 'Flap Gate', 'SeepageRate'])]) """ @@ -40,7 +37,6 @@ def normalize_inp_config(inp_obects): >>> from swmmio.defs import INP_OBJECTS >>> conf = normalize_inp_config(INP_OBJECTS) >>> print(conf['JUNCTIONS']) - >>> print(conf) OrderedDict([('columns', ['Name', 'InvertElev', 'MaxDepth', 'InitDepth', 'SurchargeDepth', 'PondedArea'])]) """ normalized = OrderedDict() diff --git a/swmmio/reporting/serialize.py b/swmmio/reporting/serialize.py index 43220c0..8200c4b 100644 --- a/swmmio/reporting/serialize.py +++ b/swmmio/reporting/serialize.py @@ -1,7 +1,7 @@ # READ/WRITE REPORTS AS JSON import json import pandas as pd -from pandas.io.json import json_normalize +from pandas import json_normalize from swmmio.utils import spatial from swmmio.graphics import swmm_graphics as sg diff --git a/swmmio/utils/functions.py b/swmmio/utils/functions.py index 17b1c81..74552dc 100644 --- a/swmmio/utils/functions.py +++ b/swmmio/utils/functions.py @@ -126,7 +126,25 @@ def trim_section_to_nodes(inp, node_ids=None, node_type='junctions', drop=True): def rotate_model(m, rads=0.5, origin=None): """ - rotate a model (its coordinates) + Rotate a model's coordinates by a specified angle around a given origin. + + Parameters + ---------- + m : swmmio.Model + The model whose coordinates are to be rotated. + rads : float, optional + The angle in radians by which to rotate the model. Default is 0.5 radians. + origin : tuple of float, optional + The (x, y) coordinates of the point around which to rotate the model. + If not provided, the origin defaults to (0, 0). + + Returns + ------- + swmmio.Model + The model with its coordinates rotated. + + Examples + -------- >>> from swmmio.tests.data import MODEL_FULL_FEATURES_XY_B >>> import swmmio >>> mb = swmmio.Model(MODEL_FULL_FEATURES_XY_B) @@ -281,7 +299,30 @@ def find_network_trace(model, start_node, end_node, return path_selection -def summarize_model(model): +def summarize_model(model) -> dict: + """ + Summarize a SWMM model by calculating various statistics and counts of elements. + + Parameters + ---------- + model : swmmio.core.Model + An instance of a SWMM model containing input data (inp) and nodes. + + Returns + ------- + dict + A dictionary containing the summary of the model with the following keys: + + - 'num_subcatchments': int, number of subcatchments in the model. + - 'num_conduits': int, number of conduits in the model. + - 'num_junctions': int, number of junctions in the model. + - 'num_outfalls': int, number of outfalls in the model. + - 'num_raingages': int, number of raingages in the model. + - 'catchment_area': float, total area of subcatchments (if subcatchments exist). + - 'mean_subcatchment_slope': float, mean slope of subcatchments weighted by area (if subcatchments exist). + - 'total_conduit_length': float, total length of conduits (if conduits exist). + - 'invert_range': float, range of invert elevations of nodes (if nodes exist). + """ model_summary = dict() # numbers of elements diff --git a/swmmio/utils/spatial.py b/swmmio/utils/spatial.py index ea3ef8e..21a0bfb 100644 --- a/swmmio/utils/spatial.py +++ b/swmmio/utils/spatial.py @@ -26,12 +26,10 @@ def change_crs(series, in_crs, to_crs): Examples -------- - >>> import swmmio - >>> m = swmmio.Model(MODEL_FULL_FEATURES_XY) + >>> from swmmio.examples import jersey >>> proj4_str = '+proj=tmerc +lat_0=36.16666666666666 +lon_0=-94.5 +k=0.9999411764705882 +x_0=850000 +y_0=0 +datum=NAD83 +units=us-ft +no_defs' - >>> m.crs = proj4_str - >>> nodes = m.nodes() - >>> change_crs(nodes['coords'], proj4_str, "EPSG:4326") + >>> jersey.crs = proj4_str + >>> change_crs(jersey.nodes.dataframe['coords'], proj4_str, "EPSG:4326") Name J3 [(39.236286854940964, -94.64346373821752)] 1 [(39.23851590020802, -94.64756446847099)] @@ -109,7 +107,7 @@ def coords_series_to_geometry(coords, geomtype='linestring', dtype='geojson'): -------- >>> import swmmio >>> model = swmmio.Model(MODEL_FULL_FEATURES_XY) - >>> nodes = model.nodes() + >>> nodes = model.nodes.dataframe >>> geoms = coords_series_to_geometry(nodes['coords'], geomtype='point') >>> geoms.iloc[0] {"coordinates": [2748073.3060000003, 1117746.087], "type": "Point"}