Tampa Bay, FL - Simple workflow

Standardize, clean and wrangle Water Quality Portal data in Tampa Bay, FL into more analytic-ready formats using the harmonize_wq package

US EPA’s Water Quality Portal (WQP) aggregates water quality, biological, and physical data provided by many organizations and has become an essential resource with tools to query and retrieval data using python or R. Given the variety of data and variety of data originators, using the data in analysis often requires data cleaning to ensure it meets the required quality standards and data wrangling to get it in a more analytic-ready format. Recognizing the definition of analysis-ready varies depending on the analysis, the harmonixe_wq package is intended to be a flexible water quality specific framework to help:

  • Identify differences in data units (including speciation and basis)

  • Identify differences in sampling or analytic methods

  • Resolve data errors using transparent assumptions

  • Reduce data to the columns that are most commonly needed

  • Transform data from long to wide format

Domain experts must decide what data meets their quality standards for data comparability and any thresholds for acceptance or rejection.

Simple workflow

This example steps through a typical workflow in Tampa Bay, FL to demonstrate commonly used functionality

Install the required libraries

[1]:
import sys
#!python -m pip uninstall harmonize-wq --yes
# Use pip to install the package from pypi or the latest from github
#!{sys.executable} -m pip install harmonize-wq
# For latest dev version
#!{sys.executable} -m pip install git+https://github.com/USEPA/harmonize-wq.git@new_release_0-3-8

Create dataretrieval query using a polygon for Area Of Interest

[2]:
from harmonize_wq import wrangle
[3]:
# Read geometry for Area of Interest from geojson file url
# NOTE: alternatively you can direct it to a local shapefile
aoi_url = r'https://github.com/USEPA/Coastal_Ecological_Indicators/raw/master/DGGS_Coastal/temperature_data/TampaBay.geojson'
[4]:
# Map aoi
aoi_gdf = wrangle.as_gdf(aoi_url)
# geoJSON should be WGS1984 standard, but this one isn't
aoi_gdf.to_crs(4326, inplace=True)
aoi_gdf.plot()
[4]:
<Axes: >
../_images/notebooks_Harmonize_Tampa_Simple_10_1.png
[5]:
# Build query
query = {'characteristicName': ['Phosphorus',
                                'Temperature, water',
                                'Depth, Secchi disk depth',
                                'Dissolved oxygen (DO)',
                                'Salinity',
                                'pH',
                                'Nitrogen',
                                'Conductivity',
                                'Organic carbon',
                                'Chlorophyll a',
                                'Turbidity',
                                'Sediment',
                                'Fecal Coliform',
                                'Escherichia coli']}
query['bBox'] = wrangle.get_bounding_box(aoi_gdf)
query['dataProfile'] = 'narrowResult'

Retrieve data

Stations will be retrieved using the query criteria seperately after results. md_narrow is metadata documenting the query not used here but meant for reproducibility

[6]:
import dataretrieval.wqp as wqp
[7]:
# Query for results
# Note: large quieries like this can take up a lot of RAM and may give a DtypeWarning,
# set low_memory=False or provide dataTypes for columns to use less memory.
res_narrow, md_narrow = wqp.get_results(**query)
[8]:
# Look at initial results (input)
df = res_narrow
df
[8]:
OrganizationIdentifier OrganizationFormalName ActivityIdentifier ActivityStartDate ActivityStartTime/Time ActivityStartTime/TimeZoneCode MonitoringLocationIdentifier ResultIdentifier DataLoggerLine ResultDetectionConditionText ... ResultDetectionQuantitationLimitUrl LaboratoryAccreditationIndicator LaboratoryAccreditationAuthorityName TaxonomistAccreditationIndicator TaxonomistAccreditationAuthorityName LabSamplePreparationUrl ProviderName ActivityStartDateTime AnalysisStartDateTime AnalysisEndDateTime
0 USGS-FL USGS Florida Water Science Center nwisfl.01.94202446 1942-04-14 12:00:00 EDT USGS-275840082305601 NWIS-6769611 NaN NaN ... NaN NaN NaN NaN NaN NaN NWIS 1942-04-14 16:00:00+00:00 NaT NaT
1 USGS-FL USGS Florida Water Science Center nwisfl.01.94202447 1942-05-05 12:00:00 EDT USGS-275850082310101 NWIS-6769631 NaN NaN ... NaN NaN NaN NaN NaN NaN NWIS 1942-05-05 16:00:00+00:00 NaT NaT
2 USGS-FL USGS Florida Water Science Center nwisfl.01.94202445 1942-05-13 12:00:00 EDT USGS-275835082313501 NWIS-6769593 NaN NaN ... NaN NaN NaN NaN NaN NaN NWIS 1942-05-13 16:00:00+00:00 NaT NaT
3 USGS-FL USGS Florida Water Science Center nwisfl.01.94202444 1942-05-13 12:00:00 EDT USGS-275826082312901 NWIS-6769579 NaN NaN ... NaN NaN NaN NaN NaN NaN NWIS 1942-05-13 16:00:00+00:00 NaT NaT
4 USGS-FL USGS Florida Water Science Center nwisfl.01.94202443 1942-05-13 12:00:00 EDT USGS-275823082312101 NWIS-6769559 NaN NaN ... NaN NaN NaN NaN NaN NaN NWIS 1942-05-13 16:00:00+00:00 NaT NaT
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
1537974 USGS-FL USGS Florida Water Science Center nwisfl.01.95500739 1955-03-25 NaN NaN USGS-273236082335801 NWIS-6842169 NaN NaN ... NaN NaN NaN NaN NaN NaN NWIS NaT NaT NaT
1537975 USGS-FL USGS Florida Water Science Center nwisfl.01.95500762 1955-04-08 NaN NaN USGS-273926082304501 NWIS-6842541 NaN NaN ... NaN NaN NaN NaN NaN NaN NWIS NaT NaT NaT
1537976 USGS-FL USGS Florida Water Science Center nwisfl.01.95500762 1955-04-08 NaN NaN USGS-273926082304501 NWIS-6842544 NaN NaN ... NaN NaN NaN NaN NaN NaN NWIS NaT NaT NaT
1537977 USGS-FL USGS Florida Water Science Center nwisfl.01.95500782 1955-04-08 NaN NaN USGS-274455082253601 NWIS-6842941 NaN NaN ... NaN NaN NaN NaN NaN NaN NWIS NaT NaT NaT
1537978 USGS-FL USGS Florida Water Science Center nwisfl.01.95500782 1955-04-08 NaN NaN USGS-274455082253601 NWIS-6842944 NaN NaN ... NaN NaN NaN NaN NaN NaN NWIS NaT NaT NaT

