Click here to Skip to main content
Click here to Skip to main content

Mapping Zip Code From Your Database.

By , 25 Jul 2004
 

Sample Image - zipcodemapping.gif

Introduction

This application was designed to help me figure out the demographics of my address list. I was curious as to where the various people were located in the continental United States. After a while, I found a couple of interesting articles that pointed me in the right direction, but nothing that was going to save me from writing a solution myself... So, here it is... The Zip Code Mapping Solution (Free). Now, please be patient with this article as it is the first one I have posted...

How it works:

The Database:

This application has some pretty simple source code in it... but the main guts and glory come from the database. In the demonstration database, you will find two tables and three queries.

  • Table 1: PUBLISHERS

    (A sample table of data put out by Microsoft, normally this would be your customer base... or whoever you would like mapped.)

  • Table 2: ZIPCODES

    (This table is something I put together through the US Census and through a free Zip Code database that I found online.

  • Query 1: ALLZIPS

    (This query simply filters out all zip codes from the ZIPCODES table that are not in the continental United States.)

  • Query 2: ZIPCODEADDRESS

    (This query also filters out zip codes that are not in the continental US as well as removes null zip codes, non-numeric zip codes [e.g. foreign], and spaces from the "PUBLISHERS" table.)

  • Query 3: ZIPLOCATIONS

    (This query counts the number of people at each zip code, gets the latitude and longitude, and lists the zip code by matching through ZIPCODEADDRESS and ZIPCODES.)

The Mathematics:

I had to determine a certain amount of mathematical formulae in order to get this to work. Basically, what the application needs to do is scale down the zip codes into a grid, based on the latitude and longitude coordinates being converted into pixels, on an image. Here are the pieces of data that are needed (these are explained in the demo project).

  • +48.987386 is the highest latitude in the continental US.
  • +18.005611 is a latitude lower than the southern most latitude (used for buffer).
  • -124.626080 is the west most longitude in the continental US.
  • -62.361014 is a longitude more east than the eastern most longitude (used for buffer).

To find out the scale, I simply figured out the difference in latitudes, and divided it by the height of my image... and then figured out the difference in the longitudes, and divided it by the width of my image. For example:

I selected a 701w X 565h pixel image. To calculate the scale, I did the following math:

Latitude:  (48.987386-18.005611)/565h  = .054835 latitude  unit/pixel
Longitude: (124.656080-67.040767)/701w = .088866 longitude unit/pixel

To put this into code, I just created two functions:

Function getLat(byVal y1)
    Return cInt((48.987386 - (cDbl(y1))) / 0.054835)
End Function
Function getLong(byVal x1)
    Return cInt((124.62608 - (cDbls(x1) * -1)) / 0.088866)
End Function

*Note that the longitude was multiplied * -1... that was to make it a positive number for the subtraction routine.

Now with these functions, I can simply send the latitudes and longitudes from the database to those functions in order to get the correct pixel area that I need to map.

The Application:

Now that we have determined the canvas size and the scale, we create a canvas:

    'declare variables
    Dim objBitmap As Bitmap = New Bitmap(701, 565) 
    Dim objGraphics As Graphics = Graphics.FromImage(objBitmap)

    'create the colors and the shapes
    Dim objBrush As SolidBrush = _
      New SolidBrush(System.Drawing.Color.LightGray) 'for US Contour
    Dim objWhite As SolidBrush = _
      New SolidBrush(System.Drawing.Color.White) 'for background
    Dim objNewBrush As SolidBrush
    Dim myRect As Rectangle

Here, I have created the Bitmap and Graphics objects to draw with. I also have created some brushes in order to draw some stuff.

The next step I took was to access everything from a database. I have tested this with both Oracle 9i and MS Access... as long as you change where you are getting your data... everything works the same. So, I am going to skip the database connection stuff as you should be able to figure that out.... if not, it is still in the demo program.

The first step I take (maybe there is an easier way) but I draw a white rectangle for the background of my bitmap.

    myRect = New Rectange(0,0,701,565)
    objGraphics.FillRectangle(objWhite, myRect)

The next step is to select all records from the "ALLZIPS" table and draw a dot at each of the records. (This is actually quite fast on my computer, but results could vary).

    rs.Open("SELECT * FROM ALLZIPS", DB, 3, 3)
    
    'LOOP THROUGH
    WHILE NOT RS.EOF
        myRect = New Rectangle(getLong(rs("LONGITUDE").value)+50, _
                                getLat(rs("LATITUDE").value)+50,2,2)
        objGraphics.FillEllipse(objBrush, myRect)
        rs.MoveNext()
    Wend

As you can notice, it is creating an Ellipse (2x2), colored LightGray, at the coordinates specified by "getLong({DB-LONGITUDE})" and "getLat({DB-LATITUDE})", and I add 50 pixels for my surrounding border on the image.

Now, I do it again, but I do it with the records that I want to mark with a different color.

    rs.close 'close previous recordset
    rs.open("SELECT * FROM ZIPLOCATIONS"), DB, 3, 3)
    'LOOP THROUGH
    WHILE NOT RS.EOF
        myRect = New Rectangle(getLong(rs("LONGITUDE").value)+50, _
                                getLat(rs("LATITUDE").value)+50,4,4)
        'now determine the color based on number of matches
        Select Case (rs("ZIPCOUNT").Value)
        Case 1
            objNewBrush = New SolidBrush(System.Drawing.Color.RoyalBlue)
        Case 2
            objNewBrush = New SolidBrush(System.Drawing.Color.MediumSeaGreen)
        Case 3
            objNewBrush = New SolidBrush(System.Drawing.Color.LawnGreen)
        Case 4
            objNewBrush = New SolidBrush(System.Drawing.Color.OliveDrab)
        Case 5
            objNewBrush = New SolidBrush(System.Drawing.Color.DarkKhaki)
        Case 6
            objNewBrush = New SolidBrush(System.Drawing.Color.Goldenrod)
        Case 7
            objNewBrush = New SolidBrush(System.Drawing.Color.DarkOrange)
        Case 8
            objNewBrush = New SolidBrush(System.Drawing.Color.Coral)
        Case 9
            objNewBrush = New SolidBrush(System.Drawing.Color.Red)
        Case 10
            objNewBrush = New SolidBrush(System.Drawing.Color.Firebrick)
        Case Else
            objNewBrush = New SolidBrush(System.Drawing.Color.DarkRed)
        End Select
        'fill the elipse with the selected color
        objGraphics.FillEllipse(objNewBrush, myRect)
        rs.MoveNext()
    Wend

