Calibration bar within subwindow

Hello,
I need to plot calibration bars in my electrophys graphs instead of regular axis with multiple subwindows. I have seen that there is a macro that can do it but this macro can't reach the subwindows.
When I use "Calibrator()" the macro window is opened but I am not able to interact with it.
When I try to trigger the function of interest from macro and gives it the name of my subwindows "WMNewCalibratorInGraph("subwin")", there is no effect.
So it will be wonderful if somebody know how to do it )))))

Function EasyGraph()
   
    String CDF, win, subwin
    CDF=GetDataFolder(1)
    Display/K=1/W=(0,0,600, 500) as "test"
    Win=S_name

    //Set the subwindows

    Variable i, j, Rows = 1, Columns = 2
   
    for (i=0; i<Rows; i+=1)
        for (j=0; j<Columns; j+=1)
            Display/HOST=$Win/W=(j/Columns,i/Rows, (j+1)/Columns, (i+1)/Rows)
            MoveSubwindow fnum=(j/Columns,((i/Rows)*0.97)+0.03, (j+1)/Columns, (((i+1)/Rows)*0.97)+0.03)            //CN move all the subwindow to allow the title in the beginning of the page
        endfor
    endfor
   
    SetActiveSubwindow $StringFromList(0, Win, "#")

    // Subwindow are set

    Subwin=Win+"#G"+num2str(0)
    appendToGraph/W=$subwin root:DA119_RPip_ch2_1000 //Name of a specific wave
    ModifyGraph/W=$Subwin nticks=0,noLabel=2,axThick=0
   
    //WMNewCalibratorInGraph("subwin")      //Test, idea is to put the basic calibration bar
   
    Subwin=Win+"#G"+num2str(1)
    appendToGraph/W=$subwin root:DA119_RPip_ch3_1000
    ModifyGraph/W=$Subwin nticks=0,noLabel=2,axThick=0
   
    Calibrator() // Idea is to open the calibrator menu and then put it by hand. The calibrator menu is open but I am not able to interact with it

End
<pre><code class="language-igor">
I think about drawing it manually...
but I still have problem with GetAxis and AxisInfo when I use subwindow... thanks if you have any advice regarding these command with subwindow
Here are some interesting tests I have just tried, using the WM utilities
#include<Append Calibrator>
#include<InsertSubwindowInGraph>

I created a graph and added a calibrator to it. Then I used the second utility above to embed this in another graph. The subgraph was successfully embedded, but the Calibrator drawing DID NOT appear in the embedded subgraph.

An awkward solution is to use the Calbrator in the parent graph, and drag it over your subgraph. The disadvantage to this is having to get the correct Calibrator scale factors (which follow the parent graph). One way to do this is to create new free axes so that the embedded subgraph's axes match smaller regions of the parent graph free axes. Apply the free axes scaling when using the calibrator GUI window. You can then hide the free axes using zero thickness and turning off labels.


After further thought, it seems to me that the most practical solution is to replace the L-shaped Calibrator drawing by a pair of 2-point y vs x waves, sharing a common corner. It is easy to adjust all the trace properties, and you can label them either with Annotations or their own axis-type labels (new/free or otherwise). Most important the Calbrator-type wave pairs can be more easily copied or created in subwindow graphs, and will automatically change with subwindow sizing.
Ok, thank for the reply.
I have used the include, so the problem is really to have access to the graph within the subwindow. As it was impossible to use function such as getAxis and AxeInfo, I have use the traces and done it manually with:

            WaveStats/M=1/Q $"root:"    +Trace 
            variable leftAxis = (V_Max - V_Min)/8      
   

            variable NiceleftAxis = CN_WMCalibratorNiceNumber(leftAxis)

            string Duration=StringByKey("DURATION0", note($"root:"+Trace),"#","\r") //Attention, this parameter is not correcly set for some traces such as DA119_TestAmpl_ch*_10*
            variable DurationBar=Str2Num(Duration)/8   
            variable NiceDurationBar = CN_WMCalibratorNiceNumber(DurationBar)
            string TimeUnits = num2str(NiceDurationBar)+ " s", CurrentOrVoltage
   
            If(NiceDurationBar < 0.5)
                TimeUnits = num2str(NiceDurationBar*10^3) +" ms"
            endif
   
            variable ValueToPrint
            if(mod(Str2Num(Channel),2)==0) //Attention, for a few traces such as RPip, the units are inverted with the channels
   
                CurrentOrVoltage = num2str(NiceleftAxis)+" V"
                if(leftAxis < 0.1*10^-9)
                    ValueToPrint = NiceleftAxis*10^12
                    CurrentOrVoltage =num2str(ValueToPrint)+ " pV"
                    DoAlert, 0, "Attention, check units for trace: "+ Trace +", they may be inverted according to the channel"
                elseif(leftAxis < 0.1*10^-6)
                    ValueToPrint =NiceleftAxis*10^9
                    CurrentOrVoltage = num2str(ValueToPrint) + " nV"
                elseif(leftAxis < 0.1)
                    ValueToPrint =NiceleftAxis*10^3
                    CurrentOrVoltage = num2str(ValueToPrint) + " mV"
                endif
            else
                CurrentOrVoltage = num2str(NiceleftAxis)+ " A"
                if(leftAxis < 0.1*10^-9)
                    ValueToPrint =NiceleftAxis*10^12
                    CurrentOrVoltage = num2str(ValueToPrint) + " pA"
                elseif(leftAxis < 0.1*10^-6)
                    ValueToPrint =NiceleftAxis*10^9
                    CurrentOrVoltage = num2str(ValueToPrint) + "nA"
                elseif(leftAxis < 0.1)
                    ValueToPrint =NiceleftAxis*10^3
                    CurrentOrVoltage = num2str(ValueToPrint) + "mA"
                    DoAlert, 0, "Attention, check units for trace: "+ Trace +", they may be inverted according to the channel"
                else
                    DoAlert, 0, "Attention, check units for trace: "+ Trace +", they may be inverted according to the channel"
                endif
            endif

   

            ShowTools/A
            SetDrawLayer UserFront
            //For the time
            SetDrawEnv/W=$subwin xcoord= bottom,ycoord= left
            DrawLine/W=$subwin -DurationBar/8, V_min-leftAxis/12, NiceDurationBar-DurationBar/8, V_min-leftAxis/12
            SetDrawEnv/W=$subwin xcoord= bottom,ycoord= left, fsize = 8
            DrawText/W=$subwin -DurationBar/8,V_min-leftAxis/3, TimeUnits //1.07 with ycoord=prel
   
            //For the volt/current
            SetDrawEnv/W=$subwin xcoord= bottom,ycoord= left
            DrawLine/W=$subwin -DurationBar/8, V_Min-leftAxis/12, -DurationBar/8, V_min + NiceleftAxis-leftAxis/12
            SetDrawEnv/W=$subwin xcoord= bottom,ycoord= left, fsize = 8
            if(ValueToPrint > 99)
                DrawText/W=$subwin -DurationBar/1.8, V_Min +NiceleftAxis/5, CurrentOrVoltage //-0.05 with xcoord=prel
            else
                DrawText/W=$subwin -DurationBar/2, V_Min +NiceleftAxis/5, CurrentOrVoltage //-0.045 with xcoord=prel
            endif
   

            ModifyGraph/W=$Subwin nticks=0,noLabel=2,axThick=0
The AxisInfo function takes as the first parameter a string containing the name of the graph. This can be a path to a subwindow. So say you have a graph (Graph0) with a subgraph (G0) and you want info on the Left axis. This command:
String info = AxisInfo("Graph0#G0", "Left")
will deposit the info string into the string variable "info".

Most functions and operations that get information or manipulate graphs have a way to specify a subwindow.

John Weeks
WaveMetrics, Inc.
support@wavemetrics.com
Igor 6.38 will have revised Axis Utilities.ipf and Append Calibrator.ipf procedures that work with subwindows.

For your enjoyment, I've attached the procedure files and a screen shot showing the revised panel at work.

The panel now adds the calibrator to the active sub window or active top-level graph.

Replace your existing Axis Utilities.ipf and Append Calibrator.ipf files in the WaveMetrics Procedure folder with the attached files.

Let me know if you find them useful or if they have problems.

--Jim Prouty
Software Engineer, WaveMetrics, Inc.
Hello,
It works perfectly, thanks a lot Jim!!!
I used Execute in the loop that goes through all the subwindow to put my scale bar within them:
                string cmd
                sprintf cmd, "SetActiveSubwindow %s", SubWin
                Execute/P/Q cmd
                Execute/P/Q "WMCalibratorPresetButtonProc(\"xNice\")"
                Execute/P/Q "WMCalibratorPresetButtonProc(\"yNice\")"
                Execute/P/Q "WMCalibratorCreateButtonProc(\"create\")"
                ModifyGraph/W=$Subwin nticks=0,noLabel=2,axThick=0 //Finally we can remove the basic axis
Oh I was wondering if there is an easy and automatic way to set up the position of the scale bar. Because it is on the graph and I want it on the bottom-left corner.

But this function is great, only the position of the scale bar is a bit tricky because for multiple graph, if I move it manually, even by double clicking on it, I can't set up the exact position.
Best
Chris
chrisNell wrote:
Oh I was wondering if there is an easy and automatic way to set up the position of the scale bar. Because it is on the graph and I want it on the bottom-left corner.

But this function is great, only the position of the scale bar is a bit tricky because for multiple graph, if I move it manually, even by double clicking on it, I can't set up the exact position.
Best
Chris


The attached revision of Append Calibrator.ipf has controls to position the calibrator, and WMNewCalibrator has optional parameters, too:

Function WMNewCalibrator(graphName, xaxis,yaxis,dx,dy,orientation,numbers,digits,penSize,red,green,blue[,location,horizInset,vertInset])


--Jim Prouty
Software Engineer, WaveMetrics, Inc.
It does exactly what I needed, thanks a lot again. It will be a precious gain of time for my research and I hope all the lab!
The last thing that can still be improved is the possibility to rotate the all the text for the y-axis by 90° like in the units regular graph axis. I can do it by selecting the text box -> ungroup ->selecting text, ->text orientation -> 90°
But as I wanted to automatize everything, if you have an idea to do it faster let me know.
chrisNell wrote:
It does exactly what I needed, thanks a lot again. It will be a precious gain of time for my research and I hope all the lab!
The last thing that can still be improved is the possibility to rotate the all the text for the y-axis by 90° like in the units regular graph axis. I can do it by selecting the text box -> ungroup ->selecting text, ->text orientation -> 90°
But as I wanted to automatize everything, if you have an idea to do it faster let me know.


The attached revision will do that.

--Jim Prouty
Software Engineer, WaveMetrics, Inc.
Append Calibrator.ipf
Thank you very much, it will do all the steps that we used to do by hand! The Igor support was really nice and it is a pleasure to use it.
Hey,
I have a small question because I have an error that comes all the time when I try to target specific function form Calibrator:

While executing SetVariable, the following error occurred: No child data folder of that name exists.

I use it with this code:
Function CN_CalibrationBar(SubWin, Win)
    string SubWin, Win
    string cmd
    sprintf cmd, "SetActiveSubwindow %s", SubWin
    Execute/P/Q cmd
    Execute/P/Q "Calibrator()"
    Execute/P/Q "WMCalibratorPresetButtonProc(\"xNice\")"
    Execute/P/Q "WMCalibratorPresetButtonProc(\"yNice\")"
    Execute/P/Q "WMCalibratorPopMenuProc(\"corner\", 3, \"lower left\")"
    Execute/P/Q "WMCalibratorNumPopMenuProc(\"numbers\", 4, \"print with units, K, m, etc\")"
    Execute/P/Q "WMCalibratorStr2NumPopMenuProc(\"digits\", 1, \"0\")"
    Execute/P/Q "WMCalibratorStr2NumPopMenuProc(\"lineSize\", 3, \"1\")"
    sprintf cmd, "root:Packages:WMCalibrator:%s:G%s:horizInset = -5", Win, subwin[strlen(subwin)-1]
    Execute/P/Q cmd
    sprintf cmd, "root:Packages:WMCalibrator:%s:G%s:vertInset = -5", Win, subwin[strlen(subwin)-1]
    Execute/P/Q cmd
    Execute/P/Q "WMCalibratorCreateButtonProc(\"create\")"
    ModifyGraph/W=$Subwin nticks=0,noLabel=1,axThick=0 //Finally we can remove the basic axis
    Label/W=$Subwin left, " " //Erase the units label on the left. If we delete the label with modifyGraph, it will delete the name for ever.
End

Thank you
Why all the Execute/P commands?

They won't execute until after the function returns.

Also, why not call the underlying routine explicitly instead of calling the panel code?

String oldLayerName= WMCalibratorCurrentDrawLayer(graphName)
SetDrawLayer/W=$graphName $layer
WMNewCalibrator(graphName, xAxis, yAxis,xBar ? xLength : 0,yBar ? yLength : 0,orientation,numbers,digits, lineSize, lineRed, lineGreen, lineBlue,location=corner,horizInset=horizInset,vertInset=vertInset,vertTextRot=vtr)


--Jim Prouty
Software Engineer, WaveMetrics, Inc.
Because it is part of a script that will plot multiple graphs, so by using the function like this, I save time because I always do the same modification on my graph. But I will try with the routine code and without execute/P and let you know.
Cheers
Chris
I have the same error message with the updated "append calibrator.ipf" (working with IGOR 6.3.7) and another one as well:

To be sure it's not an experiment-specific problem I made a blank new experiment and just created two waves, displaying both in separate graphs. When I subwindow one into the other, I can still append a calibrator in the main graph, but as soon as I click into the subwindow area and click on "add calibrator to layer" or even just the calibrator panel, I get the following error message in the history:
** DoWindow gave error: names must start with a letter and contain letters, digits or '_'
Using the debugger I trailed this problem to the line " list=HVAxisList(graphName,1) // horizontal axes, if any" in the following part:
Function WMCalibratorUpdateForGraph(graphName)
    String graphName    // can be "Panel0#G0", for example
   
    if( strlen(graphName) == 0 )
        graphName= WMCalibratorTopGraph()   // can be compound name like "Panel0#Graph0"
    endif
    Variable noGraph= strlen(graphName) == 0
   
    SetVariable subwindow,win=CalibratorPanel,value= _STR:graphName // VERY IMPORTANT: See
   
    String oldDF= WMCalibratorSetDF(graphName)
    String df= GetDataFolder(1) // has trailing ":"

    // set up defaults or load current values
    // NOTE: the control name must match the name of the global var or str in the data folder.
    String str, path, list
    Variable var
    Variable disable=0      // disable everything if no axes.
    // Axes
    //      xAxis
    list=HVAxisList(graphName,1)    // horizontal axes, if any
    if( strlen(list) == 0 )
        if( noGraph )
            list= "no graph"
        else
            list= "missing X axis"
        endif
        disable=2   // shown, but disabled.
    endif



When I clicked in the subwindow area and then try to open the calibrator panel from the menu bar, I get the error message:
"While executing SetVariable, the following error occured: No child data folder of that name exists"

    SetVariable vertInset,pos={122,195},size={90,15},bodyWidth=55,title="V Inset"
    SetVariable vertInset,format="%g %%"
    SetVariable vertInset,limits={0,100,1},value= root:Packages:WMCalibrator:Graph1:P0:G0:P0:G0:insetPercent

    SetVariable horizInset,pos={23,195},size={89,15},bodyWidth=55,title="H Inset"
    SetVariable horizInset,format="%g %%"
    SetVariable horizInset,limits={0,100,1},value= root:Packages:WMCalibrator:Graph1:P0:G0:P0:G0:insetPercent


This error message appears when debug-switching from 3rd to 4th line, and yeah, indeed, there is just a sub-folder series WMCalibrator:Graph0:Graph1, nothing that corresponds to the part called in the ipf.

Is there a way for you to fix these problems?

Yours, Dominik
Your call to DoWindow isn't in the posted code, so it's a little bit hard to comment. But DoWindow doesn't understand subwindow paths. DoWindow also does so many things that it's hard to know what you are trying to do with it. The usual thing is to activate a window (DoWindow/F). To activate a subwindow, use SetActiveSubwindow.

John Weeks
WaveMetrics, Inc.
support@wavemetrics.com
The thing is: It anyway in the whole ipf only appears thrice:
Twice in the beginning, calling the CalibratorPanel
Function Calibrator()
    DoWindow/K CalibratorPanel
    NewPanel/K=1 /W=(465,48,705,607) as "Append Calibrator"
    DoWindow/C CalibratorPanel
    ModifyPanel/W=CalibratorPanel fixedSize=1,noEdit=1
    DefaultGUIFont/W=CalibratorPanel/Mac all={"_IgorSmall",0,0}, tabcontrol={"_IgorMedium",0,0}, button={"_IgorLarge",0,0}


and once later:
Function WMCalibratorHideShowDigits(hideDigits)
    Variable hideDigits
   
    DoWindow CalibratorPanel
    if( V_Flag )
        PopupMenu digits,win=CalibratorPanel, disable=hideDigits   
    endif
End


So I see actually no reason fot he problem to occur at the positions shown by the debugger...

But, there is the "axis utilities.ipf" which seems to be the actual problem, at least for the DoWindow error message (remember, it was evoked when reaching the HVaxislist part):

Function/S HVAxisList(graphName,wantHorizAxes)
    String graphName            // "" for top graph (same as WinName(0,1)
    Variable wantHorizAxes  // 0 for vertical (left, right, etc), 1 for horizontal (bottom, top, etc).
   
    String hvlist=""
   
    if( strlen(graphName) == 0 )
        graphName= WinName(0,1)
    endif
   
    if( strlen(graphName) )
        DoWindow $graphName
        if( V_Flag )
            String axlist=AxisList(graphName)
            Variable index=0
            do
                String axis= StringFromList(index,axlist)
                if (strlen(axis) == 0)
                    break                               // ran out of items
                endif
                String info=AxisInfo(graphName,axis)
                if( AxisOrientation(info,wantHorizAxes) )
                    hvlist += axis + ";"
                endif
                index += 1
            while (1)       // loop until break above
        endif
    endif
    return hvlist
End
Please try again with the (now-revised) upload of Append Calibrator.ipf in the posting above. It has a fix for the Inset SetVariables. This changed file is part of the Igor 7 release.

You also need the attached Axis Utilities: it doesn't use DoWindow the way you show above, and doesn't suffer from this limitation.

--Jim Prouty
Software Engineer, WaveMetrics, Inc.