The drawing circle example, flush ?

Using the graphical user interface to build and exercise models. Includes customizing the GUI by writing a little bit of hoc.
Post Reply
figoyouwei
Posts: 41
Joined: Sun Aug 08, 2010 11:09 am

The drawing circle example, flush ?

Post by figoyouwei »

Dear Ted,

I got this line-Graph example from the documentation.

objref g
g = new Graph()
t = 0
g.addexpr("sin(t)")
g.xexpr("cos(t)")
g.begin()
for(t=0; t<=2*PI+0.1; t=t+0.1){
g.plot(t)
}
g.flush()

But is it supposed to display the circle on the panel ? didn't see any, confused ...

ted
Site Admin
Posts: 5772
Joined: Wed May 18, 2005 4:50 pm
Location: Yale University School of Medicine
Contact:

Re: The drawing circle example, flush ?

Post by ted »

The graph's x and y axes must be properly scaled; otherwise the graph will show a part of its canvas that is blank. See discussion in this thread:
viewtopic.php?f=15&t=785#p2563

figoyouwei
Posts: 41
Joined: Sun Aug 08, 2010 11:09 am

Re: The drawing circle example, flush ?

Post by figoyouwei »

It works !

One minor non-functional thing on this example.

Case 1: just g.size, it would bring up ONE panel with default size and g.sized coordinates. It works fine.
g.size(-1, 1, -1 ,1)

Case 2: use g.view, this would bring up TWO panels then, one with wanted size and coordinates. It works perfect, but another empty one with coordinates of x->250, y->180.
g.view(-1, -1, 2, 2, 300, 100, 500, 400)

Case 3: use both g.size and g.view, this brings up two wanted circle graphs, just in different panel size.
g.size(-1, 1, -1 ,1)
g.view(-1, -1, 2, 2, 300, 100, 500, 400)

So why .view command brings up an additional panel ? not just work on the current g object ? Anyway to work with case 2 without the annoying empty one popped up ? ^.^

ted
Site Admin
Posts: 5772
Joined: Wed May 18, 2005 4:50 pm
Location: Yale University School of Medicine
Contact:

Re: The drawing circle example, flush ?

Post by ted »

Good questions. An instance of the Graph class is like an infinitely large wall on which you can draw things. You don't get to see anything unless some part of the Graph is displayed on the computer screen. The part that is displayed is called a "view" (also known as "viewport" in some computer graphics literature). The process of creating that display is called "mapping." Every time a Graph's view method is executed, a new window appears on the computer screen that shows a part of the Graph. A single Graph can have many views. To learn more, read the Programmer's Reference documentation about the Graph class and its methods.
http://www.neuron.yale.edu/neuron/stati ... graph.html
A good way to learn how to work with Graphs is to use the Print and File Window Manager ("PFWM") to save one or more views of a graph to a session file, then examine the contents of the session file and try to reuse some of that code in your own programming. For an example of this, see
How to use hoc to plot a variable vs. time
in the NEURON hacks section of the Forum.

figoyouwei
Posts: 41
Joined: Sun Aug 08, 2010 11:09 am

Re: The drawing circle example, flush ?

Post by figoyouwei »

Hi Ted,

It turns out:

"An instance of the Graph class manages a window on which x-y plots can be drawn by calling various member functions.
The first form immediately maps the window to the screen.
With a 0 argument the window is not mapped but can be sized and placed with the view() function."

the doc solves this little g.size() and g.view() dilemma :)

thank you for the guidance and happy new year.

kahinou

Re: The drawing circle example, flush ?

Post by kahinou »

Hello,


I used a similar method to plot a vector in which values of an integral are recorded and I am facing a problem which I sense to be due to the way I set the vector. But, I couldn't figure out what's wrong.
Here is my code:

Code: Select all

objref ivec, intvec
ivec = new Vector()
intvec = new Vector()   
head[0] ivec.record(&rsyn[0].i)
head[0] intvec.integral(ivec, .1)

objref g 
g = new Graph()                                              
g.addexpr("intvec")
g.xexpr("t")
g.size(0, T_STOP, -10, 10)
g.begin()
for (intvec=-10; intvec=10; intvec=intvec+0.1){
     g.plot(intvec)
}
g.flush() 
I got this error message:

Code: Select all

bad stack access: expecting (double); really (Unknown)
Graph:: presently invalid expression: intvec
        1
bad stack access: expecting (Object **); really (double)
nrniv: interpreter stack type error
Since intvec is a vector, what triggers this error message?
Could you please help?

Thank you in advance

ted
Site Admin
Posts: 5772
Joined: Wed May 18, 2005 4:50 pm
Location: Yale University School of Medicine
Contact:

Re: The drawing circle example, flush ?

Post by ted »

Unfortunately the code you posted has several problems, plus some things that are benign but unnecessary. Let's deal with the latter first.

There are two instances of unnecessary use of section stack syntax:
head[0] ivec.record(&rsyn[0].i)
head[0] intvec.integral(ivec, .1)
Section stack syntax
sectionname statement
is necessary only when statement involves something that requires specifying the currently accessed section. But ivec, rsyn[0].i, and intvec are all unique names. There is no way that hoc can be confused about which ivec, rsyn[0].i, or intvec you mean. So the "head[0]"s are superfluous--they serve no useful function. All they do is provide opportunities for making typographical errors when writing code, and introduce clutter that interferes with reviewing the code that you wrote.