At this point, the image is drawn and stored in the variable... so we just need to finish up the export of the image and set it to the Image object.

    'finish up
    objBitmap.Save(Server.MapPath(Request.ApplicationPath) _
            & "\newGlobe.gif", Imaging.ImageFormat.Gif)
    objGraphics.Dispose()
    objBitmap.Dispose()
    rs.Close()

    'set source
    imageButton.ImageUrl = "newGlobe.gif"

And that is all she wrote... that will create everything that you need.

Additional Comments:

There is another procedure in the demo program that helps you "Zoom in", that is based off an article by: Harish Palaniappan (also found on TheCodeProject). I hope that this article has helped you out and I really would like to hear about anybody who uses this application for their web sites. Just drop me a line: aamittee{at}mtu.edu.

Regards,

Adam A. Mitteer

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Adam A. Mitteer
United States United States
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralIndividual statesmemberramprasadr3 Mar '05 - 7:25 
Hello Adam,
 
Thanks for the well explained article. I'm trying to take this further ahead, by plotting zipcodes for any specific state with the same bitmap size.
 
When I attempted it with MA, either I get a tiny represenation for the whole state, or only the eastern half (approx) of the state gets plotted. I know I'm not correct.
 
Can you please suggest me an approach if I need to plot individual states as opposed to the whole country? Thank you.
 
-r
GeneralLegal NoticessussAnonymous5 Aug '04 - 11:34 
Is there a way to add two legal notices to windows logon. They must appear sequencially as soon as you press ALT+CTRL+DEL to logon.

