You can subscribe to this list here.
2003 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(1) |
Nov
(33) |
Dec
(20) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2004 |
Jan
(7) |
Feb
(44) |
Mar
(51) |
Apr
(43) |
May
(43) |
Jun
(36) |
Jul
(61) |
Aug
(44) |
Sep
(25) |
Oct
(82) |
Nov
(97) |
Dec
(47) |
2005 |
Jan
(77) |
Feb
(143) |
Mar
(42) |
Apr
(31) |
May
(93) |
Jun
(93) |
Jul
(35) |
Aug
(78) |
Sep
(56) |
Oct
(44) |
Nov
(72) |
Dec
(75) |
2006 |
Jan
(116) |
Feb
(99) |
Mar
(181) |
Apr
(171) |
May
(112) |
Jun
(86) |
Jul
(91) |
Aug
(111) |
Sep
(77) |
Oct
(72) |
Nov
(57) |
Dec
(51) |
2007 |
Jan
(64) |
Feb
(116) |
Mar
(70) |
Apr
(74) |
May
(53) |
Jun
(40) |
Jul
(519) |
Aug
(151) |
Sep
(132) |
Oct
(74) |
Nov
(282) |
Dec
(190) |
2008 |
Jan
(141) |
Feb
(67) |
Mar
(69) |
Apr
(96) |
May
(227) |
Jun
(404) |
Jul
(399) |
Aug
(96) |
Sep
(120) |
Oct
(205) |
Nov
(126) |
Dec
(261) |
2009 |
Jan
(136) |
Feb
(136) |
Mar
(119) |
Apr
(124) |
May
(155) |
Jun
(98) |
Jul
(136) |
Aug
(292) |
Sep
(174) |
Oct
(126) |
Nov
(126) |
Dec
(79) |
2010 |
Jan
(109) |
Feb
(83) |
Mar
(139) |
Apr
(91) |
May
(79) |
Jun
(164) |
Jul
(184) |
Aug
(146) |
Sep
(163) |
Oct
(128) |
Nov
(70) |
Dec
(73) |
2011 |
Jan
(235) |
Feb
(165) |
Mar
(147) |
Apr
(86) |
May
(74) |
Jun
(118) |
Jul
(65) |
Aug
(75) |
Sep
(162) |
Oct
(94) |
Nov
(48) |
Dec
(44) |
2012 |
Jan
(49) |
Feb
(40) |
Mar
(88) |
Apr
(35) |
May
(52) |
Jun
(69) |
Jul
(90) |
Aug
(123) |
Sep
(112) |
Oct
(120) |
Nov
(105) |
Dec
(116) |
2013 |
Jan
(76) |
Feb
(26) |
Mar
(78) |
Apr
(43) |
May
(61) |
Jun
(53) |
Jul
(147) |
Aug
(85) |
Sep
(83) |
Oct
(122) |
Nov
(18) |
Dec
(27) |
2014 |
Jan
(58) |
Feb
(25) |
Mar
(49) |
Apr
(17) |
May
(29) |
Jun
(39) |
Jul
(53) |
Aug
(52) |
Sep
(35) |
Oct
(47) |
Nov
(110) |
Dec
(27) |
2015 |
Jan
(50) |
Feb
(93) |
Mar
(96) |
Apr
(30) |
May
(55) |
Jun
(83) |
Jul
(44) |
Aug
(8) |
Sep
(5) |
Oct
|
Nov
(1) |
Dec
(1) |
2016 |
Jan
|
Feb
|
Mar
(1) |
Apr
|
May
|
Jun
(2) |
Jul
|
Aug
(3) |
Sep
(1) |
Oct
(3) |
Nov
|
Dec
|
2017 |
Jan
|
Feb
(5) |
Mar
|
Apr
|
May
|
Jun
|
Jul
(3) |
Aug
|
Sep
(7) |
Oct
|
Nov
|
Dec
|
2018 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
(2) |
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
S | M | T | W | T | F | S |
---|---|---|---|---|---|---|
1
(3) |
2
(7) |
3
(5) |
4
(1) |
5
(36) |
6
(36) |
7
|
8
(7) |
9
(23) |
10
(24) |
11
(6) |
12
(16) |
13
(34) |
14
(5) |
15
|
16
(34) |
17
(25) |
18
(13) |
19
(26) |
20
(64) |
21
(26) |
22
(20) |
23
(10) |
24
(24) |
25
(23) |
26
(13) |
27
(15) |
28
(1) |
29
(4) |
30
(9) |
31
(9) |
|
|
|
|
On Tuesday 31 July 2007 02:12:06 pm you wrote: > Looking at the profile outputs, a couple of things stand out in the new > version. =A0First, various Traits things are prominent near the top. pycachegrind is telling me that traits_db is responsible for about 20%,=20 configobj is responsible for about 30%, and the config package another 30%. > Second, look at the lines for posixpath functions, which are taking > quite a bit of time. =A0Here are two examples: > > =A0 =A0 =A0 5651 =A0 =A00.108 =A0 =A00.000 =A0 =A00.188 =A0 =A00.000 posi= xpath.py:56(join) > [...] > =A0 =A0 =A0 =A0273 =A0 =A00.012 =A0 =A00.000 =A0 =A00.164 =A0 =A00.001 po= sixpath.py:410(realpath) > > If I understand correctly, path.join is being called 5651 times! =A0And > realpath is being called 273 times! =A0 I think the posix_path stuff is being called most often by python while it= =20 attempts to locate modules.=20 [...] > I would not like to see mpl become a library that is painfully sluggish > to start up; it is already too slow for my liking, with font setup being > a major contributor. I agree. Darren
On 7/31/07, Michael Droettboom <md...@st...> wrote: > Eric Firing wrote: > > I don't have a lot of experience with profiling... > Slightly OT, but I do have a recommendation for anyone doing Python > profiling. I don't usually get very excited about GUI tools, but > KCachegrind (Linux only) is very slick and works great with Python. > It's really handy to be able to "browse" the calltree interactively to > explore what's going on. > > The trick (which is very non-obvious from the documentation), is that > you use Python's 'hotspot' profiler, then convert that to 'calltree' > format using hotspot2calltree (included with KCachegrind), and then load > that with KCachegrind. > > Just my two cents for something you may want to try, Yup. The link I posted earlier is basically a little wrapper that does all that. I wrote it so you wouldn't have to think :) I keep it in my path and can profile any python script with kcachegrind just by running one command. And yes, kcachegrind rocks. I'm also very much a non-gui person, yet I've found it invaluable for doing really complex profiling of very large python codes. Cheers, f
Eric Firing wrote: > I don't have a lot of experience with profiling... Slightly OT, but I do have a recommendation for anyone doing Python profiling. I don't usually get very excited about GUI tools, but KCachegrind (Linux only) is very slick and works great with Python. It's really handy to be able to "browse" the calltree interactively to explore what's going on. The trick (which is very non-obvious from the documentation), is that you use Python's 'hotspot' profiler, then convert that to 'calltree' format using hotspot2calltree (included with KCachegrind), and then load that with KCachegrind. Just my two cents for something you may want to try, Mike
Darren, The two cases you ran have almost identical timing, so the problem is not in reading matplotlib.conf. Instead, it seems to be in the initialization of all the machinery, and I suspect that something may be getting run many times in a loop instead of just once. I used the profile.py script method to profile the whole simple_plot.py demo modified to use Agg, with NEWCONFIG True versus False. Attached are the top 100 lines of the output, sorted by cumulative time, with "new" meaning NEWCONFIG=True. The execution time of the new version is 3.2 seconds versus 1.8 for the old. (Both are pretty slow for making a minimal plot from a script.) Looking at the profile outputs, a couple of things stand out in the new version. First, various Traits things are prominent near the top. Second, look at the lines for posixpath functions, which are taking quite a bit of time. Here are two examples: 5651 0.108 0.000 0.188 0.000 posixpath.py:56(join) [...] 273 0.012 0.000 0.164 0.001 posixpath.py:410(realpath) If I understand correctly, path.join is being called 5651 times! And realpath is being called 273 times! Now, these calls are contributing only a little to the total time difference between the mpl versions, but they may be providing clues as to what is wrong. My guess is that there is a glitch in the program logic that is causing some operations that should be done once or a few times to be done hundreds or thousands of times, and this will turn out to be the biggest factor in the slowdown. If so, then we will still have to see whether a significant slowdown remains after the glitch is corrected. I don't have a lot of experience with profiling, but it seems to me that ordering results by cumulative time is good for finding the major operations that are slow, whereas ordering by time is good for finding the lowest-level functions that are holding things up. Ordering by time shows these as the top two for the new system: 32581/31616 0.152 0.000 0.168 0.000 :0(len) 98 0.132 0.001 0.372 0.004 has_traits.py:558(__init__) This doesn't mean that the len builtin is too slow, but that it is getting called a lot of times, and we have to look elsewhere to figure out how to reduce that, if possible. The second line, however, suggests to me that even after the glitch problem is solved, we will be stuck with a distressing startup overhead from using traits. This line is saying that we are initializing 98 trait instances, and this initialization alone is taking 0.37 seconds, of which 0.13 seconds is in the init code, not in functions that it is calling. If you look at the code for that __init__, you will see that it is huge. It may be that the traits overhead is small once a program is up and running, but it certainly looks to me like the startup overhead is a killer if more than a few traits are to be used. I would not like to see mpl become a library that is painfully sluggish to start up; it is already too slow for my liking, with font setup being a major contributor. Eric Darren Dale wrote: > On Monday 30 July 2007 07:10:01 pm Eric Firing wrote: >> Darren Dale wrote: >>> I just committed changes in svn that will allow matplotlib to use the >>> experimental traited mplconfig module. The traited config object itself >>> is called mplConfig, but I wrapped it in an object called rcParams to >>> make it compatible with matplotlib, so we can kick the tires without >>> extensive changes. >> Darren, >> >> There is *major* speed problem. Running "backend_driver.py Template": >> >> 0.95 minutes with NEWCONFIG = True >> 0.51 minutes False > > I used the following script in the matplotlib/config directory to profile the > mplconfig module: > def main(): > import mplconfig > > if __name__=='__main__': > import profile > import pstats > profile.run('main()', 'config.prof') > > p = pstats.Stats('config.prof') > p.sort_stats('cumulative').print_stats(55) > > I am attaching the results for two different tests. One is loading the default > mpl-data/matplotlib.conf, the other is loading an empty > ~/.matplotlib/matplotlib.conf. I haven't done much work with profiling, maybe > others can make some comments about the results.
On 7/31/07, Darren Dale <dd...@co...> wrote: > I am attaching the results for two different tests. One is loading the default > mpl-data/matplotlib.conf, the other is loading an empty > ~/.matplotlib/matplotlib.conf. I haven't done much work with profiling, maybe > others can make some comments about the results. I'm afraid I can't help with this right now, but you may want to look at http://amath.colorado.edu/faculty/fperez/python/profiling/ the little code I put in there makes using kcachegrind very easy for python profiling, and it's really a useful tool for analyzing profiling info. Cheers, f
On Tuesday 31 July 2007 11:08:42 am Darren Dale wrote: > On Monday 30 July 2007 07:10:01 pm Eric Firing wrote: > > Darren Dale wrote: > > > I just committed changes in svn that will allow matplotlib to use the > > > experimental traited mplconfig module. The traited config object itself > > > is called mplConfig, but I wrapped it in an object called rcParams to > > > make it compatible with matplotlib, so we can kick the tires without > > > extensive changes. > > > > Darren, > > > > There is *major* speed problem. Running "backend_driver.py Template": > > > > 0.95 minutes with NEWCONFIG = True > > 0.51 minutes False > > I used the following script in the matplotlib/config directory to profile > the mplconfig module: > def main(): > import mplconfig > > if __name__=='__main__': > import profile > import pstats > profile.run('main()', 'config.prof') > > p = pstats.Stats('config.prof') > p.sort_stats('cumulative').print_stats(55) sorry, that should say 'time' instead of 'cumulative' > I am attaching the results for two different tests. One is loading the > default mpl-data/matplotlib.conf, the other is loading an empty > ~/.matplotlib/matplotlib.conf. I haven't done much work with profiling, > maybe others can make some comments about the results.
On Monday 30 July 2007 07:10:01 pm Eric Firing wrote: > Darren Dale wrote: > > I just committed changes in svn that will allow matplotlib to use the > > experimental traited mplconfig module. The traited config object itself > > is called mplConfig, but I wrapped it in an object called rcParams to > > make it compatible with matplotlib, so we can kick the tires without > > extensive changes. > > Darren, > > There is *major* speed problem. Running "backend_driver.py Template": > > 0.95 minutes with NEWCONFIG = True > 0.51 minutes False I used the following script in the matplotlib/config directory to profile the mplconfig module: def main(): import mplconfig if __name__=='__main__': import profile import pstats profile.run('main()', 'config.prof') p = pstats.Stats('config.prof') p.sort_stats('cumulative').print_stats(55) I am attaching the results for two different tests. One is loading the default mpl-data/matplotlib.conf, the other is loading an empty ~/.matplotlib/matplotlib.conf. I haven't done much work with profiling, maybe others can make some comments about the results.
Hi Eric, On Monday 30 July 2007 10:14:22 pm Eric Firing wrote: > I have not made any matplotlib.conf other than the one that is now being > installed correctly in mpl-data, and it contains > > # display grid on regular or polar axes > grid = False > polargrid = True > > grep indicates the True value is coming from mplconfig: > > config/mplconfig.py: grid = T.Trait(True, mplT.BoolHandler()) > > config/rcsetup.py: 'axes.grid' : [False, validate_bool] > > so it looks like somehow this mplconfig initialization is overriding the > value in matplotlib.conf. Ok, sorry for the confusion. There were two problems: -The .conf file in mpl-data was not being read. It is fixed in svn 3645. -The .conf file is not auto-generated by setup.py. This is a more difficult problem, so I am not going to work on it unless we decide to adopt the new module. In the mean time, the file can be auto-generated by running mplconfig. Darren
Darren Dale wrote: > On Monday 30 July 2007 6:58:17 pm Eric Firing wrote: >> Darren, >> >> It looks like there is a problem with the grid lines. Although the >> matplotlib.conf file is specifying linestyle = ':', and False for the >> axes.grid parameter, everything is coming up with solid lines (see >> barh_demo.py, for example) by default. It looks like those two keys are >> not setting their respective rcParams entries. > > barh_demo turns the grid on. I accidentally set the default linestyle to '-' > in mplconfig for the grids, thats been fixed. Darren, barh_demo turns the grid on for the first plot only, but the grid is shown for both. ipython -pylab also plots with a grid by default, and shows In [3]:rcParams['axes.grid'] Out[3]:True I have not made any matplotlib.conf other than the one that is now being installed correctly in mpl-data, and it contains # display grid on regular or polar axes grid = False polargrid = True grep indicates the True value is coming from mplconfig: config/mplconfig.py: grid = T.Trait(True, mplT.BoolHandler()) config/rcsetup.py: 'axes.grid' : [False, validate_bool] so it looks like somehow this mplconfig initialization is overriding the value in matplotlib.conf. Eric
On Monday 30 July 2007 6:58:17 pm Eric Firing wrote: > Darren, > > It looks like there is a problem with the grid lines. Although the > matplotlib.conf file is specifying linestyle = ':', and False for the > axes.grid parameter, everything is coming up with solid lines (see > barh_demo.py, for example) by default. It looks like those two keys are > not setting their respective rcParams entries. barh_demo turns the grid on. I accidentally set the default linestyle to '-' in mplconfig for the grids, thats been fixed.
On Monday 30 July 2007 7:10:01 pm Eric Firing wrote: > Darren Dale wrote: > > I just committed changes in svn that will allow matplotlib to use the > > experimental traited mplconfig module. The traited config object itself > > is called mplConfig, but I wrapped it in an object called rcParams to > > make it compatible with matplotlib, so we can kick the tires without > > extensive changes. > > Darren, > > There is *major* speed problem. Running "backend_driver.py Template": > > 0.95 minutes with NEWCONFIG = True > 0.51 minutes False It looks like creating the mplConfig object is adding to the startup time. I'll look into it when I get a chance. Darren
Darren Dale wrote: > I just committed changes in svn that will allow matplotlib to use the > experimental traited mplconfig module. The traited config object itself is > called mplConfig, but I wrapped it in an object called rcParams to make it > compatible with matplotlib, so we can kick the tires without extensive > changes. Darren, There is *major* speed problem. Running "backend_driver.py Template": 0.95 minutes with NEWCONFIG = True 0.51 minutes False Eric
Darren, It looks like there is a problem with the grid lines. Although the matplotlib.conf file is specifying linestyle = ':', and False for the axes.grid parameter, everything is coming up with solid lines (see barh_demo.py, for example) by default. It looks like those two keys are not setting their respective rcParams entries. Eric
Darren, When I make a clean build and install, set NEWCONFIG, and try to run I get a permission problem. It looks like the problem is that the global matplotlib.conf is not getting generated and installed at build/install time, but I have not investigated it. Eric convert! Traceback (most recent call last): File "backend_driver.py", line 20, in <module> import matplotlib.backends as mplbe File "/usr/local/lib/python2.5/site-packages/matplotlib/__init__.py", line 712, in <module> from config import rcParams, rcdefaults File "/usr/local/lib/python2.5/site-packages/matplotlib/config/__init__.py", line 10, in <module> from mplconfig import rcParams, mplConfig, save_config, rcdefaults File "/usr/local/lib/python2.5/site-packages/matplotlib/config/mplconfig.py", line 473, in <module> filePriority=True) File "/usr/local/lib/python2.5/site-packages/matplotlib/config/tconfig.py", line 549, in __init__ rconf = RecursiveConfigObj(configFilename) File "/usr/local/lib/python2.5/site-packages/matplotlib/config/tconfig.py", line 311, in __init__ self.conf = self._load(filename) File "/usr/local/lib/python2.5/site-packages/matplotlib/config/tconfig.py", line 314, in _load conf = mkConfigObj(filename,makeMissingFile) File "/usr/local/lib/python2.5/site-packages/matplotlib/config/tconfig.py", line 289, in mkConfigObj unrepr=True) File "/usr/local/lib/python2.5/site-packages/matplotlib/config/configobj.py", line 1189, in __init__ h = open(infile, 'w') IOError: [Errno 13] Permission denied: '/usr/local/lib/python2.5/site-packages/matplotlib/mpl-data/matplotlib.conf'
On Monday 30 July 2007 4:49:24 pm Eric Firing wrote: > Darren, > > When I make a clean build and install, set NEWCONFIG, and try to run I > get a permission problem. It looks like the problem is that the global > matplotlib.conf is not getting generated and installed at build/install > time, but I have not investigated it. That was exactly the problem, I forgot to add the new file to the setup script. It is fixed in svn 3640. Darren
Darren Dale wrote: > On Monday 30 July 2007 03:33:11 pm you wrote: > >> Darren Dale wrote: >> >>> I ran backend_driver with the traited config enabled, and the only errors >>> I got were related to broken mathtext support in backend_svg, and I think >>> those are unrelated to my changes. >>> >> I think I broke that for a few hours this morning, but it's working for >> me now. Next time you update, please let me know if it still isn't >> working for you. >> > > It's still broken here: > > File "/usr/lib64/python2.5/site-packages/matplotlib-0.90.1_r3636-py2.5-linux-x86_64.egg/matplotlib/backends/backend_svg.py", > line 378, in _draw_mathtext > (fontsize, fontname)) > NameError: global name 'fontname' is not defined > Should be fixed now. The bug was only exercised when svg.embed_char_paths was turned off. Cheers, Mike
Darren Dale wrote: > I ran backend_driver with the traited config enabled, and the only errors I > got were related to broken mathtext support in backend_svg, and I think those > are unrelated to my changes. > I think I broke that for a few hours this morning, but it's working for me now. Next time you update, please let me know if it still isn't working for you. Cheers, Mike
Hi all, this is mostly for those of you using TConfig for the rcparams work, I suppose. IPython has now traits-aware 'smart' tab-completion. Svn update ipython to r2568 at least. You'll get: http://projects.scipy.org/ipython/ipython/browser/ipython/trunk/IPython/Extensions/ipy_traits_completer.py >From the module docstring, this is how it works: Usage ===== The system works as follows. If t is an empty object that HasTraits, then (assuming the threshold is at the default value of 3): In [7]: t.ed<TAB> doesn't show anything at all, but: In [7]: t.edi<TAB> t.edit_traits t.editable_traits shows these two names that come from traits. This allows you to complete on the traits-specific names by typing at least 3 letters from them (or whatever you set your threshold to), but to otherwise not see them in normal completion. ###### Let me know if that sounds like a reasonable solution, it was the best I could think of. Cheers, f
On Sun, Jul 29, 2007 at 09:03:30AM +0900, Bill Baxter wrote: > Curious, I gave it a try in photoshop. I think you have to line up the > doorways & windows to see the effect. > I see someone who looks kinda like they're holding a baby, but I don't = know > what a Templar knight is supposed to look like, so I'm not sure if I sa= w that > or not. The picture on the website is a chalk reproduction of the original, so I doubt whether you would see anything there. Of course, to see anything in the first place requires a healthy amount of imagination :) Here is a copy of the original, with its mirror-image aligned and super-imposed. http://mentat.za.net/results/last_supper_mirror.jpg Cheers St=E9fan
probably more like this <a href="http://img407.imageshack.us/my.php?image=lsoo4.jpg" target="_blank"><img src="http://img407.imageshack.us/img407/2514/lsoo4.th.jpg" border="0" alt="Free Image Hosting at www.ImageShack.us" /></a>
Curious, I gave it a try in photoshop. I think you have to line up the doorways & windows to see the effect. I see someone who looks kinda like they're holding a baby, but I don't know what a Templar knight is supposed to look like, so I'm not sure if I saw that or not. --bb On 7/29/07, Darren Dale <dd...@co...> wrote: > > I just saw this article on Reuters, which covers a theory that if you > superimpose DaVinci's Last Supper with its own mirror image, you get a new > image of a Templar night and someone holding a small baby: > > > http://news.yahoo.com/s/nm/20070727/wr_nm/italy_lastsupper_theory_dc;_ylt=AimIrSA2KgCxm6wB1a0LXuas0NUE > ? > > The websites that supposedly contain the image are unreachable, so I > thought > it would be fun to recreate the image myself using matplotlib and the PIL. > The image is attached, I dont see a Templar knight or anyone holding a > small > baby. > > Darren > > ------------------------------------------------------------------------- > This SF.net email is sponsored by: Splunk Inc. > Still grepping through log files to find problems? Stop. > Now Search log events and configuration files using AJAX and a browser. > Download your FREE copy of Splunk now >> http://get.splunk.com/ > _______________________________________________ > Matplotlib-devel mailing list > Mat...@li... > https://lists.sourceforge.net/lists/listinfo/matplotlib-devel > > >
I just saw this article on Reuters, which covers a theory that if you superimpose DaVinci's Last Supper with its own mirror image, you get a new image of a Templar night and someone holding a small baby: http://news.yahoo.com/s/nm/20070727/wr_nm/italy_lastsupper_theory_dc;_ylt=AimIrSA2KgCxm6wB1a0LXuas0NUE? The websites that supposedly contain the image are unreachable, so I thought it would be fun to recreate the image myself using matplotlib and the PIL. The image is attached, I dont see a Templar knight or anyone holding a small baby. Darren
DQpTZW50IHZpYSBCbGFja0JlcnJ5IGZyb20gVC1Nb2JpbGUNCg0KLS0tLS1PcmlnaW5hbCBNZXNz YWdlLS0tLS0NCkZyb206IEtlbiBNY0l2b3IgPG1jaXZvckBpaXQuZWR1Pg0KDQpEYXRlOiBGcmks IDI3IEp1bCAyMDA3IDE3OjM1OjA1IA0KVG86Sm9obiBIdW50ZXIgPGpkaDIzNThAZ21haWwuY29t Pg0KQ2M6bWF0cGxvdGxpYiBkZXZlbG9wbWVudCBsaXN0IDxtYXRwbG90bGliLWRldmVsQGxpc3Rz LnNvdXJjZWZvcmdlLm5ldD4NClN1YmplY3Q6IFJlOiBbbWF0cGxvdGxpYi1kZXZlbF0gbXBsMSBk cmFmdA0KDQoNCk9uIEp1bCAyNSwgMjAwNywgYXQgMTI6MDkgUE0sIEpvaG4gSHVudGVyIHdyb3Rl Og0KPg0KPiBIaSBLZW4gLS0gc29ycnkgZm9yIHRoZSByYWRpbyBzaWxlbmNlLCBJJ20gbm90IGlu dGVudGlvbmFsbHkgaWdub3JpbmcNCj4geW91LiAgUmVhbCBsaWZlIGhhcyBtYWRlIHNvbWUgZGVt YW5kcyBvbiBteSB0aW1lIG9mIGxhdGUsIGFuZCBwcm9iYWJseQ0KPiB3aWxsIHVudGlsIG5leHQg d2VlaywgYnV0IEkgd2FzIGFibGUgdG8gZG93bmxvYWQsIHJlYWQgdGhyb3VnaCBhbmQNCj4gdGVz dCB5b3VyIGNvZGUuDQoNCkkgYXBwcmVjaWF0ZSB5b3UgbWFraW5nIHRoZSB0aW1lIHRvIHRha2Ug YSBsb29rIGF0IG15IGNvZGUgaW4gc3BpdGUgIA0Kb2YgaXQuDQoNCj4gQnV0IEkgZG9uJ3QgdGhp bmsgdGhhdCBjbG9zZXMgdGhlIGJvb2sgb24gdGhlIHN1YmplY3QgLS0gZm9yICANCj4gZXhhbXBs ZSwgSSBoYXZlIHJlYWxpemVkIEkgYW0gaW50cm9kdWNpbmcgdG9vIG11Y2ggY29tcGxleGl0eSBh bmQgIA0KPiB0cmFpdCBmb3J3YXJkaW5nLCBhbmQgSSB0aGluayBJIGtub3cgYSB3YXkgdG8gd29y ayBhcm91bmQgdGhpcywgc28gIA0KPiBJIHdpbGwgYmUgaGFja2luZyB0aHJvdWdoIG15IHZlcnNp b24gb25lIG1vcmUgdGltZSB3aGlsZSBhdCB0aGUgIA0KPiBzYW1lIHRpbWUgdGFraW5nIGEgY2xv c2VyIGxvb2sgYXQgeW91cnMuDQoNCkknZCBoYXJkbHkgZXhwZWN0IGl0IHRvIGNsb3NlIHRoZSBi b29rIG9uIHRoZSBzdWJqZWN0LiAgQWx0aG91Z2ggaXQgIA0KZnVuY3Rpb25zIGFzIGEgcHJvb2Yt b2YtY29uY2VwdCwgbXkgcmVuZGVyaW5nIG1vZGVsIG5lZWRzIG1vcmUgd29yayAgDQpiZWZvcmUg aXQgY2FuIGhhbmRsZSBzcGVjaWFsIGNhc2VzIGxpa2UgdGhlIGJsZW5kZWQgYWZmaW5lICANCnRy YW5zZm9ybWF0aW9uIHRvIHBsb3QgYW4gYXhpcy4gIEkndmUgYmVlbiB0aGlua2luZyBhYm91dCBo b3cgYmVzdCB0byAgDQphY2NvbXBsaXNoIHRoaXMgYW5kIHdpbGwgdHJ5IHRvIGhhdmUgc29tZXRo aW5nIGZvciB5b3UgdG8gbG9vayBhdCBieSAgDQplYXJseSBuZXh0IHdlZWsuICBQbGVhc2UgZHJv cCBtZSBhIGxpbmUgd2hlbiB5b3UncmUgc2F0aXNmaWVkIHdpdGggIA0KeW91ciBjaGFuZ2VzIHRv IG1wbDEucHksIGFzIEknbSBsb29raW5nIGZvcndhcmQgdG8gc2VlaW5nIHRoZW0uDQoNCj4gSSBh bHNvIHdvdWxkIGxpa2UgdG8gaGVhciBtb3JlIGFib3V0IHRoZSAiaGFyZCB0byBvcHRpbWl6ZSIg cGFydCwgIA0KPiBiZWNhdXNlIHRoYXQgaXMgbm90IGludHVpdGl2ZWx5IGNsZWFyIHRvIG1lLg0K DQpNb3ZpbmcgdG8gYSByZW5kZXJpbmcgbW9kZWwgd2hlbiB0aGUgcHJpbWl0aXZlcyBtb2RpZnkg dGhlIENUTSAgDQppbnN0ZWFkIG9mIHJlcGxhY2luZyBpdCB3aXRoIGEgcHJlLWNhbGN1bGF0ZWQg dmFsdWUgcmVtb3ZlcyB0aGUgIA0KZGVwZW5kZW5jeSBiZXR3ZWVuIHByaW1pdGl2ZXMgYW5kIHRo ZWlyIGNvbnRhaW5lcnMuICBBIFByaW1pdGl2ZSAgDQpvYmplY3QsIGxpa2UgYSBQYXRoLCBtYXkg YmUgcmV1c2VkIGFuZCBzaGFyZWQgYmV0d2VlbiByZW5kZXJlcnMuICBUaGUgIA0KbmF0aXZlIHZl cnNpb24gb2YgYSBQcmltaXRpdmUgb2JqZWN0IGlzIHN0b3JlZCBieSB0aGUgUHJpbWl0aXZlICAN Cm9iamVjdCBpdHNlbGYsIHNvIGl0IGNhbiBiZSByZXVzZWQgYnkgYW55IENhbnZhcyB0aGF0IGRy YXdzIHRoZSAgDQpQcmltaXRpdmUuICBUaGlzIGFsc28gbWVhbnMgdGhhdCB5b3UgaW5jdXIgdmVy eSBsaXR0bGUgY29zdCBpbiAgDQpjbGVhcmluZyBhIFJlbmRlcmVyIGFuZCB0aGVuIHJlcG9wdWxh dGluZyBpdCB3aXRoIGV4aXN0aW5nICANClByaW1pdGl2ZXMuICBBbiBBcnRpc3QtbGV2ZWwgaW1w bGVtZW50YXRpb24gb2Ygei1vcmRlciBjb3VsZCBsZXZlcmFnZSAgDQp0aGlzIHRvIGF2b2lkIGhh dmluZyB0byBzb3J0IHByaW1pdGl2ZXMgYnkgei1vcmRlciBldmVyeSB0aW1lIGEgIA0KZmlndXJl IGlzIHJlbmRlcmVkLg0KDQpTaW5jZSBwcmltaXRpdmVzIG1vZGlmeSBncmFwaGljcyBzdGF0ZSBp bnN0ZWFkIG9mIHJlcGxhY2luZyBpdCAgDQp3aG9sZXNhbGUgdGhlIGl0J3MgZWFzaWVyIGZvciB0 aGUgQ2FudmFzIHRvIHB1c2ggYXMgZmV3IGNoYW5nZXMgdG8gIA0KdGhlIGJhY2tlbmQgYXMgcG9z c2libGUuICBGb3IgZXhhbXBsZSwgaWYgbm9uZSBvZiB0aGUgY2hpbGQgIA0KcHJpbWl0aXZlcyBv ZiBhIFNjYWxlZFZpZXcgaGF2ZSB0aGVpciBvd24gdHJhbnNmb3JtcyB0aGVuIHRoZSBDVE0gIA0K b25seSBnZXRzIG1vZGlmaWVkIG9uY2Ugd2hlbiB0aGUgU2NhbGVkVmlldyBpcyByZW5kZXJlZC4g IFRoZSBzYW1lIGlzICANCnRydWUgZm9yIGFsbCBvZiB0aGUgb3RoZXIgZ3JhcGhpY3Mgc3RhdGUg cGFyYW1ldGVycywgbGlrZSBsaW5ld2lkdGggIA0KYW5kIHN0cm9rZWNvbG9yLiAgVGhpcyBzYXZl cyBvbiB1bm5lY2Vzc2FyeSBiYWNrZW5kIG92ZXJoZWFkIChlLmcuICANCmNyZWF0aW5nIHRoZSBz YW1lIGFnZy50cmFuc19hZmZpbmUgcmVwZWF0ZWRseSkuICBJdCBjb3VsZCBhbHNvIGxlYWQgIA0K dG8gdGlnaHRlciBQREYgYW5kIEVQUyBvdXRwdXQuDQoNCkZpbmFsbHksIHRoZSBSZW5kZXJlciBj bGFzcyBpcyBjYW52YXMtaW5kZXBlbmRlbnQgc28gaXQgY2FuIGJlIHVzZWQgIA0KdG8gZHJhdyBv biBtdWx0aXBsZSBjYW52YXNlcyBkdXJpbmcgdGhlIGNvdXJzZSBvZiBpdHMgbGlmZXRpbWUuICBJ ICANCmhvcGUgdGhpcyB3aWxsIHN1YnN0YW50aWFsbHkgc2ltcGxpZnkgdGhlIHByb2Nlc3Mgb2Yg c2F2aW5nIGEgZmlndXJlICANCnRoYXQgd2FzIGRyYXduIGludGVyYWN0aXZlbHkuICBJJ20gYWxz byBjb250ZW1wbGF0aW5nIG1ha2luZyAgDQpSZW5kZXJlcnMgYWJsZSB0byBjb250YWluIGNoaWxk IFJlbmRlcmVycyBzbyBwYXJ0cyBvZiBhIGZpZ3VyZSBjYW4gYmUgIA0Kc2VsZWN0aXZlbHkgdXBk YXRlZC4gIEZvciBleGFtcGxlLCBkcmF3aW5nIHRoZSBub24tQXhpcyBjaGlsZHJlbiBvZiAgDQph biBBeGVzIGJ5IHVzaW5nIGEgc3VicmVuZGVyZXIgY291bGQgZnVydGhlciBpbXByb3ZlIGFuaW1h dGlvbiAgDQpwZXJmb3JtYW5jZS4NCg0KPiBJIGNvbmZlc3MgdG8gYmVpbmcgYSBtZXRhLWNsYXNz IGlnbm9yYW11cywgc28gSSBhbSBpbnRyaWd1ZWQgdG8gc3R1ZHkNCj4gaG93IHlvdSBoYW5kbGVk IHRoZSBjYW52YXMgcHJpbWl0aXZlIGNhY2hlIHByb2JsZW0gdXNpbmcgbWV0YSBjbGFzc2VzLg0K DQpJIGhhdGUgdG8gZGlzYXBwb2ludCB5b3UsIGJ1dCBtZXRhY2xhc3NlcyBhcmVuJ3QgaW52b2x2 ZWQuICBSaWdodCBub3cgIA0KdGhlIGNhY2hpbmcgaXMgaW1wbGVtZW50ZWQgY29vcGVyYXRpdmVs eSBieSBDYW52YXMgYW5kICANCkNhbnZhc1ByaW1pdGl2ZSB0byByZWR1Y2UgZHVwbGljYXRlIGNv ZGUuICAgDQpDYW52YXNQcmltaXRpdmUuZ2V0X2NhbnZhc19wcmltaXRpdmUoKSBoYW5kbGVzIHRo ZSBjYWNoaW5nIGxvZ2ljIGFuZCAgDQpjYWxscyBDYW52YXNQcmltaXRpdmUuY3JlYXRlX2NhbnZh c19wcmltaXRpdmUoKSB0byBjcmVhdGUgYSBuZXcgIA0KbmF0aXZlIG9iamVjdCBpZiBuZWNlc3Nh cnkuICBTdWJjbGFzc2VzIG9mIENhbnZhc1ByaW1pdGl2ZW92ZXJyaWRlICANCmNyZWF0ZV9jYW52 YXNfcHJpbWl0aXZlKCkgdG8gZGVsZWdhdGUgdGhlIGNhbGwgdG8gdGhlIGFwcHJvcHJpYXRlICAN Cm1ldGhvZCBvZiBDYW52YXMsIGUuZy4gUGF0aC5jcmVhdGVfY2FudmFzX3ByaW1pdGl2ZSgpIHJl dHVybnMgdGhlICANCnJlc3VsdCBvZiBDYW52YXMuY3JlYXRlX2NhbnZhc19wYXRoKCkuICBTdWJj bGFzc2VzIG9mIENhbnZhcyB0aGF0IGRvICANCm5vdCBjYWNoZSBQcmltaXRpdmVzIHNob3VsZCBu b3Qgb3ZlcnJpZGUgdGhlIGNyZWF0ZV9jYW52YXNfeHh4KCkgIA0KbWV0aG9kcy4NCg0KPiBIb3cg Zm9yIGV4YW1wbGUsIGlmIG9uZSBtb2RpZmllcyBhIFJlY3RhbmdsZSBvYmplY3Qgd2hpY2ggZW1i b2RpZXMgYQ0KPiBwYXRoIHByaW1pdGl2ZSwgd291bGQgdGhlIGNhbnZhcyBnZXQgdGhlIG5vdGlm aWNhdGlvbiB0byB1cGRhdGUgaXQncw0KPiBpbnRlcm5hbCBwYXRoIHJlcHJlc2VudGF0aW9uIChl Z2cgdGhlIGFnZ19wYXRoX3N0b3JhZ2UpPy4NCg0KTmF0aXZlIGNhbnZhcyBvYmplY3RzIGFyZSBh bHdheXMgY3JlYXRlZCBhdCByZW5kZXItdGltZSwgc28gcmVjdGFuZ2xlICANCndvdWxkIGp1c3Qg dXBkYXRlIGl0cyBhc3NvY2lhdGVkIFBhdGggaW5zdGFuY2Ugd2hlbiBpdHMgYm91bmRzICANCmNo YW5nZWQuICBUaGUgbmV4dCB0aW1lIHRoZSBQYXRoIGlzIGRyYXduLCBDYW52YXMuZHJhd19wYXRo KCkgd291bGQgIA0KY2FsbCBDYW52YXNQcmltaXRpdmUuZ2V0X2NhbnZhc19wcmltaXRpdmUoKSBh bmQgZW5kIHVwIHdpdGggYSBuZXcgQUdHICANCnBhdGguICBUaGF0IGJlaW5nIHNhaWQsIGl0IG1p Z2h0IGJlIG1vcmUgZWZmaWNpZW50IGlmIGFsbCBSZWN0YW5nbGVzICANCnNoYXJlIG9uZSBQYXRo IHRoYXQgZHJhd3MgYSB1bml0IHNxdWFyZSBhbmQgY2hhbmdlIGl0cyBzaXplIGJ5ICANCnVwZGF0 aW5nIHRoZSBDVE0uDQoNCj4gV2l0aCB0cmFpdHMsIEkgdXNlIHRoZSB0cmFpdCBldmVudCBoYW5k bGluZyBtZWNoYW5pc20gc28gdGhhdCB3aGVuICANCj4gYW55IG9mDQo+IHRoZSBib3ggcHJvcGVy dGllcyAobGVmdCwgd2lkdGgsIHRvcCwgZXRjLi4uKSBhcmUgbW9kaWZpZWQsIHRoZQ0KPiBQYXRo UHJpbWl0aXZlQWdnIHdvdWxkIGdldCBhIGNhbGxiYWNrLiAgU28gd2hlbiB0aGUgdXNlciBkb2Vz DQo+DQo+IHJlY3QubGVmdCA9IDAuMQ0KPg0KPiB0aGUgYWdnIHBhdGgga25vd3MgdG8gdXBkYXRl IGl0c2VsZi4gIFRoaXMgaXMgcHJldHR5IGNvb2wuDQoNClllcyBpdCBpcywgYW5kIEkgYWdyZWUg dGhhdCBtcGwxIHNob3VsZCBoYXZlIGFuIGF0dHJpYnV0ZS1iYXNlZCBBUEkgIA0KZm9yIG1vZGlm eWluZyBwbG90IG9iamVjdCBwYXJhbWV0ZXJzLg0KDQo+IHZpcy1hLXZpcyBwcm9wZXJ0aWVzIHZz IHRyYWl0cywgSSBzZWNvbmQgUGV0ZXIncyBjb21tZW50IHRoYXQgb25jZQ0KPiB5b3UndmUgd3Jp dHRlbiA4LDAwMCBzZXR0ZXJzIGFuZCBnZXR0ZXJzIGFuZCBtYW51YWxseSBjb25zdHJ1Y3RlZA0K PiBwcm9wZXJ0aWVzLCB5b3UnbGwgcHJvYmFibHkgZXZvbHZlIHRvd2FyZCBzb21ldGhpbmcgbGlr ZSB0cmFpdHMsIHcvbw0KPiBhbGwgdGhlIGZlYXR1cmVzLiAgVGhpcyBpcyBhIGxpYnJhcnkgdGhh dCBoYXMgYmVlbiBidWcgYW5kIHBlcmZvcm1hbmNlDQo+IHZldHRlZCBpbiBwcm9kdWN0aW9uIGFw cGxpY2F0aW9ucyBmb3IgeWVhcnMsIHNvIHdlIHNob3VsZCBzZXJpb3VzbHkNCj4gY29uc2lkZXIg aXQgYXMgYSBwcm9wZXJ0aWVzIGFsdGVybmF0aXZlLg0KDQpUcmFpdHMgZG9lcyBsb29rIGV4Y2Vs bGVudCBhdCB3aGF0IGl0IGRvZXMsIGJ1dCBJJ20gc3RpbGwgb2YgdGhlICANCm9waW5pb24gdGhh dCB0aGUgY29zdCBvZiBhZGRpbmcgYSBsYXJnZSBleHRlcm5hbCBkZXBlbmRlbmN5IHRoYXQgaXMg IA0Kbm90IGF2YWlsYWJsZSBpbiBEZWJpYW4gb3IgVWJ1bnR1IG91dHdlaWdocyB0aGUgYmVuZWZp dHMgb2YgcmVwbGFjaW5nICANCnZhbmlsbGEgcHJvcGVydGllcyB3aXRoIHRyYWl0cy4NCg0KPiBJ IHN0cm9uZ2x5IGVuY291cmFnZSB5b3UgdG8gZG93bmxvYWQgRmVybmFuZG8ncyBtcGxjb25maWcg c2FuZGJveCAgDQo+IHN0dWZmIGFuZCB0cnkgdGhlIGVkaXRfdHJhaXRzIGRlbW8gaW4gdGhlIHBy ZXNlbmNlIG9mIGEgd3ggZW5hYmxlZCAgDQo+IHRyYWl0cy4NCg0KSSdsbCBnaXZlIGl0IGEgdHJ5 Lg0KDQo+IEhlIGlzIHNvbWV3aGF0IGJsb3duIGF3YXkgYnkgdGhlIGZhY3QgdGhhdCBoZSBnb3Qg YSBzb3BoaXN0aWNhdGVkLCAgDQo+IG5lc3RlZCBHVUkgZGlhbG9nIHcvbyB3cml0aW5nICphbnkq IGNvZGUuICBTaW5jZSB5b3UgYXJlIGEgIA0KPiBjb21taXR0ZWQgd3ggdXNlciwgeW91IG1pZ2h0 IGZpbmQgdGhpcyBwYXJ0aWN1bGFybHkgYXBwZWFsaW5nLg0KDQpObyBvbmUncyBjb21taXR0ZWQg bWUgeWV0LCBtd2FoYWhhISAgQWN0dWFsbHksIHRoYXQgZmVhdHVyZSBkb2VzICANCmxpdHRsZSB0 byBhZHZhbmNlIG15IHByaW1hcnkgdXNlIGNhc2UgZm9yIG1wbCwgZW1iZWRkaW5nIHBsb3RzIGlu ICANCmFwcGxpY2F0aW9ucy4gIEkgbXkgZXhwZXJpZW5jZSB5b3UgaGF2ZSB0byBwdXQgZW5vdWdo IGVmZm9ydCBpbnRvICANCm1ha2luZyB0aGUgcGxvdHMgbG9vayBnb29kIHRoYXQgeW91IGRvbid0 IHdhbnQgdXNlcnMgdG8gYmUgYWJsZSB0byAgDQplZGl0IHRoZW0gYXQgcnVudGltZS4gIFRoYXQg YmVpbmcgc2FpZCwgSSB3b3VsZG4ndCBiZSBzdXJwcmlzZWQgdG8gIA0KbGVhcm4gdGhhdCBvdGhl cnMnIGV4cGVyaWVuY2VzIGRpZmZlci4NCg0KPiBCdXQgYXQgdGhlIGVuZCBvZiB0aGUgZGF5LCBJ IHRoaW5rIHRoZSAqbm90aWZpY2F0aW9uKiBhc3BlY3Qgb2YgIA0KPiB0cmFpdHMgaXMgdGhlIGtp bGxlciBmZWF0dXJlLg0KDQpJIGtub3csIGFuZCBJIHN0aWxsIHRoaW5rIHRoYXQgZm9yIG1hdHBs b3RsaWIgaXQncyBhIGJhZCBTb2Z0d2FyZSAgDQpFbmdpbmVlcmluZyBtb3ZlIGR1ZSB0byB0aGUg aW1wbGljaXQgaW50ZXItb2JqZWN0IGRlcGVuZGVuY2llcyBpdCAgDQpjcmVhdGVzLiAgSSBjYW4n dCBzZWUgd2h5IGRyYXdpbmcgcGxvdHMgc2hvdWxkIHJlcXVpcmUgdGhhdCBtdWNoICANCiJzcG9v a3kgYWN0aW9uIGF0IGEgZGlzdGFuY2UiLiAgSSBjb3VsZCBiZSB3cm9uZywgYnV0IGZvciBub3cg SSdsbCAgDQprZWVwIHdvcmtpbmcgdG8gZmluZCBhIHdheSB0aGF0IGRvZXNuJ3QuDQoNCj4gSSB0 aGluayB5b3VyIGFwcHJvYWNoIG9mIHdvcmtpbmcgb24gYSBkaXNwbGF5IFBERiByZW5kZXJlciBp bnRlcmZhY2UNCj4gaXMgYWxzbyBhIGdvb2Qgb25lLCBmb3Igc2V2ZXJhbCByZWFzb25zLiAgSXQg dXNlcyBhbiBlc3RhYmxpc2hlZA0KPiBzcGVjaWZpY2F0aW9uIGluc3RlYWQgb2YgYSBob21lIGdy b3duIG9uZSwgYW5kIGl0IG1ha2VzIGl0IGVhc2llciBmb3INCj4gdXMgdG8gY29uc2lkZXIgdGhp bmdzIGxpa2UgaW50ZWdyYXRpbmcgd2l0aCBLaXZhIG9yIENoYWNvLg0KDQpJdCdzIG5pY2UgdG8g aGVhciB5b3UgbGlrZSBpdC4gIFRob3NlIGFyZSB0d28gb2YgdGhlIHNwZWNpZmljIGdvYWxzIEkg IA0KaGF2ZSBpbiBtaW5kLiAgSSBhbHNvIGxpa2UgdGhlIGlkZWEgb2YgaGF2aW5nIGEgZ2VuZXJp YyByZXRhaW5lZCAgDQpkcmF3aW5nIHN5c3RlbSBhdmFpbGFibGUgaW4gUHl0aG9uLg0KDQo+IEkg YW0gZ2xhZCB5b3UgaW50ZXJwcmV0ZWQgbXkgbXBsMSBza2V0Y2ggaW4gdGhlIHJpZ2h0IHZlaW4s IGFzIGEgIA0KPiBsYWIgaW4gd2hpY2gNCj4gcGVvcGxlIGNhbiBhZHZvY2F0ZSBpZGVhcyBhcyB3 b3JraW5nIGNvZGUuDQoNCldlbGwsIEknbSBnbGFkIHlvdSd2ZSB0YWtlbiBteSBjcml0aWNpc21z IG9mIG1wbDEucHkgaW4gdGhlIHNwaXJpdCAgDQp0aGV5IHdlcmUgaW50ZW5kZWQgaW4uICBJIGFs c28gYXBwcmVjaWF0ZSB5b3UgdGFraW5nIHRoZSB0aW1lIHRvICANCnJldmlldyB0aGUgY29kZSBJ IHN1Ym1pdHRlZCBpbnN0ZWFkIG9mIGp1c3QgdGVsbGluZyBtZSBob3cgdmVyeSBuaWNlICANCmFu ZCBjb252ZW5pZW50IHRyYWl0cyBhcmUuICA7LSkNCg0KPiBIb3BlZnVsbHkgbmV4dCB3ZWVrIHdl IGNhbiBjb21lIHRvIHNvbWUgY29uc2Vuc3VzIGFuZCBzdGFydCBtZXJnaW5nICANCj4gb3VyIHR3 byBsaW5lcy4NCg0KVGhhdCBzb3VuZHMgbGlrZSBhIHBsYW4uICBJJ2xsIHRyeSB0byBtYWtlIHNv bWUgcHJvZ3Jlc3Mgb24gdGhlICANCmJsZW5kZWQgYWZmaW5lcyBmb3IgZHJhd2luZyBheGlzIHRp Y2ttYXJrcyBhbmQgdGhlIEFydGlzdHMgbGF5ZXIuDQoNCktlbg0K
On Jul 25, 2007, at 12:09 PM, John Hunter wrote: > > Hi Ken -- sorry for the radio silence, I'm not intentionally ignoring > you. Real life has made some demands on my time of late, and probably > will until next week, but I was able to download, read through and > test your code. I appreciate you making the time to take a look at my code in spite of it. > But I don't think that closes the book on the subject -- for > example, I have realized I am introducing too much complexity and > trait forwarding, and I think I know a way to work around this, so > I will be hacking through my version one more time while at the > same time taking a closer look at yours. I'd hardly expect it to close the book on the subject. Although it functions as a proof-of-concept, my rendering model needs more work before it can handle special cases like the blended affine transformation to plot an axis. I've been thinking about how best to accomplish this and will try to have something for you to look at by early next week. Please drop me a line when you're satisfied with your changes to mpl1.py, as I'm looking forward to seeing them. > I also would like to hear more about the "hard to optimize" part, > because that is not intuitively clear to me. Moving to a rendering model when the primitives modify the CTM instead of replacing it with a pre-calculated value removes the dependency between primitives and their containers. A Primitive object, like a Path, may be reused and shared between renderers. The native version of a Primitive object is stored by the Primitive object itself, so it can be reused by any Canvas that draws the Primitive. This also means that you incur very little cost in clearing a Renderer and then repopulating it with existing Primitives. An Artist-level implementation of z-order could leverage this to avoid having to sort primitives by z-order every time a figure is rendered. Since primitives modify graphics state instead of replacing it wholesale the it's easier for the Canvas to push as few changes to the backend as possible. For example, if none of the child primitives of a ScaledView have their own transforms then the CTM only gets modified once when the ScaledView is rendered. The same is true for all of the other graphics state parameters, like linewidth and strokecolor. This saves on unnecessary backend overhead (e.g. creating the same agg.trans_affine repeatedly). It could also lead to tighter PDF and EPS output. Finally, the Renderer class is canvas-independent so it can be used to draw on multiple canvases during the course of its lifetime. I hope this will substantially simplify the process of saving a figure that was drawn interactively. I'm also contemplating making Renderers able to contain child Renderers so parts of a figure can be selectively updated. For example, drawing the non-Axis children of an Axes by using a subrenderer could further improve animation performance. > I confess to being a meta-class ignoramus, so I am intrigued to study > how you handled the canvas primitive cache problem using meta classes. I hate to disappoint you, but metaclasses aren't involved. Right now the caching is implemented cooperatively by Canvas and CanvasPrimitive to reduce duplicate code. CanvasPrimitive.get_canvas_primitive() handles the caching logic and calls CanvasPrimitive.create_canvas_primitive() to create a new native object if necessary. Subclasses of CanvasPrimitiveoverride create_canvas_primitive() to delegate the call to the appropriate method of Canvas, e.g. Path.create_canvas_primitive() returns the result of Canvas.create_canvas_path(). Subclasses of Canvas that do not cache Primitives should not override the create_canvas_xxx() methods. > How for example, if one modifies a Rectangle object which embodies a > path primitive, would the canvas get the notification to update it's > internal path representation (egg the agg_path_storage)?. Native canvas objects are always created at render-time, so rectangle would just update its associated Path instance when its bounds changed. The next time the Path is drawn, Canvas.draw_path() would call CanvasPrimitive.get_canvas_primitive() and end up with a new AGG path. That being said, it might be more efficient if all Rectangles share one Path that draws a unit square and change its size by updating the CTM. > With traits, I use the trait event handling mechanism so that when > any of > the box properties (left, width, top, etc...) are modified, the > PathPrimitiveAgg would get a callback. So when the user does > > rect.left = 0.1 > > the agg path knows to update itself. This is pretty cool. Yes it is, and I agree that mpl1 should have an attribute-based API for modifying plot object parameters. > vis-a-vis properties vs traits, I second Peter's comment that once > you've written 8,000 setters and getters and manually constructed > properties, you'll probably evolve toward something like traits, w/o > all the features. This is a library that has been bug and performance > vetted in production applications for years, so we should seriously > consider it as a properties alternative. Traits does look excellent at what it does, but I'm still of the opinion that the cost of adding a large external dependency that is not available in Debian or Ubuntu outweighs the benefits of replacing vanilla properties with traits. > I strongly encourage you to download Fernando's mplconfig sandbox > stuff and try the edit_traits demo in the presence of a wx enabled > traits. I'll give it a try. > He is somewhat blown away by the fact that he got a sophisticated, > nested GUI dialog w/o writing *any* code. Since you are a > committed wx user, you might find this particularly appealing. No one's committed me yet, mwahaha! Actually, that feature does little to advance my primary use case for mpl, embedding plots in applications. I my experience you have to put enough effort into making the plots look good that you don't want users to be able to edit them at runtime. That being said, I wouldn't be surprised to learn that others' experiences differ. > But at the end of the day, I think the *notification* aspect of > traits is the killer feature. I know, and I still think that for matplotlib it's a bad Software Engineering move due to the implicit inter-object dependencies it creates. I can't see why drawing plots should require that much "spooky action at a distance". I could be wrong, but for now I'll keep working to find a way that doesn't. > I think your approach of working on a display PDF renderer interface > is also a good one, for several reasons. It uses an established > specification instead of a home grown one, and it makes it easier for > us to consider things like integrating with Kiva or Chaco. It's nice to hear you like it. Those are two of the specific goals I have in mind. I also like the idea of having a generic retained drawing system available in Python. > I am glad you interpreted my mpl1 sketch in the right vein, as a > lab in which > people can advocate ideas as working code. Well, I'm glad you've taken my criticisms of mpl1.py in the spirit they were intended in. I also appreciate you taking the time to review the code I submitted instead of just telling me how very nice and convenient traits are. ;-) > Hopefully next week we can come to some consensus and start merging > our two lines. That sounds like a plan. I'll try to make some progress on the blended affines for drawing axis tickmarks and the Artists layer. Ken
John Hunter wrote: > On 7/26/07, Darren Dale <dd...@co...> wrote: >>> where Math is a wrapper object that signals to "text" that its contents >>> are to be passed to the mathtext interpreter. >> I would like to voice my opinion against this idea. I think the backward >> imcompatibility will be rare, and does not justify the additionaly complexity >> of the far more common need to interpret mathtext. > > I'm on the fence as to how to handle this case. The majority of our > users will think of $ as the US currency symbol, and will have never > heard of TeX. Option 1 is to educate them, and require them to \$ > quote that symbol. Option 2 is to enable a text property eg mathtext, > and do > > text(x, y, 'what is the $\sin(x)$', mathtext=True) > > Option 3 is to try and be clever, and interpret an even number of > unquoted dollar symbols as mathtext, or any string that has a quoted > dollar sign symbol as mathtext, else assume plain text. Option 4 is > to treat *all* strings as mathtext, but I think we would pay a pretty > big performance hit to invoke the mathtext machinery for every piece > of text. But it is an option. In option 4, of course, users would be > required to quote all dollar signs, so it is related to option 1 but > slightly different in how it treats strings with no dollar signs. > > I'm not too keen on the text(x, y, Math('string')) proposal, which is > a little outside the normal matplotlib approach. > > Michael, do you have a preference or an alternate proposal? > JDH Let's rule out option 3 completely; it is an example of the type of cleverness that ends up causing more trouble and confusion than it is worth. I also oppose using something other than the $ to delimit math, if delimiters are needed, which I think they are. At least in *Tex, a string of characters (a word) is rendered very differently depending on whether it is inside an equation or outside. I suspect that options 1 and 4 will cause endless questions to matplotlib-users, and grumbling among people in the business and financial community who use lots of dollar signs and no math. That leaves some variant of 2 and the Math('string') idea. I find the latter quite pythonic; it is a very concise, readable, and general way of attaching extra information to a string object, and it does not require passing yet another kwarg through a sequence of function and method calls. But if it is judged to be too out-of-character with the rest of the mpl api, or if in practice it would cause trouble that I don't see yet, then I am happy to let it go. I have not thought it through carefully, and I am not attached to it. If a variant of 2 is chosen, one might shorten the kwarg to "math". Or use "format='math'" or something like that. This is more flexible than a boolean kwarg, leaving the door open to additional options for interpretation of strings--but not quite as flexible and powerful as the math('string') idea. Eric