1

I am trying to create a weather widget in a Flask application. I am stuck on working with wind direction in degrees (angle).

If we use the following image as a representation:

Wind Directions

When working with wind direction we are limited to a 360 degree range. I would like to assign an icon based on which range within 360 degrees I get for wind direction, to help you understand here is some information:

| Cardinal Direction | Degree Direction |
|:------------------:|------------------|
|          N         |   348.75 - 11.25 |
|         NNE        |    11.25 - 33.75 |
|         NE         |    33.75 - 56.25 |
|         ENE        |    56.25 - 78.75 |
|          E         |   78.75 - 101.25 |
|         ESE        |  101.25 - 123.75 |
|         SE         |  123.75 - 146.25 |
|         SSE        |  146.25 - 168.75 |
|          S         |  168.75 - 191.25 |
|         SSW        |  191.25 - 213.75 |
|         SW         |  213.75 - 236.25 |
|         WSW        |  236.25 - 258.75 |
|          W         |  258.75 - 281.25 |
|         WNW        |  281.25 - 303.75 |
|         NW         |  303.75 - 326.25 |
|         NNW        |  326.25 - 348.75 |

I will store the keys/values in a dict and create an if elif else loop that will do something like the following:

from numpy import arange
degrees = the_json_response['wind']['deg']
wind_directions = {
    'N': arange(348.75, 11.25, 0.25),
    ...
}
degrees_range = range(0, 360)
if degrees in wind_direction['N']:
    dirction = north_icon
elif degrees in wind_direction['NNE']:
    direction = north_north_east_icon
    

The above is only pseudo code.. To summarize, How can I apply this so that we only ever work with a 360 degree range because obviously it will throw errors when working with North wind direction due to it being in a range of 348.75 - 11.25, we need to tell it we are working with 360 degrees.

The reason I cannot for the life of my figure this out is I never learnt complex mathmatics (which to me this is). If anyone has a suggestion on how I can apply this in a better way I am very open to those suggestions.

Community
  • 1
  • 1
Jamie Lindsey
  • 928
  • 14
  • 26

2 Answers2

2

To wrap any number to a particular range, use modulo (%): How does % work in Python?. Luckily for you, the python implementation makes the sign of the result always equal to the right hand operand. Here are some examples of how modulo wraps everything to the desired range:

>>> 45 % 360
45
>>> -38 % 360
322
>>> 1000 % 360
280

Given this, it is very easy to map any value in degrees to a letter abbreviation. Each abbreviation represents a window 22.5 degrees wide. The windows are offset from zero by 11.25 degrees, so we can get a window index by doing

from math import floor

index = floor(((deg + 11.25) % 360) / 22.5)

This index will always be a number between zero and 15. You can use it directly to index into a list of points of the compass, without any dictionaries or expensive searches:

list_of_points = ['N', 'NNE', 'NE', ..., 'NW', 'NNW']

def deg_to_point(deg):
    return list_of_points[floor(((deg + 11.25) % 360) / 22.5)]

This works because all your bins are the same size. If you wanted more points on your compass rose, you could halve 11.25 and 22.5, for example. If you had unequal bins, your best bet would be to normalize your input using modulo, and then do a binary search on the bin edges.

Mad Physicist
  • 107,652
  • 25
  • 181
  • 264
  • you sir are a genius! I am pondering over the `deg_to_point()` function to learn how to do more like this.. Thank you so much! I think I actually understand this which is normally not the case with mathematics. Answer marked as accepted. – Jamie Lindsey Aug 18 '18 at 17:48
  • @Jamie. You do what you can. Glad it helped you understand – Mad Physicist Aug 18 '18 at 17:50
  • Also I was reading that [question](https://stackoverflow.com/q/4432208/2988730) a when I got a notification of your answer.. – Jamie Lindsey Aug 18 '18 at 17:53
0

Here is an idea: You can check if the upper limit of the degree range is lower than the lower limit then create arange in two step procedure. For example: 348.75, 11.25 is the only case where the upper limit 11.25 is less than the lower limit 348.75 which means due to periodicity, 360 comes in between. For all other degree ranges and directions, the upper limit is more than the lower limit. Hence you can create N in such a way that you include 360 in one range and the remaining values in the other.

x = np.arange( 348.75, 360, 0.25) 
y = np.arange(0.25, 11.25, 0.25) 
'N' = np.concatenate((x ,y), axis=0)

Just an idea, may be you can improve upon it.

Sheldore
  • 37,862
  • 7
  • 57
  • 71
  • I honestly have to say I don't understand the logic.. This gives values exponent equal to 0, 1 and 2 and the decimal point is in the wrong place - e.g. `array([3.4875e+02, 3.4900e+02, 3.4925e+02, 3.4950e+02` ... maybe I should edit my question to let everyone know I am not the best mathematician – Jamie Lindsey Aug 18 '18 at 17:09
  • For values above 100, exponent will be 2, for two digit numbers, 1 and for single digit, 0. Its just the representation. 3e+02 and 300 mean the same thing – Sheldore Aug 18 '18 at 17:27
  • your equations are not within my capabilities yet, as in I don't have a clue what you mean lol. MadPhysicist has provided a perfect working example which i understand. Thank you for your effort though I appreciate it. – Jamie Lindsey Aug 18 '18 at 17:51