different colors for different waves

Dear all,

I've got a very simple problem, but I don't find how to solve it, neither my office mates (!)

I've got N waves (corresponding to N experimental curves, taken at different times) that I want to display on a single graph.
This is easy, but I would like also to make my wave 1 = red --> wave N = yellow with incremental changes from 1 to N in color.

Every ideas are welcome...

Antoine
reserbat wrote:
I've got N waves (corresponding to N experimental curves, taken at different times) that I want to display on a single graph.
This is easy, but I would like also to make my wave 1 = red --> wave N = yellow with incremental changes from 1 to N in color.

Copy the following code in the procedure window. Make sure that your graph containing the traces is the frontmost and then execute setcolor() from the command window.
function setcolor()
    string trl=tracenamelist("",";",1), item
    variable items=itemsinlist(trl), i
    variable ink=103/(items-1)
    colortab2wave yellowHot256
    wave/i/u M_colors
    for(i=0;i<items;i+=1)
        item=stringfromlist(i,trl)
        ModifyGraph rgb($item)=(M_colors[140+i*ink][0],M_colors[140+i*ink][1],M_colors[140+i*ink][2])
    endfor
    killwaves/z M_colors
end


Andreas
You might also want t look at the KBColorizeTraces package which has functions for exactly this situation: #include <KBColorizeTraces>.
Even easier way to use that:

From Igor's Graph menu, choose Packages->Make Traces Different.

Generally useful tip: Check out the various Packages submenus when looking for something you have a feeling must be somewhere.

The other place to look is in Windows->Help Windows->WM Procedures Index.

--Jim Prouty
Software Engineer, WaveMetrics, Inc.
Hi All,

We did something similar to this many years ago and called it "Rainbow()", but I'm re-inventing it using a routine in KBColorizeTraces.ipf.

I have a simple FUNCTION to colorize traces (below), and a question, because I'd like to change it to a MACRO, but I can't get that to work.
When I make it a Macro, I get an "Expected local variable name" error for "red" in the KBRGBToHS call.
Why?
I know that I can 'cheat' and make a MACRO called "Rainbow_" that simply calls the FUNCTION caled "Rainbow", but is there a way to make a direct call instead of this transfer?


A bit of explanation first:
1) Because HUE wraps around, I stopped the range in the "violet" part of the spectrum (47500) instead of going all the way to 65535.
2) Saturation is max (65535), and lightness is mid-range (32767)
3) Do-While is used in this example because For-endFor is not allowed in a MACRO (both work equally well in a FUNCTION)
function rainbow()
      string names=tracenamelist("",";",1),name
      variable count=itemsinlist(names)
      variable i,hue,red,green,blue
      variable step = (47500) / (count-1)
      i=0
      do
          name=stringfromlist(i,names)
          hue = i * step
          KBRGBToHSL(hue, 65535, 32767, red, green, blue)
          ModifyGraph rgb($name)=(red,green,blue)
          i+=1
      while (i &lt; count)
end


Thank you!

Sean

p.s. Is there a way to get TAB or SPACE characters in the code snippet "manually", i.e. w/o using the igor and /igor tags
seanokeefe wrote:

p.s. Is there a way to get TAB or SPACE characters in the code snippet "manually", i.e. w/o using the igor and /igor tags


You can put space and tab characters in your post, but browsers collapse whitespace in HTML, so they won't be visible. In addition, if you don't surround your code with the igor tags, special characters like the < and > symbols will often be mistaken as HTML tags that are not allowed, and will not be displayed. This is done to prevent people from posting malicious HTML or javascript code on the site.

You can also use <code></code> tags around your code, but you won't get the benefit of Igor syntax highlighting that way.
In general it is very difficult to find n trace colors that are easily distinguished in a graph.

Also often I want a given quantity to be the same color in every graph. For example, if my data consists of displacement, velocity and acceleration, I want displacement to be red in all graphs, velocity to be green in all graphs and acceleration to be blue in all graphs.