1537979 rows × 81 columns

Harmonize data using defaults

[9]:
from harmonize_wq import harmonize
from harmonize_wq import location
from harmonize_wq import visualize
[10]:
# Harmonize it and look at how it changed (output)
# Note: 'ignore' unit dimensionality errors will warn when they are encountered and replace with NaN
# Note: depending on the Pint version this may cause a UnitStrippedWarning
df_harmonized = harmonize.harmonize_all(df, errors='ignore')
df_harmonized
/opt/hostedtoolcache/Python/3.9.25/x64/lib/python3.9/site-packages/harmonize_wq/wq_data.py:158: FutureWarning: unique with argument that is not not a Series, Index, ExtensionArray, or np.ndarray is deprecated and will raise in a future version.
  for bad_meas in pandas.unique(bad_measures):
/opt/hostedtoolcache/Python/3.9.25/x64/lib/python3.9/site-packages/harmonize_wq/clean.py:360: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value 'ResultMeasureValue: missing (NaN) result' has dtype incompatible with float64, please explicitly cast to a compatible dtype first.
  df_out.loc[mask & (df_out["QA_flag"].isna()), "QA_flag"] = flag
/opt/hostedtoolcache/Python/3.9.25/x64/lib/python3.9/site-packages/harmonize_wq/wq_data.py:663: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value '[<Quantity(0.001, 'milligram / liter')>
 <Quantity(0.0014, 'milligram / liter')>
 <Quantity(0.0002, 'milligram / liter')> ...
 <Quantity(0.004, 'milligram / liter')>
 <Quantity(0.005, 'milligram / liter')>
 <Quantity(0.006, 'milligram / liter')>]' has dtype incompatible with float64, please explicitly cast to a compatible dtype first.
  df_out.loc[m_mask, self.out_col] = convert_unit_series(**params)
/opt/hostedtoolcache/Python/3.9.25/x64/lib/python3.9/site-packages/harmonize_wq/wq_data.py:158: FutureWarning: unique with argument that is not not a Series, Index, ExtensionArray, or np.ndarray is deprecated and will raise in a future version.
  for bad_meas in pandas.unique(bad_measures):
/opt/hostedtoolcache/Python/3.9.25/x64/lib/python3.9/site-packages/harmonize_wq/wq_data.py:663: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value '[<Quantity(626.0, 'microsiemens / centimeter')>
 <Quantity(688.0, 'microsiemens / centimeter')>
 <Quantity(606.0, 'microsiemens / centimeter')>
 <Quantity(606.0, 'microsiemens / centimeter')>
 <Quantity(633.0, 'microsiemens / centimeter')>
 <Quantity(776.0, 'microsiemens / centimeter')>
 <Quantity(776.0, 'microsiemens / centimeter')>
 <Quantity(775.0, 'microsiemens / centimeter')>
 <Quantity(776.0, 'microsiemens / centimeter')>
 <Quantity(775.0, 'microsiemens / centimeter')>
 <Quantity(20500.0, 'microsiemens / centimeter')>]' has dtype incompatible with float64, please explicitly cast to a compatible dtype first.
  df_out.loc[m_mask, self.out_col] = convert_unit_series(**params)
/opt/hostedtoolcache/Python/3.9.25/x64/lib/python3.9/site-packages/harmonize_wq/wq_data.py:158: FutureWarning: unique with argument that is not not a Series, Index, ExtensionArray, or np.ndarray is deprecated and will raise in a future version.
  for bad_meas in pandas.unique(bad_measures):
/opt/hostedtoolcache/Python/3.9.25/x64/lib/python3.9/site-packages/harmonize_wq/wq_data.py:663: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value '[<Quantity(0.9144, 'meter')> <Quantity(1.524, 'meter')>
 <Quantity(0.9144, 'meter')> ... <Quantity(0.254, 'meter')>
 <Quantity(0.254, 'meter')> <Quantity(0.254, 'meter')>]' has dtype incompatible with float64, please explicitly cast to a compatible dtype first.
  df_out.loc[m_mask, self.out_col] = convert_unit_series(**params)