GeneralA tip about storing numeric values with leading zeros.memberAshaman30 Jul '04 - 2:37 
You should be storing your Zip codes as a char(5) instead of as an Int32.
 
I changed the data type and used the following super simple function in an update query to fix the zip codes so that they'd include their leading zeros if they needed one.
 
Public Function FixZips(ByVal ZipCode As String) As String
FixZips = Right$("00000" & ZipCode, 5)
End Function
 
P.S. I gave you a '4' because this is awfully neat.
 
Kevin Buchan
GeneralRe: A tip about storing numeric values with leading zeros.memberkcl4 Aug '04 - 0:45 
You could also format the number to a string using "00000" as the formatting string, e.g.:
 
myZipString = String.Format(myNumericZipCode,"00000")
 
This (to me at least) would seem to be more obvious as to what the intention is when you (or someone else) reads the code back at a later date - always a good aim.
 
Hope that helps,
 
Chris
Wink | ;)

GeneralRe: A tip about storing numeric values with leading zeros.memberAshaman4 Aug '04 - 1:53 
Either way, it's a simple process to convert the Zips. My point was that it is critical when storing numeric values that require leading zeros that you store them as a character type.
 
The reason I like my conversion solution is that it is a language independant process. Using the perfectly great code you posted, a language would need to support a string formatting function and one that allowed leading zeros when converting from numeric to character types.
 
I read through the TSQL books on-line and, to be perfectly honest, I couldn't see that TSQL supports converting a number to a string and putting leading zeros. Maybe it does support it, but I just didn't see it.

 
-Kevin Buchan
GeneralErrorsussAnonymous28 Jul '04 - 13:40 
Great stuff but I receive a GDI error when trying to save the image.
GeneralRe: ErrormemberAdam A. Mitteer29 Jul '04 - 3:56 
I have a hunch that it has to do with the permissions of your folder. I would play around with IUSR_account and make sure that it has the proper permissions. Check the permissions and if that doesn't solve the problem can you copy/paste the error output to this forum so that I may analyze it further?
 
Thanks,
-Adam
GeneralRe: Errormemberkcl4 Aug '04 - 0:03 
Possibly try ASP.NET user instead of IUSR_account....
 
Hope that helps
 
Chris
Generalneed help with errormembermkane727 Jul '04 - 18:08 
Server Error in '/zipcodemapping_demo' Application.
-----------------------------------------------------------------
 
Parser Error
Description: An error occurred during the parsing of a resource required to service this request. Please review the following specific parse error details and modify your source file appropriately.
 
Parser Error Message: Could not load type 'ZipCoder.zipCoder'.
 
Source Error:
 

Line 1: <%@ Page Language="vb" AutoEventWireup="false" Codebehind="zipCoder.aspx.vb" Inherits="ZipCoder.zipCoder" %>
Line 2: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
Line 3: <HTML>

 
Source File: c:\inetpub\wwwroot\zipcodemapping_demo\ZipCoder.aspx Line: 1
 

-----------------------------------------------------------------
Version Information: Microsoft .NET Framework Version:1.1.4322.573; ASP.NET Version:1.1.4322.573
GeneralRe: need help with errormemberAdam A. Mitteer28 Jul '04 - 4:18 
mkane7,
 
Okay... I managed to duplicate your error and I think that I have the following solution for you. Because this is my first post on this web site I really don't have much of a clue as to what files I need to attach and which ones I shouldn't. So... here is how you can get the demo to work.
 
1.) Create an ASP.NET Web Project (using VB)
 
2.) Copy all files from zipcodemapping_demo.zip to that new project folder.
 
3.) Include the zipCoder file by:
a.) Click on the icon that says "Show All Files" in the solution browser within Visual Studio.
b.) Right Click on the file zipCoder.aspx and click "Include in Project".
 
4.) Include the reference to ADODB by:
a.) Right click on "References" in the solution browser.
b.) In the .NET tab, find ADODB and select it. Click okay.
 
5.) Set zipCoder as your start page by:
a.) Right click on zipCoder.aspx.
b.) Click "Set as Start Page".
 
