Visualization in Google Earth

From openwfm
Revision as of 02:02, 8 October 2011 by Jbeezley (talk | contribs) (updating dependencies)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search
Back to the WRF-SFIRE user guide.

Google Earth is proprietary software from Google allowing the user to explore 3D imagery of the earth's surface. Using its native support for kml files, it is possible to overlay images from numerical simulations onto the surface of the earth. However, Google Earth is not designed to be a visualization suite for numerical models. It can't, for example, create a pseudo color image from raw data. One must generate a bitmap image (jpg or png) of the data first before it can be used in Google Earth. Once that is done, it is a simple matter of creating a kml file which tells google where to display the image on the ground.

The code described on this page is maintained in a repository at [1]. Contained within it is a simple script for generating KMZ files for visualizing the heat flux from a fire simulation for users that do not wish to customize the output. The script requires python modules, matplotlib, scipy, and netCDF4. The script takes a single argument, the WRF output file, python nc2kmz.py <wrfout file>.

Generating an image from raw data

When one generates a pseudocolor image from raw data, for example in Matlab using the imshow command, the image will usually contain a border with titles and axis labels. In order to align the image properly in Google Earth, we want just the image itself without any borders whatsoever. The easiest way to do this would be to open the image in Gimp and crop it manually; however, this is not suitable for generating a large number of visualizations or for an automated system.

Using python and matplotlib

The python programming language contains a large number of packages useful for scientific computing and visualization. In particular, matplotlib combines the numerical processing capabilities of numpy with a full-featured 2D plotting package, which is very similar to Matlab's 2D plotting capabilities. In this example, we will use the function imshow to generate a psuedo color image from some data in an EpiSim output file. In order to run this example yourself, you must have python with the matplotlib and Scientific Python (for reading the output NetCDF files) packages installed.

When we run EpiSim, we are left with a series of NetCDF files as output. These files contain the raw data from the model for a single time step. We want to create an image of the Infected variable from file episim_0100.nc to overlay onto Google Earth. We start by reading the file using the Scientific Python package.

from Scientific.IO import NetCDF

file=NetCDF.NetCDFFile('episim_0100.nc','r')
infected=file.variables['Infected']

Now we load the matplotlib package, and create a new figure window. Ordinarily, doing this is unnecessary. Because we want the image to contain no borders, we must initialize the figure window to contain only the figure axis. Note that the figure must be created with the correct aspect ratio, or the image will contain borders. We will use a constant width of 5 inches and find the correct height by multiplying the aspect ratio of the input data (the number of rows divided by the number of columns of the variable).

import pylab

width=5
height=width*float(infected.shape[0])/float(infected.shape[1])

fig=pylab.figure(figsize=(width,height))
fig.add_axes([0,0,1,1])

This should have created an empty figure window. We are now able to generate image using the imshow command. Note that imshow draws the figure from top to bottom (like an image) so we must flip the data vertically (using flipud) prior to displaying. Also, we want to visualize the data on a log color scale, so we will take the logarithm of the data (log 0 will show up as white in the figure).

data=pylab.flipud(infected)
data=pylab.log(data)

pylab.imshow(data)

Finally, we will turn off the axis to remove any remnants of tick marks from the display axis, and save the file to a png image named Infected.png.

pylab.axis('off')
pylab.savefig('Infected.png')

You should now have an image that is ready to use as an overlay in Google Earth.

Creating a kml file

External images can be included into Google Earth in a number of different ways. What we are interested in is displaying our image over the ground. This is what is known as a GroundOverlay. A minimal kml file which will do this with the Infected.png image we generated above is as follows.

<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2">
<GroundOverlay>
  <name>Infected</name>
  <Icon>
    <href>Infected.png</href>
  </Icon>
  <altitude>0.0</altitude>
  <altitudeMode>clampToGround</altitudeMode>
  <LatLonBox>
    <north>14.958334</north>
    <south>-10.000000</south>
    <east>40.958336</east>
    <west>16.000000</west>
    <rotation>0.0</rotation>
  </LatLonBox>
</GroundOverlay>
</kml>

