~ubuntu-branches/ubuntu/utopic/python-chaco/utopic

« back to all changes in this revision

Viewing changes to examples/demo/advanced/javascript_hover_tools.py

  • Committer: Package Import Robot
  • Author(s): Andrew Starr-Bochicchio
  • Date: 2014-06-01 17:04:08 UTC
  • mfrom: (7.2.5 sid)
  • Revision ID: package-import@ubuntu.com-20140601170408-m86xvdjd83a4qon0
Tags: 4.4.1-1ubuntu1
* Merge from Debian unstable. Remaining Ubuntu changes:
 - Let the binary-predeb target work on the usr/lib/python* directory
   as we don't have usr/share/pyshared anymore.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
"""
2
 
Demo of a javascript inspector tool that shows a black bar over the active
3
 
value axis, as well as the values at the current index, with the numbers
4
 
shown in the colors matching the legend.
5
 
 
6
 
To Use
7
 
------
8
 
Run Python on this file which will generate six files,
9
 
    plot_hover_coords.html
10
 
    plot_hover_coords.png
11
 
    plot_hover2_coords.png
12
 
    hover_coords.js
13
 
    plot_hover_coords_png_hover_data.js
14
 
    plot_hover2_coords_png_hover_data.js
15
 
 
16
 
Alternatively, if you pass in '-e' or '--embedded' on the command-line, then
17
 
a single HTML file will be created that has all JavaScript and images
18
 
directly embedded into it.
19
 
 
20
 
The script should automatically load your webbrowser on the output file,
21
 
but if it does not, then manually open the file hover_coords_plot.html in
22
 
your browser to see the output.
23
 
 
24
 
Author: Judah De Paula <judah@enthought.com>
25
 
Date: November 21, 2008.
26
 
"""
27
 
# Standard library imports
28
 
import os, sys, webbrowser, cStringIO
29
 
from base64 import encodestring
30
 
 
31
 
# Major library imports
32
 
import Image
33
 
from numpy import arange, searchsorted, where, array, vstack, linspace
34
 
from scipy.special import jn
35
 
 
36
 
# Chaco imports
37
 
from chaco.api \
38
 
    import ArrayPlotData, Plot, PlotGraphicsContext, LinePlot
39
 
from chaco.example_support import COLOR_PALETTE
40
 
 
41
 
 
42
 
#-- Constants -----------------------------------------------------------------
43
 
DPI = 72.0
44
 
 
45
 
 
46
 
#------------------------------------------------------------------------------
47
 
#  File templates:
48
 
#     In a real application, these templates should be their own files,
49
 
#     and a real templating engine (ex. Mako) would make things more flexible.
50
 
#------------------------------------------------------------------------------
51
 
html_template_keys = {'filename1' : 'plot_hover_coords.png',
52
 
                      'filename2' : 'plot_hover2_coords.png',
53
 
                      'file1_src' : 'plot_hover_coords.png',
54
 
                      'file2_src' : 'plot_hover2_coords.png',
55
 
                      'hover_coords' :'src="hover_coords.js">',
56
 
                      'data1' :'src="plot_hover_coords_png_hover_data.js">',
57
 
                      'data2' :'src="plot_hover2_coords_png_hover_data.js">' }
58
 
 
59
 
 
60
 
# Turns into index.html.
61
 