My solution, which is far from ideal, is to create a function that returns an RGB color given an index number. The colors are manually chosen to be as distinct as I can make them for a given n.

See the function below for an example.

I use a separate function to map between index numbers and quantity names (e.g., displacement, velocity, acceleration).

It would be great to have a function that would return maximally distinct colors for any n but that's way beyond my capabilities.

Function GetColor(colorIndex, red, green, blue)
    Variable colorIndex
    Variable &red, &green, &blue                // Outputs
   
    colorIndex = mod(colorIndex, kNumVanBlariganWaves)          // Wrap around if necessary
    switch(colorIndex)
        case 0:     // Time wave
            red = 0; green = 0; blue = 0;                               // Black
            break
           
        case 1:
            red = 65535; green = 16385; blue = 16385;           // Red
            break
           
        case 2:
            red = 2; green = 39321; blue = 1;                       // Green
            break
           
        case 3:
            red = 0; green = 0; blue = 65535;                       // Blue
            break
           
        case 4:
            red = 39321; green = 1; blue = 31457;                   // Purple
            break
           
        case 5:
            red = 39321; green = 39321; blue = 39321;           // Gray
            break
           
        case 6:
            red = 65535; green = 32768; blue = 32768;           // Salmon
            break
           
        case 7:
            red = 0; green = 65535; blue = 0;                       // Lime
            break
           
        case 8:
            red = 16385; green = 65535; blue = 65535;           // Turquoise
            break
           
        case 9:
            red = 65535; green = 32768; blue = 58981;           // Light purple
            break
           
        case 10:
            red = 39321; green = 26208; blue = 1;                   // Brown
            break
           
        case 11:
            red = 52428; green = 34958; blue = 1;                   // Light brown
            break

        case 12:
            red = 65535; green = 32764; blue = 16385;           // Orange
            break

        case 13:
            red = 1; green = 52428; blue = 26586;                   // Teal
            break

        case 14:
            red = 1; green = 3; blue = 39321;                       // Dark blue
            break

        case 15:
            red = 65535; green = 49151; blue = 55704;           // Pink
            break
    endswitch
End

seanokeefe wrote:

I have a simple FUNCTION to colorize traces (below), and a question, because I'd like to change it to a MACRO


Why would you want to do that?
Quote:

, but I can't get that to work.
When I make it a Macro, I get an "Expected local variable name" error for "red" in the KBRGBToHS call.
Why?


It's because the last three parameters are call-by-reference- they are outputs. You can't call that function from a macro. Again, why do you want to make it a macro?

John Weeks
WaveMetrics, Inc.
support@wavemetrics.com
I would like to make it a MACRO so that it auto-populates onto the MACRO pulldown so that I can Rainbow-ize a graph whenever I want. Sometimes typing is fastest, sometimes mouse-clicking, sometimes it is procedure-writing - but I tend to write these routines in small pieces, check them, and then combine them into larger routines, so I check out the pieces on different styles of plots. I also plot all sorts of different data in any given week, so it's nice to have my favorite graph-modifying routines easily at-hand (and I also don't have to remember what I called them! - the menu will prompt me!).

Is there a (historical?) programming explanation why the different code structures (do-while, for-endfor, ...) are allowed in functions, but not macros, or procedures, or vice versa?

It seems like 20 years after the introduction of these 'limitations', that someone could make each type of routine "equivalent", but I'm not a C++/?? guru to know that there would be any deep-seated programming reason why this is not possible.

Thank you,

Sean

p.s. nobody mentioned which HTML tag could be used for a TAB or SPACE character. There must be one, but I am not HTML-savvy.
seanokeefe wrote:
I would like to make it a MACRO so that it auto-populates onto the MACRO pulldown


This will equate the menu "Rainbowize" to the FUNCTION Rainbowize ...

Menu "Macros"
       "Rainbowize Graph"/Q,Rainbowize()
