<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged regression</title>
<link>https://coderlegion.com/tag/regression</link>
<description>Powered by Question2Answer</description>
<item>
<title>Mathematical Intuition of Linear Regression</title>
<link>https://coderlegion.com/21641/mathematical-intuition-of-linear-regression</link>
<description>
&lt;p&gt;Hello, I'm Ganesh. I'm building &lt;em&gt;git-lrc&lt;/em&gt;, an AI code reviewer that runs on every commit. It is free, unlimited, and source-available on Github. &lt;a href=&quot;https://github.com/HexmosTech/git-lrc?utm_source=chatgpt.com&quot; rel=&quot;noopener noreferrer nofollow&quot;&gt;Star git-lrc on GitHub&lt;/a&gt; to help more developers discover the project. Do give it a try and share your feedback for improving the product.&lt;/p&gt;

&lt;h2&gt;
  
  
  Linear Regression Line
&lt;/h2&gt;

&lt;p&gt;The line is drawn between two axes, X and Y.&lt;/p&gt;

&lt;p&gt;We can draw infinite lines with different points. But only one will be best fit for the given points.&lt;/p&gt;

&lt;p&gt;For a set of 2D points (x_i,y_i), the simplest linear regression model is:&lt;/p&gt;

&lt;p&gt;y = mx + b&lt;/p&gt;

&lt;p&gt;Where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;(m) = slope&lt;/li&gt;
&lt;li&gt;(b) = intercept&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To compute them from your points:&lt;/p&gt;

&lt;p&gt;Slope:&lt;/p&gt;

&lt;p&gt;m = (n&amp;sum;xy&amp;minus;(&amp;sum;x)(&amp;sum;y)) / (n&amp;sum;x^2&amp;minus;(&amp;sum;x)^2)&lt;/p&gt;

&lt;p&gt;Intercept:&lt;/p&gt;

&lt;p&gt;b = (&amp;sum;y&amp;minus;m&amp;sum;x) / n&lt;/p&gt;

&lt;p&gt;Then your best-fit line is:&lt;/p&gt;

&lt;p&gt;y = mx + b&lt;/p&gt;

&lt;h2&gt;
  
  
  Calculation of Slope
&lt;/h2&gt;

&lt;p&gt;For example points:&lt;/p&gt;

&lt;div class=&quot;table-wrapper-paragraph&quot;&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;x&lt;/th&gt;
&lt;th&gt;y&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Result:&lt;br&gt;
m = 0.8&lt;br&gt;
b = 1.5&lt;/p&gt;

&lt;p&gt;Best-fit line:&lt;br&gt;
y = 0.8x + 1.5&lt;/p&gt;

&lt;p&gt;Finally we get the result:&lt;/p&gt;

&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Few64hqcrljd446ltg4jz.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Few64hqcrljd446ltg4jz.png&quot; alt=&quot;&quot; width=&quot;361&quot; height=&quot;299&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/HexmosTech/git-lrc&quot; rel=&quot;noopener noreferrer nofollow&quot;&gt;&lt;img src=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fabn6nl3iehrohehnxgje.png&quot; alt=&quot;git-lrc&quot; width=&quot;800&quot; height=&quot;373&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Any feedback or contributors are welcome! It&amp;rsquo;s online, source-available, and ready for anyone to use.&lt;/p&gt;

