Updates to accommodate data access through the PurpleAir API released in July of 2022. This API requires an API_KEY. Users of the package are required to obtain their own credentials from PurpleAir.

For information, see:

  • MVCAA Tutorial series.
  • Minor documentation updates.
  • Minor documentation updates to clarify “state-of-health” calculations.
  • Improved pattern matching for South Coast communities in pas_addCommunityRegion().
  • Remove “Voc” column during pas_load() so that current and archival ‘pas’ objects can be easily merged. (Some early ‘pas’ objects contained some “Voc” data but this has never been a focus of the AirSensor package. Later ‘pas’ objects do not contain the “Voc” parameter.)
  • pas_load() now properly handles loading of archival ‘pas’ objects prior to 2019-08-02.
  • Fixed documentation and included dataset encoding to UTF-8 standard.
  • Improved legend in pat_monitorComparision().
  • CRAN submission tweaks.
  • Spell check vignettes.
  • CRAN submission tweaks.
  • First public release.
  • Fix in pat_join() to handle older ‘pat’ objects with integer deviceID.
  • Updated dependency to worldmet 0.9.2.
  • sensor_pollutionRose() now searches for the nearest 2 met sites in case the first one has no data. This matches the behavior in sensor_polarPlot().
  • Rebuilt all example_~ data files with AirSensor 0.9.17.
  • Updated tests to match new example data.
  • Removed all references to “Voc” in pas related functions as this field is not longer part of the PurpleAir .json file.
  • Used MazamaCoreUtils “timezone linting” to ensure that timezones are always specified.
  • Removed plantowerAlgorithm argument from pat_createPATimeseriesObject() as an attractive nuisance that could generate much confusion.
  • Improved examples in several sensor_~() functions.
  • Updated several articles.
  • Added guarantees in multiple places that meta$ID and meta$deviceID for both pat and airsensor objects are of type “character”. This fixes errors during joining of monthly files that may have been created with an earlier version of the package.
  • Refactored pat_join() to remove overlapping data in incoming PAT_pat objects before joining.
  • Added pat_filterDatetime() function for times that are not aligned to date boundaries.
  • Modified pat_createNew() to not trim data at date boundaries.
  • Modified pat_load() to not trim data at date boundaries and removed the days parameter.
  • Added idPattern argument to all pas_get~() functions.
  • Fixed bug in sensor_load().
  • Removed inappropriate application of round(1) from internal pat_aggregate() calculations.
  • Refactored patData_aggregate() to work properly. The passed in FUN must now return a matrix.
  • Restored/fixed examples in sensor_load~() functions.
  • Properly handling duplicate datetimes in pat_createPATimeseriesObject.R.

Changes requested by CRAN maintainers:

  • Improved function examples.
  • Removed function internal use of option(warn = -1).
  • Updates to pass CRAN checks.
  • More updates to pass win-builder checks.
  • Updates to pass win-builder checks.
  • Removed sensor_videoFrame(). This function is not general and has been moved to the AQ-SPEC-sensor-data-ingest-v1 private repository.
  • New R Markdown document for comparing QC algorithms: local_Rmd/PurpleAirQC_Comparison.Rmd.
  • Now using PurpleAirQC_hourly_AB_01() as the default QC algorithm throughout the code. (The _02 version removed too much data.)
  • Updated examples in sensor_pollutionRose() and sensor_polarPlot().

Pre-release candidate.

  • Fixed pat_dailySoH() bug that showed up with dplyr 1.0.0.
  • Improved examples in function documentation.
  • Fixed pat_aggregate() to always return a “regular” time axis with no missing timesteps.
  • Restored example_sensor dataset.
  • Additional unit tests.
  • Added another QC function – PurpleAirQC_hourly_AB_03().
  • Modified pat_monitorComparison()
    • simplified function signature by removing unused color and shape parameters
    • added FUN to specify which QC algorithm to apply
    • added distanceCutoff specifying the radius within which to search for a nearby monitor.

