{"id":171,"date":"2023-02-26T02:36:52","date_gmt":"2023-02-26T02:36:52","guid":{"rendered":"https:\/\/noerguerra.com\/?p=171"},"modified":"2023-05-31T12:07:25","modified_gmt":"2023-05-31T12:07:25","slug":"python-and-flask-101-how-to-make-your-own-weather-forecast-application","status":"publish","type":"post","link":"https:\/\/noerguerra.com\/blog\/python-and-flask-101-how-to-make-your-own-weather-forecast-application\/","title":{"rendered":"Python and Flask 101: How to Make Your Own Weather Forecast Application"},"content":{"rendered":"<p>Weather forecast applications are a prominent part of our daily lives. They help us plan our day and stay ahead of any inclement weather.<\/p>\n<p>Nowadays, every smart device includes one of those apps. You can find them in smartphones, smart bands, smart assistants, and even refrigerators.<\/p>\n<p>While weather forecast applications have varying degrees of complexity, they all boil-down to the same basic principle: Showing you the expected weather for the upcoming day.<\/p>\n<p>Creating a weather forecast application is a great place to start with your coding journey, since this can be a challenging yet useful project, without being too overly complex.<\/p>\n<p>In this article, we will be utilizing the power of Python and Flask to build a simple weather forecast application that you can access through your web browser.<\/p>\n<p>Python is a versatile, high-level programming language that is easy to learn and widely used for a variety of applications. Flask is a popular Python web framework that enables us to develop web applications with ease. By combining them, we can build dynamic and interactive web applications that can do almost anything we can imagine!<\/p>\n<p>In this article, you are going to find a comprehensive guide for beginners on how to create a weather forecast application using Python and Flask. I will be covering all the essential steps involved, from setting up the development environment to deploying the application to a hosting platform.<\/p>\n<p>Let&#8217;s get started!<\/p>\n<h2>TL;DR<\/h2>\n<p>In this article we will use Flask and Python to develop an application from scratch. This application will retrieve the local weather information by calling OpenWeatherMap&#8217;s API and will display the results in your browser, with some basic styling on top.<\/p>\n<p>You can access the project&#8217;s code in this <a href=\"https:\/\/github.com\/NoeRGuerra\/Weather-Forecast-App\" title=\"GitHub repository\">GitHub repository<\/a>.<\/p>\n<h2>Setting up the Development Environment<\/h2>\n<p>Before we can start building our weather forecast application, we need to set up our development environment. Here&#8217;s what you&#8217;ll need to get started:<\/p>\n<ul>\n<li>\n<p>Python: You will need to <a href=\"https:\/\/www.digitalocean.com\/community\/tutorials\/install-python-windows-10\" title=\"install Python\">install Python on your computer<\/a>. You can download it from the <a href=\"https:\/\/www.python.org\/downloads\/\">official Python website<\/a>.<\/p>\n<\/li>\n<li>\n<p>Flask: Once you have Python installed, you can install Flask using the Python Package Manager (pip). Install it by running the following command in your terminal or command prompt:<br \/>\n<code><code>pip install flask<\/code><\/code><\/p>\n<blockquote>\n<p>Note: It is recommended to work on a virtual environment before installing modules like Flask. Virtual Environments allow you to isolate dependencies from the rest of your system. You can read more on RealPython&#8217;s <a href=\"https:\/\/realpython.com\/python-virtual-environments-a-primer\/\" title=\"Guide to Virtual Environments\">Guide to Virtual Environments<\/a>.<\/p>\n<\/blockquote>\n<\/li>\n<li>\n<p>Text Editor or IDE: You will also need a text editor or IDE to write and run your Python code. There are many options available, such as Sublime Text, Visual Studio Code, or PyCharm. If you want to know more about some good options, you can take a look at my <a href=\"https:\/\/noerguerra.com\/a-guide-to-choosing-the-right-python-ide\/\">Guide to choosing the right Python IDE<\/a>.<br \/>\nFor this project, I recommend using <a href=\"https:\/\/code.visualstudio.com\/Download\" title=\"VS Code\">VS Code<\/a>, but feel free to go for any other text editor if you prefer.<\/p>\n<\/li>\n<li>\n<p>API Key: To retrieve the weather data, we will be using an API. For this article, we will be using OpenWeatherMap API. You will need to sign up for a free API key to be able to use the API in your application.<\/p>\n<\/li>\n<li>\n<p>Git: Git is a version control system that allows you to keep track of changes to your code. While it is not necessary for this project, it is a good idea to get into the habit of using version control from the beginning. You can download Git from the official website (<a href=\"https:\/\/git-scm.com\/downloads\">https:\/\/git-scm.com\/downloads<\/a>).<\/p>\n<\/li>\n<\/ul>\n<h3>Creating a new project and setting up the file structure<\/h3>\n<p>Once you got these tools ready, it&#8217;s time to start building our weather forecast application.<\/p>\n<p>First, create an empty folder with the name <code>Weather Forecast<\/code>. This will be the root folder of your project.<br \/>\nNext, create a file named <code>weather_app.py<\/code>. The file structure will look like this:<\/p>\n<pre><code>\ud83d\udce6 Weather Forecast\n\u2514\u2500\u2500 \ud83d\udcdc weather_app.py<\/code><\/pre>\n<p>Open the folder in your text editor. Then, copy and paste the following code in <code>weather_app.py<\/code>:<\/p>\n<pre><code class=\"language-python\">from flask import Flask, render_template\n\napp = Flask(__name__)\n\n@app.route(&quot;\/&quot;)\ndef home():\n    return &#039;Hello, World!&#039;\n\nif __name__ == &quot;__main__&quot;;:\n    app.run(debug=True)<\/code><\/pre>\n<p>The previous block of code is just a basic template for Flask applications. By running this script, you&#8217;ll be able to access the program by navigating to <code>localhost:5000<\/code> in your browser. The resulting page will display a &quot;Hello, World!&quot; message.<\/p>\n<p><a href=\"https:\/\/noerguerra.com\/wp-content\/uploads\/2023\/02\/hello_world_flask.png\"><img decoding=\"async\" src=\"https:\/\/noerguerra.com\/wp-content\/uploads\/2023\/02\/hello_world_flask.png\" alt=\"\" \/><\/a><\/p>\n<p>In the following section, we will be retrieving data from the API and processing it with Python to display the local weather in your browser.<\/p>\n<h2>Understanding the API used to Fetch Weather Data<\/h2>\n<p>For this project, we&#8217;ll be using the OpenWeatherMap API, which allows us to retrieve the weather forecast information we need for our app.<br \/>\nBut before we start coding, here&#8217;s a quick recap on APIs and why it&#8217;s a good idea to use them in this project.<\/p>\n<h3>Overview of APIs<\/h3>\n<p>APIs, or Application Programming Interfaces, are tools that allow software applications to communicate with each other. By calling an API, developers can retrieve and manipulate data from other applications without having to worry about the underlying technology that the data comes from.<br \/>\nSince modern web applications can be complex systems that work based on data coming from multiple sources, APIs are a crucial component of many modern web applications that save developers a lot of time when building said applications.<\/p>\n<h3>Explanation of the weather API used in this project<\/h3>\n<p>OpenWeatherMap is a service that provides weather information for cities around the world. They offer a free tier of access to their API, that we&#8217;ll be using to generate our weather forecast. This API provides a wide range of data, including current weather conditions, weather forecasts, historical weather data, and more.<\/p>\n<h3>Registering for an API key<\/h3>\n<p>When working with APIs, especially paid ones, you might often find that you require an API Key to retrieve the information. This way, unathorized access and unintended use can be avoided by the developers of the API.<\/p>\n<p>OpenWeatherMap&#8217;s API is no exception, and you&#8217;ll need to sign up on their website for an API Key.<br \/>\nThe process is pretty straightforward: Go to the <a href=\"https:\/\/openweathermap.org\/api\" title=\"OpenWeatherMap API website\">OpenWeatherMap API website<\/a> and sign up for an account. After you have confirmed your e-mail, you will receive a message with your API Key.<br \/>\nThe API Key activation is not always immediate, and might take up to two hours to be ready to use.<\/p>\n<p>With our API key in hand, we can now start building the backend of our weather forecast app using Flask.<\/p>\n<p>In the next section, we&#8217;ll learn how to set up our Flask application, define routes and views, and create a function to fetch weather data from the API.<\/p>\n<h2>Creating the Backend with Flask<\/h2>\n<p>The next steps are building the backend of the application. The code we are going to write will retrieve the weather forecast information using the API key from the previous section, and will display it on a web page that you can access through your web browser.<\/p>\n<h3>Setting up the Flask application<\/h3>\n<p>Open the file we created before, <code>weather_app.py<\/code>, and add your API key at the top of the code, like this:<\/p>\n<pre><code class=\"language-python\">from flask import Flask, render_template\n\napp = Flask(__name__)\nAPI_KEY = &quot;YOUR_API_KEY&quot;;<\/code><\/pre>\n<p>Don&#8217;t forget to replace the API Key string with your own API key.<br \/>\nIn the previous code, <code>API_KEY<\/code> is declared outside of any function. This means that it is a  global variable, and can be accessed freely by any function declared in this file.<\/p>\n<p>The next step is to create a function to retrieve the weather information.<br \/>\nThe OpenWeatherMap API lets you do this by specifying a city name, or by passing the coordinates of the place you want. Although just calling for a city&#8217;s name might seem simplier, using coordinates you can get precise weather for the area and also avoid a situation where two cities in the same country share the same name, so that&#8217;s the method I&#8217;ll be using here.<br \/>\nThere are many ways to find the coordinates of a zip code, one of them is to go to Google Maps and right click on a location.<br \/>\n<a href=\"https:\/\/noerguerra.com\/wp-content\/uploads\/2023\/02\/coordinates.png\"><img decoding=\"async\" src=\"https:\/\/noerguerra.com\/wp-content\/uploads\/2023\/02\/coordinates.png\" alt=\"\" \/><\/a><\/p>\n<p>Now it&#8217;s time to retrieve the current weather information, calling the OpenWeatherMap APi through the <code>get_weather_data<\/code> function:<\/p>\n<pre><code class=\"language-python\">def get_weather_data(latitude, longitude):\n    url = &quot;https:\/\/api.openweathermap.org\/data\/2.5\/weather?&quot;\n    url = f&quot;{url}lat={latitude}&amp;lon={longitude}&amp;appid={API_KEY}&amp;units=metric&quot;\n    response = requests.get(url)\n    return response.json()<\/code><\/pre>\n<p>This function receives two parameters, <code>latitude<\/code> and <code>longitude<\/code>, that are later passed to the API call.<br \/>\nThe <code>url<\/code> variable stores the access point to the API. Using f-strings, we replace the values for <code>latitude<\/code>, <code>longitude<\/code>, and <code>API_KEY<\/code> in the URL. I also defined <code>&amp;units=metric<\/code> to get the temperature in Celsius. You can change this value to <code>imperial<\/code> to get the temperature in Fahrenheit.<br \/>\nTo fetch the data from the API, you need to make an HTTP request the API&#8217;s endpoint. We can do that by importing the <code>requests<\/code> module and calling <code>requests.get()<\/code> with the URL as an argument, and storing the result in <code>response<\/code>.<br \/>\nCalling <code>response<\/code> after this would return a status code <code>&lt;Response [200]&gt;<\/code> if the request was successful, but that still won&#8217;t let us take a look at the weather data. To do that, we need to call <code>response.json()<\/code>, which will return the weather forecast data in JSON format.<br \/>\nJSON stands for JavaScript Object Notation, and is a format that we can use to easily parse the data from the response.<\/p>\n<h3>Defining routes and views<\/h3>\n<p>In Flask, a route represents the URL that users can visit, while a view is the function executed when that route is visited.<br \/>\nFor example, in this app we only have one route defined (&quot;\/&quot;), and one view (<code>home()<\/code>) that returns the string <code>&quot;Hello, world!&quot;<\/code> and displays it to the user.<\/p>\n<p>Now, it&#8217;s time to update the <code>home()<\/code> function to display the weather for the selected location.<\/p>\n<pre><code class=\"language-python\">@app.route(&quot;\/&quot;)\ndef home():\n    latitude = 35.22592847208098\n    longitude = -80.85293281605993\n    weather_data = get_weather_data(latitude, longitude)\n    temperature = weather_data[&#039;main&#039;][&#039;temp&#039;]\n    description = weather_data[&#039;weather&#039;][0][&#039;description&#039;]\n    city = weather_data[&#039;name&#039;]\n\n    return render_template(&#039;weather.html&#039;, temperature=temperature, description=description, city=city)<\/code><\/pre>\n<p>The previous code does:<\/p>\n<ul>\n<li>Define the <code>latitude<\/code> and <code>longitude<\/code> of the place we want to check.<\/li>\n<li>Call <code>get_weather_data()<\/code> and pass the coordinates we just defined as parameters. The result of performing the HTTP request is stored in <code>weather_data<\/code>, in JSON format.<\/li>\n<li>In Python, data formatted in JSON can be read as a dictionary, which let&#8217;s us easily access each part of the information we are looking for.<br \/>\nIf you take a look at the values returned by <code>get_weather_data()<\/code>, you&#8217;ll see something like this:<\/p>\n<pre><code class=\"language-python\">...\n&quot;main&quot;:{\n        &quot;temp&quot;:284.31,\n        &quot;feels_like&quot;:282.71,\n        &quot;temp_min&quot;:284.31,\n        &quot;temp_max&quot;:285.21,\n        &quot;pressure&quot;:1027,\n        &quot;sea_level&quot;:1027,\n        &quot;grnd_level&quot;:1002,\n        &quot;humidity&quot;:47,\n        &quot;temp_kf&quot;:-0.9\n     },\n&quot;weather&quot;:[\n        {\n           &quot;id&quot;:802,\n           &quot;main&quot;:&quot;Clouds&quot;,\n           &quot;description&quot;:&quot;scattered clouds&quot;,\n           &quot;icon&quot;:&quot;03d&quot;\n        }\n     ],\n...<\/code><\/pre>\n<p>This is just a fragment of the data, but it shows the nested structure of the file, very similar to dictionaries. Since every part of the data contains key-value pairs, JSON files are often accessed as dictionaries in Python.<\/p>\n<\/li>\n<li>Finally, the function <code>render_template()<\/code> is called. This function generates, or renders, the webpage that is going to be displayed to the user, based on an HTML template. <code>render_template()<\/code> also accepts receiving values that can later be used in the HTML template.<br \/>\nIf you try to run the code as is at this point, you will get an error since the <code>weather.html<\/code> template has not been created yet.<br \/>\nIn the next section, we&#8217;ll go over what Jinja templates are, and how you can use them to display information to users.<\/li>\n<\/ul>\n<h2>Displaying the fetched data on a web page<\/h2>\n<p>Before knowing how to display the data on a web page, it&#8217;s important to know what Jinja templates are, and how we can use them with Flask.<\/p>\n<h3>Setting up the template<\/h3>\n<p>Since the contents of a web application are usually dynamic, that is, they are often changing, regular static HTML pages would not be enough to display the weather data we retrieved from OpenWeatherMap to the user. Instead, Flask relies on Jinja templates to create webpages with dynamic values.<\/p>\n<p>Jinja templates are a type of HTML pages designed with Python in mind. While they are very similar to, they can receive parameters for dynamic content.<br \/>\nFor example, a static HTML page that displays the current weather might look like this:<\/p>\n<pre><code class=\"language-html\">&lt;body&gt;\n  &lt;h1&gt;Weather Forecast - Charlotte&lt;\/h1&gt;\n  &lt;p&gt;The temperature is 12\u00b0C.&lt;\/p&gt;\n  &lt;p&gt;The current weather is cloudy.&lt;\/p&gt;\n&lt;\/body&gt;<\/code><\/pre>\n<p>Being static content, the page won&#8217;t update unless you make changes manually to it. On the other side, a Jinja template might look like this:<\/p>\n<pre><code class=\"language-html\">&lt;body&gt;\n  &lt;h1&gt;Weather Forecast - {{ city }}&lt;\/h1&gt;\n  &lt;p&gt;The temperature is {{ temperature }}\u00b0C.&lt;\/p&gt;\n  &lt;p&gt;The current weather is {{ description }}.&lt;\/p&gt;\n&lt;\/body&gt;<\/code><\/pre>\n<p>Where <code>city<\/code>, <code>temperature<\/code>, and <code>description<\/code> can be variables that can be replaced with values from our Python code when calling <code>render_template()<\/code> in our view.<\/p>\n<h3>Updating the file structure<\/h3>\n<p>In Flask, the <code>templates<\/code> folder is where you store your Jinja templates. Without this folder, your program won&#8217;t be able to find any HTML files that you might use.<br \/>\nTherefore, the file structure will look like this now:<\/p>\n<pre><code>\ud83d\udce6Weather Forecast\n \u2523 \ud83d\udcc2templates\n \u2503 \u2517 \ud83d\udcdcweather.html\n \u2517 \ud83d\udcdcweather_app.py<\/code><\/pre>\n<h3>Displaying the data on a webpage<\/h3>\n<p>Finally, to display the retrieved data from OpenWeatherMap on a webpage, you&#8217;ll need to define your template on <code>weather.html<\/code>.<\/p>\n<pre><code class=\"language-html\">&lt;!DOCTYPE html&gt;\n&lt;html&gt;\n&lt;head&gt;\n  &lt;title&gt;Weather Forecast&lt;\/title&gt;\n&lt;\/head&gt;\n&lt;body&gt;\n  &lt;h1&gt;Weather Forecast - {{ city }}&lt;\/h1&gt;\n  &lt;p&gt;The temperature is {{ temperature }}\u00b0C.&lt;\/p&gt;\n  &lt;p&gt;The current weather is {{ description }}.&lt;\/p&gt;\n&lt;\/body&gt;\n&lt;\/html&gt;<\/code><\/pre>\n<p>After saving that file on the <code>templates<\/code> folder, you can run <code>weather.py<\/code> and go to <code>localhost:5000<\/code> or <code>127.0.0.1:5000<\/code> to see the result.<br \/>\n<a href=\"https:\/\/noerguerra.com\/wp-content\/uploads\/2023\/02\/weather_charlotte.png\"><img decoding=\"async\" src=\"https:\/\/noerguerra.com\/wp-content\/uploads\/2023\/02\/weather_charlotte.png\" alt=\"\" \/><\/a><\/p>\n<p>And that&#8217;s it. We have finished building a basic weather app using Flask and Python. However, there&#8217;s still a lot that we can add to it to make it more appealing or functional<br \/>\nKeep reading to find out how to further improve this application.<\/p>\n<h2>Improving the application<\/h2>\n<p>Doing small retouches to the app, we can add functionality like getting a 5-day forecast or improving the look of the application.<br \/>\nLet&#8217;s start by adding some color and icons.<\/p>\n<h3>Adding a CSS Stylesheet<\/h3>\n<p>We can apply styles to the a HTML page using CSS stylesheets, which are &quot;static&quot; files. Static files are files that don&#8217;t change while you application is running, like images, JavaScript files, and CSS files.<br \/>\nTo access static files using Flask, you need to store them in the <code>static<\/code> folder, at the root of your application.<br \/>\nNow, the structure of your app will look like this after creating <code>style.css<\/code><\/p>\n<pre><code>\ud83d\udce6Weather Forecast\n\u2523 \ud83d\udcc2static\n\u2503 \u2517 \ud83d\udcdcstyle.css\n\u2523 \ud83d\udcc2templates\n\u2523 \u2517 \ud83d\udcdcweather.html\n\u2517 \ud83d\udcdcweather_1.py<\/code><\/pre>\n<p>The next step is to link the CSS stylesheet to the HTML template. To accomplish this, we&#8217;ll use the <code>url_for()<\/code> function to find the static folder, passing the name of the file as an argument.<\/p>\n<pre><code class=\"language-html\">&lt;head&gt;;\n  &lt;title&gt;Weather Forecast&lt;\/title&gt;\n  &lt;link rel=&quot;stylesheet&quot; href=&quot;{{ url_for(&#039;static&#039;, filename=&#039;style.css&#039;) }}&quot;&gt;\n&lt;\/head&gt;<\/code><\/pre>\n<p>And in <code>style.css<\/code> we can add a nice blue background with a gradient by passing two RGB colors to <code>linear-gradient<\/code> and setting it as a background image, like this:<\/p>\n<pre><code class=\"language-css\">body{\n    background-image: linear-gradient(to right,rgb(146, 192, 219), rgb(76, 146, 250));\n}<\/code><\/pre>\n<p>After adding the background color, the page should look like this:<br \/>\n<a href=\"https:\/\/noerguerra.com\/wp-content\/uploads\/2023\/02\/weather_app_1.jpeg\"><img decoding=\"async\" src=\"https:\/\/noerguerra.com\/wp-content\/uploads\/2023\/02\/weather_app_1.jpeg\" alt=\"\" \/><\/a><\/p>\n<p>In the next section, I&#8217;ll show you how to add an icon to display besides the temperature.<\/p>\n<h3>Adding weather icons<\/h3>\n<p>Images and icons help improve the look of any application considerably and instantly make it look more friendly and approachable. Thanks to the <code>icon<\/code> key included with the data from OpenWeatherMap API, we can easily identify which icon we need to show to match the current weather.<br \/>\n<a href=\"https:\/\/openweathermap.org\/weather-conditions#Icon-list\" title=\"You can read more about OpenWeatherMap icons here\">You can read more about OpenWeatherMap icons here<\/a>.<\/p>\n<p>To represent the different weather conditions, I downloaded the icons from <a href=\"https:\/\/github.com\/manifestinteractive\/weather-underground-icons\/tree\/master\/dist\/icons\/white\/svg\" title=\"this Github repository\">this Github repository<\/a>. Since these are vector graphics in SVG format, we won&#8217;t have to worry about the resolution of the icons later when upscaling them.<\/p>\n<p>The process of adding icons to the application can be broken down into these steps:<\/p>\n<ul>\n<li>Adding the icons to the  <code>static<\/code> directory.<\/li>\n<li>Updating the Python code to dynamically select the right icon to display<\/li>\n<li>Updating the Jinja template to receive and display the icon to the user<\/li>\n<li>Update the design of the app using CSS<\/li>\n<\/ul>\n<p>Let&#8217;s start by creating a directory with the name <code>icons<\/code> in the <code>static<\/code> directory of our application, so the structure of the application will now look like this:<\/p>\n<pre><code>\ud83d\udce6Weather Forecast\n\u2523 \ud83d\udcc2static\n\u2503 \u2523 \ud83d\udcc2icons\n\u2503 \u2503 \u2523 \ud83d\udcdcclear.svg\n\u2503 \u2503 \u2523 \ud83d\udcdc...\n\u2503 \u2503 \u2517 \ud83d\udcdctstorms.svg\n\u2503 \u2517 \ud83d\udcdcstyle.css\n\u2523 \ud83d\udcc2templates\n\u2523 \u2517 \ud83d\udcdcweather.html\n\u2517 \ud83d\udcdcweather_1.py<\/code><\/pre>\n<p>Next, we&#8217;ve got to update our Python code.<br \/>\nSince the icon&#8217;s code is one of the values that we get from calling OpenWeatherMap&#8217;s API, I created a dictionary to map the icon codes to filenames in the icons directory:<\/p>\n<pre><code class=\"language-python\">icon_filenames = {&#039;01d&#039;: &#039;clear&#039;,\n                  &#039;01n&#039;: &#039;nt_clear&#039;,\n                  &#039;02d&#039;: &#039;cloudy&#039;,\n                  &#039;02n&#039;: &#039;cloudy&#039;,\n                  &#039;03d&#039;: &#039;cloudy&#039;,\n                  &#039;03n&#039;: &#039;cloudy&#039;,\n                  &#039;04d&#039;: &#039;cloudy&#039;,\n                  &#039;04n&#039;: &#039;cloudy&#039;,\n                  &#039;09d&#039;: &#039;chancerain&#039;,\n                  &#039;09n&#039;: &#039;chancerain&#039;,\n                  &#039;10d&#039;: &#039;rain&#039;,\n                  &#039;10n&#039;: &#039;rain&#039;,\n                  &#039;11d&#039;: &#039;tstorms&#039;,\n                  &#039;11n&#039;: &#039;tstorms&#039;,\n                  &#039;13d&#039;: &#039;snow&#039;,\n                  &#039;13n&#039;: &#039;snow&#039;,\n                  &#039;50d&#039;: &#039;fog&#039;,\n                  &#039;50n&#039;: &#039;fog&#039;, }\n\n@app.route(&#039;\/&#039;)\n...<\/code><\/pre>\n<p>By creating a dictionary like this, we can easily get the right filename that corresponds to each code.<br \/>\nFor example, the dictionary will return the filename <code>nt_clear<\/code> when we call it using the code <code>01n<\/code> as our key:<\/p>\n<pre><code class=\"language-python\">>&gt;&gt; icon_filenames[&#039;01n&#039;]\n&#039;nt_clear &#039;<\/code><\/pre>\n<p>In order to display the selected icon, it is necessary to create a URL that points at the file, so that it can be displayed through the resulting HTML page and served to the user. To do that, we have to update the <code>home()<\/code> function.<\/p>\n<pre><code class=\"language-python\">@app.route(&#039;\/&#039;)\ndef home():\n    latitude = 35.22592847208098\n    longitude = -80.85293281605993\n    weather_data = get_weather_data(latitude, longitude)\n    temperature = weather_data[&#039;main&#039;][&#039;temp&#039;]\n    description = weather_data[&#039;weather&#039;][0][&#039;description&#039;]\n    city = weather_data[&#039;name&#039;]\n    icon = weather_data[&#039;weather&#039;][0][&#039;icon&#039;] # Get icon filename from dictionary \n    icon_url = url_for(&#039;static&#039;, filename=f&#039;icons\/{icon_filenames[icon]}.svg&#039;) # Dynamically generate icon&#039;s URL\n\n    return render_template(&#039;weather.html&#039;, temperature=temperature, description=description, city=city, icon_url=icon_url) # Pass icon&#039;s URL as a parameter<\/code><\/pre>\n<p>Next, we are going to edit our HTML template to add an <code>&lt;img\/&gt;<\/code> tag to feature the icon for the current weather. In this case, I grouped the <code>&lt;img\/&gt;<\/code> and <code>&lt;p&gt;<\/code> tags together inside a <code>&lt;div&gt;<\/code> to later apply styling on both elements using the CSS Stylesheet.<\/p>\n<pre><code class=\"language-html\">&lt;h1&gt;Weather Forecast - {{ city }}&lt;\/h1&gt;\n  &lt;div id=&quot;main-temp&quot;&gt;\n    &lt;img src=&quot;{{ icon_url }}&quot;\/&gt;\n    &lt;p&gt;The temperature is {{ temperature }}\u00b0C&lt;\/p&gt;\n  &lt;\/div&gt;\n  &lt;p&gt;The current weather is {{ description }}.&lt;\/p&gt;<\/code><\/pre>\n<p>Finally, we add this code at the end of <code>style.css<\/code>:<\/p>\n<pre><code class=\"language-css\">#main-temp{\n    \/* Use flexbox to center the elements horizontally and vertically *\/\n    display: flex;\n    \/* Set the font size to 96 pixels *\/\n    font-size: 96px;\n    \/* Center the elements horizontally *\/\n    justify-content: center;\n    \/* Center the elements vertically *\/\n    align-items: center\n}\n\nimg{\n    \/* Set the width of the image to 2em (relative to the font size of the parent element) *\/\n    width: 2em;\n}<\/code><\/pre>\n<p>Now, the page will look like this:<br \/>\n<a href=\"https:\/\/noerguerra.com\/wp-content\/uploads\/2023\/02\/weather_forecast_1.png\"><img decoding=\"async\" src=\"https:\/\/noerguerra.com\/wp-content\/uploads\/2023\/02\/weather_forecast_1-1024x232.png\" alt=\"\" \/><\/a><\/p>\n<h3>Tweaking the application<\/h3>\n<p>Before moving forward to add a 5-day forecast, there are some quick tweaks that can make our application look better.<\/p>\n<p>Starting with <code>weather.py<\/code>, we can round up the temperature value, and capitalize the description of the current weather like this:<\/p>\n<pre><code class=\"language-python\">@app.route(&quot;\/&quot;)\ndef home():\n    ...\n\n    return render_template(&#039;weather.html&#039;,\\ \n    temperature=round(temperature), description=description.capitalize(), \\\n    city=city, icon_url=icon_url)<\/code><\/pre>\n<p>On <code>weather.html<\/code>, we can remove some of the additional text and display only the most important values to the user. I also moved the weather description to the top:<\/p>\n<pre><code class=\"language-html\">...\n&lt;body&gt;\n    &lt;h1&gt;{{ city }}&lt;\/h1&gt;\n    &lt;p id=&quot;description&quot;&gt;{{ description }}&lt;\/p&gt; &lt;!-- Add identifier to description for styling --&gt;\n    &lt;div id=&quot;main-temp&quot;&gt;\n      &lt;img src=&quot;{{ icon_url }}&quot;\/&gt;\n      &lt;p&gt;{{ temperature }}\u00b0C&lt;\/p&gt;\n    &lt;\/div&gt;\n&lt;\/body&gt;\n...<\/code><\/pre>\n<p>Most changes are done in the CSS stylesheet, like switching all text to white, changing the font, and centering the headers and text:<\/p>\n<pre><code class=\"language-css\">body{\n    background-image: linear-gradient(to right,rgb(146, 192, 219), rgb(76, 146, 250));\n    color:white; \/* Make all text white *\/\n    font-family: sans-serif; \/* Change all fonts to sans-serif *\/\n}\n...\nh1, h2, h3, h4, h5, h6, #description{\n    text-align: center; \/* Center headers and weather description *\/\n}<\/code><\/pre>\n<p>Now the application will look like this:<br \/>\n<a href=\"https:\/\/noerguerra.com\/wp-content\/uploads\/2023\/02\/weather_forecast_2.png\"><img decoding=\"async\" src=\"https:\/\/noerguerra.com\/wp-content\/uploads\/2023\/02\/weather_forecast_2-1024x543.png\" alt=\"\" \/><\/a><\/p>\n<p>In the next section, I&#8217;ll show you how to add a 5-day weather forecast.<\/p>\n<h3>Adding 5-day weather forecast<\/h3>\n<p>OpenWeatherMap also provides us with a different API endpoint to retrieve the 5-day weather forecast. The information retrieved includes max and minimum temperatures every three hours for the following 5-days and the current day.<\/p>\n<p>We can create a function very similar to <code>get_weather_data()<\/code> to retrieve the forecast information, calling the different API endpoint for this task:<\/p>\n<pre><code class=\"language-python\">def get_forecast_data(latitude, longitude):\n    url = f&quot;http:\/\/api.openweathermap.org\/data\/2.5\/forecast?&quot;\n    url = f&quot;{url}lat={latitude}&amp;lon={longitude}&amp;appid={API_KEY}&amp;units=metric&quot;\n    response = requests.get(url)\n    return response.json()<\/code><\/pre>\n<p>We are looking to display the weather in a table like this:<\/p>\n<table>\n<thead>\n<tr>\n<th>Day<\/th>\n<th>Weather<\/th>\n<th>Max\/Min<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Tuesday<\/td>\n<td>\u2600<\/td>\n<td>18\u00b0C\/13\u00b0C<\/td>\n<\/tr>\n<tr>\n<td>Wednesday<\/td>\n<td>\u2601<\/td>\n<td>19\u00b0C\/12\u00b0C<\/td>\n<\/tr>\n<tr>\n<td>Thursday<\/td>\n<td>\ud83c\udf27<\/td>\n<td>16\u00b0C\/11\u00b0C<\/td>\n<\/tr>\n<tr>\n<td>Friday<\/td>\n<td>\u26c8<\/td>\n<td>18\u00b0C\/10\u00b0C<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>While the response from the API call includes a lot of data, only some values are relevant for this project: Date of the forecast, max and minimum temps, and icon.<br \/>\nFor reference, the response from the API call looks like this (shortened for brevity):<\/p>\n<pre><code class=\"language-python\">  {&#039;dt&#039;: 1677110400,\n   &#039;main&#039;: {&#039;temp&#039;: 21.58,\n    &#039;temp_min&#039;: 19.05,\n    &#039;temp_max&#039;: 21.58,\n    },\n   &#039;weather&#039;: [{&#039;id&#039;: 803,\n     &#039;main&#039;: &#039;Clouds&#039;,\n     &#039;description&#039;: &#039;broken clouds&#039;,\n     &#039;icon&#039;: &#039;04n&#039;}],\n   &#039;dt_txt&#039;: &#039;2023-02-23 00:00:00&#039;},\n  {&#039;dt&#039;: 1677121200,\n   &#039;main&#039;: {&#039;temp&#039;: 20.42,\n    &#039;temp_min&#039;: 18.1,\n    &#039;temp_max&#039;: 20.42,\n    },\n   &#039;weather&#039;: [{&#039;id&#039;: 803,\n     &#039;main&#039;: &#039;Clouds&#039;,\n     &#039;description&#039;: &#039;broken clouds&#039;,\n     &#039;icon&#039;: &#039;04n&#039;}],\n   &#039;dt_txt&#039;: &#039;2023-02-23 03:00:00&#039;},\n   ...<\/code><\/pre>\n<p>If you look at the data, you can see that it is segmented in three hour intervals for the same day. While we can easily retrieve the weather conditions and the icon for each day, there is no set Max and Min values for a full day. However, we can write a function to list the hourly values and get the daily max and minimum temperatures:<\/p>\n<pre><code class=\"language-python\">import datetime # Import datetime\n...\ndef get_max_min_temp(forecast_data):\n    # Create an empty dictionary to store the temperature data for each day\n    temp_by_date = {}\n\n    # Loop through the forecast data\n    for item in forecast_data[&#039;list&#039;]:\n        # Extract the date and icon for the item\n        dt = datetime.datetime.fromtimestamp(item[&#039;dt&#039;])\n        date = dt.date()\n        icon = item[&#039;weather&#039;][0][&#039;icon&#039;]\n\n        # If the date isn&#039;t already in the dictionary, add it\n        if date not in temp_by_date:\n            temp_by_date[date] = {&#039;temps&#039;: [], &#039;icons&#039;: []}\n\n        # Add the temperature and icon data to the dictionary\n        temp_by_date[date][&#039;temps&#039;].append(item[&#039;main&#039;][&#039;temp&#039;])\n        temp_by_date[date][&#039;icons&#039;].append(icon)\n\n    # Loop through the dictionary to calculate the max and min temperature for each day\n    for date, temps_icons in temp_by_date.items():\n        max_temp = round(max(temps_icons[&#039;temps&#039;]))\n        min_temp = round(min(temps_icons[&#039;temps&#039;]))\n        icon = temps_icons[&#039;icons&#039;][0]\n        icon = icon_filenames[icon]\n\n        # Replace the temperature and icon lists with the max\/min temperature and the first icon\n        temp_by_date[date] = {&#039;max_temp&#039;: max_temp, &#039;min_temp&#039;: min_temp, &#039;icon&#039;: icon}\n\n    # Return the updated temperature dictionary\n    return temp_by_date\n<\/code><\/pre>\n<p>In this function:<\/p>\n<ul>\n<li>Dictionaries are used to store a list of the max and minimum tempteratures for every three hour period of a day, along with the icons for each day, using dates as values.<\/li>\n<li>The max and minimum temperature for each day are found using <code>max()<\/code> and <code>min()<\/code> on the stored lists.<\/li>\n<li>The max and minimum temperature values replace the lists for each date and are returned with the respective icon.<\/li>\n<\/ul>\n<p>And we can update <code>home()<\/code> again to call <code>get_forecast_data()<\/code> and <code>get_max_min_temp()<\/code>, and passing the result to <code>render_template()<\/code>:<\/p>\n<pre><code class=\"language-python\">@app.route(&quot;\/&quot;)\ndef home():\n    latitude = 35.22592847208098 \n    longitude = -80.85293281605993\n\n    weather_data = get_weather_data(latitude, longitude)\n    temperature = weather_data[&#039;main&#039;][&#039;temp&#039;]\n    description = weather_data[&#039;weather&#039;][0][&#039;description&#039;]\n    city = weather_data[&#039;name&#039;]\n    icon = weather_data[&#039;weather&#039;][0][&#039;icon&#039;]\n    icon_url = url_for(&#039;static&#039;, filename=f&#039;icons\/{icon_filenames[icon]}.svg&#039;)\n\n    forecast_data = get_forecast_data(latitude, longitude)\n    weather_by_date = get_max_min_temp(forecast_data) # Get max and min temperatures for each day with icons\n\n    # Add weather_by_date as a parameter\n    return render_template(&#039;weather.html&#039;, temperature=temperature, \\\n    description=description, city=city, icon_url=icon_url, \\\n    weather_by_date=weather_by_date)<\/code><\/pre>\n<h4>Displaying the weather forecast using loops<\/h4>\n<p>So far, we&#8217;ve been just passing variables and displaying them to the user using Jinja templates. However, the 5-day forecast data is inside of a dictionary, so there is no single variable that we can call to display the temperatures as a table. That&#8217;s when <code>for<\/code> loops come into play.<br \/>\nThe basic syntax for a <code>for<\/code> loop is the following:<\/p>\n<pre><code class=\"language-html\">{% for item in collection %}\n    {{ item }}\n{% endfor %}<\/code><\/pre>\n<p>As opposed to Python&#8217;s <code>for<\/code> loop, Jinja <code>for<\/code> loops requires the <code>{% endfor %}<\/code> statement to enclose the instructions in the loop.<br \/>\nFor example, if we have a list of numbers:<\/p>\n<pre><code class=\"language-python\">list_of_numbers = [10, 20, 30, 40, 50]<\/code><\/pre>\n<p>We could represent it using an ordered list and a <code>for<\/code> loop in a HTML template:<\/p>\n<pre><code class=\"language-HTML\">&lt;ol&gt;\n    {% for number in list_of_numbers %}\n    &lt;li&gt;{{ number }}&lt;\/li&gt;\n    {% endfor %}\n&lt;\/ol&gt;<\/code><\/pre>\n<p>The <code>for<\/code> loop would iterate over the list and create a <code>&lt;li&gt;<\/code> element for each element in the list.<br \/>\nThis would be the output of the previous code:<\/p>\n<pre><code class=\"language-HTML\">&lt;ol&gt;\n  &lt;li&gt;10&lt;\/li&gt;\n  &lt;li&gt;20&lt;\/li&gt;\n  &lt;li&gt;30&lt;\/li&gt;\n  &lt;li&gt;40&lt;\/li&gt;\n  &lt;li&gt;50&lt;\/li&gt;\n&lt;\/ol&gt;<\/code><\/pre>\n<p>For our weather app, we can create a <code>&lt;table&gt;<\/code>, where each element of the dictionary would occupy a cell of each table row.<\/p>\n<pre><code class=\"language-HTML\">&lt;body&gt;\n  &lt;h1&gt;{{ city }}&lt;\/h1&gt;\n  &lt;p id=&quot;description&quot;&gt;{{ description }}&lt;\/p&gt;\n  &lt;div id=&quot;main-temp&quot;&gt;\n    &lt;img src=&quot;{{ icon_url }}&quot;\/&gt;\n    &lt;p&gt;{{ temperature }}\u00b0C&lt;\/p&gt;\n  &lt;\/div&gt;\n\n  &lt;table&gt;\n    &lt;thead&gt;\n      &lt;tr&gt;\n        &lt;th colspan=&quot;3&quot;&gt;5-day Forecast&lt;\/th&gt; &lt;!-- Add a header that takes three columns --&gt;\n      &lt;\/tr&gt;\n    &lt;\/thead&gt;\n    &lt;tbody&gt;\n      {% for date in weather_by_date %} &lt;!-- Start the loop --&gt;\n        &lt;tr&gt;\n          &lt;td class=&quot;forecast-days&quot;&gt;{{ date.strftime(&quot;%A&quot;) }}&lt;\/td&gt; &lt;!-- Display the day&#039;s name --&gt;\n          &lt;td class=&quot;forecast-icons&quot;&gt;&lt;img src=&quot;{{ url_for(&#039;static&#039;, filename=&#039;icons\/&#039; + weather_by_date[date][&#039;icon&#039;] + &#039;.svg&#039;) }}&quot; class=&quot;forecast-icon&quot;&gt;&lt;\/td&gt; &lt;!-- Dynamically get the corresponding icon for each day --&gt;\n          &lt;td class=&quot;forecast-temps&quot;&gt;{{ weather_by_date[date][&#039;max_temp&#039;] }}\u00b0C \/ {{ weather_by_date[date][&#039;min_temp&#039;] }}\u00b0C&lt;\/td&gt; &lt;!-- Display max and min temperature --&gt;\n        &lt;\/tr&gt;\n      {% endfor %}\n    &lt;\/tbody&gt;\n  &lt;\/table&gt;\n&lt;\/body&gt;<\/code><\/pre>\n<p>Now, the app should look like this:<br \/>\n<a href=\"https:\/\/noerguerra.com\/wp-content\/uploads\/2023\/02\/weather_forecast_3.png\"><img decoding=\"async\" src=\"https:\/\/noerguerra.com\/wp-content\/uploads\/2023\/02\/weather_forecast_3-1024x410.png\" alt=\"\" \/><\/a><\/p>\n<p>We can still add some more styling to enhance the look of the application before finishing, since right now things are a little hard to read.<\/p>\n<h4>Additional styling<\/h4>\n<p>To make the table more easily readable, we can add a semi-transparent dark background that contrasts with the white font.<\/p>\n<pre><code class=\"language-css\">\/* Add padding, center text and align content vertically for table headers and data cells *\/\ntd {\n    padding: 10px;\n    text-align: center;\n    vertical-align: top;\n    \/* Set a semi-transparent black background color and add margin between cells *\/\n    background-color: rgba(0,0,0,0.4);\n}\n\n\/* Increase header size, add a darker background and round the corners *\/\nth{\n    font-size: 1.5em;\n    background-color: rgba(0,0,0,0.5);\n    border-top-right-radius: 10px;\n    border-top-left-radius: 10px;\n}\n<\/code><\/pre>\n<p>And then extend the table to cover the full page&#8217;s width:<\/p>\n<pre><code class=\"language-css\">\/* Set table width to 100% and remove cell borders *\/\ntable {\n    width: 100%;\n    border-collapse: collapse;\n}<\/code><\/pre>\n<p>Finally, we can move the columns of the table closer by changing their alignment:<\/p>\n<pre><code class=\"language-CSS\">\/* Align day labels to the right *\/\n.forecast-days {\n    text-align: right;\n}\n\n\/* Align temperature data to the left *\/\n.forecast-temps {\n    text-align: left;\n}<\/code><\/pre>\n<p>After applying this changes, the weather forecast application should look similar to this:<br \/>\n<a href=\"https:\/\/noerguerra.com\/wp-content\/uploads\/2023\/02\/weather_forecast_5.png\"><img decoding=\"async\" src=\"https:\/\/noerguerra.com\/wp-content\/uploads\/2023\/02\/weather_forecast_5-1024x547.png\" alt=\"\" \/><\/a><\/p>\n<h2>Final thoughts and next steps<\/h2>\n<p><a href=\"https:\/\/noerguerra.com\/wp-content\/uploads\/2023\/02\/pexels-caio-174540.jpg\"><img decoding=\"async\" src=\"https:\/\/noerguerra.com\/wp-content\/uploads\/2023\/02\/pexels-caio-174540-1024x681.jpg\" alt=\"\" \/><\/a><br \/>\nCongratulations! You have successfully built a weather forecast application using Python and Flask. By now, you may have gained a good understanding of how to create a Flask application from scratch, fetch data from an API, and display it on a webpage using Jinja templates. You have also seen how to add styling to your application using CSS and how to make use of icons to enhance the look and feel of the application.<\/p>\n<p>However, there are still many ways to improve this application, for example:<\/p>\n<ul>\n<li>\n<p>Add more data points: OpenWeatherMap&#8217;s API let&#8217;s you retrieve a lot more data than just what we used. You can add more information such as wind speed, humidity, and precipitation to provide a more complete weather forecast.<\/p>\n<\/li>\n<li>\n<p>Add more interactivity: You can add more features to make the application more interactive and versatile. For example, you can add a field to allow users input their ZIP Code and convert it to coordinates for the program to use, or do it automatically by calling the web browser&#8217;s geolocation API.<\/p>\n<\/li>\n<li>\n<p>Deploy the application: Deploying your application to a live server allows users to access it from anywhere in the world. Some hosting platforms you can use to deploy your Flask application are Heroku, PythonAnywhere, and AWS.<\/p>\n<\/li>\n<\/ul>\n<p>Overall, building a weather forecast application with Python and Flask is a great way to learn the basics of web development. By following this tutorial and exploring the next steps, you can create a more sophisticated application and take your skills to the next level. For example, take a look at how I expanded this application on <a href=\"https:\/\/github.com\/NoeRGuerra\/WeatherForecastApp\" title=\"this GitHub repository\">this GitHub repository<\/a> \ud83d\ude42<\/p>\n<p>Good luck!<\/p>\n<blockquote>\n<p>You can take a look at all the code included in this article in this <a href=\"https:\/\/github.com\/NoeRGuerra\/Weather-Forecast-App\" title=\"GitHub repository\">GitHub repository<\/a>.<\/p>\n<\/blockquote>\n","protected":false},"excerpt":{"rendered":"<p>Weather forecast applications are a prominent part of our daily lives. They help us plan our day and stay ahead of any inclement weather. Nowadays, every smart device includes one of those apps. You can find them in smartphones, smart bands, smart assistants, and even refrigerators. While weather forecast applications have varying degrees of complexity,&hellip; <a class=\"more-link\" href=\"https:\/\/noerguerra.com\/blog\/python-and-flask-101-how-to-make-your-own-weather-forecast-application\/\">Continue reading <span class=\"screen-reader-text\">Python and Flask 101: How to Make Your Own Weather Forecast Application<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":290,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[10],"tags":[15,16],"class_list":["post-171","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-programming-tutorials","tag-flask","tag-web-development","entry"],"_links":{"self":[{"href":"https:\/\/noerguerra.com\/blog\/wp-json\/wp\/v2\/posts\/171","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/noerguerra.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/noerguerra.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/noerguerra.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/noerguerra.com\/blog\/wp-json\/wp\/v2\/comments?post=171"}],"version-history":[{"count":83,"href":"https:\/\/noerguerra.com\/blog\/wp-json\/wp\/v2\/posts\/171\/revisions"}],"predecessor-version":[{"id":297,"href":"https:\/\/noerguerra.com\/blog\/wp-json\/wp\/v2\/posts\/171\/revisions\/297"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/noerguerra.com\/blog\/wp-json\/wp\/v2\/media\/290"}],"wp:attachment":[{"href":"https:\/\/noerguerra.com\/blog\/wp-json\/wp\/v2\/media?parent=171"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/noerguerra.com\/blog\/wp-json\/wp\/v2\/categories?post=171"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/noerguerra.com\/blog\/wp-json\/wp\/v2\/tags?post=171"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}