Page 1 of 1

The drawing circle example, flush ?

Posted: Thu Dec 26, 2013 4:19 pm
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 ...

Re: The drawing circle example, flush ?

Posted: Fri Dec 27, 2013 3:38 pm
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

Re: The drawing circle example, flush ?

Posted: Fri Dec 27, 2013 5:41 pm
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 ? ^.^

Re: The drawing circle example, flush ?

Posted: Mon Dec 30, 2013 3:06 pm
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.

Re: The drawing circle example, flush ?

Posted: Wed Jan 01, 2014 5:21 pm
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.

Re: The drawing circle example, flush ?

Posted: Fri May 09, 2014 9:48 am
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

Re: The drawing circle example, flush ?

Posted: Fri May 09, 2014 11:29 am
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.

Re: The drawing circle example, flush ?

Posted: Fri May 09, 2014 12:45 pm
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

Re: The drawing circle example, flush ?

Posted: Sat May 10, 2014 7:56 pm
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.

Re: The drawing circle example, flush ?

Posted: Mon May 12, 2014 6:31 am
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