This release completely refactors the way that ‘pat’ data are downloaded from ThingSpeak. Additional data columns are added to the standard pat$data dataframe.

  • Refactored pat_downloadParseRawData() data access times and also reduced the volume of data downloaded by switching from the .json to the .csv API from ThingSpeak. This function now returns a list of five dataframes.
  • Renamed and refactored pat_createPATimeseriesObject() to work with the new list of dataframes from pat_downloadParseRawData(). New fields pressure and bsec_iaq are included in the created pat object.
  • Including dependency on httpcode and readr packages.
  • Renamed pat_multiplot() to pat_multiPlot() (capital ‘P’).
  • Renamed pat_scatterMatrixPlot to pat_scatterPlotMatrx().
  • pat_createAirSensor()
  • pas_load() now ignores duplicated warning messages.
  • The upper threshold for pm25 in pat_qc() was increased to 2,000 based on a 2020-05-14 conversation with PurpleAir founder Adrian Dybwad.

This release completely refactors the way that aggregation and QC are performed. The changes should make the code easier to maintain, faster and much more flexible for those developing QC algorithms.

  • Updated pas_upgrade() to add sensorManufacturer, targetPollutant and technologyType columns.
  • Updated example archiveBaseUrl from http://smoke.mazamascience.com/data/PurpleAir to https://airsensor.aqmd.gov/PurpleAir/v1.
  • New pas_upgrade() function to upgrade pas files created with AirSensor version 0.5.
  • Fixed bug in enhanceSynopticData() when countryCodes = NULL. This was encountered when running pas_createNew() with countryCodes = NULL.
  • Added “PurpleAir Synoptic Data” article.
  • PAS function documentation typo fixes.
  • Added “Developer Style Guide” article.
  • Updated to use MazamaCoreUtils::loadDatafile() function .
  • Added more unit testing for pas_~() functions.
  • Separated calculation of SoHIndex into PurpleAirSoH_dailyToIndex()
  • Fixed bug in pat_isEmpty() so that it test for an empty data dataframe rather than an empty meta dataframe.
  • pat_trimDate() now preserves the first day if it begins at local midnight.
  • Improved error message in downloadParseTimeseriesData().
  • Changed default value to countryCodes = NULL in pas_createNew() and enhanceSynopticData() so that it is easier to create pas objects for other countries.
  • Removed countryCode and stateCode arguments from pas_get~ functions. Filter should be done with pas_filter() before these functions are called.
  • Fixed bug in enhanceSynopticData() which failed to add pwfsl~ columns when includePWFSL = FALSE. (The columns should still exist but with all NA.)
  • All pas_get~() functions now support subsetting by countryCode and US stateCode.
  • Reordered arguments in pas_filterNear() to package standard longitude, latitude.
  • Refactored pas objects to include: deviceID, locationID, deviceDeploymentID.
  • Refactored pat_createNew() andpat_load~()functions so that the firstidargument is used as thedeviceDeploymentID` unique time series identifier.
  • The second and third arguments are now label and pas and provide an alternative to specifying id.
  • Recreated example data with the new functions.
  • Improved examples.
  • Documentation corrections.
  • Recreated all exaple_pat~ data files with so they have the new metadata fields: sensorID, locationID and deviceDeploymentID.

Revisited everything at the pas object level:

  • Error message harmonization.
  • Updated package data files.
  • Updated documentation.
  • Updated tests.
  • Renamed pas_sensorDeploymentID() to pas_deviceDeploymentID()

Version 0.6 is a backwards incompatible release. It replaces label identifier with a proper “sensor-deployment” identifier and relies on the MazamaLocationUtils package to create location identifiers. Becuase of this change, archives must be regenerated and many functions must be refactored.

New fields in pat$meta include:

The following functions were added/refactored to use “sensor-deployment” identifiers:

  • Linted for timezones - fixed in Mutliplot and monitor comparison.

Minor documentation updates and package rebuild.

  • sensor_polarPlot() now uses the second-nearest met station if no data are found at the nearest station.
  • pat_filterDate() now issues a warning if requested data range is outside aviailable date range
  • removed print statements from downloadParseTimeseriesData()

Additional functionality for calculating a state of health index to be used as an overall assessment of sensor functioning.

Modified how pat_filterDate() obtains the timezone used to interpret the incoming startdate and enddate:

  1. startdate timezone if it is POSIXct
  2. timezone if it is passed in
  3. pat$meta$timezone otherwise
  • pat_outliers() no longer fails in the face of DC signals
  • New pas_getLabels() functions simplifies the creation of vectors of sensor labels (currently used as unique identifiers)

Refactored PurpleAirSoH_daily~() functions to use dplyr resulting in code that runs faster and is easier to understand.

  • Changed ~SoH_dailyCorrelation() to ~SoH_dailyMetFit().
  • Changed timeseriesTbl_multiPlot() argument parameterPatter to pattern.

Fixed bug in datetime axis that caused SoH functions to return missing values after the switch from PST to PDT.

Removed logger.error() statements from the following low-level functions as they couldn’t be turned off and ended up cluttering the log files:

Improved pat_join() logic to deal with metadata changes associated with the value pwfsl_closestMonitorID when temporary monitors come and go in the PWFSL database.

New PurpleAirSoH~ functions calculate daily state-of-health metrics from PAT data. These metrics can be combined to create multi-metric indices that provide an overall assessment of the health of a Purple Air sensor.

  • Added sensor_loadYear() to load annual files (~2-3 MB).
  • sensor_load() now attempts to load and join annual files before attempting the slower process of loading and joining monthly files.
  • Removed excessive logging in some of the loading functions.
  • timeseriesTbl_multiPlot() now supports a style paramter which can be set to "point", "line" or "area".
  • Improved handling of missing files in data loading functions.
  • Added state-of-health functions: SoH_pctValid(), SoH_pctDC().
  • Harmonized naming of state-of-health metrics.
  • Updated pat_createNew() and downloadParseTimeseriesData() to support the id parameter.
  • Enhanced PurpleAirQC_aggregationPlot() to work with any tibble or dataframe and renamed it to tbl_multiplot().
  • Added a state-of-health metrics calculation function: SoH_pctReporting().
  • Now requiring MazamaCoreUtils 0.3.10.
  • pat_aggregate() non longer stops in the face of data with a DC signal on one of the pm25 channels.
  • Added aggregation_FUN argument to pat_createAirSensor() to allow for custom aggregation statistics.
  • Added PurpleAirQC_aggregationPlot() function.
  • Improved datestamp handling in pas_load().
  • More explicit use of timezones to avoid local/UTC misunderstandings.
  • Upudated data loding to allow for loading data from a local archive. New functions include: loadDataFile(), getArchiveBaseDir(), setArchiveBaseDir().
  • All ~_load() and ~_loadLatest() functions now call loadDataFile()
  • pat_load() now continues working in the face of missing data files. under the hood and will work with data archives found at archiveBaseDir.
  • Removed pat_calendarPlot() and sensor_calendarPlot() from the packge. These work-in-progress functions are now found in local_R/. We anticipate including calendar plotting functionality in the AirMonitorPlots package.

Version 0.5.x represents the version of the package that is ready for public release.

  • Version bump.
  • Fixed bug in sensor_filterMeta() where filtering the number of rows in sensor$meta did not also filter columns in sensor$data.
  • Updated sensor_videoFrame() with new arguments and new defaults for colorPalette and colorBins.
  • Updated pat_sample() to handle cases where the A or B channel contains only missing values.
  • Improved local_executables/ scripts.
  • Added timezone argument to downloadParseTimeseriesData().
  • Improved logging in local_executables/crontab~ files.
  • Fixed implementation of downloadParseTimeseriesData() to avoid using day boundaries when explicit times are specified.
  • Using MazamaCoreUtil::stopIfNull() throughout.
  • Updated requirements: MazamaCoreUtils (>= 0.3.5).
  • All time-related functions now specify a timezone explicitly so as to avoid confusion related to the default base::Sys.timezone().
  • enhanceSynopticData() now handles presence or absence of State column in raw data obtained from PurpleAir. This was apparently removed some time during the summer of 2019.
  • pat_createAirSensor() now uses pat$meta$label to populate sensor$meta$siteName.
  • New sensor_calendarPlot().
  • Added aspectRatio argument to ~calendarPlot() functions.
  • Updated requirements: MazamaCoreUtils (>= 0.3.1), PWFSLSmoke (>= 1.2.100)
  • sensor_load() no longer stops when monthly files cannot be found. This helps when asking for the current year’s worth of data for a calendar plot.
  • Minor documentation tweaks.
  • Updated usage of MazamaCoreUtils::dateRange() to reflect change from “end of enddate” to “start of enddate”.
  • New setArchiveBaseUrl() and getArchiveBaseUrl() functions allow per session specification of the location of pre-generated data files.
  • Removed baseUrl parameter from all data loading functions. Now users must begin a session with setArchiveBaseUrl().
  • Modified behavior of sensor_load() to trim data to the requested time range.
  • Fixed bug in pat_scatterPlot() that generated an error when the number of records in the pat object was fewer than the sampleSize parameter.
  • New pat_calendarPlot() tailored to full-year calendar heatmaps.
  • Added pat_distinct() to remove duplicate data records.
  • All pat_~() functions now remove duplicate records to guarantee proper functioning of chained functions.
  • Removed Shiny app related functions.
  • Added pat_loadLatest() to always get the most recent 7 days.
  • Added pat_loadSensor() to always get the most recent 7 days.
  • Added timezone argument to pat_createNew().
  • pat_createNew() now accepts start and end points not on date boundaries.
  • Removed popups from AirShiny_leaflet()
  • Fixed pas_leaflet() coloring issue.pwd
  • Fixed bug in pat_load() which didn’t trim data to date boundaries when a local timezone was passed in.
  • Added pat_calendarPlot() to plot annual daily heat map.
  • Renamed pas_loadLatest() to pas_createNew().
  • Renamed pat_loadLatest() to pat_createNew().
  • Added “Too Many Requests” error messages to download~() functions.
  • Added timezone parameter to pas_load().
  • Included timezone information in every internal function call where it can be specified so that R’s default “system local timezone” does not accidentally get used.
  • When no wind data is provided, use nearest worldmet met station in sensor_polarplot() and sensor_pollutionRose().
  • Added PurpleAirQC_algorithm to sensor objects created by pat_createAirSensor() so that they self-document how they were created.
  • Included an archival argument to pas_load(). When archival = TRUE a pas object will be loaded that contains metadata for all PurpleAir sensors including those that have ceased reporting.
  • Removed unneeded downloadParseSensorList().
  • Changed argument name to label in pat_createNew() and downloadParseTimeseriesData().
  • Updated all scripts in local_executables/ to work with the latest release.
  • Faster geodesic calculations in pas_staticMap() and pas_filterNear().
  • Include downloadParseSensorList() to download a list of archived PurpleAir sensors.
  • Added sensor_videoFrame() function to create a single frame map for a network of sensors. These can be used to create videos showing the evolution of PM2.5 levels over several days.
  • Added local_executables/createVideo_exec.R script to generate mp4 videos.
  • Added ylim argument to pat_multiPlot().
  • Added wind_loadMonth() to load pre-generated monthly wind data
  • Added wind_load() to load pre-generated wind data from timestamps
  • Updated sensor_pollutionRose() to accept new wind data model
  • Added sensor_polarPlot() to plot bivariate polar plots
  • Renamed airsensor_load~() to sensor_load~().
  • Added sensor_~ utility functions: isSensor(), isEmpty(), extractMeta() , extractData().
  • Added example_sensor dataset for use in documentation examples.
  • Added local_examples/LA_fireworks_2019.R
  • Default required data retentaion rate during hourly aggregation was increased from 10/30 to 20/30 (min_count = 20).
  • Improved examples in the documentation.
  • Suppressing warnings from pat_scatterPlot().
  • Updated “PurpleAir Timeseries” vignette.
  • Added returnAllColumns option to `PurpleAirQC_~1 functions.
  • New PurpleQC_validationPlot() function.
  • pat_createPATimeseriesObject() now retains additional metadata: sensorManufacturer, targetPollutant, technologyType, communityRegion
  • Updated all package datasets so they include additional metadata.
  • Fixed airsensor_load() so that it includes monitors found in any month rather that those found in every month.
  • Fixed pat_createPATimeseriesObject() and pat_createAirSensor() so that they no longer generate NaN or Inf values.
  • Added as_pollutionRose()
  • Added createMonthlyWind_exec()
  • Include example_as as an example “airsensor” object
  • initializeMazamaSpatialUtils() now only sets up logging if it hasn’t already been set up.
  • Cleanup/refactoring of local_executables scripts.
  • Modified pat_loadMonth() to use the newer pat_<label>_<monthstamp>.rda naming system.
  • renamed pas_within() to pas_filterNear()
  • renamed airSensorQC_~ functions to PurpleAirQC_~
  • refactored scripts in local_executables/ to be more similar
  • Created an archive of airsensor data files with pre-generated, hourly-aggregated data suitable for use with the PWFSLSmoke package.
  • Added airsensor_load() to load pre-generated, hourly-aggregated data files suitable for use with the PWFSLSmoke package.
  • Added quality control algorithms: hourly_AB_00 and hourly_AB_01.
  • Updated pat_cerateAirSensor() to accept arguments that impact the conversion of pat data into aggregated period-averages: period, channel, qc_algorithm, min_count.
  • Fixed pat_aggregate() so that any NaN or Inf values are converted to NA.