The primary components of this file are the name of image as it is displayed in the Google Earth menu, the Icon key which tells where to find the image, the altitudeMode key tells it to stretch the image of the ground. Finally, the LatLonBox tells Google Earth where to put the image. The image is assumed to be defined on a regular latitude/longitude grid (not projected). The keys give the lines of latitude and longitude where the edges of the image should be placed. For the EpiSim output files, this can be found by looking beginning and end of the variables latitude and longitude.

In [1]: from Scientific.IO import NetCDF

In [2]: file=NetCDF.NetCDFFile('episim_0100.nc','r')

In [3]: lat=file.variables['latitude']

In [4]: lon=file.variables['longitude']

In [5]: lat[-1],lat[0],lon[-1],lon[0]
Out[5]: (14.958334, -10.0, 40.958336, 16.0)

Many more features for displaying overlays are available in the kml standard. See the documentation for further details.

Creating preloaded WRF-Fire animations

This is only for users who have older versions of Google Earth. If you have Google Earth 6, loading multiple images from KMZ files is no longer an issue.

If you have older versions of Google Earth, either download and update to Google Earth 6 or use this script for preloading multiple images, and use as follows:

python nc2kmz_GE5.py <wrfout_filename>

The preloading functionality is an extension of the ncEarth module that accomplishes preloading the set of images that is in KMZ files by adding a static copy of the animated GroundOverlays. The static copy of GroundOverlays is without the TimeSpan element. When opening preloaded animation KMZ files, Google Earth automatically loads all the static GroundOverlays which caches the images that are needed in the animation, and when it finishes loading the static GroundOverlays, the timeline slider will appear on the left top corner of the screen for playing the animation. Loading time depends on the number of GroundOverlays in the animation, and if the animation is very large in size, Google Earth may appear frozen while loading. Unfortunately, Google Earth does not provide a way to display a message to the users while loading.

Creating WRF-Fire animation legend

For conveying information, we will need a legend for the animation. First of all, get the script here to generate the image for the legend. Use it as the following example:

import colorbarImg
colorbarImg.getImages('wrfout.nc','FGRNHFX')

Passing the name of a dataset and the variable name, and the resulting images will be stored in a subfolder called “colorbarImages”. After selecting a colorbar image, we can use ScreenOverlay to display the legend in a fixed position on the screen. Here are some examples of ScreenOverlay.

Refers to an image at given URL:

<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2">

<ScreenOverlay>
   <name>Legend name</name>
   <color>ffffffff</color>
   <Icon>
      <href>http://server.com/legend.png</href>
   </Icon>
   <overlayXY x="0" y="1" xunits="fraction" yunits="fraction"/>
   <screenXY x="0" y="1" xunits="fraction" yunits="fraction"/>
   <rotationXY x="0" y="0" xunits="fraction" yunits="fraction"/>
   <size x="1" y="-1" xunits="fraction" yunits="fraction"/>
</ScreenOverlay> 

Refers to an image in the KMZ file folder:

<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2">

<ScreenOverlay>
<folder>
   <name>Legend name</name>
   <color>ffffffff</color>
   <Icon>
      <href>files/legend.png</href>
   </Icon>
   <overlayXY x="0" y="1" xunits="fraction" yunits="fraction"/>
   <screenXY x="0" y="1" xunits="fraction" yunits="fraction"/>
   <rotationXY x="0" y="0" xunits="fraction" yunits="fraction"/>
   <size x="-1" y="-1" xunits="fraction" yunits="fraction"/>
</folder>
</ScreenOverlay> 

The <Icon> element points to the image to be used. This image file can be located on a file system or on a web server. To position the overlay, change the x and y values of the <overlayXY> and <screenXY> elements, overlayXY maps a point in the image to a point on the screen specified by screenXY, the unit for x and y values can be one of three units: pixels, fraction, and insetPixels. Also the values can be specified in different ways, for example x can be in fraction and y can be in pixels. The <size> element determines the size of the ScreenOverlay, vaule of -1 indicates to use the images’ original dimension. For more detailed explanation of ScreenOverlay’ elements, see KML reference document.


External links

https://github.com/jbeezley/WRF-GoogleEarth