Changeset b297ba9 in sasmodels for sasmodels/jitter.py
- Timestamp:
- Mar 20, 2019 5:03:50 PM (5 years ago)
- Branches:
- master, core_shell_microgels, magnetic_model, ticket-1257-vesicle-product, ticket_1156, ticket_1265_superball, ticket_822_more_unit_tests
- Children:
- 4e28511
- Parents:
- 0d362b7
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
sasmodels/jitter.py
rcff2939 rb297ba9 51 51 52 52 import numpy as np 53 from numpy import pi, cos, sin, sqrt, exp, degrees, radians 53 from numpy import pi, cos, sin, sqrt, exp, log, degrees, radians, arccos, arctan2 54 55 # Too many complaints about variable names from pylint: 56 # a, b, c, u, v, x, y, z, dx, dy, dz, px, py, pz, R, Rx, Ry, Rz, ... 57 # pylint: disable=invalid-name 54 58 55 59 def draw_beam(axes, view=(0, 0), alpha=0.5, steps=25): … … 60 64 #axes.scatter([0]*100,[0]*100,np.linspace(1, -1, 100), alpha=alpha) 61 65 62 u = np.linspace(0, 2 * np.pi, steps)66 u = np.linspace(0, 2 * pi, steps) 63 67 v = np.linspace(-1, 1, 2) 64 68 65 69 r = 0.02 66 x = r*np.outer( np.cos(u), np.ones_like(v))67 y = r*np.outer( np.sin(u), np.ones_like(v))70 x = r*np.outer(cos(u), np.ones_like(v)) 71 y = r*np.outer(sin(u), np.ones_like(v)) 68 72 z = 1.3*np.outer(np.ones_like(u), v) 69 73 … … 90 94 """Draw an ellipsoid.""" 91 95 a, b, c = size 92 u = np.linspace(0, 2 * np.pi, steps)93 v = np.linspace(0, np.pi, steps)94 x = a*np.outer( np.cos(u), np.sin(v))95 y = b*np.outer( np.sin(u), np.sin(v))96 z = c*np.outer(np.ones_like(u), np.cos(v))96 u = np.linspace(0, 2 * pi, steps) 97 v = np.linspace(0, pi, steps) 98 x = a*np.outer(cos(u), sin(v)) 99 y = b*np.outer(sin(u), sin(v)) 100 z = c*np.outer(np.ones_like(u), cos(v)) 97 101 x, y, z = transform_xyz(view, jitter, x, y, z) 98 102 … … 167 171 168 172 def draw_box(axes, size, view): 173 """Draw a wireframe box at a particular view.""" 169 174 a, b, c = size 170 175 x = a*np.array([+1, -1, +1, -1, +1, -1, +1, -1]) … … 172 177 z = c*np.array([+1, +1, +1, +1, -1, -1, -1, -1]) 173 178 x, y, z = transform_xyz(view, None, x, y, z) 174 def draw(i, j):175 axes.plot([x[i], x[j]], [y[i], y[j]], [z[i], z[j]], color='black')176 draw(0, 1)177 draw(0, 2)178 draw(0, 3)179 draw(7, 4)180 draw(7, 5)181 draw(7, 6)179 def _draw(i, j): 180 axes.plot([x[i], x[j]], [y[i], y[j]], [z[i], z[j]], color='black') 181 _draw(0, 1) 182 _draw(0, 2) 183 _draw(0, 3) 184 _draw(7, 4) 185 _draw(7, 5) 186 _draw(7, 6) 182 187 183 188 def draw_parallelepiped(axes, size, view, jitter, steps=None, 184 189 color=(0.6, 1.0, 0.6), alpha=1): 185 """Draw a parallelepiped ."""190 """Draw a parallelepiped surface, with view and jitter.""" 186 191 a, b, c = size 187 192 x = a*np.array([+1, -1, +1, -1, +1, -1, +1, -1]) … … 224 229 ]) 225 230 226 def draw_sphere(axes, radius=0.5, steps=25, center=(0,0,0), color='w', alpha=1.): 231 def draw_sphere(axes, radius=0.5, steps=25, 232 center=(0, 0, 0), color='w', alpha=1.): 227 233 """Draw a sphere""" 228 u = np.linspace(0, 2 * np.pi, steps)229 v = np.linspace(0, np.pi, steps)230 231 x = radius * np.outer( np.cos(u), np.sin(v)) + center[0]232 y = radius * np.outer( np.sin(u), np.sin(v)) + center[1]233 z = radius * np.outer(np.ones(np.size(u)), np.cos(v)) + center[2]234 u = np.linspace(0, 2 * pi, steps) 235 v = np.linspace(0, pi, steps) 236 237 x = radius * np.outer(cos(u), sin(v)) + center[0] 238 y = radius * np.outer(sin(u), sin(v)) + center[1] 239 z = radius * np.outer(np.ones(np.size(u)), cos(v)) + center[2] 234 240 axes.plot_surface(x, y, z, color=color, alpha=alpha) 235 241 #axes.plot_wireframe(x, y, z) 236 242 237 243 def draw_axes(axes, origin=(-1, -1, -1), length=(2, 2, 2)): 244 """Draw wireframe axes lines, with given origin and length""" 238 245 x, y, z = origin 239 246 dx, dy, dz = length … … 243 250 244 251 def draw_person_on_sphere(axes, view, height=0.5, radius=0.5): 252 """ 253 Draw a person on the surface of a sphere. 254 255 *view* indicates (latitude, longitude, orientation) 256 """ 245 257 limb_offset = height * 0.05 246 258 head_radius = height * 0.10 … … 259 271 260 272 # circle for head 261 u = np.linspace(0, 2 * np.pi, 40)262 x = head_radius * np.cos(u)263 z = head_radius * np.sin(u) + head_height273 u = np.linspace(0, 2 * pi, 40) 274 x = head_radius * cos(u) 275 z = head_radius * sin(u) + head_height 264 276 _draw_part(x, z) 265 277 … … 304 316 dtheta, dphi, dpsi = jitter 305 317 base = {'gaussian':3, 'rectangle':sqrt(3), 'uniform':1}[dist] 306 def steps(delta):318 def _steps(delta): 307 319 if views is None: 308 320 n = max(3, min(25, 2*int(base*delta/5))) … … 310 322 n = views 311 323 return base*delta*np.linspace(-1, 1, n) if delta > 0 else [0.] 312 for theta in steps(dtheta):313 for phi in steps(dphi):314 for psi in steps(dpsi):324 for theta in _steps(dtheta): 325 for phi in _steps(dphi): 326 for psi in _steps(dpsi): 315 327 w = project_weight(theta, phi, 1.0, 1.0) 316 328 if w > 0: … … 319 331 for v in 'xyz': 320 332 a, b, c = size 321 lim = np.sqrt(a**2 + b**2 + c**2)333 lim = sqrt(a**2 + b**2 + c**2) 322 334 getattr(axes, 'set_'+v+'lim')([-lim, lim]) 323 335 #getattr(axes, v+'axis').label.set_text(v) … … 390 402 def _project(theta_i, phi_j, psi): 391 403 latitude, longitude = theta_i, phi_j 392 return latitude, longitude, psi 404 return latitude, longitude, psi, 'xyz' 393 405 #return Rx(phi_j)*Ry(theta_i) 394 406 def _weight(theta_i, phi_j, w_i, w_j): … … 400 412 longitude = phi_j/scale if abs(phi_j) < abs(scale)*180 else 0 401 413 #print("(%+7.2f, %+7.2f) => (%+7.2f, %+7.2f)"%(theta_i, phi_j, latitude, longitude)) 402 return latitude, longitude, psi 414 return latitude, longitude, psi, 'xyz' 403 415 #return Rx(longitude)*Ry(latitude) 404 416 def _project(theta_i, phi_j, w_i, w_j): … … 412 424 #latitude, longitude = guyou_invert([theta_i], [phi_j]) 413 425 longitude, latitude = guyou_invert([phi_j], [theta_i]) 414 return latitude, longitude, psi 426 return latitude, longitude, psi, 'xyz' 415 427 #return Rx(longitude[0])*Ry(latitude[0]) 416 428 def _weight(theta_i, phi_j, w_i, w_j): … … 420 432 def _project(theta_i, phi_j, psi): 421 433 latitude = sqrt(theta_i**2 + phi_j**2) 422 longitude = degrees( np.arctan2(phi_j, theta_i))434 longitude = degrees(arctan2(phi_j, theta_i)) 423 435 #print("(%+7.2f, %+7.2f) => (%+7.2f, %+7.2f)"%(theta_i, phi_j, latitude, longitude)) 424 436 return latitude, longitude, psi-longitude, 'zyz' … … 462 474 def _project(theta_i, phi_j, psi): 463 475 radius = min(1, sqrt(theta_i**2 + phi_j**2)/180) 464 latitude = 180-degrees(2* np.arccos(radius))465 longitude = degrees( np.arctan2(phi_j, theta_i))476 latitude = 180-degrees(2*arccos(radius)) 477 longitude = degrees(arctan2(phi_j, theta_i)) 466 478 #print("(%+7.2f, %+7.2f) => (%+7.2f, %+7.2f)"%(theta_i, phi_j, latitude, longitude)) 467 return latitude, longitude, psi, "zyz"479 return latitude, longitude, psi, 'zyz' 468 480 #R = Rz(longitude)*Ry(latitude)*Rz(psi) 469 481 #return R_to_xyz(R) … … 487 499 Based on: Shoemakeâs "Euler Angle Conversion", Graphics Gems IV, pp. 222-229 488 500 """ 489 phi = np.arctan2(R[1, 2], R[2, 2])490 theta = np.arctan2(-R[0, 2], np.sqrt(R[0, 0]**2 + R[0, 1]**2))491 psi = np.arctan2(R[0, 1], R[0, 0])492 return np.degrees(phi), np.degrees(theta), np.degrees(psi)501 phi = arctan2(R[1, 2], R[2, 2]) 502 theta = arctan2(-R[0, 2], sqrt(R[0, 0]**2 + R[0, 1]**2)) 503 psi = arctan2(R[0, 1], R[0, 0]) 504 return degrees(phi), degrees(theta), degrees(psi) 493 505 494 506 def draw_mesh(axes, view, jitter, radius=1.2, n=11, dist='gaussian', … … 502 514 def _rotate(theta, phi, z): 503 515 dview = _project(theta, phi, 0.) 504 if len(dview) == 4: # hack for zyz coords516 if dview[3] == 'zyz': 505 517 return Rz(dview[1])*Ry(dview[0])*z 506 else: 518 else: # dview[3] == 'xyz': 507 519 return Rx(dview[1])*Ry(dview[0])*z 508 520 … … 657 669 #orient_relative_to_beam = orient_relative_to_beam_quaternion 658 670 671 # === Quaterion class definition === BEGIN 659 672 # Simple stand-alone quaternion class 660 import numpy as np 661 from copy import copy 673 674 # Note: this code works but isn't unused since quaternions didn't solve the 675 # representation problem. Leave it here in case we want to revisit this later. 676 677 #import numpy as np 662 678 class Quaternion(object): 679 r""" 680 Quaternion(w, r) = w + ir[0] + jr[1] + kr[2] 681 682 Quaternion.from_angle_axis(theta, r) for a rotation of angle theta about 683 an axis oriented toward the direction r. This defines a unit quaternion, 684 normalizing $r$ to the unit vector $\hat r$, and setting quaternion 685 $Q = \cos \theta + \sin \theta \hat r$ 686 687 Quaternion objects can be multiplied, which applies a rotation about the 688 given axis, allowing composition of rotations without risk of gimbal lock. 689 The resulting quaternion is applied to a set of points using *Q.rot(v)*. 690 """ 663 691 def __init__(self, w, r): 664 self.w = w 665 self.r = np.asarray(r, dtype='d') 692 self.w = w 693 self.r = np.asarray(r, dtype='d') 694 666 695 @staticmethod 667 696 def from_angle_axis(theta, r): 668 theta = np.radians(theta)/2 669 r = np.asarray(r) 670 w = np.cos(theta) 671 r = np.sin(theta)*r/np.dot(r,r) 672 return Quaternion(w, r) 697 """Build quaternion as rotation theta about axis r""" 698 theta = np.radians(theta)/2 699 r = np.asarray(r) 700 w = np.cos(theta) 701 r = np.sin(theta)*r/np.dot(r, r) 702 return Quaternion(w, r) 703 673 704 def __mul__(self, other): 705 """Multiply quaterions""" 674 706 if isinstance(other, Quaternion): 675 707 w = self.w*other.w - np.dot(self.r, other.r) 676 708 r = self.w*other.r + other.w*self.r + np.cross(self.r, other.r) 677 709 return Quaternion(w, r) 710 raise NotImplementedError("Quaternion * non-quaternion not implemented") 711 678 712 def rot(self, v): 713 """Transform point *v* by quaternion""" 679 714 v = np.asarray(v).T 680 715 use_transpose = (v.shape[-1] != 3) 681 if use_transpose: v = v.T 716 if use_transpose: 717 v = v.T 682 718 v = v + np.cross(2*self.r, np.cross(self.r, v) + self.w*v) 683 719 #v = v + 2*self.w*np.cross(self.r, v) + np.cross(2*self.r, np.cross(self.r, v)) 684 if use_transpose: v = v.T 720 if use_transpose: 721 v = v.T 685 722 return v.T 723 686 724 def conj(self): 725 """Conjugate quaternion""" 687 726 return Quaternion(self.w, -self.r) 727 688 728 def inv(self): 729 """Inverse quaternion""" 689 730 return self.conj()/self.norm()**2 731 690 732 def norm(self): 733 """Quaternion length""" 691 734 return np.sqrt(self.w**2 + np.sum(self.r**2)) 735 692 736 def __str__(self): 693 737 return "%g%+gi%+gj%+gk"%(self.w, self.r[0], self.r[1], self.r[2]) 738 694 739 def test_qrot(): 695 # Define rotation of 60 degrees around an axis in y-z that is 60 degrees from y. 696 # The rotation axis is determined by rotating the point [0, 1, 0] about x. 740 """Quaternion checks""" 741 # Define rotation of 60 degrees around an axis in y-z that is 60 degrees 742 # from y. The rotation axis is determined by rotating the point [0, 1, 0] 743 # about x. 697 744 ax = Quaternion.from_angle_axis(60, [1, 0, 0]).rot([0, 1, 0]) 698 745 q = Quaternion.from_angle_axis(60, ax) … … 704 751 #test_qrot() 705 752 #import sys; sys.exit() 753 # === Quaterion class definition === END 706 754 707 755 # translate between number of dimension of dispersity and the number of … … 725 773 or the top of the range, depending on whether *mode* is 'central' or 'top'. 726 774 """ 727 if portion == 1.0: 728 return data.min(), data.max() 729 elif mode == 'central': 730 data = np.sort(data.flatten()) 731 offset = int(portion*len(data)/2 + 0.5) 732 return data[offset], data[-offset] 733 elif mode == 'top': 734 data = np.sort(data.flatten()) 735 offset = int(portion*len(data) + 0.5) 736 return data[offset], data[-1] 775 if portion < 1.0: 776 if mode == 'central': 777 data = np.sort(data.flatten()) 778 offset = int(portion*len(data)/2 + 0.5) 779 return data[offset], data[-offset] 780 if mode == 'top': 781 data = np.sort(data.flatten()) 782 offset = int(portion*len(data) + 0.5) 783 return data[offset], data[-1] 784 # Default: full range 785 return data.min(), data.max() 737 786 738 787 def draw_scattering(calculator, axes, view, jitter, dist='gaussian'): … … 765 814 766 815 # compute the pattern 767 qx, qy = calculator. _data.x_bins, calculator._data.y_bins816 qx, qy = calculator.qxqy 768 817 Iqxy = calculator(**pars).reshape(len(qx), len(qy)) 769 818 770 819 # scale it and draw it 771 Iqxy = np.log(Iqxy)820 Iqxy = log(Iqxy) 772 821 if calculator.limits: 773 822 # use limits from orientation (0,0,0) … … 781 830 #qx, qy = np.meshgrid(qx, qy) 782 831 if 0: 783 from matplotlib import cm784 832 level = np.asarray(255*(Iqxy - vmin)/(vmax - vmin), 'i') 785 833 level[level < 0] = 0 834 from matplotlib import pylab as plt 786 835 colors = plt.get_cmap()(level) 836 #from matplotlib import cm 787 837 #colors = cm.coolwarm(level) 788 838 #colors = cm.gist_yarg(level) 789 839 #colors = cm.Wistia(level) 790 colors[level <=0, 3] = 0. # set floor to transparent840 colors[level <= 0, 3] = 0. # set floor to transparent 791 841 x, y = np.meshgrid(qx/qx.max(), qy/qy.max()) 792 842 axes.plot_surface(x, y, -1.1*np.ones_like(x), facecolors=colors) … … 822 872 calculator = DirectModel(data, model) 823 873 874 # Remember the data axes so we can plot the results 875 calculator.qxqy = (q, q) 876 824 877 # stuff the values for non-orientation parameters into the calculator 825 878 calculator.pars = pars.copy() … … 829 882 # under rotation or angular dispersion 830 883 Iqxy = calculator(theta=0, phi=0, psi=0, **calculator.pars) 831 Iqxy = np.log(Iqxy)884 Iqxy = log(Iqxy) 832 885 vmin, vmax = clipped_range(Iqxy, 0.95, mode='top') 833 886 calculator.limits = vmin, vmax+1 … … 963 1016 PLOT_ENGINE(calculator, draw_shape, size, view, jitter, dist, mesh, projection) 964 1017 965 def mpl_plot(calculator, draw_shape, size, view, jitter, dist, mesh, projection):1018 def _mpl_plot(calculator, draw_shape, size, view, jitter, dist, mesh, projection): 966 1019 # Note: travis-ci does not support mpl_toolkits.mplot3d, but this shouldn't be 967 1020 # an issue since we are lazy-loading the package on a path that isn't tested. … … 1020 1073 1021 1074 ## callback to draw the new view 1022 def update(val, axis=None):1075 def _update(val, axis=None): 1023 1076 view = stheta.val, sphi.val, spsi.val 1024 1077 jitter = sdtheta.val, sdphi.val, sdpsi.val … … 1047 1100 1048 1101 ## bind control widgets to view updater 1049 stheta.on_changed(lambda v: update(v, 'theta'))1050 sphi.on_changed(lambda v: update(v, 'phi'))1051 spsi.on_changed(lambda v: update(v, 'psi'))1052 sdtheta.on_changed(lambda v: update(v, 'dtheta'))1053 sdphi.on_changed(lambda v: update(v, 'dphi'))1054 sdpsi.on_changed(lambda v: update(v, 'dpsi'))1102 stheta.on_changed(lambda v: _update(v, 'theta')) 1103 sphi.on_changed(lambda v: _update(v, 'phi')) 1104 spsi.on_changed(lambda v: _update(v, 'psi')) 1105 sdtheta.on_changed(lambda v: _update(v, 'dtheta')) 1106 sdphi.on_changed(lambda v: _update(v, 'dphi')) 1107 sdpsi.on_changed(lambda v: _update(v, 'dpsi')) 1055 1108 1056 1109 ## initialize view 1057 update(None, 'phi')1110 _update(None, 'phi') 1058 1111 1059 1112 ## go interactive … … 1062 1115 1063 1116 def map_colors(z, kw): 1117 """ 1118 Process matplotlib-style colour arguments. 1119 1120 Pulls 'cmap', 'alpha', 'vmin', and 'vmax' from th *kw* dictionary, setting 1121 the *kw['color']* to an RGB array. These are ignored if 'c' or 'color' are 1122 set inside *kw*. 1123 """ 1064 1124 from matplotlib import cm 1065 1125 … … 1083 1143 1084 1144 def make_vec(*args): 1145 """Turn all elements of *args* into numpy arrays""" 1085 1146 #return [np.asarray(v, 'd').flatten() for v in args] 1086 1147 return [np.asarray(v, 'd') for v in args] 1087 1148 1088 1149 def make_image(z, kw): 1150 """Convert numpy array *z* into a *PIL* RGB image.""" 1089 1151 import PIL.Image 1090 1152 from matplotlib import cm … … 1113 1175 'b': 'blue', 1114 1176 } 1115 def ipv_fix_color(kw):1177 def _ipv_fix_color(kw): 1116 1178 alpha = kw.pop('alpha', None) 1117 1179 color = kw.get('color', None) … … 1132 1194 kw['color'] = color 1133 1195 1134 def ipv_set_transparency(kw, obj):1196 def _ipv_set_transparency(kw, obj): 1135 1197 color = kw.get('color', None) 1136 1198 if (isinstance(color, np.ndarray) … … 1141 1203 1142 1204 def ipv_axes(): 1205 """ 1206 Build a matplotlib style Axes interface for ipyvolume 1207 """ 1143 1208 import ipyvolume as ipv 1144 1209 1145 class Plotter: 1210 class Axes: 1211 """ 1212 Matplotlib Axes3D style interface to ipyvolume renderer. 1213 """ 1146 1214 # transparency can be achieved by setting the following: 1147 1215 # mesh.color = [r, g, b, alpha] … … 1156 1224 # maybe need to synchronize update of x/y/z to avoid shimmy when moving 1157 1225 def plot(self, x, y, z, **kw): 1158 ipv_fix_color(kw) 1226 """mpl style plot interface for ipyvolume""" 1227 _ipv_fix_color(kw) 1159 1228 x, y, z = make_vec(x, y, z) 1160 1229 ipv.plot(x, y, z, **kw) 1161 1230 def plot_surface(self, x, y, z, **kw): 1231 """mpl style plot_surface interface for ipyvolume""" 1162 1232 facecolors = kw.pop('facecolors', None) 1163 1233 if facecolors is not None: 1164 1234 kw['color'] = facecolors 1165 ipv_fix_color(kw)1235 _ipv_fix_color(kw) 1166 1236 x, y, z = make_vec(x, y, z) 1167 1237 h = ipv.plot_surface(x, y, z, **kw) 1168 ipv_set_transparency(kw, h)1238 _ipv_set_transparency(kw, h) 1169 1239 #h.material.side = "DoubleSide" 1170 1240 return h 1171 1241 def plot_trisurf(self, x, y, triangles=None, Z=None, **kw): 1242 """mpl style plot_trisurf interface for ipyvolume""" 1172 1243 kw.pop('linewidth', None) 1173 ipv_fix_color(kw)1244 _ipv_fix_color(kw) 1174 1245 x, y, z = make_vec(x, y, Z) 1175 1246 if triangles is not None: 1176 1247 triangles = np.asarray(triangles) 1177 1248 h = ipv.plot_trisurf(x, y, z, triangles=triangles, **kw) 1178 ipv_set_transparency(kw, h)1249 _ipv_set_transparency(kw, h) 1179 1250 return h 1180 1251 def scatter(self, x, y, z, **kw): 1252 """mpl style scatter interface for ipyvolume""" 1181 1253 x, y, z = make_vec(x, y, z) 1182 1254 map_colors(z, kw) … … 1184 1256 kw['marker'] = _IPV_MARKERS.get(marker, marker) 1185 1257 h = ipv.scatter(x, y, z, **kw) 1186 ipv_set_transparency(kw, h)1258 _ipv_set_transparency(kw, h) 1187 1259 return h 1188 1260 def contourf(self, x, y, v, zdir='z', offset=0, levels=None, **kw): 1261 """mpl style contourf interface for ipyvolume""" 1189 1262 # Don't use contour for now (although we might want to later) 1190 1263 self.pcolor(x, y, v, zdir='z', offset=offset, **kw) 1191 1264 def pcolor(self, x, y, v, zdir='z', offset=0, **kw): 1265 """mpl style pcolor interface for ipyvolume""" 1192 1266 x, y, v = make_vec(x, y, v) 1193 1267 image = make_image(v, kw) … … 1200 1274 v = np.array([[0., 0], [1, 1]]) 1201 1275 h = ipv.plot_mesh(x, y, z, u=u, v=v, texture=image, wireframe=False) 1202 ipv_set_transparency(kw, h)1276 _ipv_set_transparency(kw, h) 1203 1277 h.material.side = "DoubleSide" 1204 1278 return h 1205 1279 def text(self, *args, **kw): 1280 """mpl style text interface for ipyvolume""" 1206 1281 pass 1207 1282 def set_xlim(self, limits): 1283 """mpl style set_xlim interface for ipyvolume""" 1208 1284 ipv.xlim(*limits) 1209 1285 def set_ylim(self, limits): 1286 """mpl style set_ylim interface for ipyvolume""" 1210 1287 ipv.ylim(*limits) 1211 1288 def set_zlim(self, limits): 1289 """mpl style set_zlim interface for ipyvolume""" 1212 1290 ipv.zlim(*limits) 1213 1291 def set_axes_on(self): 1292 """mpl style set_axes_on interface for ipyvolume""" 1214 1293 ipv.style.axis_on() 1215 1294 def set_axis_off(self): 1295 """mpl style set_axes_off interface for ipyvolume""" 1216 1296 ipv.style.axes_off() 1217 return Plotter() 1218 1219 def ipv_plot(calculator, draw_shape, size, view, jitter, dist, mesh, projection): 1297 return Axes() 1298 1299 def _ipv_plot(calculator, draw_shape, size, view, jitter, dist, mesh, projection): 1300 from IPython.display import display 1220 1301 import ipywidgets as widgets 1221 1302 import ipyvolume as ipv … … 1223 1304 axes = ipv_axes() 1224 1305 1225 def draw(view, jitter):1306 def _draw(view, jitter): 1226 1307 camera = ipv.gcf().camera 1227 1308 #print(ipv.gcf().__dict__.keys()) … … 1271 1352 #widgets.interact(update, Ξ=trange, Ï=prange, Ï=prange, ÎΞ=dtrange, ÎÏ=dprange, ÎÏ=dprange) 1272 1353 1273 def update(theta, phi, psi, dtheta, dphi, dpsi):1274 draw(view=(theta, phi, psi), jitter=(dtheta, dphi, dpsi))1275 1276 def slider(name, slice, init=0.):1354 def _update(theta, phi, psi, dtheta, dphi, dpsi): 1355 _draw(view=(theta, phi, psi), jitter=(dtheta, dphi, dpsi)) 1356 1357 def _slider(name, slice, init=0.): 1277 1358 return widgets.FloatSlider( 1278 1359 value=init, … … 1288 1369 readout_format='.1f', 1289 1370 ) 1290 theta = slider(u'Ξ', trange, view[0])1291 phi = slider(u'Ï', prange, view[1])1292 psi = slider(u'Ï', prange, view[2])1293 dtheta = slider(u'ÎΞ', dtrange, jitter[0])1294 dphi = slider(u'ÎÏ', dprange, jitter[1])1295 dpsi = slider(u'ÎÏ', dprange, jitter[2])1371 theta = _slider(u'Ξ', trange, view[0]) 1372 phi = _slider(u'Ï', prange, view[1]) 1373 psi = _slider(u'Ï', prange, view[2]) 1374 dtheta = _slider(u'ÎΞ', dtrange, jitter[0]) 1375 dphi = _slider(u'ÎÏ', dprange, jitter[1]) 1376 dpsi = _slider(u'ÎÏ', dprange, jitter[2]) 1296 1377 fields = { 1297 1378 'theta': theta, 'phi': phi, 'psi': psi, … … 1303 1384 ]) 1304 1385 1305 out = widgets.interactive_output( update, fields)1386 out = widgets.interactive_output(_update, fields) 1306 1387 display(ui, out) 1307 1388 1308 1389 1309 1390 _ENGINES = { 1310 "matplotlib": mpl_plot,1311 "mpl": mpl_plot,1312 #"plotly": plotly_plot,1313 "ipvolume": ipv_plot,1314 "ipv": ipv_plot,1391 "matplotlib": _mpl_plot, 1392 "mpl": _mpl_plot, 1393 #"plotly": _plotly_plot, 1394 "ipvolume": _ipv_plot, 1395 "ipv": _ipv_plot, 1315 1396 } 1316 1397 PLOT_ENGINE = _ENGINES["matplotlib"] 1317 1398 def set_plotter(name): 1399 """ 1400 Setting the plotting engine to matplotlib/ipyvolume or equivalently mpl/ipv. 1401 """ 1318 1402 global PLOT_ENGINE 1319 1403 PLOT_ENGINE = _ENGINES[name] 1320 1404 1321 1405 def main(): 1406 """ 1407 Command line interface to the jitter viewer. 1408 """ 1322 1409 parser = argparse.ArgumentParser( 1323 1410 description="Display jitter",
Note: See TracChangeset
for help on using the changeset viewer.