PowerPivot and Sparklines .. the easy way

March 30, 2010

Another guest post from Kasper… our man in Amsterdam!

VincentVegaLaptop
Kasper Vega Crunching Numbers on His Laptop

Today we have another guest post from Kasper de Jonge, our man in Amsterdam!  He’s been experimenting with Sparklines, a feature that’s new in Excel 2010, and integrating it into his PowerPivot work.

Take it away Kasper…

In Excel 2010 MS introduced Sparklines, as described on the Excel blog:

For Excel 2010 we’ve implemented sparklines, “intense, simple, word-sized graphics”, as their inventor Edward Tufte describes them in his book Beautiful Evidence. Sparklines help bring meaning and context to numbers being reported and, unlike a chart, are meant to be embedded into what they are describing.
blogimage1

Too bad the sparklines aren’t really tightly integrated with PowerPivot as are other charts. In this post i’ll describe an easy way to implement sparklines on PowerPivot data, with use of slicers.

Of course we start by loading data into PowerPivot, first we create a workbook in PowerPivot:

To gain more insight in sales per country per month I would like to use the sparklines per country. Lets start by adding data using a pivottable in a new sheet

Make sure you connect this Pivottable to the slicers from my other sheet by using the connect slicers option as posted in this blog post.

Ok next we are going to add the country’s to the original workbook. Select the country’s and copy them. Paste hem into the original sheet:

Now for the sparklines, go to insert and click Line. we now have to select the source for the sparklines, in our case this is the pivottable in our newly created workbook, and select all data in the months:

next we have to select where we want to put the sparklines:

This will result in the sparklines being showed:

We want them to be a little wider so we select the cell with the sparkline and the adjacent cell and click Merge and center to let our sparkline span two cells, next we select another sparkline design, I also like to use the markers.

This results in the following workbook:

We can even use the slicers, as we can see here when we select 2008 we only have 8 months, this will show in the sparklines as well:

I love sparlines, and they aren’t that hard to implement, for more information on sparklines see:

http://blogs.msdn.com/excel/archive/2009/07/22/formatting-sparklines.aspx and http://www.msofficegurus.com/post/Excel-2010-Sparklines.aspx

You can download a sample file I created here.


NotePad++

March 29, 2010

Colin just sent me a screenshot of what my formula would look like in NotePad++

Indexed Population Growth

Um, sold. 

I will be downloading it shortly.


Two Observations

March 27, 2010

I know I’ve been a bit quieter than usual.  I’ve been off learning…  a lot.  Which means that a number of things are piling up that I’d like to share.

Rapid fire today.

Notepad is a great formula editor

NotePad 

This pains me to admit since I worked on the PowerPivot formula editor, but…  I’ve been cheating on my own creation.  With Notepad, of all things.  Does that mean I’m slumming?

Never Underestimate the Impact of a Bad Childhood

Wait, how did that picture get in here?  How is that remotely relevant to slumming?  Some sort of typo I guess.  (Nazi garb…  ugh).

And did I just compare the PowerPivot formula editor to Sandra Bullock?

Turns out that Notepad lets me do a number of things that I find myself needing:

  1. Indenting the formulas – I’ve been doing a lot of complex stuff lately.  Readability has become crucial.
  2. Saving formulas – sometimes when I get something done and know I’m going to want to re-use it, I save it in a text file.
  3. Find and replace – when re-using a formula, most of the time the column names need to be changed.  How cool is it to do that automatically rather than manually?
  4. Bigger font size – better readability.

And the formula editor in PowerPivot supports copy/paste, so you can move back and forth between it and Notepad without issue.  (Somehow I think Jesse’s life might not be so smooth).

Anyway, I highly recommend it.  (Notepad, I mean).  And if anyone has another editor that they’ve tried and liked, let me know.

SharePoint Saturdays – more proof that SharePoint is exploding

SharePoint Saturday Attendees

What are these people doing on a Saturday morning, sitting in a lecture hall?

They are attending a “SharePoint Saturday” in Ann Arbor, Michigan.  These events are held every couple of weeks in a different location – I see them talked about all the time in Twitter but this was my first time attending one.  Wow!  200 people spent an entire Saturday, unpaid, listening to SharePoint talks?