html_template = """
62
 
<html>
63
 
<head>
64
 
    <script type="text/javascript" %(hover_coords)s </script>
65
 
    <script type="text/javascript" %(data1)s </script>
66
 
    <script type="text/javascript" %(data2)s </script>
67
 
</head>
68
 
<body>
69
 
<!------------------ What gets shown onmouseover. ------------------>
70
 
<div id="Hover"
71
 
     style="background-color: White; color: Black; padding:
72
 
            5px; position: absolute; visibility: hidden;"> 0
73
 
</div>
74
 
 
75
 
<div id="BlackPixel"
76
 
     style="background-color: White; color: Black; padding:
77
 
            0px; position: absolute; visibility: hidden;">
78
 
     <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAAXNSR0IArs4c6QAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAxJREFUCNdjYGBgAAAABAABJzQnCgAAAABJRU5ErkJggg=="
79
 
          width="1"
80
 
          height="100"
81
 
          alt="black_pixel.inline"
82
 
          id="black_pixel.inline" />
83
 
</div>
84
 
<!------------------ Demo plot ------------------------------------->
85
 
<div class = "tabbertab">
86
 
 
87
 
    <img src="%(file1_src)s"
88
 
         alt="%(filename1)s"
89
 
         id="%(filename1)s"
90
 
         onmouseover="javascript:ShowHovers('%(filename1)s',
91
 
                                            'Hover', 'BlackPixel')"
92
 
         onmouseout="javascript:HideHovers(event,
93
 
                                           'Hover', 'BlackPixel')" />
94
 
 
95
 
    <img src="%(file2_src)s"
96
 
         alt="%(filename2)s"
97
 
         id="%(filename2)s"
98
 
         onmouseover="javascript:ShowHovers('%(filename2)s',
99
 
                                            'Hover', 'BlackPixel')"
100
 
         onmouseout="javascript:HideHovers(event,
101
 
                                           'Hover', 'BlackPixel')" />
102
 
</div>
103
 
</body>
104
 
</html>
105
 
"""
106
 
 
107
 
 
108
 
# Turns into plot_hover_coords_png_hover_data.js
109
 
javascript_data_template = """
110
 
// Create a new "CursorData" object
111
 
obj = Object();
112
 
obj.height = %(height)s;
113
 
obj.border_width = %(border_width)s;
114
 
obj.padding_top = %(padding_top)s + 1;
115
 
obj.padding_left = %(padding_left)s;
116
 
obj.padding_bottom = %(padding_bottom)s;
117
 
obj.colors = Array( %(colors)s );
118
 
 
119
 
// Store it in the global CursorData, using the unique array_id as a key.
120
 
GlobalCursorData["%(array_id)s"] = obj
121
 
 
122
 
// Store all the data in the array
123
 
obj.data = Array( %(data_s)s );
124
 
"""
125
 
 
126
 
 
127
 
# Turns into hover_coords.js.  Absolutely no string substitution is done.
128
 
