Winning Designs

A contest judged by a group from mrexcel.com and Microsoft focused on visualizing data in Excel with PowerPivot where the data came from the Azure cloud data service. The details are at http://www.mrexcel.com/Challenge2011/challenge_52011.html.

I won one of the 2 prizes based on my three contest submissions (http://www.mrexcel.com/Challenge2011/challenge_52011_win.html). This post summarizes the three entries. My plan is to discuss each in detail in separate follow up posts and hopefully include the associated Excel file so that others can explore each approach by themselves.

For a version in a page by itself (i.e., not in a scrollable iframe as below) visit http://www.tushar-mehta.com/publish_train/data_visualization/10%20Dashboards.shtml

Tushar Mehta

Roll Your Own HTML from Excel VBA

You probably know that you can save an Excel workbook in HTML format. I do it for my golf league and it works fine. It also generates a pig of an HTML file, mainly because Microsoft is trying to have high fidelity (make it look the same in the browser as it does in the desktop).

For my most recent sports-related project, I just didn’t want such a large file. I run an NFL survivor pool. You can read all the rules if you like, but basically each participant selects one NFL team per week. If that team wins, the participant survives. If they lose, they’re done. Whoever is left at the end is the winner. I needed a quick and easy way to update the results on a web page.

I start with this spreadsheet:

Bold teams means a loss. Italicized teams are winners. Unformatted teams means they haven’t played yet (or I haven’t updated yet). The end result is this:

I found a bunch of images of NFL helmets and a free green checkmark image on the interwebs. Now all I have to do is read the data and convert it to HTML. Here’s the code:

Sub MakeHmtl()
   
    Dim rRow As Range
    Dim rCell As Range
    Dim sHtml As String
    Dim sBody As String
    Dim sTable As String
    Dim sRow As String
    Dim bLoss As Boolean
    Dim lFnum As Long
    Dim sFname As String
   
    Const sPAIDIMG As String = "<img src=""checkmark.png"" />"
   
    'header
   sHtml = Tag("DK Survivor Pool", "title") & vbNewLine
    sHtml = sHtml & "<link rel=""stylesheet"" href=""style.css"">"
    sHtml = Tag(sHtml, "head", , True) & vbNewLine
       
    'body
   sBody = Tag("DK Survivor Pool", "h1") & vbNewLine
    sBody = sBody & Tag("Updated: " & Format(Now, "yyyy-mmm-dd hh:mm AM/PM"), "p") & vbNewLine
    sBody = sBody & Tag(Tag("Rules", "a", "href = ""survivorrules.html"""), "p") & vbNewLine
   
    'table
   For Each rRow In Sheet1.Range("A2:S13").Rows
        bLoss = False
        For Each rCell In rRow.Cells
            If rCell.Column = 1 Or rCell.Row = 2 Then
                sRow = sRow & AddClass(Tag(rCell.Value, "td"), "name")
            ElseIf rCell.Column = 2 Then
                If IsEmpty(rCell.Value) Then
                    sRow = sRow & Tag("", "td")
                Else
                    sRow = sRow & Tag(sPAIDIMG, "td")
                End If
            Else
                Select Case True
                    Case rCell.Font.Bold
                        sRow = sRow & AddClass(Tag(MakeImage(rCell.Value), "td"), "loss")
                        bLoss = True
                    Case rCell.Font.Italic
                        sRow = sRow & AddClass(Tag(MakeImage(rCell.Value), "td"), "win")
                    Case IsEmpty(rCell.Value)
                        If bLoss Then
                            sRow = sRow & AddClass(Tag("", "td"), "loss")
                        Else
                            sRow = sRow & Tag("", "td")
                        End If
                    Case Else
                        sRow = sRow & Tag(MakeImage(rCell.Value), "td")
                End Select
            End If
        Next rCell
        sTable = sTable & Tag(sRow, "tr") & vbNewLine
        sRow = """"
    Next rRow
   
    sBody = sBody & Tag(sTable, "table", "border=""1"" cellpadding=""5""", True)
    sHtml = sHtml & Tag(sBody, "body", , True)
    sHtml = Tag(sHtml, "html", , True)
   
    If Len(Dir("C:Test_Datadebug.ini")) = 0 Then
        sFname = "C: UsersdickDropboxSportsSurvivorindex.html"""
    Else
        sFname = "C:UsersdickMy DocumentsMy DropboxSportsSurvivorindex.html"""
    End If
   
    lFnum = FreeFile
    Open sFname For Output As lFnum
    Print #lFnum, sHtml
    Close lFnum
   