Do you see what I am talking about when it comes to the SharePoint community?  Ignore SharePoint at your own peril.  Customer-wise, it’s the hottest thing going from MS.

And of course, the gratuitous shot of yours truly delivering the keynote speech, and my PowerPivot session where people were literally sitting in the aisle.

KeyNote robsession

Clearly the SharePoint audience has great taste :)

On a completely serious note, I will say that the SharePoint audience “gets” PowerPivot better, on average, than the Excel or BI audiences.  They see the value of the whole system more readily than the other groups, who often tend to view it through their existing lenses.

Surprising?  Perhaps.  But true.

(Note that this was my first-ever keynote speech, and I was introduced as “the most famous person we could find” – best intro ever!  There’s a joke to be made here about how scrappy the SharePoint community is, something to do with small budgets…  that said, they arranged a luxury suite at the Pistons game, and a huge limo to take all of the speakers to the arena!)

Two weeks after the event and I’m still shaking my head in (happy) disbelief.


RANK measure finished

March 21, 2010

 
Angel Eyes Always Sees the Job Through

 

“…I always see the job through.”

-Angel Eyes

Yep, I said I would return and finish off the Rank measure.  Time to deliver.

 
(And this makes three straight Spaghetti Western movie quotes!)

Where we left off – Unknown ranks #1

Last time, I’d written a mostly-working version of the measure that ranks a player by his Rushing Yards value, and that doesn’t return an error when I leave the Unknown player in the pivot:

DAX Rank Measure that Does Not Error 
But the Unknown/Blank player is still messing up my rank because of all the small-time players it lumps together into a huge number of rushing yards – I want Edgerrin James to be first.

Must remove the Unknown player from rank consideration

This turns out to be pretty tricky.  Here’s the formula again:

   COUNTROWS(
     FILTER(
       ALL(Players[FullName]),
       [RushYards](Values(Players[FullName])) < [RushYards]
     )
   ) + 1

As explained last time, that’s counting the number of players that have more rush yards than the current player in the pivot, and then adding one.

The heart of that formula is this comparison test – players only get counted if this evals to true:

   [RushYards](Values(Players[FullName])) < [RushYards]

I want to add a condition to that.  It’s not enough for a player to have more rush yards.  They also must NOT be Unknown/Blank.  So I want it to be something like:

   [RushYards](Values(Players[FullName])) < [RushYards]
      && PlayerIsNonBlank

Filling in that green part with a real formula is the trick.

Why not just remove the + 1 and be done with it?

Indeed, I could remove the “+ 1” at the end of the formula and voila! – all is right with the rankings.

But that’s only true right now, without the pivot filtered in any way.  There will definitely be cases where, as I slice the pivot down to narrow cases, no Unknown player recorded any Rush Yards.  And suddenly, the top real player would be ranked as –1.

“PlayerIsNonBlank” – the DAX solution

First I had to define a new measure, [NonBlank Player Count].  It is defined as follows:

   COUNTROWS(DISTINCT(CleanPlayers[FullName]))

It turns out that DISTINCT does not return Unknown members.  DISTINCT and VALUES are exactly the same function, except that VALUES includes Unknown and DISTINCT does not.  (Colin, sorry I never replied to your comment awhile back, but yes, that is the difference).

So that’s pretty handy.  When I am in the context of a real player, this measure returns 1.  And so I can use that measure inside my Rank measure, to weed out the Unknown player from rank consideration.  Replacing the green pseudoformula from above my condition is now:

   [RushYards](Values(Players[FullName])) < [RushYards]
      && [NonBlank Player Count] = 1

Which makes my overall measure:

   COUNTROWS(
     FILTER(
       ALL(Players[FullName]),
       [RushYards](Values(Players[FullName])) < [RushYards]
         && [NonBlank Player Count] = 1
     )
   ) + 1

Does it work?

Sort of.  Here ya go:

DAX Rank Measure - Fixed Numbers But Unknown Still Shows Up

So… the numbers are right!  Edgerrin James is now #1 as he should be, and everyone follows after.

But that pesky Unknown player.  It won’t go away…  it’s like Rasputin or something.

It’s ugly, and I want my reports to be pretty.

Furthermore, look at the Grand Total:

DAX Rank Measure - Grand Total Shows 1

Again, ugly.  The grand total cell should show nothing.

The fix:  making the measure return BLANK()