hover_coords_js_file = """
129
 
<!------------------ Javascript hover functions ----------------->
130
 
<!-- Depends upon *_hover_data.js files.                       -->
131
 
<!--------------------------------------------------------------->
132
 
 
133
 
/*
134
 
   Global variables
135
 
*/
136
 
 
137
 
// Maps an image name to a CursorData object that contains an array of
138
 
// data and plot visual attributes like height, padding, and border width.
139
 
GlobalCursorData = Array();
140
 
 
141
 
// The hash key into GlobalCursorArray that corresponds to the the current
142
 
// plot that the mouse is over.
143
 
var CurrentPlotKey = "";
144
 
 
145
 
// The ID of the <div> box that contains the cursor line image.
146
 
var BoxElementID;
147
 
 
148
 
// The ID of the <img> of the cursor line image.
149
 
var LineElementID;
150
 
 
151
 
// The number of pixels to offset the readout box from cursor position
152
 
var _xOffset = 15;
153
 
var _yOffset = 15;
154
 
 
155
 
 
156
 
/*
157
 
   Convert an array of floats into an HTML formatted string ready for
158
 
   the screen.
159
 
 */
160
 
function FormatToHTML(data) {
161
 
    var colors = GlobalCursorData[CurrentPlotKey].colors;
162
 
    var s = '<font size=2 face="Courier New">';
163
 
    for (var count = 0; count < data.length; count++) {
164
 
        s = s + '<font color=' + colors[count] + '>' + data[count] + '</font><br>';
165
 
    }
166
 
    if (data.length > 0) {
167
 
        s = s.substr(0, s.length-4);
168
 
    }
169
 
    s += "</font>"
170
 
    return s;
171
 
}
172
 
 
173
 
 
174
 
/*
175
 
   Slightly more clever get x function than the default.  Limited testing.
176
 
*/
177
 
function GetMouseX(event) {
178
 
    if (!event) {
179
 
        event = window.event;
180
 
    }
181
 
    if (event.clientX) {
182
 
        return event.clientX +
183
 
               (document.documentElement.scrollLeft
184
 
                ? document.documentElement.scrollLeft
185
 
                : document.body.scrollLeft);
186
 
    } else if (event.pageX) {
187
 
        return event.pageX;
188
 
    } else {
189
 
        return 0;
190
 
    }
191
 
}
192
 
 
193
 
 
194
 
/*
195
 
   Slightly more clever get y function than the default.  Limited testing.
196
 
*/
197
 
function GetMouseY(event) {
198
 
    if (!event) {
199
 
        event = window.event;
200
 
    }
201
 
    if (event.clientY) {
202
 
        return event.clientY +
203
 
               (document.documentElement.scrollTop
204
 
                ? document.documentElement.scrollTop
205
 
                : document.body.scrollTop);
206
 
    } else if (event.pageY) {
207
 
        return event.pageY;
208
 
    } else {
209
 
        return 0;
210
 
    }
211
 
}
212
 
 
213
 
 
214
 
/*
215
 
   Uses data registered by external *hover_data.js files.
216
 
 
217
 
   Cannot figure out how to get relative coordinates.  Have to calculate
218
 
   it instead using the reference image element registered with the
219
 
   hover IDs.
220
 
*/
221
 
function ScreenXToImageX(mouseX) {
222
 
    var referenceX = document.getElementById(CurrentPlotKey);
223
 
    var cursor_data = GlobalCursorData[CurrentPlotKey];
224
 
    var relativeX = mouseX - cursor_data.padding_left
225
 
                           - cursor_data.border_width
226
 
                           - referenceX.x;
227
 
    return relativeX;
228
 
}
229
 
 
230
 
 
231
 
/*
232
 
   Uses data registered by external *hover_data.js files.
233
 
 
234
 
   The Screen pixel coordinate that the data pixels in the plot start.
235
 
*/
236
 
function ScreenYPlotStart(event) {
237
 
    var referenceElement = document.getElementById(CurrentPlotKey);
238
 
    var cursor_data = GlobalCursorData[CurrentPlotKey];
239
 
    return referenceElement.y + cursor_data.padding_top
240
 
                              + cursor_data.border_width;
241
 
}
242
 
 
243
 
 
244
 
/*
245
 
   Uses data registered by external *hover_data.js files.
246
 
 
247
 
   Given the browser X coordinate compute the plot screen X coordinate
248
 
   and use that value to index into the data array of plot values for
249
 
   that index.
250
 
*/
251
 
function ScreenXToDataY(mouseX) {
252
 
    var dataY;
253
 
    var relativeX = ScreenXToImageX(mouseX);
254
 
    var cursor_data = GlobalCursorData[CurrentPlotKey];
255
 
 
256
 
    if (relativeX >= 0 && relativeX < cursor_data.data.length) {
257
 
        dataY = cursor_data.data[relativeX];
258
 
    // Hack to have bar hidden on the left and right side of images.
259
 
        document.getElementById(LineElementID).style.visibility = 'visible';
260
 
        document.getElementById(BoxElementID).style.visibility = 'visible';
261
 
    } else {
262
 
        dataY = 0;
263
 
        // Hack to have bar hidden on the left and right side of images.
264
 
        document.getElementById(LineElementID).style.visibility = 'hidden';
265
 
        document.getElementById(BoxElementID).style.visibility = 'hidden';
266
 
    }
267
 
    return dataY;
268
 
}
269
 
 
270
 
 
271
 
/*
272
 
   Uses data registered by external *hover_data.js files.
273
 
 
274
 
   Every time the mouse moves over the image, Follow() changes the hovering
275
 
   object attributes so they move to the new location.
276
 
*/
277
 
function Follow(event) {
278
 
    // Move the box
279
 
    var referenceElement = document.getElementById(CurrentPlotKey);
280
 
    var element = document.getElementById(BoxElementID);
281
 
    if (element != null) {
282
 
        var style = element.style;
283
 
        // ScreenXToDataY() hacked to have better control of line visibility.
284
 
        //style.visibility = 'visible';
285
 
        style.left = (parseInt(GetMouseX(event)) + _xOffset) + 'px';
286
 
        style.top = (parseInt(GetMouseY(event)) + _yOffset) + 'px';
287
 
    element.innerHTML = FormatToHTML(ScreenXToDataY(GetMouseX(event)));
288
 
    }
289
 
 
290
 
    // Move the line
291
 
    var element = document.getElementById(LineElementID);
292
 
    var image_element = document.getElementById("black_pixel.inline");
293
 
    if (element != null) {
294
 
        var style = element.style;
295
 
        // ScreenXToDataY() hacked to have better control of line visibility.
296
 
        //style.visibility = 'visible';
297
 
        style.left = parseInt(GetMouseX(event)) + 'px';
298
 
        style.top = parseInt(ScreenYPlotStart()) + 'px';
299
 
        element.height = GlobalCursorData[CurrentPlotKey].height - 1;
300
 
        image_element.height = element.height;
301
 
    }
302
 
}
303
 
 
304
 
 
305
 
/*
306
 
   Abstracted out Show() that assigns the Follow() to mouse movements.
307
 
*/
308
 
function Show(referenceElementID) {
309
 
    var referenceElement = document.getElementById(referenceElementID);
310
 
    if (referenceElement) {
311
 
        referenceElement.onmousemove = Follow;
312
 
    }
313
 
}
314
 
 
315
 
 
316
 
/*
317
 
   Abstracted out Hide() that assigns the Follow() to mouse movements.
318
 
   Turns the hover object invisible and disables the Follow() listener.
319
 
   FIXME:  The listener is turned off for both hover objects even though
320
 
   only one object is hidden by this call.
321
 
*/
322
 
function Hide(referenceElementID, elementID) {
323
 
    var divStyle = document.getElementById(elementID).style;
324
 
    var referenceElement = document.getElementById(referenceElementID);
325
 
    divStyle.visibility = 'hidden';
326
 
    referenceElement.onmousemove = '';
327
 
}
328
 
 
329
 
 
330
 
/*
331
 
   Main entry point for onmouseover event of images.  Sets the globals
332
 
   to the active image the mouse just entered and turns on the hovers.
333
 
*/
334
 
function ShowHovers(referenceElementID, boxElementID, lineElementID) {
335
 
    //_dataIndex = plot_names.indexOf(referenceElementID);
336
 
    CurrentPlotKey = referenceElementID;
337
 
    BoxElementID = boxElementID;
338
 
    LineElementID = lineElementID;
339
 
    Show(CurrentPlotKey);
340
 
    Show(CurrentPlotKey);
341
 
}
342
 
 
343
 
 
344
 
/*
345
 
   Main event call point for onmouseout event for images
346
 
*/
347
 
function HideHovers(event, boxElementID, lineElementID) {
348
 
    var relatedTarget = event.relatedTarget;
349
 
    if ((relatedTarget == null) ||
350
 
        (relatedTarget.id != boxElementID) &&
351
 
        (relatedTarget.id != lineElementID) &&
352
 
        (relatedTarget.id != 'black_pixel.inline')) {
353
 
        Hide(CurrentPlotKey, boxElementID);
354
 
        Hide(CurrentPlotKey, lineElementID);
355
 
    }
356
 
}
357
 
"""
358
 
 
359
 
 
360
 
