Skip to main content

programming code.

Weather Radar
Code Download
Download WeatherRadar.zip - 11.8 KB
This project requires that you download the
HtmlAgilityPack separately and place the
HtmlAgilityPack.dll into the appropriate Debug
and/or Release folder.
Introduction
As far as I could tell, the NOAA weather
webservice does not provide a function for
obtaining the weather radar image of particular
location, nor is this feature readily provided by
other weather web services. So here I present a
"bare-bones" implementation, using
HtmlAgilityPack for some simple XPath queries.
The radar.weather.gov Website
If you inspect a page displaying a radar image on
this website, you'll notice that the image is
actually a composite of 8 selectable pieces:
The first image is a JPG, and the remaining are
GIF's:
Topography Doppler Radar Counties Rivers
Roads Cities
Warnings (none at this moment)
Legend
So, given you're nearest radar station (pick one
on http://radar.weather.gov ) we need to obtain
these images and combine them together to
show the final composite image. There's a slight
twist - two of the images come from a different
source and are computed by the Javascript on
the page, so we have special handlers for these.
There are five steps:
Step 1: Acquiring the Page HTML
Given the URL entered in the textbox, we first
acquire the HTML for the page:
protected string GetPageHtml( string
url)
{
using (WebClient client = new
WebClient())
  {
return client.DownloadString
(url);
  }
}
Step 2: Figuring out the Image URL's
This is the most complex part of the process, as
we have to programmatically generate two of the
image URL's. You'll also see how we use the
HtmlAgilityPack to extract the specific node
values for the div sections you saw earlier.
protected List<string>
GetPageImageUrls(string html, string
url)
{
  List<string> ret = new
List<string>();
  HtmlAgilityPack.HtmlDocument doc =
new HtmlAgilityPack.HtmlDocument();
doc.LoadHtml(html);
WebClient webClient = new
WebClient();
int n = 0 ;
while ( true)
{
var nodes =
doc.DocumentNode.SelectNodes
( String .Format( "//div[@id='image
{0}']/img" , n++));
if ((nodes != null) &&
(nodes.Count == 1 ))
{
string imageUrl = nodes.Select
(node => node.Attributes
[ "src" ].Value). Single ();
// This is a computed image.
if (imageUrl == "#" )
{
string name = nodes.Select
(node => node.Attributes
[ "name" ].Value). Single ();
string rid = url.Between
( "rid=" , "&" ).ToUpper();
string product = url.Between
( "product=" , "&" ).ToUpper();
switch (name)
{
case "conditionalimage" :
// Example: <a
href="http://radar.weather.gov/
RadarImg/N0R/ENX_N0R_0.gif">http://
radar.weather.gov/RadarImg/N0R/
ENX_N0R_0.gif</a>
          imageUrl = String .Format
( "RadarImg/{0}/{1}_{0}_0.gif" ,
product, rid);
break ;
case "conditionallegend" :
// Example: <a
href="http://radar.weather.gov/
Legend/N0R/
ENX_N0R_Legend_0.gif">http://
radar.weather.gov/Legend/N0R/
ENX_N0R_Legend_0.gif</a>
          imageUrl = String .Format
( "Legend/{0}/{1}_{0}_Legend_0.gif" ,
product, rid);
break ;
}
}
ret.Add(imageUrl);
}
else
{
break ;
}
}
webClient.Dispose();
return ret;
}
Step 3: Downloading the Images
Here we simply download the images, saving the
Image and its associated MemoryStream
instance. While I could clone the image at this
point and free up the memory stream and the
original image, I opted to keep the two together
as a package for later cleanup.
protected List<ImageData>
DownloadImages(List<string>
imageUrls)
{
  List<ImageData> ret = new
List<ImageData>();
  WebClient webClient = new
WebClient();
  foreach ( string url in imageUrls)
{
byte[] data =
webClient.DownloadData( "http://
radar.weather.gov/" + url);
// Memory stream CANNOT be
disposed of!
    MemoryStream stream = new
MemoryStream(data);
    Image image = Image.FromStream
(stream);
    ret.Add( new ImageData() { Image
= image, BackingStream = stream });
  }
  webClient.Dispose();
return ret;
}
Step 4: For fun, we Save the Images
You'll note my assumption that the first image is
a JPG and the rest are GIF's. Yes, we could
figure this out by inspecting the raw image
format, but that's more work than I wanted to
put into the code at the moment.
protected void WriteImages
(List<ImageData> images)
{
int n=0;
images.ForEach(img =>
img.Image.Save( "img" + n++ +
(n==1 ? ".jpg" : ".gif" )));
}
Step 5: Combine the Images
Here we combine the images, returning a new
image consisting of the composite image data:
protected Image CombineImages
(Graphics gr, List<ImageData>
images, Size size)
{
  Image baseImage = (Image)images
[ 0].Image.Clone();
gr = Graphics.FromImage
(baseImage);
for ( int i=1; i<images.Count; i++)
{
gr.DrawImage(images[i].Image,
new Point( 0, 0 ));
}
gr.Dispose();
return baseImage;
}
Step 6: Cleanup
Here we dispose of the images and their the
associated memory streams.
protected void Cleanup
(List<ImageData> images)
{
  images.ForEach(img =>
  {
    img.BackingStream.Dispose();
    img.Image.Dispose();
  });
}
Putting it all Together
When you click on the Go button, an async
process is started, and we provide a callback to
display the progress on the status bar:
protected async void btnGo_Click
( object sender, EventArgs e)
{
  btnGo.Enabled = false;
string url = tbUrl.Text;
Graphics gr =
pbRadar.CreateGraphics();
  Image bitmap = await Task.Run(()
=> GetRadarImage(gr,
    url,
    (progress) => this.BeginInvoke
(() => tsLabel.Text = progress)));
  pbRadar.Image = bitmap;
  tsLabel.Text = "Done" ;
btnGo.Enabled = true;
}
And the implementation of GetRadarImage
chains together the processes we described
above:
protected Image GetRadarImage
(Graphics gr, string url,
Action<string> progressCallback)
{
  progressCallback( "Acquiring
page..." );
string html = GetPageHtml(url);
progressCallback( "Scraping
page..." );
List<string> imageUrls =
GetPageImageUrls(html, url);
  progressCallback( "Downloading
images..." );
List<ImageData> images =
DownloadImages(imageUrls);
  progressCallback( "Writing
images..." );
WriteImages(images);
progressCallback( "Combining
images..." );
Image bitmap = CombineImages(gr,
images, pbRadar.Size);
  progressCallback( "Cleanup..." );
Cleanup(images);
return bitmap;
}
Extension Methods
To make my life a bit easier, I borrowed some
extension methods that I use in other projects:
public static class Extensions
{
public static string Between( this
String src, string s1, string s2)
{
return src.RightOf(s1).LeftOf
(s2);
  }
public static string RightOf( this
String src, string s)
{
string ret = String .Empty;
int idx = src.IndexOf(s);
if (idx != -1)
{
ret = src.Substring(idx +
s.Length);
    }
return ret;
}
public static string LeftOf( this
String src, string s)
{
string ret = src;
int idx = src.IndexOf(s);
if (idx != -1)
{
ret = src.Substring( 0, idx);
}
return ret;
}
public static void BeginInvoke
( this Control control, Action action)
{
if (control.InvokeRequired)
{
control.BeginInvoke
((Delegate)action);
    }
else
{
action();
}
}
}
Conclusion
And there you have it, a bare-bones approach to
acquiring a radar image in your own application!

Comments

Popular Post

Apple is testing a ChatGPT-like AI chatbot

  According to a recent report by Bloomberg's Mark Gurman, Apple is making significant strides in the development of artificial intelligence tools to rival the likes of OpenAI and Google. Internally referred to as "Apple GPT," the tech giant has created a chatbot using its proprietary framework called "Ajax." This framework, built on Google Cloud with Google JAX, enables the creation of large language models similar to ChatGPT and Google's Bard. While Apple is yet to finalize its strategy for consumer release, it is reportedly planning a major AI-related announcement next year. The chatbot's internal rollout faced delays due to security concerns related to generative AI. However, it has been made available to a growing number of Apple employees with special approval, primarily for product prototyping purposes. Apple's chatbot can summarize text and answer questions based on its training data. Although it shares similarities with commercially availabl...

How to earn money using ChatGPT !

  Content Creation and Writing: You can use AI language models to assist in content creation, such as writing articles, blog posts, or social media content. Some content creators use AI-generated drafts and then refine them with their own ideas and style. Language Translation Services: You can offer language translation services using AI language models to help with translating documents or text between different languages. Chatbot Development: If you have programming skills, you can integrate AI language models into chatbots for businesses or websites, helping them provide automated customer support. Tutoring and Educational Assistance: Use AI language models to create educational content, answer students' questions, or provide tutoring support in specific subjects. Copywriting and Marketing: Assist in generating marketing copy, ad content, or email campaigns using AI language models to improve efficiency and creativity. Writing and Publishing Books: Some authors use AI lang...

UPSC

&#128204;PERIOD POVERTY Scotland may become the first country in the world to end ‘period poverty’ by making sanitary products free for all. About: • The Scottish Parliament passed the Period Products (Free Provision) (Scotland) Bill. • Referring to “period dignity”, the legislation aims to develop a universal system in Scotland, which will provide free sanitary products for “anyone who needs them”. • As of now, in Scotland, the provision of free sanitary products is already available in schools, universities and colleges. • The Bill has only passed the first hurdle to become a law. It still needs to be considered by a parliamentary committee, following which it will require approval from the parliament. It will finally need the Royal Assent of the Queen.  ▪️Important Info : What is ‘period poverty’? Some circumstances make menstruation a “difficult experience” for women. T...

Mobile hacking code.

               Hack Code. 1] *#0000# Displays Your Phones software version,Ist line: Software version, 2nd line: software release date,3rd line: compression type 2] *#9999# Phones softwares version if *#0000# does not work 3] *#06# For checking the international Mobile Equipment identity(IMEI number) 4] *#2640# Displays security Code in use 5] #pw+1234567890+1# Provides Lock Status(use the * button to obtain the "p,w,+" symbols for following codes)  6] #pw+1234567890+2# Network Lock Status(use the * button to obtain the "p,w,+" symbols for following codes)  7] #pw+1234567890+3# Country lock Status (use the * button to obtain the "p,w,+" symbols for following codes)  8] #pw+1234567890+4# SIM card Lock status(use the * button to obtain the "p,w,+" symbols for following codes) 9] *#21# Allows u to check the number that "All Calls" are diverted to 10] *#30# Lets u see the private number 11] *#43# Allows u to ch...

UPSC ARTICLE

๐Ÿ“š เคจिเคตेเคถเค•ों เค•ो เคจเคˆ เคคेเคฒ เคต เค—ैเคธ เคจीเคคि เคธे เคฒुเคญाเคจे เค•ी เค•ोเคถिเคถ เคธเคฐเค•ाเคฐ เคจे เคคेเคฒ เคเคตं เค—ैเคธ เค–ोเคœ เค•्เคทेเคค्เคฐ เคฎें เคจिเคœी เค”เคฐ เคตिเคฆेเคถी เคจिเคตेเคถ เค†เค•เคฐ्เคทिเคค เค•เคฐเคจे เค•े เคฒिเค เค‡เคธเคธे เคœुเคก़ी เคจीเคคि เคฎें เค…เคนเคฎ เคฌเคฆเคฒाเคต เค•िเค เคนैं। เคจเคˆ เคจीเคคि เค•े เคคเคนเคค เคธเคฐเค•ाเคฐ เคจเค เคเคตं เค•เคฎ เค–ोเคœे เค—เค เค•्เคทेเคค्เคฐों เคฎें เคนाเค‡เคก्เคฐोเค•ाเคฐ्เคฌเคจ เค‰เคค्เคชाเคฆเคจ เคชเคฐ เคธंเคฌंเคงिเคค เค•ंเคชเคจी เคธे เคฒाเคญ เคฎें เคนिเคธ्เคธा เคจเคนीं เคฎांเค—ेเค—ी। เคนเคฐ เคคเคฐเคน เค•े เคฌेเคธिเคจ เค•े เคฒिเค เคเค• เคธเคฎाเคจ เค…เคจुเคฌंเคง เคตाเคฒी เคฆो เคฆเคถเค• เคชुเคฐाเคจी เคจीเคคि เคฎें เคฌเคฆเคฒाเคต เค•เคฐเคคे เคนुเค เคจเคˆ เคจीเคคि เคฎें เค…เคฒเค—-เค…เคฒเค— เค•्เคทेเคค्เคฐों เค•े เคฒिเค เค…เคฒเค—-เค…เคฒเค— เคจिเคฏเคฎ เคฌเคจाเค เค—เค เคนैं। เค‡เคธเค•े เคคเคนเคค เคชเคนเคฒे เคธे เค‰เคค्เคชाเคฆเคจ เคตाเคฒे เค•्เคทेเคค्เคฐों เค”เคฐ เคจเค เค•्เคทेเคค्เคฐों เค•े เคฒिเค เคจिเคฏเคฎ เค…เคฒเค—-เค…เคฒเค— เคฐเคนेंเค—े। เค†เคงिเค•ाเคฐिเค• เค…เคงिเคธूเคšเคจा เค•े เค…เคจुเคธाเคฐ เค‰เคค्เคชाเคฆเค•ों เค•ो เคญเคตिเคท्เคฏ เคฎें เคฌोเคฒी เค•े เคฆौเคฐाเคจ เคคेเคฒ เคเคตं เค—ैเคธ เค•े เคฒिเค เคตिเคชเคฃเคจ เค”เคฐ เค•ीเคฎเคค (เคฎाเคฐ्เค•ेเคŸिंเค— เคंเคก เคช्เคฐाเค‡เคธिंเค—) เค•े เคฎाเคฎเคฒे เคฎें เค†เคœाเคฆी เคนोเค—ी। เค‡เคธ เคช्เคฐเค•्เคฐिเคฏा เคฎें เค‡เคธ เคฌाเคค เคธे เค•ोเคˆ เคช्เคฐเคญाเคต เคจเคนीं เคชเคก़ेเค—ा เค•ि เคฌेเคธिเคจ เค•ैเคธा เคนै। เค•ेंเคฆ्เคฐीเคฏ เคฎंเคค्เคฐिเคฎंเคกเคฒ เคจे 28 เคซเคฐเคตเคฐी เค•ो เคจिเคฏเคฎ เคฎें เคฌเคฆเคฒाเคต เค•ो เคฎंเคœूเคฐी เคฆी เคฅी। เค‡เคธเคฎें เค•เคนा เค—เคฏा เคนै เค•ि เคญเคตिเคท्เคฏ เคฎें เคธเคญी เคคेเคฒ เคเคตं เค—ैเคธ เค•्เคทेเคค्เคฐ เคฏा เคฌ्เคฒॉเค• เค•ा เค†เคตंเคŸเคจ เคช्เคฐाเคฅเคฎिเค• เคฐूเคช เคธे เค–ोเคœ เค•ाเคฐ्เคฏों เค•ो เคฒेเค•เคฐ เคœเคคाเคˆ เค—เคˆ เคช्เคฐเคคिเคฌเคฆ्เคงเคคा เค•े เค†เคงाเคฐ เคชเคฐ เค•िเคฏा เคœाเคเค—ा।เคจเค เคจिเคฏเคฎ เค•े เคคเคนเคค เค•ंเคชเคจिเคฏों เค•ो เคถ्เคฐेเคฃी-เคเค• ...

Follow the Page for Daily Updates!