def _df_changed(self, old, new): ''' Handles how updates occur when df changes. Evaluates if columns or columnlabels have been changed. Provides entry condition as well. Note: New automatically sets self.df, so when I refer to new, I am actually referring to self.df. Using "new" instead of self.df is just for readability''' ### Initialize plot first time df is passed into the class. Boolean listeners ### for df behave oddly, so uses self.plotdata for entry condition. if not self.plotdata: self.plotdata = PandasPlotData(df=new) self._dffull = new ### Try to infer plot title from df name ### try: self.title = new.name #Turn into a "transfer" method where I pass list of attributes i want look for except AttributeError: pass ### Draw barebones of plot self._plot_default() self._update_lines() ### Decide to update columns or completely redraw df. else: changed = self.plotdata.set_df(new) ### If 'event changed', don't bother updaing lines if not changed: self._update_lines()
def _df_changed(self, old, new): ''' Handles how updates occur when df changes. Evaluates if columns or columnlabels have been changed. Provides entry condition as well. Note: New automatically sets self.df, so when I refer to new, I am actually referring to self.df. Using "new" instead of self.df is just for readability''' ### Initialize plot first time df is passed into the class. Boolean listeners ### for df behave oddly, so uses self.plotdata for entry condition. if not self.plotdata: self.plotdata=PandasPlotData(df=new) self._dffull=new ### Try to infer plot title from df name ### try: self.title=new.name #Turn into a "transfer" method where I pass list of attributes i want look for except AttributeError: pass ### Draw barebones of plot self._plot_default() self._update_lines() ### Decide to update columns or completely redraw df. else: changed=self.plotdata.set_df(new) ### If 'event changed', don't bother updaing lines if not changed: self._update_lines()
class PandasPlot(HasTraits): '''Plot to interface a pandas df''' ### For testing rnd_cols=Bool(False) samecols=Bool(False) transpose=Bool(False) ### Traits of the actual plot and plotdatasource handler ### _dffull=Instance(DataFrame) #Any? plot=Instance(Plot) plotdata=Instance(PandasPlotData) #Data stored at any given time in the plot df=Instance(DataFrame) ### Axis traits idxname=Str('Index') colname=Str('Column') idxorient=DefaultEnum('top', 'bottom', 'left', 'right', default='bottom') colorient=DefaultEnum('top', 'bottom', 'left', 'right', default='top') selection_axis=DefaultEnum('index','value', default='index') #Which axis does selection tool sample ### Aesthetic traits title=Str('Title') #Defaults from df name linecolor=Str('yellow') pointcolor=Str('red') linestyle=Enum('line', 'scatter', 'both') markersize=Range(low=1, high=5) sampling=Range(low=0.0, high=100., value=100.0) _spacing=Property(depends_on='sampling') ### _Event Handlers def _rnd_cols_changed(self): x=np.linspace(0, 100, 100) #Index generator y=np.linspace(0, 100, 100) #Column generator scale=randint(1,1000) self.df=DataFrame((np.random.rand(len(x),len(y))), columns=(scale/2.0)*y, index=scale*x) def _samecols_changed(self): self.df=DataFrame((np.random.rand(100,100))) def _transpose_changed(self): self.df=self.df.transpose() ### Axis Aesthetics @on_trait_change('idxname','idxcolumn', 'idxorient', 'colorient') def _axis_changed(self, trait, new): '''Change plot axis name or orientation''' setattr(self, trait, new) self._update_axis() self.plot.request_redraw() #Necessary but how do I only call axis redraw? def _title_changed(self, old, new): if old != new: self.plot.title=new self.plot.request_redraw() #HOW TO PREVENT COLLISION WITH TOP OVERLAY def _selection_axis_changed(self, old, new): if old != new: self._update_lines() def _df_changed(self, old, new): ''' Handles how updates occur when df changes. Evaluates if columns or columnlabels have been changed. Provides entry condition as well. Note: New automatically sets self.df, so when I refer to new, I am actually referring to self.df. Using "new" instead of self.df is just for readability''' ### Initialize plot first time df is passed into the class. Boolean listeners ### for df behave oddly, so uses self.plotdata for entry condition. if not self.plotdata: self.plotdata=PandasPlotData(df=new) self._dffull=new ### Try to infer plot title from df name ### try: self.title=new.name #Turn into a "transfer" method where I pass list of attributes i want look for except AttributeError: pass ### Draw barebones of plot self._plot_default() self._update_lines() ### Decide to update columns or completely redraw df. else: changed=self.plotdata.set_df(new) ### If 'event changed', don't bother updaing lines if not changed: self._update_lines() ### Plot spacing def _get__spacing(self): '''Integer spacing given % sampling''' samp=self.sampling/100.0 colsize=df.shape[0] return colsize - int(round( colsize*samp, 0)) def _sampling_changed(self, old, new): if old != new: self._update_samples() def _update_samples(self): '''Updates the list of line plots shown or hidden based on plot sampling.''' if self._spacing==0: return ### Hide all plots to_hide=self.plot.plots.keys() self.plot.hideplot(*to_hide) ### Show only plots in samples to_show=self.plot.plots.keys()[::self._spacing] self.plot.showplot(*to_show) self.plot.request_redraw() def _update_rangeselect(self): ''' Overwrites range selection tool in current plot.''' #### Remove current overlay self.plot.overlays=[obj for obj in self.plot.overlays if not isinstance(obj, RangeSelectionOverlay)] mycomp=self.plot.plots.itervalues().next()[0] #Quick wayt to get first value in dictionary inds=range(len(self.df.index)) idx=ArrayDataSource(inds) vals=ArrayDataSource(df.index.values) index_range = DataRange1D(idx) val_range=DataRange1D(vals) imap=LinearMapper(range=index_range)#,stretch_data=self.index_mapper.stretch_data) vmap=LinearMapper(range=val_range) # mycomp.index_range.refresh() mycomp.index_mapper=imap mycomp.value_mapper=vmap self.rangeselect=RangeSelection(mycomp, axis=self.selection_axis) self.plot.active_tool = self.rangeselect self.plot.overlays.append(RangeSelectionOverlay(component=mycomp)) self.rangeselect.on_trait_change(self.on_selection_changed, "selection") def _update_lines(self): ''' Redraws lines, plots and reapplies line selection.''' oldplots=self.plot.plots.keys() newplots=[name for name in self.plotdata.list_data(as_strings=True)] to_remove=[p for p in oldplots if p not in newplots] to_add=[p for p in newplots if p not in oldplots] if to_remove: for p in to_remove: self.plot.delplot(p) if to_add: for name in to_add: self.plot.plot(('index', name), name=name, color=self.linecolor) self._update_axis() self._update_samples() self._update_rangeselect() def on_selection_changed(self, selection): if selection != None: self.rangeXMin, self.rangeXMax = selection print selection def _update_axis(self): ''' Forces a label axis onto the plot. ''' print 'updaing axis', self.idxname indexlabels=[str(round(i,1)) for i in self.df.index] columnlabels=[str(round(i,1)) for i in self.df.columns] index_axis=LabelAxis(self.plot, orientation=self.idxorient, positions=range(int(float(indexlabels[0])), int(float(indexlabels[-1]))), labels=indexlabels,#, resizable='hv', title=self.idxname) col_axis=LabelAxis(self.plot, orientation=self.colorient, positions=range(int(float(columnlabels[0])), int(float(columnlabels[-1]))), labels=columnlabels,#, resizable='hv', title=self.colname) ### Remove underlays self.plot.underlays=[obj for obj in self.plot.underlays if not isinstance(obj, PlotAxis)] self.plot.underlays=[obj for obj in self.plot.underlays if not isinstance(obj, LabelAxis)] self.plot.underlays.append(index_axis) self.plot.underlays.append(col_axis) def _plot_default(self, toolbar=True, **pltkwds): ''' Draw bare plot, including main plotting area, toolbar, etc... either at initialization or global redo''' if toolbar: self.plot=ToolbarPlot(self.plotdata, **pltkwds) else: self.plot=Plot(self.plotdata, **pltkwds) self.plot.title = self.title self.plot.padding = 50 self.plot.legend.visible=False self.plot.tools.append(PanTool(self.plot)) zoom=BetterSelectingZoom(component=self.plot, tool_mode="box", always_on=False) self.plot.overlays.append(zoom) def _overwrite_plotdata(self): '''When a new instance of PandasPlotData is created, this overwrites the data source and updates the axis values.''' self.plotdata=PandasPlotData(df=self.df) self._plot_default() #CAN THIS JUST DRAW LINES ### Traits View main_group=Group( HGroup(Item('rnd_cols'), Item('samecols'), Item('transpose'),), Item('plot', editor=ComponentEditor(), show_label=False), Item('idxname'), Item('idxorient'), Item('selection_axis'), Item('title'), Item('sampling'), # Item('df_new'), Item('df_change'), #Include('sample_group'), #Include('axis_traits_group') ) traits_view=View( Include('main_group') , height=600, width=800)
def _overwrite_plotdata(self): '''When a new instance of PandasPlotData is created, this overwrites the data source and updates the axis values.''' self.plotdata=PandasPlotData(df=self.df) self._plot_default() #CAN THIS JUST DRAW LINES
class PandasPlot(HasTraits): '''Plot to interface a pandas df''' ### For testing rnd_cols = Bool(False) samecols = Bool(False) transpose = Bool(False) ### Traits of the actual plot and plotdatasource handler ### _dffull = Instance(DataFrame) #Any? plot = Instance(Plot) plotdata = Instance( PandasPlotData) #Data stored at any given time in the plot df = Instance(DataFrame) ### Axis traits idxname = Str('Index') colname = Str('Column') idxorient = DefaultEnum('top', 'bottom', 'left', 'right', default='bottom') colorient = DefaultEnum('top', 'bottom', 'left', 'right', default='top') selection_axis = DefaultEnum( 'index', 'value', default='index') #Which axis does selection tool sample ### Aesthetic traits title = Str('Title') #Defaults from df name linecolor = Str('yellow') pointcolor = Str('red') linestyle = Enum('line', 'scatter', 'both') markersize = Range(low=1, high=5) sampling = Range(low=0.0, high=100., value=100.0) _spacing = Property(depends_on='sampling') ### _Event Handlers def _rnd_cols_changed(self): x = np.linspace(0, 100, 100) #Index generator y = np.linspace(0, 100, 100) #Column generator scale = randint(1, 1000) self.df = DataFrame((np.random.rand(len(x), len(y))), columns=(scale / 2.0) * y, index=scale * x) def _samecols_changed(self): self.df = DataFrame((np.random.rand(100, 100))) def _transpose_changed(self): self.df = self.df.transpose() ### Axis Aesthetics @on_trait_change('idxname', 'idxcolumn', 'idxorient', 'colorient') def _axis_changed(self, trait, new): '''Change plot axis name or orientation''' setattr(self, trait, new) self._update_axis() self.plot.request_redraw( ) #Necessary but how do I only call axis redraw? def _title_changed(self, old, new): if old != new: self.plot.title = new self.plot.request_redraw( ) #HOW TO PREVENT COLLISION WITH TOP OVERLAY def _selection_axis_changed(self, old, new): if old != new: self._update_lines() def _df_changed(self, old, new): ''' Handles how updates occur when df changes. Evaluates if columns or columnlabels have been changed. Provides entry condition as well. Note: New automatically sets self.df, so when I refer to new, I am actually referring to self.df. Using "new" instead of self.df is just for readability''' ### Initialize plot first time df is passed into the class. Boolean listeners ### for df behave oddly, so uses self.plotdata for entry condition. if not self.plotdata: self.plotdata = PandasPlotData(df=new) self._dffull = new ### Try to infer plot title from df name ### try: self.title = new.name #Turn into a "transfer" method where I pass list of attributes i want look for except AttributeError: pass ### Draw barebones of plot self._plot_default() self._update_lines() ### Decide to update columns or completely redraw df. else: changed = self.plotdata.set_df(new) ### If 'event changed', don't bother updaing lines if not changed: self._update_lines() ### Plot spacing def _get__spacing(self): '''Integer spacing given % sampling''' samp = self.sampling / 100.0 colsize = df.shape[0] return colsize - int(round(colsize * samp, 0)) def _sampling_changed(self, old, new): if old != new: self._update_samples() def _update_samples(self): '''Updates the list of line plots shown or hidden based on plot sampling.''' if self._spacing == 0: return ### Hide all plots to_hide = self.plot.plots.keys() self.plot.hideplot(*to_hide) ### Show only plots in samples to_show = self.plot.plots.keys()[::self._spacing] self.plot.showplot(*to_show) self.plot.request_redraw() def _update_rangeselect(self): ''' Overwrites range selection tool in current plot.''' #### Remove current overlay self.plot.overlays = [ obj for obj in self.plot.overlays if not isinstance(obj, RangeSelectionOverlay) ] mycomp = self.plot.plots.itervalues().next()[ 0] #Quick wayt to get first value in dictionary inds = range(len(self.df.index)) idx = ArrayDataSource(inds) vals = ArrayDataSource(df.index.values) index_range = DataRange1D(idx) val_range = DataRange1D(vals) imap = LinearMapper( range=index_range) #,stretch_data=self.index_mapper.stretch_data) vmap = LinearMapper(range=val_range) # mycomp.index_range.refresh() mycomp.index_mapper = imap mycomp.value_mapper = vmap self.rangeselect = RangeSelection(mycomp, axis=self.selection_axis) self.plot.active_tool = self.rangeselect self.plot.overlays.append(RangeSelectionOverlay(component=mycomp)) self.rangeselect.on_trait_change(self.on_selection_changed, "selection") def _update_lines(self): ''' Redraws lines, plots and reapplies line selection.''' oldplots = self.plot.plots.keys() newplots = [name for name in self.plotdata.list_data(as_strings=True)] to_remove = [p for p in oldplots if p not in newplots] to_add = [p for p in newplots if p not in oldplots] if to_remove: for p in to_remove: self.plot.delplot(p) if to_add: for name in to_add: self.plot.plot(('index', name), name=name, color=self.linecolor) self._update_axis() self._update_samples() self._update_rangeselect() def on_selection_changed(self, selection): if selection != None: self.rangeXMin, self.rangeXMax = selection print selection def _update_axis(self): ''' Forces a label axis onto the plot. ''' print 'updaing axis', self.idxname indexlabels = [str(round(i, 1)) for i in self.df.index] columnlabels = [str(round(i, 1)) for i in self.df.columns] index_axis = LabelAxis( self.plot, orientation=self.idxorient, positions=range(int(float(indexlabels[0])), int(float(indexlabels[-1]))), labels=indexlabels, #, resizable='hv', title=self.idxname) col_axis = LabelAxis( self.plot, orientation=self.colorient, positions=range(int(float(columnlabels[0])), int(float(columnlabels[-1]))), labels=columnlabels, #, resizable='hv', title=self.colname) ### Remove underlays self.plot.underlays = [ obj for obj in self.plot.underlays if not isinstance(obj, PlotAxis) ] self.plot.underlays = [ obj for obj in self.plot.underlays if not isinstance(obj, LabelAxis) ] self.plot.underlays.append(index_axis) self.plot.underlays.append(col_axis) def _plot_default(self, toolbar=True, **pltkwds): ''' Draw bare plot, including main plotting area, toolbar, etc... either at initialization or global redo''' if toolbar: self.plot = ToolbarPlot(self.plotdata, **pltkwds) else: self.plot = Plot(self.plotdata, **pltkwds) self.plot.title = self.title self.plot.padding = 50 self.plot.legend.visible = False self.plot.tools.append(PanTool(self.plot)) zoom = BetterSelectingZoom(component=self.plot, tool_mode="box", always_on=False) self.plot.overlays.append(zoom) def _overwrite_plotdata(self): '''When a new instance of PandasPlotData is created, this overwrites the data source and updates the axis values.''' self.plotdata = PandasPlotData(df=self.df) self._plot_default() #CAN THIS JUST DRAW LINES ### Traits View main_group = Group( HGroup( Item('rnd_cols'), Item('samecols'), Item('transpose'), ), Item('plot', editor=ComponentEditor(), show_label=False), Item('idxname'), Item('idxorient'), Item('selection_axis'), Item('title'), Item('sampling'), # Item('df_new'), Item('df_change'), #Include('sample_group'), #Include('axis_traits_group') ) traits_view = View(Include('main_group'), height=600, width=800)
def _overwrite_plotdata(self): '''When a new instance of PandasPlotData is created, this overwrites the data source and updates the axis values.''' self.plotdata = PandasPlotData(df=self.df) self._plot_default() #CAN THIS JUST DRAW LINES