Using D3 Tooltips

March 9, 2015 Leave a comment

Tooltips can be extremely useful for displaying additional information NOT currently being rendered in the core D3  visualization, be it a chart, graph, map, etc..  Tooltips can also enhance the overall aesthetic value of the visualization through the implementation of CSS and D3 transitions.  Let’s face it…D3 isn’t just about displaying data…it’s about “visualizing” it in such a way that captivates the user and creates a “wow thats cool” experience.

Before we get started let me first admit that at this point I’m still a newbie to D3 (only 4 months in) and much of this tutorial has been the result of studying the works of Mike Bostock and the following sites\tutorials\forums

I’m a firm believer that the best way to convey a new concept is to first demo a real world example and then break that down into the functional components.   Interestingly enough this tutorial began as an assist to a post made by a fellow techie on Google’s D3 Groups.  He originally requested help on several areas of a bar graph and one that caught my attention was: “displaying the name column on the tooltip”.  After reviewing his code I was quickly able to edit and provide a working solution, which you can view on CODEPEN...perhaps I’m not such a newbie after all..:}

tooltips-bargraph

Although the solution I provided worked to add the tooltip another fellow D3 enthusiast and more senior coder, Nick,  posted his solution as well on Codepen, which fulfilled all the users requirements, and then some. His code was also more structured and included additional code snippets for using RawGit, CSS styling\animation, as well as a different technique for positioning a tooltip.

So let’s start by reviewing the code I posted and then we’ll incorporate Nick’s tooltip code in a future post.

Tooltip Implementation

The most obvious place to start is:

  • Adding the tooltip
  • MOUSEOVER event to display tooltip

The code used to add the tooltip

var tooltip = d3.select('body').append('div')
  .style('position','absolute')
  .style('padding','0 10px')
  .style('opacity',0)
  .attr('class','tooltip')

Let’s break this down:

Position: Absolute – The position of the tooltip will be relative to the where the mouse pointer is located when the mouseover event is initiated.

Padding: 0 10px – This will pad the the div 0 px top\bottom and 10px left\right.

Opacity: 0 – This makes the tooltip invisible and provides a starting point for the transition() method when the mouseover event it initiated.

Class: tooltip – This adds a class to the div which can be used to apply additional CSS styling.

Now that we have a div in place let’s add the mouseover\mouseout events.

var rect = myChart
   .on('mouseover', function(d) {
      tooltip.transition()
        .style('opacity', .9)
        .style('background', 'lightsteelblue')
      tooltip.html( d.name + ": " + d.totalp )
        .style('left',(d3.event.pageX - 35) + 'px')
        .style('top', (d3.event.pageY - 30) + 'px')
   })
   .on('mouseout', function(d) {
      tooltip.transition()
        .style('opacity', 0)
})

Let’s break this down:

.on() – This is a method used to execute an eventlistener and requires the event to listen for, in this case both “mouseover “and “mouseout” and a callback function which executes a block of code, in this case the tooltip.transition() and tooltip.html().

tooltip.transition() – This calls the tooltip class, which was an attribute added to the div when it was created, and then executes the transition() method which changes an elements attributes, in this case the opacity will transition from 0 to .9.   I’ve also added a background color of lightsteelblue.  Transition is also used on the mouseout event to set the opacity back to 0, thereby making the tooltip seemingly disappear.

tooltip.html – This adds the text we want to display in the tooltip as well as where to position the tooltip.  The d3.event.pageX and d3.event.pageY are used as the coordinates for positioning the tooltip based on the mouse location.  In this case were looking to enter the tooltip above the mouse by moving it -35px to the left and -30px above.

So this lesson provides the basics for adding a tooltip.  In the next blog article I will discuss additional options on positioning the tooltip as I’m too crazy about displaying the data within the bar itself.   Although this technique works fine for a line chart or world map with points of interest it’s not the best implementation for a bar chart.  I’ll also review orgainizing the code a bit more by moving the mouseover\mouseout callback functions into their own named function.

Categories: Uncategorized Tags:

Powershell: Importing Items into a Sharepoint List

March 7, 2012 1 comment