After that you should be able to compile the project and run it. You can pretty much do the same steps if you want to include it into a project that you have already created. Just paste the demo archive in your project folder and follow those steps.
 
Let me know if you have any further problems and I will do my best to help you out!
 
-Adam
GeneralRe: need help with errormembermkane728 Jul '04 - 17:14 
Adam,
 
Thanks for your help. I got the project to compile but now I get a runtime error.
 
I have followed all the steps here
http://www.attention-to-details.com/newslog/38n-temporary-volatile-jet-dsn-for-process.asp
but I get the below error.
 
By the way I included the reference to ADODB (Data Objects) and ADOR (Recordset).
 
In addition here's the value of conn
"Driver={Microsoft Access Driver (*.mdb)};DBQ=c:\inetpub\wwwroot\ZipCoder\demo.mdb"
 
c:\inetpub\wwwroot\ZipCoder\demo.mdb is the correct path.
 

Server Error in '/ZipCoder' Application.
-------------------------------------------------------------------
 
[Microsoft][ODBC Microsoft Access Driver]General error Unable to open registry key 'Temporary (volatile) Jet DSN for process 0x8ac Thread 0x8b4 DBC 0x4f6684 Jet'.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
 
Exception Details: System.Runtime.InteropServices.COMException: [Microsoft][ODBC Microsoft Access Driver]General error Unable to open registry key 'Temporary (volatile) Jet DSN for process 0x8ac Thread 0x8b4 DBC 0x4f6684 Jet'.
 
Source Error:
 

Line 78:
Line 79: 'open the connection
Line 80: db.Open(conn)
Line 81:
Line 82: 'print a white background on the graphic by adding a rectangle to the dimensions

 
Source File: C:\Inetpub\wwwroot\ZipCoder\zipCoder.aspx.vb Line: 80
 
Stack Trace:
 

[COMException (0x80004005): [Microsoft][ODBC Microsoft Access Driver]General error Unable to open registry key 'Temporary (volatile) Jet DSN for process 0x8ac Thread 0x8b4 DBC 0x4f6684 Jet'.]
ADODB.ConnectionClass.Open(String ConnectionString, String UserID, String Password, Int32 Options) +0
ZipCoder.zipCoder.zipCoder.createImage() in C:\Inetpub\wwwroot\ZipCoder\zipCoder.aspx.vb:80
ZipCoder.zipCoder.zipCoder.Page_Load(Object sender, EventArgs e) in C:\Inetpub\wwwroot\ZipCoder\zipCoder.aspx.vb:38
System.Web.UI.Control.OnLoad(EventArgs e)
System.Web.UI.Control.LoadRecursive()
System.Web.UI.Page.ProcessRequestMain()
 

Version Information: Microsoft .NET Framework Version:1.1.4322.573; ASP.NET Version:1.1.4322.573
 

--------------------------------------------------
-mark
GeneralRe: need help with errormembermkane728 Jul '04 - 18:33 
Adam
I figured it out. For some reason giving the IUSR_ account access to demo.mdb wasn't enough. When I gave the Everyone account access to demo.mdb it worked!
 
By the way, I figured it out by temporarily changing the connection string as follows:
conn = "PROVIDER=Microsoft.Jet.OLEDB.4.0;Data Source=" & Server.MapPath(Request.ApplicationPath) & "\demo.mdb;"
 
The below error returned with the above connection string was alot less cryptic than before and I was able to see that giving the Everyone account access to demo.mdb would fix the problem.

The Microsoft Jet database engine cannot open the file 'c:\inetpub\wwwroot\ZipCoder\demo.mdb'. It is already opened exclusively by another user, or you need permission to view its data.
 
-mark
GeneralRe: need help with errormemberAdam A. Mitteer29 Jul '04 - 3:44 
Mark,
 
That is odd that IUSR_account wasn't enough for the project. I am glad you figured it out. And thanks for the info on the provider string... that is something I will keep in mind in the future when using those tedious ADODB connection strings. It seems like I get more and more of the errors as I create pages and it always has to do with connection strings.
 
