Meteogram.plot_thermo()   B
last analyzed

Complexity

Conditions 3

Size

Total Lines 41

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
c 0
b 0
f 0
dl 0
loc 41
rs 8.8571
1
# Copyright (c) 2017 MetPy Developers.
2
# Distributed under the terms of the BSD 3-Clause License.
3
# SPDX-License-Identifier: BSD-3-Clause
4
"""
5
Meteogram
6
=========
7
8
Plots time series data as a meteogram.
9
"""
10
11
import datetime as dt
12
13
import matplotlib as mpl
14
import matplotlib.pyplot as plt
15
import numpy as np
16
17
from metpy.calc import dewpoint_rh
18
from metpy.cbook import get_test_data
19
from metpy.units import units
20
21
22
def calc_mslp(t, p, h):
23
    return p * (1 - (0.0065 * h) / (t + 0.0065 * h + 273.15)) ** (-5.257)
24
25
26
# Make meteogram plot
27
class Meteogram(object):
28
    """ Plot a time series of meteorological data from a particular station as a
29
    meteogram with standard variables to visualize, including thermodynamic,
30
    kinematic, and pressure. The functions below control the plotting of each
31
    variable.
32
    TO DO: Make the subplot creation dynamic so the number of rows is not
33
    static as it is currently. """
34
35
    def __init__(self, fig, dates, probeid, time=None, axis=0):
36
        """
37
        Required input:
38
            fig: figure object
39
            dates: array of dates corresponding to the data
40
            probeid: ID of the station
41
        Optional Input:
42
            time: Time the data is to be plotted
43
            axis: number that controls the new axis to be plotted (FOR FUTURE)
44
        """
45
        if not time:
46
            time = dt.datetime.utcnow()
47
        self.start = dates[0]
48
        self.fig = fig
49
        self.end = dates[-1]
50
        self.axis_num = 0
51
        self.dates = mpl.dates.date2num(dates)
52
        self.time = time.strftime('%Y-%m-%d %H:%M UTC')
53
        self.title = 'Latest Ob Time: {0}\nProbe ID: {1}'.format(self.time, probeid)
54
55
    def plot_winds(self, ws, wd, wsmax, plot_range=None):
56
        """
57
        Required input:
58
            ws: Wind speeds (knots)
59
            wd: Wind direction (degrees)
60
            wsmax: Wind gust (knots)
61
        Optional Input:
62
            plot_range: Data range for making figure (list of (min,max,step))
63
        """
64
        # PLOT WIND SPEED AND WIND DIRECTION
65
        self.ax1 = fig.add_subplot(4, 1, 1)
66
        ln1 = self.ax1.plot(self.dates, ws, label='Wind Speed')
67
        plt.fill_between(self.dates, ws, 0)
68
        self.ax1.set_xlim(self.start, self.end)
69
        if not plot_range:
70
            plot_range = [0, 20, 1]
71
        plt.ylabel('Wind Speed (knots)', multialignment='center')
72
        self.ax1.set_ylim(plot_range[0], plot_range[1], plot_range[2])
73
        plt.grid(b=True, which='major', axis='y', color='k', linestyle='--', linewidth=0.5)
74
        ln2 = self.ax1.plot(self.dates,
75
                            wsmax,
76
                            '.r',
77
                            label='3-sec Wind Speed Max')
78
        plt.setp(self.ax1.get_xticklabels(), visible=True)
79
        ax7 = self.ax1.twinx()
80
        ln3 = ax7.plot(self.dates,
81
                       wd,
82
                       '.k',
83
                       linewidth=0.5,
84
                       label='Wind Direction')
85
        plt.ylabel('Wind\nDirection\n(degrees)', multialignment='center')
86
        plt.ylim(0, 360)
87
        plt.yticks(np.arange(45, 405, 90), ['NE', 'SE', 'SW', 'NW'])
88
        lns = ln1 + ln2 + ln3
89
        labs = [l.get_label() for l in lns]
90
        plt.gca().xaxis.set_major_formatter(mpl.dates.DateFormatter('%d/%H UTC'))
91
        ax7.legend(lns, labs, loc='upper center',
92
                   bbox_to_anchor=(0.5, 1.2), ncol=3, prop={'size': 12})
93
94
    def plot_thermo(self, t, td, plot_range=None):
95
        """
96
        Required input:
97
            T: Temperature (deg F)
98
            TD: Dewpoint (deg F)
99
        Optional Input:
100
            plot_range: Data range for making figure (list of (min,max,step))
101
        """
102
        # PLOT TEMPERATURE AND DEWPOINT
103
        if not plot_range:
104
            plot_range = [10, 90, 2]
105
        self.ax2 = fig.add_subplot(4, 1, 2, sharex=self.ax1)
106
        ln4 = self.ax2.plot(self.dates,
107
                            t,
108
                            'r-',
109
                            label='Temperature')
110
        plt.fill_between(self.dates,
111
                         t,
112
                         td,
113
                         color='r')
114
        plt.setp(self.ax2.get_xticklabels(), visible=True)
115
        plt.ylabel('Temperature\n(F)', multialignment='center')
116
        plt.grid(b=True, which='major', axis='y', color='k', linestyle='--', linewidth=0.5)
117
        self.ax2.set_ylim(plot_range[0], plot_range[1], plot_range[2])
118
        ln5 = self.ax2.plot(self.dates,
119
                            td,
120
                            'g-',
121
                            label='Dewpoint')
122
        plt.fill_between(self.dates,
123
                         td,
124
                         plt.ylim()[0],
125
                         color='g')
126
        ax_twin = self.ax2.twinx()
127
        #    ax_twin.set_ylim(20,90,2)
