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: Apply accessor #203

Open
wants to merge 26 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
5f0babf
ENH: New function - Apply to sweeps
syedhamidali Aug 31, 2024
f3c28b0
ADD: Added new function for volume operation
syedhamidali Aug 31, 2024
be9111f
ADD: Test apply_to_sweeps
syedhamidali Aug 31, 2024
88ab142
FIX: test_util apply_to_sweeps
syedhamidali Aug 31, 2024
22f4331
FIX: Pytest fix for apply_to_sweeps
syedhamidali Aug 31, 2024
1d717ff
ADD: Added accessor apply
syedhamidali Aug 31, 2024
bf4460b
FIX: Implemented Suggestions raised by Kai
syedhamidali Aug 31, 2024
d11fb81
FIX: DataTree node issue
syedhamidali Sep 1, 2024
3733538
MNT: update history
syedhamidali Sep 1, 2024
71a084f
ADD: apply_to_volume alias for apply_to_sweeps + fix apply_to_sweeps
syedhamidali Sep 1, 2024
c910665
FIX: fix apply_to_volume
syedhamidali Sep 1, 2024
820e399
ADD: added an example in the docstring of function
syedhamidali Sep 1, 2024
0ba03ff
FIX: added an example in the docstring of function apply
syedhamidali Sep 1, 2024
fe725d6
Merge branch 'main' into sweeps_accessor
syedhamidali Sep 19, 2024
98411d1
FIX: util tests and update history
syedhamidali Sep 19, 2024
b9f7680
Merge branch 'main' into sweeps_accessor
syedhamidali Sep 20, 2024
2f8d73f
MNT: Drop unrelated history
syedhamidali Sep 23, 2024
2597498
ADD: Apply Accessor Demo Notebook
syedhamidali Sep 23, 2024
84ad266
FIX: Linting issues
syedhamidali Sep 23, 2024
c75cb73
ADD: Added notebook to the docs/usage.md
syedhamidali Sep 24, 2024
4c38116
FIX: Fix markdown cell in apply accessor nb
syedhamidali Sep 24, 2024
eb3d560
FIX: Fix markdown cell in apply accessor nb trial 2
syedhamidali Sep 24, 2024
4fd8554
FIX: Fix markdown cell in apply accessor nb trial 3
syedhamidali Sep 24, 2024
488f1b0
FIX: Fix markdown cell in apply accessor nb trial 4
syedhamidali Sep 24, 2024
c0e62b3
Resolve Conflicts
syedhamidali Sep 30, 2024
393d0ea
Merge branch 'main' into sweeps_accessor
syedhamidali Sep 30, 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
3 changes: 2 additions & 1 deletion docs/history.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## Development Version

