Monday, September 8, 2014

Do you know what your Calculated Fields are?

or, Is my 'Profit' the same as your 'Profit'?

It's helpful to be able to identify what fields are being calculated in Tableau. From an enterprise governance perspective it's essential.

Unfortunately Tableau doesn't provide this information except through manual inspection of the fields' calculations in the calculation dialog. This is a serious deficiency, one that hinders Tableau's adoption in the Enterprise, where senior management is reluctant to let Tableau loose "in the wild" for fear of having dueling metrics without transparency.

Fortunately, there's an easy solution. This post presents a simple Ruby script I whipped up that examines Tableau workbooks and creates a CSV file containing the relevant information about the calculated fields. This CSV file is then usable with Tableau to provide the transparency necessary to tell whether or not two metrics are in fact the same.

Example: the Tableau Sample Workbooks' Calculated Fields

As an illustration of somewhat real world calculated fields, here are those found in the Tableau v8.2 sample workbooks. They range from simple to reasonably complex.

Introducing TTC_CalculatedFields.rb

Here's how it works in the simplest case: you copy/paste the code below into file named oh, say "TTC_CalculatedFields.rb" — it's then a bona fide Ruby script. Then from a command prompt run it in from the directory containing the TBWs you want the calculated fields from.

The usual way to run it is with

"{pathtoRuby}\Ruby" TTC_CalculatedFields.rb

It will then find all of the TWBs in the directory, and all the sub-directories, and record all of their calculated fields.

The usual caveats apply.

  • You need to have Ruby and the nokogiri and open-uri gems installed for it to work. This is very simple and straightforward, and most organizations have someone who's already using Ruby to help if you need it.
  • It only examines TWBs, not packaged workbooks. It's mechanically not difficult to add the functionality but it introduces complexities in handling name collisions and I wanted to keep it simple but useful.
  • There are technical properties of calculated fields that are meaningful to deeper analysis but don't mean much on the surface.
  • Groups are a specialized calculated field, but their internal structure is very different from the other types, making it difficult to add them to the properties/fields of the other classes. I decided not to force them so they show without formulae - this is a fairly common problem in analyzing Tableau workbooks and other hierarchical and network data structures, and Tableau isn't designed to support analysis of data like this.
  • It carries no warranty or guarantees that it'll work.

On the other hand, it should be pretty easy to address any shortcomings it has. Ruby is an elegant language that makes fixing and improving things generally simple and straightforward.


# TTC_CalculatedFields.rb - this Ruby script Copyright 2013, 2014 Christopher Gerrard require 'nokogiri' require 'open-uri' $recNum = 0 $CSVHeader = <<CSVHEADER.gsub("\n",'') Record Number, Workbook, Workbook Dir, Data Source Name, Data Source Caption, Data Source Name (tech), Name, Caption, Name (tech), Data Type, Role, Type, Class, Scope Isolation, Formula Code, Formula, Formula Comments CSVHEADER def init $f = File.open("TTC_CalculatedFields.csv",'w') $f.puts $CSVHeader unless $f.nil? end def parseCalculatedFields twbWithDir twb = File.basename(twbWithDir) twbDir = File.dirname(File.expand_path(twbWithDir)) puts "Found '#{twb}' in #{twbDir}" doc = Nokogiri::XML(open(twb)) calculationNodes = doc.xpath("//workbook/datasources/datasource/column/calculation").to_a calculationNodes.each do |d| #-- Data Source -- dsTechName = d.xpath('../../@name').text dsCaption = d.xpath('../../@caption').text dsName = if dsCaption == '' then dsTechName else dsCaption end #-- Field -- caption, = d.xpath('../@caption').text techName = d.xpath('../@name').text name = if caption == '' then getName(techName) else caption end dataType = d.xpath('../@datatype').text role = d.xpath('../@role').text type = d.xpath('../@type').text #-- Formula -- formulaCode = d.xpath('./@formula').text.gsub(/\r\n/, ' ') formulaLines = d.xpath('./@formula').text.split(/\r\n/) formula = getFormula( formulaLines ) comments = getComments( formulaLines ) fClass = d.xpath('./@class').text scopeIsolation = d.xpath('./@scope-isolation').text #-- emit CSV putCSV(twb, twbDir, dsName, dsCaption, dsTechName, name, caption, techName, dataType, role, type, fClass, scopeIsolation, formulaCode, formula, comments ) end end def getName techName techName.gsub(/^\[/,'').gsub(/\]$/,'') end def getFormula lines formula = '' lines.each do |line| line.strip formula += ' ' + line unless line =~ /[ ]*\/\// end return formula.strip end def getComments lines comments = '' lines.each do |line| line.strip comments += ' ' + line.strip if line.start_with?('//') end return comments.strip end def putCSV(twb, twbDir, dsName, dsCaption, dsTechName, name, caption, techName, dataType, role, type, fClass, scopeIsolation, formulaCode, formula, comments ) $recNum += 1 csvLine = <<CSV.gsub("\n",'') "#{$recNum}", "#{twb.gsub('"','""')}", "#{twbDir.gsub('"','""')}", "#{dsName.gsub('"','""')}", "#{dsCaption.gsub('"','""')}", "#{dsTechName.gsub('"','""')}", "#{name.gsub('"','""')}", "#{caption.gsub('"','""')}", "#{techName.gsub('"','""')}", "#{dataType.gsub('"','""')}", "#{role.gsub('"','""')}", "#{type.gsub('"','""')}", "#{fClass.gsub('"','""')}", "#{scopeIsolation.gsub('"','""')}", "#{formulaCode.gsub('"','""')}", "#{formula.gsub('"','""')}", "#{comments.gsub('"','""')}" CSV $f.puts csvLine unless $f.nil? end init Dir.glob("**/*.twb") {|twb| parseCalculatedFields twb } $f.close unless $f.nil?

