# Made in the Shade

** Tags: **
data, photography, strava,

** Categories: **
Data Science,

If you take a look at my Side Projects page, you’ll see that I run a cheering/race photography project to encourage NYC-area runners in local (and sometimes international!) races. Race photography is one of my favorite hobbies. I have the privilege of interacting with a community of positive, endorphin-filled humans at least a few times a month. So I want to make sure my photos come out as sharp as possible.

The biggest enemy of outdoor photography is strong sunlight directly on the subject. Because these races tend to happen early in the morning, the sun shines at enough of an angle to avoid the perils of high noon. But if I don’t pick my cheer spots carefully, I might end up in a situation where the sun shines on the runners’ front side. This makes them glow in an unflattering way. Check out the one below from the 2017 Chicago Marathon:

Note that the shadow is cast to the side of the runner. This conundrum made me realize that I should be studying the location of the sun in advance, to determine which cheer spots would be ideal. We want the sun to be behind the runners, so a shadow is cast in front of them. The photo below, taken at this year’s PPTC Cherry Tree 10 Miler, provides an example of this phenomenon.

If I know where the sun is at each time of the day, and I know the course, I should be able to determine the amount of sunlight projected in front of the runner in the worst case scenario – no clouds. I then want to pick the cheer spot that maximizes a “shade metric” over the course of the race.

### Caveats

The formula I will use to calculate this shade factor is an oversimplification. First, we disregard the effect of local changes in elevation (e.g. hills) on this value. Second, as mentioned above, we’re going to assume the worst case scenario (no clouds), as we cannot predict cloud positions on race day. Lastly, and most importantly, we do not include trees, buildings, or any other possible local sources of shade. This again ties into the worst case scenario where the only shadows are the ones cast by the runners.

### Calculations

Given a time of day, a location coordinate (in terms of latitude/longitude), and the direction one is facing, one can calculate a shade metric.

Let:

$$

\begin{align}

(\lambda_0, \phi_0) &= \text{current position (latitude, longitude)}\\

(\lambda_1, \phi_1) &= \text{next position}\\

\phi_s &= \text{the solar azimuth angle}\\

\alpha_s &= \text{solar elevation angle, or altitude of the sun}

\end{align}

$$

where \(\phi_s\) starts at due north and increases in the clockwise direction. We need to determine the direction angle from our current position to the next position. Comparing this angle to the solar azimuth will allow us to calculate the shade metric. To do so, we first need to convert from geographic to Cartesian coordinates:

$$

\begin{align}

\Delta x &\approx a \Delta \lambda \cos\left(\overline{\phi}\right)\\

\Delta y &\approx a \Delta \phi

\end{align}

$$

where \(a\) is the radius of the earth and \(\overline{\phi}\) is the average latitude on the course. As long as we’re not near the north or south poles, this approximation will do just fine. We can then define the direction angle \(\theta_a\) (with respect to the **eastward** direction, unlike the solar azimuth):

$$

\begin{align}

\theta_a &= \begin{cases}

\arctan\left(\frac{\Delta y}{\Delta x}\right) & \Delta x \geq 0 \\

\pi – \arctan\left(\frac{\Delta y}{|\Delta x|}\right) & \Delta x < 0

\end{cases}

\end{align}

$$

We then want to define a photography shade factor \(S\) that satisfies the following criteria:

$$

\begin{align}

& 0 \leq S \leq 1 \\

&S\left(\left\{\theta_a = \frac{\pi}{2} – \phi_s\right\}\right) = 0\\

&S\left(\left\{\theta_a = -\frac{\pi}{2} – \phi_s \right\}\right) = \cos\left(\alpha_s\right)\\

&S\left(\left\{\alpha_s=\frac{\pi}{2}\right\}\right) = 0

\end{align}

$$

The third requirement addresses the fact that the higher the altitude of the sun, the shorter the shadow cast in front of the runner. The function below satisfies all the above requirements:

$$

\begin{align}

S &= \frac{1}{2}\left( 1-\sin\left(\theta_a +\phi_s\right) \right)\cos\left(\alpha_s\right)

\end{align}

$$

### Example: Prospect Park

Let’s consider the course for the Cherry Tree 10 Miler, where I took that nice photo above. The race took place on February 17th, started at 10 AM EST, and consisted of about three loops of the park. I made a counter-clockwise route around the park on Strava, downloaded the GPX data, and imported it into Python using the gpxpy library. I computed the running direction by taking differences in adjacent positions. Then, I used the PySolar library to compute the elevation and azimuth of the sun at each point on the map. Finally, putting all of this together, I used the above formula to calculate the average shade factor over the period from 10 AM to 11:30 AM. The x and y axes are simply offsets from the origin (in miles)

The best photo conditions tend to emerge when the runners run in the northwest direction, which is away from the sun. My cheer spot at this race was at approximately \((-0.3, 0.6)\), giving me a decent blue shade factor!

### Possible Future Work: Adding Buildings

The City of New York maintains a database for the footprints of all buildings that are at least 400 square feet and 12 feet tall. If we know the locations of the buildings near a race course, then we can calculate the local shade effect to find an optimal cheer spot. This will require much more work, but will be a more useful tool, particularly for races on city streets with many tall buildings.