Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add section on variable naming #7

Merged
merged 45 commits into from
Jul 3, 2024
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
9b9e204
refactor slides to break into separate sections.
jatkinson1000 Jun 18, 2024
9ec93cf
add slide on naming standards
AmyOctoCat Jun 19, 2024
4fb12be
add warning about the use of f strings in logging statements
AmyOctoCat Jun 19, 2024
1c2418f
Adding instructions for naming part of exercise.
AmyOctoCat Jun 19, 2024
7d7aed6
changing some of the naming in the final version of precipitation_cli…
AmyOctoCat Jun 19, 2024
a07e7c4
hopefully made more readable
AmyOctoCat Jun 19, 2024
d273ee7
naming tweeks
AmyOctoCat Jun 19, 2024
8383480
revert changes to pluralise name for array. Not sure what best practi…
AmyOctoCat Jun 19, 2024
99042f7
add a line about boolean naming
AmyOctoCat Jun 20, 2024
1083b88
add a line about boolean naming
AmyOctoCat Jun 20, 2024
3ef0967
formatting
AmyOctoCat Jun 20, 2024
9652abe
Update exercises/00_final/precipitation_climatology.py
AmyOctoCat Jun 20, 2024
c37087c
fix excpetion raising bug introduced in this branch
AmyOctoCat Jun 20, 2024
97cd877
Merge branch 'add_section_on_variable_naming' of github.com:Cambridge…
AmyOctoCat Jun 20, 2024
6752f63
grammar in slide.
AmyOctoCat Jun 20, 2024
3c87e6f
pull naming into it's own section
AmyOctoCat Jun 20, 2024
e88749e
resolve merge conflict
AmyOctoCat Jun 20, 2024
2d2ace5
return matplotlib import to the standard plt and add small fix
AmyOctoCat Jun 20, 2024
6a8fdb0
fix merge conflicts
AmyOctoCat Jun 20, 2024
694c8fe
further renaming and some additional documentation
AmyOctoCat Jun 26, 2024
fa01f3b
further renaming
AmyOctoCat Jun 26, 2024
93caff0
further naming changes
AmyOctoCat Jun 26, 2024
e4c2fd5
further naming changes
AmyOctoCat Jun 26, 2024
09c52cc
revert naming of columns in the netcdf as editing netcdf file is too …
AmyOctoCat Jun 26, 2024
67cb57e
remove comment as have confirmed that this hasn't introduced a runtim…
AmyOctoCat Jun 26, 2024
a55b60c
add some examples into the slides
AmyOctoCat Jun 26, 2024
b60049f
add to example slide
AmyOctoCat Jun 26, 2024
471dfec
finish renaming in exercise 5
AmyOctoCat Jun 26, 2024
40c5912
renumber exercises
AmyOctoCat Jun 26, 2024
c4e37c6
include the naming slides in the main quarto file
AmyOctoCat Jun 26, 2024
7b694b1
add base code for exercise on naming
AmyOctoCat Jun 26, 2024
6710ba1
update naming in exercise 4
AmyOctoCat Jun 26, 2024
e6168aa
update exercise 4 for renaming
AmyOctoCat Jun 26, 2024
0fc9ec8
run black in all the exercises after black
AmyOctoCat Jun 26, 2024
f6ef57b
modified the wrong exercise
AmyOctoCat Jun 26, 2024
c71c31b
missed file naming
AmyOctoCat Jun 26, 2024
28e9359
renumber exercises in slides and a dd a bit of extra detail
AmyOctoCat Jun 27, 2024
fe0c39e
reformatting and splitting black and pylint sections
AmyOctoCat Jun 27, 2024
61e5ced
Update exercises 1 and 2 with blank lines to match changes to later e…
jatkinson1000 Jun 27, 2024
cf759c8
remove redundant use of xr.DataArray wrapping around array multiplica…
AmyOctoCat Jul 3, 2024
99ef3a9
change font size in slides
AmyOctoCat Jul 3, 2024
8e478f2
remove remaining uses of assert in production code
AmyOctoCat Jul 3, 2024
f9a016d
formatting changes to slides on naming
AmyOctoCat Jul 3, 2024
50e4972
Merge pull request #13 from Cambridge-ICCS/jatkinson1000-naming-patch
AmyOctoCat Jul 3, 2024
6539266
Minor typographical updates.
jatkinson1000 Jul 3, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
152 changes: 86 additions & 66 deletions exercises/00_final/precipitation_climatology.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,18 @@ def convert_precipitation_units(precipitation_in_kg_per_m_squared_s):
Parameters
----------
precipitation_in_kg_per_m_squared_s : xarray.DataArray
xarray DataArray containing model precipitation data
xarray DataArray containing model precipitation data in kg m-2 s-1

