Well, I've continued to work on it, if only because I thought it would
be good to get experience with coding something like this. And I think
I've improved things somewhat. I still haven't worked on fixing the
problem with *how* it displays when it comes to animations (that is, I
haven't sorted out animations where frames aren't all well-aligned
already), but I've tweaked things in terms of the interface itself.

So, here are the relevant changes, including all of the previous
changes (where necessary to have it run by just issuing the
appropriate cython compile command and then "sage -b"):

---- /devel/sagenb-main/sagenb/notebook/cell.py - between "elif
F.endswith('.jmol'):" and "elif F.endswith('.jmol.zip'):" lines ----
            elif F.endswith('.jmol'):
                # If F ends in -size500.jmol then we make the viewer
applet with size 500.
                i = F.rfind('-size')
                if i != -1:
                    if F.endswith('a.jmol'):
                        size = F[i+5:-6]
                    else:
                        size = F[i+5:-5]
                else:
                    size = 500

                if self.worksheet().docbrowser():
                    jmol_name = os.path.join(self.directory(), F)
                    jmol_file = open(jmol_name, 'r')
                    jmol_script = jmol_file.read()
                    jmol_file.close()

                    jmol_script =
jmol_script.replace('defaultdirectory "', 'defaultdirectory "' +
self.url_to_self() + '/')

                    jmol_file = open(jmol_name, 'w')
                    jmol_file.write(jmol_script)
                    jmol_file.close()

                if F.endswith('a.jmol'):
                    script = '<div><script>jmol_applet_anim(%s, "%s?
%d");</script></div>' % (size, url, time.time())
                else:
                    script = '<div><script>jmol_applet(%s, "%s?%d");</
script></div>' % (size, url, time.time())
                images.append(script)
            elif F.endswith('.jmol.zip'):