#------------------------------------------------------------------------------
361
 
#  Data generation functions for *_hover_data.js files.
362
 
#------------------------------------------------------------------------------
363
 
 
364
 
def get_pixel_data(segment, renderer, screen_width):
365
 
    """
366
 
    Take a segment of points and use a renderer to map them to screen coords.
367
 
 
368
 
    Algorithm
369
 
    ---------
370
 
    Fast little function that only works if the samples are sorted.
371
 
    FIXME: Need more explanation.
372
 
    """
373
 
    screen_points = renderer.map_screen(segment)
374
 
 
375
 
    if len(screen_points) == 0:
376
 
        return array([])
377
 
 
378
 
    s_index = screen_points[:,0].astype(int)
379
 
    d_value = segment[:,1]
380
 
    if len(s_index) != len(d_value):
381
 
        raise ValueError('Data-to-screen mapping not 1-to-1.')
382
 
    indices = searchsorted(s_index, arange(0, screen_width))
383
 
    indices[where(indices == 0)] = 1
384
 
    return d_value[indices-1]
385
 
 
386
 
 
387
 
def write_hover_coords(container, array_id, script_filename=None):
388
 
    """
389
 
    Create a JavaScript formatted file of screen index to data values.
390
 
 
391
 
    Parameters
392
 
    ----------
393
 
    container : Plot
394
 
        Chaco container object such as a plot that contain renderers
395
 
        and border padding information.
396
 
    array_id : str
397
 
        An identifier that will be used as the key when assigning the
398
 
        data array to the global list of data arrays.  This identifier
399
 
        should be unique among all the scripts that will be loaded in
400
 
        a single HTML file.
401
 
    script_filename : str
402
 
        Full path to the desired output javascript file.  If no name
403
 
        is passed in, then no file is written.
404
 
 
405
 
    Returns
406
 
    -------
407
 
    Returns the JavaScript data file as a string.
408
 
 
409
 
    Description
410
 
    -----------
411
 
    To have a PNG plot show the values of the curves in a browser,
412
 
    JavaScript is used to get the screen X/Y and convert the X into the
413
 
    corresponding plot data values.  This function creates that mapping
414
 
    array.  A couple of extra padding variables are also exported so the
415
 
    JavaScript can do some additional offset calculations.
416
 
    """