To solve this, I took the entire measure above and wrapped it in two nested IF’s:

=IF(COUNTROWS(VALUES(CleanPlayers[FullName]))=1,
   IF(NOT(ISBLANK(Values(CleanPlayers[FullName]))),
      <The entire measure formula from above>,
      BLANK()
   ),
   BLANK()
)

What that means is this:

  1. If the current pivot context corresponds to exactly one player, AND that player is NOT a Blank player, then go ahead and evaluate the measure expression. 
  2. If the current pivot context corresponds to multiple players (as what happens in a Grand Total, or a Subtotal), return BLANK()
  3. If the current pivot context corresponds to a Blank player, again return BLANK()

This works great!  Check out the results at the top and bottom of the pivot:

DAX Rank Measure - BLANK for Unknown Player Means It No Longer Shows Up DAX Rank Measure - BLANK for Totals Too

When a measure returns BLANK(), that row disappears from the pivot, even the Grand Total.  Yay!

And if I add another measure that is non-blank for those rows, the Blank player comes back, but my Rank measure will display a blank cell rather than a number.

Are we done?  Depends on the intent

I said this was tricky remember?  Look what happens when I add another field to rows, like College Attended:

DAX Rank Measure - Rank Evaluates By Parent Not Overall

Neat!  Now my Rank measure treats each parent value (each College in this case) as a separate world in which to rank players.

Shaun Alexander is indeed the #1 NFL rusher from Alabama in my database.  Perhaps that’s exactly the behavior I want, and in some cases it will be.

At some point I will explore how to NOT do this – how to still display Shaun’s overall rank while nesting him under his college name.  But for now, this is enough to digest I think.

Next Football Post:  Do Not Over-Use FILTER()  >>


Retailer Overlap Analysis Using PowerPivot

March 16, 2010

 
Clint Pondering Where to Buy More Cigars

 

“The Rite Aids on one side of town, the Walgreens on the other, and me right in the middle.”

-The Shopper with No Name (and a Fistful of Dollars)

 

One of the coolest things about my new job at PivotStream is all of the cool new data sources I get to play with.  I thought I’d take a brief break from the Rank member posts and share a little bit from one of those sources.

Retailer Overlap Report

I just finished cooking up this report – click for full-size version.

All Retailer Intersections with PowerPivot

What does that show?

It shows the top 15 US retail chains by number of stores, and their competition against one another by ZIP code population.

For example:  take the first row, Albertsons.  Of all the people who live near an Albertsons, 65.9% of them also live close to a CVS, but only 4.7% live near a Rite-Aid.

Cool, huh?

Marketing versus competitors

Let’s say you are in charge of advertising and promotions for a large grocery or drugstore chain.  One of your primary jobs is to lure consumers into your stores as opposed to your competitors’.  Every day you receive a collection of all the specials, advertisements, etc. that your competitors are running in various regions of the country.

Naturally, you want to respond to their efforts.  But you can’t focus on them all equally, or you’d fall hopelessly behind.  So, which ones should you pay the most attention to?  This is the kind of thing that would help you.

Sliceable too!

OK, let’s say you work for Safeway, and you only run advertising for them in the South region.  How useful is the nationwide report above?  Hard to say.

For instance, nationwide, Walgreens competes with you for 47.3% of your customers, and Rite-Aid is second at 36.1%.  Does that hold up in the South?

One click and you have a brand new report:

South Region Only Retailer Intersections with PowerPivot

And look, Walgreens falls to 14.1%!  Rite Aid climbs to 52.5%…  but CVS now checks in at a whopping 73.5%!

So no, the national report would mislead you.  Same thing would be true if you ran all newspaper advertising nationally for Safeway, but you were ignoring an ad that CVS was running in the South.

Also Sliceable by Income Range!

Lastly, let’s say you work for ShopRite, and you control advertising in the South region.  Walgreens is running a monthlong special on Product X, and you happen to have the ability to run a better special on Product X…  but should you?

Well, you consult the report above, and it shows you that Walgreens only competes with you for 34.9% of your customers.  So you decide not to run a special on Product X, since that costs you a lot of money for not enough benefit.

But suppose you knew that Product X was primarily targeted at households making between $50K and $75K.  Slice by that income and you get:

South Region Only Specific Income Range Retailer Intersections with PowerPivot

