Publication-Quality Plots Using MATLAB and METAR Data From Nearby Airports
This tutorial will focus on producing publication-quality plots by utilizing MATLAB and the Meteorological Aerodrome Report (METAR). METAR stations record atmospheric conditions of nearby airports to ensure that aviators operate under safe conditions in the proximal airspace. Meteorologists also use METAR data for forecasting and calibration of remote sensing instruments. The procedure outlined below will use your zip code to find a nearby METAR station, parse the data from the National Weather Service, and ultimately produce a plot of recent weather data published by that METAR station. By the end of this tutorial, the user will have a better grasp of MATLAB's figure and plot tools and produce publication-quality results.
Finding Your METAR Station
First and foremost, a METAR station needs to be identified. The METAR station can be random, a local station, or a chosen location. A 4-letter identifier has to be selected in order for the MATLAB routine to request data.
Steps for Finding METAR Station
- Visit http://www.weather.gov/
- Enter a Zip Code in the red box shown in Figure 1, then click 'Go'
- After clicking 'Go' a new page should appear showing the current conditions of the METAR station local to that Zip Code. Find and record the 4-letter identifier (see Figure 2's red box), and continue with this tutorial
Now that a station is identified, it's time to explore the METAR data. For every METAR station there is a government database where the data is stored. The data can be accessed the following way:
In my case, my station ID is 'KNYC' so my full path would be:
And if the link above is clicked, the METAR database can be observed for Central Park, NY (KNYC) for the past 72 hours. Figure 3 shows the METAR station data for KNYC for a few hours on February 14, 2018. If the station selected does not show the same table, then another station should be chosen.
Reading and Parsing METAR Data With MATLAB
Now that a station ID has been identified, it is time to tell MATLAB to read the data from the URL created above. In the code below, MATLAB is creating a URL for the METAR station, and subsequently reading the webpage using 'webread.' The variable 'web_str_crawl' now contains the data from the METAR station for the last 72 hours.
%% URL read for Real-time Weather Station Measurements % clear all close all clc % station_repos = 'http://w1.weather.gov/data/obhistory/'; % This is where % the weather stations are located at www.weather.gov % You type in your address and then look for the 4-letter station % identifier (for example, if you type in '10024' for NYC, the station % ID for that Zip Code is 'KNYC' - Central Park's weather station % station_ID = 'KNYC'; % % concatenate station repository with your local station % web_url = strcat(station_repos,station_ID,'.html'); % % Crawl the URL for data web_str_crawl = webread(web_url);
From here, I will demonstrate how to parse that data, which is currently formatted in html. The code below is a function for taking METAR station data and parsing out the variables we want and formatting them into a nice table in MATLAB. All the function needs is the URL for the METAR station.
function station_table = data_reformat(web_url_str) % % Parse each row, which in html is identified by <td></td>, then put each % into the station_parse variable station_parse = {}; for jj = 1:length(web_url_str)-4 if web_url_str(jj:jj+4)=='</td>' for kk = 1:80 if web_url_str(jj-kk)=='>' station_parse{end+1} = web_url_str(jj-kk+1:jj-1); break end end end end % shift data to get rid of the extra headers station_vec = {}; n_shift = 9; for ll = 1:length(station_parse) if ll>=n_shift station_vec{ll-n_shift+1} =station_parse{ll}; end end % % reformat the data into an easily-readable table % col_size = 18; station_table = {zeros(floor(length(station_vec)/col_size)+1,col_size)}; % I rewrote the headers to make them more friendly for labeling station_header = {'Date','Time (Local)','Wind [MPH]','Visibility [Miles]','Weather Cond.',... 'Sky Cond.','Air Temperature [F]','Dew Point [F]','Temp (6 Hour Max) [F]','Temp (6 Hour Min)','Relative Humidity [%]',... 'Wind Chill [F]','Heat Index [F]','Pressure (Alt, inches)','Pressure (Sea, mbar)',... 'Precipitation (1 hr) [inches]','Precipitation (inches) [3 hr]','Precipitation (inches) [6 hr]'}; % This is the loop where the table is created and formatted for mm = 1:floor(length(station_vec)/col_size)+1 for nn = 1:col_size if mm == 1 station_table{mm,nn} = station_header{nn}; else pp = (mm-2)*col_size+nn; if nn==11 station_table{mm,nn} = station_vec{pp}(1:2); else station_table{mm,nn} = station_vec{pp}; end end end end
MATLAB Figure Formatting
In science and industry alike, visualization plays an important role in research and analysis. MATLAB also requires extensive alteration of its default plotting tools to produce beautiful visualizations. Therefore, I have included a MATLAB function that produces a figure which mimics a popular graphics tool used in the R programming language, called ggplot. With this new template, any dull MATLAB figure can be transformed into a contrasting, visually compelling visualization.
function [fig1,ax1,dcm_obj] = fig_open() set(0,'defaultfigurecolor',[1 1 1]) % white background set(0,'defaultaxesfontname','cambria math') % beautify the axes a bit scrn_size = get(0,'ScreenSize'); % get size of screen shrink_pct = 0.1; % shrink the figure by 10% % fig1 = figure('Visible','off','DefaultAxesFontSize',20,'Position',... [scrn_size(1)+(scrn_size(3)*shrink_pct) scrn_size(2)+(scrn_size(4)*shrink_pct)... scrn_size(3)-(scrn_size(3)*2*shrink_pct) scrn_size(4)-(scrn_size(4)*2*shrink_pct)]); % shrinking the figure % ax1 = gca; dcm_obj = datacursormode(fig1); % enable control of datatips % set(dcm_obj,'UpdateFcn',@myupdatefcn) % this will be used to configure % data tips set(ax1,'fontsize',22,'Color',[0.8 0.8 0.8],'gridcolor',[1 1 1],'gridalpha',0.9) % set the axis color % to compliment the white background % xlabel('Time [Day HH:MM]') % x-axis date label hold all grid on % grid for more contrast in the axes end
Plotting The METAR Variables
The final and most important part of this tutorial is the data visualization. Now that we have found our METAR station, parsed the data from weather.gov, and created our figure, we now need to plot the data. The station data above exists in a cell of strings within MATLAB. One major complication with the data is the fact that the time spans two columns: 'Date' and 'Time (Local).' Therefore, the first thing we need to do is convert those times to a single datenumber in order to plot the variables in the correct time sequence. The function for this is below:
function [datenum_vec,var_pick,var_name] = parse_and_format(station_table,var_col) curr_time = datetime(); % get the current time for year information datenum_vec = []; var_pick = []; var_name = station_table{1,var_col}; % variable name for ss = 2:length(station_table) % starting at the second row since the first contains the variable names var_pick = [var_pick,str2double(station_table{ss,var_col})]; if isempty(str2double(station_table{ss,var_col})) % if there is no data in the row, skip the loop continue end if ss==2 % making sure the first row is the reference year, month, and day datenum_vec = [datenum_vec,datenum(year(curr_time),month(curr_time),str2num(station_table{ss}),str2num(station_table{ss,2}(1:2)),str2num(station_table{ss,2}(4:5)),0)]; else if str2double(station_table{ss})>str2double(station_table{2}) % this ensures that if the date grows, then the day is in the previous month if month(curr_time)==1 % if it's december, then we have to roll back the month and year datenum_vec = [datenum_vec,datenum(year(curr_time)-1,12,str2double(station_table{ss}),str2double(station_table{ss,2}(1:2)),str2double(station_table{ss,2}(4:5)),0)]; else % end of month, roll back month datenum_vec = [datenum_vec,datenum(year(curr_time),month(curr_time)-1,str2double(station_table{ss}),str2double(station_table{ss,2}(1:2)),str2double(station_table{ss,2}(4:5)),0)]; end else datenum_vec = [datenum_vec,datenum(year(curr_time),month(curr_time),str2double(station_table{ss}),str2double(station_table{ss,2}(1:2)),str2double(station_table{ss,2}(4:5)),0)]; end end end end
Finally, we have the x-variable ('datenum_vec') and y-variable ('var_pick'), along with the variable name ('var_name'), which can all be used to plot the data onto our figure above. The function shown above plots the data for a given column of data using the station table created in the program. To determine which column to plot, take a look at the table data, or just plot the variables based on the columns in the weather.gov METAR website. They should be identical. To plot the raw temperature values, the only lines of code needed are:
plt1 = plot(ax1,datenum_vec,var_pick);
fig1.Visible='on';
The plot is a simple line plot, and the visibility of the plot is set to visible once the data is plotted. The figure should now look something like this:
Perfecting the MATLAB Plot Appearance
At this point, we have a fully functional plotting routine that grabs data from the internet (weather.gov METAR station data), decomposes its html codec into a MATLAB table, and plots a chosen variable into a nicely-formatted MATLAB figure. Now, we have a few tweaks and adjustments to make before we can call this 'publication quality.' Several issues are apparent: the line is too skinny, there are no labels or title, the x-axis has date numbers which speak nothing to the actual dates, and the limits on the x-axis are too arbitrary. Below is the fixed figure with the proper titles, axes, line width, and I even included scatter points to show the individual data points.
Figure 7 is a good example of a near publication-quality visual. It has a resolution of 600 dpi (sometimes even higher is recommended), it has formatted axes, visible font sizes, colorful visuals with thick lines and markers, and a clear and concise title that allows the reader to know exactly what they are viewing. Depending on the journal or form of publication, the formatting or color palette may need to be altered. Some journals do not use color in their plots, some do not want color backgrounds, some have specific formatting for units, etc. The figure above is not particularly interesting, however it meets publication expectations in visual representation. Below is a more detailed plot showing the relative behavior between temperature and humidity.
The figure shown above, Figure 8, is a perfect example of the quality you might see in scientific research journals. As I mentioned above, the format may not fit the targeted journal's specifications, however, the basics are there. Some alterations could be made to the axes colors, or the time format on the x-axis, or the legend, or figure background color, or the limits - all of these are possibilities that are specific to both user and journal. The code below outlines the function used to produce the figure above:
function plot_algo(station_table,station_name_formal,home_station,var_select) legend_str = {}; for ii = 1:length(var_select) % loop through variables to ensure legend catches each [datenum_vec,var_pick,var_name] = parse_and_format(station_table,var_select(ii)); % send variable through parse function % plotting traits sz = 10; % size of marker color_map = lines; % colormap used for lines and markers if length(var_select)<=2 % this is particular to my dataset (METAR) switch ii case 1 % if only 1 variable, make 1 y-axis label ylabel(var_name) case 2 % if two variables, make two y-axis labels yyaxis right; % second y-axis to the right y2 = gca; ylabel(var_name) y2.YColor = color_map(ii,:); % ensure the color of the axis matches the second line end % in my case, I'm chosing to discard the y-labels if more than 2 variables are entered end % plot specifics: -s creates a square marker with a line plot(datenum_vec,var_pick,'-s','linewidth',3,'color',color_map(ii,:),... 'MarkerFaceColor',(1-color_map(ii,:))/1.5+color_map(ii,:),'MarkerEdgeColor',[25 25 25]./256,... 'MarkerSize',sz) % title handling for month and year curr_time = datetime(); title(strcat('Weather for {}',station_name_formal,'{ }(',home_station,') in {}',datestr(curr_time,'mmmm, yyyy'))) xlabel('Time [Day HH:MM]') % chosing to step through x-values by 6 (72/6 = 12 x-ticks) xticks(datenum_vec(end:-6:1)) datetick(gca,'x','dd HH:MM','keepticks') % rotating the x-ticks so they don't overlap xtickangle(20) % setting the limits xlim([datenum_vec(end) datenum_vec(1)]) % appending the names to the legend handler legend_str{end+1} = var_name; end % white background and letting MATLAB choose the best location for the % legend legend(legend_str,'Location','Best','Color','white') end
Now, with all the tools above, one should be capable of producing a plot similar to the one above. The only hard coding the user needs to do is call the function as such:
The function above needs four variables:
Station table
Station name
Station ID
Weather variables to plot
For example, if you wanted to plot the temperature and dew point for Austin-Bergstrom International Airport (KAUS), the function needs to be formatted as follows:
This produces the plot shown in Figure 9, below.
Conclusions
When it comes to exhibiting professional work, the human eye determines the scale of expectation. That is precisely why I meticulously craft representations of my research. Peer reviewed journals scour through manuscripts, which is why it is important to maintain excellence when publishing figures. Above, I demonstrated how to create powerful visuals in MATLAB by utilizing the METAR database. The tutorial showed how to take publicly available weather data, import and parse it into MATLAB, and produce high quality figures. MATLAB is a robust tool that, when used properly, can be used to generate publication-worthy plots to represent data across all fields.
NOTE: The figures shown above may appear fuzzy. This is because the images are automatically resized and reformatted by my web provider. Therefore, the 600 dpi resolution is not showing honored here, however, rest assured that MATLAB is capable of exporting resolutions of 600 dpi and greater. For a high resolution example, see here.
See more in Programming: