Highlight a data point on all graphs

Using the code below, you will be able to Shift-click on specified graph windows to have the data point on the trace under the mouse pointer (if there is one) be highlighted with a tag on all other graphs on which that same wave is displayed. This currently will probably not work on traces displayed using XY pairs, and may not work on images or more complicated graphs.

Usage: You need to set a named window hook on all graph windows that you want to be able to click on a data point and have it highlighted in all other graph windows. To do this, from the Igor command line execute the following code (replacing Graph0 with the name of the graph:
SetWindow Graph0 hook(HighlightPoint)=HighlightDataPoint_Hook


Here's some quick code to give an example. Paste it into the command line and execute it. Then Shift-click on a point of the trace in Graph10 and see that in both Graph10 and Graph11 a tag is placed at that data point. Shift-click again to remove the tag in both windows.

Make testwave1 = p, testwave2 = sin(x)
Display/N=Graph10 testwave1, testwave2
Display/N=Graph11 testwave1, testwave2
AutoPositionWindow/R=Graph10 Graph11
SetWindow Graph10 hook(HighlightPoint)=HighlightDataPoint_Hook




static Constant HIGHLIGHT_CLICK_MODIFIERS = 2       // Shift key is down

//**
// Window hook function that responds to clicking on a graph
// and then causes a data point to be highlighted.
// @param s
//  An instance of the WMWinHookStruct structure.
// @return
//  A non-zero value if this function handled the event or zero
//  if it did not.
//*
Function HighlightDataPoint_Hook(s)
    STRUCT WMWinHookStruct &s
    Variable hookResult
   
    // Only handle the event if the proper modifier key(s) were pressed.
    if (s.eventCode == 5 && s.eventMod == HIGHLIGHT_CLICK_MODIFIERS)
        // Determine the trace and wave that were clicked on and
        // the point index where the user clicked.
        String hitInfo = TraceFromPixel(s.mouseLoc.h, s.mouseLoc.v, "WINDOW:" + s.winName)
        if (strlen(hitInfo) > 0)
            String traceName = StringByKey("TRACE", hitInfo, ":", ";")
            Variable hitPoint = NumberByKey("HITPOINT", hitInfo, ":", ";")
            if (strlen(traceName) > 0 && numtype(hitPoint) == 0)
                WAVE/Z targetWave = TraceNameToWaveRef(s.winName, traceName)
                if (WaveExists(targetWave))
                    HighlightDataPoint(targetWave, hitPoint, s.winName)
                    hookResult = 1
                endif
            endif
        endif
    endif

    return hookResult
End


//**
// Main utility function that is called to highlight (or remove the highlight from) a
// data point on a wave in a number of graph windows.
//
// @param targetWave
//  A wave reference to the wave the user clicked on.
// @param pointIndex
//  A variable containing the point value at which
//  the tag should be added or removed.
// @param activeGraphName
//  A string containing the name of the graph on which
//  the user clicked.  This graph will always have the tag
//  toggled on or off.
// @param targetGraphList
//  [OPTIONAL]  A string containing a semicolon separated list
//  of graphs which should have a tag added or removed if the
//  specified wave is displayed on the graph.  If this parameter
//  is not specified all graph windows will be acted upon.
// *
Function HighlightDataPoint(targetWave, pointIndex, activeGraphName, [targetGraphList])
    WAVE targetWave
    Variable pointIndex
    String activeGraphName
    String targetGraphList
   
    // If the parameter targetGraphList is not specified, then
    // call a function to get target windows.
    if (ParamIsDefault(targetGraphList))
        targetGraphList = GetTargetGraphList()
    endif
   
    // Make sure that the active graph (the one the user used to
    // trigger this function being called) is included in the list
    // of graphs on which the highlighting of the point should be
    // toggled.
    if (WhichListItem(activeGraphName, targetGraphList, ";") < 0)
        targetGraphList = AddListItem(activeGraphName, targetGraphList, ";", inf)
    endif
   
    Variable numGraphs = ItemsInList(targetGraphList, ";")
    Variable n, traceIndex, numTraces
    String currentGraphName
    String thisWaveFullName
    String targetWaveFullName
    String traceList, currentTraceName
    For (n=0; n<numGraphs; n+=1)
        currentGraphName = StringFromList(n, targetGraphList, ";")
       
        // Make sure this is actually a graph.
        If (WinType(currentGraphName) != 1)
            continue
        endif
       
        // Iterate through the traces on the graph to find
        // if any of them are based on targetWave and if so then
        // append or remove tags on the graph at the specified point.
        // NOTE:  This won't work as expected for traces
        // that are XY pairs.
        traceList = TraceNameList(currentGraphName, ";", 5)     // Include normal graph traces and omit hidden traces
        numTraces = ItemsInList(traceList, ";")
        targetWaveFullName = GetWavesDataFolder(targetWave, 2)
        thisWaveFullName = ""
        traceIndex = 0
        For (traceIndex = 0; traceIndex < numTraces; traceIndex +=1)
            currentTraceName = StringFromList(traceIndex, traceList, ";")
            WAVE/Z thisWave = TraceNameToWaveRef(currentGraphName, currentTraceName)

            // If thisWave is NULL for any reason, skip it.
            if (!WaveExists(thisWave))
                continue
            endif
           
            // Determine if targetWave and thisWave are the same wave.
            thisWaveFullName = GetWavesDataFolder(thisWave, 2)
            if (cmpstr(thisWaveFullName, targetWaveFullName) == 0)
                // Toggle the presence of tags for the given point on the specified graphs.
                RemoveOrAddTagToTrace(currentGraphName, currentTraceName, pointIndex)
            endif
        EndFor
    EndFor
End

//**
// Toggles the presence of a tag on the specified trace at the specified point.
//
// @param graphName
//  A string containing the full name of the graph.
// @param traceName
//  A string containing the name of the trace.
// @param pointIndex
//  A variable containing the point value at which
//  the tag should be added or removed.
//
// @return
//  1 if a tag was removed, 0 if it was added, or NaN if there was
//  an error, such as an invalid graph or trace name.
//*
Function RemoveOrAddTagToTrace(graphName, traceName, pointIndex)
    String graphName
    String traceName
    Variable pointIndex
   
    // Make sure graph exists.
    if (WinType(graphName) != 1)
        return NaN
    endif
   
    // Make sure trace is on graph
    if (strlen(TraceInfo(graphName, traceName, 0)) < 1)
        return NaN
    endif
   
    // So that we don't delete an annotation that has been placed
    // on the graph outside of this function, filter the list
    // of all annotations so we only process ones
    // with names beginning with "highlight_tag_"
    String listOfAnnotations = AnnotationList(graphName)
    listOfAnnotations = ListMatch(listOfAnnotations, "highlight_tag_*", ";")

    Variable numAnnotations = ItemsInList(listOfAnnotations, ";")
    String currentAnnotationName, info
    Variable n, attachedPoint
    Variable removedATag

    // Determine if there is already a tag on the trace at the
    // specified point.
    For (n=0; n<numAnnotations; n+=1)
        currentAnnotationName = StringFromList(n, listOfAnnotations, ";")
        info = AnnotationInfo(graphName, currentAnnotationName)
        if (strlen(info) > 0)
            // If this isn't a tag then ignore it.
            if (cmpstr(StringByKey("TYPE", info, ":", ";"), "Tag") == 0)
                // If this tag isn't attached to traceName, ignore it.
                if (cmpstr(StringByKey("YWAVE", info, ":", ";"), traceName) == 0)
                    // If the tag isn't attached to point pointIndex, ignore it.
                    attachedPoint = NumberByKey("ATTACHX", info, ":", ";")
                    if (numtype(attachedPoint) == 0 && attachedPoint == pointIndex)
                        // Tag is already attached to the given point on the given
                        // graph and trace, so remove it.
                        Tag/W=$(graphName)/N=$(currentAnnotationName)/K
                        removedATag = 1
                    endif
                endif
            endif
        endif
    EndFor
   
    // If we didn't just remove one or more tags, then we need to add a tag
    // to the specified trace.  If we did remove a tag, then just return.
    if (!removedATag)
        // Add a tag.
        String newTagName = UniqueName("highlight_tag_", 14, 0, graphName)
        Tag/W=$(graphName)/C/N=$(newTagName)/F=0/B=1/H={0,2,10}/X=0.00/Y=0.00/L=0/TL=0 $(traceName), pointIndex, "\\W519"
    endif
    return removedATag
End

//**
// Get a list of target windows.
//
// @TODO:  This could be expanded so that
// child windows were also returned.  As is, subwindows
// will not be affected.
//
// @return
// A string with a semicolon separated list of graph
// window names.
//*
Function/S GetTargetGraphList()
    String targetGraphList = ""
   
    targetGraphList = WinList("*", ";", "WIN:1")        // All graph windows.
    return targetGraphList
End

Forum

Support

Gallery

Igor Pro 8

Learn More

Igor XOP Toolkit

Learn More

Igor NIDAQ Tools MX

Learn More