128
        ax_twin.set_ylim(plot_range[0], plot_range[1], plot_range[2])
129
        lns = ln4 + ln5
130
        labs = [l.get_label() for l in lns]
131
        plt.gca().xaxis.set_major_formatter(mpl.dates.DateFormatter('%d/%H UTC'))
132
133
        self.ax2.legend(lns, labs, loc='upper center',
134
                        bbox_to_anchor=(0.5, 1.2), ncol=2, prop={'size': 12})
135
136
    def plot_rh(self, rh, plot_range=None):
137
        """
138
        Required input:
139
            RH: Relative humidity (%)
140
        Optional Input:
141
            plot_range: Data range for making figure (list of (min,max,step))
142
        """
143
        # PLOT RELATIVE HUMIDITY
144
        if not plot_range:
145
            plot_range = [0, 100, 4]
146
        self.ax3 = fig.add_subplot(4, 1, 3, sharex=self.ax1)
147
        self.ax3.plot(self.dates,
148
                      rh,
149
                      'g-',
150
                      label='Relative Humidity')
151
        self.ax3.legend(loc='upper center', bbox_to_anchor=(0.5, 1.22), prop={'size': 12})
152
        plt.setp(self.ax3.get_xticklabels(), visible=True)
153
        plt.grid(b=True, which='major', axis='y', color='k', linestyle='--', linewidth=0.5)
154
        self.ax3.set_ylim(plot_range[0], plot_range[1], plot_range[2])
155
        plt.fill_between(self.dates, rh, plt.ylim()[0], color='g')
156
        plt.ylabel('Relative Humidity\n(%)', multialignment='center')
157
        plt.gca().xaxis.set_major_formatter(mpl.dates.DateFormatter('%d/%H UTC'))
158
        axtwin = self.ax3.twinx()
159
        axtwin.set_ylim(plot_range[0], plot_range[1], plot_range[2])
160
161
    def plot_pressure(self, p, plot_range=None):
162
        """
163
        Required input:
164
            P: Mean Sea Level Pressure (hPa)
165
        Optional Input:
166
            plot_range: Data range for making figure (list of (min,max,step))
167
        """
168
        # PLOT PRESSURE
169
        if not plot_range:
170
            plot_range = [970, 1030, 2]
171
        self.ax4 = fig.add_subplot(4, 1, 4, sharex=self.ax1)
172
        self.ax4.plot(self.dates,
173
                      p,
174
                      'm',
175
                      label='Mean Sea Level Pressure')
176
        plt.ylabel('Mean Sea\nLevel Pressure\n(mb)', multialignment='center')
177
        plt.ylim(plot_range[0], plot_range[1], plot_range[2])
178
        axtwin = self.ax4.twinx()
179
        axtwin.set_ylim(plot_range[0], plot_range[1], plot_range[2])
180
        plt.fill_between(self.dates, p, plt.ylim()[0], color='m')
181
        plt.gca().xaxis.set_major_formatter(mpl.dates.DateFormatter('%d/%H UTC'))
182
        self.ax4.legend(loc='upper center', bbox_to_anchor=(0.5, 1.2), prop={'size': 12})
183
        plt.grid(b=True, which='major', axis='y', color='k', linestyle='--', linewidth=0.5)
184
        plt.setp(self.ax4.get_xticklabels(), visible=True)
185
        # OTHER OPTIONAL AXES TO PLOT
186
        # plot_irradiance
187
        # plot_precipitation
188
189
190
# set the starttime and endtime for plotting, 24 hour range
191
endtime = dt.datetime(2016, 3, 31, 22, 0, 0, 0)
192
starttime = endtime - dt.timedelta(hours=24)
193
194
# Height of the station to calculate MSLP
195
hgt_example = 292.
196
197
198
# Parse dates from .csv file, knowing their format as a string and convert to datetime
199
def parse_date(date):
200
    return dt.datetime.strptime(date.decode('ascii'), '%Y-%m-%d %H:%M:%S')
201
202
203
testdata = np.genfromtxt(get_test_data('timeseries.csv', False), names=True, dtype=None,
204
                         usecols=list(range(1, 8)),
205
                         converters={'DATE': parse_date}, delimiter=',')
206
207
# Temporary variables for ease
208
temp = testdata['T']
209
pres = testdata['P']
210
rh = testdata['RH']
211
ws = testdata['WS']
212
wsmax = testdata['WSMAX']
213
wd = testdata['WD']
214
date = testdata['DATE']
215
216
# ID For Plotting on Meteogram
217
probe_id = '0102A'
218
219
data = {'wind_speed': (np.array(ws) * units('m/s')).to(units('knots')),
220
        'wind_speed_max': (np.array(wsmax) * units('m/s')).to(units('knots')),
221
        'wind_direction': np.array(wd) * units('degrees'),
222
        'dewpoint': dewpoint_rh((np.array(temp) * units('degC')).to(units('K')),
223
                                np.array(rh) / 100.).to(units('degF')),
224
        'air_temperature': (np.array(temp) * units('degC')).to(units('degF')),
225
        'mean_slp': calc_mslp(np.array(temp), np.array(pres), hgt_example) * units('hPa'),
226
        'relative_humidity': np.array(rh), 'times': np.array(date)}
227
228
fig = plt.figure(figsize=(20, 16))
229
meteogram = Meteogram(fig, data['times'], probe_id)
230
meteogram.plot_winds(data['wind_speed'], data['wind_direction'], data['wind_speed_max'])
231
meteogram.plot_thermo(data['air_temperature'], data['dewpoint'])
232
meteogram.plot_rh(data['relative_humidity'])
233
meteogram.plot_pressure(data['mean_slp'])
234
fig.subplots_adjust(hspace=0.5)
235
plt.show()
236