Hey look, Walgreens competes with you for 61.6% of your customers in that income range. 

So that ad campaign might be targeted specifically at stealing business from ShopRite, for all you know :)

How did I do this?

It’s complicated, and once again pushed the bounds of what I know about DAX measures.  It starts out a lot like a Market Basket Analysis, which takes some work to explain, but then it takes another twist.

I’ll explain in subsequent posts :)

Flexibility!

But the crucial thing to note here for now is that this amount of flexibility is impossible in Excel by itself.

I mean, if I wanted to build a report that showed overlap between any two retail stores, with particular variables like region and income level held constant, I can do it.  Takes awhile but I can build one.

But as soon as someone says something like “I want to see this report filtered down to a different region,” well, you’re doing surgery on your original report.  Sometimes that takes almost as long as it did the first time around.

And when you’re done, well, now you have TWO reports to maintain.  Fun fun!

That’s the coolest thing about this report for me:  it remains flexible.  Its consumers don’t have to ask me for new versions of the report.  They can just click to filter.

And if they want new variables added, like racial demographics, that’s just a matter of adding new calculated columns to the PowerPivot window, not a new report.  I might even do that for next time.


The Great Broken Links

March 15, 2010

Just discovered this morning that all of my links to the Great Football Project were broken.  Ugh, that’s the best intro to PowerPivot since it’s where I started blogging back in the Fall.

Links fixed now.


Rank continued – dealing with unknown members

March 11, 2010

 
Unknown Player Right Next to Edgerrin James

 

TUCO:  “There’s no name on it!”

BLONDIE:  “Well, there’s no name here, either.”

 

 

Ode to YouTube HD

When I used to work on Bing and would look at search logs, I was always puzzled by some of the search strings that went by.  Well today I gave them one of my own –“Clint Eastwood holding rock,” among others.  I hope that confuses someone.

YouTube in HD, though – you are my new best friend for finding obscure screenshots from movies.

The problem from last time

Remember my Rank report that started with #2?

Number Two Tops the List

Filtering out Unknown PlayersWell, the reason for that is that I have some unknown players.  I’ve been filtering them out using the Row filter feature, shown here at right.  Note the last checkbox in the list, with the blank name unchecked.

(Also note the appearance of Zeron Flemister, two checkboxes from the bottom.  My friends and I had a tradition of always picking him in the last round of fantasy drafts just because we thought his name was so funny.)

 

 

 

 

 

Anyway, if I clear that filter and try to include that blank player in the pivot, I get the lovely error below.

image

Actually, that’s a pretty good error string, since it tells me pretty much exactly why the measure failed to evaluate.

Question 1: Where do the blank players come from?

My first hunch here was that my CleanPlayers[Full Name] column contained some blank values.

But then I remembered that the whole point of the CleanPlayers table was to make sure all unnamed players were removed.

So if that column does not contain any blank player names, why on earth do I get a blank player name in the list when I put that column in my pivot?

Answer: The Plays table sneaks them back in

alien-ceiling-large

 

“They must have found another way in, something we missed!”

-Ripley

(Best picture I could find.  Seriously.)

Here’s the thing:  when I removed all of the “blank name” players from my Clean Players table, I didn’t go back and remove all rows from the Plays table that involved those players.

So those rows from the Plays table now point to *nothing* in the Clean Players table.

To demonstrate, I sorted both the Plays and CleanPlayers table by [PlayerID]:

Plays Table First Player ID is 4 CleanPlayers Table First Player ID is 70

The first player in the Plays table is ID=4.  The first player in CleanPlayers is ID=70.

So when I add a measure from the Plays table (like Rushing Yards, or even my Rank measure), that forces a blank/unknown item to appear in my Clean Players list, even though there aren’t any such blank rows in the CleanPlayers table.

Step one of the fix:  find the error

OK, I spent a LONG time trying to figure out WHERE the error occurred in my measure.  Along the way I sent mail to my buddies in Redmond and begged them for a “step into” debugger feature.  But I know that it’s an incredibly difficult feature to build.

Let’s make a long story short.  Remember that second filter clause from the last post that I wasn’t sure was needed?  The one that made sure we weren’t comparing a player to himself?  Well, it’s actually the place where the error occurs, too:

   Players[FullName]<> Values(Players[FullName])

