3
\$\begingroup\$

I am writing a python GUI application that plots weather data on a map for a specific region. It plots temperature, dewpoint, wind data, and icons that represent the sky conditions. It extracts the data for longitude/latitude from text files. I timed out how long it takes for the program to plot each type of weather data and I got the following results:

temperature: 10 seconds

dewpoint: 10 seconds

wind: 15 seconds

sky conditions: 90 seconds

So, it doesn't take too long for it to plot temperature, dewpoint, and wind. However, it takes a very long time for it to plot the sky conditions, which are icon images. My goal is for my application to display any kind of weather data in a few seconds. I am wondering what I can do to my python code to make it more efficient and run faster, so it meets that goal.

I use global variables, which I know is not good programming practice. This is likely one thing I am doing in my code that is slowing things down. I also use numerous function calls, which could also be slowing things down as well. I would like to rewrite my code, so that I don't use so many global variables and function calls.

The biggest problem I think is when it displays the icons, which are images as stated above. I am new at working with images in python, so I don't know if python is just slow with dealing with images or not. Any analysis of my code/suggestions to make it better would be greatly appreciated.

import tkinter as tk
from tkinter import ttk
import tkinter.font as tkFont
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
import matplotlib.image as mpimg
from mpl_toolkits.basemap import Basemap
from PIL import Image
from matplotlib.offsetbox import OffsetImage, AnnotationBbox
import matplotlib.pyplot as plt
import numpy as np
import requests

def retrieve_filedata():
      file = area.get() + '.txt'
      f = open(file, 'r')
      line = f.readline()
      global minlon
      minlon = float(line.split(' ')[0])
      global minlat
      minlat = float(line.split(' ')[1])
      global maxlon
      maxlon = float(line.split(' ')[2])
      global maxlat
      maxlat = float(line.split()[3])
      global centerlat
      centerlat = float(line.split()[4]) 
      global centerlon
      centerlon = float(line.split()[5]) 
      
      lines = f.readlines()[1:] #put longitude and latitudes into array
      global lat
      lat = []
      global lon
      lon = []

      for x in lines:
         lat.append(float(x.split(' ')[0]))
         lon.append(float(x.split()[1]))
      f.close()

def current_weather():
       retrieve_filedata()
       key = '4a7a419e4e16e2629a4cedc37cbf7e50'
       url = 'https://api.openweathermap.org/data/2.5/weather'
       global observation
       observation = []
       global u
       u = []
       global v
       v = []
       global icon
       icon = []
       for i in range(0,len(lon)):
          params = {'lat': lat[i], 'lon': lon[i], 'appid': key, 'units': 'imperial'}
          response = requests.get(url, params = params)
          weather = response.json()
          airtemp = round(weather['main']['temp'])
          humidity = weather['main']['humidity'] #relative humidity
          kelvin = ((airtemp-32)/1.8)+273 #convert temperature from F to Kelvin
          #E = 0.611 * np.exp(5423 * ((1/273) - (1/dewpoint))) vapor pressure
          Es = 0.611 * np.exp(5423 * ((1/273) - (1/kelvin))) #saturation vapor pressure
          kelvindew = 5423/((5423/273)-np.log(((humidity/100)*Es)/0.611)) #use vapor pressure equation to find dewpoint in Kelvin
          dewpoint = round(((kelvindew-273)*1.8)+32) #convert dewpoint from Kelvin to F
          windspeed = round(weather['wind']['speed'])
          winddirection = weather['wind']['deg']
          u.append(-(windspeed)*np.sin(((np.pi)/180)*winddirection))
          v.append(-(windspeed)*np.cos(((np.pi)/180)*winddirection))
          icon.append(weather['weather'][0]['icon'])
          if data.get() == 'Temperature':
             observation.append(airtemp)
          if data.get() == 'Dewpoint':
             observation.append(dewpoint)

