Skip to content
scipython.com

P6.2.18000 m peaks

The text file ex6-2-b-mountain-data.txt, reproduced below, gives some data concerning the 8000 m peaks, in alphabetical order.

ex6-2-b-mountain-data.txt
This file contains a list of the 14 highest mountains in the
world with their names, height, year of first ascent, year of
first winter ascent, and location as longitude and latitude
in degrees (d), minutes (m) and seconds (s).
Note: as of 2019, no winter ascent has been made of K2.

--------------------------------------------------------------------
Name         Height  First Ascent First Winter Location
               m         Date     Ascent Date   (WGS84)
--------------------------------------------------------------------
Annapurna I   8091    3/6/1950    3/2/1987     28d35m46sN 83d49m13sE
Broad Peak    8051    9/6/1957    5/3/2013     35d48m39sN 76d34m06sE
Cho Oyu       8201    19/10/1954  12/2/1985    28d05m39sN 86d39m39sE
Dhaulagiri I  8167    13/5/1960   21/1/1985    27d59m17sN 86d55m31sE
Everest       8848    29/5/1953   17/2/1980    27d59m17sN 86d55m31sE
Gasherbrum I  8080    5/7/1958    9/3/2012     35d43m28sN 76d41m47sE
Gasherbrum II 8034    7/7/1956    2/2/2011     35d45m30sN 76d39m12sE
K2            8611    31/7/1954   -            35d52m57sN 76d30m48sE
Kangchenjunga 8568    25/5/1955   11/1/1986    27d42m09sN 88d08m54sE
Lhotse        8516    18/5/1956   31/12/1988   27d57m42sN 86d56m00sE
Makalu        8485    15/5/1955   9/2/2009     27d53m21sN 87d05m19sE
Manaslu       8163    9/5/1956    12/1/1984    28d33m0sN  84d33m35sE
Nanga Parbat  8126    3/7/1953    16/2/2016    35d14m15sN 74d35m21sE
Shishapangma  8027    2/5/1964    14/1/2005    28d21m8sN  85d46m47sE
--------------------------------------------------------------------

Note: the first winter ascent of K2 was made by a team of Nepali climbers in January 2021, but is not included in the above data set.

Use NumPy's genfromtxt method to read these data into a suitable structured array in order to determine the following:

(a) The lowest 8000 m peak

(b) The most northely, easterly, southerly and westerly peaks

(c) The most recent first ascent of the peaks

(d) The first of the peaks to be climbed in winter

Also produce another structured array containing a list of mountains with their height in feet (1 metre = 3.2808399 feet) and first ascent date, ordered by increasing height.

Show solution

Reading this text file with numpy.genfromtxt will require converter functions to handle the dates and locations (longitudes and latitudes). We will choose to store the former as a float: in this solution, we will convert dates into the number of seconds since the midnight on 1 January 1970 (the "Unix epoch"), although any fiducial date will do. Note that this means that dates before this time will be represented by negative numbers.

The locations we will convert into float values in decimal degrees. Latitudes will be positive values from 0 to 90 in the Northern hemisphere and negative values from 0 to -90 in the Southern hemisphere; longitudes will be from 0 to 180 in the Eastern hemisphere and from 0 to -180 in the Western hemisphere.

The code is as follows:

mountains8000m
import numpy as np
from datetime import datetime, timedelta

EPOCH = datetime(1970, 1, 1)

dt = np.dtype(
    {
        "names": [
            "name",
            "height",
            "first_ascent",
            "first_winter_ascent",
            "latitude",
            "longitude",
        ],
        "formats": ["|S13", "u2", "f8", "f8", "f8", "f8"],
    }
)


def angle_str_to_float(s):
    """
    Convert an angle given in degrees, D, minutes, M, and seconds, S as a
    string 'DdMdSs' in to a float representing decimal degrees.
    """

    d, rem = s.split("d")
    m, rem = rem.split("m")
    s, rem = rem.split("s")
    return float(d) + float(m) / 60 + float(s) / 3600


def angle_float_to_str(abs_angle):
    """
    Convert a float representing an angle in degrees to a string of the form
    'DdMdSs' representing degrees, D, minutes, M, and seconds, S.

    """

    d = int(abs_angle)
    fmins = (abs_angle - d) * 60
    m = int(fmins)
    s = int(round((fmins - m) * 60))
    return "{D:d}d{M:d}m{S:d}s".format(D=d, M=m, S=s)


def longlat_str_to_float(s):
    """
    Convert a longitude or latitude given as a string 'DdMmSsZ' (Z=N, E, S or W)
    into a float representing decimal degrees.

    """

    sgn = {"N": 1, "E": 1, "S": -1, "W": -1}
    return sgn[s[-1]] * angle_str_to_float(s[:-1])


def latitude_float_to_str(angle):
    """
    Convert a latitude as a float between -90 and 90 degrees into a string
    giving degrees, minutes and seconds: 'DdMmSsZ' (Z=N or S).

    """

    hemisphere = "N" if angle >= 0 else "S"
    return angle_float_to_str(abs(angle)) + hemisphere