I was teaching a Windows Server 2003 to 2008 upgrade class onsite recently for a client and it included several Powershell examples on performing such tasks as installing a role\feature or managing AD users\groups.   While on break I got to speaking with one of the tech’s and asked if he was currently utilizing Powershell to automate common day to day tasks.  His response was not what I expected as he made the statement that he couldn’t see any use for Powershell.   My initial reaction was suprise as I thought any decent tech would want to embrace such a robust and versitile automation technology, especially one that provides a standard platform for managing all things Microsoft.   Read more…

Powershell: Create Custom MAC\IP Table

February 20, 2012 Leave a comment

Local MAC Discovery

There are times where I need to determine the MAC address of not only my PC but also the other PC’s on the local network segment.  There are a few different ways to determine the local PC”s MAC address(s) using Powershell:

    getmac           
    (ipconfig /all) -match " ([0-9A-Z]{2}[-]){5}[0-9A-Z]{2}$"           
    (ipconfig /all) | Select-String " ([0-9A-Z]{2}[-]){5}[0-9A-Z]{2}$"           
    GWMI Win32_NetworkAdapter -f "MacAddress like '%:%'" |
          Select -expand MacAddress

Although they all display the MAC address information for all network adapters the output is done so differently for each command, except for -Match and Select-String as they produce the same output.  Read more…

Categories: Powershell Tags:

Powershell: Retrieving AD FSMO Role Holders

February 18, 2012 2 comments

I was recently asked to create a script to display the current FSMO Role holders in an Active Directory domain.  There are 5 FSMO roles and the first domain controller in the forest root domain holds them all by default.  Of the 5 roles, 2 are per forest and 3 per domain.  These roles can be transfered or seized during the lifetime of the AD Domain and it’s important to know what DC’s hold which roles, especially when doing maintenance.

Powershell isn’t the only way to retrieve the role holders and both Netdom and NTDSUtil provide the same info, with Netdom being the easier of the two commands to use.  Here is an example of using Netdom:

Read more…

Categories: Powershell Tags:

Powershell: Adding Directories to Path Statement

February 10, 2012 1 comment

Adding directories to the Path statement is a rarity for most techs these days but on occasion, such as configuring Sharpeoint 2010 to use an Adobe IFilter or my own desire to make it easier to run powershell scripts, updating the Path statement must be done.  Either way it’s just the reason I was looking for to write another powershell script.🙂

I always approach writing powershell code with the intention of making it resuable, mostly in the form of a function.  The function I’ve created this time is called  AddTo-SystemPath

I begin by defining parameters.  Since there may be a need to add several directories to the path statement I’ve cast the $PathToAdd variable  as an array.

  Param(
     [array]$PathToAdd
 )

