{ "cells": [ { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "import geoviews as gv\n", "\n", "gv.extension('bokeh')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Define data\n", "\n", "IMPORTANT:\n", "\n", "Unlike the `VectorField` direction, which follows the mathematical convention:\n", "\n", "Reference: 0° = East (positive x-axis)\n", "Direction: Counterclockwise\n", "Meaning: Direction the vector points to\n", "Formula: θ = arctan2(v, u)\n", "\n", "```\n", " N (90°)\n", " |\n", "W (180°)-+-E (0°)\n", " |\n", " S (270°)\n", "```\n", "\n", "The `WindBarbs` direction follows the meteorological convention:\n", "\n", "Reference: 0° = North\n", "Direction: Clockwise\n", "Meaning: Direction the wind is coming from\n", "Formula: θ = 90° - arctan2(-v, -u)\n", "\n", "```\n", " N (0°/360°)\n", " |\n", "W (270°)-+-E (90°)\n", " |\n", " S (180°)\n", "```\n", "\n", "For convenience, `from_uv` can be used to create a `WindBarbs` directly from U/V components to use the meteorological conventions." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "lat = np.arange(60, 37.5, -2.5)\n", "lon = np.arange(270, 292.5, 2.5)\n", "uwnd = np.array(\n", " [\n", " [2, 0, -2, -2, -3, -3, -3, -2, -1],\n", " [2, 0, -2, -2, -2, -2, -2, -1, 1],\n", " [2, -1, -2, -2, -2, -1, 0, 1, 3],\n", " [3, 0, -3, -5, -5, -4, -4, -2, 0],\n", " [8, 4, 0, -3, -5, -6, -6, -6, -5],\n", " [12, 10, 8, 5, 3, 0, -2, -2, -2],\n", " [13, 14, 16, 16, 14, 12, 10, 9, 10],\n", " [13, 18, 22, 24, 25, 24, 23, 22, 23],\n", " [20, 25, 29, 32, 33, 32, 32, 33, 34],\n", " ]\n", ")\n", "vwwnd = np.array(\n", " [\n", " [3, 1, 0, -1, -1, 0, 1, 3, 4],\n", " [-2, -3, -3, -2, 0, 2, 4, 6, 8],\n", " [-6, -6, -4, -1, 2, 5, 7, 10, 12],\n", " [-12, -10, -6, -1, 4, 7, 10, 12, 14],\n", " [-17, -15, -10, -4, 2, 6, 9, 12, 16],\n", " [-20, -18, -14, -8, -2, 2, 5, 10, 16],\n", " [-17, -16, -13, -9, -6, -3, 1, 7, 15],\n", " [-11, -10, -8, -6, -6, -5, -2, 6, 15],\n", " [-5, -3, -2, -2, -4, -5, -2, 6, 15],\n", " ]\n", ")\n", "\n", "# equivalent to metpy.calc.wind_direction(uwnd, vwwnd).to(\"radian\")\n", "wdir = np.pi / 2 - np.arctan2(-vwwnd, -uwnd)\n", "wspd = np.sqrt(uwnd**2 + vwwnd**2)\n", "\n", "wind_barbs = gv.WindBarbs((lon, lat, wdir, wspd)).opts(\n", " width=500, height=500, padding=0.5, title=\"Wind Barbs from direction/speed\"\n", ")\n", "wind_barbs_from_uv = gv.WindBarbs.from_uv((lon, lat, uwnd, vwwnd)).opts(\n", " width=500, height=500, padding=0.5, title=\"Wind Barbs from U/V components\"\n", ")\n", "coastline = gv.feature.coastline()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Plot" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "wind_barbs * coastline + wind_barbs_from_uv * coastline" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Alternatively, `WindBarbs` can be adapted to oceanography convention:\n", "\n", "- Takes the direction the fluid is moving\n", "\n", "- But uses North = 0° and clockwise (like meteorology)\n", "\n", "- It's 180° opposite from meteorological convention" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "wind_barbs_ocean = gv.WindBarbs((lon, lat, wdir, wspd)).opts(\n", " width=500, height=500, padding=0.5, title=\"Wind Barbs from direction/speed\", convention=\"to\"\n", ")\n", "wind_barbs_from_uv_ocean = gv.WindBarbs.from_uv((lon, lat, uwnd, vwwnd)).opts(\n", " width=500, height=500, padding=0.5, title=\"Wind Barbs from U/V components\", convention=\"to\"\n", ")\n", "wind_barbs_from_uv_ocean * coastline + wind_barbs_ocean * coastline" ] } ], "metadata": { "language_info": { "name": "python", "pygments_lexer": "ipython3" } }, "nbformat": 4, "nbformat_minor": 2 }