(This allows the code to recognise the difference between animated
jmol applets and normal ones, so that the animated ones have animation
control on the interface.

---- /devel/sagenb-main/sagenb/data/sage/js/jmol_lib.js - replacing
function jmol_applet(size, url) ----
function jmol_applet(size, url) {
    var s;
    jmolSetDocument(cell_writer);
    jmolSetAppletCssClass('jmol_applet');
    cell_writer.write('<table border=0 bgcolor="white"><tr><td>');
    jmolApplet(size, "script " + url, jmol_count);
    s = '</td><td><input type="button" onclick="jmol_image(' +
jmol_count +
        ');return false;" value="Get Image"><br>' +
        '<form name="MyForm'+jmol_count+'" action="#"
onsubmit="jmolResize(100*document.MyForm'+jmol_count+'.jmolResizeText'
+ jmol_count + '.value,100*document.MyForm'+jmol_count
+'.jmolResizeText' + jmol_count + '.value,' + jmol_count + ');return
false;"><input type="text" size=2 value=5 name="jmolResizeText' +
jmol_count + '"><input type="submit" value="Resize"></form>' +
        '</td></tr></table>';
    cell_writer.write(s);
    jmol_count += 1;
    return s;
}

function jmol_applet_anim(size, url) {
    var s;
    jmolSetDocument(cell_writer);
    jmolSetAppletCssClass('jmol_applet');
    cell_writer.write('<table border=0 bgcolor="white"><tr><td>');
    jmolApplet(size, "script " + url, jmol_count);
    s = '</td><td><input type="button" onclick="jmol_image(' +
jmol_count +
        ');return false;" value="Get Image"><br>' +
        'Animation: <input type="button"
onclick="jmolFrameControl(true,'+jmol_count+')" value="On"><input
type="button" onclick="jmolFrameControl(false,'+jmol_count+')"
value="Off"><br>' +
        '<form name="MyForm'+jmol_count+'" action="#"
onsubmit="jmolResize(100*document.MyForm'+jmol_count+'.jmolResizeText'
+ jmol_count + '.value,100*document.MyForm'+jmol_count
+'.jmolResizeText' + jmol_count + '.value,' + jmol_count + ');return
false;"><input type="text" size=2 value=5 name="jmolResizeText' +
jmol_count + '"><input type="submit" value="Resize"></form>' +
        '</td></tr></table>';
    cell_writer.write(s);
    jmol_count += 1;
    return s;
}

function jmolFrameControl(onval,jmolcount) {
    if (onval) {
        jmolScript("frame play",jmolcount);
    } else {
        jmolScript("frame pause",jmolcount);
    }
}

(The first function is the original jmol_applet with some
modifications. The second function is the animation-appropriate
version, and the third function provides the command functionality for
the animations)

---- /devel/sage-main/sage/plot/plot3d/base.pyx - export_jmol
function, main comment removed ----
    def export_jmol(self, filename='jmol_shape.jmol',
force_reload=False,
                    zoom=100, spin=False, background=(1,1,1),
stereo=False,
                    mesh=False, dots=False,
                    perspective_depth = True,
                    orientation = (-764,-346,-545,76.39),
                    moreframes = [1, 1, 1, 1, 1, []], **ignored_kwds):
        render_params = self.default_render_params()
        render_params.mesh = mesh
        render_params.dots = dots
        render_params.output_file = filename
        render_params.force_reload = render_params.randomize_counter =
force_reload
        render_params.output_archive = zipfile.ZipFile(filename, 'w',
zipfile.ZIP_DEFLATED, True)
        # Render the data
        all = flatten_list([self.jmol_repr(render_params), ""])

        numextraframes=len(moreframes[5])
        if numextraframes:
            all_otherframes = []
            frame = moreframes[0]
            axes = moreframes[1]
            frame_aspect_ratio = moreframes[2]
            aspect_ratio = moreframes[3]
            zoom_other = moreframes[4]
            moreframes=moreframes[5]
            for framenum in xrange(numextraframes):
                MF=moreframes[framenum]._prepare_for_jmol(frame, axes,
frame_aspect_ratio, aspect_ratio, zoom_other,labels=False)
 
all_otherframes.append(flatten_list([MF.jmol_repr(render_params),
""]))
        f = StringIO()

        if render_params.atom_list:
            # Load the atom model
            f.write('data "model list"\n')
            for framenum in xrange(numextraframes+1):
                f.write('%s\nempty\n' % (len(render_params.atom_list)
+ 1))
                for atom in render_params.atom_list:
                    f.write('Xx %s %s %s\n' % atom)
                f.write('Xx 5.5 5.5 5.5\n') # so the zoom fits the box
            f.write('end "model list"; show data\n')
            f.write('select *\n')
            f.write('wireframe off; spacefill off\n')
            f.write('set labelOffset 0 0\n')


        # Set the scene background color
        f.write('background [%s,%s,%s]\n'%tuple([int(a*255) for a in
background]))
        if spin:
            f.write('spin ON\n')
        else:
            f.write('spin OFF\n')
        if stereo:
            if stereo is True: stereo = "redblue"
            f.write('stereo %s\n' % stereo)
        if orientation:
            f.write('moveto 0 %s %s %s %s\n'%tuple(orientation))

        f.write('centerAt absolute {0 0 0}\n')
        f.write('zoom %s\n'%zoom)
        f.write('frank OFF\n') # jmol logo

        if perspective_depth:
            f.write('set perspectivedepth ON\n')
        else:
            f.write('set perspectivedepth OFF\n')

        # Put the rest of the object in
        f.write("\n".join(all))
        if numextraframes:
            for framenum in xrange(numextraframes):
                f.write('\nframe 1.%s\n'%(framenum+2))
                f.write("\n".join(all_otherframes[framenum]))
        # Make sure the lighting is correct
        f.write("isosurface fullylit; pmesh o* fullylit; set
antialiasdisplay on;\n")
        if numextraframes:
            f.write("frame 1.1;animation mode loop 0 0;animation fps
10;animation on\n")

        render_params.output_archive.writestr('SCRIPT', f.getvalue())
        render_params.output_archive.close()

---- /devel/sage-main/sage/plot/plot3d/base.pyx - _prepare_for_jmol
function ----
    def _prepare_for_jmol(self, frame, axes, frame_aspect_ratio,
aspect_ratio, zoom, labels=True):
        from sage.plot.plot import EMBEDDED_MODE
        if EMBEDDED_MODE:
            s = 6
        else:
            s = 3
        box_min, box_max =
self._rescale_for_frame_aspect_ratio_and_zoom(s, frame_aspect_ratio,
zoom)
        a_min, a_max = self._box_for_aspect_ratio(aspect_ratio,
box_min, box_max)
        return self._transform_to_bounding_box(box_min, box_max,
a_min, a_max, frame=frame,
                                               axes=axes, thickness=1,
                                               labels = labels)   #
jmol labels are implemented

(added "labels=True" in arguments and replaced "labels=True" in return
command with "labels=labels")

---- /devel/sage-main/sage/plot/plot3d/base.pyx - show function, main
comment removed ----
    def show(self, moreframes=[], **kwds):
        opts = self._process_viewing_options(kwds)

        viewer = opts['viewer']
        verbosity = opts['verbosity']
        figsize = opts['figsize']
        aspect_ratio = opts['aspect_ratio']
        frame_aspect_ratio = opts['frame_aspect_ratio']
        zoom = opts['zoom']
        frame = opts['frame']
        axes = opts['axes']

        import sage.misc.misc
        if 'filename' in kwds:
            filename = kwds['filename']
            del kwds['filename']
        else:
            filename = sage.misc.misc.tmp_filename()

        from sage.plot.plot import EMBEDDED_MODE, DOCTEST_MODE
        ext = None

        # Tachyon resolution options
        if DOCTEST_MODE:
            opts = '-res 10 10'
            filename = sage.misc.misc.SAGE_TMP + "/tmp"
        elif EMBEDDED_MODE:
            opts = '-res %s %s'%(figsize[0]*100, figsize[1]*100)
            filename = sage.misc.misc.graphics_filename()[:-4]
        else:
            opts = '-res %s %s'%(figsize[0]*100, figsize[1]*100)

        if DOCTEST_MODE or viewer=='tachyon' or (viewer=='java3d' and
EMBEDDED_MODE):
            T = self._prepare_for_tachyon(frame, axes,
frame_aspect_ratio, aspect_ratio, zoom)
            tachyon_rt(T.tachyon(), filename+".png", verbosity, True,
opts)
            ext = "png"
            import sage.misc.viewer
            viewer_app = sage.misc.viewer.browser()

        if DOCTEST_MODE or viewer=='java3d':
            f = open(filename+".obj", "w")
            f.write("mtllib %s.mtl\n" % filename)
            f.write(self.obj())
            f.close()
            f = open(filename+".mtl", "w")
            f.write(self.mtl_str())
            f.close()
            ext = "obj"
            viewer_app = os.path.join(sage.misc.misc.SAGE_LOCAL, "bin/
sage3d")

        if DOCTEST_MODE or viewer=='jmol':
            # Temporary hack: encode the desired applet size in the
end of the filename:
            # (This will be removed once we have dynamic resizing of
applets in the browser.)
            base, ext = os.path.splitext(filename)
            fg = figsize[0]
            #if fg >= 2:
            #    fg = 2
            filename = '%s-size%s%s'%(base, fg*100, ext)
            ext = "jmol"
            archive_name = "%s.%s.zip" % (filename, ext)
            if EMBEDDED_MODE:
                # jmol doesn't seem to correctly parse the ?params
part of a URL
                archive_name = "%s-%s.%s.zip" % (filename, randint(0,
1 << 30), ext)

            T = self._prepare_for_jmol(frame, axes,
frame_aspect_ratio, aspect_ratio, zoom)
            T.export_jmol(archive_name, force_reload=EMBEDDED_MODE,
zoom=zoom*100, moreframes=[frame, axes, frame_aspect_ratio,
aspect_ratio, zoom, moreframes], **kwds)
            viewer_app = os.path.join(sage.misc.misc.SAGE_LOCAL, "bin/
jmol")

            # We need a script to load the file
            if moreframes:
                f = open(filename + 'a.jmol', 'w')
            else:
                f = open(filename + '.jmol', 'w')
            f.write('set defaultdirectory "%s"\n' % archive_name)
            f.write('script SCRIPT\n')
            f.close()

        if viewer == 'canvas3d':
            T = self._prepare_for_tachyon(frame, axes,
frame_aspect_ratio, aspect_ratio, zoom)
            data =
flatten_list(T.json_repr(T.default_render_params()))
            f = open(filename + '.canvas3d', 'w')
            f.write('[%s]' % ','.join(data))
            f.close()
            ext = 'canvas3d'

        if ext is None:
            raise ValueError, "Unknown 3d plot type: %s" % viewer

        if not DOCTEST_MODE and not EMBEDDED_MODE:
            if verbosity:
                pipes = "2>&1"
            else:
                pipes = "2>/dev/null 1>/dev/null &"
            os.system('%s "%s.%s" %s' % (viewer_app, filename, ext,
pipes))

(note that for animated jmol animations, this puts an "a" on the end
of the filename, prior to the extension. This will cause the function
to fail if cell.py and jmol_lib.js are not amended as noted above)


I *think* that's all of the code that I changed - if the code doesn't
seem to work, let me know, so I can try to find any bits of change
that I may have made. So, what does it do? Right now, it adjusts the
display to have a "Get Image" button rather than a text link, it adds
a resize option (put a "3" into the text box and hit the resize
button, and it'll make the applet 300x300, for instance), and if it's
an animation, it provides animation "on" and "off" buttons. As a test
run, use the following code in the notebook:

x,y=var('x y')
ps1=[plot3d(cos(2*pi*sqrt((x^2+y^2)/2)+t),(x,-1,1),
(y,-1,1),color='blue',adaptive=True,aspect_ratio=(1,1,1))
+cube((0,0,1.5),color='red').rotate((0,0,1),t/4) for t in
srange(0,2*pi,pi/12)]
ps1[0].show(moreframes=ps1[1:])

This should create an animated jmol of a rotating red cube above a
blue plot that appears like a circular wave rippling out from the
centre. To see the animation buttons disappear, and to confirm that
the code still works without animation, just remove
"moreframes=ps1[1:]" from the show command, and it will show the first
frame only, with the resize and get image options, but no animation
option.

I'm still working on it, though. I'm certainly getting a better feel
of how sage's code works, so I may be able to look into "interact"
jmol plots that don't require reloading of the applet. But the next
step is to fix it so that it uses an appropriate scaling to keep the
entire plot stable, rather than having each frame generated with its
own bounds.

On Sep 30, 3:09 pm, Jonathan <gu...@uwosh.edu> wrote:
> It would definitely be good to figure out an interactive version.  I
> keep intending to work on this but have had no time.  It would make
> interacts work much better.  The problem is that by default the server
> deletes everything in a cell output div when the cell is
> recalculated.  I was thinking about putting the jmol in a separate
> "applet" div that would only be deleted if the recalculation did not
> generate Jmol data.  This requires reworking both the python of plot3D
> and the notebook javascript.  If you've got time to work on this now,
> I'm willing to provide insight into Jmol, just not much coding time.
> I personally think the interactive version may be higher priority.
>
> Jonathan

-- 
To post to this group, send an email to sage-devel@googlegroups.com
To unsubscribe from this group, send an email to 
sage-devel+unsubscr...@googlegroups.com
For more options, visit this group at http://groups.google.com/group/sage-devel
URL: http://www.sagemath.org

Reply via email to