Building a Layer for Google Sky
In this exercise, we will take a look at how to build layers for the Sky feature in Google Earth (http://earth.google.com). We will be building and editing files written in the Keyhole Markup Language (KML). KML is XML which the Google Earth client translates into features on the globe. If you wish to follow along with this lecture, you will need to download the Google Earth client, if not, don't worry. This lecture will be moved to here after the Summer School is over.
The obvious thing to do with a vast unclutterd panorama is to put up a bunch of stick pins to mark places interesting to you. The first thing we'll do is use the interactive placemark wizard. Search for Leo in the search box. This should take you to the constellation Leo. If not, double click on the graticule next to the name Leo in the search results. Now you can zoom in and out using the wheel on your mouse or by using the control surfaces in the upper right of the view port. Let's put down a mark right here, so that we can share the location of Leo with our friends and collaborators. Click on the pushpin icon in the navigation bar at the top of the screen (see the circled icon in Figure 1).
You will now see a dialog box. Add your content and click "OK."
|Figure 2||Figure 3|
<?xml version="1.0" encoding="UTF-8"?> <kml xmlns="http://earth.google.com/kml/2.2" hint="target=sky"> <Document> <name>mymark.kml</name> <StyleMap id="msn_ylw-pushpin"> <Pair> <key>normal</key> <styleUrl>#sn_ylw-pushpin</styleUrl> </Pair> <Pair> <key>highlight</key> <styleUrl>#sh_ylw-pushpin</styleUrl> </Pair> </StyleMap> <Style id="sn_ylw-pushpin"> <IconStyle> <scale>1.1</scale> <Icon> <href>http://maps.google.com/mapfiles/kml/pushpin/ylw-pushpin.png</href> </Icon> <hotSpot x="20" y="2" xunits="pixels" yunits="pixels"/> </IconStyle> <ListStyle> </ListStyle> </Style> <Style id="sh_ylw-pushpin"> <IconStyle> <scale>1.3</scale> <Icon> <href>http://maps.google.com/mapfiles/kml/pushpin/ylw-pushpin.png</href> </Icon> <hotSpot x="20" y="2" xunits="pixels" yunits="pixels"/> </IconStyle> <ListStyle> </ListStyle> </Style> <Placemark> <name>My Placemark</name> <description><![CDATA[Here is a description of my placemark. I can include <a href="http://en.wikipedia.org/wiki/HTML">HTML</a>, if I want.]]></description> <LookAt> <longitude>-19.99352634474181</longitude> <latitude>13.1579726526353</latitude> <altitude>0</altitude> <range>7287.773774440994</range> <tilt>0</tilt> <heading>360.0000000000001</heading> </LookAt> <styleUrl>#msn_ylw-pushpin</styleUrl> <Point> <coordinates>-19.99352634474181,13.1579726526353,0</coordinates> </Point> </Placemark> </Document> </kml> Listing 1
Listing 1 shows the content of the KML file created in making the placemark. The important bits are in read. First, notice the target=sky hint attribute. This tells this client that the content should be displayed in sky mode and will prompt the user to change to sky if they open it in Earth mode. Second is the pointer to the icon. The default template uses two icon definitions to give that "Popping" effect when one mouses over the icon. These URLs can be changed to any icon you wish. Finally, the Placemark tag contains all the relevant info for the marker. The description holds the balloon text and must be in a CDATA block if any HTML is used. The LookAt tag tells the camera what to do when you zoom to this place and the Point tag places the marker on the screen.
You may have noticed that the longitude is negative in the example. This is a strange concept for astronomers where the the longitude coordinate, RA, goes from 0 to 360. Unfortunately, the cartographers never got the memo that longitude should never be negative. In Geographic Information Systems speak longitude goes from -180 to 180. Someone has to budge on this one, and since Earth existed before Sky, it is the astronomers. To convert from RA to longitude simply subtract 180. So, longitude = RA - 180.0 and RA = longitude + 180. I suppose it could have been done to keep zero RA at zero longitude by subtracting 360 if RA > 180, but the current scheme has the advantage of keeping the coordinate system discontinuity at the same place in both representations. Like it or not, that's the situation right now.
You have no doubt noticed that the "to here" and "from here" links are still present in the balloons we made. This is due to the fact that the default layout for the balloons puts those in automatically. They don't make sense in the context of the sky, so let's get rid of them. We do this by adding a BalloonStyle tag. This allows for lots of nice formatting, like background color and font type. We will just touch on how to put text in the balloon today. The text tag can contain HTML, but it can also put in content based on the other tags.
<Style id="sh_ylw-pushpin"> <IconStyle> <scale>1.3</scale> <Icon> <href>http://maps.google.com/mapfiles/kml/pushpin/ylw-pushpin.png</href> </Icon> <hotSpot x="20" y="2" xunits="pixels" yunits="pixels"/> </IconStyle> <ListStyle> </ListStyle> <BalloonStyle> <text><![CDATA[ <b>NAME:</b> $[name]<br> <font color="red">Following is the description:</font><br> $[description] ]]> </text> </BalloonStyle> </Style> Listing 2
Listing 2 shows the addition made to the Style section. The balloon text will now have the name and description substituted where you see the $[name] and $[description] variables. Make sure that you have the styleUrl tag in your placemark, otherwise all your hard work will be ignored. This sort of templating allows you to have the same look and feel for all the balloons without doing the formatting on a balloon by balloon basis. The modified KML can be found here.
Of course you're asking, who would ever have just a single point? Let's put up all the Abell clusters with 10th brightest magnitude brighter than 17.2. I went to Vizier and got the semicolon separated Abell catalog. Then I stripped the header out. Find it here. Then I wrote a little piece of python to output my KML. The resulting file is here. Get the code sample here
#!/usr/bin/env python file = open("abell.tsv") file.readline() print '<?xml version="1.0" encoding="UTF-8"?>' print '<kml xmlns="http://earth.google.com/kml/2.2" hint="target=sky">' print '<Document>' print '<Style id="MyStyle">' print ' <BalloonStyle>' print ' <text><![CDATA[' print ' <b>ACO Cluster:</b> $[name]<br>' print ' <font color="red">Vital Stats:</font><br>' print ' $[description]' print ' ]]>' print ' </text>' print ' </BalloonStyle>' print ' </Style>' for line in file.readlines(): fields = line.split(';') anum = int(fields) ra = float(fields) dec = float(fields) m10 = float(fields) if m10 < 17.2: print ' <Placemark>' print ' <styleUrl>#MyStyle</styleUrl>' print ' <name>Abell %i</name>'%anum print ' <description>m10 = %3.1f</description>'%m10 print ' <LookAt>' print ' <longitude>%f</longitude>'%(ra-180.0) print ' <latitude>%f</latitude>'%(dec) print ' <altitude>0</altitude>' print ' <tilt>0</tilt>' print ' <heading>360.0</heading>' print ' <range>20000</range>' print ' </LookAt>' print ' <Point><coordinates>%f,%f,0</coordinates></Point>'%(ra-180.0, dec) print ' </Placemark>' print '</Document>' print '</kml>' Listing 3
Listing 3 shows the Python code to write out the KML file. As you can see, it just writes a KML file line by line adding placemarks unless the m10 is too faint. The file has about 1000 placemarks in it. On my machine this is o.k, but you may need to play around with how many work on your setup.
I've got images!!!!! Of course this whole thing is less than useful if you can't put up your images. First, let's get an image to work with. I searched Google for images matching "night sky photograph." The first hit is this image: If I knew where this image was taken, I could use the manual alignment tools to import this in Google Earth directly. Since I don't and it is more impressive, I'll use astrometry.net. There is no public interface for astrometry.net, but you can get a tester account or download the source code yourself. The image was solved in just a few seconds returning a wcs solution. If you are following along, grab the png image and wcs. If you have a FITS file with a WCS all ready to go, you can use the fits2png Python program to turn your FITS into a PNG for display in Google Earth. The fits2png program is shipped with wcs2kml.
Now we need to warp from the native projection to the Cartesian projection needed for overlaying on the Google Earth canvas. Jeremy Brewer while interning at Google was nice enough to write a tool for this step. You can get wcs2kml at the Google code repository. After compiling the code, we do:
> wcs2kml -input_image_origin_is_upper_left -imagefile=fullsize.png --fitsfile=wcs.fits Listing 4
The -input_image_origin_is_upper_left flag is necessary because the convention in FITS (and therefore the WCS) is to consider the lower left pixel to be the origin in display space. Most other digital graphics formats, including PNG, call the upper left pixel the origin. Other flags can be supplied to create an image hierarchy appropriate for large images. In this case, a single level of detail is fine. The warped image looks like this:
In addition to the warped image, a file called doc.kml is produced and contains all the necessary info to load the image directly into Google Earth. Open Google Earth, switch to Sky, and select open under the file menu. Navigate to your working directory and open doc.kml. If the client does not navigate automatically, you can double click on the icon in the left panel. Try highlighting the entry on the left panel and sliding the transparency slider at the bottom of the panel.
Hopefully, you now have an idea of how to create placemarks, manipulate balloon content, and add image overlays. With these three components, you can do quite a bit, so go out there and make some layers.