LoginSignup
2
2

More than 1 year has passed since last update.

OpenWeatherMapとPySimpleGUIでお天気表示GUIを作る

Posted at

はじめに

OpenWeatherMapでデータを取得してPySimpleGUIで天気を表示しました。
image.png

OpenWeatherMapについて

実装コードにはOpenWeatherMapのAPIを利用しています。
利用するにはAPIkeyの取得が必要です。
取得方法については以下にまとめられています。
無料天気予報APIのOpenWeatherMapを使ってみる

実装コード

from tkinter import font
import requests
import json
import PySimpleGUI as sg


class MyWeather:
    API_Endpoint = "http://api.openweathermap.org/data/2.5/forecast"
    API_Key = "あなたのkeyを入力"
    location = "Osaka"
    query = {"q": location, "APPID": API_Key, "lang": "ja"}
    data = requests.get(API_Endpoint, params=query).json()
    WEATHER_LENGTH = 10#天気を返す数 三時間ごと

    def __init__(self):
        pass

    def getTime(self, num):
        # 時間 19XX-01-01 00:00:00のように返ってくる
        time = self.data["list"][num]["dt_txt"]
        return time

    def getIconID(self,num):#デバッグ用
        weather = self.data["list"][num]["weather"]
        icon = weather[0]["icon"]
        return icon
    def getWeather(self, num):  # 天気アイコンのパスを返す

        sunnyImage = "weather/icon/sunny_icon.png"
        fewCloudsImage = "weather/icon/fewClouds_icon.png"
        brokenCloudsImage = "weather/icon/brokenClouds_icon.png"
        cloudyImage = "weather/icon/cloudy_icon.png"
        rainyImgae = "weather/icon/rainy_icon.png"
        snowImage = "weather/icon/snow_icon.png"
        thunderImage = "weather/icon/thunder_icon.png"
        errorImage = "weather/icon/error_icon.png"

        weather = self.data["list"][num]["weather"]
        icon = weather[0]["icon"]
        if icon == "01n" or icon == "01d":
            return sunnyImage
        elif icon == "02d" or icon == "02n":
            return fewCloudsImage
        elif icon == "03d" or icon == "03n":
            return cloudyImage
        elif icon == "04d" or icon == "04n":
            return brokenCloudsImage
        elif icon == "09d" or icon == "09n":
            return rainyImgae
        elif icon == "10d" or icon == "10n":
            return rainyImgae
        elif icon == "11d" or icon == "11n":
            return thunderImage
        elif icon == "13d" or icon == "13n":
            return snowImage
        else:
            return errorImage

    def drawScreen(self):
        sg.theme("Python")#GUIの配色

        title = [
            [sg.Text(str(self.getTime(0))+'~' +
                     str(self.getTime(self.WEATHER_LENGTH-1)+'の'+self.location+'の'+'天気'), font=('メイリオ', 20))]
        ]
        titleFrame = sg.Frame(
            '', [[sg.Column(title, justification='c')]], size=(self.WEATHER_LENGTH*150, 100))


        timeText = [[]]
        timeFrame = [[]]
        timeFrameBig = [[]]
        for i in range(self.WEATHER_LENGTH):
            time = str(self.getTime(i).split(' ', 1)[1])
            time = time.split(':', 1)[0]
            timeText = [sg.Column
                        ([[sg.Text(time+'時', font=('メイリオ', 30))]], justification='c')]
            timeFrame[0].extend(
                [sg.Frame('', [timeText], size=(150, 100))])
        timeFrameBig = [[sg.Frame('', [timeFrame[0]])]]


        icon = [[]]
        iconFrame = [[]]
        iconFrameBig = [[]]
        for i in range(self.WEATHER_LENGTH):
            icon = [
                sg.Column([[sg.Image(self.getWeather(i))]], justification='c')]
            iconFrame[0].extend(
                [sg.Frame('', [icon], size=(150, 120))])
        iconFrameBig = [[sg.Frame('', [iconFrame[0]])]]


        layout = [[titleFrame], [timeFrameBig], [iconFrameBig]]
        window = sg.Window("お天気", layout, resizable=True)
        while True:
            event, values = window.read()
            if event == sg.WIN_CLOSED:
                break

        window.close()

def main():
    hoge = MyWeather()
    hoge.drawScreen()
    return 0


if __name__ == "__main__":
    main()

API部(OpenWeatherMap部)

class MyWeather:
    API_Endpoint = "http://api.openweathermap.org/data/2.5/forecast"
    API_Key = "あなたのkeyを入力"
    location = "Osaka"
    query = {"q": location, "APPID": API_Key, "lang": "ja"}
    data = requests.get(API_Endpoint, params=query).json()

classの先頭でAPIに渡す情報を作っています。
queryの内容やAPIの返答内容(dataの中身)はOpenWeatherMapのFAQみたいなところに書いてあります。
参考にした記事:APIの仕組みが分かる・使いこなせる人材になれる記事(Pythonコード付き)

