Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 9a83bff

Browse files
huardmdboom
authored andcommitted
simplified javascript code and added CSS transitions.
1 parent 80d1a7c commit 9a83bff

1 file changed

Lines changed: 71 additions & 43 deletions

File tree

examples/user_interfaces/svg_histogram.py

Lines changed: 71 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,38 @@
55
Demonstrate how to create an interactive histogram, in which bars
66
are hidden or shown by cliking on legend markers.
77
8-
The interactivity is encoded in ecmascript and inserted in the SVG code
9-
in a post-processing step. To render the image, open it in a web
10-
browser. SVG is supported in most web browsers used by Linux and OSX
11-
users. Windows IE9 supports SVG, but earlier versions do not.
8+
The interactivity is encoded in ecmascript (javascript) and inserted in
9+
the SVG code in a post-processing step. To render the image, open it in
10+
a web browser. SVG is supported in most web browsers used by Linux and
11+
OSX users. Windows IE9 supports SVG, but earlier versions do not.
12+
13+
Notes
14+
-----
15+
The matplotlib backend lets us assign ids to each object. This is the
16+
mechanism used here to relate matplotlib objects created in python and
17+
the corresponding SVG constructs that are parsed in the second step.
18+
While flexible, ids are cumbersome to use for large collection of
19+
objects. Two mechanisms could be used to simplify things:
20+
* systematic grouping of objects into SVG <g> tags,
21+
* assingning classes to each SVG object according to its origin.
22+
23+
For example, instead of modifying the properties of each individual bar,
24+
the bars from the `hist` function could either be grouped in
25+
a PatchCollection, or be assigned a class="hist_##" attribute.
26+
27+
CSS could also be used more extensively to replace repetitive markup
28+
troughout the generated SVG.
1229
1330
__author__="[email protected]"
1431
1532
"""
1633

34+
1735
import numpy as np
1836
import matplotlib.pyplot as plt
1937
import xml.etree.ElementTree as ET
2038
from StringIO import StringIO
39+
import json
2140

2241
plt.rcParams['svg.embed_char_paths'] = 'none'
2342

@@ -26,16 +45,7 @@
2645
# space with ns0.
2746
ET.register_namespace("","http://www.w3.org/2000/svg")
2847

29-
30-
def python2js(d):
31-
"""Return a string representation of a python dictionary in
32-
ecmascript object syntax."""
33-
34-
objs = []
35-
for key, value in d.items():
36-
objs.append( key + ':' + str(value) )
37-
38-
return '{' + ', '.join(objs) + '}'
48+
3949

4050

4151
# --- Create histogram, legend and title ---
@@ -62,7 +72,11 @@ def python2js(d):
6272
# Set ids for the legend patches
6373
for i, t in enumerate(leg.get_patches()):
6474
t.set_gid('leg_patch_%d'%i)
65-
75+
76+
# Set ids for the text patches
77+
for i, t in enumerate(leg.get_texts()):
78+
t.set_gid('leg_text_%d'%i)
79+
6680
# Save SVG in a fake file object.
6781
f = StringIO()
6882
plt.savefig(f, format="svg")
@@ -77,10 +91,15 @@ def python2js(d):
7791
for i, t in enumerate(leg.get_patches()):
7892
el = xmlid['leg_patch_%d'%i]
7993
el.set('cursor', 'pointer')
80-
el.set('opacity', '1.0')
81-
el.set('onclick', "toggle_element(evt, 'hist_%d')"%i)
94+
el.set('onclick', "toggle_hist(this)")
8295

83-
# Create script defining the function `toggle_element`.
96+
# Add attributes to the text objects.
97+
for i, t in enumerate(leg.get_texts()):
98+
el = xmlid['leg_text_%d'%i]
99+
el.set('cursor', 'pointer')
100+
el.set('onclick', "toggle_hist(this)")
101+
102+
# Create script defining the function `toggle_hist`.
84103
# We create a global variable `container` that stores the patches id
85104
# belonging to each histogram. Then a function "toggle_element" sets the
86105
# visibility attribute of all patches of each histogram and the opacity
@@ -91,37 +110,46 @@ def python2js(d):
91110
<![CDATA[
92111
var container = %s
93112
94-
function toggle_element(evt, element) {
113+
function toggle(oid, attribute, values) {
114+
/* Toggle the style attribute of an object between two values.
115+
116+
Parameters
117+
----------
118+
oid : str
119+
Object identifier.
120+
attribute : str
121+
Name of syle attribute.
122+
values : [on state, off state]
123+
The two values that are switched between.
124+
*/
125+
var obj = document.getElementById(oid);
126+
var a = obj.style[attribute];
127+
128+
a = (a == values[0] || a == "") ? values[1] : values[0];
129+
obj.style[attribute] = a;
130+
}
95131
96-
var names = container[element]
97-
var el, state;
132+
function toggle_hist(obj) {
98133
99-
state = evt.target.getAttribute("opacity") == 1.0 ||
100-
evt.target.getAttribute("opacity") == null;
101-
102-
if (state) {
103-
evt.target.setAttribute("opacity", 0.5);
104-
105-
for (var i=0; i < names.length; i++) {
106-
el = document.getElementById(names[i]);
107-
el.setAttribute("visibility","hidden");
108-
}
109-
}
110-
111-
else {
112-
evt.target.setAttribute("opacity", 1);
113-
114-
for (var i=0; i < names.length; i++) {
115-
el = document.getElementById(names[i]);
116-
el.setAttribute("visibility","visible");
117-
}
118-
119-
};
134+
var num = obj.id.slice(-1);
135+
136+
toggle('leg_patch_' + num, 'opacity', [1, 0.3]);
137+
toggle('leg_text_' + num, 'opacity', [1, 0.5]);
138+
139+
var names = container['hist_'+num]
140+
141+
for (var i=0; i < names.length; i++) {
142+
toggle(names[i], 'opacity', [1,0])
120143
};
144+
}
121145
]]>
122146
</script>
123-
"""%python2js(hist_patches)
147+
"""%json.dumps(hist_patches)
124148

149+
# Add a transition effect
150+
css = tree.getchildren()[0][0]
151+
css.text = css.text + "g {-webkit-transition:opacity 0.4s ease-out;-moz-transition:opacity 0.4s ease-out;}"
152+
125153
# Insert the script and save to file.
126154
tree.insert(0, ET.XML(script))
127155

0 commit comments

Comments
 (0)