Skip to content

Commit

Permalink
Format code in black style (ruff format)
Browse files Browse the repository at this point in the history
Also includes small number of other lint-style cleanups.
  • Loading branch information
dmcc committed Sep 12, 2024
1 parent 68f4d91 commit e1ece33
Show file tree
Hide file tree
Showing 19 changed files with 615 additions and 465 deletions.
13 changes: 4 additions & 9 deletions atmospy/__init__.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,16 @@
from importlib.metadata import version

# import warnings
# import pandas as pd
# import numpy as np
# import math
# import os
import matplotlib as mpl

from .utils import *
from .rcmod import *
from .relational import *
from .trends import *
from .rose import *
from .stats import *
from .trends import *
from .utils import *

# Capture the original matplotlib rcParams
import matplotlib as mpl
_orig_rc_params = mpl.rcParams.copy()

# Determine the atmospy version
__version__ = version('atmospy')
__version__ = version("atmospy")
17 changes: 3 additions & 14 deletions atmospy/distributions.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,7 @@
from .utils import (
remove_na,
)
from seaborn import (
FacetGrid,
)
__all__ = []

__all__ = ["psdplot", ]


def psdplot(
data=None, *,
x=None, y=None, row=None, col=None,
**kwargs
):
def psdplot(data=None, *, x=None, y=None, row=None, col=None, **kwargs):
"""Plot a particle size distribution.
Parameters
Expand All @@ -32,4 +21,4 @@ def psdplot(


def bananaplot():
return
return
45 changes: 28 additions & 17 deletions atmospy/rcmod.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,24 @@

__all__ = ["set_theme"]

def set_theme(context="notebook", style='ticks', palette='colorblind',
font='sans-serif', font_scale=1., color_codes=True, rc=None):

def set_theme(
context="notebook",
style="ticks",
palette="colorblind",
font="sans-serif",
font_scale=1.0,
color_codes=True,
rc=None,
):
"""Change the look and feel of your plots with one simple function.
This is a simple pass-through function to the Seaborn function of the
same name, but with different default parameters. For complete information
This is a simple pass-through function to the Seaborn function of the
same name, but with different default parameters. For complete information
and a better description that I can provide, please see the Seaborn docs
`here <https://seaborn.pydata.org/generated/seaborn.set_theme.html#seaborn.set_theme>`_.
This mostly passes down to the seaborn function of the same name, but with a
This mostly passes down to the seaborn function of the same name, but with a
few opinions mixed in.
Parameters
Expand All @@ -23,28 +31,31 @@ def set_theme(context="notebook", style='ticks', palette='colorblind',
palette : string or sequence, optional
Set the color palette, by default 'colorblind'
font : string, optional
Set the font family, by default 'sans-serif'. See the
Set the font family, by default 'sans-serif'. See the
matplotlib font manager for more information.
font_scale : float, optional
Independently scale the font size, by default 1
color_codes : bool, optional
If `True`, remap the shorthand color codes assuming you are
If `True`, remap the shorthand color codes assuming you are
using a seaborn palette, by default True
rc : dict or None, optional
Pass through a dictionary of rc parameter mappings to override
Pass through a dictionary of rc parameter mappings to override
the defaults, by default None
"""
default_rcparams = {
"mathtext.default": "regular"
}

default_rcparams = {"mathtext.default": "regular"}

if rc is not None:
rc = dict(default_rcparams, **rc)
else:
rc = default_rcparams

sns.set_theme(
context=context, style=style, palette=palette,
font=font, font_scale=font_scale, color_codes=color_codes, rc=rc
context=context,
style=style,
palette=palette,
font=font,
font_scale=font_scale,
color_codes=color_codes,
rc=rc,
)
137 changes: 76 additions & 61 deletions atmospy/rose.py
Original file line number Diff line number Diff line change
@@ -1,32 +1,47 @@
"""This file contains the wind and pollution rose figures."""
import seaborn as sns
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

import math
from .utils import (
check_for_numeric_cols,
)

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns

from .utils import check_for_numeric_cols

# Turn off chained assignment warnings
pd.options.mode.chained_assignment = None

__all__ = ["pollutionroseplot"]

def pollutionroseplot(data=None, *, ws=None, wd=None, pollutant=None,
faceted=False, segments=12, bins=[0, 10, 100, 1000], suffix="a.u.",
calm=0., lw=1, legend=True, palette="flare",
title=None, **kwargs):

def pollutionroseplot(
data=None,
*,
ws=None,
wd=None,
pollutant=None,
faceted=False,
segments=12,
bins=[0, 10, 100, 1000],
suffix="a.u.",
calm=0.0,
lw=1,
legend=True,
palette="flare",
title=None,
**kwargs,
):
"""Plot the intensity and directionality of a variable on a traditional wind-rose plot.
This function is a modified version of `Phil Hobson's work <https://gist.github.com/phobson/41b41bdd157a2bcf6e14>`_.
Traditionally, a wind rose plots wind speed and direction so that you can see from what
direction is the wind coming from and at what velocity. For air quality purposes, we
often wonder whether or not there is directionality to the intensity of a certain
air pollutant. Well, look no further. This plot allows you to easily visualize the
Traditionally, a wind rose plots wind speed and direction so that you can see from what
direction is the wind coming from and at what velocity. For air quality purposes, we
often wonder whether or not there is directionality to the intensity of a certain
air pollutant. Well, look no further. This plot allows you to easily visualize the
directionality of a pollutant.
Parameters
----------
data : :class:`pandas.DataFrame`
Expand All @@ -44,13 +59,13 @@ def pollutionroseplot(data=None, *, ws=None, wd=None, pollutant=None,
, by default 12
bins : list or array of floats, optional
An array of floats corresponding to the bin boundaries
for `pollutant`; if the last entry is not inf, it will be
for `pollutant`; if the last entry is not inf, it will be
automatically added, by default [0, 10, 100, 1000]
suffix : str, optional
The suffix (or units) to use on the labels for `pollutant`, by default "a.u."
calm : float, optional
Set the definition of calm conditions; data under calm winds
will not be used to compute the statistics and
Set the definition of calm conditions; data under calm winds
will not be used to compute the statistics and
will be shown on the plot as blank in the center, by default 0.
lw : int, optional
Set the line width, by default 1
Expand All @@ -60,34 +75,34 @@ def pollutionroseplot(data=None, *, ws=None, wd=None, pollutant=None,
Select the color palette to use, by default "flare"
title : str, optional
Set the figure title, by default None
Returns
-------
:class:`matplotlib.axes._axes.Axes`
Examples
--------
Using defaults, plot the pollution rose for PM2.5:
>>> df = atmospy.load_dataset("air-sensors-met")
>>> atmospy.pollutionroseplot(data=df, ws="ws", wd="wd", pollutant="pm25")
"""
check_for_numeric_cols(data, [ws, wd, pollutant])

# if the bins don't end in inf, add it
if not np.isinf(bins[-1]):
bins.append(np.inf)
#

#
bins = np.asarray(bins)

# setup the color palette
cp = sns.color_palette(palette, n_colors=bins.shape[0]-1)
cp = sns.color_palette(palette, n_colors=bins.shape[0] - 1)

# convert the number of segments into the wind bins
wd_segments = np.linspace(0, 360, segments+1)
wd_segments = np.linspace(0, 360, segments + 1)

def _cat_pollutant_labels(bins, suffix):
"""_summary_
Expand All @@ -104,66 +119,66 @@ def _cat_pollutant_labels(bins, suffix):
list_of_labels.append(f">{lowerbound:.0f} {suffix}")
else:
list_of_labels.append(f"{lowerbound:.0f} to {upperbound:.0f} {suffix}")

return list_of_labels

def _compute_bar_dims(thetas):
thetas = (thetas[:-1] + thetas[1:]) / 2.
thetas = (thetas[:-1] + thetas[1:]) / 2.0

midpoints = [math.radians(theta) for theta in thetas]
width = math.radians(360./thetas.shape[0])
width = math.radians(360.0 / thetas.shape[0])

return midpoints, width

# compute the percentage of calm datapoints
# where calm is anything with a windspeed < `calm`
pct_calm = 100*data[data[ws] <= calm].shape[0] / data.shape[0]
pct_calm = 100 * data[data[ws] <= calm].shape[0] / data.shape[0]

# group the data by bin and normalize
rv = (
data[data[ws] > calm]
.assign(
_cp=lambda x: pd.cut(
data[pollutant],
bins=bins,
data[pollutant],
bins=bins,
right=True,
labels=_cat_pollutant_labels(bins, suffix)
labels=_cat_pollutant_labels(bins, suffix),
)
)
.assign(
_wb=lambda x: pd.cut(
data[wd],
bins=wd_segments,
right=True,
labels=(wd_segments[:-1]+wd_segments[1:])/2.
labels=(wd_segments[:-1] + wd_segments[1:]) / 2.0,
)
)
.groupby(["_cp", "_wb"])
.size()
.unstack(level="_cp")
.fillna(0.)
.fillna(0.0)
.sort_index(axis=1)
.applymap(lambda x: 100 * x / data.shape[0])
)

# compute the bar dims
bar_midpoints, bar_width = _compute_bar_dims(wd_segments)

# if plotting onto a FacetGrid, get the current axis, otherwise create one
if faceted:
ax = plt.gca()
else:
fig = plt.gcf()
ax = fig.add_subplot(111, projection='polar')
ax = fig.add_subplot(111, projection="polar")

ax.set_theta_direction("clockwise")
ax.set_theta_zero_location("N")

# determine the buffer at the center of the plot
# this is where ws <= `calm` and is evenly spread
# this is where ws <= `calm` and is evenly spread
# across all angles
buffer = pct_calm / segments

for i, (innerbar, outerbar) in enumerate(zip(rv.columns[:-1], rv.columns[1:])):
if i == 0:
# for the first bar, we need to plot the calm hole in the center first
Expand All @@ -174,33 +189,33 @@ def _compute_bar_dims(thetas):
bottom=buffer,
label=innerbar,
lw=lw,
color=cp[i]
color=cp[i],
)

ax.bar(
bar_midpoints,
rv[outerbar].values,
width=bar_width,
label=outerbar,
bottom=buffer + rv.cumsum(axis=1)[innerbar].values,
lw=lw,
color=cp[i+1]
color=cp[i + 1],
)

if legend:
ax.legend(
loc="center left",
handlelength=1,
handlelength=1,
handleheight=1,
bbox_to_anchor=(1.1, 0, 0.5, 1)
bbox_to_anchor=(1.1, 0, 0.5, 1),
)

if title:
ax.set_title(title)

# clean up the ticks and things
ax.set_xticks([math.radians(x) for x in [0, 45, 90, 135, 180, 225, 270, 315]])
ax.set_xticklabels(["N", "NE", "E", "SE", "S", "SW", "W", "NW"])
ax.set_yticklabels([])
return ax

return ax
Loading

0 comments on commit e1ece33

Please sign in to comment.