PURPLE_AIR_API_READY_KEY instead of MY_API_READ_KEY.show_only is used, spatial bounding information is ignored in:
pa_getSensorsData(), pas_downloadParseRawData() and pas_createNew().pas_createNew() to be backwards compatible with MazamaSpatialUtils
version 0.7.6.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:
Updated Mazama package dependency versions.
pas_createNew(), pas_downloadParseData(), pas_enhanceRawData()
and pas_leaflet().pat_downloadParseRawData(), pat_createNew().pas_addCommunityRegion().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.pat_externalFit() and pat_monitorComparison().pat_monitorComparision().sensor_calendarPlot().pat_join() to handle older 'pat' objects with integer deviceID.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().example_~ data files with AirSensor 0.9.17..json file.plantowerAlgorithm argument from pat_createPATimeseriesObject() as
an attractive nuisance that could generate much confusion.sensor_~() functions.sensor_polarPlot() and sensor_pollutionRose() functionality by
upgrading to worldmet 0.9.1.sensor_join().sensor_load().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.PurpleAirQC_hourly_~() functions, returnAllColumns now returns a
column of data for every parameter used in the QC algorithm.stats::t.test()
inside of PurpleAirQC_hourly_AB_01(). PurpleAirQC_hourly_AB_01() to properly use the t-test p_value.PurpleAirQC_hourly_AB_01() to gracefully handle time periods when
R's stats::t.test() function returns an error -- e.g. when an hourly subset
contains insufficient data.pas_downloadParseRawData() to guarantee that all "ID" parameters are
of "character" type and not "integer".sensor_filterDatetime() function for times that are not aligned to
date boundaries.sensor_load() to use sensor_join() and other internal functions
for package consistency.PWFSLSmoke::monitor_isMonitor()
with package internal sensor_isSensor().pat_join() to remove overlapping data in incoming PAT_pat objects
before joining. pat_filterDatetime() function for times that are not aligned to date
boundaries.pat_createNew() to not trim data at date boundaries.pat_load() to not trim data at date boundaries and removed the
days parameter.sensor_join() function to "join" airsensor objects from different
months.pat_distinct() to remove duplicated time stamps and guarantee proper
ordering by datetime.pat_isPat() and sensor_isSensor().idPattern argument to all pas_get~() functions.sensor_load().round(1) from internal pat_aggregate()
calculations.patData_aggregate() to work properly. The passed in FUN must
now return a matrix.sensor_load~() functions.pat_createPATimeseriesObject.R.Changes requested by CRAN maintainers:
option(warn = -1).sensor_videoFrame(). This function is not general and has been moved
to the AQ-SPEC-sensor-data-ingest-v1 private repository.local_Rmd/PurpleAirQC_Comparison.Rmd.PurpleAirQC_hourly_AB_01() as the default QC algorithm throughout
the code. (The _02 version removed too much data.)sensor_pollutionRose() and sensor_polarPlot().Pre-release candidate.
setArchiveBaseDir(NULL) now works identically to removeArchiveBasesDir().
Ditto for setArchiveBaseUrl(NULL).pas_load() returns helpful message when the archive BASE_DIR is set and
no requested pas data is found: removeArchiveBaseDir().verbose parameter to sensor_polarPlot() and sensor_pollutionRose().pat_multiplot() as an alias for pat_multiPlot().pat_dailySoH() bug that showed up with dplyr 1.0.0.pat_aggregate() to always return a "regular" time axis with no
missing timesteps.example_sensor dataset.PurpleAirQC_hourly_AB_03().pat_monitorComparison()FUN to specify which QC algorithm to applydistanceCutoff specifying the radius within which to search for a
nearby monitor.pat_filterDate().pat_createNew() check for spatial data.pat_upgrade() function to bring version 0.6 'pat' objects up to the
version 0.8 data model.pas_createNew().pat_dygraph() to include support for parameter = "pressure".pat_aggregateOutlierCounts().This release completely refactors the way that 'pat' data are downloaded from
ThingSpeak. Additional data columns are added to the standard pat$data
dataframe.
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.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.pat_multiplot() to pat_multiPlot() (capital 'P').pat_scatterMatrixPlot to pat_scatterPlotMatrx().pat_createAirSensor() pas_load() now ignores duplicated warning messages.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.
pat_aggregate() and pat_createAirSensor() functions.PurpleAirQC_hourly_AB_02().pat_externalFit() and pat_monitorComparison() updated to use new
aggregation/QC functions.pat_aggregate() and pat_createAirSensor() are now
now available as pat_aggregate_old and pat_createAirSensor_old().PurpleAirQC_validationPlot() renamed to PurpleAirQC_validationPlot_old().pat_outliers() defaults updated to reflect current default 120 second sample
interval.pat_multiPlot() now returns a ggplot2 object which can be manipulated.downloadParseTimeseriesData() to pat_downloadParseRawData().pas_load().pas_upgrade() to add sensorManufacturer, targetPollutant and
technologyType columns.archiveBaseUrl from http://smoke.mazamascience.com/data/PurpleAir
to https://airsensor.aqmd.gov/PurpleAir/v1.pat_scatterPlot() to pat_scatterPlotMatrix().downloadParseSynopticData() to pas_downloadParseRawData().enhanceSynopticData() to pas_enhanceData().pas objects: pas_addAirDistrict(),
pas_addSpatialMetadata(), pas_addUniqueIDs(), pas_addUniqueIDs(),
pas_hasSpatial().pas_upgrade() function to upgrade pas files created with
AirSensor version 0.5.enhanceSynopticData() when countryCodes = NULL. This was
encountered when running pas_createNew() with countryCodes = NULL.MazamaCoreUtils::loadDatafile() function .pas_~() functions.pat_multiPlot() and pat_monitorComparison()PurpleAirSoH_dailyToIndex()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.downloadParseTimeseriesData().pat/YYYY/. The pat_loadMonth() function
was modified to search in this location.pat$meta$pm25_A/B values now come from the raw data outdoor value
PM2.5 (ATM) rather than the indoor value PM2.5 (CF=1). See
https://www2.purpleair.com/community/faq#!hc-what-is-the-difference-between-cf-1-and-cf-atmdownloadParseTimeseriesData().countryCodes = NULL in pas_createNew() and
enhanceSynopticData() so that it is easier to create pas objects for other
countries.countryCode and stateCode arguments from pas_get~ functions.
Filter should be done with pas_filter() before these functions are called.enhanceSynopticData() which failed to add pwfsl~ columns when
includePWFSL = FALSE. (The columns should still exist but with all NA.)pas_get~() functions now support subsetting by countryCode and US
stateCode.days argument to pat_loadLatest().pat_load() and sensor_load() default to the last 7 days when no dates
are provided.pat_trimDate() function trims data to local time full days.pas_isPas() no longer requires presence of optional pwfsl_~ columns.pas_filterNear() to package standard
longitude, latitude.deviceID, locationID,
deviceDeploymentID.pat_createNew() andpat_load~()functions so that the firstidargument is used as thedeviceDeploymentID` unique time series identifier.label and pas and provide an
alternative to specifying id.exaple_pat~ data files with so they have the new metadata
fields: sensorID, locationID and deviceDeploymentID.Revisited everything at the pas object level:
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:
sensorID -- same as ID but more explicitlocationID -- generated with MazamaLocationUtils::location_createID()sensorDeploymentID -- combination of the aboveThe following functions were added/refactored to use "sensor-deployment" identifiers:
pas_sensorDeploymentID() creates a unique "sensor-deployment"
identifier. This identifier is used in creation of file names in the archive
database and as the unique time series identifer in airsensor objects.pas_getColumn(), past_getLabels(), pas_getIDs()pat_createNew()pat_load(), pat_loadLatest(), pat_loadMonth()pat_createAirSensor() 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 rangedownloadParseTimeseriesData()Additional functionality for calculating a state of health index to be used as an overall assessment of sensor functioning.
pat_dailyStateOfHealth() to pat_dailySoH()pat_dailySoHPlot(), pat_dailySoHIndex_00(),
pat_dailySoHIndexPlot()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 signalspas_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.
~SoH_dailyCorrelation() to ~SoH_dailyMetFit().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:
loadDataFile()pas_load()pat_createNew()pat_loadLatest()pat_loadMonth()sensor_loadLatest()sensor_loadMonth()sensor_loadYear()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.
PurpleAirSoH_dailyCorrelation()PurpleAirSoH_dailyPctDC()PurpleAirSoH_dailyPctReporting()PurpleAirSoH_dailyPctValid()pat_dailyStateOfHealth()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.timeseriesTbl_multiPlot() now supports a style paramter which can be set
to "point", "line" or "area".SoH_pctValid(), SoH_pctDC().pat_createNew() and downloadParseTimeseriesData() to support the
id parameter.PurpleAirQC_aggregationPlot() to work with any tibble or dataframe
and renamed it to tbl_multiplot().SoH_pctReporting().pat_aggregate() non longer stops in the face of data with a DC signal on
one of the pm25 channels.aggregation_FUN argument to pat_createAirSensor() to allow for
custom aggregation statistics.PurpleAirQC_aggregationPlot() function.datestamp handling in pas_load().make.names argument to pat_loadMonth() and pat_loadLatest().pat_dygraph() which referenced PWFSLSmoke::parseDatetime()
which is now deprecated in favor of MazamaCoreUtils::parseDatetime().loadDataFile(), getArchiveBaseDir(),
setArchiveBaseDir().~_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.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.
sensor_filterMeta() where filtering the number of rows in
sensor$meta did not also filter columns in sensor$data.sensor_videoFrame() with new arguments and new defaults for
colorPalette and colorBins.pat_sample() to handle cases where the A or B channel contains
only missing values.sensor_loadLatest() no supports a days argument and defaults to loading
a 45-day file.local_executables/ scripts.timezone argument to downloadParseTimeseriesData().local_executables/crontab~ files.downloadParseTimeseriesData() to avoid using day
boundaries when explicit times are specified.pas_load() default retries was increased from 10 to 30.pat_createNew() created time ranges that ended (UTC - local)
hours short of the requested enddate.pat_externalFit(), pat_internalFit(),
pat_monitorComparison() and pat_outliers()
now have time axes with sensor local time rather than UTC.pat_externalFit() and pat_monitorComparison() labeling now includes PWFSL
monitor siteNameMazamaCoreUtil::stopIfNull() throughout.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_calendarPlot() and sensor_calendarPlot() to handle discrete
color scales.pat_createAirSensor() now uses pat$meta$label to populate
sensor$meta$siteName.sensor_calendarPlot().aspectRatio argument to ~calendarPlot() functions.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.MazamaCoreUtils::dateRange() to reflect change from "end of
enddate" to "start of enddate".setArchiveBaseUrl() and getArchiveBaseUrl() functions allow per
session specification of the location of pre-generated data files.baseUrl parameter from all data loading functions. Now users must
begin a session with setArchiveBaseUrl().sensor_load() to trim data to the requested time
range.pat_scatterPlot() that generated an error when the number of
records in the pat object was fewer than the sampleSize parameter.pat_calendarPlot() tailored to full-year calendar heatmaps.pat_distinct() to remove duplicate data records.pat_~() functions now remove duplicate records to guarantee proper
functioning of chained functions.pat_loadLatest() to always get the most recent 7 days.pat_loadSensor() to always get the most recent 7 days.timezone argument to pat_createNew().pat_createNew() now accepts start and end points not on date boundaries.AirShiny_leaflet()pas_leaflet() coloring issue.pwdpat_load() which didn't trim data to date boundaries when a
local timezone was passed in. pat_calendarPlot() to plot annual daily heat map. pas_loadLatest() to pas_createNew().pat_loadLatest() to pat_createNew().download~() functions.timezone parameter to pas_load().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.sensor_polarplot() and sensor_pollutionRose().PurpleAirQC_algorithm to sensor objects created by
pat_createAirSensor() so that they self-document how they were created.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.downloadParseSensorList().name to label in pat_createNew() and
downloadParseTimeseriesData().local_executables/ to work with the latest release.pas_staticMap() and pas_filterNear().downloadParseSensorList() to download a list of archived PurpleAir
sensors. 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.local_executables/createVideo_exec.R script to generate mp4 videos.ylim argument to pat_multiPlot().sensor_filter(), sensor_filterDate() and sensor_filterMeta().local_examples/downloadSpeeds.Rmd to benchmark data download times
from ThinkSpeak.pat_aggregateOutlierCounts() to count outliers per aggregation
period. pat_aggregate() to fix warnings and optimizewind_loadMonth() to load pre-generated monthly wind datawind_load() to load pre-generated wind data from timestampssensor_pollutionRose() to accept new wind data modelsensor_polarPlot() to plot bivariate polar plotsairsensor_load~() to sensor_load~().sensor_~ utility functions: isSensor(), isEmpty(), extractMeta()
, extractData().example_sensor dataset for use in documentation examples.local_examples/LA_fireworks_2019.Rmin_count = 20).pat_scatterPlot().returnAllColumns option to `PurpleAirQC_~1 functions.PurpleQC_validationPlot() function.pat_createPATimeseriesObject() now retains additional metadata:
sensorManufacturer, targetPollutant, technologyType, communityRegionairsensor_load() so that it includes monitors found in any month
rather that those found in every month.pat_createPATimeseriesObject() and pat_createAirSensor() so that they
no longer generate NaN or Inf values.as_pollutionRose()createMonthlyWind_exec()example_as as an example "airsensor" objectinitializeMazamaSpatialUtils() now only sets up logging if it hasn't
already been set up.local_executables scripts.pat_loadMonth() to use the newer pat_<label>_<monthstamp>.rda
naming system.pat_monitorComparison().local_examples/bikesgv_story.Rmd.pas_filter()."pm25_a" and "pm25_b" plot types to pat_multiPlot().pas_within() to pas_filterNear()airSensorQC_~ functions to PurpleAirQC_~local_executables/ to be more similarairsensor data files with pre-generated,
hourly-aggregated data suitable for use with the PWFSLSmoke package.airsensor_load() to load pre-generated, hourly-aggregated data files
suitable for use with the PWFSLSmoke package.hourly_AB_00 and hourly_AB_01.pat_cerateAirSensor() to accept arguments that impact the conversion
of pat data into aggregated period-averages: period, channel, qc_algorithm,
min_count.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.
pat_aggregate() that occasionaly returned empty columns of data.local_examples/Jons_qc_1.R with Jon's best take on appropriate QC of
the hourly aggregated data. pat_createAirSensor() added to barplot global.R to improve clarity of scopepas_within() for spatial analysispat_createAirSensor() function converts from pat object to airsensor
object that is compatible with the PWFSLSmoke package.pat_qc() argument humidityMax --> max_humidity.pat_aggregate() to fix an issue with t-test statistics. Also
simplified the function signature to accept just pat and period arguments.pat_load() to default to the most recent week of datapat_qc() function applies low level QCpat_outliers() to retain records with missing PM2.5 values when
replace = TRUEpat_aggregate() defaults to: period = "1 hour", quickStats = TRUEpat_aggregate() dataThreshold argumentexample_pat_failure_B dataset with severe A channel errorspat_scatterPlot()pat_loadLatest()createMonthlyPAT_exec.RthreePlot web-appdailyAveragePlot web-appsample() to .sample() to avoid confusion with
base::sample()utils-plot.R added to support general functionsutils-gen.R added to support general functionslocal_examples/07_pat_archive.R demonstrates how to efficiently work with
pre-generated pat files from the archivepat_loadMonth() loads pre-generated "pat" objects from a data archivepat_aggregate() -- it now always returns all statisticsplotList parameter from pat_multiPlot()pat_join() can now accept either individual pat objects or a list of
pat objectslocal_executables/createMonthlyPAT_exec.R script for populating an
archive with pat data filespat_load() to pat_loadLatest()subset and weights parameters from pat_internalFit()param parameter from pat_join()ast_createAirSensor() converts ast objects into "airsensor" objects that
are compatible with the PWFSLSmoke packageinitializeMazamaSpatialUtils() now imports all datasets need to create
pas objectsexample_pas data file has additional fields introduced by the
0.2.8 version of enhanceSynopticData()pat_timeAverage() functionpat_aggregate() function performs temporal aggregationenhanceSynopticData() now handle changing order of json
properties and validate locations before adding spatial metadatapat_createASTimeseries() function handles conversion of
Purple Air-specific "pat" objects into sensor-generic "ast" objects.ast_createAirSensor() objects converts "ast" objects into a "as" data
type that is compatible with the "ws_monitor" data type used in the
PWFSLSmoke packagepat_sample(forGraphics = TRUE)pas_leaflet() and pas_staticMap()enhanceSynopticMetadata() adds the following columns to a pas object:airDistrict -- CARB air districtsensorManufacturer = "Purple Air"targetPollutant = "PM"technologyType = "consumer-grade"communityRegion -- (where known)example_pat_failure datasetcreateASTimeseriesObject()pas_staticMap() function with customizable base maps and color schemespas_esriMap() because the ESRI map service we were using started
requiring tokens on April 25, 2019param to parameter in pas_leaflet()pat_sample() outlier detection window size to n = 23 to match
pat_outliers()pat~ functionspat_sample() functionpat~ plot functionspat_sample() included to sample pat datasetspat_dygraphs() included to plot JavaScript based "dygraphs"pat_multiPlot() time axis now in sensor local timepat_multiPlot() has a new pm25_over plottypepat_scatterPlot()pas_esriMap()local_examples/example_02_pas-filtering.Rpas_filterArea()pas_isPas(), pas_isEmpty()pat_internalData() to pat_scatterPlot() with improved functionalitypat_outliers() to pat_outliers() with improved functionalitypat_isPat(), pat_isEmpty(), pat_extractMeta(),
pat_extractData()pat_internalFit() functionpas_filter() to filter toolboxpas_esriMap()multi_ggplot()pas_esriMap()pat_filterData pat_subdate() has been renamed to pat_filterDate() and defaults to
the America/Los_Angeles timezonepat_loadLatest() -- all requests are assumed
to be in the sensor's local timezonepas_load() function now downloads pre-generated pas objectspas_loadLatest() function downloads raw synoptic data from Purple
Air and generates a pas objectexample_pas and example_raw_pasdata/ directory with sample pas objectvignettes/purple-air-synoptic.RmdInitial functions to download and map Purple Air synoptic data.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.