def display_winds():
   current_weather()
   map = Basemap(llcrnrlon= minlon, llcrnrlat= minlat, urcrnrlon= maxlon, urcrnrlat= maxlat ,resolution='i',
             lat_0 = centerlat, lon_0 = centerlon)
   for i in range(0, len(lon)):
      x,y = map(lon[i], lat[i])
      map.barbs(x, y, u[i], v[i], length = 5, pivot = 'middle', zorder = 100)
   plt.show()

def display_icons():
    map = Basemap(llcrnrlon= minlon, llcrnrlat= minlat, urcrnrlon= maxlon, urcrnrlat= maxlat ,resolution='i',
             lat_0 = centerlat, lon_0 = centerlon)
    image = []
    im = []
    ab = []
    x,y = map(lon, lat) 
    for i in range(0, len(lon)):
       image.append(Image.open(requests.get('http://openweathermap.org/img/wn/' + icon[i] + '@2x.png', stream=True).raw))
       im.append(OffsetImage(image[i], zoom = 0.25))
       ab.append(AnnotationBbox(im[i], (x[i],y[i]), frameon=False))
       map._check_ax().add_artist(ab[i])
plt.show()

def plot_data():     
    current_weather()
    map = Basemap(llcrnrlon= minlon, llcrnrlat= minlat, urcrnrlon= maxlon, urcrnrlat= maxlat ,resolution='i',
             lat_0 = centerlat, lon_0 = centerlon)
    map.drawmapboundary(fill_color='#A6CAE0')
    map.drawcounties(zorder = 20)
    map.drawstates()
    map.fillcontinents(color='#e6b800',lake_color='#A6CAE0') 
    for i in range(0, len(lon)):
         x,y = map(lon[i], lat[i])
         if data.get() == 'Temperature' or data.get() == 'Dewpoint':
             plt.text(x, y, observation[i], fontsize = 7)
         if data.get() == 'Wind':
             display_winds()
         if data.get() == 'Sky Conditions':
             display_icons()
    plt.show()

root = tk.Tk()
canvas = tk.Canvas(root, height = '300', width = '400')
canvas.pack()

#create widgets
titlefont = tkFont.Font(size = 20)
title = tk.Label(text = "Current Weather Map Data", font = titlefont)

arealabel = tk.Label(text = "Choose Region: ")
areavalue = tk.StringVar()
area = ttk.Combobox(root, width = '13', textvariable = areavalue)

datalabel = tk.Label(text = "Choose Data: ")
datavalue = tk.StringVar()
data = ttk.Combobox(root, width = '12', textvariable = datavalue)

button = tk.Button(root, text = "Plot Data", command = plot_data)

#organize widgets
title.place(relx = 0.1, rely = 0.05)
arealabel.place(relx = 0.05, rely = 0.25)
area.place(relx = 0.35, rely = 0.25)
datalabel.place(relx = 0.05, rely = 0.40)
data.place(relx = 0.35, rely = 0.40)
button.place(relx = 0.40, rely = 0.65)

#Insert Values into Area Combobox
area['values'] = ('Pennsylvania', 'Maryland', 'Delaware', 'New Jersey', 'Virginia', 'West Virginia', 'Ohio', 'New York',
                  'Rhode Island', 'Massachusetts', 'Connecticut', 'Vermont', 'New Hampshire', 'Maine', 'Mid Atlantic', 'New England')
area.current(0)

#Insert Values into Data Combobox
data['values'] = ('Temperature', 'Dewpoint', 'Wind', 'Sky Conditions')
data.current(0)

root.mainloop()
\$\endgroup\$
  • \$\begingroup\$ Looks like your internet is slow or that api's server is slow in serving you.Lots of get requests for image download, code has to be slow. \$\endgroup\$ – Vishesh Mangla Jul 23 at 17:16
  • \$\begingroup\$ Code can be made faster if you download images in async but I don't have experience with that. \$\endgroup\$ – Vishesh Mangla Jul 23 at 17:25
  • \$\begingroup\$ Please show a sample of your input text file. \$\endgroup\$ – Reinderien Jul 26 at 2:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.