I remove that from the formula and now just have this for my rank measure:

   COUNTROWS(
     FILTER(
       ALL(Players[FullName]),
       [RushYards](Values(Players[FullName])) < [RushYards]
     )
   ) + 1

And that no longer errors with the unknown player in the pivot:

DAX Rank Measure that Does Not Error

Good news: not only does the measure no longer error, I verified that it returns the exact same results for all 4,000 players as the measure did before I removed the second clause.  It was like my measure had appendicitis – a critical problem in a needless organ :)

Bad news:  That unknown player is still grabbing the top rank, demoting Edge to 2.

Good news:  I figured out how to fix that.

Bad news:  Man is the fix ugly.  I’m going to see if there’s a better way before I blog about my Rube Goldberg solution.

I really did intend to finish this off for you guys today but don’t want to spread bad methodology.  Stay tuned.


Down the rabbit hole: my new adventure revealed

March 9, 2010

 The%20Matrix%20_DivX_%20127_0001

 
"You’ve been down there, Neo. You already know that road. You know exactly where it ends. And I know that’s not where you want to be."

 

 
Not looking for “Redmond Lite”

First of all, I’d like to thank all of you for your wonderfully kind thoughts and wishes on my “Leaving Microsoft” post.  That felt excellent, especially coming from such an illustrious group of people :)

In those comments, some expressed a sentiment that it was a shame MS didn’t keep me on in another role.  I want to clear that up – the folks at MS made many such efforts.  One way to view it is that they were trying hard to retain me.  Another way is that they were sincerely trying to help.  Both are true, for which I am honored and grateful.  MS could not have handled things any better.

Bottom line for me, though, was that after 14 years at “the brightest point in the MS galaxy,” I didn’t think I would thrive in “the outer systems,” to paraphrase from the book of Luke (Skywalker).

Please remove walls, ceiling, and net

Furthermore, in recent years I’d had a growing desire to try to build a business on my own.  Take an idea, accept the risks associated with pursuing it, take responsibility for delivering results, remove the restraints that naturally exist at a large company, and directly reap whatever rewards come from it… if it succeeds.

High risk, high reward.  Flexibility to pursue multiple ideas, to the extent that I am willing to put in the hours.  Ownership, in every sense of the word, was what I was looking for.  I’d been increasingly wanting that, and if I wasn’t willing to try it now, I knew I never would be.

I just needed to find the right fit.  And then, the right fit found me.

“Knock knock, Neo”

RedpillMatrix The trail started a few months ago.  An email from someone I didn’t know, with a movie quote as the subject line!  Followed by a face to face meeting in a picture-perfect town that looked like the setting of Gilmour Girls, The Truman Show, and the Stepford Wives blended together.

I never would have guessed that such a setting was the chosen lair of an analytics Morpheus, leader of a renegade BI outfit, who already grasped the potential of PowerPivot to change the rules.  It was a fascinating lunch – two High Priests of compatible religions opening each others’ eyes to possibilities.

I took the red pill :)

This Artist is Amazing - Click for his Site“That is the sound… of inevitability”

As of today, I am now officially CTO (Chief Technology Officer) and CAO (Cinematic Analogy Officer) of PivotStream.  (Seriously.  I’m gonna put both titles on my business cards.  I’ve long said that it would be ideal to be paid to quote movies, and this makes it official.)

They are data ninjas who move silently through the halls of big business. The Consumer Packaged Goods, Pharma, and Retail landscapes are where there art is most deadly, but they have forayed into other arenas as well, even…  sports data.  They accept data challenges for the sake of solving them.

I can’t say it any simpler than this:  they are my kind of people.

And PowerPivot figures heavily in our plans, so to already have “Pivot” shrinkwrapped in the title is pretty damn nice as well.

Why this fits me

No walls, ceiling, or net – the PowerPivotPro division
My mission is to run a Skunkworks-style startup division, charged with jumpstarting new platforms and business models.  No walls.

And for the first time in my life, I am a partner rather than just an employee.  I can’t tell you how exciting that is for me, to have my personal and professional success so tightly linked.  I can die by this particular sword, but I can also live very well by it.  No net.  No ceiling.  Pure motivation and energy.

Mission #1 – On-Premise BI JumpStarts
Think of this as consulting and training.  Want to hit the ground running with PowerPivot or the overall SharePoint/MS BI Platform?  The Pro (and my team, when needed) will come to you and get you up to speed fast.  More details here.

