Professional Documents
Culture Documents
Thebookofsho
Thebookofsho
Table of Contents
Chapter 1: What Is Sho? ........................................................................................................................... 5 1.1 Welcome to Sho .............................................................................................................................. 5 1.2 What Sho Is .................................................................................................................................... 5 1.2.1 What Sho Looks Like ............................................................................................................... 5 1.2.2 How Sho Relates to IronPython and .NET................................................................................. 5 1.3 Why Should I Use Sho? .................................................................................................................. 6 Chapter 2: Getting Started......................................................................................................................... 7 2.1 The Sho Environment...................................................................................................................... 7 2.1.1 The Sho Console ...................................................................................................................... 7 2.1.2 Editing Python Files, Functions, and Modules ........................................................................... 8 2.1.3 Browsing the Command History ............................................................................................... 9 2.1.4 Using Sho from the Command Shell ......................................................................................... 9 2.2 OS Utilities ................................................................................................................................... 10 2.3 Odds and Ends .............................................................................................................................. 11 2.4 Documentation Utilities ................................................................................................................ 11 2.4.1 The help function ................................................................................................................... 11 2.4.2 Using doc to Examine Types or Objects .................................................................................. 11 2.4.3 The lookup utility ................................................................................................................... 13 Chapter 3: IronPython Basics .................................................................................................................. 15 3.1 Python vs. IronPython ................................................................................................................... 15 3.2 Types ............................................................................................................................................ 15 3.3 Formatting Code ........................................................................................................................... 16 3.4 Conditionals.................................................................................................................................. 16 3.5 Built-in Collections: Lists, Tuples and Dictionaries........................................................................ 16 3.6 Loops and Iterators........................................................................................................................ 18 3.7 Manipulating Lists ........................................................................................................................ 19 3.7.1 List Comprehensions .............................................................................................................. 19 3.7.2 List ........................................................................................................................................ 19 3.7.3 Zip ......................................................................................................................................... 20 3.7.4 Sort ........................................................................................................................................ 20 3.8 Dictionaries and Hashtables .......................................................................................................... 20 3.9 Using .NET Generics .................................................................................................................... 21 3.10 Functions .................................................................................................................................... 21 3.10.1 Default Values and Named Arguments.................................................................................. 22 3.10.2 Function Pointers and Delegates ........................................................................................... 22 3.10.3 Yield .................................................................................................................................... 22 3.11 Classes ........................................................................................................................................ 23 3.12 Files and Namespaces ................................................................................................................. 24 3.12.1 Execfile ................................................................................................................................ 24 3.12.2 Import .................................................................................................................................. 25 3.12.3 From <module> import <symbol> ........................................................................................ 26 3.13 Exceptions .................................................................................................................................. 26 3.14 ShoThreads ................................................................................................................................. 27 Chapter 4: Matrix Classes ....................................................................................................................... 29 4.1 Array Creation .............................................................................................................................. 29 4.2 Element Access and Slicing........................................................................................................... 31 4.3 Optimized Matrix Methods............................................................................................................ 32 4.4 Sparse Arrays ................................................................................................................................ 33 4.5 Multidimensional Arrays ............................................................................................................... 34 4.6 Group and Elementwise Operations ............................................................................................... 35 4.7 The Find Command ...................................................................................................................... 36 4.8 Linear Algebra .............................................................................................................................. 37 Chapter 5: Math and Data Analysis ......................................................................................................... 39 3
5.1 Mapping functions ........................................................................................................................ 39 5.2 Stepping through intervals ............................................................................................................. 39 5.3 Histogramming ............................................................................................................................. 40 Chapter 6: Data Handling ....................................................................................................................... 42 6.1 Pickling Sho data .......................................................................................................................... 42 6.2 Reading/Writing Delimited Files ................................................................................................... 42 6.3 Reading from a Database............................................................................................................... 43 6.4 Roll your own data readers/writers ................................................................................................ 44 6.4.1 Custom ASCII Data Reader .................................................................................................... 44 6.4.2 Custom Binary Data Reader.................................................................................................... 44 Chapter 7: Plotting and visualization ....................................................................................................... 46 7.1 Line/scatter plots ........................................................................................................................... 46 7.1.1 Multiple Plots ......................................................................................................................... 49 7.1.2 Advanced Plot Options ........................................................................................................... 50 7.1.3 Legends.................................................................................................................................. 51 7.1.4 Drawing Images, Lines, Shapes, and Text onto Plots ............................................................... 52 7.1.5 Setting Plot Properties ............................................................................................................ 53 7.2 Bar Charts..................................................................................................................................... 54 7.3 DataGridView............................................................................................................................... 56 7.4 Contour Plots ................................................................................................................................ 58 7.5 Viewing Arrays as Images ............................................................................................................. 58 7.6 Interactive Histograms .................................................................................................................. 60 7.7 Inline plots in ShoConsole ............................................................................................................. 60 7.8 Copying, Exporting, and Saving Plots............................................................................................ 61 Chapter 8: .NET ..................................................................................................................................... 62 8.1 Using .NET Framework Classes .................................................................................................... 62 8.2 Using Other .NET Libraries .......................................................................................................... 62 8.3 Using COM Libraries .................................................................................................................... 63 Chapter 9: Extending Sho ....................................................................................................................... 64 9.1 Python Modules ............................................................................................................................ 64 9.2 Single C# Files.............................................................................................................................. 64 9.3 Dynamically Extending Sho with Visual Studio............................................................................. 66 9.3.1 Signing the Assembly ............................................................................................................. 66 9.3.2 Auto-Updating the Assembly Version ..................................................................................... 67 9.3.3 Loading/Reloading the Assembly from Sho ............................................................................ 67 9.3.4 Debugging the Assembly ........................................................................................................ 68 9.4 Sho Packages ................................................................................................................................ 68 Chapter 10: Using Sho from .NET .......................................................................................................... 70 10.1 Writing .NET Code Using Sho Libraries ...................................................................................... 70 10.2 Calling Python Code from .NET .................................................................................................. 71 Chapter 11: Writing GUIs with Sho ........................................................................................................ 73 Chapter 12: Debugging Sho Code ........................................................................................................... 75 12.1 Debugging Sho Code from Sho ................................................................................................... 75 12.2 Debugging with Visual Studio ..................................................................................................... 75 Chapter 13: Epilogue .............................................................................................................................. 77 13.1 Other Resources .......................................................................................................................... 77 13.2 And Youre Off! ......................................................................................................................... 77
So what does Sho add to the mix? Basically, we have added a number of class libraries, utilities, and interfaces to extend the IronPython environment into an ideal playground for data analysis and manipulation. This includes math, plotting, and visualization facilities, as well as a host of utilities that make it easy and fun to do research and prototyping in a mixed-language environment.
The Sho Console is our recommended means of accessing Sho, and has many features, as we describe below. Heres a rundown of the principal features: Tab Completion and Inline Documentation. Hit Tab after typing the partial name of a .NET or Python class, method, namespace, or function, and the console will list all the possible completions beneath the prompt. Hit Tab after typing a function/method name and an open parenthesis or within the argument list, and the console will list all the prototypes for that function; if there is documentation available it will show that as well. Command History Recall. Type a few characters and hit up-arrow; the console will then retrieve all commands youve entered that started with those characters. Rich Copy/Paste with C-c/v. This is the behavior youre used to in other windows applications, as opposed to the command shells non-standard behavior. However, Shos rich copy and paste also lets you paste in images, Excel ranges, and other data from sources outside Sho. Break Execution with Ctrl-Alt-C or Ctrl-Shift-C. Use this to stop any foreground Sho task and get back a command prompt.
Visual History Browser. You can bring up a history browser that persists across sessions by typing historypicker(); this includes a search box at the top where you can do incremental search on your past commands. Inline graphics. You can view charts and graphs inline in the console window using the showplot, showbar and show commands.
Theres also an extensive set of key bindings (many of these will be familiar to Emacs users): Ctrl-a: Beginning of Line Ctrl-e: End of Line Ctrl-b: Backwards Character Ctrl-f: Forwards Character Ctrl-p: Previous line in history (same as Up-Arrow) Ctrl-n: Next line in history (same as Down-Arrow) Ctrl-k: Clear to end-of-line Alt-f: Forward word Alt-b: Backward word Ctrl-Alt-c: Break execution Ctrl-Alt-s: Suspend (pause) execution Ctrl-Alt-q: Resume execution Additionally, there is a shell-escape mode that allows you to quickly execute DOS-shell commands from the Sho console. Just start your command with a %, and the rest of the line will be send to the shell. If youd like to change the font used by the Sho console, just call the setfont function (just type setfont() in the console window). It will present you with a font selection dialog where you can choose the font to use. You can also set the title of the console window using the setconsoletitle() command.
*The default editor is notepad.exe, since everybody has it; unfortunately, it does not have the ability to jump to a specified line number. You can change the default editor by setting the sys.Sho.Editor variable, and you can use the sys.Sho.EditorArgs to specify how to open the file at the appropriate line number. For instance, if you want to use Visual Studio (devenv.exe) as your editor and have it open files at the right number, you can do the following: >>> sys.Sho.Editor = "devenv.exe" #note devenv.exe must be in your PATH >>> sys.Sho.EditorArgs = "%f /command \"edit.goto %l\"" If youre an Emacs user, use the following commands:
>>> sys.Sho.Editor = "emacs.exe" #note emacs.exe must be in your PATH >>> sys.Sho.EditorArgs = "+%l %f" Note you can put these lines into your startup file (startup.py), which is in the root of your {SHODIR}.
Figure 2.3: Using Sho from the command prompt. Cutting and pasting can be a pain in a command shell, so we suggest using QuickEdit mode. Right click on the titlebar, choose Properties, then go to the Options Tab, and turn on the checkbox for QuickEdit mode. With this mode, you can click and drag to highlight a rectangular section of the box and then hit Enter to grab that section. Right-clicking will paste into the box. Its a bit cumbersome, but better than right-click->Edit->Copy/Paste.
2.2 OS Utilities
Sho has a number of OS-level utilities which make it easier to get around and see whats going on. Note that in all these commands, you can specify pathnames using either forward slashes (c:/sho) or double backslashes (c:\\sho). 10 cd(path) takes you to the directory of your choice. pwd() returns the current working directory as a string. ls(path) prints the contents of the specified directory, returns the FileInfo values if an optional argument is set files(pattern,dir) returns the files matching pattern (e.g., *.*) as an array of strings. dirs(pattern, dir) returns the dirs matching pattern as an array of strings. findinfiles(regex, basepath, filetypes) prints line numbers and files in which regex appears; recursively scans directories starting with basepath. egrep(regex, path) prints line numbers and files in which regex appears; similar to findinfiles() but with wildcard-style path specification. findfiles(regex, basepath, filetypes) prints files whose names contain regex; recursively scans directories starting with basepath. addpath(path) adds path to both the system PATH for the current process and the Python path. which(filename) returns where in the Python (sys.path) or bin (System PATH) path a given file appears. shell(cmd) start up another process as if from the Windows command prompt
Available Help Topics: help("plot") - plotting functions help("array") - matrix classes and help("math") - linear algebra and help("pickle") - saving and loading
11
Figure 2.4: Getting interactive documentation using the doc command The doc window contains a sorted list of the methods, events, properties, and so on for that object. The interface also has a few widgets to help you narrow down the information displayed, and to get more information about some constituent element of the object youre browsing (either from doc itself or by searching MSDN). Say youre trying to find out more about handling drag and drop events you could set the focus to the search box in the upper-right corner (shortcut: type ctrl-s), type drag, and the window filters out anything that doesnt have drag in it:
Figure 2.5: Using the search box to incrementally filter doc's output Now, if you want to find out more about, say, the DragOver event, you could right-click on that entry and youll get a menu that will invoke doc on the argument types for that event, or search MSDN for the event itself:
12
Figure 2.6: The doc contextual menu If you want to filter out the methods and properties from specific parts of the class hierarchy you can toggle them by clicking on the appropriate labels in the hierarchy bar to the left of the search box. In the above example, we dont display any items inherited from Object, MarshalByRefObject or Component. The doc window will also display the values of an objects fields. Here in an example of calling doc on a Rectangle object:
13
2.8 Finding Sho commands using lookup If you dont want a separate window to pop up, you can use the console version of lookup, called simply look: >>> look('grid') autoadvancegrid sho autoadvancegrid -- controls whether a chart grid automatically advances to the next cell after plotting (default: True) datagridview sho usage: datagridview(data, ...) or dgv(data, ...) dgv sho usage: datagridview(data, ...) or dgv(data, ...) grid sho grid -- create grid of subplots and direct plotting operations into the first cell
14
3.2 Types
As you may know, Python is not a strongly typed language, which means functions dont declare the types of their input arguments, among other things. In other words, you can pass objects about willy-nilly without knowing anything about what they are, and someone can painlessly pass a Color into your function cuberoot(x) (which will result in an exception eventually, of course). That said, because were in .NET, everything does have a type, and you can call the GetType method to examine what type it is. To keep things consistent for both the Python and .NET worlds, many basic types in IronPython have both a Python type and an underlying .NET type. For instance, if you set a = "foo", a will be a str (an IronPython string), and also a System.String. There are other types, though, such as lists (which well cover shortly), which have distinct IronPython and .NET types. If you set a=[1,2,3], a.GetType() or type(a) will return the value IronPython.Runtime.List, which is distinct from the usual .NET ArrayList. However, it does satisfy the IEnumerable interface, so you can use iterators with it. In fact, you can even pass this to C# code that knows nothing about Python types, as long as it only looks at it through the IEnumerable interface.
15
3.4 Conditionals
Conditionals in IronPython are comprised of the if, elif, and else statements. The conditional statements are set off by a colon, and the conditional bodies are indented as shown in the Figure below. >>> x = 5 >>> if x==1: print "foo" >>> if x>10: print "bar" elif x==3: print "baz" else: print "bak" bak
16
l = [1, 2, 3, 4] t = ('a', 'b', 'c') d = {'a':1, 'b':2, 'z':26} l[0] # access first element of l # access first element of t # look up the value bound to a # set an existing entry in a list
>>> t[0] = 123 # tuples are read-only, you cant change their values Error: 'tuple' object is unsubscriptable >>> l.append('bye!') # you can append values to a list, however >>> l ['howdy', 2, 3, 4, 'bye!'] >>> d['a'] = 'one' # replace a value in a dictionary >>> d['foo'] = 'bar' # add a new value >>> d # note that the ordering of a dict may change {'b': 2, 'z': 26, 'a': 'one', 'foo': 'bar'} >>> l[-1] 4 >>> l[-2] 3 >>> t[-1] 'c' # you can use negative indices in tuples and lists # in order to access elements starting from the end
You can use the keyword in to test if a value exists in a collection. Note that in looks at the keys, not the values in a dictionary.
17
>>> li = [1,2,3] >>> 2 in li True >>> 9 in li False >>> t = (1,2,3) >>> 2 in t True >>> 9 in t False >>> d = {'a':1, 'b':2, 'c':3} >>> 'a' in d True >>> 'x' in d False >>> 2 in d False
18
>>> di = System.IO.DirectoryInfo(".") >>> for f in di.GetFiles(): print f dlmread.dll imatrix.dll IronMath.dll IronPython.dll ...
3.7.2 List
List simply takes any enumerable series and makes it into a list. This is particularly useful for hard-to-see objects like the keys in a hashtable:
19
>>> h = System.Collections.Hashtable() >>> h['a'] = 1 >>> h['b'] = 2 >>> h['c'] = 3 >>> list(h.Keys) ['a', 'b', 'c']
3.7.3 Zip
Zip lets you take multiple lists and zip them together, pairing the first element of the first list with the first element of the others, and so on: >>> zip(['a','b','c'],[1,2,3]) [('a', 1), ('b', 2), ('c', 3)]
3.7.4 Sort
Sort lets you sort a list (no surprise there), optionally passing in a comparison function of your choice that compares two elements in the list. If you like, you can define the sort function inline via a lambda expression (anonymous function): >>> h = {'a':1, 'b':2, 'c':3, 'd':4} >>> z = zip(list(h.Keys), list(h.Values)) >>> z [('d', 4), ('b', 2), ('c', 3), ('a', 1)] >>> z.sort() >>> z [('a', 1), ('b', 2), ('c', 3), ('d', 4)] >>> z.sort(lambda a,b: a[1] < b[1]) >>> z [('d', 4), ('c', 3), ('b', 2), ('a', 1)]
20
>>> d = dict() >>> d["a"] = 1 >>> "a" in d True >>> d["a"] 1 >>> h = System.Collections.Hashtable() >>> h["dog"] = 1 >>> h["cat"] = 2 >>> h["giraffe"] = 3 >>> for key in h.Keys: print key, h[key] dog 1 giraffe 3 cat 2 Of course, if you have consistent types for your keys and values, you can use the .NET generic type, System.Collections.Generic.Dictionary; well discuss how to use generics in the next section.
3.10 Functions
Defining a function is done with the def keyword. Heres a simple example: >>> def myfunc(x): return(x+1) >>> myfunc(1) 2 We can call myfunc with arbitrary arguments, but not all arguments will provide the desired results!
21
>>> myfunc("a") Error: unsupported operand type(s) for +: 'str' and 'int' at myfunc$687$41.myfunc$687(PythonFunction $function, Object x) in <string>: on or before line 2 at myfunc: line 2
3.10.3 Yield
They say its better to give than receive, so if youre tired of consuming and manipulating lists made by others, you can produce enumerable lists with the yield command. Yield is like a fancy version of return that produces an enumerator object (called a generator in Python parlance). You can call the next method
22
on the generator object to get values in the sequence, or use it in anywhere an enumerable collection is appropriate: >>> def yielder(): res = "" for i in range(10): res = res+"foo" yield(res) >>> y = yielder() >>> print y.next() foo >>> print y.next() foofoo >>> for s in y: print s foofoofoo foofoofoofoo foofoofoofoofoo foofoofoofoofoofoo foofoofoofoofoofoofoo foofoofoofoofoofoofoofoo foofoofoofoofoofoofoofoofoo foofoofoofoofoofoofoofoofoofoo
3.11 Classes
Defining classes is accomplished with the class keyword. Heres an example: >>> class myclass(object): y = 5 def __init__(self): self.x = self.y + 1 # this is the y defined above def addto(self,y): return(self.x+y) # this uses the passed in y >>> c = myclass() >>> c.x 6 >>> c.y 5 >>> c.addto(4) 10 A few important things to notice in that example: Here we inherit from the base object class by putting the parent class name in parentheses after the class name The constructor is called __init__ There is an explicit self argument to all methods, which is the this pointer for the object. This is handy when you want to call methods from a subclass just call baseclass.method(self, args) Inside methods, all member variables must be referred to in terms of self: self.x will be the member variable, whereas x will just be a local variable in the method.
23
You can declare a class variable either in the constructor or in the body of the class definition (outside of any method definition).
If you are inheriting from something more interesting than just object, you can directly call methods on the superclass by directly calling its methods, as seen in the constructor below. Note you can subclass .NET classes as well as IronPython classes. >>> class subclass(myclass): def __init__(self): self.y = 4 myclass.__init__(self) def addmore(self, z): return(self.x+self.y+z) >>> >>> 5 >>> 4 >>> 14 s = subclass() s.x s.y s.addmore(5)
3.12.1 Execfile
The execfile(filename) function interprets the file as though youd typed it in. This is the classic scripting model:
24
>>> execfile("myfile.py") >>> foo 4 >>> testfunc(2) 4 This is convenient when youre doing the same thing over and over again, but too much of it leads to poor modularity. If you find yourself doing this a lot or on really long files, you should start thinking about making them into modules and importing them, as we discuss below. Note that execfile does not search through the IronPython path, so youll have to either cd to the proper directory or fully qualify the filename.
3.12.2 Import
Import interprets everything in the file and puts it into a namespace that defaults to the filename root. All variables, classes, and functions are accessible, but must be qualified with this namespace. For instance: >>> import myfile >>> foo Error: name 'foo' not defined Stack Trace: IronPython.Runtime.Exceptions.PythonNameErrorException: name 'foo' not defined >>> myfile.foo 4 >>> myfile.testfunc(2) 4 Now lets say you edit myfile.py to change the behavior of some function. Youd think you can just import again, right? Python doesnt work that way, and its actually to make things more efficient if you have a bunch of modules that are importing the same module, this prevents multiple re-interpretings. To force an update, you have to use the reload command: >>> myfile.foo 4 # now update myfile.py so that foo = 5 >>> reload(foo) <module myfile from "C:\test\myfile.py"> >>> myfile.foo 5 Python files can themselves import other modules (and must, if they want to use other functionality). Such modules, then, will exist inside the namespace of the module youve imported. Lets say myfile.py imports yourfile, and yourfile implements a function called bar. Then if you import myfile, bar can be accessed as myfile.yourfile.bar. If thats inconvenient, of course you can import bar at the top level. Another subtlety to keep in mind is that reload does not work recursively. Thus, if myfile imports yourfile as above, and you edit/save yourfile.py, calling reload(myfile) will not update the behavior of yourfile. To do that youll have to do reload(myfile.yourfile). If youve updated myfile as well, youll then have to reload(myfile). If youre not happy with the default name of your module, you can change it with the as keyword. This is especially useful for collapsing multilevel namespaces:
25
3.13 Exceptions
Exception handling in Python works beautifully with exception handling in .NET. Essentially, .NET exceptions are passed up to IronPython and can be dealt with from the interpreter level. As shown below, you can catch a particular exception with try: <block> except exceptionname:, or catch them all with except:. Heres how it works: >>> try: print a except NameError: print "a is not defined!" unknown error: name 'a' is not defined >>> try: a = "foo"+234 except: msg, stacktrace = geterror() print message unsupported operand type(s) for +: 'str' and 'int'
26
Note that the geterror() function returns both the error message and the stack trace; the latter contains line number information and can be quite helpful if the error is occurring in a function or method defined in a module. You can also create your own exceptions via the raise(obj) command, where obj can be a class or instance. Its best to use System.Exception objects or derive your own exceptions from that; that way the usual exception-processing pipeline will be able to handle your exceptions: >>> raise System.Exception("something went terribly, terribly wrong") Error: something went terribly, terribly wrong
3.14 ShoThreads
IronPython does not have its own threads, but Sho has a threading facility, called ShoThreads, based on the native .NET threading model. While it is possible to use .NET threads directly, we recommend against this, since an exception in a raw .NET thread will break all of IronPython. ShoThreads catch any errors and print them to the console. ShoThreads also allow you to specify a tag, so you have anonymous threads you need to kill or otherwise manage you can find them with lsShoThreads(). For instance, we can define a simple loop and put it in a thread: >>> def loop(): while True: print "foo" System.Threading.Thread.Sleep(100) >>> t = ShoThread(loop, "test thread") >>> t.Start() foo foo foo >>> t.Abort() Some useful things to know about ShoThreads: The function you pass in to the constructor cant take any arguments Once you start a thread, youll get back control of the command prompt You can list currently running ShoThreads via the lsShoThreads() command You can kill an individual ShoThread via killShoThreadByIndex(index) You can set the ApartmentState to STA or MTA using the third argument to the constructor
Heres another example, showing how to put up a .NET Form in its own thread in just three lines of code: >>> f = System.Windows.Forms.Form(Text="hello world") >>> t = ShoThread(f.ShowDialog) >>> t.Start() Below we show the resulting window, which you can move around, refresh, iconify, close, etc. (since the thread is running the message pump with ShowDialog).
27
Figure 3.1: A .NET Form in its own thread in three lines of code.
28
29
>>> DoubleArray.From([[1,2],[3,4]]) [ 1.0000 2.0000 3.0000 4.0000] >>> a = DoubleArray.From([ [[1,2],[3,4]] , [[5,6],[7,8]] ]) # returns a 2x2x2 array >>> a[0,:,:].Squeeze() [ 1.0000 2.0000 3.0000 4.0000] >>> a[1,:,:].Squeeze() [ 5.0000 6.0000 7.0000 8.0000] The utility functions eye and ones let you quickly create identity matrices and matrices filled with ones. >>> eye(3,3) [ 1.0000 0.0000 0.0000 0.0000 1.0000 0.0000 0.0000 0.0000 1.0000] To create matrices out of other matrices, you can use the <type>Array.HorizStack and <type>Array.VertStack commands: >>> DoubleArray.HorizStack(eye(2,2), eye(2,2)) [ 1.0000 0.0000 1.0000 0.0000 0.0000 1.0000 0.0000 1.0000] >>> DoubleArray.VertStack(eye(2,2), eye(2,2)) [ 1.0000 0.0000 0.0000 1.0000 1.0000 0.0000 0.0000 1.0000] You can easily create matrices full of random numbers using the rand, randn and randint functions, to produce arrays of uniformly or Gaussian-distributed doubles, or uniformly-distributed integers in a given range: >>> rand(3, 3) [ 0.2886 0.7908 0.5283 0.8500 0.2996 0.2847 0.5477 0.8334 0.1295] >>> randn(3, 3) [-0.3155 0.8782 -0.9785 -1.0173 -0.4855 1.3568 -0.3304 -1.0168 0.7422] >>> randint(3, 3, 100) [ 68 93 93 73 32 87 4 93 59] To fill an existing array with random numbers, use the FillRandom method, which requires you to supply a random number generator object. >>> A.FillRandom(System.Random())
30
31
And, you can do extra fancy stuff with both row and column specifiers: >>> A[3:5:2, 3:5:2] = A[4:6:2, 4:6:2] For 1D arrays, you can access elements in the same way, but only need one index: >>> b = rand(10) >>> b[:5] [ 0.2850 0.4686 0.3585 0.6589 0.0573] >>> b[0:8:3] [ 0.2850 0.6589 0.9287] Now back to the implications of slices being shallow: since what you get back is a view of the underlying data and not a copy of that data, changes to the slice will change the original array you sliced from as well! The example below shows the implications of this: >>> >>> A = eye(3,3) >>> b = A[:,0] # b is a shallow version of part of A >>> b[0] = -1 >>> A [-1.0000 0.0000 0.0000 0.0000 1.0000 0.0000 0.0000 0.0000 1.0000]
# B = A.T * A # C = A * A.T
where is a scalar.
# A = A + 3.0 * B
( ) ( ) MultiplyInto is used to compute , where and are scalars and (T) denotes an optional transpose. This method maps directly into MKLs gemm, so it more efficient than the code that uses operators because it bypasses the copying incurred by using operators.
There are two overloads of this method. The two-parameter version computes the already allocated matrix .
32
The six-parameter version computes transpose, false otherwise). >>> >>> >>> >>> >>>
A = rand(10,10) B = rand(10,10) C = rand(10,10) # Compute A = 3.0 * B * C.T + 4.5 * A A.MultiplyInto(3.0, B, False, C, True, 4.5)
33
The standard math operators have been implemented for sparse arrays: >>> sa1 = SparseDoubleArray(10000, 10000) >>> sa2 = SparseDoubleArray(10000, 10000) >>> sa1[1, 1] = 10 >>> sa1[1, 1] = 1 >>> sa1[1, 2] = 2 >>> sa2[1, 1] = 10 >>> sa2[2, 1] = 20 >>> sa3 = sa1*sa2 >>> for x in sa3.Elements: print x [1,1 -> 50] Note that the implementation of sparse arrays trades off some compactness in the representation for speed in accessing elements. Therefore, an mn array with N nonzero elements uses memory proportional to n plus N.
34
35
>>> A = rand(3, 4) >>> A [ 0.2657 0.2968 0.0606 0.1262 0.3873 0.9614 0.0057 0.1781 0.7405 0.5911 0.9570 0.3714] >>> A.ElementLT(0.5) [ 1 1 1 1 1 0 1 1 0 0 0 1] >>> A<0.5 [ 1 1 1 1 1 0 1 1 0 0 0 1]
36
37
SVD and eigenvalue both include classes (SingularVals, EigenVals) for computing just the singular or eigen values; use these if you do not need the full decomposition, as they will be faster and more memory efficient. The following is an example of using the linear algebra classes: >>> s = SVD(A) >>> A_hat = s.U * s.D * s.V.T >>> norm(A-A_hat, 1) 1.26426646929e-014 Notice here that the SVD class has 3 properties: U (the left singular vectors), D (the diagonal matrix of singular values), and V (the right singular vectors). In addition to the specialized linear algebra classes, the inv and det functions return the inverse and determinant of an array: >>> norm(A*inv(A) - eye(10,10)) 1.3079625534173405e-14 >>> det(A*inv(A)) 1.000000000000006 The generic solver class, Solver, attempts to solve the system by the most appropriate method. After solving, you can check the property MethodUsed to see which method was utilized. For square matrices, the system will be solved by one of the following methods: 1) Cholesky if the matrix is positive-definite. 2) LU if the matrix is not positive-definite and is not rank deficient. 3) SVD if the matrix is rank deficient. For non-square matrices, the system is over or underdetermined. In this case, the system will be solved either by 1) QR if the matrix is not rank-deficient or 2) SVD if the matrix is rank-deficient. >>> a = rand(10,10) >>> c = a * a.T >>> s = Solver(c) >>> x = rand(10,1) >>> b = c * x # create a right hand side >>> s = Solver(a) >>> y = s.Solve(b) # we should get the same as x >>> s.MethodUsed ShoNS.Array.SolverMethod.SolveChol # the Cholesky method was used >>> (x y) # if zeros, we found the solution (printout of 10-element column vector full of zeros suppressed)
38
39
>>> DoubleArray.From(drange(2, 4.5)) # default step size of 1 [ 2.0000 3.0000 4.0000] >>> DoubleArray.From(drange(2.1, 2.6, 0.1)) # specify a step of 0.1 [ 2.1000 2.2000 2.3000 2.4000 2.5000 2.6000] >>> DoubleArray.From(drange(1.0, 2.0, Count=10)) # specify 10 elements [ 1.0000 1.1111 1.2222 1.3333 1.4444 1.5556 1.6667 1.7778 1.8889 2.0000] drange is a .NET IEnumerable object, so you can loop over it: >>> d = drange(0, 1, 0.01) >>> s = 0 >>> for x in d: s = s+x >>> s 50.5 You can also tweak its parameters, and even add, subtract, and multiply it by scalars: >>> d.Begin = -1 >>> d.Step = 0.1 >>> d [-1:0.1:1] >>> e = (d*2-1)/4 >>> e [-0.75:0.05:0.25]
5.3 Histogramming
The Histogram class buckets data into a set of consecutive bins (a related function well see in the next chapter is hist() which both creates and plots the histogram): >>> h = Histogram(A) Histogram automatically chooses buckets and counts the number elements in the input collection that fall into that bucket: >>> h.Count System.Int32[](2, 7, 13, 12, 19, 17, 11, 12, 6, 1) >>> h.BinCenter System.Object[](-1.87989378990, -1.45514758655, -1.03040138320, 0.605655179848, -0.180908976497, 0.243837226854, 0.668583430206, 1.09332963356, 1.51807583691, 1.94282204026) You can also change the number of bins with an optional second argument >>> h = Histogram(A, 20) >>> h.Count System.Int32[](2, 0, 4, 3, 7, 6, 3, 9, 12, 7, 7, 10, 5, 6, 6, 6, 2, 4, 0, 1)
40
Or specify the bin centers, instead, with a second argument that is array-like: >>> h = Histogram([1,1,1,4,5], [1,4]) >>> h.Count System.Int32[](3, 2) If the data in the input collection is discrete, the bins become exact, rather than ranges: >>> a = ['abc', 'abc', 'def', 'ghi'] >>> h = Histogram(a) >>> h.BinCenter System.Object[]('abc','def','ghi') >>> h.Count System.Int32[](2, 1, 1)
41
42
>>> A = csvreadJaggedArray('foo.csv') >>> A.GetType() System.Object[] >>> csvwrite('goo.csv', A) Note that csvreadJaggedArray produces a native .NET object array (Object[]) that contains other Object[]s (if there is only one row or column, it just returns an Object[]). If you want an ObjArray, use csvreadArray, and if you want a DoubleArray, use csvreadDoubleArray (or csvreadFloatArray, etc.). If you want to read a file with a delimeter other than a comma, use one of the dlmread functions: >>> A = dlmreadJaggedArray('foo.dat', '\t') >>> dlmwrite('foo.dat','\t' ,A) To read these into Sho arrays, use the dlmreadArray and dlmreadDoubleArray functions.
43
You can also use DataByCol, which returns one or more columns of the queries, as object[] (for one) or object[object[]] (for multiple): >>> x = db.DataByCol() # get all columns >>> x = db.DataByCol(0) # get the first column (in order specified by select statement) >>> x = db.DataByCol([1,4]) # get the second and fifth columns The database object is smart it only executes the query once, when you first get the data. If you change the command string, it will re-execute the string at the next opportunity.
44
>>> fs = System.IO.File.OpenRead(filename) >>> br = System.IO.BinaryReader(fs) >>> while (True): res = br.ReadBytes(4) id = System.Text.ASCIIEncoding().GetString(res) print id chunkarray = br.ReadBytes(4) System.Array.Reverse(chunkarray) chunklength = System.BitConverter.ToInt32(chunkarray, 0) print chunklength abcd 243
45
46
You can also plot one data series versus another (if theyre of the same length): >>> x = rand(30) >>> plot(x, y, '*')
7.2 Plotting two data series against one another Note that in this case, instead of connecting all of the points (which is the default), we placed a star at every data point, with no line between them. This third (optional) parameter specifies the color and shape of the line and marker through shortcut characters. The color is specified by one character: r = red g = green b = blue k = black y = yellow c = cyan m = magenta w = white
The marker at each point is specified with one character (default is no marker): + = plus sign o = dot * = asterisk . = dot s = square ^ = triangle pointing up v = triangle pointing down
47
When you specify a marker, Sho assumes you dont want to connect the markers. You can tell it to connect with a line by adding one of the following character codes: - = solid line : = dotted line -- = dashed line -. = dash-dot line
Note that you can specify color, shape and/or line style by using a string with multiple characters. So, you can get a blue line with connected square markers by using bs- (or any other order). You can also plot more than one series per plot, mixing and matching styles as you wish: >>> plot(x, 'r^-', y, 'bo')
7.3 Plotting multiple series and styles of data on one set of axes
48
Each series is specified by either 1 or 2 collections, followed by an optional string of shape/color commands. Plot also automatically cycles through colors: >>> plot(x, y, '+', x+1, y, '+', x, y+1, '+', x+1, y+1, '+')
You can also tell the current figure to keep its contents so that further plot commands will add to it using the hold function. >>> >>> >>> >>> figure(1) hold(True) # tells current figure (figure 1) to keep old stuff plot(x, y, 'o') hold(False)
Yet another way to tell Sho to plot multiple figures is to use the grid function. This function sets the current figure to have a fixed number of subplots (rows and columns), and sets the current plot to the first cell. You can target a particular cell with setgridcell. Alternately, you can call autoadvancegrid to automatically advance to the next grid cell after plotting something.
49
grid(1, 2) # make a 1 row, 2 column figure, current cell = (0,0) plot(x) # plot x in the first one setgridcell(0, 1) # now select cell(0,1) plot(y) # plot y in the second one
7.5 Putting multiple plots in one window using the grid command
50
Figure 7.6: Setting custom data labels for a line series There are many other aspects of the plot you can also control, such as the number of horizontal and vertical lines, the spacing of the vertical and horizontal ticks, the fonts of the ticks and axis labels, and much more, which we discuss in the Setting Plot Properties section below.
7.1.3 Legends
You can easily add legends to your plot using the legend command. >>> plot(x, 'r-', y, 'b-') >>> legend("baseline", "new")
51
52
53
54
7.10 A basic bar chart using the bar command You can also plot multiple series on the same bar chart with custom colors and a legend: >>> >>> >>> >>> >>> categories = ['user1', 'user2', 'user3', 'robot'] trial1scores = [1.7, 2.3, 1.8, 5.0] trial2scores = [2.2, 1.9, 1.9, 4.8] bar(categories, trial1scores, 'b', categories, trial2scores, 'r') legend('trial 1', 'trial 2')
55
7.3 DataGridView
If you want to look at the values of your 2D data in an editable grid, you can use the datagrid view, through the dgv function: >>> d = rand(20, 30) >>> dgv(d) This produces a data grid view in a separate window, with scroll bars:
7.12 Viewing and editing tabular data with the dgv command There are a number of optional keyword arguments you can give to dgv in order to customize the way the data is displayed. For instance, you can use the color keyword to have the cells colored according to their value, and set the width of each cell to form a more image-like array: >>> d = DoubleArray.From(drange(0, 1, 0.05)) >>> dgv(d.T*d, color=True, colWidth = 30)
56
Figure 7.13 Using cell coloring with dgv When you put the data grid view into a variable, you can modify its properties after displaying it. So, we could achieve the same display as above with this sequence: >>> g = dgv(d) >>> g.colorize() >>> g.setColWidth(30) The colorization automatically finds the largest and smallest entries of your 2D data. It can also take minVal and maxVal keyword arguments to override those automatic values. Note also that dgv can take multiple data arguments it treats each argument as a column of data, they neednt be the same type or have the same length. In fact, dgv remembers the arguments you pass to it, and if they are mutable objects, it is possible to edit their values from the data grid view. To toggle between edit and read-only modes, you can hit the F2 key (alternately, you can make the view come up in edit mode by setting the keyword parameter edit to True, and you can disable toggling edit mode by setting the keyword parameter locked to True). If the collection you are displaying is a typed collection (an IntArray, for instance), dgv will try to coerce the text you type into the cell into a legal value for that collection. Otherwise, it will set that entry to be the string you typed in. If the values in the collection youve displayed with dgv change, you can hit F5 to refresh the view to reflect the new values.
57
58
Figure 7.15: Viewing an array as an image with imageview By default, the image is scaled to fill the window. Pressing z toggles between scale-to-fit mode and manual zooming mode. In manual mode, the +/- keys zoom the image in and out, and hitting <space> sets the zoom level so that 1 pixel represents 1 value in the underlying dataset. The s key switches between nearest-neighbor (the default) and bilinear interpolation when zoomed in on an image. If you want the bitmap itself, you can create it via the arrayimage function. The resulting bitmap can then be passed to imageview in order to display it. Of course, the imageview command can also be used directly on .NET Image and Bitmap objects: >>> img = System.Drawing.Image.FromFile("d:/images/madblogsmall.jpg") >>> imageview(img)
59
7.17 Displaying interactive histograms with the hist command Note that hist and Histogram both take the same optional arguments hist simply passes its arguments along to Histogram.
60
7.18 Displaying inline plots in the Sho Console with the show command
61
Chapter 8: .NET
This chapter will show you how to connect to the vast world of .NET libraries and utilities from Sho. Fortunately, this is very easy, again due to the power of IronPython all .NET objects are first class objects in IronPython, and you can freely access them. In the following sections, we will show you how to load and use existing .NET libraries.
62
63
// addstuff.cs namespace AddStuff { public class MyAdder { public int hello() { System.Console.Out.Write("foo\n"); return 43; } } } To use this, load the .cs file and then import the namespace. The load command will invoke the C# compiler and load the assembly. >>> load("addstuff.cs") csc.exe /target:library /out:"C:\Users\sumitb\AppData\Local\Temp\sho_tmp58CTBLSGBU5HREJAU9O0233 F4\addstuff_3ZCZ74AL069ZLZMRJ4WGTH85D.dll" /debug "c:\src\sho2\Sho\Current\playpen\addstuff.cs" Microsoft (R) Visual C# 2005 Compiler version 8.00.50727.4927 >>> import addstuff >>> m = addstuff.MyAdder() >>> m.hello() 42 If you have additional arguments you need to give the compiler, you can fully specify the command line via a comment line at the top of the file that starts with cscargs:. In the example below, matrixexample.cs (also in {SHODIR}\playpen), we create a C# file which will horizontally flip a DoubleArray. Since it takes and returns DoubleArrays, we need to reference the appropriate assemblies: // matrixexample.cs // // cscargs: /r:"{SHODIR}\bin\MatrixInterf.dll" \ /r:"{SHODIR}\bin\ShoArray.dll" /debug /target:library using ShoNS.Array; namespace matrixexample { public class tester { public DoubleArray fliphoriz(DoubleArray d) { DoubleArray e = new DoubleArray(d.Size[0],d.Size[1]); for (int i = 0; i < d.Size[0]; i++) { for (int j = 0; j < d.Size[1]; j++) { e[i,j] = d[i,d.Size[1]-1-j]; } } return(e); } } }
65
Note that the {VARNAME} notation expands environment variables; in the example above SHODIR is set to c:\Program Files\Sho. We can now load this just like the previous C# file: >>> load("matrixexample.cs") >>> import matrixexample >>> t = matrixexample.tester() >>> t.fliphoriz(DoubleArray.From([1,2,3,4,5])) [5.0000 4.0000 3.0000 2.0000 1.0000] Note that we can now update testmatrix.cs to change its behavior and load it again; new instances of testmatrix.tester will then reflect the new behavior.
Figure 9.1: Setting up Strong Naming (aka Assembly Signing) in the Properties pane of a C# project 66
Turn on the check mark for Sign the Assembly, and then select <New> under the Choose a strong name key file drop down. Youll have the option of choosing a password to protect your keyfile, which you most likely dont need.
Note that instead of the addpath command, we could also have specified the full path for load. Again, note that we need to load the assembly and then import the namespace. When we want to update the code/assembly and reload it, we first rebuild the assembly from Visual Studio, and then load it back into Sho: # update C# file in Visual Studio so c.message is hello world # and rebuild the dll >>> load("CSharpLibraryExample.dll") >>> c = CSharpLibraryExample.Class1() >>> c.message "hello world"
67
Note that we didnt have to re-import the namespace, but we did have to re-load the new assembly, as well as re-instantiate the variables; this resulted in the new behavior of the class. If we didnt reinstantiate c, it would still have its old behavior in fact, the old dll is still attached to the process, and we could even have saved its namespace by setting CSharpLibraryExample_old = CSharpLibraryExample before re-loading.
Figure 9.2: Debugging a C# project while it's being called from Sho
68
# __init__.py - sample package sho_import_list = ['testvar', 'testfunc', 'testclass'] testvar = "hello" def testfunc(x): return (2*x) class testclass: def __init__(self): x = 3 y = 4 def hello(self, z): return(z*2) def dontimportme(x): print x The package directory may contain additional Python files, DLLs, or any other resources necessary for your package. This way, you can easily send a package to a colleague or prepare for posting your package to the web by simply zipping up the directory for your package.
69
70
71
static void Main(string[] args) { // create the Embedded Sho System.Console.Write("Starting Embedded Sho..."); // the path argument below should point to what "SHODIR" evaluates // to in Sho EmbeddedSho es = new EmbeddedSho("c:/src/sho2/sho/current"); System.Console.Write("done.\n"); // es.CacheShoOutput will store the output from Sho so you can show // it in a form, etc; // if you don't call this the default is to print the output to //the console. es.CacheShoOutput(); // create a class from the containing assembly TestClass t = new TestClass(); // put it into the Sho environment es.SetPythonVariable("tc", t); // do some Sho stuff es.ExecutePython("a = rand(10,10)"); es.ExecutePython("foo = a[0,0]"); // print information from the class es.ExecutePython("print tc.info"); // print cached output from Sho System.Console.WriteLine("{0}", es.GetOutputText()); es.ExecutePython("plot([1,2,3,4,5])"); // get the result in res so we can bring it back to C# es.ExecutePython("res = tc.info"); es.ExecutePython("for x in range(10): print x"); // print cached output text. This can be called as often as //you wish; the text is flushed each time. System.Console.WriteLine("{0}", es.GetOutputText()); // get back and print Sho values // note that GetPythonVariable will return an Object, which we //can cast to a known type System.Console.WriteLine("foo: {0}", es.GetPythonVariable("foo")); // alternatively, we can use GetPythonVariableAs<type>, which //will cast it to the type in one call. System.Console.WriteLine("res: {0}", es.GetPythonVariableAs<String>("res")); } An example project showing how to call Sho code from C# can be found in the {SHODIR}\playpen directory.
72
73
(Note the try/except around the Click handler function: this is to make sure that the user never gets a popup error message.) Now we can create a fibdisp form and put it in its own thread: >>> f = fibdisp() >>> t = ShoThread(f.ShowDialog) >>> t.Start() Which will produce the window below. Its very easy to make a simple GUI to display the output of some Python script (or other piece of code) this way.
Figure 11.1 Creating a simple GUI in Sho Note that while some Forms functionality, like setting the text of the textbox, can be called from the console thread (as opposed to the thread that the form is running on), other functionality, like adding widgets, need to be invoked on the Forms thread. For instance, if we just tried to add a Button to the form, wed see an error: >>> b = Button() >>> f.Controls.Add(b) Error: Controls created on one thread cannot be parented to a control on a different thread. To do this properly, well need to use the Forms Invoke method and pass it a delegate for a function that will add the button; this will execute the function in the context of the Forms thread. To create a delegate, well use the System.Action class (if our function returned a value wed use System.Func instead). >>> def foo(): f.Controls.Add(b) >>> f.Invoke(System.Action(foo)) Since this is such a common task, weve created a couple of convenience functions in Sho to make it easier: >>> AddControl(f, b) >>> RemoveControl(f, b) # add the button to form f # ...and then remove it
74
Figure 12.1: The dialog box in Visual Studio that appears after Debug->Attach to Process (in VS 2008) or Tools->Attach to Process (in VS 2010)
75
You can import the Python file into the Sho process before or after this point. If you set breakpoints in your Python code (or your C# code called from Python), the debugger will stop there as shown in the figure below. You can then step through the code, step into and over functions, examine local variables, etc.
76
77