417
 
    screen_width = container.width
418
 
    # For every renderer in the plot, create an array of the same length
419
 
    # as the screen width that contains the data value for each screen
420
 
    # position.  Stack all of these arrays together into the 2D 'pixel_data'
421
 
    # array, then pass it into the template for the hover_data javascript file.
422
 
    segment_data = []
423
 
    colors = []
424
 
    for renderer_name in sorted(container.legend.plots.keys()):
425
 
        renderer = container.legend.plots[renderer_name][0]
426
 
        data_points = renderer._cached_data_pts
427
 
        if not isinstance(renderer, LinePlot):
428
 
            data_points = [data_points]
429
 
        for segment in data_points:
430
 
            segment_data.append(get_pixel_data(segment, renderer, screen_width))
431
 
        colors.append(renderer.color_)
432
 
 
433
 
    if len(segment_data) > 0:
434
 
        pixel_data = vstack(segment_data).T
435
 
    else:
436
 
        pixel_data = array([]).reshape(0, 2)
437
 
 
438
 
    # Fill out a template using the just-created data.
439
 
    colstrings = []
440
 
    for color in colors:
441
 
        if len(color) == 4:
442
 
            alpha = color[3]
443
 
        else:
444
 
            alpha = 1
445
 
        r, g, b = [int(component * alpha * 255) for component in color[:3]]
446
 
        colstrings.append('"#%02x%02x%02x"' % (r,g,b))
447
 
    colors = ",".join(colstrings);
448
 
 
449
 
    line_template = ",".join(['"%1.2f"'] * pixel_data.shape[1])