Now on to the important stuff.

The code will not do what you think it will do. hoc executes this statement
intvec.integral(ivec, .1)
as soon as it encounters it. ivec is empty, so intvec will also be empty--or maybe hoc will emit an error message because it objects to integrating an empty vector. Who cares; neither result is what you want. You need to wait until after a simulation has been executed, before you integrate the contents of ivec. So defer execution of intvec.integral until after you call run().

A minor comment before proceeding to the next item: I know that the Programmer's Reference contains many examples in which numbers < 1 are typed as .xxxx without a 0 in front of the decimal point. In many practical fields, such as engineering, chemistry, pharmacology, medicine, etc. this is regarded as a bad practice because the decimal point may be easy to miss. For example, .125 may be misread as 125, and the consequences of using 125 units (milligrams or whatever) of something when the author meant 0.125 can be quickly fatal. So please get in the habit of typing a zero before the decimal point--the life you save may be your own.

Next item:
g.addexpr("intvec")
is syntactically incorrect because intvec is not a scalar variable or an expression that returns a scalar value.
Furthermore, even if you replaced the "intvec" string with the name of a scalar, the statements that involve g would still do nothing useful, not only because intvec won't contain anything at all, but also because nothing will advance the xexpr's value from point to point.

"But suppose I have run a simulation and intvec finally contains meaningful values--how can I see a graph that shows what they are?"

Use the Vector class's plot method, and do it _after_ calling intvec.integral. No need for you to write a for loop that iterates over the contents of intvec--plot will do that automatically--and no need to call flush.

kahinou

Re: The drawing circle example, flush ?

Post by kahinou »

Thank you for your quick answer!

I understand almost everthing unless the reason why ivec and intvec are empty; I defined them just before the saveData block because my first try was to save their values then export them to Matlab. But as this is not very practical, I tried to plot intvec directly in Neuron. It's probably no longer neccessary to keep that saveData part, then. Is there a particular location in the program where I have to define those vectors so that they are not empty?

On the other hand, the only place I see a "run()" is in the GUI block of my program (where buttons and graphs are created). When I execute intvec.integral(ivec, 0.1) right below this block, I get the same error message :

Code: Select all

bad stack access: expecting (double); really (Unknown)
Graph:: presently invalid expression: intvec
Is it necessary to use "g.addexpr()"?
but also because nothing will advance the xexpr's value from point to point.
Why is that?

Thanks again

ted
Site Admin
Posts: 5772
Joined: Wed May 18, 2005 4:50 pm
Location: Yale University School of Medicine
Contact:

Re: The drawing circle example, flush ?

Post by ted »

kahinou wrote:I understand almost everthing unless the reason why ivec and intvec are empty
I just tried your code snippet, and indeed neither ivec nor intvec is empty. Each contains only a single element, and the value of that element is 0.

And that's what those vectors will contain, regardless of how many simulations you ran before you created them. The Vector class's record method captures a series of values into a vector during a simulation, not before or after a simulation--see the documentation of it in the Programmer's Reference.
the only place I see a "run()" is in the GUI block of my program (where buttons and graphs are created)
The points I was trying to make are
1. you have to run a simulation in order to fill ivec with numerical values
and
2. if you execute intvec.integrate(ivec, 0.1) before ivec contains anything useful, then intvec won't contain anything useful either.

Presumably the code you inherited contains a statement similar to
xbutton("Init & Run","run()")
so read about xbutton in the Programmer's Reference. If you want to automatically compute the integral of a recorded variable after a simulation run, you could do that by defining a new procedure called run_and_integrate

Code: Select all

proc run_and_integrate() {
  run() // fills ivec with recorded values
  intvec.integrate(ivec, 0.1) // integrates the contents of ivec
}
and changing the xbutton statement from
xbutton("Init & Run","run()")
to
xbutton("Run and integrate","run_and_integrate()")
When I execute intvec.integral(ivec, 0.1) right below this block, I get the same error message :

Code: Select all

bad stack access: expecting (double); really (Unknown)
Graph:: presently invalid expression: intvec
Yes because you are asking the Graph class to do something that is impossible. According to the documentation of the Graph class's plot method, plot is used to specify the abscissa (horizontal coordinate) for each item in a list of graph lines. The abscissa must be a scalar variable or a numerical value (an ordinary number). intvec is an instance of the Vector class, which is neither a scalar nor a numerical value.
Is it necessary to use "g.addexpr()"?
It is necessary to throw away everything from g.addexpr down. If you want to see a graph of the contents of intvec vs. time, the easiest way is to use the Vector class's plot method. To do that, you will have to record the values of t to a vector. Change

Code: Select all

objref ivec, intvec
ivec = new Vector()
intvec = new Vector()
to

Code: Select all

objref ivec, intvec, tvec
ivec = new Vector()
intvec = new Vector()
tvec = new Vector()
tvec.record(&t)
and you will be able to plot intvec's contents vs. time after a run. A small change to proc run_and_integrate() will automate this.
nothing will advance the xexpr's value from point to point.
Why is that?
The xexpr is t. The for loop contains no statements that do anything to the value of t.

kahinou

Re: The drawing circle example, flush ?

Post by kahinou »

Hello Ted,

Thank you for you quick and precise answer. You helped me to see and understand errors I wasn't even aware of.
I will try the method with the new procedure and will let you know if I get any new bugs.

Thanks again

Post Reply