This may help you out in the future too... this is an article I found while dealing with the Provider (0x80004005) error. It tells you how to optimize IIS to run your ADO connections to MS Access databases.
 
http://forums.aspfree.com/t18145/s.html
 
If you have any other questions let me know.
 
Thanks,
 
-Adam
GeneralRe: need help with errormemberkcl3 Aug '04 - 23:30 
Try the ASP.NET user account - rather than the IUSR_account or Everyone.
 
Hope that helps.
 
Chris
Cool | :cool:
GeneralRe: need help with errorsussAnonymous9 Aug '04 - 9:32 
Can you explain how to use the ASPNET account, rather than the   IUSR account?   I am getting a GDI error when running in debug mode:
Source Error:
 

Line 141:
Line 142:            'finish up
Line 143:            objBitmap.Save(Server.MapPath(Request.ApplicationPath) & "\newGlobe.gif", Imaging.ImageFormat.Gif)
Line 144:            objGraphics.Dispose()
Line 145:            objBitmap.Dispose()

 
Source File: C:\Inetpub\wwwroot\ZipCodeMap\zipCoder.aspx.vb      Line: 143
 
Stack Trace:
 

[ExternalException (0x80004005): A generic error occurred in GDI+.]
   System.Drawing.Image.Save(String filename, ImageCodecInfo encoder, EncoderParameters encoderParams)
   System.Drawing.Image.Save(String filename, ImageFormat format)
   ZipCodeMap.zipCoder.createImage() in C:\Inetpub\wwwroot\ZipCodeMap\zipCoder.aspx.vb:143
   ZipCodeMap.zipCoder.Page_Load(Object sender, EventArgs e) in C:\Inetpub\wwwroot\ZipCodeMap\zipCoder.aspx.vb:29
   System.Web.UI.Control.OnLoad(EventArgs e)
   System.Web.UI.Control.LoadRecursive()
   System.Web.UI.Page.ProcessRequestMain()
 

Thanks for any help.WTF | :WTF:
GeneralRe: need help with errormemberAdam A. Mitteer9 Aug '04 - 10:27 
Hmmm...
 
Let me first give you the permissions I have set for my folder... I know my machine isn't set up as securely as it could be... but good enough to develop. Maybe what I have will help you.
 
F = Full control
M = Modify
E = Read and Execute
L = List folder contents
R = Read
W = Write
 
Users:
Administrator = F
Everyone = E,L,R
IUSR_%Machine% = E,L,R
SYSTEM = F
VS Developers = F
 
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
 
Let me know if that helps...
GeneralRe: need help with errormemberCat Doan1 Apr '09 - 18:07 
Hi Mr. Mitteer,
 
Your program (Mapping Zip Code From Your Database) is very helful. Do you have it in VB6 or could you explain it in VB6. Thank you very much.
 
Cat Doan
catdoan@worldnet.att.net
GeneralRe: need help with errormemberkcl10 Aug '04 - 2:50 
By default...The ASP.NET engine operates under the ASPNET user account.
 
If you have administrator access on the machine hosting your website you can set security permissions on files & folders for the APSNET account as you need to.
 
Impersonation...
If you want to have the ASP.NET engine operates under a different (authenticated user's) user account you can do so using impersonation....
 
- If impersonation is enabled, ASP.NET executes with the identity of the entity on behalf of which it is performing executing the task.
 
- If impersonation is not enabled, the application runs with the privileges of the ASPNET user account.
 

I hope that helps, but shout if you need more. Big Grin | :-D
 
Kind regards,
 
Chris
GeneralRe: need help with errorsussanonymous10 Aug '04 - 3:50 
Well, I appreciate the help. I got it to work after Adam's suggestion. I work in a government agency that has tight control over permissions and was finally able to get to the folder to assign permissions. I don't think I will be having those problems again. I appreciate the explanation. I was actually looking at impersonation online last night. Thanks!
 
WTF | :WTF:

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130516.1 | Last Updated 26 Jul 2004
Article Copyright 2004 by Adam A. Mitteer
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid