Difference between revisions of "Visualization in Google Earth"

From openwfm
Jump to navigation Jump to search
m (Changed the original ncEarth.py link)
(added category)
Line 154: Line 154:
  
 
[[Category:Visualization]]
 
[[Category:Visualization]]
 +
[[Category:WRF-Fire]]

Revision as of 17:43, 10 February 2011

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.

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.

Python Class for creating WRF-Fire animations

For a more complicated example of automating the creation of KML files from NetCDF, see the Python module ncEarth at [1]. This can easily be extended to provide more functionality or to output KML from other models. The following code can be used to display an animation of the heat flux from a WRF-Fire simulation using this module.

import ncEarth
kmz=ncEarth.ncWRFFire_mov('wrfout')
kmz.write('FGRNHFX')

Creating preloaded WRF-Fire animations

The preloading functionality is an extension of the ncEarth module that accomplishes preloading the set of images that is in KML 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. The following code is an example of generating a preloaded animation of the heat flux from a wrfout output file.

import ncEarth
kmz=ncEarth.ncWRFFire_mov('wrfout')
kmz.write_preload('FGRNHFX')

Creating WRF-Fire animation legend

For clarity, we will need a legend for the animation. Since we only need one legend image for the animation, we can follow the steps of generating an image from raw data, and then save the image with its color bar. Post process the image by using image editing programs such as Paint, GIMP, Photoshop that has the crop function to get the color bar image by itself. After getting the image, we can use ScreenOverlay to display the legend in a fixed position on the screen. Here are some examples of ScreenOverlay.

Refer 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> 

Refer 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.