Skip to content

Commit

Permalink
Merge branch 'release-1.4.7'
Browse files Browse the repository at this point in the history
  • Loading branch information
Milind220 committed Mar 24, 2022
2 parents bef2e41 + 2571621 commit 952804d
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 28 deletions.
1 change: 1 addition & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ repos:
rev: 'v0.941' # Use the sha / tag to point at specific version
hooks:
- id: mypy
additional_dependencies: ['types-requests', 'types-urllib3']
- repo: https://github.com/psf/black
rev: '22.1.0'
hooks:
Expand Down
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ I want to make it easy to get your hands on accurate air quality data for your p

[License and TOS](#license-and-terms-of-service)

[Contributors](#contributors)

## Install it here!

```sh
Expand Down Expand Up @@ -67,6 +69,22 @@ data = o3.get_multiple_city_air([ARRAY OF CITY NAMES])

![Gif of ozone.get_multiple_city_air()](/src/media/ozone_get_multiple_city_air_updated.gif)

### Air Quality Parameters

Ozone can fetch the following parameters:

* `aqi`: air quality index, a measurement of air quality that tells you how clean or polluted the air is
* `pm25`: fine particulate matter, a measure of 2.5 micrometers or smaller particles in the air
* `pm10`: respirable particulate matter, a measure of 10 micrometers or smaller particles in the air
* `o3`: a measure of ground level ozone concentrations in the air
* `co`: a measure of carbon monoxide concentrations in the air
* `no2`: a measure of nitrogen dioxide concentrations in the air
* `so2`: a measure of sulfur dioxide concentrations in the air
* `dew`: dew point, the temperature the air needs to be cooled to in order to reach 100% relative humidity
* `h`: relative humidity, a measure of moisture in the atmosphere
* `p`: atmospheric pressure, a measure of the weight of atoms and molecules that make up the layers in the atmosphere
* `t`: temperature, a measure of thermal energy in one or a combined substance at a given time
* `w`: wind speed, a measure of air in motion

Sample output:
<img width="1065" alt="blehblhe" src="https://user-images.githubusercontent.com/68847270/159113134-e7e2d76d-c64d-4f96-83c4-e85d8c76b503.png">
Expand Down Expand Up @@ -97,6 +115,14 @@ This package is a wrapper around an API provided by the World Air Quality Index
1. Ozone is licensed under the GNU GENERAL PUBLIC LICENSE v3.0, and so it cannot be used for closed-source software or for monetary gain.
2. The WAQI API, which Ozone uses to provide data, has it's own [Acceptable Usage Policy](https://aqicn.org/api/tos/). Please refer to it for more details.

## Contributors

Contributions of any kind are welcome and these are our amazing contributors.

<a href="https://github.com/Milind220/Ozone/graphs/contributors">
<img src="https://contrib.rocks/image?repo=Milind220/Ozone" />
</a>

Enjoy using Ozone!
🥳 🍾 🚀

Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[metadata]
name = ozon3
version = 1.4.6
version = 1.4.7
author = Milind Sharma
author_email = [email protected]
description = A package to get air quality data using the WAQI API
Expand Down
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
description="A package to get air quality data using the WAQI API",
license="GPLv3+",
url="https://github.com/Milind220/Ozone",
version="1.4.6",
download_url="https://github.com/Milind220/Ozone/archive/refs/tags/v1.4.6.tar.gz",
version="1.4.7",
download_url="https://github.com/Milind220/Ozone/archive/refs/tags/v1.4.7.tar.gz",
packages=setuptools.find_packages(),
install_requires=[
"numpy; python_version>='3'",
Expand Down
91 changes: 66 additions & 25 deletions src/ozone/ozone.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
Attributes (module level):
CALLS (int=1000): The number of calls per second allowed by the WAQI API is 1000.
RATE_LIMIT (int=1): The time period in seconds for the max number of calls is 1 second.
RATE_LIMIT (int=1): The time period in seconds for the max number of calls is
1 second.
"""

import pandas
Expand Down Expand Up @@ -112,12 +113,15 @@ def reset_token(self, token: str) -> None:
self._check_token_validity()

def _format_output(
self, data_format: str = "df", df: pandas.DataFrame = pandas.DataFrame(),
self,
data_format: str = "df",
df: pandas.DataFrame = pandas.DataFrame(),
) -> pandas.DataFrame:
"""Format output data
Args:
data_format (str): File format. Defaults to 'df'. Choose from 'csv', 'json', 'xlsx'.
data_format (str): File format. Defaults to 'df'.
Choose from 'csv', 'json', 'xlsx'.
df (pandas.DataFrame,): Dataframe object of air quality data.
Returns:
Expand All @@ -133,7 +137,9 @@ def _format_output(
df.to_json("air_quality_data.json")
print("File saved to disk as air_quality_data.json")
elif data_format == "xlsx":
df.to_excel("air_quality_data.xlsx",)
df.to_excel(
"air_quality_data.xlsx",
)
print("File saved to disk as air_quality_data.xlsx")
else:
raise Exception(
Expand All @@ -147,7 +153,8 @@ def _parse_data(
"""Parse the data from the API response
Args:
data_obj (JSON object returned by json.loads): The data from the API response.
data_obj (JSON object returned by json.loads): The data from the API's
response.
city (str): The city name.
params (List[str]): The parameters to parse.
Expand Down Expand Up @@ -197,27 +204,44 @@ def _AQI_meaning(self, aqi: float) -> Tuple[str, str]:

if 0 <= aqi <= 50:
AQI_meaning = "Good"
AQI_health_implications = "Air quality is considered satisfactory, and air pollution poses little or no risk"
AQI_health_implications = (
"Air quality is considered satisfactory, "
"and air pollution poses little or no risk"
)
elif 51 <= aqi <= 100:
AQI_meaning = "Moderate"
AQI_health_implications = "Air quality is acceptable; however, for some pollutants there may be a moderate health concern for a very small number of people who are unusually sensitive to air pollution."
AQI_health_implications = (
"Air quality is acceptable; however, for some pollutants "
"there may be a moderate health concern for a very small "
"number of people who are unusually sensitive to air pollution."
)
elif 101 <= aqi <= 150:
AQI_meaning = "Unhealthy for sensitive group"
AQI_health_implications = "Members of sensitive groups may experience health effects. The general public is not likely to be affected."
AQI_health_implications = (
"Members of sensitive groups may experience health effects. "
"The general public is not likely to be affected."
)
elif 151 <= aqi <= 200:
AQI_meaning = "Unhealthy"
AQI_health_implications = "Everyone may begin to experience health effects; members of sensitive groups may experience more serious health effects."
AQI_health_implications = (
"Everyone may begin to experience health effects; members of "
"sensitive groups may experience more serious health effects."
)
elif 201 <= aqi <= 300:
AQI_meaning = "Very Unhealthy"
AQI_health_implications = "Health warnings of emergency conditions. The entire population is more likely to be affected."
AQI_health_implications = (
"Health warnings of emergency conditions. "
"The entire population is more likely to be affected."
)
elif 301 <= aqi <= 500:
AQI_meaning = "Hazardous"
AQI_health_implications = (
"Health alert: everyone may experience more serious health effects."
)
else:
raise Exception(
f"{aqi} is not valid air quality index value. Should be between 0 to 500."
f"{aqi} is not valid air quality index value. "
"Should be between 0 to 500."
)

return AQI_meaning, AQI_health_implications
Expand Down Expand Up @@ -269,8 +293,10 @@ def get_coordinate_air(
Args:
lat (float): Latitude
lon (float): Longitude
data_format (str): File format for data. Defaults to 'df'. Choose from 'csv', 'json', 'xlsx'.
df (pandas.DataFrame, optional): An existing dataframe to append the data to.
data_format (str): File format for data. Defaults to 'df'.
Choose from 'csv', 'json', 'xlsx'.
df (pandas.DataFrame, optional): An existing dataframe to
append the data to.
params (List[str], optional): A list of parameters to get data for.
Gets all parameters by default.
Expand Down Expand Up @@ -302,8 +328,10 @@ def get_city_air(
Args:
city (str): The city to get data for.
data_format (str): File format for data. Defaults to 'df'. Choose from 'csv', 'json', 'xlsx'.
df (pandas.DataFrame, optional): An existing dataframe to append the data to.
data_format (str): File format for data. Defaults to 'df'.
Choose from 'csv', 'json', 'xlsx'.
df (pandas.DataFrame, optional): An existing dataframe to
append the data to.
params (List[str], optional): A list of parameters to get data for.
Gets all parameters by default.
Expand All @@ -326,7 +354,8 @@ def get_city_air(
)

raise Exception(
f'There is a problem with city "{city}", the returned data: {data_obj}'
f'There is a problem with city "{city}", '
"the returned data: {data_obj}"
)

row = self._parse_data(data_obj, city, params)
Expand All @@ -345,8 +374,10 @@ def get_multiple_coordinate_air(
Args:
locations (list): A list of pair (latitude,longitude) to get data for.
data_format (str): File format. Defaults to 'df'. Choose from 'csv', 'json', 'xlsx'.
df (pandas.DataFrame, optional): An existing dataframe to append the data to.
data_format (str): File format. Defaults to 'df'.
Choose from 'csv', 'json', 'xlsx'.
df (pandas.DataFrame, optional): An existing dataframe to
append the data to.
params (List[str], optional): A list of parameters to get data for.
Gets all parameters by default.
Expand All @@ -355,7 +386,8 @@ def get_multiple_coordinate_air(
selected another data format, this dataframe will be empty)
"""
for loc in locations:
# This just makes sure that it's always a returns a pd.DataFrame. Makes mypy happy.
# This just makes sure that it's always a returns a pandas.DataFrame.
# Makes mypy happy.
df = pandas.DataFrame(
self.get_coordinate_air(loc[0], loc[1], df=df, params=params)
)
Expand All @@ -376,8 +408,10 @@ def get_range_coordinates_air(
Args:
lower_bound (tuple): start coordinate
upper_bound (tuple): end coordinate
data_format (str): File format. Defaults to 'df'. Choose from 'csv', 'json', 'xlsx'.
df (pandas.DataFrame, optional): An existing dataframe to append the data to.
data_format (str): File format. Defaults to 'df'.
Choose from 'csv', 'json', 'xlsx'.
df (pandas.DataFrame, optional): An existing dataframe to
append the data to.
params (List[str], optional): A list of parameters to get data for.
Gets all parameters by default.
Expand All @@ -403,23 +437,30 @@ def get_multiple_city_air(
Args:
cities (list): A list of cities to get data for.
data_format (str): File format. Defaults to 'df'. Choose from 'csv', 'json', 'xlsx'.
data_format (str): File format. Defaults to 'df'.
Choose from 'csv', 'json', 'xlsx'.
params (List[str], optional): A list of parameters to get data for.
Gets all parameters by default.
df (pandas.DataFrame, optional): An existing dataframe to append the data to.
df (pandas.DataFrame, optional): An existing dataframe to
append the data to.
Returns:
pandas.DataFrame: The dataframe containing the data. (If you
selected another data format, this dataframe will be empty)
"""
for city in cities:
# This just makes sure that it's always a returns a pd.DataFrame. Makes mypy happy.
# This just makes sure that it's always a returns a pandas.DataFrame.
# Makes mypy happy.
df = pandas.DataFrame(self.get_city_air(city=city, df=df, params=params))

df.reset_index(inplace=True, drop=True)
return self._format_output(data_format, df)

def get_specific_parameter(self, city: str, air_param: str = "",) -> float:
def get_specific_parameter(
self,
city: str,
air_param: str = "",
) -> float:
"""Get specific parameter as a float
Args:
Expand Down

0 comments on commit 952804d

Please sign in to comment.