/opt/hostedtoolcache/Python/3.9.25/x64/lib/python3.9/site-packages/harmonize_wq/wq_data.py:158: FutureWarning: unique with argument that is not not a Series, Index, ExtensionArray, or np.ndarray is deprecated and will raise in a future version.
  for bad_meas in pandas.unique(bad_measures):
/opt/hostedtoolcache/Python/3.9.25/x64/lib/python3.9/site-packages/harmonize_wq/wq_data.py:663: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value '[<Quantity(8.3, 'milligram / liter')> <Quantity(7.3, 'milligram / liter')>
 <Quantity(6.9, 'milligram / liter')> ...
 <Quantity(6.8, 'milligram / liter')> <Quantity(8.0, 'milligram / liter')>
 <Quantity(6.8, 'milligram / liter')>]' has dtype incompatible with float64, please explicitly cast to a compatible dtype first.
  df_out.loc[m_mask, self.out_col] = convert_unit_series(**params)
/opt/hostedtoolcache/Python/3.9.25/x64/lib/python3.9/site-packages/harmonize_wq/wq_data.py:158: FutureWarning: unique with argument that is not not a Series, Index, ExtensionArray, or np.ndarray is deprecated and will raise in a future version.
  for bad_meas in pandas.unique(bad_measures):
/opt/hostedtoolcache/Python/3.9.25/x64/lib/python3.9/site-packages/harmonize_wq/convert.py:128: UserWarning: WARNING: 'MPN/100mL' converted to NaN
  warn(f"WARNING: '{unit}' converted to NaN")
/opt/hostedtoolcache/Python/3.9.25/x64/lib/python3.9/site-packages/harmonize_wq/convert.py:128: UserWarning: WARNING: 'cfu/100mL' converted to NaN
  warn(f"WARNING: '{unit}' converted to NaN")
/opt/hostedtoolcache/Python/3.9.25/x64/lib/python3.9/site-packages/harmonize_wq/convert.py:128: UserWarning: WARNING: 'CFU/100mL' converted to NaN
  warn(f"WARNING: '{unit}' converted to NaN")
/opt/hostedtoolcache/Python/3.9.25/x64/lib/python3.9/site-packages/harmonize_wq/wq_data.py:663: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value '[nan nan nan ... nan nan nan]' has dtype incompatible with float64, please explicitly cast to a compatible dtype first.
  df_out.loc[m_mask, self.out_col] = convert_unit_series(**params)
/opt/hostedtoolcache/Python/3.9.25/x64/lib/python3.9/site-packages/harmonize_wq/wq_data.py:158: FutureWarning: unique with argument that is not not a Series, Index, ExtensionArray, or np.ndarray is deprecated and will raise in a future version.
  for bad_meas in pandas.unique(bad_measures):
/opt/hostedtoolcache/Python/3.9.25/x64/lib/python3.9/site-packages/harmonize_wq/convert.py:128: UserWarning: WARNING: 'MPN/100mL' converted to NaN
  warn(f"WARNING: '{unit}' converted to NaN")
/opt/hostedtoolcache/Python/3.9.25/x64/lib/python3.9/site-packages/harmonize_wq/convert.py:128: UserWarning: WARNING: 'cfu/100mL' converted to NaN
  warn(f"WARNING: '{unit}' converted to NaN")
/opt/hostedtoolcache/Python/3.9.25/x64/lib/python3.9/site-packages/harmonize_wq/convert.py:128: UserWarning: WARNING: 'CFU/100mL' converted to NaN
  warn(f"WARNING: '{unit}' converted to NaN")
/opt/hostedtoolcache/Python/3.9.25/x64/lib/python3.9/site-packages/harmonize_wq/wq_data.py:663: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value '[<Quantity(0.0, 'Colony_Forming_Units / milliliter')>
 <Quantity(0.0, 'Colony_Forming_Units / milliliter')>
 <Quantity(0.0, 'Colony_Forming_Units / milliliter')> ...
 <Quantity(3500.0, 'Colony_Forming_Units / milliliter')>
 <Quantity(2.0, 'Colony_Forming_Units / milliliter')>
 <Quantity(2.0, 'Colony_Forming_Units / milliliter')>]' has dtype incompatible with float64, please explicitly cast to a compatible dtype first.
  df_out.loc[m_mask, self.out_col] = convert_unit_series(**params)
/opt/hostedtoolcache/Python/3.9.25/x64/lib/python3.9/site-packages/harmonize_wq/wq_data.py:158: FutureWarning: unique with argument that is not not a Series, Index, ExtensionArray, or np.ndarray is deprecated and will raise in a future version.
  for bad_meas in pandas.unique(bad_measures):
/opt/hostedtoolcache/Python/3.9.25/x64/lib/python3.9/site-packages/harmonize_wq/basis.py:343: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value 'as N' has dtype incompatible with float64, please explicitly cast to a compatible dtype first.
  df_out.loc[mask, basis_col] = basis
/opt/hostedtoolcache/Python/3.9.25/x64/lib/python3.9/site-packages/harmonize_wq/wq_data.py:484: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value '[nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan
 nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan
 nan nan nan nan nan nan nan nan nan 'as N' 'as N' 'as N' 'as N' 'as N'
 'as N' 'as N' 'as N' nan nan nan nan nan nan nan nan nan nan nan nan nan
 nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan
 nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan
 nan nan nan nan nan nan nan 'as N' nan nan nan 'as N' nan nan nan nan nan
 nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan
 'as N' nan 'as N' nan nan nan nan nan nan nan nan nan nan nan nan nan nan
 nan nan nan 'as N' nan nan nan nan 'as N' nan 'as N' 'as N']' has dtype incompatible with float64, please explicitly cast to a compatible dtype first.
  self.df[c_mask] = basis.basis_from_method_spec(self.df[c_mask])