The AirSensor package is now almost feature complete with functions for QC and aggregation to an houly axis.

  • Fixed bug in pat_aggregate() that occasionaly returned empty columns of data.
  • Added local_examples/Jons_qc_1.R with Jon’s best take on appropriate QC of the hourly aggregated data.
  • Updated AirShiny theme and include About section
  • Revamped AirShiny UI
  • Support for pat_createAirSensor() added to barplot
  • Dockerized AirShiny
  • Updated Namespace
  • Added global.R to improve clarity of scope
  • Added hex-sticker logo for AirShiny
  • Added pas_within() for spatial analysis
  • New pat_createAirSensor() function converts from pat object to airsensor object that is compatible with the PWFSLSmoke package.
  • Changed pat_qc() argument humidityMax –> max_humidity.
  • Refactored pat_aggregate() to fix an issue with t-test statistics. Also simplified the function signature to accept just pat and period arguments.
  • Updated pat_load() to default to the most recent week of data
  • New pat_qc() function applies low level QC
  • updated pat_outliers() to retain records with missing PM2.5 values when replace = TRUE
  • modified pat_aggregate() defaults to: period = "1 hour", quickStats = TRUE
  • removed pat_aggregate() dataThreshold argument
  • added example_pat_failure_B dataset with severe A channel errors
  • Fixed default parameters bug in pat_scatterPlot()
  • New shiny utilities for AirShiny
  • Remove out-of-time-range records in pat_loadLatest()
  • Corrected default date calculation in createMonthlyPAT_exec.R
  • Added ShinyAirSensor directory for alpha web-apps
  • Added threePlot web-app
  • Added dailyAveragePlot web-app
  • renamed internal sample() to .sample() to avoid confusion with base::sample()
  • simplified end-user parameters
  • Added ShinyAirSensor
  • utils-plot.R added to support general functions
  • utils-gen.R added to support general functions
  • local_examples/07_pat_archive.R demonstrates how to efficiently work with pre-generated pat files from the archive
  • new pat_loadMonth() loads pre-generated “pat” objects from a data archive
  • simplified pat_aggregate() – it now always returns all statistics
  • removed unused plotList parameter from pat_multiPlot()
  • pat_join() can now accept either individual pat objects or a list of pat objects
  • new local_executables/createMonthlyPAT_exec.R script for populating an archive with pat data files
  • ast_createAirSensor() converts ast objects into “airsensor” objects that are compatible with the PWFSLSmoke package
  • initializeMazamaSpatialUtils() now imports all datasets need to create pas objects
  • updated example_pas data file has additional fields introduced by the 0.2.8 version of enhanceSynopticData()
  • removed first attempt pat_timeAverage() function
  • new pat_aggregate() function performs temporal aggregation
  • improvements in enhanceSynopticData() now handle changing order of json properties and validate locations before adding spatial metadata
  • new pat_createASTimeseries() function handles conversion of Purple Air-specific “pat” objects into sensor-generic “ast” objects.
  • new ast_createAirSensor() objects converts “ast” objects into a “as” data type that is compatible with the “ws_monitor” data type used in the PWFSLSmoke package
  • corrected the algorithm for pat_sample(forGraphics = TRUE)
  • consistent support for named palettes in pas_leaflet() and pas_staticMap()
  • enhanceSynopticMetadata() adds the following columns to a pas object:
    • airDistrict – CARB air district
    • sensorManufacturer = "Purple Air"
    • targetPollutant = "PM"
    • technologyType = "consumer-grade"
    • communityRegion – (where known)
  • added example_pat_failure dataset
  • added createASTimeseriesObject()
  • improved labeling in all plots
  • new pas_staticMap() function with customizable base maps and color schemes
  • removed pas_esriMap() because the ESRI map service we were using started requiring tokens on April 25, 2019
  • uniform parameter validation in all pat~ functions
  • improved defaults for pat_sample() function
  • minor improvements to pat~ plot functions
  • pat_sample() included to sample pat datasets
  • pat_dygraphs() included to plot JavaScript based “dygraphs”
  • minor documentation cleanup
  • graphical options and other improvements for pas_esriMap()
  • added local_examples/example_02_pas-filtering.R
  • added pas_filterArea()
  • new utility functions pas_isPas(), pas_isEmpty()
  • added generalized multiplot function multi_ggplot()
  • include static mapping functionality with pas_esriMap()
  • added pat_filterData
  • pat_subdate() has been renamed to pat_filterDate() and defaults to the America/Los_Angeles timezone
  • improved handling of date ranges in pat_loadLatest() – all requests are assumed to be in the sensor’s local timezone
  • pas_load() function now downloads pre-generated pas objects
  • a new pas_loadLatest() function downloads raw synoptic data from Purple Air and generates a pas object
  • simplified docker image usage
  • include docker image
  • added subdating feature
  • added multiplotting tools
  • added outlier detection
  • added pat_internalData
  • added PurpleAir timeseries functionality
  • updated PurpleAir synoptic vignette
  • improved, more consistent documentation
  • renamed example datasets to example_pas and example_raw_pas
  • added documentation file for package datasets
  • changed header of vignette so that it is built properly
  • added parameter validation and testing for all existing functions
  • adding data/ directory with sample pas object
  • added vignettes/purple-air-synoptic.Rmd
  • added parameter validation to pas_leaflet.R
  • added test-pas_leaflet.R file

Initial functions to download and map Purple Air synoptic data.

  • downloadParseSynopticData.R – gets the most recent syoptic data from purpleair.com
  • enhanceSynopticData.R – adds spatial metadata to a synoptic dataset
  • initializeMazamaSpatialUtils.R – convenience function to install Mazama spatial data
  • pas_leaflet.R – creates an interactive map from a synoptic dataset
  • pas_load.R – download/parse/enhance synoptic data
  • pwfsl_load.R – download PWFSL monitoring data