end


seanokeefe wrote:
It seems like ... there would be any deep-seated programming reason why this is not possible.


I don't know either. AFAIK however, macros run somewhat as BASIC code in a "line-by-line" mode while functions run as pre-compiled units.

seanokeefe wrote:
p.s. nobody mentioned which HTML tag could be used for a TAB or SPACE character. There must be one, but I am not HTML-savvy.


http://webdesign.about.com/od/localization/l/blhtmlcodes-punc.htm?rd=1
http://www.web-source.net/symbols.htm

The "non-breaking space" code - $nbsp; - is fairly common.


--
J. J. Weimer
Chemistry / Chemical & Materials Engineering, UAHuntsville
Thanks JJ for the &nbsp reference.
In an earlier post, I also mentioned using a macro to call a function/procedure, but that just seems "wasteful", and I was wondering if there was a programming reason why the loop styles are not interchangeable, and similarly why Macros, Functions, and Procedures are all handled differently.
Sean
seanokeefe wrote:
In an earlier post, I also mentioned using a macro to call a function/procedure, but that just seems "wasteful",


That depends on what you figure is "wasted". For me, adding the extra Menu call at the top of the procedure is always a cleaner way to track where I am making the entry point in my code. I also think (though I could be wrong), using Menu calls to enter functions runs faster than using Macros to generate menu calls due to compiled versus run-time issues -- though even if I am correct, you would likely not notice the difference anyway.

seanokeefe wrote:
and I was wondering if there was a programming reason why the loop styles are not interchangeable, and similarly why Macros, Functions, and Procedures are all handled differently.


My guess for the first is because writing pre-compiled code segments to map to do-while is a harder task than to map for-endfor.

My guess for the second is ... that is just showing the historical development of Igor coding from a run-time macro language to a compiled level function language.

--
J. J. Weimer
Chemistry / Chemical & Materials Engineering, UAHuntsville
seanokeefe wrote:
p.s. nobody mentioned which HTML tag could be used for a TAB or SPACE character. There must be one, but I am not HTML-savvy.

You can use a regular space character or a regular tab character. Note that in most browsers, hitting the tab key will move the selected form element, not insert the tab into a text box, so you have to copy and paste it in. But just because you have entered a tab character or multiple space characters doesn't mean that the browser will actually render them. That's why you need to enclose your code in code or igor tags, because doing so tells the browser that you want it to render the text as you have typed it. You can use multiple &nbsp; characters   as a substitute for a tab character, because the browser will not collapse them into just one space, however this works just as well as using multiple spaces does to left align text...that is, not very well unless you're using a monospaced font. To use a monospaced font, you need to use code or igor tags, and if you use the tags you don't have to worry about putting in your own &nbsp; characters.

If you ever look at a .html page created by MS Word from a few versions ago, you'll see that they attempt to keep the layout the same by filling the document with &nbsp; characters all over the place, yet it still doesn't look very good.

seanokeefe wrote:
In an earlier post, I also mentioned using a macro to call a function/procedure, but that just seems "wasteful", and I was wondering if there was a programming reason why the loop styles are not interchangeable, and similarly why Macros, Functions, and Procedures are all handled differently.

When Igor was very young, it didn't support user defined functions. At some point, they were added. Because they are better in every (or almost every) way, new programming features were added to functions but weren't added to macros, because outside of window recreation macros people really should be writing functions.

So sayeth Programming.ihf

Because functions are compiled, they are dramatically faster than macros. Compilation also allows Igor to detect errors in functions when you write the function, whereas errors in macros are detected only when they are executed.
Macros are a legacy of Igor's early days. With rare exceptions, all new programming should use functions, not macros.


I'll also add that you can use Igor's debugger with functions, but can't do so with macros. [edit: actually, you can]