End Sub

Creating text files from scratch can be a pain in the butt, but HTML files are worse. You have to get all those tags right and properly closed. I hate unindented HTML, so there’s more work there too. Generally I try to work from the inside out on HTML files. That way I can a pass a couple of arguments into a function to make the tags and be assured that I don’t miss something. Take the header section for example. First I pass “DK Survivor Pool” and “title” into the Tag function. That function looks like this:

Function Tag(sValue As String, sTag As String, Optional sAttr As String = "", Optional bIndent As Boolean = False) As String
   
    Dim sReturn As String
   
    If Len(sAttr) > 0 Then
        sAttr = Space(1) & sAttr
    End If
   
    If bIndent Then
        sValue = vbTab & Replace(sValue, vbNewLine, vbNewLine & vbTab)
        sReturn = "< " & sTag & sAttr & ">" & vbNewLine & sValue & vbNewLine & "< /" & sTag & ">"
    Else
        sReturn = "< " & sTag & sAttr & ">" & sValue & "< /" & sTag & ">"
    End If
   
    Tag = sReturn
   
End Function

(WordPress doesn’t like HTML so there’s an extra space in the closing tag part.) I get back something that looks like this

<title>DK Survivor Pool</title>

Next, I append the link tag manually because it doesn’t really fit into my inside-out dynamic. Finally, I call sHtml = Tag(sHtml, "head", , True) & vbNewLine to wrap what I have in a head tag. I also set the optional Indent argument to true and get this:

<head>
    <title>DK Survivor Pool</title>
    <link rel="stylesheet" href="style.css" />
</head>

The code wraps whatever I send it, in whatever tag I send it, and indents along the way. The other optional argument is for including attributes within the tag. I want my table tag to have border=”1″ and cellpadding=”5″ so I supply those to the function when needed. I use the class attribute a lot to format winners and losers. I created a separate function to add a class attribute so I wouldn’t have to type it in the code.