&lt;p&gt;&amp;#11088; &lt;a href=&quot;https://github.com/HexmosTech/git-lrc?utm_source=chatgpt.com&quot; rel=&quot;noopener noreferrer nofollow&quot;&gt;Star git-lrc on GitHub&lt;/a&gt;&lt;/p&gt;
</description>
<category>Other</category>
<guid isPermaLink="true">https://coderlegion.com/21641/mathematical-intuition-of-linear-regression</guid>
<pubDate>Mon, 06 Jul 2026 18:58:15 +0000</pubDate>
</item>
<item>
<title>AI-driven architectural regression</title>
<link>https://coderlegion.com/15308/ai-driven-architectural-regression</link>
<description>&lt;h1&gt;AI Code: It Passes Review, but the System Dies Anyway&lt;/h1&gt;
&lt;p&gt;Ever had that sinking feeling? The CI is glowing green, linters are silent, and the code looks like a work of art. This phenomenon, often leading to &lt;a rel=&quot;nofollow&quot; href=&quot;https://krun.pro/ai-code-architectural-regress/&quot;&gt;AI-driven architectural regression&lt;/a&gt;, starts when variable names are meaningful and logic seems modular, but the foundation is rotting. You hit Merge, go to bed, and at 3 AM on a Tuesday, the system starts bleeding out. No explosions, no dramatic crashes — just a slow, agonizing erosion of stability. This isn’t a logic bug. It’s Architectural Drift.&lt;/p&gt;
&lt;p&gt;We’ve entered an era where LLMs optimize for the context window, not for your system's survival. The AI solved the ticket? Yes. Was it correct? In isolation, absolutely. But it just drilled a hole through a load-bearing wall in your architecture, and nobody noticed because the &quot;drywall&quot; looks perfect.&lt;/p&gt;
&lt;h2&gt;The Illusion of Correctness&lt;/h2&gt;
&lt;p&gt;The core issue is that AI doesn't understand invariants — the invisible, unwritten rules that have kept your project alive since 2021. This isn’t &quot;code debt&quot; you can refactor away during a Friday cleanup. This is Architectural Debt. You don't &quot;fix&quot; it; you amputate it along with the affected modules — if you’re lucky enough to find it before it metastasizes.&lt;/p&gt;
&lt;h3&gt;Why Your &quot;Clean&quot; Code is a Time Bomb&lt;/h3&gt;
&lt;ul&gt;
    &lt;li&gt;Thread Safety? The LLM will drop a &lt;code&gt;dict.update()&lt;/code&gt; where atomicity is a hard requirement. It looks fine in a unit test, but under real load, you’ve got a corrupted state.&lt;/li&gt;
    &lt;li&gt;Idempotency? It’ll write a beautiful retry loop that ends up double-charging your customer because of a 50ms network hiccup.&lt;/li&gt;
    &lt;li&gt;Event Loop Blocking? To an LLM, &lt;code&gt;numpy.dot()&lt;/code&gt; is just a function. In production, at 5,000 req/s, it’s a silent killer that hangs your entire &lt;code&gt;asyncio&lt;/code&gt; loop for 40ms.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;The Halo Effect: How Seniors Become Rubber Stamps&lt;/h2&gt;
&lt;p&gt;The most dangerous link in this chain isn't the bot — it’s the exhausted Senior Engineer. AI-generated code is deceptively tidy. The styling is consistent, the comments are there. The reviewer’s brain falls for the Halo Effect: the first 10 lines are elegant, so the pattern-recognition system marks the whole thing as &quot;high quality.&quot;&lt;/p&gt;
&lt;p&gt;A &lt;code&gt;&amp;gt;&lt;/code&gt; that should’ve been a &lt;code&gt;&amp;gt;=&lt;/code&gt; on line 47, or an &lt;code&gt;assert&lt;/code&gt; that gets stripped in production with the &lt;code&gt;-O&lt;/code&gt; flag, slips through without a second thought because the surrounding code &lt;em&gt;looks&lt;/em&gt; professional.&lt;/p&gt;
&lt;h2&gt;Survival Protocols for 2026&lt;/h2&gt;
&lt;p&gt;If you think your project is safe because you have 90% test coverage, congratulations — you’re the primary target. We need to move beyond simple unit tests and start enforcing architecture at the CI level.&lt;/p&gt;
&lt;p&gt;In the full breakdown, we dissect:&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;Invariant Drift: How local logic violates the global state of your system.&lt;/li&gt;
    &lt;li&gt;Silent Memory Pressure: Where descriptor leaks hide in &quot;convenient&quot; AI patterns.&lt;/li&gt;
    &lt;li&gt;The Thundering Herd: How removing one &quot;redundant&quot; timeout cascades into a multi-service blackout.&lt;/li&gt;
    &lt;li&gt;Practical Mitigations: From custom Ruff rules to contract-based thinking that prevents AI from burning your house down.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Stop guessing and start auditing. Check out the deep dive on AI-driven architectural regression and learn how to stop the bleeding before it's too late.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/15308/ai-driven-architectural-regression</guid>
