Completed
Pull Request — master (#318)
by
unknown
01:26
created

Meteogram.plot_thermo()   B

Complexity

Conditions 2

Size

Total Lines 39

Duplication

Lines 11
Ratio 28.21 %

Importance

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