There are a few very old operations that cannot be called directly from within user defined functions. Some XOPs have similar limitations in external operations they provide. In those cases you can use the Execute operation to execute those operations.
Thanks guys for the thoughts and for the function reference from WAVEMETRICS!
I also learned recently that you can execute a function by just typing it, without the need to actually do anything with the RETURNed value. i.e. just type foo() instead of print foo().
Slowly but surely I'll get back into the swing of things and I'll start thinking along the lines of making everything into FUNCTIONs.
Cheers!
Sean
Quote:
I'll also add that you can use Igor's debugger with functions, but can't do so with macros.

Well, that's actually not true: the debugger works just fine with Macros and Procs.

I know, because I wrote the debugger.

--Jim Prouty
Software Engineer, WaveMetrics, Inc.
JimProuty wrote:
From Igor's Graph menu, choose Packages->Make Traces Different.

Generally useful tip: Check out the various Packages submenus when looking for something you have a feeling must be somewhere.

The other place to look is in Windows->Help Windows->WM Procedures Index.


I found the package in the Graph menu. Can I also do this automatically with a command in a procedure? How would I do that?
(Sorry if the answer should already be clear from the previous post, but I'm new to Igor)
tatj wrote:
JimProuty wrote:
From Igor's Graph menu, choose Packages->Make Traces Different.

Generally useful tip: Check out the various Packages submenus when looking for something you have a feeling must be somewhere.

The other place to look is in Windows->Help Windows->WM Procedures Index.


I found the package in the Graph menu. Can I also do this automatically with a command in a procedure? How would I do that?


Take a look at the content of the KBColorizeTraces.ipf procedure window that's loaded into your experiment when you select the package, and call the desired function(s).

For example to use the "Commonly-used Colors" feature from your own function, call:

Function myFunction()
    CommonColorsButtonProc("")
End


--Jim Prouty
Software Engineer, WaveMetrics, Inc.
JimProuty wrote:


For example to use the "Commonly-used Colors" feature from your own function, call:

Function myFunction()
    CommonColorsButtonProc("")
End




This example works fine, but I can't figure out, how I would use the function to color the graph in e.g. Rainbow colors. I found this function "static Function KBColorTablePopMenuProc(ctrlName,popNum,popStr) : PopupMenuControl" which looks to me like the option I have in the graphical interface. But what are the arguments I would have to use?
Could you maybe give me a really small (but complete) example of how I can color a graph in rainbow colors? Being a beginner in Igor, I couldn't figure it out myself so far.
tatj wrote:
I can't figure out, how I would use the function to color the graph in e.g. Rainbow colors. I found this function "static Function KBColorTablePopMenuProc(ctrlName,popNum,popStr) : PopupMenuControl" which looks to me like the option I have in the graphical interface. But what are the arguments I would have to use?
Could you maybe give me a really small (but complete) example of how I can color a graph in rainbow colors? Being a beginner in Igor, I couldn't figure it out myself so far.

 
KBColorizeTraces#KBColorTablePopMenuProc("",0,"Rainbow")
 
 
KBColorizeTraces#KBColorTablePopMenuProc("",0,"Rainbow")
 

worked out fine so far. But now all on a sudden I get the error "attempt to use a null string variable".
It must come from the colorize traces. If I comment it out, the error is gone. I changed a few things in the procedure, but the error even persists if I open a new experiment and load the last working procedure I saved. Where might this error come from?
tatj wrote:
But now all on a sudden I get the error "attempt to use a null string variable". . . . Where might this error come from?


Turn on "Enable Debugger", "Debug on Error", and "Wave, NVAR and SVAR Checking" in the Procedure menu. To do this you must first activate a procedure window. Then when an error occurs, Igor will drop into the debugger and you can see where the error is coming from.

For details execute this:
DisplayHelpTopic "The Debugger"


#pragma rtGlobals=1     // Use modern global access method.
#include <KBColorizeTraces>

Macro test_load()
LoadWave/J/D/W/K=0 "J:TFT-Tatjana:evaporation:sample1:2010-06-11-gate-or-source-drain-scans:ivg_30050.txt"
Display Isd_A_ vs Vg_V_
•KBColorizeTraces#KBColorTablePopMenuProc("",0,"Rainbow")
end


This is a small code, where the error still occurs. I just have now idea. Does the colorizeTraces use a string I don't know about? I seems that I have changes something in the program itself as it occurs now always (restarting Igor doesn't help, neither does a starting a new experiment).