Returns
-------
precipitation_in_mm_per_day : xarray.DataArray
the input DataArray with precipitation units modified
the input DataArray with precipitation units modified to mm day-1
"""
# density 1000 kg m-3 => 1 kg m-2 == 1 mm
# There are 60*60*24 = 86400 seconds per day
precipitation_in_mm_per_day = xr.DataArray(precipitation_in_kg_per_m_squared_s * 86400)
precipitation_in_mm_per_day = xr.DataArray(
precipitation_in_kg_per_m_squared_s * 86400
)

precipitation_in_mm_per_day.attrs["units"] = "mm/day"

Expand All @@ -40,32 +42,30 @@ def convert_precipitation_units(precipitation_in_kg_per_m_squared_s):
return precipitation_in_mm_per_day


# I think it would be good to give more detail here about what the dimensions and
# content of the input array needs to be, to save the reader having to go through
# the code and infer it in order to use the method. Would it also be possible to give
# the input variable a more specific name?
def plot_zonally_averaged_precipitation(data):
def plot_zonally_averaged_precipitation(precipitation_data):
"""
Plot zonally-averaged precipitation data and save to file.

Parameters
----------
data : xarray.DataArray
xarray DataArray containing model data
precipitation_data : xarray.DataSet
xarray DataSet containing precipitation model data, specifying precipitation in
[kg m-2 s-1] at given latitudes, longitudes and time. The Dataset should contain
four aligned DataArrays: precipitation, latitude, longitude and time.

Returns
-------
None

"""
zonal_precipitation = data["precipitation"].mean("longitude", keep_attrs=True)
zonal_precipitation = precipitation_data["pr"].mean("lon", keep_attrs=True)

figure, axes = plt.subplots(nrows=4, ncols=1, figsize=(12, 8))

zonal_precipitation.sel(lat=[0]).plot.line(ax=axes[0], hue="latitude")
zonal_precipitation.sel(lat=[-20, 20]).plot.line(ax=axes[1], hue="latitude")
zonal_precipitation.sel(lat=[-45, 45]).plot.line(ax=axes[2], hue="latitude")
zonal_precipitation.sel(lat=[-70, 70]).plot.line(ax=axes[3], hue="latitude")
zonal_precipitation.sel(lat=[0]).plot.line(ax=axes[0], hue="lat")
zonal_precipitation.sel(lat=[-20, 20]).plot.line(ax=axes[1], hue="lat")
zonal_precipitation.sel(lat=[-45, 45]).plot.line(ax=axes[2], hue="lat")
zonal_precipitation.sel(lat=[-70, 70]).plot.line(ax=axes[3], hue="lat")

plt.tight_layout()
for axis in axes:
AmyOctoCat marked this conversation as resolved.
Show resolved Hide resolved
Expand All @@ -79,16 +79,17 @@ def plot_zonally_averaged_precipitation(data):

plt.savefig("zonal_map.png", dpi=200) # Save figure to file

# could data be named more specifically and more detail be given in the docstring about
# what the dimension and contents of the array are?
def get_country_annual_average(data, countries):

def get_country_annual_average(precipitation_data, countries):
"""
Calculate annual precipitation averages for countries and save to file.