450
 
    data_s = ''
451
 
    for row in pixel_data[:-1]:
452
 
        data_s += '[' + line_template % tuple(row) +  '],'
453
 
    if len(pixel_data) > 0:
454
 
        data_s += '[' + line_template % tuple(row) + ']'
455
 
 
456
 
    template_keys = dict(height = container.height,
457
 
                         padding_top = container.padding_top,
458
 
                         padding_left = container.padding_left,
459
 
                         padding_bottom = container.padding_bottom,
460
 
                         border_width = container.border_width,
461
 
                         array_id = array_id,
462
 
                         pixel_data = pixel_data,
463
 
                         colors = colors,
464
 
                         data_s = data_s)
465
 
 
466
 
    # Write out and return the result.
467
 
    output = javascript_data_template % template_keys
468
 
    if script_filename:
469
 
        f = open(script_filename, 'wt')
470
 
        f.write(output)
471
 
        f.close()
472
 
 
473
 
    return output
474
 
 
475
 
 
476
 
#------------------------------------------------------------------------------
477
 
#  Plot and renderer generation functions.
478
 
#------------------------------------------------------------------------------
479
 
def create_plot(num_plots=8, type='line'):
480
 
    """ Create a single plot object, with multiple renderers. """
481
 
    # This is a bit of a hack to work around that line widths don't scale
482
 
    # with the GraphicsContext's CTM.
483
 
    dpi_scale = DPI / 72.0
484
 
    numpoints = 100
485
 
    low = -5
486
 
    high = 15.0
487
 
    x = linspace(low, high, numpoints)
488
 
    pd = ArrayPlotData(index=x)
489
 
    p = Plot(pd, bgcolor="white", padding=50, border_visible=True)
490
 
    for i in range(1,num_plots+2):
491
 
        pd.set_data("y" + str(i), jn(i,x))
492
 
        p.plot(("index", "y" + str(i)), color=tuple(COLOR_PALETTE[i]),
493
 
               width = 2.0 * dpi_scale, type=type)
494
 
    p.x_grid.visible = True
495
 
    p.x_grid.line_width *= dpi_scale
496
 
    p.y_grid.visible = True
497
 
    p.y_grid.line_width *= dpi_scale
498
 
    p.legend.visible = True
499
 
    return p
500
 
 
501
 
 
502
 
def draw_plot(filename, size=(800,600), num_plots=8, type='line', key=''):
503
 
    """ Save the plot, and generate the hover_data file. """
504
 
    container = create_plot(num_plots, type)
505
 
    container.outer_bounds = list(size)
506
 
    container.do_layout(force=True)
507
 
    gc = PlotGraphicsContext(size, dpi=DPI)
508
 
    gc.render_component(container)
509
 
    if filename:
510
 
        gc.save(filename)
511
 
        script_filename = filename[:-4] + "_png_hover_data.js"
512
 
    else:
513
 
        script_filename = None
514
 
    plot = make_palettized_png_str(gc)
515
 
    script_data = write_hover_coords(container, key, script_filename)
516
 
    return (plot, script_data)
517
 
 
518
 
 
519
 
def make_palettized_png_str(gc):
520
 
    """ Generate a png file in a string, base64 encoded. """
521
 
    format = gc.format()[:-2].upper()
522
 
    if format != "RGBA":
523
 
        gc = gc.convert_pixel_format("rgba32")
524
 
    img = Image.fromstring("RGBA",
525
 
                           (gc.width(), gc.height()), gc.bmp_array.tostring())
526
 
    img2 = img.convert("P")
527
 
    output_buf = cStringIO.StringIO()
528
 
    img2.save(output_buf, 'png')
529
 
    output = encodestring(output_buf.getvalue())
530
 
    output_buf.close()
531
 
    return output
532
 
 
533
 
 
534
 
#------------------------------------------------------------------------------
535
 
#  Main
536
 