I tried with the debugger. It stops at         SetDataFolder savedDataFolder in StoreKBColorizeSettings (function static Function StoreKBColorizeSettings())which is called by KBColorTablePopMenuProc in function static Function KBColorTablePopMenuProc(ctrlName,popNum,popStr) : PopupMenuControl

I also get the information "savedDataFolder ¦ "root" "

It would be great if somebody could help in order to solve this problem. I think I don't know yet enough about Igor to understand such problems.
The problem is with this code:

ControlInfo/W=KBColorizePanel ColorTablePop
String/G gColorTableName= S_value


It assumes that the KBColorizePanel control panel exists, but that is not the case.

You are calling this:
KBColorizeTraces#KBColorTablePopMenuProc("",0,"Rainbow")


This is a popup menu action procedure that is designed to be called when the user clicks a popup menu in a control panel.

In other words, you're trying to use a function designed to work with a control panel but you don't have the control panel.

As it stands, it appears that KBColorizeTraces is not appropriate for programmatic use.

I would not use KBColorizeTraces for programmatic use but instead would create a custom function. See my post from June 11th above.
hrodstein wrote:
The problem is with this code:
As it stands, it appears that KBColorizeTraces is not appropriate for programmatic use.

I would not use KBColorizeTraces for programmatic use but instead would create a custom function. See my post from June 11th above.


But why did it work before without showing me an error?
And it still gives the desired result but shows me the error in the end.
Quote:
But why did it work before without showing me an error?


Because you had opened the panel which created variables that the function expects to exist.

tatj wrote:
But why did it work before without showing me an error? And it still gives the desired result but shows me the error in the end.


This is a nice feature of Igor's programming environment: Igor allows the code to execute anyway even though the error occurred immediately at the beginning - the error message is simply "delayed" as you said. The executed function StoreKBColorizeSettings() in which the error occurred certainly fails in some way, but this does not stop the calling function KBColorTablePopMenuProc to execute successfully.

You seem earnest in learning more about Igor programming and I fear you are "being led" to a part of the learning curve that is particularly steep: You have been tempted to call a function deep in a procedure file not written by yourself, and you have even been enticed to use the debugger. If you want to compound this, here is "some more rope to hang yourself with" (as WM are prone to say): You can modify the KPColorizeTraces.ipf (after having saved it under a new name).

A "quick hack" would be to put the following code:
DoWindow KBColorizePanel    // *** added for external use of functions ***
if( V_Flag == 0 )   // KBColorizePanel does not exist
    return -1
endif

immediately below the line saying
static Function StoreKBColorizeSettings()


This checks whether the panel actually exists and bypasses the rest of the code if it doesn't. It allows you to use your function call
KBColorizeTraces#KBColorTablePopMenuProc("",0,"Rainbow")

without throwing the error, and without the need to actually open the panel even once ...

On the other hand, it is probably healthier to follow Howard Rodstein's advice and rather write a single, shiny new function as the one he put in his June-11th post. This avoids carrying a lot of functions around that are also part of the KBColorizeTraces package but "do nothing" for you, and reduces the future risk of entanglements in KBColorizeTrace's inner workings.

If you use my tip above, you should also change the module name (second line in your newly saved .ipf file) to something other than
#pragma moduleName=KBColorizeTraces

so that you can still use the original package if the need arises. If you do this, remember to change your call accordingly, i.e., type the same module name befor the "#" sign in the line
KBColorizeTraces#KBColorTablePopMenuProc("",0,"Rainbow")



Greetings,
Wolfgang