<pubDate>Mon, 20 Apr 2026 15:02:43 +0000</pubDate>
</item>
<item>
<title>Weather Service Project (Part 3): Predicting the Future with AI and OpenWeatherMap</title>
<link>https://coderlegion.com/10251/weather-service-project-part-3-predicting-the-future-with-ai-and-openweathermap</link>
<description>&lt;p&gt;In the &lt;a rel=&quot;nofollow&quot; href=&quot;https://datalaria.com/en/posts/weather-service-part-1/&quot;&gt;first part of this series&lt;/a&gt;, we set up the backbone of our global weather service, collecting raw data using Python and GitHub Actions. Then, in &lt;a rel=&quot;nofollow&quot; href=&quot;https://datalaria.com/en/posts/weather-service-part-2/&quot;&gt;Part 2&lt;/a&gt;, we transformed that raw data into a beautiful, interactive dashboard, leveraging GitHub Pages/Netlify, JavaScript, PapaParse.js, and Chart.js.&lt;/p&gt;
&lt;p&gt;Now, it's time for the grand finale: adding predictive power to our Weather Service. We'll explore how to augment our historical data visualization with actual forecasts. This installment focuses on a dual approach: integrating an official, reliable forecast from a professional service (OpenWeatherMap) and, more excitingly, building and training our very own simple AI model (Linear Regression) to predict tomorrow's weather based on the historical data we've meticulously collected. Finally, we'll visualize both forecasts on our dashboard, allowing for a direct comparison and a real-world test of our AI's accuracy.&lt;/p&gt;
&lt;p&gt;Let's turn our data into a crystal ball! &lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://datalaria.com/en/posts/app_openweather_part3_ai_prediction/AI_App_Weather_Image_Predictions.png&quot; alt=&quot;Conceptual image of Weather Service Predictions&quot;&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;the-predictive-core-openweathermap-and-our-custom-ai&quot;&gt;The Predictive Core: OpenWeatherMap and Our Custom AI&lt;/h4&gt;
&lt;p&gt;The goal for this predictive functionality was twofold:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Official Forecast&lt;/strong&gt;: Obtain a reliable, multi-day forecast from a professional weather service (OpenWeatherMap - OWM).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Custom AI Prediction&lt;/strong&gt;: Create our own simple AI model (Linear Regression) trained on the historical data we've collected, to predict the next day's weather.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Visualization &amp;amp; Comparison&lt;/strong&gt;: Display and compare both forecasts to gauge the accuracy and performance of our custom AI model.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h4 id=&quot;1-backend-logic-read-weather-py-gets-smarter&quot;&gt;1. ⚙️ Backend Logic: &lt;code&gt;read_weather.py&lt;/code&gt; Gets Smarter&lt;/h4&gt;
&lt;p&gt;Our &lt;code&gt;read_weather.py&lt;/code&gt; script, previously responsible for data collection, now expands its role to gather data from both OWM and our historical archives, consolidating everything into a single &lt;code&gt;predicciones.json&lt;/code&gt; file.&lt;/p&gt;
&lt;h5 id=&quot;step-1-fetching-openweathermap-s-5-day-forecast&quot;&gt;Step 1: Fetching OpenWeatherMap's 5-Day Forecast&lt;/h5&gt;
&lt;p&gt;We decided that in addition to our 1-day AI prediction, a 5-day forecast from OWM would provide valuable context.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;API Endpoint&lt;/strong&gt;: We opted for the free &lt;code&gt;data/2.5/forecast&lt;/code&gt; API (since OneCall 3.0 required a payment method).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Data Processing&lt;/strong&gt;: This API returns data in 3-hour blocks. We had to add Python logic to:&lt;ul&gt;
&lt;li&gt;Iterate over the list of ~40 forecasts.&lt;/li&gt;
&lt;li&gt;Group them by day (ignoring the current day).&lt;/li&gt;
&lt;li&gt;For each of the next 5 days, calculate the maximum, minimum, and average temperature from all 3-hour blocks within that day.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Result&lt;/strong&gt;: A list of 5 objects (one per day) containing OWM's max, min, and average temperature predictions.&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&quot;step-2-implementing-our-ai-model-1-day-prediction-&quot;&gt;Step 2: Implementing Our AI Model (1-Day Prediction)&lt;/h5&gt;
&lt;p&gt;This is the core of our &quot;homemade AI.&quot; For each city:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Data Loading&lt;/strong&gt;: We used &lt;code&gt;pandas&lt;/code&gt; to read the city's historical CSV file (e.g., &lt;code&gt;datos/Madrid.csv&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Feature Engineering&lt;/strong&gt;: Since we had multiple readings per day, the most crucial step was transforming this data:&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Resampling&lt;/strong&gt;: We used &lt;code&gt;df.resample('D')&lt;/code&gt; from &lt;code&gt;pandas&lt;/code&gt; to group data by day, calculating the actual daily aggregates (e.g., &lt;code&gt;temp_max&lt;/code&gt;, &lt;code&gt;temp_min&lt;/code&gt;, &lt;code&gt;avg_temp&lt;/code&gt;, &lt;code&gt;avg_humidity&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Feature Creation (X)&lt;/strong&gt;: We created new &quot;shifted&quot; columns (&lt;code&gt;.shift(1)&lt;/code&gt;) so that each row (representing a day) contained the previous day's data (e.g., &lt;code&gt;temp_max_lag1&lt;/code&gt;, &lt;code&gt;avg_humidity_lag1&lt;/code&gt;). We also added &lt;code&gt;day_of_year&lt;/code&gt; to capture seasonality.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Target Creation (y)&lt;/strong&gt;: We defined what we wanted to predict (e.g., the actual &lt;code&gt;temp_max&lt;/code&gt; of the current day).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Training 3 Models&lt;/strong&gt;: Instead of one, we trained three independent Linear Regression models (&lt;code&gt;scikit-learn&lt;/code&gt;):&lt;ul&gt;
&lt;li&gt;&lt;code&gt;model_max&lt;/code&gt;: Trained with &lt;code&gt;y = df_clean['temp_max']&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;model_min&lt;/code&gt;: Trained with &lt;code&gt;y = df_clean['temp_min']&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;model_avg&lt;/code&gt;: Trained with &lt;code&gt;y = df_clean['avg_temp']&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Prediction&lt;/strong&gt;:&lt;ul&gt;
&lt;li&gt;We took the last row of aggregated data (representing &quot;today's&quot; data).&lt;/li&gt;
&lt;li&gt;Fed this data to the 3 models to predict &quot;tomorrow's&quot; values.&lt;/li&gt;
&lt;li&gt;We included a safeguard (&lt;code&gt;MIN_RECORDS_FOR_IA = 10&lt;/code&gt;) so the model only attempts to predict if it has sufficient historical data (e.g., 10 clean days).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&quot;step-3-consolidate-and-save&quot;&gt;Step 3: Consolidate and Save&lt;/h5&gt;
&lt;p&gt;The script combines the results from Steps 1 and 2 into a JSON structure and saves it to &lt;code&gt;predicciones.json&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &quot;Madrid&quot;: {
    &quot;pred_owm_5day&quot;: [ 
      { &quot;date&quot;: &quot;...&quot;, &quot;max&quot;: 15.0, &quot;min&quot;: 10.0, &quot;avg&quot;: 12.5 }, 
      ... (5 days) ...
    ],
    &quot;pred_ia&quot;: {
      &quot;max&quot;: 14.8,
      &quot;min&quot;: 7.5,
      &quot;avg&quot;: 11.2,
      &quot;records&quot;: 120
    }
  },
  &quot;A Coruña&quot;: {
      ...
      &quot;pred_ia&quot;: { &quot;max&quot;: null, &quot;min&quot;: null, &quot;avg&quot;: null, &quot;records&quot;: 9 } // Example of insufficient data
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h4 id=&quot;2-frontend-logic-index-html-visualizes-the-future&quot;&gt;2.  Frontend Logic: &lt;code&gt;index.html&lt;/code&gt; Visualizes the Future&lt;/h4&gt;
&lt;p&gt;The frontend is responsible for loading this &lt;code&gt;predicciones.json&lt;/code&gt; file and presenting it in a visually appealing and informative way.&lt;/p&gt;
&lt;h5 id=&quot;step-1-data-loading&quot;&gt;Step 1: Data Loading&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;loadPredictions()&lt;/code&gt;: We created a new &lt;code&gt;async&lt;/code&gt; function that runs once during initialization (before &lt;code&gt;updateDashboard&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;allPredictionsCache&lt;/code&gt;: This function loads &lt;code&gt;predicciones.json&lt;/code&gt; and saves it into this new global variable so that all visualization functions have access to it.&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&quot;step-2-visualization-in-the-super-cards-kpis-&quot;&gt;Step 2: Visualization in the &quot;Super-Cards&quot; (KPIs)&lt;/h5&gt;
&lt;p&gt;We wanted a direct and clear comparison.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;OWM 5-Day Forecast&lt;/strong&gt;:&lt;ul&gt;
&lt;li&gt;We created a helper function &lt;code&gt;buildForecastHTML()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;This function takes the &lt;code&gt;pred_owm_5day&lt;/code&gt; list and generates an HTML block with a list of the 5 days and their max/min temperatures (e.g., &quot;Sat, Nov 9: 15.1°C / 10.0°C&quot;).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AI 1-Day Forecast (Comparison)&lt;/strong&gt;:&lt;ul&gt;
&lt;li&gt;We created a second helper function &lt;code&gt;buildIAForecastHTML()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;This function takes the &lt;code&gt;pred_ia&lt;/code&gt; object and the first day of the OWM forecast (&lt;code&gt;pred_owm_5day[0]&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Comparison Logic&lt;/strong&gt;: For max, min, and average temperatures, it displays the AI's value and then, next to it, the difference from OWM.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Visual Impact&lt;/strong&gt;: The difference is colored red (if our AI predicts warmer) or blue (if it predicts cooler), giving us an immediate visual cue of our model's deviation.&lt;/li&gt;
&lt;li&gt;It also handles the &quot;Insufficient Data&quot; case (&lt;code&gt;${ia_preds.records}/${MIN_RECORDS_FOR_IA}&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;updateKPIs()&lt;/code&gt;: The card template was modified to call these two new functions, displaying both forecast blocks.&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&quot;step-3-visualization-in-the-charts&quot;&gt;Step 3: Visualization in the Charts&lt;/h5&gt;
&lt;p&gt;We wanted the forecasts to be integrated directly into the existing charts.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Evolution Chart (Dotted Line)&lt;/strong&gt;:&lt;ul&gt;
&lt;li&gt;In &lt;code&gt;updateChart()&lt;/code&gt;, we added a new dataset for each city.&lt;/li&gt;
&lt;li&gt;This dataset uses the average of the OWM prediction (&lt;code&gt;pred_owm_5day&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;We applied the style &lt;code&gt;borderDash: [5, 5]&lt;/code&gt; to draw it as a dotted line.&lt;/li&gt;
&lt;li&gt;We &quot;stitched&quot; the beginning of this line to the last real data point to make it appear as a seamless continuation.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Variation Chart (Striped Bars)&lt;/strong&gt;:&lt;ul&gt;
&lt;li&gt;In &lt;code&gt;updateVariationChart()&lt;/code&gt;, we added another dataset for each city.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;y&lt;/code&gt; data for this set is &lt;code&gt;day.max - day.min&lt;/code&gt; (the variation) from the OWM forecast.&lt;/li&gt;
&lt;li&gt;For styling, we created a helper function &lt;code&gt;createStripedPattern()&lt;/code&gt; that draws a striped pattern on a canvas.&lt;/li&gt;
&lt;li&gt;We used this pattern as the &lt;code&gt;backgroundColor&lt;/code&gt; for the forecast bars, differentiating them from the solid bars of real data.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4 id=&quot;conclusion-part-3-&quot;&gt;Conclusion (Part 3)&lt;/h4&gt;
&lt;p&gt;With this final installment, our Weather Service project is complete! We've successfully integrated both professional 5-day forecasts from OpenWeatherMap and a custom 1-day AI prediction model, all powered by our collected historical data. The frontend now provides a rich, interactive experience that not only visualizes past weather but also offers a glimpse into the future, complete with a comparative analysis of our AI's performance.&lt;/p&gt;
&lt;p&gt;This journey has covered everything from backend data collection, automation with GitHub Actions, static site hosting with Netlify, to dynamic frontend development with vanilla JavaScript, advanced data parsing with PapaParse.js, interactive charting with Chart.js, and finally, dipping our toes into Machine Learning for predictive analytics.&lt;/p&gt;
&lt;p&gt;We've built a robust, serverless, and insightful application entirely on free services. The possibilities for expansion (e.g., more complex ML models, different data sources, user accounts) are endless, but for now, we have a fully functional weather oracle!&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;references-and-links-of-interest-&quot;&gt;References and Links of Interest:&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Complete Web Service&lt;/strong&gt;: You can see the final project in action here: &lt;a rel=&quot;nofollow&quot; href=&quot;https://datalaria.com/apps/weather/&quot;&gt;https://datalaria.com/apps/weather/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Project GitHub Repository&lt;/strong&gt;: Explore the source code and project structure in my repository: &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/Dalaez/app_weather&quot;&gt;https://github.com/Dalaez/app_weather&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;OpenWeatherMap API&lt;/strong&gt;: &lt;a rel=&quot;nofollow&quot; href=&quot;https://openweathermap.org/api&quot;&gt;https://openweathermap.org/api&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pandas&lt;/strong&gt;: Python Data Analysis Library: &lt;a rel=&quot;nofollow&quot; href=&quot;https://pandas.pydata.org/&quot;&gt;https://pandas.pydata.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scikit-learn&lt;/strong&gt;: Machine Learning in Python: &lt;a rel=&quot;nofollow&quot; href=&quot;https://scikit-learn.org/&quot;&gt;https://scikit-learn.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PapaParse.js&lt;/strong&gt;: Fast in-browser CSV parser for JavaScript: &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.papaparse.com/&quot;&gt;https://www.papaparse.com/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/10251/weather-service-project-part-3-predicting-the-future-with-ai-and-openweathermap</guid>
<pubDate>Thu, 22 Jan 2026 06:49:58 +0000</pubDate>
</item>
<item>
<title>Tester's Six Eye Technique: Visual Regression Testing</title>
<link>https://coderlegion.com/2848/testers-six-eye-technique-visual-regression-testing</link>
<description>&lt;p&gt;Visual UI Regression Testing is a critical practice in web development that ensures the visual consistency of a user interface (UI) across updates, browser versions, or devices. This guide explains what it is, why it matters, and how tools like Playwright (and AI-powered solutions like Applitools) simplify the process.&lt;/p&gt;
&lt;h3 id=&quot;what-is-visual-ui-regression-testing-&quot;&gt;What Is Visual UI Regression Testing?&lt;/h3&gt;
&lt;p&gt;Visual UI Regression Testing involves comparing screenshots of a web application’s UI before and after changes to detect unintended visual differences. Unlike functional testing, which verifies logic and workflows, visual testing focuses on pixel-perfect rendering of elements like layout, colors, fonts, and images.&lt;/p&gt;
&lt;h3 id=&quot;why-does-it-matter-&quot;&gt;Why Does It Matter?&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Prevents UI Bugs&lt;/strong&gt;: Catches visual regressions caused by code changes, such as misaligned buttons or broken styles.  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Enhances User Trust&lt;/strong&gt;: Ensures a consistent experience, especially for apps with frequent updates (e.g., ecommerce platforms).  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Saves Time&lt;/strong&gt;: Automates repetitive manual checks during sanity testing.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;which-applications-need-it-&quot;&gt;Which Applications Need It?&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Ecommerce Platforms&lt;/strong&gt;: Visual consistency directly impacts user trust and conversion rates. A misplaced &quot;Buy Now&quot; button or a broken product image can lead to lost sales.  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dynamic Content Apps&lt;/strong&gt;: Apps with frequent A/B tests, CMS-driven content, or third-party integrations benefit from automated visual checks.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;how-it-simplifies-sanity-testing&quot;&gt;How It Simplifies Sanity Testing&lt;/h3&gt;
&lt;p&gt;Sanity testing ensures critical functionalities work after minor updates. Visual regression testing automates this by:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Reducing Manual Effort&lt;/strong&gt;: No need to manually inspect every UI element.  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Enabling Rapid Deployment&lt;/strong&gt;: Catch visual issues early in CI/CD pipelines.  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Supporting Cross-Browser/Device Validation&lt;/strong&gt;: Ensure consistency across browsers without manual testing.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;combining-visual-testing-with-accessibility-testing&quot;&gt;Combining Visual Testing with Accessibility Testing&lt;/h3&gt;
&lt;p&gt;While visual testing focuses on appearance, accessibility testing ensures usability for all users, including those with disabilities. They complement each other:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Run Both in Parallel&lt;/strong&gt;: Use tools like Playwright for visual checks and Axe for accessibility audits.  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Shared Workflows&lt;/strong&gt;: Trigger both tests during CI/CD to catch visual and usability issues.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Why It’s Not Accessibility Testing&lt;/strong&gt;:  &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Visual testing ignores screen reader compatibility, keyboard navigation, or ARIA labels.  &lt;/li&gt;
&lt;li&gt;Accessibility testing doesn’t verify pixel-level design consistency.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;performing-visual-testing-with-playwright&quot;&gt;Performing Visual Testing with Playwright&lt;/h3&gt;
&lt;p&gt;Playwright, a modern testing framework, simplifies visual regression testing with built-in screenshot comparison. Below is an example test:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import { test, expect } from '@playwright/test';

test('Visual Regression Test for My Website', async ({ page }) =&amp;gt; {
  // Navigate to the website
  await page.goto('https://yusufasik.com'); // Replace with your website URL

  // Scroll through the page to trigger lazy loading
  await page.evaluate(() =&amp;gt; {
    return new Promise&amp;lt;void&amp;gt;((resolve) =&amp;gt; {
      let totalHeight = 0;
      const distance = 100;
      const timer = setInterval(() =&amp;gt; {
        const scrollHeight = document.body.scrollHeight;
        window.scrollBy(0, distance);
        totalHeight += distance;

        if (totalHeight &amp;gt;= scrollHeight) {
          clearInterval(timer);
          resolve();
        }
      }, 300);// Adjust the interval as needed, scroll every 300ms
    });
  });

// After initial page load and full-page scrolling:

// Handle all lazy-loaded images
const hoverElements = await page.getByRole('link', { name: 'mail' }).all();
for (const img of images) {
  await img.scrollIntoViewIfNeeded(); // Makes each image visible
  await img.waitFor({ state: 'visible' }); // Waits for load completion
}

// Handle hover-activated elements if any
const hoverElements = await page.getByRole('link', { name: 'mail' }).all();
for (const el of hoverElements) {
  await el.hover();
  await page.waitForTimeout(500); // Adjust based on your animations
}

// Additional safety measures
await page.waitForLoadState('networkidle'); // Waits for network inactivity
await page.waitForTimeout(500); // Small buffer for final rendering

    // Take a full page screenshot and mask out dynamic elements
    await expect(page).toHaveScreenshot({
      fullPage: true,
      animations: 'disabled',
      mask: [
        page.locator('[data-test=&quot;titles&quot;]:nth-of-type(1)'), // Replace with the selector of the dynamic element
      ],
      maxDiffPixelRatio: 0.01,
    });
});
});

&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;example-playwright-report-on-fail&quot;&gt;Example Playwright Report on Fail&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=15046925182747001369&quot; alt=&quot;Example Playwright Report on Fail&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;pro-tips&quot;&gt;Pro Tips&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Customize selectors&lt;/strong&gt; - Use attributes specific to your hover mechanism like &lt;code&gt;[data-hover]&lt;/code&gt; or &lt;code&gt;.hover-load&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Adjust timings&lt;/strong&gt; - Some hover effects have delays (CSS transitions/JS timeouts)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Combine approaches&lt;/strong&gt; - Some elements might need both scrolling AND hovering&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This combination ensures you capture all dynamic content in your visual tests, whether triggered by scroll, hover, or other interactions.&lt;/p&gt;
&lt;h4 id=&quot;-tomatchsnapshot-vs-tohavescreenshot-&quot;&gt;.toMatchSnapshot() vs .toHaveScreenshot()&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;.toMatchSnapshot() comes from Jest or generic test runner while.toHaveScreenshot() built-in Playwright runner. &lt;/li&gt;
&lt;li&gt;You can give snapshot name manually .toMatchSnapshot() but not Pw runner.&lt;/li&gt;
&lt;li&gt;Tolerance is none if you use .toMatchSnapshot(), so best practice would be put it on critical aspects like purchase now, login/logout.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;important-attributes&quot;&gt;Important Attributes&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;animations: &quot;disabled&quot;&lt;/strong&gt;: Disables animations to prevent flaky comparisons.  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;mask&lt;/strong&gt;: If there is dynamic elements constantly changing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;maxDiffPixelRatio&lt;/strong&gt;: Allows minor differences (e.g., anti-aliasing) to reduce false positives.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;ci-cd-integration&quot;&gt;CI/CD Integration&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;tracing.start()&lt;/code&gt; and &lt;code&gt;tracing.stop()&lt;/code&gt; to capture traces (screenshots, DOM snapshots) in CI environments.  &lt;/li&gt;
&lt;li&gt;Update baselines with &lt;code&gt;npx playwright test --update-snapshots&lt;/code&gt; after intentional UI changes.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;ai-powered-visual-testing-with-applitools&quot;&gt;AI-Powered Visual Testing with Applitools&lt;/h2&gt;
&lt;p&gt;Tools like Applitools enhance traditional pixel comparison with AI:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Ultra-fast Grid&lt;/strong&gt;: Test across 100+ browser/device combinations in parallel.  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Smart Baseline Management&lt;/strong&gt;: AI auto-approves insignificant changes (e.g., text rendering).  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Test Result Monitoring&lt;/strong&gt;: Cloud dashboards highlight visual diffs and track trends.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;why-it-s-better&quot;&gt;Why It’s Better&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Reduces False Positives&lt;/strong&gt;: AI ignores trivial differences (e.g., font rendering).  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scales Effortlessly&lt;/strong&gt;: Test complex UIs (e.g., ecommerce dashboards) without infrastructure setup.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;example-applitools-with-playwright&quot;&gt;Example: Applitools with Playwright&lt;/h3&gt;
&lt;p&gt;Below is a sample setup using Applitools Eyes with Playwright. This code enables testing across both classic and Ultrafast Grid runners.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import { test } from '@playwright/test';
import {
  BatchInfo,
  Configuration,
  EyesRunner,
  ClassicRunner,
  VisualGridRunner,
  BrowserType,
  DeviceName,
  ScreenOrientation,
  Eyes,
  Target
} from '@applitools/eyes-playwright';
require('dotenv').config();

export const USE_ULTRAFAST_GRID: boolean = true;
export let Batch: BatchInfo;
export let Config: Configuration;
export let Runner: EyesRunner;
let eyes: Eyes;
let URL = 'https://demo.applitools.com';

test.beforeAll(async() =&amp;gt; {
  if (USE_ULTRAFAST_GRID) {
    Runner = new VisualGridRunner({ testConcurrency: 5 });
  } else {
    Runner = new ClassicRunner();
  }

  const runnerName = (USE_ULTRAFAST_GRID) ? 'Ultrafast Grid' : 'Classic runner';
  Batch = new BatchInfo({ name: `ACME Project - ${runnerName}` });

  Config = new Configuration();
  Config.setBatch(Batch);

  if (USE_ULTRAFAST_GRID) {
    Config.addBrowser(800, 600, BrowserType.CHROME);
    Config.addBrowser(1600, 1200, BrowserType.FIREFOX);
    Config.addBrowser(1024, 768, BrowserType.SAFARI);
    Config.addDeviceEmulation(DeviceName.iPhone_11, ScreenOrientation.PORTRAIT);
    Config.addDeviceEmulation(DeviceName.Nexus_10, ScreenOrientation.LANDSCAPE);
  }
});

test.beforeEach(async ({ page }) =&amp;gt; {
  eyes = new Eyes(Runner, Config);
  await eyes.open(
    page,
    'Example Page',
    test.info().title,
    { width: 1024, height: 768 }
  );
});

test.afterEach(async () =&amp;gt; {
  await eyes.close();
});

test.afterAll(async () =&amp;gt; {
  const results = await Runner.getAllTestResults();
  console.log('Visual test results', results);
});

test.describe('Example Test', () =&amp;gt; {
  //Test code here...
});

&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;important-attributes-1&quot;&gt;Important Attributes&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;USE_ULTRAFAST_GRID&lt;/code&gt;&lt;/strong&gt;: Flag to switch between Applitools' Ultrafast Grid and Classic Runner.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;BatchInfo&lt;/code&gt;&lt;/strong&gt;: Groups related test results for better organization in the Applitools dashboard.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;Configuration&lt;/code&gt;&lt;/strong&gt;: Holds test settings like browser types, devices, screen sizes, and the batch reference.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;VisualGridRunner&lt;/code&gt; / &lt;code&gt;ClassicRunner&lt;/code&gt;&lt;/strong&gt;: Determines how tests are executed—either in parallel across devices (Ultrafast Grid) or locally (Classic).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;addBrowser()&lt;/code&gt; / &lt;code&gt;addDeviceEmulation()&lt;/code&gt;&lt;/strong&gt;: Specifies the environments (browsers or devices) to run visual checks against.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;eyes.open()&lt;/code&gt;&lt;/strong&gt;: Initializes a visual testing session, associating it with the current page.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;eyes.close()&lt;/code&gt;&lt;/strong&gt;: Ends the session and submits the results for comparison.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;getAllTestResults()&lt;/code&gt;&lt;/strong&gt;: Retrieves a report of all visual check results after the test suite completes.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;&lt;p&gt;This setup makes it easy to scale visual testing across a matrix of&lt;br&gt;
devices and browsers while maintaining consistency and clarity in&lt;br&gt;
reporting.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;domain-expansion-&quot;&gt;Domain Expansion:&lt;/h3&gt;
&lt;p&gt;Visual UI Regression Testing is essential for maintaining brand integrity and user satisfaction, especially in fast-paced environments like ecommerce. Playwright offers a robust open-source solution, while AI-powered tools like Applitools provide enterprise-grade scalability. By combining visual and accessibility testing, teams can deliver polished, inclusive experiences with confidence.&lt;/p&gt;
</description>
<category>QA Best Practices</category>
<guid isPermaLink="true">https://coderlegion.com/2848/testers-six-eye-technique-visual-regression-testing</guid>
<pubDate>Fri, 02 May 2025 10:27:37 +0000</pubDate>
</item>
</channel>
</rss>