Mission #2 – My Pet Project
How cool is it to pitch your pet idea and be told “yes, get started immediately!”  Well that’s how Morpheus rolls.

What is it?  Well, it will be easier to show it than explain it, so I’ve got some work to do.  In the meantime, here’s the gist:

  1. PowerPivot is at its core, so I will always have good fuel for the blog and FAQ
  2. I see myself becoming a bit of a Mashup Monster – of data, tools, and services
  3. At times, it most definitely will involve sports – how could it not?
  4. At times it will also leverage PivotStream’s existing expertise in Retail, Pharma, and CPG
  5. “IQ as a Utility” is one way we’ve described it amongst ourselves

Secondary Mission – PivotStream’s Current Business
PivotStream already has customers today, using an existing platform.  The expertise is already in place to keep that platform cranking along, as are the plans to grow business on it.  So that’s not going to be my focus, but I will be advising on infrastructure and optimization out of the gate.

Onwards

Thanks for reading this far.  We now resume normal programming.


Writing a RANK measure (and living to tell the tale)

March 8, 2010

 
Beavis_and_Butthead

“Number One, I order you to take…  a number two.”

-Captain Jean-Luc Butthead

 

 

Before I get started, do you have any idea how hard it is to find cartoon images from the pre-Internet era?  I just lost ninety minutes, first looking for the Far Side cartoon of “Custer’s Last Group Photo” (where everyone is holding up the “we’re number 1!” finger – get it?) and then struggling to find a version of the Beavis and Butthead image above at a better size.  No dice.  OK, enough of that…

DAX v1 has no RANK() function

That’s right.  If you want to write a pivot measure that tells you where a particular store, or product, or customer ranks according to another measure, and according to current filter context, well, a RANK() function would be nice.  But there wasn’t time to implement it in PowerPivot v1.

Never fear, there’s a workaround…

OK, yes, there’s a workaround – the FAQ says so right here.

But “never fear” might be an overstatement.  In fact, I should pause right here and say…

PowerPivot is simple, this technique is not

I’ve been doing this blog since October.  I’ve covered a lot of ground.  If you read this post and fear that you have to understand it in order to get great results with PowerPivot, well, then I’ve done you a great disservice.

Because in many ways, PowerPivot is actually easier than Excel itself.  If you are new here, I strongly recommend going back to the Great Football Project and starting from the beginning.

OK, back to the power technique

I don’t know about you, but personally, my first impression of the formula referenced in the FAQ sounded a lot like “double yoo tee eff.”  Check it out:

  COUNTROWS(
      FILTER( 
          ALL(DimCustomer[CustomerName]), 
          DimCustomer[CustomerSales]
              (Values(DimCustomer[CustomerName]))
                  
< DimCustomer[CustomerSales]
          && DimCustomer[CustomerName] <>  
                   Values(DimCustomer[CustomerName]) 
      )
  )
+1

Explaining how it works

That formula has been bothering me for a long time.  I knew it wasn’t going to be easy to break it down, but on our little DAX adventure together, we must leave no stone unturned, even the really heavy ones.

So today, I dove in.  And whenever I get uncomfortable, I run to familiar ground.  Which means, of course, oh yes…

The Great Football Project Returns!

Quick!  Someone get me some early-2000’s running backs!

  94801734-marshall-faulk   Edgerrin-James_1 Shaun_Alexander

Phew, I feel better already.  OK, let’s dig in.  A long time ago I defined a [RushingYards] measure using the CALCULATE function.  Let’s park that in a pivot:

PowerPivot Rushing Yards 
I want to write a measure that gives me the rank of each player, by Rushing Yards, no matter how I have sliced or filtered my pivot.

First step:  convert the sample formula over to my table/column names

When I substitute my football workbook’s names into that formula, I get:

   COUNTROWS(FILTER(ALL(Players[FullName]),
   [Rushing Yards](Values(Players[FullName]))
   <[Rushing Yards] && Players[FullName]<>
   Values(Players[FullName])))+1

I won’t bother pretty-printing that monster just yet, because I’m going to dissect it step by step.

Outside functions:  COUNTROWS + 1

The formula is basically:

   COUNTROWS(all kinds of crazy stuff) + 1