/opt/hostedtoolcache/Python/3.9.25/x64/lib/python3.9/site-packages/harmonize_wq/wq_data.py:663: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value '[<Quantity(0.073, 'milligram / liter')>
 <Quantity(0.036, 'milligram / liter')>
 <Quantity(0.124, 'milligram / liter')>
 <Quantity(0.144, 'milligram / liter')>
 <Quantity(0.191, 'milligram / liter')>
 <Quantity(0.606, 'milligram / liter')>
 <Quantity(0.105, 'milligram / liter')>
 <Quantity(0.183, 'milligram / liter')>
 <Quantity(0.056, 'milligram / liter')>
 <Quantity(0.063, 'milligram / liter')>
 <Quantity(0.031, 'milligram / liter')>
 <Quantity(0.024, 'milligram / liter')>
 <Quantity(0.056, 'milligram / liter')>
 <Quantity(0.069, 'milligram / liter')>
 <Quantity(0.08, 'milligram / liter')>
 <Quantity(0.084, 'milligram / liter')>
 <Quantity(0.094, 'milligram / liter')>
 <Quantity(0.101, 'milligram / liter')>
 <Quantity(0.061, 'milligram / liter')>
 <Quantity(0.042, 'milligram / liter')>
 <Quantity(0.024, 'milligram / liter')>
 <Quantity(0.054, 'milligram / liter')>
 <Quantity(0.077, 'milligram / liter')>
 <Quantity(0.038, 'milligram / liter')>
 <Quantity(0.029, 'milligram / liter')>
 <Quantity(0.156, 'milligram / liter')>
 <Quantity(0.066, 'milligram / liter')>
 <Quantity(18.0, 'milligram / liter')>
 <Quantity(19.7, 'milligram / liter')>
 <Quantity(15.3, 'milligram / liter')>
 <Quantity(16.7, 'milligram / liter')>
 <Quantity(19.5, 'milligram / liter')>
 <Quantity(15.7, 'milligram / liter')>
 <Quantity(22.5, 'milligram / liter')>
 <Quantity(18.0, 'milligram / liter')>
 <Quantity(21.3, 'milligram / liter')>
 <Quantity(17.6, 'milligram / liter')>
 <Quantity(15.7, 'milligram / liter')>
 <Quantity(0.166, 'milligram / liter')>
 <Quantity(0.091, 'milligram / liter')>
 <Quantity(0.084, 'milligram / liter')>
 <Quantity(0.057, 'milligram / liter')>
 <Quantity(0.03, 'milligram / liter')>
 <Quantity(0.39, 'milligram / liter')>
 <Quantity(0.4475, 'milligram / liter')>
 <Quantity(0.425, 'milligram / liter')>
 <Quantity(0.4625, 'milligram / liter')>
 <Quantity(0.33625, 'milligram / liter')>
 <Quantity(0.28, 'milligram / liter')>
 <Quantity(0.5625, 'milligram / liter')>
 <Quantity(0.21875, 'milligram / liter')>
 <Quantity(0.629, 'milligram / liter')>
 <Quantity(0.505, 'milligram / liter')>
 <Quantity(0.253, 'milligram / liter')>
 <Quantity(0.325, 'milligram / liter')>
 <Quantity(0.253, 'milligram / liter')>
 <Quantity(0.456, 'milligram / liter')>
 <Quantity(0.183, 'milligram / liter')>
 <Quantity(0.526, 'milligram / liter')>
 <Quantity(0.264, 'milligram / liter')>
 <Quantity(0.188, 'milligram / liter')>
 <Quantity(0.346, 'milligram / liter')>
 <Quantity(0.641, 'milligram / liter')>
 <Quantity(0.392, 'milligram / liter')>
 <Quantity(0.444, 'milligram / liter')>
 <Quantity(0.274, 'milligram / liter')>
 <Quantity(0.284, 'milligram / liter')>
 <Quantity(0.321, 'milligram / liter')>
 <Quantity(0.343, 'milligram / liter')>
 <Quantity(0.384, 'milligram / liter')>
 <Quantity(0.295, 'milligram / liter')>
 <Quantity(0.20244, 'milligram / liter')>
 <Quantity(0.42266, 'milligram / liter')>
 <Quantity(0.2191, 'milligram / liter')>
 <Quantity(0.43078, 'milligram / liter')>
 <Quantity(0.19796, 'milligram / liter')>
 <Quantity(0.95186, 'milligram / liter')>
 <Quantity(0.329, 'milligram / liter')>
 <Quantity(0.20986, 'milligram / liter')>
 <Quantity(0.31556, 'milligram / liter')>
 <Quantity(0.35686, 'milligram / liter')>
 <Quantity(0.3409, 'milligram / liter')>
 <Quantity(0.2919, 'milligram / liter')>
 <Quantity(0.60508, 'milligram / liter')>
 <Quantity(0.25802, 'milligram / liter')>
 <Quantity(0.32074, 'milligram / liter')>
 <Quantity(0.64302, 'milligram / liter')>
 <Quantity(0.6727, 'milligram / liter')>
 <Quantity(0.5376, 'milligram / liter')>
 <Quantity(0.54488, 'milligram / liter')>
 <Quantity(0.3353, 'milligram / liter')>
 <Quantity(0.68194, 'milligram / liter')>
 <Quantity(0.391, 'milligram / liter')>
 <Quantity(0.50134, 'milligram / liter')>
 <Quantity(0.205, 'milligram / liter')>
 <Quantity(0.57512, 'milligram / liter')>
 <Quantity(0.278, 'milligram / liter')>
 <Quantity(0.26, 'milligram / liter')>
 <Quantity(0.416, 'milligram / liter')>
 <Quantity(0.451, 'milligram / liter')>
 <Quantity(0.2163, 'milligram / liter')>
 <Quantity(0.165, 'milligram / liter')>
 <Quantity(0.526, 'milligram / liter')>
 <Quantity(0.308, 'milligram / liter')>
 <Quantity(0.234, 'milligram / liter')>
 <Quantity(0.301, 'milligram / liter')>
 <Quantity(0.219, 'milligram / liter')>
 <Quantity(1.4, 'milligram / liter')>
 <Quantity(0.253, 'milligram / liter')>
 <Quantity(0.238, 'milligram / liter')>
 <Quantity(0.271, 'milligram / liter')>
 <Quantity(1.59, 'milligram / liter')>
 <Quantity(0.224, 'milligram / liter')>
 <Quantity(0.225, 'milligram / liter')>
 <Quantity(0.203, 'milligram / liter')>
 <Quantity(0.463, 'milligram / liter')>
 <Quantity(0.165, 'milligram / liter')>
 <Quantity(0.36, 'milligram / liter')>
 <Quantity(0.80493, 'milligram / liter')>
 <Quantity(0.523, 'milligram / liter')>
 <Quantity(0.233, 'milligram / liter')>
 <Quantity(0.402, 'milligram / liter')>
 <Quantity(0.378, 'milligram / liter')>
 <Quantity(0.412, 'milligram / liter')>
 <Quantity(0.499, 'milligram / liter')>
 <Quantity(0.49267, 'milligram / liter')>
 <Quantity(0.181, 'milligram / liter')>
 <Quantity(0.519, 'milligram / liter')>
 <Quantity(0.141, 'milligram / liter')>
 <Quantity(0.497, 'milligram / liter')>
 <Quantity(0.546, 'milligram / liter')>
 <Quantity(0.208, 'milligram / liter')>
 <Quantity(0.55243, 'milligram / liter')>
 <Quantity(0.253, 'milligram / liter')>
 <Quantity(1.02, 'milligram / liter')>
 <Quantity(0.418, 'milligram / liter')>
 <Quantity(2.7, 'milligram / liter')>
 <Quantity(0.404, 'milligram / liter')>
 <Quantity(0.178, 'milligram / liter')>
 <Quantity(0.437, 'milligram / liter')>
 <Quantity(0.333, 'milligram / liter')>
 <Quantity(0.208, 'milligram / liter')>
 <Quantity(0.344, 'milligram / liter')>
 <Quantity(0.275, 'milligram / liter')>
 <Quantity(0.238, 'milligram / liter')>
 <Quantity(0.223, 'milligram / liter')>
 <Quantity(0.288, 'milligram / liter')>
 <Quantity(0.421, 'milligram / liter')>
 <Quantity(0.475, 'milligram / liter')>
 <Quantity(0.539, 'milligram / liter')>
 <Quantity(0.3, 'milligram / liter')>
 <Quantity(0.244, 'milligram / liter')>
 <Quantity(0.308, 'milligram / liter')>
 <Quantity(0.315, 'milligram / liter')>
 <Quantity(1.4, 'milligram / liter')>
 <Quantity(0.455, 'milligram / liter')>
 <Quantity(0.189, 'milligram / liter')>
 <Quantity(0.336, 'milligram / liter')>
 <Quantity(0.229, 'milligram / liter')>
 <Quantity(1.58, 'milligram / liter')>
 <Quantity(0.20901, 'milligram / liter')>
 <Quantity(1.68, 'milligram / liter')>
 <Quantity(1.57, 'milligram / liter')>]' has dtype incompatible with float64, please explicitly cast to a compatible dtype first.
  df_out.loc[m_mask, self.out_col] = convert_unit_series(**params)
