brian-team / brian2

Brian is a free, open source simulator for spiking neural networks.
http://briansimulator.org
Other
943 stars 220 forks source link

Tutorials #413

Closed thesamovar closed 9 years ago

thesamovar commented 9 years ago

It would be good to have a tutorial like in Brian 1.x (although maybe better than that). I realised after explaining how Brian works to some students today that you can get a lot of understanding in a short amount of time with a tutorial. One possibility would be to make it an IPython notebook with figures included, and that would also allow people to get a feel for how Brian works by changing a few things and seeing the effect easily.

I think something like this would be good:

I think that would be enough.

Thoughts?

mstimberg commented 9 years ago

This sounds very reasonable, and I agree that an ipython notebook would be ideal for this. The Brian1 tutorial also had exercises and solutions, some of which went beyond Brian and were general computational neuroscience questions (e.g. "solve the differential equation by hand") -- I don't think this is necessary, here.

thesamovar commented 9 years ago

Not necessary but actually maybe useful and not too much effort to include. Even if you mostly know something, it can be nice to have it all in context. (And of course, they don't have to do the exercises!)

thesamovar commented 9 years ago

I started work on this in the tutorial branch.

Are there any useful functions/tricks for using Brian in an IPython notebook? For example, it would be useful to have a cell magic that restricts magic to objects defined in that cell.

thesamovar commented 9 years ago

Actually for the tutorial (and maybe for some users too) it would be useful to have a global flag that always restricted magic networks to objects defined in the current cell.

thesamovar commented 9 years ago

OK I added this as a new cell magic brian2_restricted in the tutorial branch. Thoughts?

thesamovar commented 9 years ago

OK I put in a first draft of a tutorial on the use of neurons. What do you think?

I stripped out all of the binary data so as not to clog up the git repository. I think we discussed this before but I guess we need to decide now how to do it. One option would be to keep the binaries but put the tutorial in a separate repository. Another option would be to make sure to strip out the binary data. We can still run the notebook and generate HTML from that. That requires us to be careful to remember to strip out that binary data though. Any other options?

mstimberg commented 9 years ago

First of all: great work, the tutorial looks really nice already. I think the brian2_restricted cell magic is a good approach for introductory tutorials, for more advanced stuff it would be nice if you could split up your model definition over multiple cells, but for that you can always create a Network object (hmm, maybe we could actually shorten the usual net = Network(G1, G2, ...); net.run(runtime) to run([G1, G2, ...], runtime)?).

About the binary data. I agree that we should keep it out of the repository, I think in the end we should have the same approach as for the examples. The tutorial ipython notebook files are like the example script, one of us would run them on their machines and then upload the generated images/HTML files somewhere (we could use https://github.com/paulgb/runipy in a generate_tutorials script). It's not 100% foolproof, but we could have a git pre-commit hook that checks ipython notebook files for binary data (or simply any executed cells) and refuses to commit them like that.

thesamovar commented 9 years ago

Thanks! What did you think of the implementation of the brian2_restricted and the name? I thought maybe we could make the same mechanism more general actually. You could do things like with brian2_restricted(): .... I always wasn't very happy with the name but couldn't think of anything better.

I think Network(...).run(time) is as good as run([...], time) - or is there an advantage?

A pre-commit hook to strip the binary data is a good idea. Is that straightforward to implement in a cross-platform way?

mstimberg commented 9 years ago

brian2_scope maybe? magic_scope? I could well imagine with magic_scope(): (or for those not doing the star import with brian2.magic_scope(): but for an ipython cell magic, the name should probably contain brian2, I guess? The implementation looks good to me. Maybe one idea, less elegant but not ipython-specific: Have a start_collect() method (or something better named) that does put a similar "restrict key" into each object. Actually, all this will turn out (from the user's point of view) to not be that different from a forget() call in Brian 1.

I think Network(...).run(time) is as good as run([...], time) - or is there an advantage?

Yeah, you're probably right.

A pre-commit hook to strip the binary data is a good idea. Is that straightforward to implement in a cross-platform way?

I think it all has been done already. A pre-commit hook is quite OS-specific (it's a shell script) but a filter should be really straightforward, see https://gist.github.com/minrk/6176788 (with the first comment about the filter, ignore the pre-commit hook). Such filters are user-specific, i.e. they are not part of the repository but we could include them in dev/tools for us.

thesamovar commented 9 years ago

I was a bit worried about the use of the word magic because of "cell magic" in IPython. Seemed like a recipe for confusion. The word scope is good though. For the IPython magic, %%brian2_cell_scope or %%brian2_local_scope are meaningful but longer than %%brian2_scope. I think brian2_scope works for IPython magic actually, but do we want to use the same word for the with statement? Maybe not. In which case, how about magic scope or local scope for the with statement, and brian2_scope for IPython?

For the more general version, we could actually name the scopes with the current automatically generated numbers used if you don't specify anything. So for IPython you'd write %%brian2_scope scopename and for a script you'd write with magic_scope('scopename'). I think that would be really nice for IPython actually. We could have a function set_scope(name) (where name=None resets it) that is used by the with statement and cell magic. What do you think?

Filter does indeed look simple and cross-platform. Relies on the user to install it though, which isn't too bad given that it's mostly just the two of us. There's no way to enforce it in the repo itself then?

mstimberg commented 9 years ago

For the more general version, we could actually name the scopes with the current automatically generated numbers used if you don't specify anything. So for IPython you'd write %%brian2_scope scopename and for a script you'd write with magic_scope('scopename'). I think that would be really nice for IPython actually. We could have a function set_scope(name) (where name=None resets it) that is used by the with statement and cell magic. What do you think?

In general I think that sounds very good. I'm still not 100% convinced we actually need a with or a cell magic -- isn't the scope implicitly defined between the ..._scope call and run? I.e. wouldn't a general set_scope work both in ipython and in general scripts?

Filter does indeed look simple and cross-platform. Relies on the user to install it though, which isn't too bad given that it's mostly just the two of us. There's no way to enforce it in the repo itself then?

I don't think we can do this, this is something that would have to be enforced on the server side and github does not support pre-receive hooks (which is not surprising, it would mean to run arbitrary shell scripts on the server...). But as you said, it shouldn't be a big problem.

thesamovar commented 9 years ago

I like the with/cell magic because it ends the scope and makes it entirely self-contained. If you just have the function and you want to end the scope you have to do it yourself. Still, we can easily support both. I'll go ahead and implement that. For names, I think the best would be: brian2_scope for IPython, magic_scope for the with statement, and set_scope for the function. What do you think?

mstimberg commented 9 years ago

Hmm, but do you think there will be a situation where you mix explicit scopes and general magic scopes? If not, the next set_scope will end the previous scope, you could even have multiple runs without problems:

set_scope()  # or maybe: start_scope()
G = NeuronGroup(...)
...
I = 0*nA
run(...)
I = 1*nA
run(...)

set_scope() # start a new scope, end the old one
...
run(...)

What did you have in mind as a use case for named scopes? Continuing previous simulations from different scopes? Shouldn't we rather encourage the creation of Network objects in that case?

thesamovar commented 9 years ago

You're right it would probably be rare to mix explicit and general scopes, at least in a Python script. In IPython I can imagine doing it because you might want to temporarily experiment with an idea in just one cell. Actually though, that wouldn't work with the current approach because the general scope would include the named scope too. Perhaps there shouldn't be a general scope, but always a particular scope (it could be None or 0 or something like that at the start).

Similarly for named scopes in IPython you might want to split something across several cells but have several different sections in one notebook and potentially come back to one later and add new cells. It could actually be quite nice even for the tutorial maybe.

So I'd say yes to named scopes, but maybe if there is no 'general' scope and you always have one then there's no need to explicitly end it. You might still want a with statement that remembers the scope you were in before and automatically resets to that though? (Similarly for IPython cell magic.)

I like start_scope() over set_scope() when there's no name, but I think if you're using named scopes and possibly coming back to them set_scope(name) is clearer than start_scope(name)?

thesamovar commented 9 years ago

How about switch_scope or begin_scope as alternatives?

mstimberg commented 9 years ago

I like the wording, but I'm still not convinced that we need the switch_scope feature :) I don't quite see the benefit of having multiple sections in a notebook and then later adding cells (and not changing/replacing them) -- I have the feeling that this together with the possibility of executing cells in arbitrary order will just lead to a big mess...

thesamovar commented 9 years ago

Well you use IPython more than me so I'm happy to go with your feeling about what is more sensible. So we just switch to having a single function that creates a new scope? Maybe still worth having an IPython cell magic but it won't have to do much. Let's use start_scope for the function - same name for the IPython cell magic or brian2_scope?

mstimberg commented 9 years ago

My preferred solution would be to not include the cell magic for now (it would not make any difference if it only starts a new scope, right?). The reason is that it introduces some issues for testing, e.g. we should add testing configurations with and without ipython. Actually, the branch does currently only work when you run it in a notebook, it uses get_ipython without import which is only available when you are running under ipython.

If we see a need for it, then we can always add it later -- I could also imagine other potential features that we want to add specifically for the ipython notebook.

thesamovar commented 9 years ago

OK, I'm happy with that. Will do that soon.

thesamovar commented 9 years ago

OK that's done: what do you think?

mstimberg commented 9 years ago

Looks very good! I don't have a strong feeling about the name, I think I'd slightly prefer begin_scope over start_scope but either is fine for me. I guess the conversion to HTML and upload could be handled together with #340?

thesamovar commented 9 years ago

For me, on the principle of laziness, I'd leave it as start_scope but I also like begin_scope so if you want to change it go ahead! :)

For documentation yes, I've put a note about that on #340.

thesamovar commented 9 years ago

This is done now and can be closed, right? Or should we leave it open to remind us to do more tutorials?

thesamovar commented 9 years ago

More tutorials is good but I'm closing this for now.