class DataGrid(DataGridBase, W.Box): """An (overly) opinionated `DataFrame`-backed datagrid ``[0.1.6]/datagrid.ts#L64`` Used JSONModel, which expect JSON Table Schema ``[0.1.6]/jsonmodel.ts#L21`` """ _model_name = T.Unicode("DataGridModel").tag(sync=True) _view_name = T.Unicode("DataGridView").tag(sync=True) value = TT.DataFrame(None, allow_none=True).tag( sync=True, to_json=lambda df, obj: None if df is None else json.loads(df.to_json(**TABLE)), from_json=lambda value, obj: None if value is None else pd.read_json(json.dumps(value), **TABLE), ) def _repr_keys(self): """this shouldn't be needed, but we're doing _something wrong_""" try: super_keys = super()._repr_keys() for key in super_keys: if key != "value": yield key except Exception: return
class FrameLinkedPlot(widgets.Box): ploty = tl.List(tl.Union([tl.Integer(), tl.Unicode()]), default_value=[0]) plotx = tl.Union([tl.Integer(), tl.Unicode()], default_value=1) stride = tl.Integer(default_value=1) title = tl.Unicode(default_value='') colvars = tl.List(trait=tl.Union([tt.DataFrame(), tt.Array()]), read_only=True) bokeh = tl.Instance(klass=BokehWrapper, read_only=True) views = tl.List(trait=NGLViewTrait(), read_only=True) sources = tl.List(trait=CDSTrait(), read_only=True) _reuse_colvars = tl.Bool(read_only=True) def_button_layout = widgets.Layout(height='30px') def_view_layout = dict(width='250px', height='300px', flex='0 0 auto') def_figure_layout = widgets.Layout(width='400', height='550') def_box_layout = widgets.Layout(display='flex', flex_flow='column wrap', height='650px', width='100%', align_items='flex-start') def __init__(self, colvars, mdtraj_trajectories, plotx_label=None, ploty_label=None, ploty=None, legendlocation='top_right', **kwargs): super().__init__(**kwargs) # colvars and mdtraj_trajectories can be specified either as a list or a single item if isinstance(mdtraj_trajectories, Trajectory): mdtrajs = [mdtraj_trajectories] else: mdtrajs = list(mdtraj_trajectories) if isinstance(colvars, DataFrame) or isinstance(colvars, Mapping): cvs = [colvars] else: cvs = list(colvars) if len(mdtrajs) != 1 and len(cvs) != len(mdtrajs) and len(ploty) != len(mdtrajs): print(len(mdtrajs), len(cvs), len(ploty)) raise ValueError("Should have either 1 mdtraj trajectory, or one for every colvar") # ploty wasn't given to super, so it's currently the default per the traitlet # So if it was user-specified, we need to make sure its a list and then # throw it in if isinstance(ploty, str): print("ploty is a str") self.ploty = [ploty] * len(cvs) elif ploty is not None: try: self.ploty = list(iter(ploty)) except TypeError: self.ploty = [ploty] * len(cvs) else: if len(cvs) == 1: cvs = cvs * len(self.ploty) if len(cvs) != len(self.ploty): raise ValueError("Couldn't broadcast colvars to plotys: {}, {}".format(len(cvs), len(ploty))) self.set_trait('colvars', cvs) self.layout = copy(self.def_box_layout) plotx = self.plotx ploty = self.ploty self._vlines = {} TOOLS="crosshair,pan,zoom_in,zoom_out,box_zoom,box_select,undo,reset," hover = HoverTool(tooltips=[ ("x", "@x (@plotx_label)"), ("y", "@y (@ploty_label)"), ("time", "@time ns"), ("run", "@run") ]) if plotx_label is None: plotx_label = "Collective variable {}".format(plotx+1) if plotx_label is None: ploty_label = "Collective variable {}".format(ploty+1) p = figure( title=self.title, x_axis_label=plotx_label, y_axis_label=ploty_label, tools=TOOLS) p.add_tools(hover) figure_layout = copy(self.def_figure_layout) bokeh = BokehWrapper(p, layout=figure_layout, showing=False) self.set_trait('bokeh', bokeh) sources, views = self._init_plots_views(mdtrajs, plotx_label, ploty_label) p.legend.click_policy = "hide" p.legend.location = legendlocation if len(cvs) == 1 or len(cvs) == len(mdtrajs): p.legend.visible = False self.set_trait('views', views) self.set_trait('sources', sources) button = widgets.Button( description='Next selected frame', disabled=False, button_style='', # 'success', 'info', 'warning', 'danger' or '' tooltip='Set NGLView frame to the next selected point', layout=copy(self.def_button_layout) ) button.on_click(self._on_button_clicked) self.children =tuple(self.views + [self.bokeh, button]) self.bokeh.show() def _on_button_clicked(self, b): for view in self.views: view.next_selected() def _init_plots_views(self, mdtraj_trajectories, plotx_label, ploty_label): colvars = self.colvars stride = self.stride plotx = self.plotx plotys = self.ploty p = self.figure n = len(colvars) if n >= 3: palette = colorblind['Colorblind'][n] else: palette = colorblind['Colorblind'][3] palette = palette[::-1] view_layout = widgets.Layout(**self.def_view_layout) if len(mdtraj_trajectories) == 1: view_layout.width='500px' view_layout.height='600px' sources = [] views = [] for n,(colvar, traj, ploty) in enumerate(zip_longest(colvars, mdtraj_trajectories, plotys)): if traj is not None: working_traj = traj times = working_traj.time[::stride] if len(colvar) != len(working_traj): raise ValueError("Colvar and trajectory should have same number of frames") if isinstance(colvar, np.ndarray): x = colvar[::stride, plotx] y = colvar[::stride, ploty] else: x = colvar[plotx][::stride] y = colvar[ploty][::stride] if isinstance(ploty, str): this_ploty_label = ploty elif ploty_label is not None: this_ploty_label = ploty_label else: this_ploty_label = str(ploty) ploty_label_list = [this_ploty_label] * len(y) source = ColumnDataSource(data={ 'run': [n]*len(x), 'plotx_label': [plotx_label]*len(x), 'ploty_label': ploty_label_list, 'time': times/1000, 'x': x, 'y': y, 'alphas': [(t)/(times[-1]) for t in times] }) sources.append(source) colour = palette[n-1] if traj is not None: view = show_mdtraj(traj[::stride], gui=False) view.observe(self._update_frame, names=['frame']), view._colour = colour if len(traj.top.select('protein')): view.clear_representations() view.add_cartoon(selection='polymer', color=colour) # view.frame_stride = stride view.layout = view_layout view._set_sync_camera() views.append(view) vline = Span( location=view.frame * traj.timestep * stride + traj.time[0], dimension='height', line_color=colour ) self._vlines[view] = vline p.add_layout(vline) view.link_to_bokeh_ds(source) p.scatter(x='x', y='y', source=source, color=colour, fill_alpha='alphas', legend=this_ploty_label) return sources, views @property def figure(self): return self.bokeh.figure @property def mdtraj_trajectories(self): return (view.original_trajectory for view in self.views) @property def traj(self): traj_list = list(self.mdtraj_trajectories) first_traj = trajlist.pop() for traj in traj_list: if traj is not first_traj: raise ValueError("FrameLinkedPlot has multiple trajectories") return first_traj @property def view(self): if len(self.views) == 1: return self.views[0] else: raise ValueError("FrameLinkedPlot has multiple views") @property def source(self): if len(self.views) == 1: return self.sources[0] else: raise ValueError("FrameLinkedPlot has multiple sources") def _update_frame(self, changes): # selections = [deepcopy(source.selected['1d']) for source in self.sources] view = changes['owner'] new_frame = changes['new'] traj = view.original_trajectory vline = self._vlines[view] vline.location = traj.timestep * new_frame + traj.time[0] # for sele, src in zip(selections, self.sources): # src.selected['1d'] = sele self.bokeh.refresh()
class Case(t.HasTraits): name = t.Unicode() gen = tt.DataFrame() bus = tt.DataFrame() load = tt.DataFrame() branch = tt.DataFrame() bus_name = t.List(t.Unicode()) gen_name = t.List(t.Unicode()) branch_name = t.List(t.Unicode()) unique_gen_names = t.Bool(default_value=True) _attributes = t.List(t.Unicode()) def __init__(self, filename=None, *args, **kwargs): super(Case, self).__init__(*args, **kwargs) self.gen = pd.DataFrame(columns=list(Generator().traits().keys())) self.gen = self.gen.set_index('name') self.bus = pd.DataFrame(columns=list(Bus().traits().keys())) self.bus = self.bus.set_index('name') self.branch = pd.DataFrame(columns=list(Branch().traits().keys())) self.branch = self.branch.set_index('name') if filename is None: self.load_default_case() elif filename.endswith('.m'): self._attributes = list() self.read_matpower(filename) else: raise NotImplementedError( "Unsupported filetype .{fileextension} in {filename}. Please contact the developer" .format(fileextension=filename.split('.')[-1], filename=filename)) def __repr__(self): name_string = "name='{name}'".format( name=self.name) if self.name != '' else '' gen_string = 'Generators={number}'.format(number=len(self.gen_name)) bus_string = 'Buses={number}'.format(number=len(self.bus_name)) branch_string = 'Branches={number}'.format( number=len(self.branch_name)) l = [ s for s in [name_string, gen_string, bus_string, branch_string] if s != '' ] repr_string = ', '.join(l) return '<{}.{}({})>'.format( self.__class__.__module__.replace('.case.case', '.case'), self.__class__.__name__, repr_string, ) def load_default_case(self): self.add_generator(name='GenCo0', maximum_real_power=100, generator_bus='Bus1') self.add_generator(name='GenCo1', maximum_real_power=200, generator_bus='Bus2') self.add_bus(name='Bus1', bus_type='SWING', real_power_demand=50, imag_power_demand=0) self.add_bus(name='Bus2', real_power_demand=250, imag_power_demand=0) self.add_branch(from_bus='Bus1', to_bus='Bus2') def add_generator(self, **kwargs): model = Generator(**kwargs) d = OrderedDict() for i in sorted(model.traits().keys()): d[i] = getattr(model, i) name = d.pop('name') self.gen.loc[name] = d self.fix_names() return model def add_bus(self, **kwargs): model = Bus(**kwargs) d = OrderedDict() for i in sorted(model.traits().keys()): d[i] = getattr(model, i) name = d.pop('name') self.bus.loc[name] = d self.fix_names() return model def add_branch(self, **kwargs): model = Branch(**kwargs) d = OrderedDict() for i in sorted(model.traits().keys()): d[i] = getattr(model, i) name = d.pop('name') self.branch.loc[name] = d self.fix_names() return model def fix_names(self): self.gen_name = list(self.gen.index) self.bus_name = list(self.bus.index) self.branch_name = list(self.branch.index) def read_matpower(self, filename, auto_assign_names=True, fill_loads=True, remove_empty=True, reset_generator_status=True): with open(os.path.abspath(filename)) as f: string = f.read() gen_list = list() for attribute in matpower.find_attributes(string): _list = matpower.parse_file(attribute, string) if attribute == 'gen': for row in _list: model = Generator(**dict(zip(row, row))) s = pd.Series(model._trait_values) gen_list.append(s) self.gen = pd.DataFrame(gen_list) @property def swing_bus(self): swing_bus = self.bus[self.bus['bus_type'] == 'SWING'].index[0] return swing_bus
class SunRayBlaster(OrthographicRayBlaster): # ground: Position of center of ray projection on the ground # zenith: Position directly above 'ground' at distance that sun # blaster should be placed. # north: Direction of north on ground from 'ground' latitude = traitlets.Float() longitude = traitlets.Float() date = traitlets.Instance(klass=datetime.datetime) ground = traittypes.Array().valid(check_dtype("f4"), check_shape(3)) zenith = traittypes.Array().valid(check_dtype("f4"), check_shape(3)) north = traittypes.Array().valid(check_dtype("f4"), check_shape(3)) solar_altitude = traitlets.CFloat() solar_azimuth = traitlets.CFloat() solar_distance = traitlets.CFloat() _solpos_info = traittypes.DataFrame() @traitlets.default("_solpos_info") def _solpos_info_default(self): return pvlib.solarposition.get_solarposition(self.date, self.latitude, self.longitude) @traitlets.default("solar_altitude") def _default_solar_altitude(self): solar_altitude = self._solpos_info["apparent_elevation"][0] if solar_altitude < 0: raise ValueError("For the provided lat, long, date, & time " "the sun will be below the horizon.") return solar_altitude @traitlets.default("solar_azimuth") def _default_solar_azimuth(self): return self._solpos_info["azimuth"][0] @property def zenith_direction(self): zd_nonorm = self.zenith - self.ground solar_distance = np.linalg.norm(zd_nonorm) print("sd zd", solar_distance, zd_nonorm) return zd_nonorm / solar_distance @traitlets.default("solar_distance") def _solar_distance_default(self): zd_nonorm = self.zenith - self.ground return np.linalg.norm(zd_nonorm) def solar_rotation(self, point): r"""Rotate a point according to same rotation that moves sun from the zenith to it location in the sky. Args: point (array): 3D point to rotate """ return sun_calc.rotate_u( sun_calc.rotate_u(point, np.radians(90 - self.solar_altitude), self.north), np.radians(90 - self.solar_azimuth), self.zenith_direction) @traitlets.default("forward") def _forward_default(self): # Negative to point from sun to the earth rather than from # eart to the sun return -self.solar_rotation(self.zenith_direction) @traitlets.default("center") def _center_default(self): v = self.ground - self.solar_distance * self.forward offset = max( 0.0, ((self.height / 2.0) - np.abs( np.linalg.norm(v - self.ground) * np.tan(np.radians(self.solar_altitude)))) / 2, ) print(offset) v = v + offset * self.up return v @traitlets.default("up") def _up_default(self): zenith_direction = self.zenith_direction east = np.cross(self.north, zenith_direction) # The "east" used here is not the "east" used elsewhere. # This is the east wrt north etc, but we need an east for blasting from elsewhere. return -self.solar_rotation(east)
class NetworkModel(t.HasTraits): """The NetworkModel object is created from a PSSTCase object, using the PSSTNetwork object. It contains state information neccesary to interactively visualize a network. Parameters ---------- case : PSSTCase An instance of a PSST case. sel_bus : str (Default=None) The name of a bus in the case to focus on. solver : str (Default='glpk') The name of the mixed integer solver you wish to use Attributes ---------- view_buses : :obj:`list` of :obj:`str` The names of the buses to be displayed. pos : pandas.DataFrame All the x,y positions of all the nodes. edges : pandas.DataFrame All the edges between nodes, and their x,y coordiantes. x_edges, y_edges : numpy.Array List of coordinates for 'start' and 'end' node, for all edges in network. bus_x_vals, bus_y_vals : numpy.Array Arrays containing coordinates of buses to be displayed. bus_x_edges, bus_y_edges : numpy.Array List of coordinates for 'start' and 'end' bus for each edge to be displayed. bus_names: :obj:`list` of :obj:`str` List of names of buses to be displayed. gen_x_vals, gen_y_vals : numpy.Array Arrays containing coordinates of generators to be displayed. gen_x_edges, gen_y_edges : numpy.Array List of coordinates for 'start' and 'end' generator for each edge to be displayed. gen_names: :obj:`list` of :obj:`str` List of names of generators to be displayed. load_x_vals, load_y_vals : numpy.Array Arrays containing coordinates of loads to be displayed. load_x_edges, load_y_edges : numpy.Array List of coordinates for 'start' and 'end' bus for each edge to be displayed. load_names: :obj:`list` of :obj:`str` List of names of loads to be displayed. """ case = t.Instance(PSSTCase, help='The original PSSTCase') network = t.Instance(PSSTNetwork) G = t.Instance(nx.Graph) model = t.Instance(PSSTModel, allow_none=True) sel_bus = t.Unicode(allow_none=True) view_buses = t.List(trait=t.Unicode) all_pos = tt.DataFrame(help='DF with all x,y positions of nodes.') all_edges = tt.DataFrame() pos = tt.DataFrame(help='DF with x,y positions only for display nodes') edges = tt.DataFrame() x_edges = tt.Array([]) y_edges = tt.Array([]) bus_x_vals = tt.Array([]) bus_y_vals = tt.Array([]) bus_names = t.List(trait=t.Unicode) bus_x_edges = tt.Array([]) bus_y_edges = tt.Array([]) gen_x_vals = tt.Array([]) gen_y_vals = tt.Array([]) gen_names = t.List(trait=t.Unicode) gen_x_edges = tt.Array([]) gen_y_edges = tt.Array([]) load_x_vals = tt.Array([]) load_y_vals = tt.Array([]) load_names = t.List(trait=t.Unicode) load_x_edges = tt.Array([]) load_y_edges = tt.Array([]) x_min_view = t.CFloat() x_max_view = t.CFloat() y_min_view = t.CFloat() y_max_view = t.CFloat() _VIEW_OFFSET = 50 def __init__(self, case, sel_bus=None, solver='glpk', *args, **kwargs): super(NetworkModel, self).__init__(*args, **kwargs) # Store PPSTCase, PSSTNetwork, and networkx.Graph self.case = case self.network = create_network(case=self.case) self.G = self.network.graph # Try to solve model self.model = build_model(self.case) self.model.solve(solver=solver) # Make full pos DF. self.all_pos = pd.DataFrame(self.network.positions, index=['x', 'y']).T # Make full edges DF, with coordinates and branch index self.all_edges = pd.DataFrame.from_records( [(i, j) for i, j in self.G.edges()], columns=['start', 'end']) # ---> Add coordinates self.all_edges['start_x'] = self.all_edges['start'].map( lambda e: self.all_pos.loc[e]['x']) self.all_edges['end_x'] = self.all_edges['end'].map( lambda e: self.all_pos.loc[e]['x']) self.all_edges['start_y'] = self.all_edges['start'].map( lambda e: self.all_pos.loc[e]['y']) self.all_edges['end_y'] = self.all_edges['end'].map( lambda e: self.all_pos.loc[e]['y']) # ---> Add branch index # new = case.branch[['F_BUS', 'T_BUS']] # new = new.reset_index() # new = new.rename_axis({'F_BUS': 'start', 'T_BUS': 'end', 'index': 'branch_idx'}, axis=1) # self.all_edges = pd.merge(self.all_edges, new, on=['start', 'end'], how='outer') # Make df with all edge data self.x_edges = [ tuple(edge) for edge in self.all_edges[['start_x', 'end_x']].values ] self.y_edges = [ tuple(edge) for edge in self.all_edges[['start_y', 'end_y']].values ] # Set 'start' and 'end' as index for all_edges df # Todo: Refactor so this happens later. self.all_edges.set_index(['start', 'end'], inplace=True) # Set 'sel_bus' (this should in turn set other variables) self.sel_bus = sel_bus