/opt/hostedtoolcache/Python/3.9.25/x64/lib/python3.9/site-packages/harmonize_wq/domains.py:277: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`
  sub_df[cols[2]] = sub_df[cols[2]].fillna(sub_df[cols[1]])  # new_fract
/opt/hostedtoolcache/Python/3.9.25/x64/lib/python3.9/site-packages/harmonize_wq/domains.py:277: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`
  sub_df[cols[2]] = sub_df[cols[2]].fillna(sub_df[cols[1]])  # new_fract
/opt/hostedtoolcache/Python/3.9.25/x64/lib/python3.9/site-packages/harmonize_wq/domains.py:277: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`
  sub_df[cols[2]] = sub_df[cols[2]].fillna(sub_df[cols[1]])  # new_fract
/opt/hostedtoolcache/Python/3.9.25/x64/lib/python3.9/site-packages/harmonize_wq/domains.py:277: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`
  sub_df[cols[2]] = sub_df[cols[2]].fillna(sub_df[cols[1]])  # new_fract
/opt/hostedtoolcache/Python/3.9.25/x64/lib/python3.9/site-packages/harmonize_wq/wq_data.py:158: FutureWarning: unique with argument that is not not a Series, Index, ExtensionArray, or np.ndarray is deprecated and will raise in a future version.
  for bad_meas in pandas.unique(bad_measures):
