diff --git a/CAST.iss b/CAST.iss index 628bfa9..b4d14da 100644 --- a/CAST.iss +++ b/CAST.iss @@ -7,9 +7,9 @@ [Setup] AppName=CAST AppPublisher=GeoDa Center -AppPublisherURL=http://geoda.asu.edu/ -AppSupportURL=http://geoda.asu.edu/ -AppUpdatesURL=http://geoda.asu.edu/ +AppPublisherURL=http://spatial.uchicago.edu/ +AppSupportURL=http://spatial.uchicago.edu/ +AppUpdatesURL=http://spatial.uchicago.edu/ AppSupportPhone=(480)965-7533 AppVersion=0.99(alpha) DefaultDirName={pf}\GeoDa Software @@ -26,17 +26,17 @@ OutputDir=userdocs:Inno Setup Examples Output Name:"{app}\examples" [Files] -Source: "CAST.exe"; DestDir: "{app}" +Source: "dist\CAST.exe"; DestDir: "{app}" Source: "Microsoft.VC90.CRT.manifest"; DestDir: "{app}" Source: "msvcm90.dll"; DestDir: "{app}" Source: "msvcp90.dll"; DestDir: "{app}" Source: "msvcr90.dll"; DestDir: "{app}" -Source: "examples\tempe.shp"; DestDir: "{app}\examples" -Source: "examples\tempe.dbf"; DestDir: "{app}\examples" -Source: "examples\tempe.shx"; DestDir: "{app}\examples" -Source: "examples\beats.shp"; DestDir: "{app}\examples" -Source: "examples\beats.dbf"; DestDir: "{app}\examples" -Source: "examples\beats.shx"; DestDir: "{app}\examples" +;Source: "examples\tempe.shp"; DestDir: "{app}\examples" +;Source: "examples\tempe.dbf"; DestDir: "{app}\examples" +;Source: "examples\tempe.shx"; DestDir: "{app}\examples" +;Source: "examples\beats.shp"; DestDir: "{app}\examples" +;Source: "examples\beats.dbf"; DestDir: "{app}\examples" +;Source: "examples\beats.shx"; DestDir: "{app}\examples" ;Source: "Readme.txt"; DestDir: "{app}"; Flags: isreadme diff --git a/msvcm90.dll b/msvcm90.dll new file mode 100644 index 0000000..b9cb123 Binary files /dev/null and b/msvcm90.dll differ diff --git a/msvcp90.dll b/msvcp90.dll new file mode 100644 index 0000000..6b07c75 Binary files /dev/null and b/msvcp90.dll differ diff --git a/msvcr90.dll b/msvcr90.dll new file mode 100644 index 0000000..a68249a Binary files /dev/null and b/msvcr90.dll differ diff --git a/setup.py.win b/setup.py.win index 3e20200..526a624 100644 --- a/setup.py.win +++ b/setup.py.win @@ -24,7 +24,7 @@ class Target(object): def __init__(self, **kw): """ Default class constructor. Update as you need. """ self.__dict__.update(kw) - + # Ok, let's explain why I am doing that. # Often, data_files, excludes and dll_excludes (but also resources) @@ -35,7 +35,7 @@ sys.path.append("C:\\Program Files\\Microsoft Visual Studio 9.0\\VC\\redist\\x86 data_files = [] data_files = [("", glob.glob(r"C:\Program Files\Microsoft Visual Studio 9.0\VC\redist\x86\Microsoft.VC90.CRT\*.*"))] -includes = [] +includes = ['scipy', 'scipy.integrate', 'scipy.special.*','scipy.linalg.*'] excludes = ['_gtkagg', '_tkagg', 'bsddb', 'curses', 'email', 'pywin.debugger', 'pywin.debugger.dbgcon', 'pywin.dialogs', 'tcl', 'Tkconstants', 'Tkinter'] @@ -63,7 +63,7 @@ GUI2Exe_Target_1 = Target( icon_resources = icon_resources, bitmap_resources = bitmap_resources, other_resources = other_resources, - dest_base = "CAST", + dest_base = "CAST", version = "0.1", company_name = "GeoDa Cener", copyright = "GeoDa Center", @@ -75,14 +75,14 @@ GUI2Exe_Target_1 = Target( # That's serious now: we have all (or almost all) the options py2exe # supports. I put them all even if some of them are usually defaulted # and not used. Some of them I didn't even know about. - + setup( # No UPX or Inno Setup data_files = data_files, - options = {"py2exe": {"compressed": 2, + options = {"py2exe": {"compressed": 2, "optimize": 2, "includes": includes, "excludes": excludes, @@ -114,4 +114,3 @@ setup( # And we are done. That's a setup script :-D - diff --git a/stars.py b/stars.py index 067340f..3bf3e04 100755 --- a/stars.py +++ b/stars.py @@ -3,5 +3,8 @@ import stars import warnings +def dependencies_for_myprogram(): + from scipy.sparse.csgraph import _validation + warnings.filterwarnings("ignore") -stars.main() \ No newline at end of file +stars.main() diff --git a/stars/core/mt_densitymap_wrap.cpp b/stars/core/mt_densitymap_wrap.cpp index 838c03c..8dda249 100644 --- a/stars/core/mt_densitymap_wrap.cpp +++ b/stars/core/mt_densitymap_wrap.cpp @@ -125,6 +125,7 @@ template class SwigValueWrapper { #endif +#include /* Python.h has to appear first */ #include diff --git a/stars/visualization/dialogs/Weights.py b/stars/visualization/dialogs/Weights.py index b98c001..99c1ad9 100644 --- a/stars/visualization/dialogs/Weights.py +++ b/stars/visualization/dialogs/Weights.py @@ -381,7 +381,7 @@ def __init__(self, main, resource): self.dialog.Bind(wx.EVT_BUTTON, self.OnAddIDVariable, self.btn_add_id_var) def ShowMsgBox(self,msg,mtype='Warning',micon=wx.ICON_WARNING): - dlg = wx.MessageDialog(self, msg, mtype, wx.OK|micon) + dlg = wx.MessageDialog(None, msg, mtype, wx.OK|micon) dlg.ShowModal() dlg.Destroy() diff --git a/stars/visualization/maps/DensityMap.py b/stars/visualization/maps/DensityMap.py index f91ba67..b9ca04e 100644 --- a/stars/visualization/maps/DensityMap.py +++ b/stars/visualization/maps/DensityMap.py @@ -563,7 +563,7 @@ def OnPaneChanged(self,event): self.btn_cancel.SetPosition((x+190,y-offset)) def ShowMsgBox(self,msg,mtype='Warning',micon=wx.ICON_WARNING): - dlg = wx.MessageDialog(self, msg, mtype, wx.OK|micon) + dlg = wx.MessageDialog(None, msg, mtype, wx.OK|micon) dlg.ShowModal() dlg.Destroy() diff --git a/stars/visualization/maps/DynamicDensityMap.py b/stars/visualization/maps/DynamicDensityMap.py index aacd205..5d77303 100644 --- a/stars/visualization/maps/DynamicDensityMap.py +++ b/stars/visualization/maps/DynamicDensityMap.py @@ -13,7 +13,7 @@ from DensityMap import DensityMap, DensityMapQueryDialog from stars.visualization.DynamicWidget import DynamicMapWidget from stars.visualization.DynamicControl import DynamicMapControl -from stars.visualization.SpaceTimeQueryDialog import SpaceTimeQueryDialog +from stars.visualization.SpaceTimeQueryDialog import SpaceTimeQueryDialog from stars.visualization.utils import * class DynamicDensityMap(DensityMap): @@ -22,48 +22,50 @@ class DynamicDensityMap(DensityMap): """ def __init__(self, parent, layers, **kwargs): DensityMap.__init__(self,parent, layers, **kwargs) - + try: self.start_date = kwargs["start"] self.end_date = kwargs["end"] self.step, self.step_by = kwargs["step"] ,kwargs["step_by"] self.density_data_dict = kwargs["density_data_dict"] self.isAccumulative = kwargs["isAccumulative"] - + self.data_sel_keys = sorted(self.density_data_dict.keys()) self.data_sel_values = [self.density_data_dict[i] for i in self.data_sel_keys] self.n = len(self.data_sel_values) self.tick = 0 - + self.bufferWidth, self.bufferHeight = kwargs["size"] self.extent = self.point_layer.extent self.view = View2ScreenTransform( - self.extent, - self.bufferWidth, + self.extent, + self.bufferWidth, self.bufferHeight - self.bufferHeight/3.0 - ) - + ) + # strip map self.bStrip = True self.nav_left = None self.nav_right = None self.stripBuffer = None self.bAnimate = False - + # setup dynamic control buttons self.datetime_intervals, self.interval_labels = GetDateTimeIntervals(self.start_date, self.end_date,self.n, self.step, self.step_by) self.setupDynamicControls() - self.parentFrame.SetTitle('Dynamic Density Map-%s %s' % (self.point_layer.name,kwargs["title"])) - + + ttl = "" if "title" not in kwargs else kwargs["title"] + self.parentFrame.SetTitle('Dynamic Density Map-%s %s' % (self.point_layer.name,ttl)) + self.gradient_color_max = stars.MAP_GRADIENT_COLOR_MAX self.gradient_color_min = stars.MAP_GRADIENT_COLOR_MIN - + # preload density maps self.createDensityMaps() - - # display first map + + # display first map self.updateDraw(0) - + # Thread-based controller for dynamic LISA self.dynamic_control = DynamicMapControl( self.parentFrame, @@ -77,7 +79,7 @@ def __init__(self, parent, layers, **kwargs): if os.name == 'nt': self.Destroy() return None - + def setupDynamicControls(self): """ assign labels of dynamic controls @@ -87,14 +89,14 @@ def setupDynamicControls(self): self.slider = self.parentWidget.animate_slider if isinstance(self.start_date, datetime.date): self.parentWidget.label_start.SetLabel( - '%2d/%2d/%4d'% + '%2d/%2d/%4d'% (self.start_date.day, self.start_date.month, self.start_date.year ) ) self.parentWidget.label_end.SetLabel( - '%2d/%2d/%4d'% + '%2d/%2d/%4d'% (self.end_date.day, self.end_date.month, self.end_date.year @@ -106,7 +108,7 @@ def setupDynamicControls(self): self.parentWidget.label_current.SetLabel('current: %d (%d-%s period)'%(1,self.step, self.step_by)) except: raise Exception("Setup dynamic controls in toolbar failed!") - + def OnSize(self,event): """ overwrite OnSize in ShapeMap.py @@ -119,13 +121,13 @@ def OnSize(self,event): self.view.pixel_height = self.bufferHeight - self.bufferHeight/3.0 self.view.pixel_width = self.bufferWidth self.view.init() - - if self.bStrip: + + if self.bStrip: self.stripBuffer = None - + self.bAnimate = False self.reInitBuffer = True - + def OnMotion(self, event): """ """ @@ -136,34 +138,34 @@ def OnMotion(self, event): if self.nav_left[0] <= mouse_end_x <= self.nav_left[2] and \ self.nav_left[1] <= mouse_end_y <= self.nav_left[3]: return - # determine for right + # determine for right if self.nav_right: if self.nav_right[0] <= mouse_end_x <= self.nav_right[2] and \ self.nav_right[1] <= mouse_end_y <= self.nav_right[3]: return - + if event.Dragging() and event.LeftIsDown() and self.isMouseDrawing: - x, y = event.GetX(), event.GetY() + x, y = event.GetX(), event.GetY() # while mouse is down and moving if self.map_operation_type == stars.MAP_OP_PAN: # disable PAN (not support in this version) return - + # give the rest task to super class super(DynamicDensityMap,self).OnMotion(event) - + def updateDraw(self, tick): """ When SLIDER is dragged """ self.tick = tick self.reInitBuffer = True - + self.parentWidget.label_current.SetLabel( - 'current: %d (%d-%s period)' % + 'current: %d (%d-%s period)' % (tick+1,self.step, self.step_by)) - + def createDensityMap(self): """ Override to avoid regular densitymap function @@ -175,15 +177,15 @@ def createDensityMaps(self): c++ version: create density maps for all interval points data """ - x = [] + x = [] y = [] for pt in self.points: x.append(pt[0]) y.append(pt[1]) intervals = len(self.data_sel_values) - + from stars.core.DKDEWrapper import call_dkde - + progress_dlg = wx.ProgressDialog( "Progress", "Creating density maps... ", @@ -202,22 +204,22 @@ def createDensityMaps(self): self.extent, self.bandwidth, self.cell_size, - self.kernel, - self.color_band, + self.kernel, + self.color_band, self.opaque*2.55 ) - + progress_dlg.Update(2) - + self.grids = arrs self.gradient_color_max = gmax self.gradient_color_min = gmin - + self.density_bmps = [] for grid in self.grids: bmp = wx.BitmapFromBufferRGBA(cols, rows, grid) self.density_bmps.append(bmp) - + def setup_bitmap(self): """ bmp variables, in case of resize/pan/extent/zoom @@ -227,44 +229,44 @@ def setup_bitmap(self): self.bmp_right, self.bmp_lower = self.view.view_to_pixel(right, lower) self.bmp_width = self.bmp_right - self.bmp_left self.bmp_height = self.bmp_lower - self.bmp_upper - + def drawDensityMaps(self,dc): density_bmp = self.density_bmps[self.tick] - + if self.isResizing: self.setup_bitmap() - + # resize the one displaying image = wx.ImageFromBitmap(density_bmp) image = image.Scale(self.bmp_width, self.bmp_height, wx.IMAGE_QUALITY_HIGH) density_bmp = wx.BitmapFromImage(image) - - # draw density map + + # draw density map dc.DrawBitmap(density_bmp, self.bmp_left, self.bmp_upper) - - + + def DoDraw(self, dc): # draw background shape files once - # when Density map is ready, draw it - + # when Density map is ready, draw it + # change color schema for every tick local_query_pts = self.data_sel_values[self.tick] if len(local_query_pts) < len(self.points): id_group = [local_query_pts] color_group = [self.color_schema_dict[self.point_layer.name].colors[0]] edge_color_group = [self.color_schema_dict[self.point_layer.name].edge_color] - + """ non_query_points = list(set(range(len(self.points))) - set(local_query_pts)) id_group.append(non_query_points) color_group.append(wx.Colour(255,255,255,0)) edge_color_group.append(wx.Colour(255,255,255,0)) """ - + self.draw_layers[self.point_layer].set_data_group(id_group) self.draw_layers[self.point_layer].set_fill_color_group(color_group) self.draw_layers[self.point_layer].set_edge_color_group(edge_color_group) - + # draw layer in buffer for layer_name in self.layer_name_list[::-1]: if layer_name == "Density Map": @@ -274,64 +276,64 @@ def DoDraw(self, dc): layer = self.layer_dict[layer_name] if self.hide_layers[layer] == False: self.draw_layers[layer].draw(dc,self.view) - + if self.bStrip == True: if not self.bAnimate: self.stripBuffer = self.drawStrip() - start_offset = -self.stripBmpFrameWidth * self.tick + start_offset = -self.stripBmpFrameWidth * self.tick dc.DrawBitmap(self.stripBuffer,start_offset, self.bufferHeight/1.5) self.drawHighlightSubview(dc) - + def drawHighlightSubview(self, dc): # draw red highlight box dc.SetBrush(wx.TRANSPARENT_BRUSH) dc.SetPen(wx.RED_PEN) dc.DrawRectangle( - self.middleBmpPos[0], - self.middleBmpPos[1], + self.middleBmpPos[0], + self.middleBmpPos[1], int(math.ceil(self.stripBmpWidth)), self.stripBmpHeight - ) - + ) + def enableKDEStrip(self,event): self.bStrip = not self.bStrip if self.bStrip == False: self.view = View2ScreenTransform( - self.extent, - self.bufferWidth, + self.extent, + self.bufferWidth, self.bufferHeight ) else: self.view = View2ScreenTransform( - self.extent, - self.bufferWidth, + self.extent, + self.bufferWidth, self.bufferHeight - self.bufferHeight/3.0 ) self.reInitBuffer = True - + def drawSubView(self, index, bufferWidth, bufferHeight, bmp): dc = wx.BufferedDC(None, bmp) dc.SetBrush(wx.WHITE_BRUSH) dc.SetPen(wx.TRANSPARENT_PEN) dc.DrawRectangle(0,0,bufferWidth,bufferHeight) image = wx.ImageFromBitmap(self.density_bmps[index]) - + bmpWidth = self.stripBmpWidth* 0.8 bmpHeight = self.stripBmpHeight* 0.8 bmpRatio = self.bmp_width / self.bmp_height - + if self.bmp_width > self.bmp_height: bmpHeight = bmpWidth / bmpRatio else: bmpWidth = bmpHeight * bmpRatio - - bmpOffsetX = (self.stripBmpWidth- bmpWidth )/2.0 - bmpOffsetY = (self.stripBmpHeight- bmpHeight)/2.0 + + bmpOffsetX = (self.stripBmpWidth- bmpWidth )/2.0 + bmpOffsetY = (self.stripBmpHeight- bmpHeight)/2.0 image = image.Scale(bmpWidth, bmpHeight, wx.IMAGE_QUALITY_NORMAL) bmp = wx.BitmapFromImage(image) - dc.DrawBitmap(bmp,bmpOffsetX,bmpOffsetY) + dc.DrawBitmap(bmp,bmpOffsetX,bmpOffsetY) #dc.Destroy() - + def drawStrip(self): n_stripBmps = len(self.data_sel_keys) stripFramePos = 0, self.bufferHeight * 2.0/3.0 @@ -340,13 +342,13 @@ def drawStrip(self): stripBmpWidth = stripBmpHeight * 0.8 stripBmpGap = stripFrameHeight * 0.1 stripBmpFrameWidth = stripBmpWidth + 2*stripBmpGap - + stripFrameMarginLR = (self.bufferWidth - stripBmpWidth)/ 2.0 - stripBmpGap stripFrameWidth = stripBmpFrameWidth * n_stripBmps + stripFrameMarginLR * 2 - + if stripFrameWidth < self.bufferWidth: stripFrameWidth = self.bufferWidth - + self.nav_left = stripFramePos[0], stripFramePos[1], \ stripFramePos[0] + self.bufferWidth/ 2.0, \ stripFramePos[1] + stripFrameHeight @@ -360,21 +362,21 @@ def drawStrip(self): self.stripFrameHeight = stripFrameHeight self.stripFramePos = stripFramePos self.stripFrameMarginLR = stripFrameMarginLR - self.middleBmpPos = stripFrameMarginLR + stripBmpGap, stripFramePos[1] + stripBmpGap - + self.middleBmpPos = stripFrameMarginLR + stripBmpGap, stripFramePos[1] + stripBmpGap + stripBuffer = wx.EmptyBitmap(stripFrameWidth, stripFrameHeight) tmp_dc = wx.BufferedDC(None, stripBuffer) - + # draw light gray background first pen = wx.Pen(stars.STRIP_VIEW_BG_COLOR) tmp_dc.SetPen(pen) brush = wx.Brush(stars.STRIP_VIEW_BG_COLOR) tmp_dc.SetBrush(brush) tmp_dc.DrawRectangle(0,0,stripFrameWidth,stripFrameHeight) - + font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT) tmp_dc.SetFont(font) - + # draw each bmp at strip area tmp_dc.SetBrush(wx.Brush(stars.STRIP_VIEW_MAP_BG_COLOR)) for i in range(n_stripBmps): @@ -391,7 +393,7 @@ def drawStrip(self): tmp_dc.SetPen(wx.TRANSPARENT_PEN) tmp_dc.DrawRectangle(start_pos[0], start_pos[1], stripBmpWidth, stripBmpHeight) tmp_dc.DrawBitmap(bmp, start_pos[0], start_pos[1]) - + # draw label for each map in subview start_date, end_date = self.datetime_intervals[i] if isinstance(start_date, datetime.date): @@ -399,21 +401,21 @@ def drawStrip(self): (start_date.month, start_date.day, start_date.year, - end_date.month, - end_date.day, + end_date.month, + end_date.day, end_date.year) else: info_tip = "t%d" % (start_date) txt_w,txt_h = tmp_dc.GetTextExtent(info_tip) tmp_dc.DrawText( - info_tip, - start_pos[0]+(stripBmpWidth-txt_w)/2, + info_tip, + start_pos[0]+(stripBmpWidth-txt_w)/2, start_pos[1]+stripBmpHeight+2 ) #tmp_dc.Destroy() - - return stripBuffer - + + return stripBuffer + def OnMotion(self, event): if self.bStrip: mouse_end_x, mouse_end_y = (event.GetX(), event.GetY()) @@ -422,14 +424,14 @@ def OnMotion(self, event): if self.nav_left[0] <= mouse_end_x <= self.nav_left[2] and \ self.nav_left[1] <= mouse_end_y <= self.nav_left[3]: return - # determine for right + # determine for right if self.nav_right: if self.nav_right[0] <= mouse_end_x <= self.nav_right[2] and \ self.nav_right[1] <= mouse_end_y <= self.nav_right[3]: return # give the rest task to super class super(DynamicDensityMap,self).OnMotion(event) - + def OnLeftDown(self, event): """ override for click on strip view """ if self.bStrip: @@ -440,7 +442,7 @@ def OnLeftDown(self, event): self.nav_left[1] <= mouse_end_y <= self.nav_left[3]: self.stopAnimation = True return - # determine for right + # determine for right if self.nav_right: if self.nav_right[0] <= mouse_end_x <= self.nav_right[2] and \ self.nav_right[1] <= mouse_end_y <= self.nav_right[3]: @@ -448,7 +450,7 @@ def OnLeftDown(self, event): return # give the rest task to super class super(DynamicDensityMap,self).OnLeftDown(event) - + def OnLeftUp(self, event): """ override for click on strip view """ if self.bStrip: @@ -460,18 +462,18 @@ def OnLeftUp(self, event): if self.nav_left[0] <= mouse_end_x <= self.nav_left[2] and \ self.nav_left[1] <= mouse_end_y <= self.nav_left[3]: self.stopAnimation = False - start_offset = -self.stripBmpFrameWidth * self.tick + start_offset = -self.stripBmpFrameWidth * self.tick if self.tick < self.n-1: self.tick = self.tick + 1 self.animateStripView(acc, start_offset) else: self.animateStripView(acc, start_offset,isEnd=True) - # determine for right + # determine for right if self.nav_right: if self.nav_right[0] <= mouse_end_x <= self.nav_right[2] and \ self.nav_right[1] <= mouse_end_y <= self.nav_right[3]: self.stopAnimation = False - start_offset = -self.stripBmpFrameWidth * self.tick + start_offset = -self.stripBmpFrameWidth * self.tick if self.tick>0: self.tick = self.tick -1 self.animateStripView(acc, start_offset, isLeft=False) @@ -479,7 +481,7 @@ def OnLeftUp(self, event): self.animateStripView(acc, start_offset, isLeft=False, isEnd=True) # give the rest task to super class super(DynamicDensityMap,self).OnLeftUp(event) - + def animateStripView(self, acc, start_offset, isLeft=True, t=1,isEnd=False): """ """ @@ -491,10 +493,10 @@ def animateStripView(self, acc, start_offset, isLeft=True, t=1,isEnd=False): offset = acc*20*t - acc * (t**2) / 2.0 else: offset = acc*10*t - acc * (t**2) / 2.0 - + if isLeft: offset = -offset offset = start_offset + offset - + tmp_buffer = wx.EmptyBitmap(self.bufferWidth, self.bufferHeight) tmp_dc = wx.BufferedDC(None, tmp_buffer) tmp_dc.DrawBitmap(self.drawing_backup_buffer,0,0) @@ -515,16 +517,16 @@ def animateStripView(self, acc, start_offset, isLeft=True, t=1,isEnd=False): # self.stripFrameWidth, self.stripFrameHeight)) t = t + 1 if self.stopAnimation == False: - wx.FutureCall(10, self.animateStripView, acc, start_offset, isLeft,t,isEnd) - - + wx.FutureCall(10, self.animateStripView, acc, start_offset, isLeft,t,isEnd) + + def ExportMovie(self,path,duration=3): from stars.visualization.utils.images2gif import writeGif,writeBmps2Gif - + Y,M,D = self.start_date.year, self.start_date.month, self.start_date.day # python.DateTime start_date = wx.DateTime.Today() start_date.Year,start_date.Month, start_date.Day = Y,M,D - + tick = self.tick movie_bmps = [] for i in range(self.n): @@ -535,19 +537,19 @@ def ExportMovie(self,path,duration=3): self.isResizing = True self.DoDraw(dc) self.isResizing = False - + # draw lables if i < self.n -1: end_date = wx.DateTime.Today() end_date.Set(start_date.Day, start_date.Month, start_date.Year) - + if self.step_by == 'Day': end_date += wx.DateSpan(days=self.step) elif self.step_by == 'Month': end_date += wx.DateSpan(months=self.step) elif self.step_by == 'Year': end_date += wx.DateSpan(years=self.step) - + label = '(%d/%d) %s/%s/%s - %s/%s/%s (%s %s period)' % \ (i+1,self.n, start_date.Month,start_date.Day,start_date.Year, end_date.Month, end_date.Day, end_date.Year,self.step, self.step_by @@ -559,7 +561,7 @@ def ExportMovie(self,path,duration=3): (i+1,self.n, start_date.Month,start_date.Day,start_date.Year, self.end_date.month, self.end_date.day, self.end_date.year,self.step, self.step_by ) - + dc.DrawText(label, 5,5) #dc.Destroy() movie_bmps.append(tmp_bmp) @@ -568,7 +570,7 @@ def ExportMovie(self,path,duration=3): self.ShowMsgBox("Movie file (GIF) created successfully.", mtype='CAST information', micon=wx.ICON_INFORMATION) - + def UpdateGradient(self,gradient_type): self.color_band = gradient_type self.gradient_color = GradientColor(gradient_type) @@ -577,65 +579,65 @@ def UpdateGradient(self,gradient_type): self.createDensityMaps() self.isResizing = True self.reInitBuffer = True - + return self.color_schema_dict["Density Map"] - + def UpdateOpaque(self, opaque): self.opaque = opaque*2.55 self.createDensityMaps() self.isResizing = True self.reInitBuffer = True - + def OnRightUp(self,event): menu = wx.Menu() menu.Append(201, "Show/Hide KDE strip", "") - + menu.UpdateUI() menu.Bind(wx.EVT_MENU, self.enableKDEStrip, id=201) self.PopupMenu(menu) - + event.Skip() - + class DynamicDensityMapQueryDialog(DensityMapQueryDialog): def __init__(self, parent, title, points_data, isShowSpace=False, **kwargs): DensityMapQueryDialog.__init__(self,parent,title, points_data, isShowSpace, **kwargs) - + def Add_Customized_Controls(self): self.isAddAccumOption = True super(DynamicDensityMapQueryDialog,self).Add_Customized_Controls() - + def OnDateFieldSelected(self, event): # step_by is not needed in Time Density Map super(DynamicDensityMapQueryDialog, self).OnDateFieldSelected(event) - + self.textbox_step.Enable(True) self.cmbox_step.Enable(True) - - + + def OnQuery(self,event): if self._check_time_itv_input() == False or\ self._check_KDE_input() == False: return - + self.current_selected = range(self.dbf.n_records) self._filter_by_query_field() self.query_date = None # query_date is not available in Trend Graph case self._filter_by_date_interval() self._filter_by_tod() - + self.isAccumulative = self.accu_kde.GetValue() density_data_dict = self.gen_date_by_step() - + background_layer = None if self.isShowSpace: background_layer = None if self.cmbox_location.CurrentSelection<0 else\ self.background_shps[self.cmbox_location.CurrentSelection] - + title = "" if self.query_field.lower() != "all fields": title = "(%s:%s)"%(self.query_field,self.query_range) - + densityMap_widget= DynamicMapWidget( self.parent, [self.points_data], @@ -654,20 +656,20 @@ def OnQuery(self,event): isAccumulative=self.isAccumulative, size =(800,650), title=title - ) + ) densityMap_widget.Show() - + self.btn_save.Enable(True) - + def OnSaveQueryToDBF(self, event): try: import pysal if self.query_data == None: return dlg = wx.FileDialog( - self, message="Save query into a dbf file...", defaultDir=os.getcwd(), - defaultFile='%s.dbf' % (self.points_data.name + '_dynamicKDE'), - wildcard="dbf file (*.dbf)|*.dbf|All files (*.*)|*.*", + self, message="Save query into a dbf file...", defaultDir=os.getcwd(), + defaultFile='%s.dbf' % (self.points_data.name + '_dynamicKDE'), + wildcard="dbf file (*.dbf)|*.dbf|All files (*.*)|*.*", style=wx.SAVE) if dlg.ShowModal() != wx.ID_OK: dlg.Destroy() @@ -675,19 +677,19 @@ def OnSaveQueryToDBF(self, event): path = dlg.GetPath() dlg.Destroy() dbf = self.points_data.dbf - + field_name = "" for item in dbf.header: if item.startswith('TIME_PERIOD'): field_name = item +"_1" if field_name == "": field_name = "TIME_PERIOD" - + try: os.remove(path) except: pass - + newDBF= pysal.open(path,'w') newDBF.header = [] newDBF.field_spec = [] @@ -695,49 +697,49 @@ def OnSaveQueryToDBF(self, event): newDBF.header.append(i) for i in dbf.field_spec: newDBF.field_spec.append(i) - + newDBF.header.append(field_name) newDBF.field_spec.append(('N',4,0)) - + rows = [] for i in range(dbf.n_records): rows.append(dbf.read_record(i)) - + for key in self.query_data.keys(): vals = self.query_data[key] for i in vals: rows[i].append(key) - - for row in rows: + + for row in rows: newDBF.write(row) newDBF.close() - + self.ShowMsgBox("Query results have been saved to column 'TIME_PERIOD' in dbf file", mtype='CAST information', micon=wx.ICON_INFORMATION) except Exception as err: self.ShowMsgBox("""Saving query results to new dbf file failed. - + Details: """+str(err.message)) - + def gen_date_by_step(self): """ generate dynamic density map data by STEP """ from stars.visualization.utils import GetIntervalStep - + step = self.step step_by = self.step_by - #background_shp_idx = self.background_shp_idx - + #background_shp_idx = self.background_shp_idx + #background_shp = self.background_shps[background_shp_idx] start_date = self.start_query_date # already python datetime - end_date = self.end_query_date + end_date = self.end_query_date total_steps = GetIntervalStep(end_date, start_date, step, step_by) - + # displaying progress - n = len(self.current_selected) - + n = len(self.current_selected) + if total_steps <= 0: self.ShowMsgBox("Start and end dates are not correct.") return None @@ -753,11 +755,11 @@ def gen_date_by_step(self): self.Destroy() return None self.Destroy() - + if n == 0: self.ShowMsgBox("There is no points in query result. Please change query parameters and retry.") return None - + itv = n/5 progress_dlg = wx.ProgressDialog( "Progress", @@ -767,21 +769,21 @@ def gen_date_by_step(self): style = wx.PD_APP_MODAL|wx.PD_AUTO_HIDE ) progress_dlg.CenterOnScreen() - + density_data_dict = {} # startdatetime:points density_data_dict = dict([(s,[]) for s in range(total_steps)]) - + for count,j in enumerate(self.current_selected): if count % itv == 0: progress_dlg.Update(count +1) - - _date = self.all_dates[j] + + _date = self.all_dates[j] interval_idx = GetIntervalStep(_date, start_date, step, step_by) -1 density_data_dict[interval_idx].append(j) - + progress_dlg.Update(n) - progress_dlg.Destroy() - + progress_dlg.Destroy() + self.query_data = density_data_dict - - return density_data_dict \ No newline at end of file + + return density_data_dict diff --git a/stars/visualization/maps/DynamicLisaMap.py b/stars/visualization/maps/DynamicLisaMap.py index ff9c5e2..04e6134 100644 --- a/stars/visualization/maps/DynamicLisaMap.py +++ b/stars/visualization/maps/DynamicLisaMap.py @@ -20,28 +20,28 @@ class DynamicLISAMap(ShapeMap): """ - Dynamic/Animated LISA Maps. - + Dynamic/Animated LISA Maps. + Parameters ---------- - + layers : array (n,1) - n SHAPE layers, the first one should be the used for generating LISA - + n SHAPE layers, the first one should be the used for generating LISA + cs_data_dict : dict (time_range:data) crosssectional data dictionary - + weight_file : string weight file path - + """ def __init__(self, parent, layers, **kwargs): ShapeMap.__init__(self,parent, layers) - + try: self.parent = parent self.layer = layers[0] - + self.cs_data_dict = kwargs["data"] self.weight_file = kwargs["weight"] start_date,end_date = kwargs["start"],kwargs["end"] @@ -52,47 +52,48 @@ def __init__(self, parent, layers, **kwargs): self.data_sel_keys = sorted(self.cs_data_dict.keys()) self.data_sel_values = [self.cs_data_dict[i] for i in self.data_sel_keys] self.weight = pysal.open(self.weight_file).read() - + self.bufferWidth, self.bufferHeight = kwargs["size"] self.extent = self.layer.extent self.view = View2ScreenTransform( - self.extent, - self.bufferWidth, + self.extent, + self.bufferWidth, self.bufferHeight - self.bufferHeight/3.0 - ) - + ) + # strip map self.tick = 0 self.bStrip = True self.nav_left = None self.nav_right = None - + self.bAnimate = False - + # setup dynamic control buttons - self.SetTitle('Dynamic LISA - %s %s'% (self.layer.name,kwargs["title"])) + ttl = "" if "title" not in kwargs else kwargs["title"] + self.SetTitle('Dynamic LISA - %s %s'% (self.layer.name, ttl)) self.datetime_intervals, self.interval_labels = GetDateTimeIntervals(self.start_date, self.end_date,self.t, self.step, self.step_by) self.setupDynamicControls() - + # preprocess multi LISA maps self.processLISAMaps() - + # inital drawing lisa map self.updateDraw(0) - + # Thread-based controller for dynamic LISA - self.dynamic_control = DynamicMapControl(self.parentFrame,self.t,self.updateDraw) - + self.dynamic_control = DynamicMapControl(self.parentFrame,self.t,self.updateDraw) + except Exception as err: self.ShowMsgBox("""Dynamic LISA map could not be created. Please choose or create a valid spatial weights file. - + Details: """ + str(err.message)) self.UnRegister() self.parentFrame.Close(True) if os.name == 'nt': self.Destroy() return None - + def setupDynamicControls(self): """ assign labels of dynamic controls @@ -109,7 +110,7 @@ def setupDynamicControls(self): self.parentWidget.label_current.SetLabel('current: %d (%d-%s period)' % (1,self.step, self.step_by)) except: raise Exception("Setup dynamic controls in toolbar failed!") - + def processLISAMaps(self): """ Create LISA maps for each interval data @@ -125,7 +126,8 @@ def processLISAMaps(self): style = wx.PD_APP_MODAL|wx.PD_AUTO_HIDE ) progress_dlg.CenterOnScreen() - + + from stars.core.LISAWrapper import call_lisa self.moran_locals = [] for i, data in enumerate(self.data_sel_values): @@ -138,14 +140,14 @@ def processLISAMaps(self): ml = [localMoran, sigLocalMoran, sigFlag, clusterFlag] self.moran_locals.append(ml) progress_dlg.Destroy() - + # default color schema for LISA color_group =[ - stars.LISA_NOT_SIG_COLOR, + stars.LISA_NOT_SIG_COLOR, stars.LISA_HH_COLOR, - stars.LISA_LL_COLOR, + stars.LISA_LL_COLOR, stars.LISA_LH_COLOR, - stars.LISA_HL_COLOR, + stars.LISA_HL_COLOR, stars.LISA_OBSOLETE_COLOR] self.lisa_color_group = color_group label_group = ["Not Significant","High-High","Low-Low","Low-High","High-Low","Neighborless"] @@ -153,7 +155,7 @@ def processLISAMaps(self): except: raise Exception("Compute LISA error. Please check weight file.") - + def OnSize(self,event): """ overwrite OnSize in ShapeMap.py @@ -166,96 +168,96 @@ def OnSize(self,event): self.view.pixel_height = self.bufferHeight - self.bufferHeight/3.0 self.view.pixel_width = self.bufferWidth self.view.init() - if self.bStrip: + if self.bStrip: self.stripBuffer = None - + self.bAnimate = False self.reInitBuffer = True - + def remove_layer(self,layer, isRemoveContent=True): # support Toolbar REMOVE_LAYER button #if self.fixed_layer: - + if layer.name == self.layer.name: self.ShowMsgBox("Can't remove original LISA layer.") return False - + super(DynamicLISAMap, self).remove_layer(layer, isRemoveContent) - - + + def Update(self, tick): """ When SLIDER is dragged """ - self.updateDraw(tick) - + self.updateDraw(tick) + def updateDraw(self, tick): """ When SLIDER is dragged """ self.tick = tick ml = self.moran_locals[tick] - + # 0 not significant, 1 HH, 2 LL, 3 LH, 4 HL, 5 Neighborless sigFlag = ml[2] clusterFlag = ml[3] lm_sig = np.array(sigFlag) lm_q = np.array(clusterFlag) - + id_groups = [[] for i in range(6)] for i,sig in enumerate(lm_sig): if sig > 0: id_groups[lm_q[i]].append(i) else: id_groups[0].append(i) - + self.draw_layers[self.layer].set_data_group(id_groups) self.draw_layers[self.layer].set_fill_color_group(self.lisa_color_group) - + edge_clr = self.color_schema_dict[self.layer.name].edge_color self.draw_layers[self.layer].set_edge_color(edge_clr) - - # trigger to draw + + # trigger to draw self.reInitBuffer = True self.parentWidget.label_current.SetLabel('current: %d (%d-%s period)' % (tick+1,self.step, self.step_by)) - + def DoDraw(self, dc): super(DynamicLISAMap, self).DoDraw(dc) - + if self.bStrip: if not self.bAnimate: #self.drawStripView(dc) self.stripBuffer = self.drawStrip() - start_offset = -self.stripBmpFrameWidth * self.tick + start_offset = -self.stripBmpFrameWidth * self.tick dc.DrawBitmap(self.stripBuffer,start_offset, self.bufferHeight/1.5) self.drawHighlightSubview(dc) - + def drawHighlightSubview(self, dc): # draw red highlight box dc.SetBrush(wx.TRANSPARENT_BRUSH) dc.SetPen(wx.RED_PEN) dc.DrawRectangle( - self.middleBmpPos[0], - self.middleBmpPos[1], - int(math.ceil(self.stripBmpWidth)), - self.stripBmpHeight) - + self.middleBmpPos[0], + self.middleBmpPos[1], + int(math.ceil(self.stripBmpWidth)), + self.stripBmpHeight) + def drawStrip(self): n_stripBmps = len(self.data_sel_keys) stripFramePos = 0, self.bufferHeight * 2.0/3.0 stripFrameHeight = self.bufferHeight / 3.0 stripBmpHeight = stripFrameHeight * 0.8 - + stripBmpWidth = stripBmpHeight * 0.8 stripBmpGap = stripFrameHeight * 0.1 stripBmpFrameWidth = stripBmpWidth + 2*stripBmpGap - + stripFrameMarginLR = (self.bufferWidth - stripBmpWidth)/ 2.0 - stripBmpGap stripFrameWidth = stripBmpFrameWidth * n_stripBmps + stripFrameMarginLR * 2 - + if stripFrameWidth < self.bufferWidth: stripFrameWidth = self.bufferWidth - + self.nav_left = stripFramePos[0], stripFramePos[1], \ stripFramePos[0] + self.bufferWidth/ 2.0, \ stripFramePos[1] + stripFrameHeight @@ -269,21 +271,21 @@ def drawStrip(self): self.stripFrameHeight = stripFrameHeight self.stripFramePos = stripFramePos self.stripFrameMarginLR = stripFrameMarginLR - self.middleBmpPos = stripFrameMarginLR + stripBmpGap, stripFramePos[1] + stripBmpGap - + self.middleBmpPos = stripFrameMarginLR + stripBmpGap, stripFramePos[1] + stripBmpGap + stripBuffer = wx.EmptyBitmap(stripFrameWidth, stripFrameHeight) tmp_dc = wx.BufferedDC(None, stripBuffer) - + # draw light gray background first pen = wx.Pen(stars.STRIP_VIEW_BG_COLOR) tmp_dc.SetPen(pen) brush = wx.Brush(stars.STRIP_VIEW_BG_COLOR) tmp_dc.SetBrush(brush) tmp_dc.DrawRectangle(0,0,stripFrameWidth,stripFrameHeight) - + font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT) tmp_dc.SetFont(font) - + # draw each bmp at strip area tmp_dc.SetBrush(wx.Brush(stars.STRIP_VIEW_MAP_BG_COLOR)) for i in range(n_stripBmps): @@ -300,7 +302,7 @@ def drawStrip(self): tmp_dc.SetPen(wx.TRANSPARENT_PEN) tmp_dc.DrawRectangle(start_pos[0], start_pos[1], stripBmpWidth, stripBmpHeight) tmp_dc.DrawBitmap(bmp, start_pos[0], start_pos[1]) - + # draw label for each map in subview start_date, end_date = self.datetime_intervals[i] if isinstance(start_date, datetime.date): @@ -308,20 +310,20 @@ def drawStrip(self): (start_date.month, start_date.day, start_date.year, - end_date.month, - end_date.day, + end_date.month, + end_date.day, end_date.year) else: info_tip = "t%d" % (start_date) txt_w,txt_h = tmp_dc.GetTextExtent(info_tip) tmp_dc.DrawText( - info_tip, - start_pos[0]+(stripBmpWidth-txt_w)/2, + info_tip, + start_pos[0]+(stripBmpWidth-txt_w)/2, start_pos[1]+stripBmpHeight+2) #tmp_dc.Destroy() - + return stripBuffer - + def OnMotion(self, event): """ """ @@ -332,28 +334,28 @@ def OnMotion(self, event): if self.nav_left[0] <= mouse_end_x <= self.nav_left[2] and \ self.nav_left[1] <= mouse_end_y <= self.nav_left[3]: return - # determine for right + # determine for right if self.nav_right: if self.nav_right[0] <= mouse_end_x <= self.nav_right[2] and \ self.nav_right[1] <= mouse_end_y <= self.nav_right[3]: return - - + + if event.Dragging() and event.LeftIsDown() and self.isMouseDrawing: - x, y = event.GetX(), event.GetY() + x, y = event.GetX(), event.GetY() # while mouse is down and moving if self.map_operation_type == stars.MAP_OP_PAN: # disable PAN (not support in this version) return """ - # prepare DC for brushing drawing + # prepare DC for brushing drawing tmp_buffer = wx.EmptyBitmap(self.bufferWidth, self.bufferHeight) tmp_dc = wx.BufferedDC(None, tmp_buffer) - delta_px = -x0 + x + delta_px = -x0 + x delta_py = -y0 + y tmp_dc.DrawBitmap(self.drawing_backup_buffer,delta_px,delta_py) if self.bStrip : - start_offset = -self.stripBmpFrameWidth * self.tick + start_offset = -self.stripBmpFrameWidth * self.tick tmp_dc.DrawBitmap(self.stripBuffer,start_offset, self.bufferHeight/1.5) self.drawHighlightSubview(tmp_dc) self.buffer = tmp_buffer @@ -361,35 +363,35 @@ def OnMotion(self, event): #tmp_dc.Destroy() return """ - + # give the rest task to super class super(DynamicLISAMap,self).OnMotion(event) - + def drawStripView(self,dc): n = len(self.data_sel_keys) if n <= 1: return - - # put the current self.tick in the middle + + # put the current self.tick in the middle if self.tick == 0: start = self.tick elif 1<= self.tick < n-1: start = self.tick -1 else: start = self.tick -2 - + # flag for drawing navigation arrow b2LeftArrow = False b2RightArrow = False - + if self.tick > 0: b2LeftArrow = True if self.tick < n-1: b2RightArrow = True - + # only display 3 maps on strip if n > 3: n = 3 - + # at area: 0,self.bufferHeight * 2/3.0 # draw a light gray area at the bottom first font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT) @@ -403,14 +405,14 @@ def drawStripView(self,dc): bmpFrameHeight = self.bufferHeight / 3.0 bmpWidth = bmpFrameWidth * 0.7 bmpHeight = bmpFrameHeight * 0.8 - bmpOffsetX = (bmpFrameWidth - bmpWidth )/2.0 - bmpOffsetY = (bmpFrameHeight- bmpHeight)/2.0 - + bmpOffsetX = (bmpFrameWidth - bmpWidth )/2.0 + bmpOffsetY = (bmpFrameHeight- bmpHeight)/2.0 + # draw each bmp at strip area dc.SetBrush(wx.Brush(stars.STRIP_VIEW_MAP_BG_COLOR)) end = self.t if start + 3 > self.t else start+3 for i in range(start, end): - start_pos = bmpFrameWidth * (i-start) + bmpOffsetX , framePos[1]+bmpOffsetY + start_pos = bmpFrameWidth * (i-start) + bmpOffsetX , framePos[1]+bmpOffsetY bmp = wx.EmptyBitmapRGBA( bmpFrameWidth, bmpFrameHeight, red = stars.STRIP_VIEW_BG_COLOR.red, @@ -423,7 +425,7 @@ def drawStripView(self,dc): dc.SetPen(wx.TRANSPARENT_PEN) dc.DrawRectangle( start_pos[0], start_pos[1], bmpWidth, bmpHeight) dc.DrawBitmap(bmp, start_pos[0], start_pos[1]) - + # draw red highlight box dc.SetBrush(wx.TRANSPARENT_BRUSH) if self.tick == i: @@ -431,7 +433,7 @@ def drawStripView(self,dc): else: dc.SetPen(wx.TRANSPARENT_PEN) dc.DrawRectangle( start_pos[0], start_pos[1], bmpWidth, bmpHeight) - + # draw label for each map in subview start_date, end_date = self.datetime_intervals[i] if isinstance(start_date, datetime.date): @@ -439,18 +441,18 @@ def drawStripView(self,dc): (start_date.month, start_date.day, start_date.year, - end_date.month, - end_date.day, + end_date.month, + end_date.day, end_date.year ) else: info_tip = "t%d" % (start_date) txt_w,txt_h = dc.GetTextExtent(info_tip) dc.DrawText(info_tip, start_pos[0] + (bmpWidth - txt_w)/2, start_pos[1]+bmpHeight+2) - + # draw navigation arrows arrow_y = framePos[1] + bmpFrameHeight/2.0 - + dc.SetFont(wx.Font(8, wx.NORMAL, wx.NORMAL, wx.NORMAL)) dc.SetBrush(wx.Brush(stars.STRIP_VIEW_NAV_BAR_BG_COLOR)) dc.SetPen(wx.WHITE_PEN) @@ -461,7 +463,7 @@ def drawStripView(self,dc): dc.DrawText("<<", framePos[0]+3, arrow_y) else: self.nav_left = None - + if b2RightArrow: self.nav_right = framePos[0]+self.bufferWidth - 20,framePos[1], 20, self.bufferHeight/3.0 dc.DrawRectangle(self.nav_right[0], self.nav_right[1], self.nav_right[2], self.nav_right[3]) @@ -469,39 +471,39 @@ def drawStripView(self,dc): dc.DrawText(">>", self.bufferWidth-15, arrow_y) else: self.nav_right = None - + #self.Refresh(False) - + def drawSubView(self, lisa_idx, bufferWidth, bufferHeight,bmp): dc = wx.BufferedDC(None, bmp) dc.SetBrush(wx.WHITE_BRUSH) dc.SetPen(wx.TRANSPARENT_PEN) dc.DrawRectangle(0,0,bufferWidth,bufferHeight) - + if not "Linux" in stars.APP_PLATFORM: # not good drawing effect using GCDC in linux dc = wx.GCDC(dc) - + view = View2ScreenTransform( - self.extent, - bufferWidth, + self.extent, + bufferWidth, bufferHeight - ) - + ) + ml = self.moran_locals[lisa_idx] # 0 not significant, 1 HH, 2 LL, 3 LH, 4 HL, 5 Neighborless sigFlag = ml[2] clusterFlag = ml[3] lm_sig = np.array(sigFlag) lm_q = np.array(clusterFlag) - + id_groups = [[] for i in range(6)] for i,sig in enumerate(lm_sig): if sig > 0: id_groups[lm_q[i]].append(i) else: id_groups[0].append(i) - + from stars.visualization.maps.BaseMap import PolygonLayer draw_layer = PolygonLayer(self, self.layer, build_spatial_index=False) #edge_clr = wx.WHITE#wx.Colour(200,200,200, self.opaque) @@ -510,20 +512,20 @@ def drawSubView(self, lisa_idx, bufferWidth, bufferHeight,bmp): draw_layer.set_data_group(id_groups) draw_layer.set_fill_color_group(self.lisa_color_group) draw_layer.draw(dc, view) - - + + def enableStripView(self, event): self.bStrip = not self.bStrip if self.bStrip == False: self.view = View2ScreenTransform( - self.extent, - self.bufferWidth, + self.extent, + self.bufferWidth, self.bufferHeight ) else: self.view = View2ScreenTransform( - self.extent, - self.bufferWidth, + self.extent, + self.bufferWidth, self.bufferHeight - self.bufferHeight/3.0 ) self.reInitBuffer = True @@ -538,7 +540,7 @@ def OnLeftDown(self, event): self.nav_left[1] <= mouse_end_y <= self.nav_left[3]: self.stopAnimation = True return - # determine for right + # determine for right if self.nav_right: if self.nav_right[0] <= mouse_end_x <= self.nav_right[2] and \ self.nav_right[1] <= mouse_end_y <= self.nav_right[3]: @@ -546,7 +548,7 @@ def OnLeftDown(self, event): return # give the rest task to super class super(DynamicLISAMap,self).OnLeftDown(event) - + def OnLeftUp(self, event): """ override for click on strip view """ if self.bStrip: @@ -558,27 +560,27 @@ def OnLeftUp(self, event): if self.nav_left[0] <= mouse_end_x <= self.nav_left[2] and \ self.nav_left[1] <= mouse_end_y <= self.nav_left[3]: self.stopAnimation = False - start_offset = -self.stripBmpFrameWidth * self.tick + start_offset = -self.stripBmpFrameWidth * self.tick if self.tick < self.t-1: self.tick = self.tick + 1 self.animateStripView(acc, start_offset) else: self.animateStripView(acc, start_offset,isEnd=True) - # determine for right + # determine for right if self.nav_right: if self.nav_right[0] <= mouse_end_x <= self.nav_right[2] and \ self.nav_right[1] <= mouse_end_y <= self.nav_right[3]: self.stopAnimation = False - start_offset = -self.stripBmpFrameWidth * self.tick + start_offset = -self.stripBmpFrameWidth * self.tick if self.tick>0: self.tick = self.tick -1 self.animateStripView(acc, start_offset, isLeft=False) else: self.animateStripView(acc, start_offset, isLeft=False, isEnd=True) - + # give the rest task to super class super(DynamicLISAMap,self).OnLeftUp(event) - + def animateStripView(self, acc, start_offset, isLeft=True, t=1,isEnd=False): """ """ @@ -590,10 +592,10 @@ def animateStripView(self, acc, start_offset, isLeft=True, t=1,isEnd=False): offset = acc*20*t - acc * (t**2) / 2.0 else: offset = acc*10*t - acc * (t**2) / 2.0 - + if isLeft: offset = -offset offset = start_offset + offset - + tmp_buffer = wx.EmptyBitmap(self.bufferWidth, self.bufferHeight) tmp_dc = wx.BufferedDC(None, tmp_buffer) tmp_dc.DrawBitmap(self.drawing_backup_buffer,0,0) @@ -612,37 +614,37 @@ def animateStripView(self, acc, start_offset, isLeft=True, t=1,isEnd=False): self.buffer = tmp_buffer #tmp_dc.Destroy() self.Refresh(False) - + t = t + 1 if self.stopAnimation == False: - wx.FutureCall(10, self.animateStripView, acc, start_offset, isLeft,t,isEnd) + wx.FutureCall(10, self.animateStripView, acc, start_offset, isLeft,t,isEnd) #tmp_dc.DrawBitmap(self.stripBuffer, offset_dist, self.bufferHeight/1.5) - + def OnRightUp(self,event): menu = wx.Menu() menu.Append(201, "Show/Hide strip view", "") menu.Append(210, "Select Neighbors", "") menu.Append(211, "Cancel Select Neighbors", "") - + menu.UpdateUI() menu.Bind(wx.EVT_MENU, self.enableStripView, id=201) menu.Bind(wx.EVT_MENU, self.select_by_weights, id=210) menu.Bind(wx.EVT_MENU, self.cancel_select_by_weights, id=211) self.PopupMenu(menu) - - event.Skip() - + + event.Skip() + def ExportMovie(self,path,duration=3): from stars.visualization.utils.images2gif import writeGif,writeBmps2Gif - + if isinstance(self.start_date, datetime.date): Y,M,D = self.start_date.year, self.start_date.month, self.start_date.day # python.DateTime start_date = wx.DateTime.Today() start_date.Year,start_date.Month, start_date.Day = Y,M,D else: # 1,2,3..., n time step - start_date = self.start_date - + start_date = self.start_date + tick = self.tick movie_bmps = [] for i in range(self.t): @@ -652,20 +654,20 @@ def ExportMovie(self,path,duration=3): dc.SelectObject(tmp_bmp) self.updateDraw(i) self.DoDraw(dc) - + # draw lables if isinstance(self.start_date, datetime.date): if i < self.t -1: end_date = wx.DateTime.Today() end_date.Set(start_date.Day, start_date.Month, start_date.Year) - + if self.step_by == 'Day': end_date += wx.DateSpan(days=self.step) elif self.step_by == 'Month': end_date += wx.DateSpan(months=self.step) elif self.step_by == 'Year': end_date += wx.DateSpan(years=self.step) - + label = '(%d/%d) %s/%s/%s - %s/%s/%s (%s %s period)' % \ (i+1,self.t, start_date.Month,start_date.Day,start_date.Year, end_date.Month, end_date.Day, end_date.Year,self.step, self.step_by @@ -682,7 +684,7 @@ def ExportMovie(self,path,duration=3): end_date = start_date + 1 label = '(%d/%d) step: %d (%s %s period)' % (i+1, self.t, start_date, self.step, self.step_by) start_date = end_date - + dc.DrawText(label, 5,5) #dc.Destroy() movie_bmps.append(tmp_bmp) @@ -691,7 +693,7 @@ def ExportMovie(self,path,duration=3): self.ShowMsgBox("Movie file (GIF) created successfully.", mtype='CAST information', micon=wx.ICON_INFORMATION) - + class DynamicLISAQueryDialog(SpaceTimeQueryDialog): """ Query Dialog for generating dynamic LISA Maps @@ -705,31 +707,31 @@ def Add_Customized_Controls(self): open_bmp = wx.BitmapFromImage(stars.OPEN_ICON_IMG) self.btn_weight_path = wx.BitmapButton(self.panel,-1, open_bmp, pos=(x2+292,y2+32), style=wx.NO_BORDER) self.Bind(wx.EVT_BUTTON, self.BrowseWeightFile, self.btn_weight_path) - + def OnReset(self,event): self.reset() self.cmbox_location.SetSelection(-1) self.txt_weight_path.SetValue('') self.background_shps = [] self.background_shp_idx = -1 - self.weight_path =None - + self.weight_path =None + def BrowseWeightFile(self,event): dlg = wx.FileDialog( - None, message="Choose a file", + None, message="Choose a file", wildcard="Weights file (*.gal,*.gwt)|*.gwt;*.gal|All files (*.*)|*.*", style=wx.OPEN | wx.CHANGE_DIR ) if dlg.ShowModal() == wx.ID_OK: - self.weight_path = dlg.GetPath() + self.weight_path = dlg.GetPath() self.txt_weight_path.SetValue(self.weight_path) - dlg.Destroy() - + dlg.Destroy() + def _check_weight_path(self): if len(self.txt_weight_path.GetValue())>0: return True return False - + def OnQuery(self,event): if self._check_time_itv_input() == False: self.ShowMsgBox("Please select a time interval first.") @@ -740,34 +742,34 @@ def OnQuery(self,event): if self._check_weight_path() == False: self.ShowMsgBox("Please select a weights file first.") return - + self.current_selected = range(self.dbf.n_records) self._filter_by_query_field() self.query_date = None # query_date is not available in Trend Graph case self._filter_by_date_interval() self._filter_by_tod() - + # LISA layer (only one) lisa_layer = self.background_shps[self.background_shp_idx] if lisa_layer.shape_type != stars.SHP_POLYGON: self.ShowMsgBox("Space should be a POLYGON layer.") return - + self.lisa_layer = lisa_layer lisa_data_dict = self.gen_date_by_step() self.query_data = lisa_data_dict - + if self.query_data == None: self.ShowMsgBox("Query dynamic data by STEP error.") return - + title = "" if self.query_field.lower() != "all fields": title = "(%s:%s)"%(self.query_field,self.query_range) - + # check the extent of LISA layer and Points layer """ - for lisa_data in lisa_data_dict.values(): + for lisa_data in lisa_data_dict.values(): if sum(lisa_data) == 0: self.ShowMsgBox("No records found inside the space area, please check if the space and points are in same extent.") return @@ -784,28 +786,28 @@ def OnQuery(self,event): title = title ) dynamic_lisa_widget.Show() - + self.btn_save.Enable(True) - + def gen_date_by_step(self): """ generate dynamic LISA map data by STEP """ from stars.visualization.utils import GetIntervalStep - + step = self.step step_by = self.step_by - background_shp_idx = self.background_shp_idx + background_shp_idx = self.background_shp_idx background_shp = self.background_shps[background_shp_idx] - + if background_shp.shape_type != stars.SHP_POLYGON: self.ShowMsgBox("Background shape file should be POLYGON!") return None - + if not pysal.cg.standalone.bbcommon(background_shp.extent, self.points_data.extent): self.ShowMsgBox("Mismatch of spatial extent of points and polygon shapefiles.") return None - + start_date = self._wxdate2pydate(self.itv_start_date.GetValue()) end_date = self._wxdate2pydate(self.itv_end_date.GetValue()) total_steps = GetIntervalStep(end_date, start_date, step, step_by) @@ -827,12 +829,12 @@ def gen_date_by_step(self): self.Destroy() return None self.Destroy() - + self.start_date = start_date self.end_date = end_date - - return_data_dict = dict([(i,np.zeros(len(background_shp))) for i in range(total_steps)]) - + + return_data_dict = dict([(i,np.zeros(len(background_shp))) for i in range(total_steps)]) + # create a kd-tree from centroids of lisa_shp n = len(self.current_selected) itv = n/5 @@ -844,33 +846,33 @@ def gen_date_by_step(self): style = wx.PD_APP_MODAL|wx.PD_AUTO_HIDE) progress_dlg.CenterOnScreen() - + # check which point is in which polygon bmp,view,poly_color_dict = self.draw_space_in_buffer(background_shp) not_sure_points = [] is_valid_query = False - + for count,j in enumerate(self.current_selected): if count % itv == 0: progress_dlg.Update(count +1) - + _date = self.all_dates[j] interval_idx = GetIntervalStep(_date, start_date, step, step_by)-1 - + p = self.points[j] x,y = view.view_to_pixel(p[0],p[1]) x,y = int(round(x)), int(round(y)) - + if x<0 or y < 0 or x >= bmp.Width or y >= bmp.Height: continue - + r = bmp.GetRed(x,y) g = bmp.GetGreen(x,y) b = bmp.GetBlue(x,y) - + if r==255 and g==255 and b==255: continue - + if (r,g,b) in poly_color_dict: poly_id = poly_color_dict[(r,g,b)] poly_id_cnt = 0 @@ -892,10 +894,10 @@ def gen_date_by_step(self): # this case, the color of border line of severl polygons # accidentally equals to an existing color code not_sure_points.append(j) - + else: # check if this pixel is sitting on the boarder line - # pick up the color code, in the case that this is + # pick up the color code, in the case that this is # the boarder line of only one polygon candidate_color = None candidate_color_cnt = 0 @@ -908,22 +910,22 @@ def gen_date_by_step(self): n_r = bmp.GetRed(n_x,n_y) n_g = bmp.GetGreen(n_x,n_y) n_b = bmp.GetBlue(n_x,n_y) - + local_color = (n_r,n_g,n_b) if poly_color_dict.has_key(local_color): candidate_color = local_color candidate_color_cnt += 1 if candidate_color_cnt > 1: break - + if candidate_color_cnt == 1: poly_id = poly_color_dict[candidate_color] return_data_dict[interval_idx][poly_id] += 1 is_valid_query = True else: not_sure_points.append(j) - - + + if len(not_sure_points)>0: query_points = [self.points[i] for i in not_sure_points] poly_ids = background_shp.test_point_in_polygon(query_points) @@ -933,27 +935,27 @@ def gen_date_by_step(self): interval_idx = GetIntervalStep(_date, start_date, step, step_by)-1 return_data_dict[interval_idx][poly_ids[i]] += 1 is_valid_query = True - + progress_dlg.Update(n) - progress_dlg.Destroy() - + progress_dlg.Destroy() + return return_data_dict - + def OnSaveQueryToDBF(self, event): try: if self.query_data == None: return dlg = wx.FileDialog( - self, message="Save query into new dbf files...", defaultDir=os.getcwd(), - defaultFile='%s.dbf' % (self.lisa_layer.name + '_dynamic_lisa'), - wildcard="shape file (*.dbf)|*.dbf|All files (*.*)|*.*", + self, message="Save query into new dbf files...", defaultDir=os.getcwd(), + defaultFile='%s.dbf' % (self.lisa_layer.name + '_dynamic_lisa'), + wildcard="shape file (*.dbf)|*.dbf|All files (*.*)|*.*", style=wx.SAVE) if dlg.ShowModal() != wx.ID_OK: dlg.Destroy() return path = dlg.GetPath() dlg.Destroy() - + dbf = self.lisa_layer.dbf newDBF= pysal.open('%s.dbf'%path[:-4],'w') newDBF.header = [] @@ -962,12 +964,12 @@ def OnSaveQueryToDBF(self, event): newDBF.header.append(i) for i in dbf.field_spec: newDBF.field_spec.append(i) - + for i in self.query_data.keys(): newDBF.header.append('T_%d'%(i+1)) newDBF.field_spec.append(('N',4,0)) - - for i in range(dbf.n_records): + + for i in range(dbf.n_records): newRow = [] row = dbf.read_record(i) newRow = [item for item in row] @@ -981,14 +983,14 @@ def OnSaveQueryToDBF(self, event): micon=wx.ICON_INFORMATION) except: self.ShowMsgBox("Saving query results to new dbf file failed. Please check if the dbf file already exists.") - + def ShowDynamicLISAMap(self): # self is Main.py if not self.shapefiles or len(self.shapefiles) < 1: return shp_list = [shp.name for shp in self.shapefiles] dlg = wx.SingleChoiceDialog( - self, 'Select a POINT or Polygon(with time field) shape file:', + self, 'Select a POINT or Polygon(with time field) shape file:', 'Dynamic LISA Map', shp_list,wx.CHOICEDLG_STYLE) if dlg.ShowModal() == wx.ID_OK: idx = dlg.GetSelection() @@ -997,18 +999,18 @@ def ShowDynamicLISAMap(self): # create dynamic LISA from points d_lisa_dlg = DynamicLISAQueryDialog( self,"Dynamic LISA:" + shp.name, - shp, + shp, background_shps=self.shapefiles, size=stars.DIALOG_SIZE_QUERY_DYNAMIC_LISA ) d_lisa_dlg.Show() elif shp.shape_type == stars.SHP_POLYGON: - # bring up a dialog and let user select + # bring up a dialog and let user select # the time field in POLYGON shape file - dbf_field_list = shp.dbf.header + dbf_field_list = shp.dbf.header timedlg = wx.MultiChoiceDialog( - self, 'Select TIME fields to generate Dynamic LISA:', - 'DBF fields view', + self, 'Select TIME fields to generate Dynamic LISA:', + 'DBF fields view', dbf_field_list ) if timedlg.ShowModal() == wx.ID_OK: @@ -1019,7 +1021,7 @@ def ShowDynamicLISAMap(self): count = 0 for idx in selections: lisa_data_dict[count] = np.array(dbf.by_col(dbf.header[idx])) - count += 1 + count += 1 # select weight file wdlg = wx.FileDialog( self, message="Select a weights file", @@ -1042,8 +1044,8 @@ def ShowDynamicLISAMap(self): dynamic_lisa_widget.Show() wdlg.Destroy() timedlg.Destroy() - else: + else: self.ShowMsgBox("File type error. Should be a POINT shapefile.") dlg.Destroy() return - dlg.Destroy() \ No newline at end of file + dlg.Destroy() diff --git a/stars/visualization/maps/DynamicLocalG.py b/stars/visualization/maps/DynamicLocalG.py index b8f7fc7..de3194e 100644 --- a/stars/visualization/maps/DynamicLocalG.py +++ b/stars/visualization/maps/DynamicLocalG.py @@ -22,19 +22,19 @@ class DynamicLocalG(ShapeMap): """ def __init__(self, parent, layers, **kwargs): ShapeMap.__init__(self,parent, layers) - + try: self.weight_file = kwargs["weight"] self.cs_data_dict = kwargs["query_data"] self.bufferWidth, self.bufferHeight = kwargs["size"] self.step, self.step_by = kwargs["step"] ,kwargs["step_by"] self.start_date, self.end_date = kwargs["start"],kwargs["end"] - + self.nav_left = None self.nav_right = None self.bStrip = True - - # preprocessing parameters + + # preprocessing parameters self.parent = parent self.layer = layers[0] self.data_sel_keys = sorted(self.cs_data_dict.keys()) @@ -42,35 +42,36 @@ def __init__(self, parent, layers, **kwargs): self.weight = pysal.open(self.weight_file).read() self.t = len(self.cs_data_dict) # number of data slices self.n = len(self.data_sel_values[0]) # number of shape objects - + self.extent = self.layer.extent self.view = View2ScreenTransform( - self.extent, - self.bufferWidth, + self.extent, + self.bufferWidth, self.bufferHeight - self.bufferHeight/3.0 - ) - + ) + self.tick = 0 self.datetime_intervals, self.interval_labels = GetDateTimeIntervals(self.start_date, self.end_date,self.t, self.step, self.step_by) self.setupDynamicControls() - self.parentFrame.SetTitle('Local G Map-%s %s' % (self.layer.name,kwargs["title"])) + ttl = "" if "title" not in kwargs else kwargs["title"] + self.parentFrame.SetTitle('Local G Map-%s %s' % (self.layer.name, ttl)) self.dynamic_control = DynamicMapControl(self.parentFrame,self.t+1,self.updateDraw) - + self.trendgraphWidget = None self.popupTrendGraph = None - + # preprocessing Gi* SpaceTime maps self.processDynamicLocalG() - + except Exception as err: detail_message = err.message if err.message == "dimension mismatch": detail_message = "The number of time intervals doesn't match time weights and space-time query." message = """Dynamic Local G map could not be created. Please re-select appropriate parameters and weights file. - + Details:""" + detail_message self.ShowMsgBox(message) - + self.UnRegister() if self.trendgraphWidget: self.trendgraphWidget.Close(True) @@ -80,7 +81,7 @@ def __init__(self, parent, layers, **kwargs): if os.name == 'nt': self.Destroy() return None - + def OnClose(self, event): self.UnRegister() if self.trendgraphWidget: @@ -88,7 +89,7 @@ def OnClose(self, event): if self.popupTrendGraph: self.popupTrendGraph.Close(True) event.Skip() - + def setupDynamicControls(self): """ assign labels of dynamic controls @@ -105,15 +106,15 @@ def setupDynamicControls(self): self.parentWidget.label_current.SetLabel('current: %d (%d-%s period)' % (1,self.step, self.step_by)) except: raise Exception("Setup dynamic controls in toolbar failed!") - + def processDynamicLocalG(self): b_gstar, b_binary = choose_local_g_settings(self) map_type = 'Gi*' if b_gstar else 'Gi' add_type = 'binary' if b_binary else 'row-standardized' self.parentFrame.SetTitle('Local G Map (%s,%s)-%s' % (map_type,add_type,self.layer.name)) - - self.space_gstar = dict() + + self.space_gstar = dict() self.space_gstar_z= dict() for tid,obs in self.cs_data_dict.iteritems(): y = np.array(obs) @@ -123,14 +124,14 @@ def processDynamicLocalG(self): lg = pysal.esda.getisord.G_Local(y,self.weight,star=b_gstar,transform='B') self.space_gstar[tid] = lg.p_sim self.space_gstar_z[tid] = lg.Zs - + trendgraph_data = dict() for i in range(self.n): data = [] for j in range(self.t): data.append(self.cs_data_dict[j][i]) trendgraph_data[i] = data - self.trendgraph_data = trendgraph_data + self.trendgraph_data = trendgraph_data # default color schema for Gi* self.HH_color = stars.LISA_HH_COLOR @@ -140,24 +141,24 @@ def processDynamicLocalG(self): color_group =[self.NOT_SIG_color,self.HH_color,self.LL_color] label_group = ["Not Significant","High-High","Low-Low"] self.color_schema_dict[self.layer.name] = ColorSchema(color_group,label_group) - + self.gi_color_group = color_group - + self.updateDraw(0) - + # Thread-based controller for dynamic LISA - self.dynamic_control = DynamicMapControl(self.parentFrame,self.t,self.updateDraw) - + self.dynamic_control = DynamicMapControl(self.parentFrame,self.t,self.updateDraw) + def draw_selected_by_ids(self, shape_ids_dict, dc=None): super(DynamicLocalG, self).draw_selected_by_ids(shape_ids_dict,dc) self.selected_shape_ids = shape_ids_dict - - def draw_selected_by_region(self,dc, region, - isEvtResponse=False, + + def draw_selected_by_region(self,dc, region, + isEvtResponse=False, isScreenCoordinates=False): super(DynamicLocalG, self).draw_selected_by_region( dc, region, isEvtResponse, isScreenCoordinates) - + def OnSize(self,event): """ overwrite OnSize in ShapeMap.py @@ -170,10 +171,10 @@ def OnSize(self,event): self.view.pixel_height = self.bufferHeight - self.bufferHeight/3.0 self.view.pixel_width = self.bufferWidth self.view.init() - if self.bStrip: + if self.bStrip: self.stripBuffer = None self.reInitBuffer = True - + def OnMotion(self, event): """ """ @@ -184,27 +185,27 @@ def OnMotion(self, event): if self.nav_left[0] <= mouse_end_x <= self.nav_left[2] and \ self.nav_left[1] <= mouse_end_y <= self.nav_left[3]: return - # determine for right + # determine for right if self.nav_right: if self.nav_right[0] <= mouse_end_x <= self.nav_right[2] and \ self.nav_right[1] <= mouse_end_y <= self.nav_right[3]: return - + if event.Dragging() and event.LeftIsDown() and self.isMouseDrawing: - x, y = event.GetX(), event.GetY() + x, y = event.GetX(), event.GetY() # while mouse is down and moving if self.map_operation_type == stars.MAP_OP_PAN: # disable PAN (not support in this version) return - + # give the rest task to super class super(DynamicLocalG,self).OnMotion(event) - + def Update(self, tick): """ When SLIDER is dragged """ - self.updateDraw(tick) + self.updateDraw(tick) def updateDraw(self,tick): """ @@ -213,32 +214,32 @@ def updateDraw(self,tick): self.tick = tick p_values = self.space_gstar[tick] z_values = self.space_gstar_z[tick] - + # 0 not significant, 6 significant change not_sig = list(np.where(p_values>0.05)[0]) sig = set(np.where(p_values<=0.05)[0]) hotspots = list(sig.intersection(set(np.where(z_values>=0)[0])) ) coldspots = list(sig.intersection(set(np.where(z_values<0)[0])) ) id_groups = [not_sig,hotspots,coldspots] - + self.id_groups = id_groups self.draw_layers[self.layer].set_data_group(id_groups) self.draw_layers[self.layer].set_fill_color_group(self.gi_color_group) edge_clr = self.color_schema_dict[self.layer.name].edge_color self.draw_layers[self.layer].set_edge_color(edge_clr) - # trigger to draw - self.reInitBuffer = True + # trigger to draw + self.reInitBuffer = True self.parentWidget.label_current.SetLabel('current: %d (%d-%s period)' % (tick+1,self.step, self.step_by)) - + def DoDraw(self, dc): """ Overwrite this function from base class for customized drawing """ super(DynamicLocalG, self).DoDraw(dc) - + if self.bStrip: self.drawStripView(dc) - + def OnLeftUp(self, event): """ override for click on strip view """ if self.bStrip: @@ -249,34 +250,34 @@ def OnLeftUp(self, event): self.nav_left[1] <= mouse_end_y <= self.nav_left[1] + self.nav_left[3]: self.tick = self.tick -1 if self.tick>0 else 0 self.updateDraw(self.tick) - # determine for right + # determine for right if self.nav_right: if self.nav_right[0] <= mouse_end_x <= self.nav_right[0] + self.nav_right[2] and \ self.nav_right[1] <= mouse_end_y <= self.nav_right[1] + self.nav_right[3]: self.tick = self.tick +1 if self.tick<=self.n else self.tick self.updateDraw(self.tick) - + # give the rest task to super class super(DynamicLocalG,self).OnLeftUp(event) - + def drawStripView(self,dc): """ - For each Gi map at T_i, two related Gi maps at + For each Gi map at T_i, two related Gi maps at T_(i-1) ant T_(i+1) will be displayed in this strip area """ n = len(self.data_sel_keys) if n <= 1: return - + start = self.tick if start+1 > n: return end = start + 2 - + # flag for drawing navigation arrow b2LeftArrow = True if self.tick > 0 else False b2RightArrow = True if self.tick < n-2 else False - + # at area: 0,self.bufferHeight * 2/3.0 # draw a light gray area at the bottom first font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT) @@ -286,14 +287,14 @@ def drawStripView(self,dc): dc.SetBrush(brush) framePos = 0, self.bufferHeight * 2.0/3.0 dc.DrawRectangle(framePos[0],framePos[1], self.bufferWidth, self.bufferHeight/3.0) - + # calculate width and height for each bmp bmpFrameWidth = self.bufferWidth / 2.0 # frame is divided into 2 parts bmpFrameHeight = self.bufferHeight / 3.0 bmpWidth = bmpFrameWidth * 0.6 bmpHeight = bmpFrameHeight * 0.8 - bmpOffsetX = (bmpFrameWidth - bmpWidth )/2.0 - bmpOffsetY = (bmpFrameHeight- bmpHeight)/2.0 + bmpOffsetX = (bmpFrameWidth - bmpWidth )/2.0 + bmpOffsetY = (bmpFrameHeight- bmpHeight)/2.0 # draw text for center large graph start_date, end_date = self.datetime_intervals[self.tick] @@ -305,12 +306,12 @@ def drawStripView(self,dc): info_tip = "t%d - t%d" % (start_date, end_date) txt_w,txt_h = dc.GetTextExtent(info_tip) dc.DrawText(info_tip, (self.bufferWidth - txt_w)/2, framePos[1] - txt_h) - + # draw two related Gi* maps in strip area dc.SetBrush(wx.Brush(stars.STRIP_VIEW_MAP_BG_COLOR)) #for i in range(start, end): if self.tick - 1 >= 0: - start_pos = bmpOffsetX, framePos[1]+bmpOffsetY + start_pos = bmpOffsetX, framePos[1]+bmpOffsetY dc.DrawRectangle(start_pos[0], start_pos[1], bmpWidth, bmpHeight) bmp = wx.EmptyBitmapRGBA( bmpFrameWidth, bmpFrameHeight, @@ -330,9 +331,9 @@ def drawStripView(self,dc): info_tip = "t%d - t%d" % (start_date, end_date) txt_w,txt_h = dc.GetTextExtent(info_tip) dc.DrawText(info_tip, start_pos[0] + (bmpWidth - txt_w)/2, start_pos[1]+bmpHeight+2) - + if self.tick + 1 < self.t: - start_pos = bmpFrameWidth + bmpOffsetX , framePos[1]+bmpOffsetY + start_pos = bmpFrameWidth + bmpOffsetX , framePos[1]+bmpOffsetY dc.DrawRectangle(start_pos[0], start_pos[1], bmpWidth, bmpHeight) bmp = wx.EmptyBitmapRGBA( bmpFrameWidth, bmpFrameHeight, @@ -352,10 +353,10 @@ def drawStripView(self,dc): info_tip = "t%d - t%d" % (start_date, end_date) txt_w,txt_h = dc.GetTextExtent(info_tip) dc.DrawText(info_tip, start_pos[0] + (bmpWidth - txt_w)/2, start_pos[1]+bmpHeight+2) - + # draw navigation arrows arrow_y = framePos[1] + bmpFrameHeight/2.0 - + dc.SetFont(wx.Font(stars.NAV_ARROW_FONT_SIZE, wx.NORMAL, wx.NORMAL, wx.NORMAL)) dc.SetBrush(wx.Brush(stars.STRIP_VIEW_NAV_BAR_BG_COLOR)) dc.SetPen(wx.WHITE_PEN) @@ -366,7 +367,7 @@ def drawStripView(self,dc): dc.DrawText("<<", framePos[0]+3, arrow_y) else: self.nav_left = None - + if b2RightArrow: self.nav_right = framePos[0]+self.bufferWidth - 20,framePos[1], 20, self.bufferHeight/3.0 dc.DrawRectangle(self.nav_right[0], self.nav_right[1], self.nav_right[2], self.nav_right[3]) @@ -374,7 +375,7 @@ def drawStripView(self,dc): dc.DrawText(">>", self.bufferWidth-15, arrow_y) else: self.nav_right = None - + def drawSubGiMap(self, idx, bufferWidth, bufferHeight,bmp): """ Draw two relative Gi* maps for current Gi* map @@ -383,26 +384,26 @@ def drawSubGiMap(self, idx, bufferWidth, bufferHeight,bmp): dc.SetBrush(wx.WHITE_BRUSH) dc.SetPen(wx.TRANSPARENT_PEN) dc.DrawRectangle(0,0,bufferWidth,bufferHeight) - + if not "Linux" in stars.APP_PLATFORM: # not good drawing effect using GCDC in linux dc = wx.GCDC(dc) - + view = View2ScreenTransform( - self.extent, - bufferWidth, + self.extent, + bufferWidth, bufferHeight - ) - + ) + p_values = self.space_gstar[idx] z_values = self.space_gstar_z[idx] - + not_sig = list(np.where(p_values>0.05)[0]) sig = set(np.where(p_values<=0.05)[0]) hotspots = list(sig.intersection(set(np.where(z_values>=0)[0])) ) coldspots = list(sig.intersection(set(np.where(z_values<0)[0])) ) id_groups = [not_sig,hotspots,coldspots] - + from stars.visualization.maps.BaseMap import PolygonLayer draw_layer = PolygonLayer(self, self.layer, build_spatial_index=False) #edge_clr = wx.Colour(200,200,200, self.opaque) @@ -410,26 +411,26 @@ def drawSubGiMap(self, idx, bufferWidth, bufferHeight,bmp): draw_layer.set_edge_color(edge_clr) draw_layer.set_data_group(id_groups) draw_layer.set_fill_color_group(self.gi_color_group) - draw_layer.draw(dc, view) - + draw_layer.draw(dc, view) + return bmp - + def OnRightUp(self,event): menu = wx.Menu() menu.Append(210, "Select Neighbors", "") menu.Append(211, "Cancel Select Neighbors", "") #menu.Append(212, "Toggle internal popup window", "") #menu.Append(212, "Show external popup time LISA", "") - + menu.UpdateUI() menu.Bind(wx.EVT_MENU, self.select_by_weights, id=210) menu.Bind(wx.EVT_MENU, self.cancel_select_by_weights, id=211) #menu.Bind(wx.EVT_MENU, self.showInternalPopupTimeLISA, id=212) #menu.Bind(wx.EVT_MENU, self.showExtPopupTimeLISA, id=212) self.PopupMenu(menu) - - event.Skip() - + + event.Skip() + class DynamicLocalGQueryDialog(DynamicLISAQueryDialog): """ """ @@ -440,32 +441,32 @@ def Add_Customized_Controls(self): self.txt_weight_path = wx.TextCtrl(self.panel, -1, "",pos=(x2+100,y2+30), size=(180,-1) ) #open_bmp = wx.ArtProvider.GetBitmap(wx.ART_FILE_OPEN, wx.ART_TOOLBAR, (16,16)) open_bmp = wx.BitmapFromImage(stars.OPEN_ICON_IMG) - + self.btn_weight_path = wx.BitmapButton(self.panel,-1, open_bmp, pos=(x2+292,y2+32), style=wx.NO_BORDER) - + self.Bind(wx.EVT_BUTTON, self.BrowseWeightFile, self.btn_weight_path) - + def OnQuery(self,event): if self._check_time_itv_input() == False or\ self._check_weight_path() == False or\ self._check_space_input() == False: return - + self.current_selected = range(self.dbf.n_records) self._filter_by_query_field() - self.query_date = None + self.query_date = None self._filter_by_date_interval() self._filter_by_tod() - + self.query_data = self.gen_date_by_step() if self.query_data == None or len(self.query_data) <= 1: self.ShowMsgBox("Dynamic Local G Map requires at least 2 time intervals, please reselect step-by parameters.") return - + title = "" if self.query_field.lower() != "all fields": title = "(%s:%s)"%(self.query_field,self.query_range) - + # LISA layer (only one) g_layer = [self.background_shps[self.background_shp_idx]] gi_widget = DynamicMapWidget( @@ -482,38 +483,38 @@ def OnQuery(self,event): title=title ) gi_widget.Show() - + # (enable) save LISA Markov to new shp/dbf files #self.btn_save.Enable(True) #self.lisa_layer = lisa_layer[0] #self.lisa_markov_map = gi_widget.map_canvas - - + + def OnSaveQueryToDBF(self, event): """ Save Markov type in each interval for each record to dbf file. """ if self.query_data == None: return - + dlg = wx.FileDialog( - self, - message="Save Markov LISA type to new dbf file...", - defaultDir=os.getcwd(), - defaultFile='%s.shp' % (self.lisa_layer.name + '_markov_lisa'), - wildcard="shape file (*.shp)|*.shp|All files (*.*)|*.*", + self, + message="Save Markov LISA type to new dbf file...", + defaultDir=os.getcwd(), + defaultFile='%s.shp' % (self.lisa_layer.name + '_markov_lisa'), + wildcard="shape file (*.shp)|*.shp|All files (*.*)|*.*", style=wx.SAVE ) if dlg.ShowModal() != wx.ID_OK: return - + path = dlg.GetPath() dbf = self.lisa_layer.dbf try: n_intervals = self.lisa_markov_map.t -1 n_objects = len(dbf) lisa_markov_mt = self.lisa_markov_map.lisa_markov_mt - + newDBF= pysal.open('%s.dbf'%path[:-4],'w') newDBF.header = [] newDBF.field_spec = [] @@ -521,37 +522,37 @@ def OnSaveQueryToDBF(self, event): newDBF.header.append(i) for i in dbf.field_spec: newDBF.field_spec.append(i) - + for i in range(n_intervals): newDBF.header.append('MARKOV_ITV%d'%(i+1)) newDBF.field_spec.append(('N',4,0)) - - for i in range(n_objects): + + for i in range(n_objects): newRow = [] newRow = [item for item in dbf[i][0]] for j in range(n_intervals): move_type = lisa_markov_mt[i][j] newRow.append(move_type) - + newDBF.write(newRow) newDBF.close() - + self.ShowMsgBox("Query results have been saved to new dbf file.", mtype='CAST Information', micon=wx.ICON_INFORMATION) except: self.ShowMsgBox("Saving query results to dbf file failed! Please check if the dbf file already exists.") - - + + def ShowDynamicLocalGMap(self): # self is Main.py if not self.shapefiles or len(self.shapefiles) < 1: return shp_list = [shp.name for shp in self.shapefiles] dlg = wx.SingleChoiceDialog( - self, - 'Select a POINT or Polygon(with time field) shape file:', - 'Dynamic Local G Map', + self, + 'Select a POINT or Polygon(with time field) shape file:', + 'Dynamic Local G Map', shp_list, wx.CHOICEDLG_STYLE) if dlg.ShowModal() == wx.ID_OK: @@ -562,18 +563,18 @@ def ShowDynamicLocalGMap(self): # create Dynamic Local G from points gi_dlg = DynamicLocalGQueryDialog( self,"Dynamic Local G:" + shp.name, - shp, + shp, background_shps=background_shapes, size=stars.DIALOG_SIZE_QUERY_DYNAMIC_LISA ) gi_dlg.Show() elif shp.shape_type == stars.SHP_POLYGON: - # bring up a dialog and let user select + # bring up a dialog and let user select # the time field in POLYGON shape file - dbf_field_list = shp.dbf.header + dbf_field_list = shp.dbf.header timedlg = wx.MultiChoiceDialog( - self, 'Select TIME fields to generate Dynamic Local G map:', - 'DBF fields view', + self, 'Select TIME fields to generate Dynamic Local G map:', + 'DBF fields view', dbf_field_list ) if timedlg.ShowModal() == wx.ID_OK: @@ -584,7 +585,7 @@ def ShowDynamicLocalGMap(self): count = 0 for idx in selections: lisa_data_dict[count] = np.array(dbf.by_col(dbf.header[idx])) - count += 1 + count += 1 # select weight file wdlg = wx.FileDialog( self, message="Select a weights file", @@ -595,8 +596,8 @@ def ShowDynamicLocalGMap(self): # todo: select filter weight_path = wdlg.GetPath() gi_spacetime_widget= DynamicMapWidget( - self, - [shp], + self, + [shp], DynamicLocalG, weight = weight_path, query_data = lisa_data_dict, @@ -613,4 +614,4 @@ def ShowDynamicLocalGMap(self): self.ShowMsgBox("File type error. Should be a POINT or POLYGON shapefile.") dlg.Destroy() return - dlg.Destroy() \ No newline at end of file + dlg.Destroy() diff --git a/stars/visualization/plots/TrendGraph.py b/stars/visualization/plots/TrendGraph.py index 9ca6744..27a0061 100644 --- a/stars/visualization/plots/TrendGraph.py +++ b/stars/visualization/plots/TrendGraph.py @@ -15,7 +15,7 @@ from stars.visualization.EventHandler import AbstractData from stars.visualization.PlotWidget import PlotWidget,PlottingCanvas from stars.visualization.utils import PaintCollection, View2ScreenTransform, GetRandomColor, GetDateTimeIntervals -from stars.visualization.utils.PaintCollection import DrawLines +from stars.visualization.utils.PaintCollection import DrawLines from stars.visualization.SpaceTimeQueryDialog import SpaceTimeQueryDialog from stars.visualization.maps.ClassifyMap import ClassifyMapFactory @@ -24,58 +24,59 @@ class TrendGraph(PlottingCanvas): """ def __init__(self,parent, layer, trend_data, **kwargs): PlottingCanvas.__init__(self,parent,trend_data) - + try: self.start_date,self.end_date = kwargs["start"],kwargs["end"] self.step, self.step_by = kwargs["step"] ,kwargs["step_by"] - + self.margin_right = 70 - self.margin_left =100 + self.margin_left =100 self.margin_bottom = 140 self.enable_axis = False self.enable_axis_x = False self.enable_axis_y = False - - self.layer_name = layer.name + + self.layer_name = layer.name self.layer = layer self.data = trend_data self.n = len(self.data) all_values = self.data.values() self.t = len(all_values[0]) self.datetime_intervals, self.interval_labels = GetDateTimeIntervals(self.start_date, self.end_date,self.t, self.step, self.step_by) - - self.title = "%s %s" % (self.layer_name,kwargs["title"]) + + ttl = "" if "title" not in kwargs else kwargs["title"] + self.title = "%s %s" % (self.layer_name,ttl) self.x_label = "" self.y_label = "Number of observations" - + self.x_min = 1 - self.x_max = len(all_values[0]) + self.x_max = len(all_values[0]) self.x_max = self.x_max if self.x_max > self.x_min else self.x_max*1.5 - + all_values = np.array(all_values) self.y_min = np.min(all_values) self.y_min = self.y_min if self.y_min > 0 else 0 self.y_max = np.max(all_values) - + self.local_paths = [] - + self.extent = (self.x_min, self.y_min, self.x_max,self.y_max) self.selected_path_ids = [] self.status_bar = self.parentFrame.status_bar - + """ self.sum_data = np.sum(all_values,axis=1) factory = ClassifyMapFactory(self.sum_data, k=5) classify_results = factory.createClassifyMap(stars.MAP_CLASSIFY_QUANTILES) self.id_group, self.label_group, self.color_group = classify_results """ - + except Exception as err: self.ShowMsgBox("Trend graph could not be created. " + str(err.message)) self.isValidPlot = False self.parentFrame.Close(True) return None - + # linking-brushing events self.Register(stars.EVT_OBJS_SELECT, self.OnPathsSelected) self.Register(stars.EVT_OBJS_UNSELECT, self.OnNoPathSelect) @@ -84,10 +85,10 @@ def OnClose(self,event): self.Unregister(stars.EVT_OBJS_SELECT, self.OnPathsSelected) self.Unregister(stars.EVT_OBJS_UNSELECT, self.OnNoPathSelect) event.Skip() - + def DoDraw(self,dc): super(TrendGraph, self).DoDraw(dc) - + # draw y axis at each time interval y_axis_font_size = stars.TRENDGRAPH_Y_AXIS_FONT_SIZE dc.SetFont(wx.Font(y_axis_font_size,wx.NORMAL,wx.NORMAL,wx.NORMAL)) @@ -97,60 +98,60 @@ def DoDraw(self,dc): else: self.enable_axis_labels = False self.draw_axis_y(dc, start_x=i, isRotate=False) - + def test_line_at_rect_liang(self, line_seg, rect): t_min = 0 t_max = 1 - + x1,y1 = line_seg[0] x2,y2 = line_seg[1] - + left,upper = rect[0] right,bottom = rect[1] - + if max(x1,x2) < left or min(x1,x2) > right or max(y1,y2) < bottom or min(y1,y2) > upper: return False - + dx = float(x2-x1) dy = float(y2-y1) - + P1 = -dx q1 = x1 - left r1 = q1 / P1 - + P2 = dx q2 = right - x1 r2 = q2/P2 - + P3 = -dy q3 = y1- bottom r3 = q3/P3 - + P4 = dy q4 = upper - y1 r4 = q4/P4 - + P_set = (P1, P2, P3, P4) r_set = (r1, r2, r3, r4) - + t1_set = [0] t2_set = [1] - + for i in range(4): if P_set[i] < 0: t1_set.append(r_set[i]) if P_set[i] > 0: t2_set.append(r_set[i]) - + t1 = max(t1_set) t2 = min(t2_set) - + return t1 < t2 - + def plot_data(self,dc): y_ticks = self.yAxisScale.GetNiceTicks() - + # draw verticle time lines at background dc.SetFont(wx.Font(10,wx.NORMAL,wx.NORMAL,wx.NORMAL)) j = 0 @@ -163,21 +164,21 @@ def plot_data(self,dc): lbl_w,lbl_h = dc.GetTextExtent(lbl) #dc.DrawText(lbl, vtl_end_x - lbl_w/2.0, vtl_start_y+8) dc.DrawRotatedText(lbl, vtl_start_x - lbl_w/1.414, vtl_start_y+lbl_w/1.414+4,45) - + x_label = "Time Interval" x_lbl_w, x_lbl_h = dc.GetTextExtent(x_label) center_x = max(self.margin_left + self.ax_width/2.0 - x_lbl_w/2.0, self.margin_left) dc.DrawText(x_label, center_x, self.bufferHeight - x_lbl_h - 8) - + # plots data pen = wx.BLACK_PEN pen.SetStyle(wx.SOLID) dc.SetPen(pen) - + paths = [] self.local_paths = [] self.seg_dict = {} - + for key in self.data.keys(): item = self.data[key] path = [] @@ -186,7 +187,7 @@ def plot_data(self,dc): x0, x1 = i +1, i+2 y0, y1 = item[i], item[i+1] seg = ((x0,y0),(x1,y1)) - + if seg in self.seg_dict: path.append(self.seg_dict[seg]) else: @@ -196,11 +197,11 @@ def plot_data(self,dc): x1,y1 = self.transform_coord_pt(x1,y1) path.append((x0,y0,x1,y1)) self.seg_dict[seg] = (x0,y0,x1,y1) - + local_path.append(seg) paths.append(path) - self.local_paths.append([local_path,min(item),max(item)]) - """ + self.local_paths.append([local_path,min(item),max(item)]) + """ DrawLines(dc,paths, data_group=self.id_group, fill_color_group=self.color_group, @@ -208,7 +209,7 @@ def plot_data(self,dc): opaque=255) """ DrawLines(dc, paths) - + def draw_selected(self,dc): dc = wx.GCDC(dc) if len(self.selected_path_ids) > 0: @@ -220,30 +221,30 @@ def draw_selected(self,dc): y0, y1 = item[i], item[i+1] seg = ((x0,y0),(x1,y1)) path.append(self.seg_dict[seg]) - DrawLines(dc,[path], edge_color=wx.RED,edge_thickness=2) - + DrawLines(dc,[path], edge_color=wx.RED,edge_thickness=2) + def display_xy_on_status(self,x,y): if self.status_bar and self.view: # display current lat/lot on status bar x,y = self.view.pan_to(x,y,-self.margin_left,-self.margin_top) w_y,w_x = self.view.pixel_to_view(x,y) self.status_bar.SetStatusText("%.4f,%.4f"%(w_x,w_y)) - + def screen_to_plot(self,x,y): x,y = self.view.pan_to(x,y,-self.margin_left,-self.margin_top) w_x,w_y = self.view.pixel_to_view(x,y) return w_x,w_y - + def draw_selected_by_region(self, dc,select_region, isScreenCoordinates=True): """ - this function highlight the lines selected + this function highlight the lines selected by mouse drawing a region """ self.selected_path_ids = [] x0,y0,x1,y1= select_region x0,y0 = self.screen_to_plot(x0,y0) x1,y1 = self.screen_to_plot(x1,y1) - + if x0==x1 and y0==y1: # test point and path pass @@ -252,7 +253,7 @@ def draw_selected_by_region(self, dc,select_region, isScreenCoordinates=True): query_min_y = min(y0,y1) query_max_y = max(y0,y1) query_rect = [(x0,y0),(x1,y1)] - + for i, local_path in enumerate(self.local_paths): # try simple test first segs, p_ymin,p_ymax = local_path @@ -264,10 +265,10 @@ def draw_selected_by_region(self, dc,select_region, isScreenCoordinates=True): if self.test_line_at_rect_liang(seg, query_rect): self.selected_path_ids.append(i) break - + self.draw_selected(dc) #self.reInitBuffer = True - + if len(self.selected_path_ids)>0: # draw selected # tell this action to THE OBSERVER @@ -279,19 +280,19 @@ def draw_selected_by_region(self, dc,select_region, isScreenCoordinates=True): # tell this action to THE OBSERVER data = AbstractData(self) self.UpdateEvt(stars.EVT_OBJS_UNSELECT,data) - + def OnPathsSelected(self,event): """ Event handler for EVT_OBJ_SELECT. Observer will call this function when any other widgets/panels dispatch EVT_OBJ_SELECT event - + event is an instance of EventHandler.Event class event.object are the data for selecting shape objects """ - if not event: + if not event: return - + data = event.data if len(data.shape_ids) > 0 and self.layer_name in data.shape_ids: # directly select by shape_ids @@ -300,25 +301,25 @@ def OnPathsSelected(self,event): tmp_dc = wx.BufferedDC(None, tmp_buffer) background_buffer = self.drawing_backup_buffer if self.drawing_backup_buffer else self.buffer tmp_dc.DrawBitmap(background_buffer,0,0) # draw map as background first - + self.selected_path_ids = data.shape_ids[self.layer_name] self.draw_selected(tmp_dc) # exchange buffer self.buffer = tmp_buffer self.Refresh(False) - + def OnNoPathSelect(self, event): """ Event handler for EVT_OBJ_SELECT. Observer will call this function when any other widgets/panels dispatch EVT_OBJ_SELECT event - + Normally, event could be None, you just need to clean and refresh you selected/highlighted """ self.selected_path_ids = [] self.buffer = self.drawing_backup_buffer - self.Refresh(False) + self.Refresh(False) #self.reInitBuffer = True class TrendGraphQueryDialog(SpaceTimeQueryDialog): @@ -329,29 +330,29 @@ def OnQuery(self,event): if self._check_space_input() == False or\ self._check_time_itv_input() == False: return - + self.current_selected = range(self.dbf.n_records) self._filter_by_query_field() # query_date is not available in Trend Graph case - self.query_date = None + self.query_date = None self._filter_by_date_interval() self._filter_by_tod() - + self.query_data = self.gen_date_by_step() - + if self.query_data== None: self.ShowMsgBox("Querying dynamic data by time step could not be completed. Please respecify input parameters.") return - + background_shp, trend_data_dict = self.query_data - + queryfield = "" if self.query_field_idx < 0 else self.query_field queryrange = "" if self.query_range == None else "" - + title = "" if self.query_field.lower() != "all fields": title = "(%s:%s)"%(self.query_field,self.query_range) - + trendgraph_widget= PlotWidget( self.parent, background_shp, @@ -366,17 +367,17 @@ def OnQuery(self,event): title=title ) trendgraph_widget.Show() - + self.btn_save.Enable(True) - + def OnSaveQueryToDBF(self, event): try: if self.query_data == None: return dlg = wx.FileDialog( - self, message="Save query into a dbf file...", defaultDir=os.getcwd(), - defaultFile='%s.dbf' % (self.points_data.name + '_trendgraph'), - wildcard="dbf file (*.dbf)|*.dbf|All files (*.*)|*.*", + self, message="Save query into a dbf file...", defaultDir=os.getcwd(), + defaultFile='%s.dbf' % (self.points_data.name + '_trendgraph'), + wildcard="dbf file (*.dbf)|*.dbf|All files (*.*)|*.*", style=wx.SAVE) if dlg.ShowModal() != wx.ID_OK: dlg.Destroy() @@ -384,7 +385,7 @@ def OnSaveQueryToDBF(self, event): path = dlg.GetPath() dlg.Destroy() dbf = self.background_shps[0].dbf - + n_new_fields = len(self.query_data[1].values()[0]) field_names = [] for item in dbf.header: @@ -397,12 +398,12 @@ def OnSaveQueryToDBF(self, event): for i in range(n_new_fields): field_name = "TIME_PERIOD" +"_"+ str(i+1) field_names.append(field_name) - + try: os.remove(path) except: pass - + newDBF= pysal.open(path,'w') newDBF.header = [] newDBF.field_spec = [] @@ -410,11 +411,11 @@ def OnSaveQueryToDBF(self, event): newDBF.header.append(i) for i in dbf.field_spec: newDBF.field_spec.append(i) - + for field_name in field_names: newDBF.header.append(field_name) newDBF.field_spec.append(('N',4,0)) - + rows = [] for i in range(dbf.n_records): rows.append(dbf.read_record(i)) @@ -422,18 +423,16 @@ def OnSaveQueryToDBF(self, event): vals = self.query_data[1][key] for val in vals: rows[key].append(val) - for row in rows: + for row in rows: newDBF.write(row) newDBF.close() - + self.ShowMsgBox("Query results have been saved to new dbf file successfully.", mtype='CAST Information', micon=wx.ICON_INFORMATION) except: - self.ShowMsgBox("Saving query results to new dbf file failed.") - + self.ShowMsgBox("Saving query results to new dbf file failed.") + def OnReset(self,event): self.reset() self.cmbox_location.SetSelection(-1) - -