Function AddClass(sTag As String, sClass As String) As String
   
    AddClass = Replace(sTag, ">", " class=""" & sClass & """>", 1, 1)
   
End Function

The last helper function is to create an image tag. My Tag function is good for enclosing something in opening and closing tags. The image tag is self-closing, so it gets its own home. On the spreadsheet, I record the team name so that it matches the image file name. If I type “eagles” for a Philadelphia pick, the MakeImage function returns <img src="eaglesleft.bmp" />

Function MakeImage(sValue As String) As String
   
    MakeImage = "<img src=""" & sValue & "left.bmp"" />"
   
End Function

The main code basically loops through all the cells, determines the HTML necessary, and appends it to one long string. That string is then written to a file. Once complete, I manually FTP that file up to my web server. A couple of other notes on the code:

Losing teams are colored red and that participant doesn’t get to select any more. I wanted all the succeeding weeks to be red also. I use the bLoss variable to handle this. When I get to a loss, I set bLoss to True. When an empty cell is detected (no selection yet), I add the “loss” class to the td tag to color it red.

The last part is the location of the file. My dropbox folder is in two different places on two different computers. I’m not sure why this is, but I think it relates to which operating system was installed when I installed Dropbox. Back in the Windows XP days, Dropbox put it in My DocumentsMy Dropbox and in Windows 7, it’s directly under the user folder and they dropped the “My”. At least I think that’s what happened. To differentiate the two, I found a file that I’m absolutely sure is on one computer and absolutely sure isn’t on the other. I use Len(Dir(..)) to test the existence of the file and change the path accordingly. I think we both know this will break some time in the future, but it works for now.

One of the downsides to the inside-out approach for concatenating HTML is code readability. If I’m just building a string one character at a time, it’s pretty easy to follow along. When I use functions to wrap strings in tags, it’s a little harder. You might expect that the html opening tag would be near the top of the procedure, but it’s actually the last tag I add because it’s “outside”.

Finally, if you’re new to creating big strings in VBA, you should note that to embed a double quote into a string, you use two double quotes in succession.

Spot the 10 differences

Hi everyone!

Yesterday I experienced the tedious task of figuring out what the differences are between the VBA projects of two different versions of a customer project I built a long time ago. Luckily there are tools to compare differences in text files, such as ExamDiff.
But the VB editor doesn’t give you an easy way to export all of your code into a single textfile. So I figured I’d roll my own. At first I simply let the routine run through all VBComponents of the VBA project.

To my surprise, the order of the components in the generated textfiles wasn’t the same for both workbooks, even with the exact same components in there.
So I decided I’d better first make a list of all VBComponents, sort that list and then export the content to a textfile.

Download ExportVBAProject here.

Enjoy!

Jan Karel Pieterse

Flipping Coins

Sometimes people post their homework problems on stackoverflow.com I don’t answer homework problems, but I do like to try to figure them out.

Problem description: Take a stack of coins all heads up. Upturn the topmost coin, place back on the stack and then proceed: take the top 2 coins and upturn as a single stack (tail, head becomes when upturned and placed back on the stack tail, head (the two coins are flipped as if glued together)). Now in the same way flip the top 3 coins and place back on the stack (you get: tail, tail, head (and if there were 4 coins that would be tail, tail, tail, head). When you upturn the whole stack begin again with the first coin. Continue until you return to a stack with all heads up.

Here’s what I came up with:

Sub FlipCoin()
   
    ‘Stack a number of coins all heads up
   ‘flip the first coin and put on the stack
   ‘flip the first and second coin as a unit and put on the stack
   ‘flip the fist n coins as a unit and put on the stack
   ‘repeat flipping the first coin
   ‘stop when all coins are heads up
   
    Dim i As Long, j As Long
    Dim aCoins() As String
    Dim lCount As Long
    Dim dMidPoint As Double
    Dim sTemp As String
    Dim bAllHeads As Boolean
   
    Const lCOINS As Long = 6
   
    ReDim aCoins(1 To lCOINS)
   
    ‘set all coins to heads
   For i = 1 To lCOINS
        aCoins(i) = “H”
    Next i
   
    lCount = 0
    Debug.Print lCount, Join(aCoins, “,”)
   
    Do
        For i = 1 To lCOINS
            ‘flip the first j coins
           For j = 1 To i
                If aCoins(j) = “H” Then
                    aCoins(j) = “T”
                Else
                    aCoins(j) = “H”
                End If
            Next j
           
            ‘swap coins around the midpoint
           dMidPoint = i / 2
            For j = 1 To Int(dMidPoint)
                sTemp = aCoins(j)
                aCoins(j) = aCoins(i – (j – 1))
                aCoins(i – (j – 1)) = sTemp
            Next j
           
            lCount = lCount + 1
            Debug.Print lCount, Join(aCoins, “,”)
           
            ‘check for tails
           bAllHeads = InStr(1, Join(aCoins, “,”), “T”) = 0
            If bAllHeads Then Exit Do
        Next i
    Loop Until bAllHeads
   
End Sub

I only tested it to six coins. I thought the graph would be prettier.

Colored Cube Game

Justin created a Rubik’s Cube game in Excel.

Just like in the real Rubik’s cube, I’m only good for one side. The code is unprotected, so check it out.

Conditional Correlation

The CORREL function is used to find the correlation between two arrays. Because CORREL ignores text, you can use an array formula as one of the arguments of CORREL to limit it to a subset of the data.

To demonstrate, we’ll need some data. I fired up QuickSampleData to make fifty rows with a continent name in the first column and a two-digit number in the second.

Next I created the second array using RANDBETWEEN to give me data that had a relatively high correlation.

The formula needed to limit the correlation to Africa, with “Africa” in B1, is:

{=CORREL(IF(A3:A52=B1,B3:B52,”"),C3:C52)}

Enter that with Control+Shift+Enter, not just enter and Excel will put the curly braces in for you. I only needed to turn one of the arguments to text to get CORREL to ignore that row.

ODBC Microsoft Access Driver Is Not a Valid Path

A few weeks ago, out of nowhere, I started receiving the following error when I started Excel after a restart or resuming from a locked computer.

Run-time error ‘-2147467259 (80004005)

[Microsoft][ODBC Microsoft Access Driver] ‘(unknown)’ is not a valid path. Make sure that the path name is spelled correctly and that you are connected to the server on which the file resides.

I have a ton of add-ins that load at startup and more than a few of them connect to an Access database via ActiveX Data Objects (ADO). The offending code was simply establishing the ADO connection.

Sub ConnectToMRP()
   
    If gcnMRP Is Nothing Then
        Set gcnMRP = New ADODB.Connection
        gcnMRP.Open gsMRPConn
    End If
   
End Sub

The global constant, gsMRPConn, pointed to the file correctly. I was able to access the network share via Windows Explorer. But when I executed the code

?Len(Dir(gsMRPConn))

I got 0, meaning VBA couldn’t resolve the path. The fix for a while was to close Excel and restart. Sometimes one restart would fix it and other times it took up to five restarts. I was at a loss for why VBA couldn’t see the network share.

After much searching, I read something about offline files. I had no idea what offline files were or why I would want them. Apparently Windows makes a cache of network files locally so that I can access them when I’m not on the network. I typed “offline files” in the Win7 start menu and found the Offline Files dialog.

offline files dialog

I disabled offline files and have not had the problem since. I still don’t know how offline files work. I was connected to the network, so there was no need for Windows to use files offline. And if it had a cache, I’m not sure why it didn’t use it. I guess Windows was working to sync offline files in the background, which is why it worked after some number or restarts. I’m just glad the nightmare is over.

Same function different add-ins

Ever since Microsoft introduced the ribbon and I did my initial development work with it, an open issue has been how to handle the case where two, or more, add-ins offer the same functionality. One scenario is when the feature is something required for the larger functionality offered by an add-in. Here’s an example.

The TM Chart Utilities add-in offers the capability whereby for a chart series labels one can specify a range other than just the X or Y values.

The TM Chart Labels Hover add-in, developed to display a label only when the user hovers over the associated data point, incorporates, as a sub-function, if you will, the capability to specify a range as the source for a series’ data labels. The UI and the code are the same in the two add-ins (I essentially copy the form and the supporting modules from one add-in to the other).

The problem is that with both add-ins installed the UI displays two buttons, both labeled Set Data Labels, that do the same time. It looks clumsy, to say the least.

What I would like is that whether one or both of the add-ins are installed, there is only one Set Data Labels button.

For a version in a page by itself (i.e., not in a scrollable iframe as below) visit http://www.tushar-mehta.com/publish_train/xl_vba_cases/1019%20Same%20function%20Different%20AddIns.shtml

Tushar Mehta

Excel 2011 on the Mac

Hi all

FYI

A few weeks back I start working on my first Mac, and I must say I love the OS but there is a lot of work to do in Office for the Mac.
My idea is to go through all my webpages and see if I can make the VBA code also working in Excel 2011.

I start this problem page
http://www.rondebruin.nl/mac.htm

I also add VBA code examples last week to mail from Excel 2011 with Apple Mail and Outlook 2011.
If you have problems with Excel on a Mac post it here, maybe I can check it out and find a workeround for it.

Ron de Bruin
http://www.rondebruin.nl/tips.htm

Ease of reuse of modular code

The primary reason I write modular code is that it is self-documenting, easy to understand, and easy to maintain. A secondary reason is the ease of reuse.

One of the comments to my post Two new range functions: Union and Subtract (www.dailydoseofexcel.com/archives/2007/08/17/two-new-range-functions-union-and-subtract/) was a request for code to copy a range from one worksheet to another with certain ranges excluded. While I agree with DK that there’s no need to get fancy with something that is used once a month, I couldn’t pass up the opportunity to illustrate the ease of reuse of modular code.

For a version in a page by itself (i.e., not in a scrollable iframe as below) visit http://www.tushar-mehta.com/publish_train/xl_vba_cases/1102%20Modular%20code%20-%20ease%20of%20reuse.shtml

Tushar Mehta