/opt/hostedtoolcache/Python/3.9.25/x64/lib/python3.9/site-packages/harmonize_wq/wq_data.py:663: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value '[<Quantity(19.0, 'milligram / liter')>
 <Quantity(83.0, 'milligram / liter')>
 <Quantity(15.0, 'milligram / liter')> ...
 <Quantity(9.0, 'milligram / liter')> <Quantity(6.0, 'milligram / liter')>
 <Quantity(9.0, 'milligram / liter')>]' has dtype incompatible with float64, please explicitly cast to a compatible dtype first.
  df_out.loc[m_mask, self.out_col] = convert_unit_series(**params)
/opt/hostedtoolcache/Python/3.9.25/x64/lib/python3.9/site-packages/harmonize_wq/wq_data.py:158: FutureWarning: unique with argument that is not not a Series, Index, ExtensionArray, or np.ndarray is deprecated and will raise in a future version.
  for bad_meas in pandas.unique(bad_measures):
/opt/hostedtoolcache/Python/3.9.25/x64/lib/python3.9/site-packages/harmonize_wq/wq_data.py:663: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value '[<Quantity(0.2, 'milligram / liter')>
 <Quantity(0.03, 'milligram / liter')>
 <Quantity(0.3, 'milligram / liter')> ...
 <Quantity(1.2, 'milligram / liter')>
 <Quantity(0.73, 'milligram / liter')>
 <Quantity(1.4, 'milligram / liter')>]' has dtype incompatible with float64, please explicitly cast to a compatible dtype first.
  df_out.loc[m_mask, self.out_col] = convert_unit_series(**params)
2 Phosphorus sample fractions not in frac_dict
2 Phosphorus sample fractions not in frac_dict found in expected domains, mapped to "Other_Phosphorus"
/opt/hostedtoolcache/Python/3.9.25/x64/lib/python3.9/site-packages/harmonize_wq/wq_data.py:158: FutureWarning: unique with argument that is not not a Series, Index, ExtensionArray, or np.ndarray is deprecated and will raise in a future version.
  for bad_meas in pandas.unique(bad_measures):
/opt/hostedtoolcache/Python/3.9.25/x64/lib/python3.9/site-packages/harmonize_wq/basis.py:343: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value '@25C' has dtype incompatible with float64, please explicitly cast to a compatible dtype first.
  df_out.loc[mask, basis_col] = basis
/opt/hostedtoolcache/Python/3.9.25/x64/lib/python3.9/site-packages/harmonize_wq/wq_data.py:510: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value '[nan nan nan ... nan nan nan]' has dtype incompatible with float64, please explicitly cast to a compatible dtype first.
  self.df[c_mask] = basis.update_result_basis(
/opt/hostedtoolcache/Python/3.9.25/x64/lib/python3.9/site-packages/harmonize_wq/wq_data.py:663: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value '[<Quantity(21.44, 'Practical_Salinity_Units')>
 <Quantity(21.51, 'Practical_Salinity_Units')>
 <Quantity(21.51, 'Practical_Salinity_Units')> ...
 <Quantity(29.0, 'Practical_Salinity_Units')>
 <Quantity(28.0, 'Practical_Salinity_Units')>
 <Quantity(16.0, 'Practical_Salinity_Units')>]' has dtype incompatible with float64, please explicitly cast to a compatible dtype first.
  df_out.loc[m_mask, self.out_col] = convert_unit_series(**params)
/opt/hostedtoolcache/Python/3.9.25/x64/lib/python3.9/site-packages/harmonize_wq/wq_data.py:158: FutureWarning: unique with argument that is not not a Series, Index, ExtensionArray, or np.ndarray is deprecated and will raise in a future version.
  for bad_meas in pandas.unique(bad_measures):
/opt/hostedtoolcache/Python/3.9.25/x64/lib/python3.9/site-packages/harmonize_wq/wq_data.py:663: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value '[<Quantity(24.7, 'degree_Celsius')> <Quantity(24.7, 'degree_Celsius')>
 <Quantity(25.6, 'degree_Celsius')> ... <Quantity(25.0, 'degree_Celsius')>
 <Quantity(25.7, 'degree_Celsius')> <Quantity(26.1, 'degree_Celsius')>]' has dtype incompatible with float64, please explicitly cast to a compatible dtype first.
  df_out.loc[m_mask, self.out_col] = convert_unit_series(**params)
/opt/hostedtoolcache/Python/3.9.25/x64/lib/python3.9/site-packages/harmonize_wq/wq_data.py:158: FutureWarning: unique with argument that is not not a Series, Index, ExtensionArray, or np.ndarray is deprecated and will raise in a future version.
  for bad_meas in pandas.unique(bad_measures):