def longitude_float_to_str(angle):
    """
    Convert a longitude as a float between -180 and 180 degrees into a string
    giving degrees, minutes and seconds: 'DdMmSsZ' (Z=E or W).

    """

    hemisphere = "E" if angle >= 0 else "W"
    return angle_float_to_str(abs(angle)) + hemisphere


def date_str_to_float(s):
    """
    Converts a date represented as string formatted 'DD/MM/YYYY' to a number
    of seconds since "the epoch" (1/1/1970).
    """

    return (datetime.strptime(s, "%d/%m/%Y") - EPOCH).total_seconds()


def date_float_to_str(t):
    """
    Convert a time in seconds since the epoch to a string formatted
    'DD/MM/YYYY'

    """

    return datetime.strftime((EPOCH + timedelta(seconds=t)), "%d/%m/%Y")

Using these functions, we can parse the file into a NumPy structured array and sort it for the required quantities:

mountains8000m
peaks = np.genfromtxt(
    "ex6-2-b-mountain-data.txt",
    dtype=dt,
    skip_header=11,
    converters={
        2: date_str_to_float,
        3: date_str_to_float,
        4: longlat_str_to_float,
        5: longlat_str_to_float,
    },
    delimiter=(13, 5, 14, 12, 13, 11),
    skip_footer=1,
    autostrip=True,
)

ilowest = np.argmin(peaks["height"])
print(
    "The lowest 8000 m peak is {:s} at {:4d} m".format(
        peaks[ilowest]["name"].decode("utf-8"), peaks[ilowest]["height"]
    )
)

peaks.sort(order="latitude")
print(
    "The most Northerly peak is {:s} at {:s} deg North".format(
        peaks[-1]["name"].decode("utf-8"),
        latitude_float_to_str(peaks[-1]["latitude"]),
    )
)
print(
    "The most Southerly peak is {:s} at {:s} deg North".format(
        peaks[0]["name"].decode("utf-8"),
        latitude_float_to_str(peaks[0]["latitude"]),
    )
)

peaks.sort(order="longitude")
print(
    "The most Easterly peak is {:s} at {:s} deg East".format(
        peaks[-1]["name"].decode("utf-8"),
        longitude_float_to_str(peaks[-1]["longitude"]),
    )
)
print(
    "The most Westerly peak is {:s} at {:s} deg East".format(
        peaks[0]["name"].decode("utf-8"),
        longitude_float_to_str(peaks[0]["longitude"]),
    )
)

peaks.sort(order="first_ascent")
print(
    "Most recent first ascent: {:s} on {:s}".format(
        peaks[-1]["name"].decode("utf-8"),
        date_float_to_str(peaks[-1]["first_ascent"]),
    )
)

i = np.nanargmax(peaks["first_winter_ascent"])
print(
    "Most recent first winter ascent: {:s} on {:s}".format(
        peaks[i]["name"].decode("utf-8"),
        date_float_to_str(peaks[i]["first_winter_ascent"]),
    )
)


dt2 = np.dtype(
    {
        "names": ["name", "height", "first_ascent"],
        "formats": ["|S13", "u2", "|S10"],
    }
)
ordered_peaks = np.zeros(len(peaks), dtype=dt2)
ordered_peaks["name"] = peaks["name"]
ordered_peaks["height"] = peaks["height"] * 3.2808399
ordered_peaks["first_ascent"] = [
    date_float_to_str(t) for t in peaks["first_ascent"]
]
ordered_peaks = np.sort(ordered_peaks, order="height")[::-1]

print("+---------------+------------+--------------+")
print("| Peak          | height /ft | first ascent |")
print("+---------------+------------+--------------+")
for peak, height, first_ascent in ordered_peaks:
    print(
        "| {:13s} | {:^10d} | {:^12s} |".format(
            peak.decode("utf-8"), height, first_ascent.decode("utf-8")
        )
    )
print("+---------------+------------+--------------+")

The output is:

The lowest 8000 m peak is Shishapangma at 8027 m
The most Northerly peak is K2 at 35d52m57sN deg North
The most Southerly peak is Kangchenjunga at 27d42m9sN deg North
The most Easterly peak is Kangchenjunga at 88d8m54sE deg East
The most Westerly peak is Nanga Parbat at 74d35m21sE deg East
Most recent first ascent: Shishapangma on 02/05/1964
Most recent first winter ascent: Nanga Parbat on 16/02/2016
+---------------+------------+--------------+
| Peak          | height /ft | first ascent |
+---------------+------------+--------------+
| Everest       |   29028    |  29/05/1953  |
| K2            |   28251    |  31/07/1954  |
| Kangchenjunga |   28110    |  25/05/1955  |
| Lhotse        |   27939    |  18/05/1956  |
| Makalu        |   27837    |  15/05/1955  |
| Cho Oyu       |   26906    |  19/10/1954  |
| Dhaulagiri I  |   26794    |  13/05/1960  |
| Manaslu       |   26781    |  09/05/1956  |
| Nanga Parbat  |   26660    |  03/07/1953  |
| Annapurna I   |   26545    |  03/06/1950  |
| Gasherbrum I  |   26509    |  05/07/1958  |
| Broad Peak    |   26414    |  09/06/1957  |
| Gasherbrum II |   26358    |  07/07/1956  |
| Shishapangma  |   26335    |  02/05/1964  |
+---------------+------------+--------------+