An interesting exercise would be to round up the various workbooks that have been published about Table Calculations to see what that population looks like. Maybe something to do during the conference this week.


I hope you find this little utility useful. If so, please leave a comment. If it doesn't work, please leave a comment — I may or may not be able to help (time, other demands upon, etc.). If you extend it in some useful way, please leave a comment.

Or just leave a comment.

Thursday, September 4, 2014

A Better Tableau Server Permissions Resolution Explanation

image/svg+xml http://onlinehelp.tableausoftware.com/current/server/en-us/help.htm#license_permissions_backgrnd.htm When resolving the permissions in place for a Dashboard or Worksheet (both are 'views'), the object used to evaluate the permissions is either the view or the Workbook the view is contained in. So, when when evaluating the Permissions for a View this is the first step: Yes No Was the Workbook published showing sheets as tabs? Workbook View's Once the source of Permissions has been determined, this process resolves whether or not the User is granted the Permission: Also see: use the Permissions of the use the the view is in How Tableau Server Resolves Permissions At Runtime else if the User is in a Group for which the Permission is Deny then Deny else Deny "Not granted by any permission for..." the Permission is configured for the User If as configured then Deny or Allow else if the User is in a Group for which the Permission is Allow then Allow The evaluation here is acrossALL the Groups for which the User is a member,if the Permission is Deny for anyof them the User's Permission is Deny. Only if none of the User's Groups'Permissions is 'Deny' is the checkfor 'Allow' made. If a Permission is set directlyfor a User, it doesn't matter ifthe Permission is also set forany Group that the User is a member of. the Permission has not been configured, so it's Denied and is shown by Tableau Server with this message. What happened to? Roles Roles are prominent in Tableau Serverand Tableau's documentation, but asimplemented and presented by Tableau Serverthey are more of a hinderance to understandinghow Permissions work than they're worth.There are too many problems to document here.Look for an in depth ctitique at Tableau Friction.If the ability to create and manage true custom Roles existed they could be useful. Inherited "Inherited" is an unfortunate name."Not configured here" is better.As shown above, if a Permission is not specificallyconfigured as "Allow" or "Deny", it defaults to "Deny"and there's no need to consider "Inherited".Semantically, "Inherited" is a problem because itindicates a positive situation where one does notnecessarily exist, leading to a cognitive conflict inthe person trying to interpret the actual Permissionstate. Not recognizing this situationis a common source of frustration when trying to puzzle out why a User'saccess and abilities to aDashboard (or worksheet)aren't what they're expectedto be. Yes Permissions Permissions are associated with Projects, Workbooks, Dashboards, Worksheets, and Data Sources. Which Permissions are evaluated when assessing User capabilities? Whenever a User accesses Tableau Server that User's Permissions are evaluated by Tableau Serverto determine which objects the User can see, and what s/he can do with them.Tableau Server does this by evaluating the Permissions configured for the diferent objects vis-a-visthe User, either associated directly to the User or to Group(s) the User is a member of. This seems like a straightforward situation - the object's Permissions should be used, but it's not that simple.For Projects, Workbooks, and Data Sources, their configured Permissions are used.But for Dashboards and Worksheets, it depends... This is not clear in Tableau's documentation: Copyright (c) 2009, 2014 Chris Gerrard http://onlinehelp.tableausoftware.com/current/server/en-us/help.htm#license_permissions_backgrnd.htm When resolving the permissions in place for a Dashboard or Worksheet (both are 'views'), the object used to evaluate the permissions is either the view or the Workbook the view is contained in. So, when when evaluating the Permissions for a View this is the first step: Yes No Was the Workbook published showing sheets as tabs? Workbook View's Once the source of Permissions has been determined, this process resolves whether or not the User is granted the Permission: Also see: use the Permissions of the use the the view is in How Tableau Server Resolves Permissions At Runtime else if the User is in a Group for which the Permission is Deny then Deny else Deny "Not granted by any permission for..." the Permission is configured for the User If as configured then Deny or Allow else if the User is in a Group for which the Permission is Allow then Allow The evaluation here is acrossALL the Groups for which the User is a member,if the Permission is Deny for anyof them the User's Permission is Deny. Only if none of the User's Groups'Permissions is 'Deny' is the checkfor 'Allow' made. If a Permission is set directlyfor a User, it doesn't matter ifthe Permission is also set forany Group that the User is a member of. the Permission has not been configured, so it's Denied and is shown by Tableau Server with this message. What happened to? Roles Roles are prominent in Tableau Serverand Tableau's documentation, but asimplemented and presented by Tableau Serverthey are more of a hinderance to understandinghow Permissions work than they're worth.There are too many problems to document here.Look for an in depth ctitique at Tableau Friction.If the ability to create and manage true custom Roles existed they could be useful. Inherited "Inherited" is an unfortunate name."Not configured here" is better.As shown above, if a Permission is not specificallyconfigured as "Allow" or "Deny", it defaults to "Deny"and there's no need to consider "Inherited".Semantically, "Inherited" is a problem because itindicates a positive situation where one does notnecessarily exist, leading to a cognitive conflict inthe person trying to interpret the actual Permissionstate. Not recognizing this situationis a common source of frustration when trying to puzzle out why a User'saccess and abilities to aDashboard (or worksheet)aren't what they're expectedto be. Yes Permissions Permissions are associated with Projects, Workbooks, Dashboards, Worksheets, and Data Sources. Which Permissions are evaluated when assessing User capabilities? Whenever a User accesses Tableau Server that User's Permissions are evaluated by Tableau Serverto determine which objects the User can see, and what s/he can do with them.Tableau Server does this by evaluating the Permissions configured for the diferent objects vis-a-visthe User, either associated directly to the User or to Group(s) the User is a member of. This seems like a straightforward situation - the object's Permissions should be used, but it's not that simple.For Projects, Workbooks, and Data Sources, their configured Permissions are used.But for Dashboards and Worksheets, it depends... This is not clear in Tableau's documentation: Copyright (c) 2009, 2014 Chris Gerrard