/opt/hostedtoolcache/Python/3.9.25/x64/lib/python3.9/site-packages/harmonize_wq/wq_data.py:663: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value '[<Quantity(7.5701, 'Nephelometric_Turbidity_Units')>
 <Quantity(71.43362, 'Nephelometric_Turbidity_Units')>
 <Quantity(190.0373, 'Nephelometric_Turbidity_Units')> ...
 <Quantity(38.0023, 'Nephelometric_Turbidity_Units')>
 <Quantity(95.0773, 'Nephelometric_Turbidity_Units')>
 <Quantity(95.0773, 'Nephelometric_Turbidity_Units')>]' has dtype incompatible with float64, please explicitly cast to a compatible dtype first.
  df_out.loc[m_mask, self.out_col] = convert_unit_series(**params)
/opt/hostedtoolcache/Python/3.9.25/x64/lib/python3.9/site-packages/harmonize_wq/wq_data.py:158: FutureWarning: unique with argument that is not not a Series, Index, ExtensionArray, or np.ndarray is deprecated and will raise in a future version.
  for bad_meas in pandas.unique(bad_measures):
/opt/hostedtoolcache/Python/3.9.25/x64/lib/python3.9/site-packages/harmonize_wq/wq_data.py:663: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value '[<Quantity(7.5, 'dimensionless')> <Quantity(7.7, 'dimensionless')>
 <Quantity(7.2, 'dimensionless')> ... <Quantity(7.3, 'dimensionless')>
 <Quantity(7.8, 'dimensionless')> <Quantity(7.6, 'dimensionless')>]' has dtype incompatible with float64, please explicitly cast to a compatible dtype first.
  df_out.loc[m_mask, self.out_col] = convert_unit_series(**params)
[10]:
OrganizationIdentifier OrganizationFormalName ActivityIdentifier ActivityStartDate ActivityStartTime/Time ActivityStartTime/TimeZoneCode MonitoringLocationIdentifier ResultIdentifier DataLoggerLine ResultDetectionConditionText ... TOTAL NITROGEN_ MIXED FORMS Carbon Phosphorus TP_Phosphorus TDP_Phosphorus Other_Phosphorus Salinity Temperature Turbidity pH
0 USGS-FL USGS Florida Water Science Center nwisfl.01.94202446 1942-04-14 12:00:00 EDT USGS-275840082305601 NWIS-6769611 NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN 7.5 dimensionless
1 USGS-FL USGS Florida Water Science Center nwisfl.01.94202447 1942-05-05 12:00:00 EDT USGS-275850082310101 NWIS-6769631 NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN 7.7 dimensionless
2 USGS-FL USGS Florida Water Science Center nwisfl.01.94202445 1942-05-13 12:00:00 EDT USGS-275835082313501 NWIS-6769593 NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN 7.2 dimensionless
3 USGS-FL USGS Florida Water Science Center nwisfl.01.94202444 1942-05-13 12:00:00 EDT USGS-275826082312901 NWIS-6769579 NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN 7.7 dimensionless
4 USGS-FL USGS Florida Water Science Center nwisfl.01.94202443 1942-05-13 12:00:00 EDT USGS-275823082312101 NWIS-6769559 NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN 7.7 dimensionless
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
1537974 USGS-FL USGS Florida Water Science Center nwisfl.01.95500739 1955-03-25 NaN NaN USGS-273236082335801 NWIS-6842169 NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN 7.3 dimensionless
1537975 USGS-FL USGS Florida Water Science Center nwisfl.01.95500762 1955-04-08 NaN NaN USGS-273926082304501 NWIS-6842541 NaN NaN ... NaN NaN NaN NaN NaN NaN NaN 25.7 degree_Celsius NaN NaN
1537976 USGS-FL USGS Florida Water Science Center nwisfl.01.95500762 1955-04-08 NaN NaN USGS-273926082304501 NWIS-6842544 NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN 7.8 dimensionless
1537977 USGS-FL USGS Florida Water Science Center nwisfl.01.95500782 1955-04-08 NaN NaN USGS-274455082253601 NWIS-6842941 NaN NaN ... NaN NaN NaN NaN NaN NaN NaN 26.1 degree_Celsius NaN NaN
1537978 USGS-FL USGS Florida Water Science Center nwisfl.01.95500782 1955-04-08 NaN NaN USGS-274455082253601 NWIS-6842944 NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN 7.6 dimensionless

1537979 rows × 100 columns

[11]:
# Get harmonized stations clipped to the Area of Interest
stations_gdf, stations, site_md = location.get_harmonized_stations(query, aoi=aoi_gdf)
/opt/hostedtoolcache/Python/3.9.25/x64/lib/python3.9/site-packages/harmonize_wq/clean.py:356: FutureWarning: Logical ops (and, or, xor) between Pandas objects and dtype-less sequences (e.g. list, tuple) are deprecated and will raise in a future version. Wrap the object in a Series, Index, or np.array before operating instead.
  cond_notna = mask & (df_out["QA_flag"].notna())  # Mask cond and not NA
/opt/hostedtoolcache/Python/3.9.25/x64/lib/python3.9/site-packages/harmonize_wq/clean.py:360: FutureWarning: Logical ops (and, or, xor) between Pandas objects and dtype-less sequences (e.g. list, tuple) are deprecated and will raise in a future version. Wrap the object in a Series, Index, or np.array before operating instead.
  df_out.loc[mask & (df_out["QA_flag"].isna()), "QA_flag"] = flag
/opt/hostedtoolcache/Python/3.9.25/x64/lib/python3.9/site-packages/harmonize_wq/clean.py:360: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value 'LatitudeMeasure: Imprecise: lessthan3decimaldigits' has dtype incompatible with float64, please explicitly cast to a compatible dtype first.
  df_out.loc[mask & (df_out["QA_flag"].isna()), "QA_flag"] = flag