Which starts to make a little bit of sense, if you’re feeling sleuthy.  Really, what this is doing is:

   COUNTROWS(# of Player Rows where Player has more yards) + 1

Make sense?  Find how many players outrank the current player, add one, and that’s your rank.  OK, so how does the middle stuff determine the number of players that outrank the current player?

Inside functions – FILTER and ALL

   FILTER(ALL(Players[FullName]),
   [Rushing Yards](Values(Players[FullName]))<[Rushing Yards]
    && Players[FullName]<>Values(Players[FullName])))

Recall that the syntax for FILTER is:

   FILTER(Table Expression, Filter Clause)

In this case, our table expression is:

   ALL(Players[FullName])

Which makes sense.  Remember, on a particular row of our pivot above, the Players table is going to only contain the row from that player, for purposes of measure calculation.

Ranking Edgerrin James against himself, for instance, isn’t very interesting, unless you want to compare the Colts version to the Cards version, or heaven forbid the Seahawks version.  (The wear and tear on RB’s really is astounding).

So in order to have any players to rank the current player against, we need a table where the filter has been cleared.  That’s why we use ALL.

That leaves us with the Filter Clause, and it deserves its own section.

Inside Functions – the “Filter Clause” parameter to FILTER

OK, so we have a table that consists of all player names.  And we want to filter that down to just those players that have more Rushing Yards than the current player.

The FILTER function goes through that table of player names, one by one, and for each row, evaluates the filter clause to determine whether that row is “in” or “out.”

Our filter clause is really two clauses connected by the logical “and” operator – &&.  So a row must meet BOTH criteria to be included.

First clause:

   [Rushing Yards](Values(Players[FullName]))<[Rushing Yards]

First Row of PivotThis gets tricky, so let’s anchor it in an example.  Let’s say we are evaluating this measure for the very first row of our pivot, Edgerrin James:

Player Table

And the FILTER function is going to step through  our table of all player names, at right.  (There are about 4,000 players in my players table).  So, FILTER starts with Rabih Abdullah.

The right side of the clause above, [Rushing Yards], is the [Rushing Yards] measure, evaluated in the context of this source row, Rabih Abdullah.  Well, he totaled 172 yards in his rushing career.

But what about the left side of the clause:

  [Rushing Yards](Values(Players[FullName]))

That uses the context from the *pivot*, not the source table.  the VALUES function returns the list of valid values of the specified column, according to current pivot context.  Since the specified column is on the rows axis of our pivot, it only returns one value in this case, which is Edgerrin James.

Edge has 9,842 rushing yards.  So the clause becomes:

   9842 < 172

Which is of course FALSE.  Rabih’s row gets excluded by the FILTER function.

Wash rinse, repeat.  And then repeat.

FILTER then moves on to the next source row:  Khalid Abdullah.  The pivot context remains the same (Edge James), so the left side of the comparison is still 9842.  Khalid has less than that, so again, excluded.

Well, in my data set, no one has more yards than Edge, he’s the top dog in my data set.  So when FILTER finishes its pass, there are no rows left included.  COUNTROWS then returns 0, the + 1 from the end of the formula gets added, and Edge gets his proper rank of 1.

Second Row of PivotThe measure then moves on to the next pivot context, the second row, which is Curtis Martin:

And then FILTER starts over again, running through the entire Players table again, row by row, starting with our friend Rabih.

Two loops tucked inside each other.  Wow.

The other half of the filter clause

Remember this?

    && Players[FullName]<>Values(Players[FullName])))

That just makes sure we don’t count the player against himself for purposes of rank.  Off the top of my head, I’m not sure that’s 100% necessary.  I’ll have to noodle on that a bit.

OK, let’s see it in action

I add my new measure to the pivot, and I get:

Number Two Tops the List

What the heck?  Is my measure broken?

No, it’s not.  I’ll explain what’s going on in my next post, since this one has run so long already.

Next Football Post:  RANK Measure Continued >>


Do you work for a sports team?

March 5, 2010

I see interesting things in the website logs.  I don’t want to disclose who you are, but I very much would like to help you out.

I think we might be able to arrange something low-cost for you, to evaluate PowerPivot’s potential impact to what you do.

Please drop me a note at robert.c.collie@gmail.com and I will give you more information.