Download as PDF here.

Sunday, August 24, 2014

Tableau Server Role Permissions Revealed

Please allow us to present, for your entertainment and edification, the one, the only, the Tableau Server Role Permissions:

One of the tricky parts of working with Tableau Server is getting the Permissions straight. Tableau's Roles are part of the mix, and can be useful in some circumstances (the whens and whereofs are themselves a topic begging for exploration and explanation, but that's for another time).

Understanding how different Roles' Permissions are configured can be difficult—like many parts of Tableau they're described individually, but with no consolidated documentation that brings them all together so that they can be seen at a glance and compared with one another. Until now.

Tableau Public-published Workbook

This workbook brings the Roles, their Permissions, and the Permissions' objects into a single view, helpful for achieving the holistic view necessary for understanding and employing them when it makes sense to. Comments and observations are below.

Screen Shots Tableau Server's presentation of the Roles' permissions.

Observations and Comments

  • None of the Roles' Permissions are ever set to Deny.
  • It's not clear from Tableau's documentation but unless a Permission is explicitly Allowed for an object it is effectively Denied - this makes using positive Allow-only Permissioning to be an effective strategy. (I'll be writing more on this)
  • Using Roles is reasonable as long as the Role's Permissions matches the set you need for the object, otherwise they need to be masked out and this introduces complexity that can be more confusing than if the Role wasn't used in the first place.
  • The name "Custom" for the 'Role' that's really 'Not one of the preconfigured ones" is unfortunate, in a number of different ways. It at least implies that there is -A- Custom role, when in fact what needs to be signaled is that there's a possibly unique blend of Permission configurations in effect for this User/Group for this object.
  • The lack of Role creation and management is a huge deficiency. It would be far, far easier, cleaner, and faster to configure Tableau Server to specific requirements if it were possible to create true custom Roles and apply them when and where they're needed. It would also make the whole system much more transparent—Tableau Server Admins would have a much easier time of understanding what Permissions are actually in effect, making it that much easier to support the business stakeholders who can't see what they're supposed to, or can see something they shouldn't.
    For example, it would be very nice to have a Role for viewing that allowed filtering but not the ability to see underlying data.
  • "Inherited" is a singularly bad name for what really is "Not Configured Here". One of the problems to using "Inherited" is that it means something to the great majority of people who see it very different from its meaning in Tableau Server, way is itself poorly explained and difficult to puzzle out.

I hope this is helpful. There's plenty more to explore and explain about Permissions, and I hope to one day get a good, concise explanation out into the world.

References

Tuesday, July 22, 2014

Perplexed by Permissions? Puzzled, Perhaps?

Have you ever tried to piece together all of the parts that affect what a Tableau Server user can and cannot do?

Have you ever tried to explain it to someone else, other than "It's complicated, complex, confusing, confounding, and mysterious"?

I feel your pain.

After pondering it yet again as I'm trying to figure out how to transfer this arcane knowledge to a client, I finally threw in the towel and sat down to try and map it out.

Here's the result (PDF online).

It's a decent first stab, I think, but I'll be keeping it up as I think of what to add to it, and how.

I'll appreciate any input anyone has, particularly things I've got wrong, followed by things I've missed and suggestions for additional information and presentation improvements.

Until then, happy Permissioning.