/opt/hostedtoolcache/Python/3.9.25/x64/lib/python3.9/site-packages/harmonize_wq/clean.py:356: FutureWarning: Logical ops (and, or, xor) between Pandas objects and dtype-less sequences (e.g. list, tuple) are deprecated and will raise in a future version. Wrap the object in a Series, Index, or np.array before operating instead.
  cond_notna = mask & (df_out["QA_flag"].notna())  # Mask cond and not NA
/opt/hostedtoolcache/Python/3.9.25/x64/lib/python3.9/site-packages/harmonize_wq/clean.py:360: FutureWarning: Logical ops (and, or, xor) between Pandas objects and dtype-less sequences (e.g. list, tuple) are deprecated and will raise in a future version. Wrap the object in a Series, Index, or np.array before operating instead.
  df_out.loc[mask & (df_out["QA_flag"].isna()), "QA_flag"] = flag
[12]:
# Map number of usable results at each station
gdf_count = visualize.map_counts(df_harmonized, stations_gdf)
legend_kwds={"fmt": "{:.0f}", 'bbox_to_anchor':(1, 0.75)}
gdf_count.plot(column='cnt', cmap='Blues', legend=True, scheme='quantiles', legend_kwds=legend_kwds)
[12]:
<Axes: >
../_images/notebooks_Harmonize_Tampa_Simple_21_1.png
[13]:
# Map average temperature results at each station
gdf_temperature = visualize.map_measure(df_harmonized, stations_gdf, 'Temperature')
gdf_temperature.plot(column='mean', cmap='OrRd', legend=True)
[13]:
<Axes: >
../_images/notebooks_Harmonize_Tampa_Simple_22_1.png

Clean additional columns of data

[14]:
from harmonize_wq import clean
[15]:
df_cleaned = clean.datetime(df_harmonized)  # datetime
df_cleaned = clean.harmonize_depth(df_cleaned)  # Sample depth

Reduce data to the columns that are most commonly needed

There are many columns in the dataframe that are characteristic specific, that is they have different values for the same sample depending on the characteristic. To ensure one result for each sample after the transformation of the data these columns must either be split, generating a new column for each characteristic with values, or moved out from the table if not being used.

[16]:
# Split single QA column into multiple by characteristic (rename the result to preserve these QA_flags)
df_expanded = wrangle.split_col(df_cleaned)
df_expanded
[16]:
OrganizationIdentifier OrganizationFormalName ActivityIdentifier ActivityStartDate ActivityStartTime/Time ActivityStartTime/TimeZoneCode MonitoringLocationIdentifier ResultIdentifier DataLoggerLine ResultDetectionConditionText ... QA_E_coli QA_TP_Phosphorus QA_TDP_Phosphorus QA_Other_Phosphorus QA_Temperature QA_Chlorophyll QA_Salinity QA_Conductivity QA_pH QA_DO
0 USGS-FL USGS Florida Water Science Center nwisfl.01.94202446 1942-04-14 12:00:00 EDT USGS-275840082305601 NWIS-6769611 NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
1 USGS-FL USGS Florida Water Science Center nwisfl.01.94202447 1942-05-05 12:00:00 EDT USGS-275850082310101 NWIS-6769631 NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
2 USGS-FL USGS Florida Water Science Center nwisfl.01.94202445 1942-05-13 12:00:00 EDT USGS-275835082313501 NWIS-6769593 NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
3 USGS-FL USGS Florida Water Science Center nwisfl.01.94202444 1942-05-13 12:00:00 EDT USGS-275826082312901 NWIS-6769579 NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
4 USGS-FL USGS Florida Water Science Center nwisfl.01.94202443 1942-05-13 12:00:00 EDT USGS-275823082312101 NWIS-6769559 NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
1537974 USGS-FL USGS Florida Water Science Center nwisfl.01.95500739 1955-03-25 NaN NaN USGS-273236082335801 NWIS-6842169 NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
1537975 USGS-FL USGS Florida Water Science Center nwisfl.01.95500762 1955-04-08 NaN NaN USGS-273926082304501 NWIS-6842541 NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
1537976 USGS-FL USGS Florida Water Science Center nwisfl.01.95500762 1955-04-08 NaN NaN USGS-273926082304501 NWIS-6842544 NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
1537977 USGS-FL USGS Florida Water Science Center nwisfl.01.95500782 1955-04-08 NaN NaN USGS-274455082253601 NWIS-6842941 NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
1537978 USGS-FL USGS Florida Water Science Center nwisfl.01.95500782 1955-04-08 NaN NaN USGS-274455082253601 NWIS-6842944 NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN

1465941 rows × 116 columns

[17]:
# Split table into main with columns of interest and characteristic specific columns/metadata
main_df, chars_df = wrangle.split_table(df_expanded)
[18]:
# Drop empty columns (QA columns without flags)
main_df_small = main_df.dropna(axis=1, how='all')

Transform data from long to wide format

[19]:
transformed_df = wrangle.collapse_results(main_df_small)

Results are collapsed by retaining the first result that isn’t NAN. There can be several reasons for multiple results for the same parameter/characteristic sampled at the same station, time and by the same organization. The collapse_results function assumes the user has already reviewed the quality of all results and narrowed down instances of multiple results to only the desired/best/highest quality result before running this function.