* ADD: Added a new accessor `apply` for volume operations ({pull}`203`) by [@syedhamidali](https://github.com/syedhamidali).
* ADD: Added `apply_to_sweeps` function for applying custom operations to all sweeps in a `DataTree` radar volume Implemented by [@syedhamidali](https://github.com/syedhamidali), ({pull}`202`).

## 0.6.5 (2024-09-20)
Expand All @@ -16,7 +17,7 @@

## 0.6.3 (2024-08-13)

FIX: use rstart in meter for ODIM_H5/V2_4 ({issue}`196`) by [@kmuehlbauer](https://github.com/kmuehlbauer), ({pull}`197`) by [@kmuehlbauer](https://github.com/kmuehlbauer).
* FIX: use rstart in meter for ODIM_H5/V2_4 ({issue}`196`) by [@kmuehlbauer](https://github.com/kmuehlbauer), ({pull}`197`) by [@kmuehlbauer](https://github.com/kmuehlbauer).

## 0.6.2 (2024-08-12)

Expand Down
1 change: 1 addition & 0 deletions docs/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ datamodel
importers
exporters
notebooks/Accessors
notebooks/Apply_Accessor
```

```{toctree}
Expand Down
370 changes: 370 additions & 0 deletions examples/notebooks/Apply_Accessor.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,370 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "0",
"metadata": {},
"source": [
"# Apply Accessor"
]
},
{
"cell_type": "markdown",
"id": "1",
"metadata": {},
"source": [
"Have you ever wondered how to efficiently apply operations to a full volume of radar sweeps, rather than processing each sweep individually? \n",
"\n",
"Xradar has the solution: the `apply` accessor. In this notebook, we’ll explore how you can leverage Xradar’s powerful `apply` functionality to perform volume-level operations on radar data.\n",
"\n",
"In radar data analysis, it's common to work with multiple sweeps in a radar volume. Xradar allows you to apply custom functions across the entire dataset with ease, making complex operations, such as filtering reflectivity or calculating rain rate, efficient and scalable.\n",
"\n",
"Here's what you'll learn in this notebook:\n",
"- How to load and inspect radar data using Xradar’s `DataTree`.\n",
"- How to apply functions to process all radar sweeps in one go.\n",
"- How to visualize radar variables like reflectivity and rain rate before and after processing.\n",
"\n",
"Let’s dive into radar volume processing and learn how to apply operations across multiple sweeps efficiently."
]
},
{
"cell_type": "markdown",
"id": "2",
"metadata": {},
"source": [
"## Imports"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "3",
"metadata": {},
"outputs": [],
"source": [
"import matplotlib.pyplot as plt\n",
"from matplotlib import gridspec\n",
"from open_radar_data import DATASETS\n",
"\n",
"import xradar as xd"
]
},
{
"cell_type": "markdown",
"id": "4",
"metadata": {},
"source": [
"## Load Read/Data"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5",
"metadata": {},
"outputs": [],
"source": [
"# Fetch the sample radar file\n",
"filename = DATASETS.fetch(\"sample_sgp_data.nc\")\n",
"\n",
"# Open the radar file into a DataTree object\n",
"dtree = xd.io.open_cfradial1_datatree(filename)\n",
"dtree = dtree.xradar.georeference()"
]
},
{
"cell_type": "markdown",
"id": "6",
"metadata": {},
"source": [
"## Exploring Data Variables"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7",
"metadata": {},
"outputs": [],
"source": [
"dtree"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "8",
"metadata": {},
"outputs": [],
"source": [
"for var in dtree[\"sweep_0\"].ds:\n",
" print(var)"
]
},
{
"cell_type": "markdown",
"id": "9",
"metadata": {},
"source": [
"## Apply"
]
},
{
"cell_type": "markdown",
"id": "10",
"metadata": {},
"source": [
"We define custom functions like `filter_radar` that filters radar reflectivity based on certain conditions, and `calculate_rain_rate` which is self explanatory, and use `apply` accessor to implement these."
]
},
{
"cell_type": "markdown",
"id": "11",
"metadata": {},
"source": [
"### Example #1"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "12",
"metadata": {},
"outputs": [],
"source": [
"# It is just a demonstration, you can ignore the logic\n",
"def filter_radar(ds):\n",
" ds[\"DBZH_Filtered\"] = ds.where(\n",
" (ds[\"corrected_reflectivity_horizontal\"] > 10)\n",
" & (ds[\"corrected_reflectivity_horizontal\"] < 70)\n",
" & (ds[\"copol_coeff\"] > 0.8)\n",
" )[\"corrected_reflectivity_horizontal\"]\n",
" return ds"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "13",
"metadata": {},
"outputs": [],
"source": [
"# Apply the function across all sweeps\n",
"dtree = dtree.xradar.apply(filter_radar)"
]
},
{
"cell_type": "markdown",
"id": "14",
"metadata": {},
"source": [
"### Comparison"
]
},
{
"cell_type": "markdown",
"id": "15",
"metadata": {},
"source": [
"Now, let's compare the unfiltered and filtered reflectivity"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "16",
"metadata": {},
"outputs": [],
"source": [
"# Set a larger figure size with a wider aspect ratio for readability\n",
"fig, ax = plt.subplots(figsize=(10, 4))\n",
"\n",
"# Plot the unfiltered and filtered reflectivity with clear distinctions\n",
"ax.plot(\n",
" dtree[\"sweep_0\"][\"range\"],\n",
" dtree[\"sweep_0\"][\"corrected_reflectivity_horizontal\"].sel(\n",
" azimuth=100, method=\"nearest\"\n",
" ),\n",
" alpha=0.7,\n",
" lw=2,\n",
" linestyle=\"-\",\n",
" color=\"m\",\n",
" label=\"Unfiltered\",\n",
")\n",
"\n",
"ax.plot(\n",
" dtree[\"sweep_0\"][\"range\"],\n",
" dtree[\"sweep_0\"][\"DBZH_Filtered\"].sel(azimuth=100, method=\"nearest\"),\n",
" alpha=0.7,\n",
" lw=2,\n",
" linestyle=\"--\",\n",
" color=\"green\",\n",
" label=\"Filtered\",\n",
")\n",
"\n",
"ax.set_xlim(1000, 40_000)\n",
"ax.set_ylim(0, 50)\n",
"\n",
"# Set title and labels with enhanced font sizes\n",
"ax.set_title(\n",
" \"Compare Unfiltered and \\\n",
"Filtered Reflectivity Variables (Azimuth = 100°)\",\n",
" fontsize=16,\n",
" pad=15,\n",
")\n",
"ax.set_ylabel(\"Reflectivity [dBZ]\", fontsize=14)\n",
"ax.set_xlabel(\"Range [m]\", fontsize=14)\n",
"\n",
"# Add minor ticks and a grid for both major and minor ticks\n",
"ax.minorticks_on()\n",
"ax.grid(True, which=\"both\", linestyle=\"--\", linewidth=0.5)\n",
"\n",
"# Adjust legend to avoid overlapping with the plot, and make it clear\n",
"ax.legend(loc=\"upper right\", fontsize=12, frameon=True)\n",
"\n",
"# Apply a tight layout to avoid label/title overlap\n",
"plt.tight_layout()\n",
"\n",
"# Show the plot\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"id": "17",
"metadata": {},
"source": [
"### Example #2"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "18",
"metadata": {},
"outputs": [],
"source": [
"# Define a function to calculate rain rate from reflectivity\n",
"def calculate_rain_rate(ds, ref_field=\"DBZH\"):\n",
" def _rain_rate(dbz, a=200.0, b=1.6):\n",
" Z = 10.0 ** (dbz / 10.0)\n",
" return (Z / a) ** (1.0 / b)\n",
"\n",
" ds[\"RAIN_RATE\"] = _rain_rate(ds[ref_field])\n",
" ds[\"RAIN_RATE\"].attrs = {\"units\": \"mm/h\", \"long_name\": \"Rain Rate\"}\n",
" return ds"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "19",
"metadata": {},
"outputs": [],
"source": [
"# Apply the function across all sweeps\n",
"dtree = dtree.xradar.apply(calculate_rain_rate, ref_field=\"DBZH_Filtered\")\n",
"dtree"
]
},
{
"cell_type": "markdown",
"id": "20",
"metadata": {},
"source": [
"If you expand the `dtree` groups and sweeps, you'll notice that the `RAIN_RATE` variable has been successfully added to the DataTree. This confirms that the function was applied across all sweeps, incorporating the calculated rain rate into the dataset."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "21",
"metadata": {},
"outputs": [],
"source": [
"# Create a figure with a GridSpec layout\n",
"fig = plt.figure(figsize=(8, 8))\n",
"gs = gridspec.GridSpec(2, 2, wspace=0.05, hspace=0.1) # Reduced spacing between plots\n",
"\n",
"# Define common plotting settings\n",
"vmin = 0\n",
"vmax = 50\n",
"cmap = \"viridis\"\n",
"\n",
"# Create the subplots without shrinking due to colorbar\n",
"axes = [fig.add_subplot(gs[i // 2, i % 2]) for i in range(4)]\n",
"\n",
"# Plot each sweep on the respective subplot\n",
"for i, ax in enumerate(axes):\n",
" sweep = f\"sweep_{i}\"\n",
" im = dtree[sweep][\"RAIN_RATE\"].plot(\n",
" x=\"x\",\n",
" y=\"y\",\n",
" vmin=vmin,\n",
" vmax=vmax,\n",
" cmap=cmap,\n",
" ax=ax,\n",
" add_colorbar=False, # Disable individual colorbars\n",
" )\n",
" ax.set_title(f\"Rain Rate for {sweep.replace('_', ' ').capitalize()}\", fontsize=14)\n",
"\n",
" # Turn off ticks and labels for inner subplots\n",
" if i in [0, 1]: # Top row\n",
" ax.set_xticklabels([])\n",
" ax.set_xlabel(\"\")\n",
" if i in [1, 3]: # Right column\n",
" ax.set_yticklabels([])\n",
" ax.set_ylabel(\"\")\n",
"\n",
"# Create a single shared colorbar outside the subplots\n",
"# Adjust [left, bottom, width, height] for colorbar position\n",
"cbar_ax = fig.add_axes([0.92, 0.25, 0.02, 0.5])\n",
"fig.colorbar(im, cax=cbar_ax, label=\"Rain Rate (mm/hr)\")\n",
"\n",
"# Set a main title for the entire figure\n",
"fig.suptitle(\"Rain Rate Across Different Sweeps\", fontsize=16, fontweight=\"bold\")\n",
"\n",
"# Show the plot\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"id": "22",
"metadata": {},
"source": [
"## Conclusion"
]
},
{
"cell_type": "markdown",
"id": "23",
"metadata": {},
"source": [
"In this notebook, we demonstrated how to handle and process radar data efficiently using Xradar’s `apply` accessor. By applying operations across an entire volume of radar sweeps, you can streamline your workflow and avoid the need to manually process each sweep.\n",
"\n",
"We explored two key use cases:\n",
"- **Filtering Reflectivity**: We applied a custom filtering function across all sweeps in the radar dataset, allowing us to isolate meaningful reflectivity values based on specific criteria.\n",
"- **Calculating Rain Rate**: Using the radar reflectivity data, we calculated the rain rate for each sweep, demonstrating how to perform scientific computations across multiple sweeps with minimal effort.\n",
"\n",
"The `apply` functionality in Xradar opens the door to performing various radar data processing tasks efficiently. Whether it's filtering, calculating derived quantities like rain rate, or applying more complex algorithms, Xradar simplifies working with radar volumes, making it easier to scale your analysis."
]
}
],
"metadata": {
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.5"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Loading