In this video, learn how to extend your GUI by turning it into a weather app using data from NOAA. First, use previously saved data to populate your GUI, and in the end, directly retrieve the weather data in real time from the website.
- [Narrator] In this video, we will enhance our GUI, and populate it with weather data. First, we create a new labelframe. Next, we move the location label, and the combobox into this new labelframe. So here, we create the new labelframe, and we position it in column zero, and row zero. Now, there was already the weather_conditions_frame in row zero, so we have to move that one row down.
So that's very easy using the grid layout manager. All we have to do is change row zero to row one, and create the new frame. Column zero, row zero. And then we put our combobox and the label into the new weather_cities_frame labelframe. When we now run the code, GUI looks like this. Location label combobox are in a new labelframe up here. And the Current Weather Conditions are still down here, as they were before.
Compare that to our previous GUI, you can see that Location and combobox were all in Current Weather Conditions. Now we move them out and above into it's own labelframe. When we get data from the National Oceanic and Atmospheric Administration website, it will eventually be in a dictionary format. So here we've done a menu search result, and placed the data into this dictionary. So the keys are on the left hand side, and the values on the right hand side.
So weather, for example, is partly cloudy, wind degrees, 250. So, what we do now is, we're going to update all of our text entry widgets with this data. So the way to do it, is we use a variable we have saved for each of the entries, and we call on each variable the set method. And we pass in the weather_data dictionary. We give it a key, and that will return the value for us.
We do that for all of them. And sometimes we add a little bit more text. And, when we run our GUI now, we can see that all of our fields, all of our entries have been populated with data. It's read-only, so we cannot change it, but we can highlight it, copy and paste it. Now this data is hard-coded. When we change the location, different city, the data doesn't change. When we change it back to the original city, the data also doesn't change.
It's still hard-coded, but we will improve this very soon. We start by creating a dictionary, and the keys will be all of the entries we have in our GUI, and the values at the beginning will all be empty strings. We don't have any data there yet. Next, what we do is, we import urllib request, and then we start to retrieve live data from the website. So in order to do that, we have to build up the url.
It's this one, which at this position requires a station ID. So we are passing in a station_id. In this case it's Los Angeles International Airport as a default. Station_id equals KLAX. And, we code that into a function. And, when we run this. Comment out this line, and run it. And, when we click on get weather, we get the data in xml format.
This is the data from NOAA as of now. It's live from the website. And see here, the date, the time, and the city, and all of this data. So it's in xml format, it's not a dictionary, so we have to transform this xml into the data we want to get. So in order to do this, we import the ElementTree and because we already got the url data, and we transformed it.
We decoded it into a string basically, it's xml but it's already decoded. So, we can import all of the content we just looked at from string, and what that is, it's going to give us the xml_root. When we print this out, we can see that the root is current_observation. And that really is the root of all of the weather data. We go back for a moment, we can run it again.
Uncomment this. Run this again. Click the Get Weather button. And we can see current_observation is the root, which has all of the data we're interested in. The wind_string, temperature in Fahrenheit and Celsius, etc. So the next thing we do is, we use the dictionary we created here, the one that only has keys and empty strings as data, and we look through the results.
We look through all of the keys in our dictionary, call it data_point, and then we use the xml_root, the root element, which is as we saw observation, and we find the data_point which is the key of the dictionary, and we retrieve the text. So, the text is the data. So when we look at our xml again, the one we got from the website, for example, temperature Fahrenheit is the key, and the value is 64.0 degrees.
So what this loop does is, it populates our entire dictionary with values. So we loop through every single key, find it in the xml, and populate the dictionary with the value. We then do the same thing here. We do a wind set weather_data_tags_dict, and then the key as we did before. And when we run it, we can see that our entry text have been populated with live data, from the current web search as of now.
When we click the Get Weather button, we are calling this get_station callback function. This one gets the value of the station_id combobox as station, passes it into the get_weather_data function, and after that we populate the GUI from the dictionary, which has been populated by the get_weather_data function. So, when we run it, for now we have hard-coded three values here.
We have one for Los Angeles, for Denver, and for New York City. So when we change to Denver, we can click Get Weather, and see this is the weather for Denver International Airport in Colorado, and these are the current conditions. You can go to New York City, Get Weather for New York, Central Park, and these are it's current conditions. Now, how do we find out the station ids for a particular city and a particular state in the United States? What we've done here, is on tab two, we've created another combobox, and we are populating this combobox with all 50 states of the United States.
Now when we run the GUI, and when we switch to tab two, we can select a state. After selecting a state, California. And we click on Get Cities. We get all of the cities where NOAA has a weather station, or weather data available. So what we can do is, we can highlight any of the station ids, copy them, go back to tab one, override the current one, paste it in there, click on Get Weather, and this will get the weather for this station id.
This happens to be Fullerton, in California. We can also get data from any state. Maybe New Jersey. Click Get Cities. Here's another one. Another code we can try. So we copy this one, go back to tab one. Make this station id the current one in this combobox. Click on Get Weather. And this one is Caldwell, in New Jersey.
Now, how does this work? It works like this. When we click the Get Cities button, we are calling this callback function, which gets the current state from this combobox, and then it passes it into the get_city_station_ids method. This method uses a special url, which is this one here, and we are passing in the state into the placeholder here. So state equals, the default would be ca, but in our case we just run New Jersey. Now this has to be lowercase, so we make the state lowercase, because in our combobox it's all in uppercase.
Has to be lowercase otherwise it doesn't work. So the rest of the code is similar. We do urllib request urlopen, pass in the url. Get the content back, read it, and decode it. Now there's one difference though. In the first example, we got back xml. But in this case, we're actually getting back html. It's not quite the same. So when we uncomment this, and run it.
And click on Get Cities. This is what we're getting back. This is the html we're getting back, and in the middle of all of this is the data we are interested in. So below all of the different states that are available for search, here comes the interesting part. So we're interested in station id equals the id.
And then, and the name of the city that belongs to this id. So, in order to get to this data, we have to do it slightly different. It's not xml, it's html. So what we did here is, we created a WeatherHTMLParser, and this one is very simple. It inherits from the HTMLParser, which we import from html.parser. It inherits from it, and then we have to call super on it.
So we initialize the base class, the super class. And we create two lists, for stations and for cities, and we say grab_data. So, basically the HTMLParser has handle_starttag, handle_data, and many other functions or methods. And, what we are interested in is only if display station id is in that attribute, then we clean it up a little bit. We only want to get the station id, not the other thing that's surrounding it.
And we append the station id to the self stations list. And we say grab data true, because only when we get, in all of this html, only when we get a station id, are we interested in the city, and the city is under data. So, once we get a station id, we set this to true, then we grab the data, append it to cities, and it works. We have the station id in the stations list.
We have the cities that belong to it in the cities list. And in the end we can bring it together. We make a check here. We verify that the lengths of our stations equals the lengths of our cities. If not, something went wrong. So this does match. And then what we do is, we just put it together, and then we insert it into our scrolltextbox control. So in the end, we get this result where we have the city.
Sometimes longer, sometimes it spans a line. The city, and the station id, again and again. And we do that for all 50 states. And this is how we can find within a specific state, for a specific station, what the station id is. Then we can pass it in here, and we can run it. When we run it for Los Angeles International Airport, we get the following data right now. And, we can run the same url in a browser.
And we are getting the exact same data, because it's the same url we are running. You can see, fair, 64 degrees, 59. It's all the same data. So what we've done is, we've scraped the NOAA website, getting back the xml, passing the xml, and putting it into our own GUI. 84 percent humidity, 84 percent. Date, time, everything is the same.
In order to display images, we can pip install Pillow in Python 2.x. It was called PIL, Python Imaging Library. But in Python 3, this doesn't work. But there is something called Pillow, which does the same thing. So once we've pip installed Pillow, we can import from it Image, and ImageTK. So with Image, we can open pgn image, as image. And then we pass that into PhotoImage, ImageTK.
We get a photo. And now, all we have to do is place that photo as image into ttk Label. And, we have a few images here of weather data, so I've put that onto tab three. So when we run this, and when we click on tab three, we can see some data icons some image.
Note: This course was created by Packt Publishing. We are pleased to host this training in our library.
- Running Python programs within Eclipse
- Setting breakpoints
- Using the PyDev debugger
- Using design patterns
- Creating a GUI application with Tkinter
- Writing a Windows scheduling service