Parameters
----------
data : xarray.DataArray
xarray DataArray containing model data
precipitation_data : xarray.DataSet
xarray DataSet containing precipitation model data, specifying precipitation in
[kg m-2 s-1] at given latitudes, longitudes and time. The Dataset should contain
four aligned DataArrays: precipitation, latitude, longitude and time.
countries : dict(str: str)
dictionary mapping country names to regionmask codes. For a list see:
regionmask.defined_regions.natural_earth_v5_0_0.countries_110.regions
Expand All @@ -98,62 +99,77 @@ def get_country_annual_average(data, countries):
None

"""
data_average = data["precipitation"].groupby("time.year").mean("time",
keep_attrs=True)
data_average = convert_precipitation_units(data_average)

# would it be possible to give land a more specific name?
land = (regionmask.
defined_regions.
natural_earth_v5_0_0
.countries_110.mask(data_average))

with open("data.txt", "w", encoding="utf-8") as datafile:
# could k and v be named more specifically?
for k, v in countries.items():
data_avg_mask = data_average.where(land.cf == v)

for year in data_avg_mask.year.values:
precipitation = data_avg_mask.sel(year=year).mean().values
datafile.write(f"{k.ljust(25)} {year} : {precipitation:2.3f} mm/day\n")
annual_average_precipitation = (
precipitation_data["pr"].groupby("time.year").mean("time", keep_attrs=True)
)
annual_average_precipitation = convert_precipitation_units(
annual_average_precipitation
)

country_mask = regionmask.defined_regions.natural_earth_v5_0_0.countries_110.mask(
annual_average_precipitation
)

with open(
"annual_average_precipitation_by_country.txt", "w", encoding="utf-8"
) as datafile:
for country_name, country_code in countries.items():
country_annual_average_precipitation = annual_average_precipitation.where(
country_mask.cf == country_code
)

for year in country_annual_average_precipitation.year.values:
precipitation = (
country_annual_average_precipitation.sel(year=year).mean().values
)
datafile.write(
f"{country_name.ljust(25)} {year} : {precipitation:2.3f} mm/day\n"
)
datafile.write("\n")


# could data be named more specifically and more detail be given in the docstring about
# what the dimension and contents of the array are?
def plot_enso_hovmoller_diagram(data):
def plot_enso_hovmoller_diagram(precipitation_data):
"""
Plot Hovmöller diagram of equatorial precipitation to visualise ENSO.

Parameters
----------
data : xarray.DataArray
xarray DataArray containing model data
precipitation_data : xarray.DataSet
xarray DataSet containing precipitation model data, specifying precipitation in
[kg m-2 s-1] at given latitudes, longitudes and time. The Dataset should contain
four aligned DataArrays: precipitation, latitude, longitude and time.

Returns
-------
None

"""
enso = (
data["precipitation"]
precipitation_data["pr"]
.sel(lat=slice(-1, 1))
.sel(lon=slice(120, 280))
.mean(dim="latitude", keep_attrs=True)
.mean(dim="lat", keep_attrs=True)
AmyOctoCat marked this conversation as resolved.
Show resolved Hide resolved
)

enso.plot()
plt.savefig("enso.png", dpi=200) # Save figure to file


def create_precipitation_climatology_plot(climatology_data, model_name, season, mask=None, plot_gridlines=False, levels=None):
def create_precipitation_climatology_plot(
seasonal_average_precipitation,
model_name,
season,
mask=None,
plot_gridlines=False,
levels=None,
):
"""
Plot the precipitation climatology.

Parameters
----------
climatology_data : xarray.DataArray
Precipitation climatology data
seasonal_average_precipitation : xarray.DataArray
Precipitation climatology data. Seasonally averaged precipitation data.
model_name : str
Name of the climate model
season : str
Expand Down Expand Up @@ -181,12 +197,12 @@ def create_precipitation_climatology_plot(climatology_data, model_name, season,
subplot_kw={"projection": ccrs.PlateCarree(central_longitude=180)},
)