描画部(PySimpleGUI部)

    def drawScreen(self):
        sg.theme("Python")#GUIの配色

        title = [
            [sg.Text(str(self.getTime(0))+'~' +
                     str(self.getTime(self.WEATHER_LENGTH-1)+'の'+self.location+'の'+'天気'), font=('メイリオ', 20))]
        ]
        titleFrame = sg.Frame(
            '', [[sg.Column(title, justification='c')]], size=(self.WEATHER_LENGTH*150, 100))


        timeText = [[]]
        timeFrame = [[]]
        timeFrameBig = [[]]
        for i in range(self.WEATHER_LENGTH):
            time = str(self.getTime(i).split(' ', 1)[1])
            time = time.split(':', 1)[0]
            timeText = [sg.Column
                        ([[sg.Text(time+'時', font=('メイリオ', 30))]], justification='c')]
            timeFrame[0].extend(
                [sg.Frame('', [timeText], size=(150, 100))])
        timeFrameBig = [[sg.Frame('', [timeFrame[0]])]]


        icon = [[]]
        iconFrame = [[]]
        iconFrameBig = [[]]
        for i in range(self.WEATHER_LENGTH):
            icon = [
                sg.Column([[sg.Image(self.getWeather(i))]], justification='c')]
            iconFrame[0].extend(
                [sg.Frame('', [icon], size=(150, 120))])
        iconFrameBig = [[sg.Frame('', [iconFrame[0]])]]


        layout = [[titleFrame], [timeFrameBig], [iconFrameBig]]
        window = sg.Window("お天気", layout, resizable=True)
        while True:
            event, values = window.read()
            if event == sg.WIN_CLOSED:
                break

        window.close()

描画部分です。

        layout = [[titleFrame], [timeFrameBig], [iconFrameBig]]
        window = sg.Window("お天気", layout, resizable=True)
        while True:
            event, values = window.read()
            if event == sg.WIN_CLOSED:
                break

layout内にGUIのレイアウトを記述します。レイアウトについては以下の記事が参考になると思います。

pythonでも簡単にGUIは作れる
PySimpleGUIのレイアウトの設定方法

タイトル部

   def drawScreen(self):
        sg.theme("Python")#GUIの配色

        title = [
            [sg.Text(str(self.getTime(0))+'~' + #self.getTime(i)の返り値→ 19XX-YY-ZZ xx:yy:zz
                     str(self.getTime(self.WEATHER_LENGTH-1)+'の'+self.location+'の'+'天気'), font=('メイリオ', 20))]
        ]
        titleFrame = sg.Frame(
            '', [[sg.Column(title, justification='c')]], size=(self.WEATHER_LENGTH*150, 100))


image.png
赤枠の部分です。sg.Text単体では文章を中央揃えにできなさそうなので、sg.Columnを介して中央揃えにしています。

時間部


        timeText = [[]]
        timeFrame = [[]]
        timeFrameBig = [[]]
        for i in range(self.WEATHER_LENGTH):#self.getTime(i)の返り値→ 19XX-YY-ZZ xx:yy:zz
            time = str(self.getTime(i).split(' ', 1)[1])#xx:yy:zz
            time = time.split(':', 1)[0]#xx
            timeText = [sg.Column
                        ([[sg.Text(time+'時', font=('メイリオ', 30))]], justification='c')]
            timeFrame[0].extend(
                [sg.Frame('', [timeText], size=(150, 100))])
        timeFrameBig = [[sg.Frame('', [timeFrame[0]])]]

image.png
赤枠の部分です。リストの入れ子構造を間違えてエラーが頻発しました。
ここもsg.Columnで中央揃えにしています。

アイコン部

        icon = [[]]
        iconFrame = [[]]
        iconFrameBig = [[]]
        for i in range(self.WEATHER_LENGTH):
            icon = [
                sg.Column([[sg.Image(self.getWeather(i))]], justification='c')]#self.getWeatherの返り値は画像のパス
            iconFrame[0].extend(
                [sg.Frame('', [icon], size=(150, 120))])
        iconFrameBig = [[sg.Frame('', [iconFrame[0]])]]

image.png
赤枠の部分です。self.getWeather(i)は画像のパスを返します。

getWeather

    def getWeather(self, num):  # 天気アイコンのパスを返す

        sunnyImage = "weather/icon/sunny_icon.png"
        fewCloudsImage = "weather/icon/fewClouds_icon.png"
        brokenCloudsImage = "weather/icon/brokenClouds_icon.png"
        cloudyImage = "weather/icon/cloudy_icon.png"
        rainyImgae = "weather/icon/rainy_icon.png"
        snowImage = "weather/icon/snow_icon.png"
        thunderImage = "weather/icon/thunder_icon.png"
        errorImage = "weather/icon/error_icon.png"

        weather = self.data["list"][num]["weather"]
        icon = weather[0]["icon"]
        if icon == "01n" or icon == "01d":
            return sunnyImage
        elif icon == "02d" or icon == "02n":
            return fewCloudsImage
        elif icon == "03d" or icon == "03n":
            return cloudyImage
        elif icon == "04d" or icon == "04n":
            return brokenCloudsImage
        elif icon == "09d" or icon == "09n":
            return rainyImgae
        elif icon == "10d" or icon == "10n":
            return rainyImgae
        elif icon == "11d" or icon == "11n":
            return thunderImage
        elif icon == "13d" or icon == "13n":
            return snowImage
        else:
            return errorImage

天気アイコンはicoon-mono 様のものをお借りしました。
また、OpenWetherMapに詳細なアイコンのIDがあります。

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2