A Foreach loop will then be run against the $PathToAdd variable .  It also seemed like best practice  to make sure that the Path statement didn’t already contain the directory(s) in the $PathToAdd variable so comparison is used inside an If\Else statement. The  $VerifiedPathsToAdd variable is then populated with the directories to add.

 Foreach($Path in $PathToAdd) {            

    #Verify if the Path statement already contains the folder
    if($env:Path -like "*$Path*") {
       Write-Host "$Path already exists in Path statement" }
    else { $VerifiedPathsToAdd += ";$Path"
       Write-Host "`$VerifiedPathsToAdd updated to contain: $Path"}

I now want to make sure that $VerifiedPathsToAdd contains something, and if so update the Path statement  using the [Environment] class.

The code below containing  [Environment]::SetEnvironmentVariable() is too long to display as one line so I’ve divided it into the class and method overloads.

[Environment]::SetEnvironmentVariable
("Path",$env:Path + $VerifiedPathsToAdd,"Process")

It’s possible to update the Path statement using just the $Env:Path variable, however it’s not persistent and any added values will be lost when the PS session closes. An example of using this non-persistent method is:

$ENV:Path = $ENV:Path + ";$Path"

The complete If statement containing the persistent method is:

  #Verify that there is something in $VerifiedPathsToAdd to update the Path statement
  if($VerifiedPathsToAdd -ne $null) {
    Write-Host "`$VerifiedPathsToAdd contains: $verifiedPathsToAdd"
    Write-Host "Adding $Path to Path statement now..."
  [Environment]::SetEnvironmentVariable("Path",$env:Path + $VerifiedPathsToAdd,"Process")
   }#End If

The complete Function is below:

Function AddTo-SystemPath {            

 Param(
  [array]$PathToAdd
  )
 $VerifiedPathsToAdd = $Null
 Foreach($Path in $PathToAdd) {            

  if($env:Path -like "*$Path*") {
   Write-Host "Currnet item in path is: $Path"
   Write-Host "$Path already exists in Path statement" }
   else { $VerifiedPathsToAdd += ";$Path"
    Write-Host "`$VerifiedPathsToAdd updated to contain: $Path"}            

  if($VerifiedPathsToAdd -ne $null) {
   Write-Host "`$VerifiedPathsToAdd contains: $verifiedPathsToAdd"
   Write-Host "Adding $Path to Path statement now..."
   [Environment]::SetEnvironmentVariable("Path",$env:Path + $VerifiedPathsToAdd,"Process")            

   }
  }
 }
Categories: Powershell Tags:

Powershell: Importing Hyper-V VM’s

February 2, 2012 5 comments

In my previous post Creating Hyper-V Symolic Links using Powershell I created a small but useful function called Create-SymbolicLinks which was used to execute one or more .bat files that created symbolic links to base or middle tier VHD’s as part of the initial classroom VM setup.  Once this was completed the next step was to import the VM’s and of course what better way to automate this then to use Powershell.

The first task at hand is to download and import the Hyper-V module from Codeplex.  There are 2 versions of this module available to download, with the latest version being R2 SP1.  Once downloaded I then place it into the directory where I will be running the script\function so that it can be copied to the appropriate Modules directory on the server.   Both the module path and name are defined in the Param statement as follows, along with the path to the VM’s.

 Param (
  $ModulePath = ($env:psmodulePath -split ";")[1],
  $ModuleName = "HyperV",
  $path = "C:\Program Files\Microsoft Learning\6419\Drives\"
  )

The code to copy the HyperV module and import it is:

 #Copy the HyperV module if it doesn't already exist
 if(!((Dir $ModulePath) -match $ModuleName)) {
  Copy-Item .\$ModuleName $ModulePath -Recurse
  }
 #Import the HyperV module if not already imported
 if(!(Get-Module | ?{$_.Name -like $ModuleName})) {
   Import-Module $ModuleName
  }

Now the real work begins.  I need to determine what VM’s have already imported into Hyper-V to make sure we don’t 1) do more work then is necessary and 2) don’t try overwriting any previously imported VMs.  Doing this involves using Get-VM and extracting just he name property ( or in this case the ElementName property) and putting those results into an array called $ActiveVMs.
In order to get a list of the VM’s I need to import I run a Get-ChildItem $Path and extract just the Name property and put the results into an array called $VMsToImport.

 #Create array to contain active VM's
 $ActiveVMs = Get-VM | Foreach{$_.ElementName}
 #Create array to contain VM's to be imported
 $VMsToImport = (Get-ChildItem $path) | Foreach{ $_.Name }

Now comes the interesting part.  How to do a comparision of the two arrays and determine if any VM names overlap.  This seemed like a perfect opportunity to use a regular expression.  I remember reading an article on the Scripting Guys called “Speed Up Array Comparisions in Powershell with a Runtime Regex” where the author discussed the benefits of using the -Match operator with a regular expression  instead of the -Contains comparison operator.  Needless to say using a regular expression was way faster…10x faster and since Powershell is all about automation and efficiency , creating a regex seems like the way to go.

 [regex]$ActiveVMs_Regex = '(?i)^('+(($ActiveVMs |
        Foreach {[regex]::Escape($_)})-join "|" )+')$'

The only thing left now was to run the -Match comparison and import the VM’s  using Import-VM.   I also needed to use Start-Sleep 5 because during my initial tests ( and there were many of them ) some VM’s weren’t imported.  It was random and not consistent but after having the script pause before each import provided just the rate of success I was looking for.   Powershell you rock!!!

            
 #Import the VMs            
 $VMsToImport -notmatch $ActiveVMs_Regex |             
        Foreach{ Import-VM (Join-Path $path $_ )             
        Start-Sleep 5            
  }