climatology_data.sel(season=season).plot.contourf(
seasonal_average_precipitation.sel(season=season).plot.contourf(
ax=geo_axes,
levels=levels,
extend="max",
transform=ccrs.PlateCarree(),
cbar_kwargs={"label": climatology_data.units},
cbar_kwargs={"label": seasonal_average_precipitation.units},
cmap=cmocean.cm.rain,
)

Expand Down Expand Up @@ -230,13 +246,13 @@ def create_precipitation_climatology_plot(climatology_data, model_name, season,


def main(
precipitation_netcdf_file,
season="DJF",
output_file="output.png",
plot_gridlines=False,
mask=None,
cbar_levels=None,
countries=None,
precipitation_netcdf_file,
season="DJF",
output_file="output.png",
plot_gridlines=False,
mask=None,
cbar_levels=None,
countries=None,
):
"""
Run the program for producing precipitation plots.
Expand Down Expand Up @@ -267,31 +283,35 @@ def main(
if countries is None:
countries = {"United Kingdom": "GB"}

input_data = xr.open_dataset(precipitation_netcdf_file)
precipitation_data = xr.open_dataset(precipitation_netcdf_file)

plot_zonally_averaged_precipitation(input_data)
plot_enso_hovmoller_diagram(input_data)
get_country_annual_average(input_data, countries)
plot_zonally_averaged_precipitation(precipitation_data)
plot_enso_hovmoller_diagram(precipitation_data)
get_country_annual_average(precipitation_data, countries)

climatology = input_data["precipitation"].groupby("time.season").mean("time", keep_attrs=True)
seasonal_average_precipitation = (
precipitation_data["pr"].groupby("time.season").mean("time", keep_attrs=True)
)

try:
input_units = climatology.attrs["units"]
input_units = seasonal_average_precipitation.attrs["units"]
except KeyError as exc:
raise KeyError(
"Precipitation variable in {pr_file} must have a units attribute"
) from exc

if input_units == "kg m-2 s-1":
climatology = convert_precipitation_units(climatology)
seasonal_average_precipitation = convert_precipitation_units(
seasonal_average_precipitation
)
elif input_units == "mm/day":
pass
else:
raise ValueError("""Input units are not 'kg m-2 s-1' or 'mm/day'""")

create_precipitation_climatology_plot(
climatology,
input_data.attrs["source_id"],
seasonal_average_precipitation,
precipitation_data.attrs["source_id"],
season,
mask=mask,
plot_gridlines=plot_gridlines,
Expand Down
20 changes: 20 additions & 0 deletions exercises/03_naming/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Exercise 3 - Naming for code clarity

Look through the code for any names of methods or variables that could be improved or
clarified and update them. Note if you are using an IDE like Intellij or VSCode,
you can use automatic renaming.
Can you find an example from each of the suggestions listed below?
AmyOctoCat marked this conversation as resolved.
Show resolved Hide resolved
Does this make the code easier to follow?

Consider the following:

- The name should show the intention, think about how someone else might read it (this could be future you)
- Use pronounceable names e.g. `mass` not `ms`, `stem` not `stm`
- avoid abbreviations and single letter variable names where possible
- One word per concept e.g. choose one of `put`, `insert`, `add` in the same code base
- Use names that can be searched
- Describe content rather than storage type
- Naming booleans, use prefixes like `is`, `has` or `can` and avoid negations like `not_green`
- Plurals to indicate groups, e.g. a list of dog objects would be `dogs`, not `dog_list`
- Keep it simple and use technical terms where appropriate
- Use explaining variables
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Exercise 3 - Linting
# Exercise 4 - Linting

This exercise contains the original code after applying black.

Expand Down
File renamed without changes.
Loading