#------------------------------------------------------------------------------
537
 
def main(embedded=False):
538
 
    """
539
 
    Create the files and load the output in a webbrowser.
540
 
    """
541
 
    # 1. Create the JavaScript hover tool file.
542
 
    #    Only doing this to keep the demo file self-contained.
543
 
    target_path = os.path.join(os.getcwd(), 'hover_coords.js')
544
 
    if embedded:
545
 
        html_template_keys['hover_coords'] = '>\n%s\n' % hover_coords_js_file
546
 
    else:
547
 
        f = open(target_path, 'wt')
548
 
        f.write(hover_coords_js_file)
549
 
        f.close()
550
 
 
551
 
    # 2. Create the dynamically generated JavaScript data files.
552
 
    if embedded:
553
 
        html_template_keys['file1_src'] = None
554
 
        html_template_keys['file2_src'] = None
555
 
    file1_strs = draw_plot(html_template_keys['file1_src'],
556
 
                           size=(800, 600),
557
 
                           key=html_template_keys['filename1'])
558
 
    file2_strs = draw_plot(html_template_keys['file2_src'],
559
 
                           size=(600, 400),
560
 
                           num_plots = 4,
561
 
                           type='scatter',
562
 
                           key=html_template_keys['filename2'])
563
 
 
564
 
    # 3. Choose the correct src type for the HTML file if embedded.
565
 
    if embedded:
566
 
        src1 = 'data:image/png;base64,' + file1_strs[0]
567
 
        html_template_keys['file1_src'] = src1
568
 
        src2 = 'data:image/png;base64,' + file2_strs[0]
569
 
        html_template_keys['file2_src'] = src2
570
 
        html_template_keys['data1'] = '>\n%s\n' % file1_strs[1]
571
 
        html_template_keys['data2'] = '>\n%s\n' % file2_strs[1]
572
 
 
573
 
    # 4. Create the HTML file.
574
 
    out_html = os.path.join(os.getcwd(), 'plot_hover_coords.html')
575
 
    f = open(out_html, 'wt')
576
 
    f.write(html_template % html_template_keys)
577
 
    f.close()
578
 
 
579
 
    # 5. Load the finished product.
580
 
    try:
581
 
        webbrowser.open(out_html)
582
 
    except Exception, e:
583
 
        print 'Browser did not open properly.  Exception %s.  The results' \
584
 
              'can be viewed with the file plot_hover_coords.html.' % str(e)
585
 
        raise
586
 
    return
587
 
 
588
 
#===============================================================================
589
 
# # Demo class that is used by the demo.py application.
590
 
#===============================================================================
591
 
# NOTE: The Demo class is being created for the purpose of running this
592
 
# example using a TraitsDemo-like app (see examples/demo/demo.py in Traits3).
593
 
# The demo.py file looks for a 'demo' or 'popup' or 'modal popup' keyword
594
 
# when it executes this file, and displays a view for it.
595
 
 
596
 
# NOTE2: In this case, Demo class is just a mock object. Essentially we want to
597
 
# execute main instead of displaying a UI for Demo: so we hack this by
598
 
# overriding configure_traits and edit_traits to return a blank UI.
599
 
 
600
 
from traits.api import HasTraits
601
 
from traitsui.api import UI, Handler
602
 
 
603
 
class Demo(HasTraits):
604
 
 
605
 
    def configure_traits(self, *args, **kws):
606
 
        main(embedded=True)
607
 
        return True
608
 
 
609
 
    def edit_traits(self, *args, **kws):
610
 
        main(embedded=True)
611
 
        return UI(handler=Handler())
612
 
 
613
 
popup = Demo()
614
 
 
615
 
if __name__ == "__main__":
616
 
    if '-e' in sys.argv or '--embedded' in sys.argv:
617
 
        main(embedded=True)
618
 
    else:
619
 
        main(embedded=False)
620
 
#-- eof -----------------------------------------------------------------------