Here is the complete function..

Function Import-VMs {            

 Param (
  $ModulePath = ($env:psmodulePath -split ";")[1],
  $ModuleName = "HyperV",
  $path = "C:\Program Files\Microsoft Learning\6419\Drives\"
     )            
 #Copy the HyperV module if it doesn't already exist
 if(!((Dir $ModulePath) -match $ModuleName)) {
  Copy-Item .\$ModuleName $ModulePath -Recurse
     }             

 #Import the HyperV module if not already imported
 if(!(Get-Module | Where{$_.Name -like $ModuleName})) {
   Import-Module $ModuleName
     }            

 #Create array to contain active VM's
 $ActiveVMs = Get-VM | Foreach{$_.ElementName}            

 #Create array to contain VM's to be imported
 $VMsToImport = ( Get-ChildItem $path ) | Foreach{$_.Name}
 [regex]$ActiveVMs_Regex = '(?i)^('+(($ActiveVMs |
        Foreach {[regex]::Escape($_)})-join "|" )+')$'            

 #Import the VMs            
 $VMsToImport -notmatch $ActiveVMs_Regex |             
        Foreach{ Import-VM ( Join-Path $path $_ )             
        Start-Sleep 5            
     }
}#End Function
Categories: Powershell Tags: ,

Backing Up Event Logs using Powershell

January 31, 2012 5 comments

I was recently asked to create a script that would backup certain event logs ( Application & Security ) to it’s native .evt format and then clear all events from the corresponding logs once complete.  This seemed simple enough although I didn’t recall seeing any parameters in either Get-WinEvent or any of the *-Eventlog cmdlets that provided this functionality.  Then I remembered that when something can’t be done using object specific cmdlet the next possible option is to explore the Win32_* classess.   So I used Get-WMIObject to query possible Win32_* classes that referenced Event Log.

Get-WMIObject Win32_*event* -List

The query produced the following results:

So the question now was which Win32 class to choose from.   I  narrowed it down to the Win32_NTEvent* classes and after some further examination determined that Win32_NTEventLogFile had a method called BackupEventLog.  I was able to make this determination by using Get-Member on the class.

Get-WMIObject Win32_NTEventLogFile | Get-Member

This query displayed all Properties and Methods of the Event Logs.  I’ve filtered the results to display only the first few Methods

The BackupEventLogFile method accepts one overload of System.String type which will be the name of the backup log file with an .evt extension.  The files were going to be backed up daily and then the Event Logs cleared of all events  so I needed to make sure the backup log files had unique names and decided to include the current date in the event log name.  I also needed to use a Foreach loop so as to run the code on several Event Logs in sequence.   I also included the following parameters to make the function more versitile:

 Param(
      $Computername = $ENV:COMPUTERNAME,
      [array]$EventLogs = @("application","security"),
      $BackupFolder = "C:\BackupEventLogs\"
      )

Logic was also added to create the $BackupFolder if it didn’t exist.

If(!( Test-Path $BackupFolder )) { New-Item $BackupFolder -Type Directory }

I called the function Clear-EventLogs and below is the complete script.

Function Clear-Eventlogs {            

 Param(
  $Computername = $ENV:COMPUTERNAME,
  [array]$EventLogs = @("application","security"),
  $BackupFolder = "C:\BackupEventLogs\"
  )            

 Foreach ( $i in $EventLogs ) {
 If(!( Test-Path $BackupFolder )) { New-Item $BackupFolder -Type Directory }
 $eventlog="c:\BackupEventLogs\$i" + (Get-Date).tostring("yyyyMMdd") + ".evt"
 (get-wmiobject win32_nteventlogfile -ComputerName $computername |
  Where {$_.logfilename -eq "$i"}).backupeventlog($eventlog)            

 Clear-EventLog -LogName $i            

 }# end Foreach            

}#end function            

Clear-Eventlogs

The results of running the script are the following log files:

Categories: Powershell Tags: ,