Ejemplo n.º 1
0
 def create_polygon(self, poly, rgb_color, **kwargs):
     p = Polygon(poly,
                 closed=True,
                 fc=rgb2mpl(rgb_color),
                 ec='black',
                 **kwargs)
     p.set_linewidth(self.linewidth)
     return p
 def __add_xy_values_as_polygon__(self, xy: list, color: str, closed=False, fill=False, alpha=0.2, line_width=2):
     xy = PlotterInterface.get_xy_from_timestamp_to_date_number(xy)
     polygon = Polygon(np.array(xy), closed=closed, fill=fill)
     polygon.set_visible(True)
     polygon.set_color(color)
     polygon.set_alpha(alpha)
     polygon.set_linewidth(line_width)
     self.axes_for_candlesticks.add_patch(polygon)
Ejemplo n.º 3
0
 def __init__(self, xy, closed=True, plotview=None, **opts):
     shape = Polygon(xy, closed, **opts)
     if 'linewidth' not in opts:
         shape.set_linewidth(1.0)
     if 'facecolor' not in opts:
         shape.set_facecolor('r')
     super(NXpolygon, self).__init__(shape, resize=False, plotview=plotview)
     self.shape.set_label('Polygon')
     self.polygon = self.shape
Ejemplo n.º 4
0
 def __init__(self, xy, closed=True, plotview=None, **opts):
     shape = Polygon(xy, closed, **opts)
     if 'linewidth' not in opts:
         shape.set_linewidth(1.0)
     if 'facecolor' not in opts:
         shape.set_facecolor('r')
     super(NXpolygon, self).__init__(shape, resize=False, plotview=plotview)
     self.shape.set_label('Polygon')
     self.polygon = self.shape
Ejemplo n.º 5
0
def BoxDraw(box):
    import matplotlib
    from matplotlib.patches import Polygon
    ax = matplotlib.pyplot.subplot(111, aspect='equal')
    rect = Polygon([[box[0], box[2]], [box[1], box[2]], [box[1], box[3]],
                    [box[0], box[3]]])
    rect.set_fill(False)
    rect.set_linewidth(2)
    ax.add_patch(rect)
Ejemplo n.º 6
0
 def create_polygon(self, poly, **kwargs):
     rgb_color = kwargs.pop('fill_color')
     p = Polygon(poly,
                 closed=True,
                 fc=rgb2mpl(rgb_color),
                 ec='black',
                 **kwargs)
     p.set_linewidth(self.linewidth)
     return p
 def __plot_single_fibonacci_wave__(self, fib_wave: FibonacciWave, color: str, suffix: str = ''):
     if self.sys_config.config.fibonacci_detail_print:
         fib_wave.print(suffix)
     xy = fib_wave.get_xy_parameter()
     xy = PlotterInterface.get_xy_from_timestamp_to_date_number(xy)
     fib_polygon = Polygon(np.array(xy), closed=False, fill=False)
     fib_polygon.set_visible(True)
     fib_polygon.set_color(color)
     fib_polygon.set_linewidth(1)
     self.axes_for_candlesticks.add_patch(fib_polygon)
     fib_wave_patch = FibonacciWavePatch(fib_wave, fib_polygon)
     self.fibonacci_patch_container.add_patch(fib_wave_patch)
     fib_wave_patch.add_retracement_patch_list_to_axis(self.axes_for_candlesticks)
 def __add_to_ranges_polygon_dic__(self, polygon: Polygon, for_main: bool, range: PatternRange):
     polygon.set_visible(False)
     polygon.set_color('r' if for_main else 'k')
     polygon.set_linewidth(1)
     self.axes_for_candlesticks.add_patch(polygon)
     for ticks in range.tick_list:
         if for_main:
             if ticks.f_var not in self.ranges_polygon_dic_list:
                 self.ranges_polygon_dic_list[ticks.f_var] = [polygon]
             else:
                 self.ranges_polygon_dic_list[ticks.f_var].append(polygon)
         else:
             if ticks.f_var not in self.ranges_opposite_polygon_dic_list:
                 self.ranges_opposite_polygon_dic_list[ticks.f_var] = [polygon]
             else:
                 self.ranges_opposite_polygon_dic_list[ticks.f_var].append(polygon)
class BrainLabelingGUI(QMainWindow, Ui_BrainLabelingGui):
	def __init__(self, parent=None, parent_labeling_name=None, stack=None, section=None):
		"""
		Initialization of BrainLabelingGUI.
		"""

		self.params_dir = '../params'

		# self.app = QApplication(sys.argv)
		QMainWindow.__init__(self, parent)

		self.parent_labeling_name = parent_labeling_name

		self.dm = DataManager(data_dir=os.environ['LOCAL_DATA_DIR'], 
			repo_dir=os.environ['LOCAL_REPO_DIR'], 
			result_dir=os.environ['LOCAL_RESULT_DIR'], 
			labeling_dir=os.environ['LOCAL_LABELING_DIR'])

		self.gabor_params_id='blueNisslWide'
		self.segm_params_id='blueNisslRegular'
		self.vq_params_id='blueNissl'

		self.dm.set_gabor_params(gabor_params_id=self.gabor_params_id)
		self.dm.set_segmentation_params(segm_params_id=self.segm_params_id)
		self.dm.set_vq_params(vq_params_id=self.vq_params_id)

		if (stack is None or section is None) and self.parent_labeling_name is not None:
			stack, section_str, user, timestamp = self.parent_labeling_name[:-4].split('_')
			section = int(section_str)

		self.dm.set_image(stack, 'x5', section)

		self.is_placing_vertices = False
		self.curr_polygon_vertices = []
		self.polygon_list = []
		self.polygon_labels = []
		self.vertex_list = []
		self.highlight_polygon = None

		self.segm_transparent = None
		self.under_img = None
		self.textonmap_vis = None
		self.dirmap_vis = None

		self.debug_mode = False

		self.load_labeling()

		# self.data_manager.close()
		self.initialize_brain_labeling_gui()

	def paramSettings_clicked(self):
		pass
        # self.paramsForm = ParamSettingsForm()
        # self.paramsForm.show()

        # self.gabor_params_id='blueNisslWide'
        # self.segm_params_id='blueNisslRegular'
        # self.vq_params_id='blueNissl'

	def load_labeling(self):

		# self.masked_img = self.dm.image_rgb.copy()
		self.masked_img = gray2rgb(self.dm.image)
		# self.masked_img[~self.dm.mask, :] = 0

		if self.parent_labeling_name is None:

			print 'No labeling is given. Initialize labeling.'

			self.parent_labeling = None

			self.labeling = {
				'username' : None,
				'parent_labeling_name' : None,
				'login_time' : datetime.datetime.now().strftime("%m%d%Y%H%M%S"),
				'initial_polygons': None,
				'final_polygons': None,
				# 'init_label_circles' : [],
				# 'final_label_circles' : None,
				# 'labelnames' : self.dm.labelnames,
				'labelnames' : [],  # will be filled by _add_buttons()
			}

			# labelnames not including -1 ("no label")
			# labelnames_fn = os.path.join(self.dm.labelings_dir, 'labelnames.txt')
			# if os.path.isfile(labelnames_fn) and not IGNORE_EXISTING_LABELNAMES:
			# 	with open(labelnames_fn, 'r') as f:
			# 		labelnames = f.readlines()
				# labelnames = json.load(open(labelnames_fn, 'r'))
			# self.labeling['labelnames'] = 
			# else:
			# 	# n_models = 10
			# 	n_models = 0
		else:

			self.parent_labeling = self.dm.load_labeling(self.parent_labeling_name)

			print 'Load saved labeling'
			
			# label_circles = parent_labeling['final_label_circles']

			self.labeling = {
				'username' : None,
				'parent_labeling_name' : self.parent_labeling_name,
				'login_time' : datetime.datetime.now().strftime("%m%d%Y%H%M%S"),
				'initial_polygons': self.parent_labeling['final_polygons'],
				'final_polygons': None,
				# 'init_label_circles' : label_circles,
				# 'final_label_circles' : None,
				'labelnames' : [],  # will be filled by _add_buttons()
			}
		
		# self.n_labels = len(self.labeling['labelnames'])

		# initialize GUI variables
		self.paint_label = -1        # color of pen
		self.pick_mode = False       # True while you hold ctrl; used to pick a color from the image
		self.press = False           # related to pan (press and drag) vs. select (click)
		self.base_scale = 1.2       # multiplication factor for zoom using scroll wheel
		self.moved = False           # indicates whether mouse has moved while left button is pressed


	def openMenu(self, canvas_pos):

		# if self.seg_enabled:
		# 	self.growRegion_Action.setEnabled(True)
		# 	seed_sp = self.segmentation[int(canvas_pos[1]), int(canvas_pos[0])]
		# else:
		# 	self.growRegion_Action.setEnabled(False)

		self.endDraw_Action.setVisible(self.is_placing_vertices)
		self.deletePolygon_Action.setVisible(not self.is_placing_vertices)

		pos = self.cursor().pos()

		action = self.menu.exec_(pos)
		
		# if action == self.growRegion_Action:
					
		# 	self.statusBar().showMessage('Grow region from superpixel %d' % seed_sp )
		# 	self.curr_label = self.sp_labellist[seed_sp]
		# 	for sp in self.cluster_sps[seed_sp]:
		# 		self.paint_superpixel(sp)

		# elif action == self.pickColor_Action:

		# 	self.pick_color(self.sp_labellist[seed_sp])

		# elif action == self.eraseColor_Action:

		# 	self.pick_color(-1)
		# 	self.paint_superpixel(seed_sp)

		# elif action == self.eraseAllSpsCurrColor_Action:

		# 	self.pick_color(-1)
		# 	for sp in self.cluster_sps[seed_sp]:
		# 		self.paint_superpixel(sp)

		# elif action == self.endDraw_Action:
		if action == self.endDraw_Action:

			self.is_placing_vertices = False

			polygon = Polygon(self.curr_polygon_vertices, closed=True, fill=False,
									edgecolor=self.colors[self.curr_label + 1], linewidth=2)
			self.axes.add_patch(polygon)
			self.polygon_list.append(polygon)
			self.polygon_labels.append(self.curr_label)

			self.curr_polygon_vertices = []

			for v in self.vertex_list:
				v.remove()
			self.vertex_list = []

			self.statusBar().showMessage('Done labeling region using label %d (%s)' % (self.curr_label,
											self.labeling['labelnames'][self.curr_label]))


		elif action == self.endDrawOpen_Action:

			self.is_placing_vertices = False

			polygon = Polygon(self.curr_polygon_vertices, closed=False, fill=False,
									edgecolor=self.colors[self.curr_label + 1], linewidth=2)
			self.axes.add_patch(polygon)
			self.polygon_list.append(polygon)
			self.polygon_labels.append(self.curr_label)

			self.curr_polygon_vertices = []

			for v in self.vertex_list:
				v.remove()
			self.vertex_list = []

			self.statusBar().showMessage('Done labeling region using label %d (%s)' % (self.curr_label,
											self.labeling['labelnames'][self.curr_label]))


		elif action == self.deletePolygon_Action:

			polygon_index = self.polygon_list.index(self.selected_polygon)
			self.selected_polygon.remove()
			del self.polygon_list[polygon_index]
			del self.polygon_labels[polygon_index]
			self.remove_highlight_polygon()

		elif action == self.crossReference_Action:
			self.parent().refresh_data()
			self.parent().comboBoxBrowseMode.setCurrentIndex(self.curr_label + 1)
			self.parent().set_labelnameFilter(self.curr_label)
			self.parent().switch_to_labeling()

	def initialize_brain_labeling_gui(self):

		self.menu = QMenu()
		# self.growRegion_Action = self.menu.addAction("Label similar neighbors")
		# self.pickColor_Action = self.menu.addAction("Pick this label")
		# self.eraseColor_Action = self.menu.addAction("Remove label of this superpixel")
		# self.eraseAllSpsCurrColor_Action = self.menu.addAction("Clear similar neighbors")
		self.endDraw_Action = self.menu.addAction("End drawing region")
		self.endDrawOpen_Action = self.menu.addAction("End drawing open boundary")
		self.deletePolygon_Action = self.menu.addAction("Delete polygon")
		self.crossReference_Action = self.menu.addAction("Cross reference")

		# A set of high-contrast colors proposed by Green-Armytage
		self.colors = np.loadtxt('100colors.txt', skiprows=1)
		self.label_cmap = ListedColormap(self.colors, name='label_cmap')

		self.curr_label = -1

		self.setupUi(self)

		self.fig = self.canvaswidget.fig
		self.canvas = self.canvaswidget.canvas

		self.canvas.mpl_connect('scroll_event', self.zoom_fun)
		self.bpe_id = self.canvas.mpl_connect('button_press_event', self.press_fun)
		self.bre_id = self.canvas.mpl_connect('button_release_event', self.release_fun)
		self.canvas.mpl_connect('motion_notify_event', self.motion_fun)

		# self.canvas.customContextMenuRequested.connect(self.openMenu)

		# self.display_buttons = [self.img_radioButton, self.imgSeg_radioButton, self.textonmap_radioButton, self.dirmap_radioButton, self.labeling_radioButton]
		self.display_buttons = [self.img_radioButton, self.textonmap_radioButton, self.dirmap_radioButton, self.labeling_radioButton]
		self.img_radioButton.setChecked(True)
		self.seg_enabled = False
		self.seg_loaded = False
		self.groups_loaded = False

		for b in self.display_buttons:
			b.toggled.connect(self.display_option_changed)

		self.spOnOffSlider.valueChanged.connect(self.display_option_changed)

		self.set_debug_mode()

		########## Label buttons #############

		self.n_labelbuttons = 0
		
		self.labelbuttons = []
		self.labeledits = []

		if self.parent_labeling is not None:
			for n in self.parent_labeling['labelnames']:
				self._add_labelbutton(desc=n)
		else:
			for n in self.dm.labelnames:
				self._add_labelbutton(desc=n)

		# self.loadButton.clicked.connect(self.load_callback)
		self.saveButton.clicked.connect(self.save_callback)
		self.newLabelButton.clicked.connect(self.newlabel_callback)
		# self.newLabelButton.clicked.connect(self.sigboost_callback)
		self.quitButton.clicked.connect(self.close)
		self.buttonParams.clicked.connect(self.paramSettings_clicked)
		self.buttonDebugMode.clicked.connect(self.debugMode_toggled)


		# self.brushSizeSlider.valueChanged.connect(self.brushSizeSlider_valueChanged)
		# self.brushSizeEdit.setText('%d' % self.brushSizeSlider.value())

		# help_message = 'Usage: right click to pick a color; left click to assign color to a superpixel; scroll to zoom, drag to move'
		# self.setWindowTitle('%s' %(help_message))

		self.setWindowTitle(self.windowTitle() + ', parent_labeling = %s' %(self.parent_labeling_name))

		# self.statusBar().showMessage()       

		self.fig.clear()
		self.fig.set_facecolor('white')

		self.axes = self.fig.add_subplot(111)
		self.axes.axis('off')

		self.axes.imshow(self.masked_img, cmap=plt.cm.Greys_r,aspect='equal')
		
		# labelmap_vis = label2rgb(self.labelmap, image=self.img, colors=self.colors, alpha=0.3, image_alpha=1)
		# self.axes.imshow(labelmap_vis)

		# self.circle_list = [plt.Circle((x,y), radius=r, color=self.colors[l+1], alpha=.3) for x,y,r,l in self.labeling['init_label_circles']]
		# self.labelmap = self.generate_labelmap(self.circle_list)

		if self.labeling['initial_polygons'] is not None:
			for l, xys_percent in self.labeling['initial_polygons']:
				p = Polygon(xys_percent * np.array([self.dm.image_width, self.dm.image_height])[np.newaxis,:],
									closed=True, fill=False, edgecolor=self.colors[l + 1], linewidth=2)
				self.polygon_list.append(p)
				self.polygon_labels.append(l)
				self.axes.add_patch(p)

			self.labelmap = self.generate_labelmap(self.polygon_list, self.polygon_labels)

		self.fig.subplots_adjust(left=0, bottom=0, right=1, top=1)

		self.newxmin, self.newxmax = self.axes.get_xlim()
		self.newymin, self.newymax = self.axes.get_ylim()

		self.canvas.draw()
		self.show()

	############################################
	# QT button CALLBACKs
	############################################

	# def growThreshSlider_valueChanged(self):
	# 	self.growThreshEdit.setText('%.2f' % (self.growThreshSlider.value()/100.))

	# def brushSizeSlider_valueChanged(self, new_val):
	# 	self.brushSizeEdit.setText('%d' % new_val)

	def set_debug_mode(self):
		if self.debug_mode:
			self.display_groupBox.show()
			self.buttonParams.show()
		else:
			self.display_groupBox.hide()
			self.buttonParams.hide()


	def debugMode_toggled(self):
		self.debug_mode = ~self.debug_mode
		self.set_debug_mode()

	def load_groups(self):

		self.groups = self.dm.load_pipeline_result('clusterGroups', 'pkl')

		self.groups_ranked, self.group_scores_ranked = zip(*self.groups)
		
		for i, g in enumerate(self.groups_ranked[:50]):
			self._add_labelbutton()
			self.pick_color(i)
			for sp in g:
				self.paint_superpixel(sp)

		self.groups_loaded = True

	def load_segmentation(self):

		self.segmentation = self.dm.load_pipeline_result('segmentation', 'npy')
		self.n_superpixels = len(np.unique(self.segmentation)) - 1

		self.sp_props = self.dm.load_pipeline_result('spProps', 'npy')
		
		self.sp_labellist = -1*np.ones((self.n_superpixels, ), dtype=np.int)
		self.sp_rectlist = [None for _ in range(self.n_superpixels)]

		# self.neighbors = self.dm.load_pipeline_result('neighbors', 'npy')
		# self.texton_hists = self.dm.load_pipeline_result('texHist', 'npy')
		# self.textonmap = self.dm.load_pipeline_result('texMap', 'npy')

		self.clusters = self.dm.load_pipeline_result('clusters', 'pkl')
		# self.cluster_sps, curr_cluster_score_sps, scores_sps, nulls_sps, models_sps, added_sps = zip(*self.clusters)
		self.cluster_sps, self.curr_cluster_score_sps = zip(*self.clusters)

		# self.n_texton = 100

		# from scipy.spatial.distance import cdist
		# overall_texton_hist = np.bincount(self.textonmap[self.mask].flat, minlength=self.n_texton)
		# self.overall_texton_hist_normalized = overall_texton_hist.astype(np.float) / overall_texton_hist.sum()
		# self.D_sp_null = np.squeeze(cdist(self.texton_hists, [self.overall_texton_hist_normalized], chi2))

		self.seg_loaded = True

	# def display_option_changed(self, checked):
	def display_option_changed(self):
		# if checked:

			# self.axes.clear()

		if self.sender() == self.spOnOffSlider:

			if self.spOnOffSlider.value() == 1:

				if self.segm_transparent is None:
					self.segm_transparent = self.dm.load_pipeline_result('segmentationTransparent', 'png')
					self.my_cmap = plt.cm.Reds
					self.my_cmap.set_under(color="white", alpha="0")

				# self.segm_handle = self.axes.imshow(self.segm_transparent, aspect='equal', 
				# 					cmap=self.my_cmap, alpha=1.)

				if not self.seg_loaded:
					self.load_segmentation()

				self.seg_enabled = True
			else:
				self.segm_handle.remove()
				self.seg_enabled = False

		# elif self.sender() == self.imgSeg_radioButton:

		# 	# self.seg_vis = self.dm.load_pipeline_result('segmentationWithText', 'jpg')
		# 	# self.seg_vis[~self.dm.mask] = 0

		# 	# self.axes.imshow(self.seg_vis, aspect='equal')

		# 	self.axes.imshow(self.masked_img, aspect='equal', cmap=plt.cm.Greys_r)
		# 	self.axes.imshow(self.segm_transparent, aspect='equal', cmap=my_red_cmap, alpha=1.)

		# 	if not self.seg_loaded:
		# 		self.load_segmentation()

		# 	self.seg_enabled = True

		else:
			# if self.under_img is not None:
			# 	self.under_img.remove()

			self.axes.clear()

			if self.sender() == self.img_radioButton:

				# self.axes.clear()
				# self.axes.axis('off')

				# self.under_img = self.axes.imshow(self.masked_img, aspect='equal', cmap=plt.cm.Greys_r)
				self.axes.imshow(self.masked_img, aspect='equal', cmap=plt.cm.Greys_r)
				# self.seg_enabled = False

			elif self.sender() == self.textonmap_radioButton:

				# self.axes.clear()
				# self.axes.axis('off')

				if self.textonmap_vis is None:
					self.textonmap_vis = self.dm.load_pipeline_result('texMap', 'png')

				# if self.under_img is not None:
				# 	self.under_img.remove()

				# self.under_img = self.axes.imshow(self.textonmap_vis, cmap=plt.cm.Greys_r, aspect='equal')
				self.axes.imshow(self.textonmap_vis, cmap=plt.cm.Greys_r, aspect='equal')
				# self.seg_enabled = False

			elif self.sender() == self.dirmap_radioButton:

				# self.axes.clear()
				# self.axes.axis('off')

				if self.dirmap_vis is None:
					self.dirmap_vis = self.dm.load_pipeline_result('dirMap', 'jpg')
					self.dirmap_vis[~self.dm.mask] = 0


				# self.under_img = self.axes.imshow(self.dirmap_vis, aspect='equal')
				self.axes.imshow(self.dirmap_vis, aspect='equal')

				# if not self.seg_loaded:
				# 	self.load_segmentation()

				# self.seg_enabled = False

			elif self.sender() == self.labeling_radioButton:


				self.axes.clear()
				self.axes.axis('off')

				if not self.seg_loaded:
					self.load_segmentation()

				# if not self.groups_loaded:
				# 	self.load_groups()
				# else:
				for rect in self.sp_rectlist:
					if rect is not None:
						self.axes.add_patch(rect)

				self.seg_vis = self.dm.load_pipeline_result('segmentationWithText', 'jpg')
				self.seg_vis[~self.dm.mask] = 0
				self.axes.imshow(self.seg_vis, aspect='equal')

			# self.seg_enabled = True

		if self.seg_enabled:
			self.segm_handle = self.axes.imshow(self.segm_transparent, aspect='equal', 
									cmap=self.my_cmap, alpha=1.)

			for i in range(len(self.sp_rectlist)):
				self.sp_rectlist[i] = None

		self.axes.axis('off')

		self.axes.set_xlim([self.newxmin, self.newxmax])
		self.axes.set_ylim([self.newymin, self.newymax])

		self.fig.subplots_adjust(left=0, bottom=0, right=1, top=1)
		self.canvas.draw()


	def _add_labelbutton(self, desc=None):
		self.n_labelbuttons += 1

		index = self.n_labelbuttons - 1

		row = (index) % 5
		col = (index) / 5

		btn = QPushButton('%d' % index, self)

		if desc is None:
			labelname = 'label %d'%index			
		else:
			labelname = desc

		edt = QLineEdit(QString(labelname))
		self.labeling['labelnames'].append(labelname)

		self.labelbuttons.append(btn)
		self.labeledits.append(edt)

		btn.clicked.connect(self.labelbutton_callback)
		edt.editingFinished.connect(self.labelNameChanged)

		r, g, b, a = self.label_cmap(index + 1)

		btn.setStyleSheet("background-color: rgb(%d, %d, %d)"%(int(r*255),int(g*255),int(b*255)))
		btn.setFixedSize(20, 20)

		self.labelsLayout.addWidget(btn, row, 2*col)
		self.labelsLayout.addWidget(edt, row, 2*col+1)

	def newlabel_callback(self):
		# self.n_labels += 1
		self._add_labelbutton()

	# def sigboost_callback(self):
	# 	self._save_labeling()

	# def load_callback(self):
	# 	self.initialize_data_manager()

	def labelNameChanged(self):
		edt = self.sender()
		ind_onscreen = self.labeledits.index(edt) # the first one is "no label"
		self.labeling['labelnames'][ind_onscreen] = str(edt.text())


	def _save_labeling(self, ):

		username, ok = QInputDialog.getText(self, "Username", 
							"Please enter your username:"******"%m%d%Y%H%M%S")
		# self.labeling['labelnames'] = [str(edt.text()).strip() for edt in self.labeledits[1:]]

		# labelnames_fn = os.path.join(self.data_dir, 'labelnames.json')

		new_labeling_name = self.username + '_' + self.labeling['logout_time']

		# new_labeling_fn = os.path.join(self.dm.labelings_dir, self.dm.image_name + '_' + new_labeling_name + '.pkl')
		# pickle.dump(self.labeling, open(new_labeling_fn, 'w'))
		# print 'Labeling saved to', new_labeling_fn

		# self.labelmap = self.generate_labelmap(self.circle_list)

		# self.labelmap = self.generate_labelmap(self.circle_list)
		# labelmap_vis = self.colors[self.labelmap]

		self.labelmap = self.generate_labelmap(self.polygon_list, self.polygon_labels)

		labelmap_vis = label2rgb(self.labelmap, image=self.masked_img, colors=self.colors[1:], 
						bg_label=-1, bg_color=(1,1,1), alpha=0.3, image_alpha=1.)

		new_labeling_fn = self.dm.save_labeling(self.labeling, new_labeling_name, labelmap_vis)


		print 'Curr labelnames', self.labeling['labelnames']

		new_labelnames = []
		q = [n.lower() for n in self.dm.labelnames]
		for n in self.labeling['labelnames']:
			if n.lower() not in q:
				new_labelnames.append(n)

		print 'Global Labelnames', self.dm.labelnames + new_labelnames

		self.dm.set_labelnames(self.dm.labelnames + new_labelnames)
		
		self.statusBar().showMessage('Labeling saved to %s' % new_labeling_fn )


	def save_callback(self):
		self._save_labeling()

	def labelbutton_callback(self):
		self.statusBar().showMessage('Left click to select vertices')
		self.is_placing_vertices = True
		self.pick_color(int(self.sender().text()))

	############################################
	# matplotlib canvas CALLBACKs
	############################################

	def zoom_fun(self, event):
		# get the current x and y limits and subplot position
		cur_pos = self.axes.get_position()
		cur_xlim = self.axes.get_xlim()
		cur_ylim = self.axes.get_ylim()
		
		xdata = event.xdata # get event x location
		ydata = event.ydata # get event y location

		if xdata is None or ydata is None: # mouse position outside data region
			return

		left = xdata - cur_xlim[0]
		right = cur_xlim[1] - xdata
		up = ydata - cur_ylim[0]
		down = cur_ylim[1] - ydata

		# print left, right, up, down

		if event.button == 'up':
			# deal with zoom in
			scale_factor = 1/self.base_scale
		elif event.button == 'down':
			# deal with zoom out
			scale_factor = self.base_scale
		
		self.newxmin = xdata - left*scale_factor
		self.newxmax = xdata + right*scale_factor
		self.newymin = ydata - up*scale_factor
		self.newymax = ydata + down*scale_factor

		# set new limits

		# inv = self.axes.transData.inverted()
		# lb_disp = inv.transform([self.newxmin, self.newymin])
		# rt_disp = inv.transform([self.newxmax, self.newymax])
		# print lb_disp, rt_disp

		self.axes.set_xlim([self.newxmin, self.newxmax])
		self.axes.set_ylim([self.newymin, self.newymax])

		self.canvas.draw() # force re-draw

	def press_fun(self, event):
		self.press_x = event.xdata
		self.press_y = event.ydata
		self.press = True
		self.press_time = time.time()

	def motion_fun(self, event):
			
		if self.press and time.time() - self.press_time > .5:
			# this is drag and move
			cur_xlim = self.axes.get_xlim()
			cur_ylim = self.axes.get_ylim()
			
			if (event.xdata==None) | (event.ydata==None):
				#print 'either event.xdata or event.ydata is None'
				return

			offset_x = self.press_x - event.xdata
			offset_y = self.press_y - event.ydata
			
			self.axes.set_xlim(cur_xlim + offset_x)
			self.axes.set_ylim(cur_ylim + offset_y)
			self.canvas.draw()


	def remove_highlight_polygon(self):
		# Remove the highlight polygon if it exists
		if self.highlight_polygon is not None:
			self.highlight_polygon.remove()
			self.highlight_polygon = None

	def draw_highlight_polygon(self, event):

		if not self.is_placing_vertices:
			# Check if the click is within a polygon. If so, 
			# construct the hightlight polygon over the selected polygon
			containing_polygons = []
			for i, (p,l) in enumerate(zip(self.polygon_list, self.polygon_labels)):
				contains, attrd = p.contains(event)
				if contains:
					containing_polygons.append((p,l))

			if len(containing_polygons) > 0:
				selected_polygon, selected_polygon_label = containing_polygons[0]

				self.selected_polygon = selected_polygon
				self.seletced_polygon_label = selected_polygon_label
				self.statusBar().showMessage('Polygon (%s) is selected' %
					self.labeling['labelnames'][self.seletced_polygon_label])
				
				self.highlight_polygon = Polygon(selected_polygon.get_xy())
				self.highlight_polygon.update_from(selected_polygon)
				self.highlight_polygon.set_linewidth(5)
				self.axes.add_patch(self.highlight_polygon)

				self.pick_color(self.seletced_polygon_label)


	def release_fun(self, event):
		"""
		The release-button callback is responsible for picking a color or changing a color.
		"""

		self.press = False
		self.release_x = event.xdata
		self.release_y = event.ydata
		self.release_time = time.time()

		# Fixed panning issues by using the time difference between the press and release event
		# Long times refer to a press and hold
		if (self.release_time - self.press_time) < .21 and self.release_x > 0 and self.release_y > 0:

			self.remove_highlight_polygon()
			self.draw_highlight_polygon(event)

			if event.button == 1: # left click: draw
				if self.curr_label is None:
					self.statusBar().showMessage('want to paint, but no label is selected')
				else:
					if self.seg_enabled:

						sp_ind = self.segmentation[int(event.ydata), int(event.xdata)]

						if sp_ind == -1:
							self.statusBar().showMessage('This is the background')
						else:
							self.statusBar().showMessage('Labeled superpixel %d using label %d (%s)' % (sp_ind, self.curr_label, self.labeling['labelnames'][self.curr_label]))
							# self.paint_superpixel(sp_ind)
							self.show_region(sp_ind)

					else:
						if self.is_placing_vertices:
							self.curr_polygon_vertices.append([event.xdata, event.ydata])

							vertex = plt.Circle((event.xdata, event.ydata), radius=10, 
											color=self.colors[self.curr_label + 1], alpha=.8)
							self.axes.add_patch(vertex)
							self.vertex_list.append(vertex)

							self.statusBar().showMessage('... in the process of labeling region using label %d (%s)' % (self.curr_label, self.labeling['labelnames'][self.curr_label]))

			elif event.button == 3: # right click: erase
				canvas_pos = (event.xdata, event.ydata)
				self.openMenu(canvas_pos)


			#     self.statusBar().showMessage('Erase %d (%s)' % (self.curr_label, self.labeling['labelnames'][self.curr_label + 1]))
			#     self.erase_circles_near(event.xdata, event.ydata)

			
		self.canvas.draw() # force re-draw

	############################################
	# other functions
	############################################

	def pick_color(self, selected_label):

		self.curr_label = selected_label
		self.statusBar().showMessage('Picked label %d (%s)' % (self.curr_label, self.labeling['labelnames'][self.curr_label]))

	# def paint_circle(self, x, y):

	# 	if self.curr_label is None:
	# 		self.statusBar().showMessage('No label is selected')
	# 	else:
	# 		pass

			# brush_radius = self.brushSizeSlider.value()
			# circ = plt.Circle((x, y), radius=brush_radius, color=self.colors[self.curr_label + 1], alpha=.3)
			# self.axes.add_patch(circ)
			# self.circle_list.append(circ)

	# def erase_circles_near(self, x, y):
	# 	to_remove = []
	# 	for c in self.circle_list:
	# 		if abs(c.center[0] - x) < 30 and abs(c.center[1] - y) < 30:
	# 			to_remove.append(c)

	# 	for c in to_remove:
	# 		self.circle_list.remove(c)
	# 		c.remove()

	# def circle_list_to_labeling_field(self, circle_list):
	# 	label_circles = []
	# 	for c in circle_list:
	# 		label = np.where(np.all(self.colors == c.get_facecolor()[:3], axis=1))[0][0] - 1
	# 		label_circles.append((int(c.center[0]), int(c.center[1]), c.radius, label))
	# 	return label_circles


	def show_region(self, sp_ind):

		for i, r in enumerate(self.sp_rectlist):
			if r is not None:
				r.remove()
				self.sp_rectlist[i] = None

		for i in self.cluster_sps[sp_ind]:

			ymin, xmin, ymax, xmax = self.sp_props[i, 4:]
			width = xmax - xmin
			height = ymax - ymin

			rect = Rectangle((xmin, ymin), width, height, 
				ec="none", alpha=.3, color=self.colors[self.curr_label + 1])

			self.sp_rectlist[i] = rect
			self.axes.add_patch(rect)

		self.statusBar().showMessage('Sp %d, cluster score %.4f' % (sp_ind, self.curr_cluster_score_sps[sp_ind]))


	def paint_superpixel(self, sp_ind):

		if self.curr_label == self.sp_labellist[sp_ind]:

			self.statusBar().showMessage('Superpixel already has the selected label')

		elif self.curr_label != -1:

			self.sp_labellist[sp_ind] = self.curr_label
			# self.labelmap = self.sp_labellist[self.segmentation]

			### Removes previous color to prevent a blending of two or more patches ###
			if self.sp_rectlist[sp_ind] is not None:
				self.sp_rectlist[sp_ind].remove()

			# approximate the superpixel area with a square

			ymin, xmin, ymax, xmax = self.sp_props[sp_ind, 4:]
			width = xmax - xmin
			height = ymax - ymin

			rect = Rectangle((xmin, ymin), width, height, 
				ec="none", alpha=.3, color=self.colors[self.curr_label + 1])

			self.sp_rectlist[sp_ind] = rect
			self.axes.add_patch(rect)

		else:
			self.statusBar().showMessage("Remove label of superpixel %d" % sp_ind)
			self.sp_labellist[sp_ind] = -1

			self.sp_rectlist[sp_ind].remove()
			self.sp_rectlist[sp_ind] = None


	def generate_labelmap(self, polygon_list, polygon_labels):
		"""
		Generate labelmap from the list of polygons and the list of polygon labels
		"""

		labelmap_flat = -1 * np.ones((self.dm.image_height * self.dm.image_width, 1), dtype=np.int)

		X, Y = np.mgrid[0:self.dm.image_height, 0:self.dm.image_width]
		all_points = np.column_stack([Y.ravel(), X.ravel()]) # nx2
		for p, l in zip(self.polygon_list, self.polygon_labels):
			labelmap_flat[p.get_path().contains_points(all_points)] = l

		labelmap = labelmap_flat.reshape((self.dm.image_height, self.dm.image_width))

		# for c in zip(polygon_list):
		# 	cx, cy = c.center
		# 	for x in np.arange(cx-c.radius, cx+c.radius):
		# 		for y in np.arange(cy-c.radius, cy+c.radius):
		# 			if (cx-x)**2+(cy-y)**2 <= c.radius**2:
		# 				label = np.where(np.all(self.colors == c.get_facecolor()[:3], axis=1))[0][0] - 1
		# 				labelmap[int(y),int(x)] = label

		return labelmap
Ejemplo n.º 10
0
ax.axis("off")
titleax.axis("off")
m = Basemap(projection='eck4', lon_0=160, resolution='c', ax=ax)
m.drawcoastlines(linewidth=0, color="#FFFFFF")
m.drawmapboundary(color="aqua")
m.fillcontinents(color='#cccccc', lake_color='#FFFFFF')
# Read shapefile
m.readshapefile("data/ne_10m_admin_0_countries/ne_10m_admin_0_countries",
                "units",
                drawbounds=False)

patches = []
for info, shape in zip(m.units_info, m.units):
    poly = Polygon(np.array(shape), True)
    poly.set_facecolor('none')
    poly.set_linewidth(0)
    poly.set_edgecolor("#000000")
    poly.set_zorder(1)
    poly = ax.add_patch(poly)
    patches.append(poly)

x1, y1 = m(coords["lng"].values, coords["lat"].values)
_c = [scalarMap.to_rgba(groups.index(i)) for i in groups]
p = m.scatter(x1,
              y1,
              marker="o",
              alpha=1,
              color=_c,
              zorder=2,
              sizes=[0] * coords.shape[0])
lwidths = list(np.logspace(np.log(1), np.log(5), 300, base=np.e))
Ejemplo n.º 11
0



# for line in csvfile:
#     lon = (float(line[0]) + float(line[2]))/2 + float(line[5])
#     lat = (float(line[1]) + float(line[3]))/2 + float(line[6])
#     x, y = m(lon, lat)
#     name = line[4].replace('\\n', '\n')
#     plt.text(x, y, name, horizontalalignment='center', verticalalignment='center', fontsize=int(line[7]))

for lakepoly in m.lakepolygons:
    lp = Polygon(lakepoly.boundary, zorder=2)
    lp.set_facecolor('0.8')
    lp.set_edgecolor('0.8')
    lp.set_linewidth(0.1)
    ax.add_patch(lp)


# xx, yy = m(-72.0, 26.0)
# plt.text(xx, yy, u'Made by zhyuey', color='yellow')

# plt.title('Map of contiguous United States', fontsize=24)

# # plt.savefig('usa_state_75.png', dpi=75)
# # plt.savefig('usa_state_75.png', dpi=75)
# plt.savefig('usa_state_300.png', dpi=300)
# # plt.savefig('usa_state_600.png', dpi=600)

# m.drawcoastlines(linewidth=0.3)
# m.drawcountries(linewidth=0.3)
Ejemplo n.º 12
0
class Shape(object):
    """
    Displays the polygon objects onto the canvas by supplying draw methods
    and maintaining internal information on the shape. Draws to matplotlib
    backend
    """
    def __init__(self, canvas=None, tag='', color=''):
        self.__canvas = canvas
        self.__coordinates = []
        self.__tag = tag
        self.__color = color
        self.__item_handler = None
        self.__plot = Plot.baseplot
        self.__hdf = None
        self.__attributes = []
        self.__note = ''
        self.__id = None
        self.__prev_x = 1.0
        self.__prev_y = 1.0
        self.__lines = []
        self.__saved = False
        self.__selected = False
        self.__drawing_line = None  # temporary line for free draw

    def add_attribute(self, attr):
        """
        Append a passed attribute onto the internal attribute list

        :param str attr: An attribute enum
        """
        if attr in TAGS:
            self.__attributes.append(attr)
            self.__saved = False
        else:
            logger.error('Caught invalid attribute for adding \'%s\'' % attr)

    def anchor_rectangle(self, event):
        """
        Establishes a corner of a rectangle as an anchor for when the user drags the cursor to
        create a rectangle. Used in 'Draw Rect' button

        :param event: A matplotlib backend event object
        """
        self.__coordinates.append((event.xdata, event.ydata))
        self.__prev_x = event.x
        self.__prev_y = self.__canvas.figure.bbox.height - event.y

    def clear_lines(self):
        """
        Remove any existing lines and clear the shape data. This is called so the lines don't
        remain on the screen if the user unclicks the toggleable button.
        """
        for line in self.__lines:
            line.remove()

    def clear_unfinished_data(self):
        """
        In the event the user is plotting points and decides to switch
        buttons without finishing the free draw polygon, the lines must
        be cleared and data must be reset. this function will ensure
        any unfinished data is cleared for future shape drawing.
        """
        if self.__can_draw() != -1:
            return
        for line in self.__lines:
            line.remove()
        self.__coordinates = []

    def draw(self, fig, fl, plot=Plot.baseplot, fill=False):
        """
        Draw the shape to the canvas, onto the passed figure. Only fill the
        object if the *fill* parameter is set to ``True``

        :param fig: A ``SubplotAxes`` object from the matplotlib backend
        :param fl: A string representing the HDF path
        :param plot: ``constants.Plot`` enum specifying which plot the object belongs to
        :param bool fill: ``False`` for fill, ``True`` for outline
        """
        logger.info("Drawing polygon")

        # Generates a random color
        r = lambda: random.randint(0, 255)
        clr = '#%02X%02X%02X' % (r(), r(), r())

        self.__color = clr
        self.__plot = plot
        self.__hdf = fl
        self.__item_handler = \
            Polygon(self.__coordinates, facecolor=clr, fill=fill, picker=5)
        if self.__selected:
            self.set_highlight(True)
        fig.add_patch(self.__item_handler)

    def fill_rectangle(self, event, plot, fl, fig, fill=False):
        """
        Draws the rectangle and stores the coordinates of the rectangle internally. Used
        in 'Draw Rect' button. Forwards argument parameters to ``draw``

        :param fig: Figure to draw canvas to
        :param bool fill: Whether to fill or no fill the shape
        """
        try:
            self.lastrect
        except AttributeError:
            pass
        else:
            self.__canvas._tkcanvas.delete(self.lastrect)
            del self.lastrect

        if event.xdata is not None and event.ydata is not None:
            beg = self.__coordinates[0]
            self.__coordinates.append((event.xdata, beg[1]))
            self.__coordinates.append((event.xdata, event.ydata))
            self.__coordinates.append((beg[0], event.ydata))

            self.draw(fig, fl, plot, fill)
        else:
            self.__coordinates = []

    def generate_lat_range(self):
        axes = self.__canvas.figure.get_axes()
        labels = [x.get_xlabel() for x in axes]
        lat = axes[labels.index(u'Latitude')]
        time = axes[labels.index(u'Time')]
        min_ = lat.transData.inverted().transform(
            time.transData.transform(np.array(min(self.__coordinates))))[0]
        max_ = lat.transData.inverted().transform(
            time.transData.transform(np.array(max(self.__coordinates))))[0]
        return '%.4f - %.4f' % (min_, max_)

    def get_attributes(self):
        """
        Return attributes list maintained by shape

        :rtype: :py:class:`list`
        """
        return self.__attributes

    def get_color(self):
        """
        Return the hexdecimal color value

        :rtype: :py:class:`str`
        """
        return self.__color

    def get_coordinates(self):
        """
        Return the list of coordinates internally maintained by shape

        :rtype: :py:class:`list`
        """
        return self.__coordinates

    def get_id(self):
        """
        Return the database ID of shape

        :rtype: :py:class:`int`
        """
        return self.__id

    def get_itemhandler(self):
        """
        Return the item handler object to the actual backend base

        :rtype: :py:class:`matplotlib.patches.polygon`
        """
        return self.__item_handler

    def get_max_lat(self):
        axes = self.__canvas.figure.get_axes()
        labels = [x.get_xlabel() for x in axes]
        lat = axes[labels.index(u'Latitude')]
        time = axes[labels.index(u'Time')]
        max_ = lat.transData.inverted().transform(
            time.transData.transform(np.array(max(self.__coordinates))))[0]
        return max_

    def get_min_lat(self):
        axes = self.__canvas.figure.get_axes()
        labels = [x.get_xlabel() for x in axes]
        lat = axes[labels.index(u'Latitude')]
        time = axes[labels.index(u'Time')]
        min_ = lat.transData.inverted().transform(
            time.transData.transform(np.array(min(self.__coordinates))))[0]
        return min_

    def get_notes(self):
        """
        Return the notes string internally maintained by shape

        :rtype: :py:class:`str`
        """
        return self.__note

    def get_plot(self):
        """
        Return the plot type

        :rtype: :py:class:`int`
        """
        return self.__plot

    def get_hdf(self):
        """
        Return the file used

        :rtype: :py:class:`str`
        """
        return self.__hdf

    def get_saved(self):
        """
        Returns if the shape has been saved or not
        """
        return self.__saved

    def get_tag(self):
        """
        Return the program Tag of shape

        :rtype: :py:class:`str`
        """
        return self.__tag

    def in_x_extent(self, x):
        time_cords = [pair[0] for pair in self.__coordinates]
        if min(time_cords) <= x <= max(time_cords):
            return True
        else:
            return False

    def in_y_extent(self, y):
        altitude_cords = [pair[1] for pair in self.__coordinates]
        if min(altitude_cords) <= y <= max(altitude_cords):
            return True
        else:
            return False

    def is_attribute(self, attr):
        """
        Return ``True`` if *attr* is inside the attributes list, ``False``
        otherwise.

        :param str attr:
        :rtype: :py:class:`bool`
        """
        for item in self.__attributes:
            if attr == item:
                logger.info('Found attribute')
                return True
        return False

    def is_empty(self):
        """
        Return ``True`` if empty, ``False`` otherwise
        """
        if len(self.__coordinates) == 0:
            return True
        return False

    def is_selected(self):
        """
        Return a boolean value based on whether the object is currently
        highlighted in the figure. Uses ``__selected``

        :rtype: :py:class:`bool`
        """
        return self.__selected

    def loaded_draw(self, fig, fill):
        """
        Called in the case of panning the plot, since panning the plot invalidates
        the previous figure, the figures must first be cleared and the shapes are removed.
        Loaded draw draws the shapes back into view using a new figure.

        :param fig: A ``SubplotAxes`` object to add the patch to
        :param bool fill: Boolean value whether to have the shape filled in when drawn to or not
        """
        self.__item_handler = \
            Polygon(self.__coordinates, facecolor=self.__color, fill=fill, picker=5)
        if self.__selected:
            self.set_highlight(True)
        fig.add_patch(self.__item_handler)

    def paint(self, color):
        """
        Changes the color of the shape and saves it internally

        :param color: the new color of the shape
        """
        self.set_color(color)
        self.__saved = False

    def plot_point(self, event, plot, fl, fig, fill=False):
        """
        Plot a single point to the shape, connect any previous existing
        points and fill to a shape if the current coordinate intersects
        the beginning point.

        :param event: A ``matplotlib.backend_bases.MouseEvent`` passed object
        :param plot: an integer indicating which plot it was draw on
        :param fl: A string representing the HDF it was drawn on
        :param fig: The figure to be drawing the canvas to
        :param bool fill: Whether the shape will have a solid fill or not
        """
        self.__coordinates.append((event.xdata, event.ydata))
        logger.debug("Plotted point at (%0.5f, %0.5f)", event.xdata,
                     event.ydata)
        if len(self.__coordinates) > 1:
            logger.debug("Drawing line from plot")
            self.__lines.append(
                mlines.Line2D((self.__prev_x, event.xdata),
                              (self.__prev_y, event.ydata),
                              linewidth=2.0,
                              color='#000000'))
            fig.add_artist(self.__lines[-1])
            self.__canvas.show()

        if len(self.__coordinates) > 3:
            index = self.__can_draw()
            if index > -1:
                logger.debug("Creating polygon from points")
                a1 = tuple_to_nparray(self.__coordinates[index])
                a2 = tuple_to_nparray(self.__coordinates[index + 1])
                b1 = tuple_to_nparray(self.__coordinates[-1])
                b2 = tuple_to_nparray(self.__coordinates[-2])
                x = get_intersection(a1, a2, b1, b2)
                pair = nparray_to_tuple(x)
                self.__coordinates[index] = pair

                del self.__coordinates[:index]
                self.__coordinates.pop()
                for line in self.__lines:
                    line.remove()
                self.__drawing_line.remove()
                self.__drawing_line = None
                self.__lines = []
                self.draw(fig, fl, plot=plot, fill=fill)
                self.__plot = plot
                self.__hdf = fl
                return True

        self.__prev_x = event.xdata
        self.__prev_y = event.ydata

    def sketch_line(self, event, fig):
        if self.__drawing_line:
            self.__drawing_line.remove()
        self.__drawing_line = \
            mlines.Line2D((self.__prev_x, event.xdata), (self.__prev_y, event.ydata), linewidth=2.0,
                          color='#000000')
        fig.add_artist(self.__drawing_line)
        self.__canvas.show()
        return

    def close_polygon(self, event, plot, fl, fig, fill=False):
        if len(self.__coordinates) > 3:
            index = self.__can_draw()
            if index > -1:
                logger.debug("Creating polygon from points")
                a1 = tuple_to_nparray(self.__coordinates[index])
                a2 = tuple_to_nparray(self.__coordinates[index + 1])
                b1 = tuple_to_nparray(self.__coordinates[-1])
                b2 = tuple_to_nparray(self.__coordinates[-2])
                x = get_intersection(a1, a2, b1, b2)
                pair = nparray_to_tuple(x)
                self.__coordinates[index] = pair

                del self.__coordinates[:index]
                self.__coordinates.pop()
                for line in self.__lines:
                    line.remove()
                self.__drawing_line.remove()
                self.__drawing_line = None
                self.__lines = []
                self.draw(fig, plot, fill)
                self.__plot = plot
                self.__hdf = fl
                return True
        else:
            logger.warning('Not enough points')

    def redraw(self, fig, fl, fill):
        """
        Function to draw the shape in the event the shape *may* or *may not* already
        be drawn. Checks if the image already exists, if not draws the image

        :param fig: A ``SubplotAxes`` object to add the patch to
        :param fl: A string representing the HDF file
        :param bool fill: Boolean value whether to have the shape filled in when drawn or not
        """
        if self.__item_handler is not None and self.__item_handler.is_figure_set(
        ):
            self.__item_handler.remove()
        self.__item_handler = \
            Polygon(self.__coordinates, facecolor=self.__color, fill=fill, picker=5)
        if self.__selected:
            self.set_highlight(True)
        self.__hdf = fl
        fig.add_patch(self.__item_handler)

    def remove(self):
        """
        Wrapper function to internally call matplotlib backend to remove
        the shape from the figure
        """
        if self.__item_handler is None:
            self.clear_lines()
        else:
            self.__item_handler.remove()

    def remove_attribute(self, attr):
        """
        Remove an attribute as specified in ``constants.py`` from the internal attributes variable

        :param str attr:
        """
        if attr in TAGS:
            self.__attributes.remove(attr)
            self.__saved = False
        else:
            logger.error('Caught invalid attribute for removal \'%s\'' % attr)

    # noinspection PyAttributeOutsideInit
    def rubberband(self, event):
        """
        Draws a temporary helper rectangle that outlines the final shape of the rectangle for
        the user. This draws to **screen** coordiantes, so backend is not needed here.

        :param event: A ``matplotlib.backend_bases.MouseEvent`` forwarded object.
        """
        try:
            self.lastrect
        except AttributeError:
            pass
        else:
            self.__canvas._tkcanvas.delete(self.lastrect)

        height = self.__canvas.figure.bbox.height
        y2 = height - event.y
        self.lastrect = self.__canvas._tkcanvas.create_rectangle(
            self.__prev_x, self.__prev_y, event.x, y2)

    def save(self):
        """
        Marks the shape as saved
        """
        self.__saved = True

    def set_attributes(self, attributes_list):
        """
        Set the internal list of attributes to a custom passed list

        :param list attributes_list:
        """
        for i in attributes_list:
            if i not in TAGS:
                logger.error('Caught invalid attribute for setting \'%s\'' % i)
                return
        self.__attributes = attributes_list

    def set_color(self, color):
        """
        Set internal color variable

        :param str color: Valid hexadecimal color value
        """
        self.__color = color

    def set_coordinates(self, coordinates):
        """
        Pass a list of coordinates to set to the shape to.

        :param list coordinates:
        """
        self.__coordinates = coordinates

    def set_highlight(self, highlight):
        """
        Set the ``linewidth`` and ``linestyle`` attributes of a the internal item
        handler. Highlights if *highlight* is ``True``, otherwise sets to normal
        outline.

        :param bool highlight:
        """
        if highlight:
            self.__selected = True
            self.__item_handler.set_linewidth(3.0)
            self.__item_handler.set_linestyle('dashed')
        else:
            self.__selected = False
            self.__item_handler.set_linewidth(1.0)
            self.__item_handler.set_linestyle('solid')

    def set_id(self, _id):
        """
        Set the database ID of the shape. **unsafe** to use outside letting
        database call this.

        :param int _id: Database primary key
        """
        self.__id = _id

    def set_notes(self, note):
        """
        Pass a string containing new notes to set the shape to

        :param str note: New note string
        """
        self.__note = note

    def set_plot(self, plot):
        """
        Manually set the new value of the internal plot variable. **unsafe**

        :param constants.Plot plot: Plot value
        """
        self.__plot = plot

    def set_hdf(self, fl):
        """
        Manually set the value of the internal file variable

        :param fl: HDF file path
        """
        self.__hdf = fl

    def set_tag(self, tag):
        """
        Set internal tag variable

        :param str tag:
        """
        self.__tag = tag

    def __can_draw(self):
        if not self.__coordinates:
            logger.warning('Attempting to ask to draw empty shape, probably just ' + \
                           'toggling a button after using free draw? See ticket #92')
            return -1
        b1 = tuple_to_nparray(self.__coordinates[-1])
        b2 = tuple_to_nparray(self.__coordinates[-2])
        for i in range(len(self.__coordinates) - 3):
            a1 = tuple_to_nparray(self.__coordinates[i])
            a2 = tuple_to_nparray(self.__coordinates[i + 1])
            if is_intersecting(a1, a2, b1, b2):
                logger.debug("Polygon labeled for draw")
                return i
        return -1

    def __str__(self):
        logger.debug('Stringing %s' % self.__tag)
        time_cords = [
            mpl.dates.num2date(x[0]).strftime('%H:%M:%S')
            for x in self.__coordinates
        ]
        altitude_cords = [x[1] for x in self.__coordinates]
        string = 'Name:\n\t%s\n' % self.__tag
        string += 'Time Scale:\n\t%s - %s\n' % (min(time_cords),
                                                max(time_cords))
        string += 'Latitude Scale:\n\t%s\n' % self.generate_lat_range()
        string += 'Altitude Scale:\n\t%.4f km - %.4f km\n' % (
            min(altitude_cords), max(altitude_cords))
        string += 'Color:\n\t%s\n' % self.__color
        if len(self.__attributes) > 0:
            string += 'Attributes:\n'
            for item in self.__attributes:
                string += '\t%s\n' % item
        if self.__note != '':
            string += 'Notes:\n\t%s' % self.__note
        return string
def plot_planform(c_r, c_k, c_t, b_k, b, Lambda_le_1, Lambda_le_2, *args, **kwargs):

    fig = plt.subplots(figsize=(9, 9))
    
    # optional arguments
    c_mac = kwargs.get('mac', None)
    X_le_mac = kwargs.get('X_le_mac', None)
    Y_mac = kwargs.get('Y_mac', None)
    X_ac = kwargs.get('X_ac', None)
    
    xLineWing = [0, b_k/2, b/2, b/2, b_k/2, 0]
    dy_k = (b_k/2)*math.tan(Lambda_le_1)
    dy = dy_k + (b/2 - b_k/2)*math.tan(Lambda_le_2)
    yLineWing = [
        0, 
        dy_k, 
        dy,
        dy + c_t, 
        dy_k + c_k, 
        c_r]
        
    # planform
    lineWing, = plt.plot(xLineWing, yLineWing, 'k-')

    plt.scatter(xLineWing, yLineWing, marker='o', s=40)    
    
    # centerline
    centerLine, = plt.plot([0,0], [-0.2*c_r,2.1*c_r], 'b')
    centerLine.set_dashes([8, 4, 2, 4]) 
    # c/4 line
    pC4r = [0, 0.25*c_r]
    pC4k = [b_k/2, dy_k + 0.25*c_k]
    pC4t = [b/2, dy + 0.25*c_t]
    quarterChordLine, = plt.plot([pC4r[0],pC4k[0],pC4t[0]], [pC4r[1],pC4k[1],pC4t[1]], 'k--')
    plt.scatter([pC4r[0],pC4k[0],pC4t[0]], [pC4r[1],pC4k[1],pC4t[1]], marker='o', s=40)

    if ('mac' in kwargs) and ('X_le_mac' in kwargs) and ('Y_mac' in kwargs):
        c_mac = kwargs['mac']
        X_le_mac = kwargs['X_le_mac']
        Y_mac = kwargs['Y_mac']
        #print(mac)
        #print(X_le_mac)
        #print(Y_mac)
        lineMAC, = plt.plot([Y_mac, Y_mac], [X_le_mac, X_le_mac + c_mac], color="red", linewidth=2.5, linestyle="-")
        lineMAC.set_dashes([1000,1]) # HUUUUGE
        lineLEMAC, = plt.plot([0,b/2], [X_le_mac,X_le_mac], color="orange", linewidth=1.5, linestyle="-")
        lineLEMAC.set_dashes([10,2])
        lineTEMAC, = plt.plot([0,b/2], [X_le_mac + c_mac, X_le_mac + c_mac], color="orange", linewidth=1.5, linestyle="-")
        lineTEMAC.set_dashes([10,2])
        plt.scatter(Y_mac, X_le_mac, marker='o', s=40)
        ax = plt.gca()  # gca stands for 'get current axis'
        ax.annotate(
            r'$(Y_{\bar{c}},X_{\mathrm{le},\bar{c}}) = '
                +r'( {0:.3}'.format(Y_mac) + r'\,\mathrm{m}'+r',\,{0:.3}'.format(X_le_mac) + r'\,\mathrm{m} )$',
                         xy=(Y_mac, X_le_mac), xycoords='data',
                         xytext=(20, 30), textcoords='offset points', fontsize=12,
                         arrowprops=dict(arrowstyle="->", connectionstyle="arc3,rad=.2")) # 

    if ('X_le_r_eq' in kwargs) and ('c_r_eq' in kwargs):
        X_le_r_eq = kwargs['X_le_r_eq']
        c_r_eq = kwargs['c_r_eq']
        vertices = [(0, X_le_r_eq)] + [(b/2, dy)] + [(b/2, dy+c_t)] + [(0, X_le_r_eq + c_r_eq)]
        poly = Polygon(vertices, facecolor="yellow", alpha=0.5)
        poly.set_edgecolor("brown")
        poly.set_linewidth(2)
        ax0 = plt.gca()  # gca stands for 'get current axis'
        ax0.add_patch(poly)
        
    if 'X_ac' in kwargs:
        X_ac = kwargs['X_ac']
        #print(X_ac)
        plt.scatter(0, X_ac, marker='o', s=40)
        lineAC, = plt.plot([0,b/2], [X_ac,X_ac], color="brown", linewidth=3.5, linestyle="-")
        lineAC.set_dashes([10,2.5,3,2.5])
        ax = plt.gca()  # gca stands for 'get current axis'
        ax.annotate(r'$X_{\mathrm{ac,W}} = '+r'{0:.3}'.format(X_ac)+r'\,\mathrm{m} $',
                         xy=(b/2, X_ac), xycoords='data',
                         xytext=(20, 30), textcoords='offset points', fontsize=12,
                         arrowprops=dict(arrowstyle="->", connectionstyle="arc3,rad=.2")) # 

    plt.axis('equal')
    
    #    xmajorLocator = MultipleLocator(2.0)
    #    xmajorFormatter = FormatStrFormatter('%.1f')
    #    xminorLocator = MultipleLocator(4)
    #    ax = plt.gca()  # gca stands for 'get current axis'
    #    ax.xaxis.set_major_locator(xmajorLocator)
    #    ax.xaxis.set_major_formatter(xmajorFormatter)
    #    # for the minor ticks, use no labels; default NullFormatter
    #    ax.xaxis.set_minor_locator(xminorLocator)
    
    plt.axis([-0.02*b/2, 1.1*b/2, -0.05*c_r, 1.1*(dy + c_t)])
    plt.gca().invert_yaxis()
    plt.title('Wing planform', fontsize=16)
    plt.xlabel('$y$ (m)', fontsize=16)
    plt.ylabel('$X$ (m)', fontsize=16)
    # Moving spines
    ax = plt.gca()  # gca stands for 'get current axis'
    ax.spines['right'].set_color('none')
    ax.spines['top'].set_color('none')
    ax.xaxis.set_ticks_position('bottom')
    ax.spines['bottom'].set_position(('outward',10)) # outward by 10 points
    ax.yaxis.set_ticks_position('left')
    ax.spines['left'].set_position(('data',-0.07*b/2))

    plt.show()
Ejemplo n.º 14
0
circle.set_facecolor(None)
patches = [circle]

for i in range(nPolys):
    p = [1] + [0] * (n - 1) + [-z[i]]
    roots = np.roots(p)
    angles = np.sort([cmath.phase(root) for root in roots])
    roots = np.cos(angles) + j * np.sin(angles)
    x = roots.real
    y = roots.imag
    coords = np.stack((x, y), axis=1)

    poly = Polygon(xy=coords, closed=True)
    poly.set_edgecolor('royalblue')
    poly.set_facecolor('lightsteelblue')
    poly.set_linewidth(1)
    patches.append(poly)

fig, ax = plt.subplots(subplot_kw={'aspect': 'equal'})

# Set bottom and left spines as x and y axes of coordinate system
ax.spines['bottom'].set_position('zero')
ax.spines['left'].set_position('zero')

# Remove top and right spines
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
# Create 'x' and 'y' labels placed at the end of the axes
ax.set_xlabel('x', size=14, labelpad=-24, x=1.03)
ax.set_ylabel('y', size=14, labelpad=-21, y=1.02, rotation=0)
Ejemplo n.º 15
0
class WindroseAxes(PolarAxes):
    """

    Makes a windrose axes

    """

    RESOLUTION = 100

    def __init__(self, *args, **kwargs):
        """
        See Axes base class for args and kwargs documentation
        """
        PolarAxes.__init__(self, *args, **kwargs)
        self.set_aspect('equal', adjustable='box', anchor='C')
        self.radii_angle = 67.5
        self.cla()

    def _init_axis(self):
        self.xaxis = None
        self.yaxis = None

    def cla(self):
        """
        Clear the current axes
        """

        self._get_lines = _process_plot_var_args(self)
        self._get_patches_for_fill = _process_plot_var_args(self, 'fill')
        self._gridOn = matplotlib.rcParams['polaraxes.grid']
        self.thetagridlabels = []
        self.thetagridlines = []
        self.rgridlabels = []
        self.rgridlines = []
        self.lines = []
        self.images = []
        self.patches = []
        self.artists = []
        self.collections = []
        self.texts = []  # text in axis coords
        self.legend_ = None
        self.grid(self._gridOn)
        self.title = Text(
            x=0.5,
            y=1.05,
            text='',
            fontproperties=FontProperties(
                size=matplotlib.rcParams['axes.titlesize']),
            verticalalignment='bottom',
            horizontalalignment='center',
        )
        self.title.set_transform(self.transAxes)
        self._set_artist_props(self.title)
        self.thetas = N.linspace(0, 2 * N.pi, self.RESOLUTION)
        verts = list(zip(self.thetas, N.ones(self.RESOLUTION)))
        self.axesPatch = Polygon(
            verts,
            facecolor=self._axisbg,
            edgecolor=matplotlib.rcParams['axes.edgecolor'],
        )
        self.axesPatch.set_figure(self.figure)
        self.axesPatch.set_transform(self.transData)
        self.axesPatch.set_linewidth(matplotlib.rcParams['axes.linewidth'])
        self.axison = True
        self.rintv = Interval(Value(0), Value(1))
        self.rintd = Interval(Value(0), Value(1))
        self.rformatter = ScalarFormatter()
        self.rformatter.set_view_interval(self.rintv)
        self.rformatter.set_data_interval(self.rintd)

        class RadialLocator(AutoLocator):
            'enforce strictly positive radial ticks'

            def __call__(self):
                ticks = AutoLocator.__call__(self)
                return [t for t in ticks if t > 0]

        self.rlocator = RadialLocator()
        self.rlocator.set_view_interval(self.rintv)
        self.rlocator.set_data_interval(self.rintd)

        self.theta_angles = N.arange(0, 360, 45)
        self.theta_labels = ['E', 'N-E', 'N', 'N-W', 'W', 'S-W', 'S', 'S-E']
        self.set_thetagrids(angles=self.theta_angles, labels=self.theta_labels)

        self._info = {'dir': list(), 'bins': list(), 'table': list()}

        self.patches_list = list()

    def _colors(self, cmap, n):
        '''
        Returns a list of n colors based on the colormap cmap

        '''
        return [cmap(i) for i in N.linspace(0.0, 1.0, n)]

    def set_radii_angle(self, **kwargs):
        """
        Set the radii labels angle
        """

        null = popd(kwargs, 'labels', None)
        angle = popd(kwargs, 'angle', None)
        if angle is None:
            angle = self.radii_angle
        self.radii_angle = angle
        radii = N.linspace(0.1, self.get_rmax(), 6)
        radii_labels = ["%.1f" % r for r in radii]
        radii_labels[0] = ""  #Removing label 0
        null = self.set_rgrids(radii=radii,
                               labels=radii_labels,
                               angle=self.radii_angle,
                               **kwargs)

    def _update(self):
        self.regrid(self.get_rmax())
        self.set_radii_angle(angle=self.radii_angle)

    def legend(self, loc='lower left', **kwargs):
        """
        Sets the legend location and her properties.
        The location codes are

          'best'         : 0,
          'upper right'  : 1,
          'upper left'   : 2,
          'lower left'   : 3,
          'lower right'  : 4,
          'right'        : 5,
          'center left'  : 6,
          'center right' : 7,
          'lower center' : 8,
          'upper center' : 9,
          'center'       : 10,

        If none of these are suitable, loc can be a 2-tuple giving x,y
        in axes coords, ie,

          loc = (0, 1) is left top
          loc = (0.5, 0.5) is center, center

        and so on.  The following kwargs are supported:

        isaxes=True           # whether this is an axes legend
        prop = FontProperties(size='smaller')  # the font property
        pad = 0.2             # the fractional whitespace inside the legend border
        shadow                # if True, draw a shadow behind legend
        labelsep = 0.005     # the vertical space between the legend entries
        handlelen = 0.05     # the length of the legend lines
        handletextsep = 0.02 # the space between the legend line and legend text
        axespad = 0.02       # the border between the axes and legend edge
        """
        def get_handles():
            handles = list()
            for p in self.patches_list:
                if isinstance(p, matplotlib.patches.Polygon) or \
                isinstance(p, matplotlib.patches.Rectangle):
                    color = p.get_facecolor()
                elif isinstance(p, matplotlib.lines.Line2D):
                    color = p.get_color()
                else:
                    raise AttributeError("Can't handle patches")
                handles.append(
                    Rectangle((0, 0),
                              0.2,
                              0.2,
                              facecolor=color,
                              edgecolor='black'))
            return handles

        def get_labels():
            labels = N.copy(self._info['bins'])
            labels = ["[%.1f : %0.1f[" %(labels[i], labels[i+1]) \
                      for i in range(len(labels)-1)]
            return labels

        null = popd(kwargs, 'labels', None)
        null = popd(kwargs, 'handles', None)
        handles = get_handles()
        labels = get_labels()
        self.legend_ = matplotlib.legend.Legend(self, handles, labels, loc,
                                                **kwargs)
        return self.legend_

    def _init_plot(self, dir, var, **kwargs):
        """
        Internal method used by all plotting commands
        """
        #self.cla()
        null = popd(kwargs, 'zorder', None)

        #Init of the bins array if not set
        bins = popd(kwargs, 'bins', None)
        if bins is None:
            bins = N.linspace(N.min(var), N.max(var), 6)
        if isinstance(bins, int):
            bins = N.linspace(N.min(var), N.max(var), bins)
        nbins = len(bins)

        #Init of the number of sectors
        nsector = popd(kwargs, 'nsector', None)
        if nsector is None:
            nsector = 16

        #Sets the colors table based on the colormap or the "colors" argument
        colors = popd(kwargs, 'colors', None)
        cmap = popd(kwargs, 'cmap', None)
        if colors is not None:
            if isinstance(colors, str):
                colors = [colors] * nbins
            if isinstance(colors, (tuple, list)):
                if len(colors) != nbins:
                    raise ValueError("colors and bins must have same length")
        else:
            if cmap is None:
                cmap = cm.jet
            colors = self._colors(cmap, nbins)

        #Building the list of angles
        angles = N.arange(0, -2 * N.pi, -2 * N.pi / nsector) + N.pi / 2

        normed = popd(kwargs, 'normed', False)
        blowto = popd(kwargs, 'blowto', False)

        #Set the global information dictionnary
        self._info['dir'], self._info['bins'], self._info['table'] = histogram(
            dir, var, bins, nsector, normed, blowto)

        return bins, nbins, nsector, colors, angles, kwargs

    def contour(self, dir, var, **kwargs):
        """
        Plot a windrose in linear mode. For each var bins, a line will be
        draw on the axes, a segment between each sector (center to center).
        Each line can be formated (color, width, ...) like with standard plot
        pylab command.

        Mandatory:
        * dir : 1D array - directions the wind blows from, North centred
        * var : 1D array - values of the variable to compute. Typically the wind
        speeds
        Optional:
        * nsector: integer - number of sectors used to compute the windrose
        table. If not set, nsectors=16, then each sector will be 360/16=22.5°,
        and the resulting computed table will be aligned with the cardinals
        points.
        * bins : 1D array or integer- number of bins, or a sequence of
        bins variable. If not set, bins=6, then
            bins=linspace(min(var), max(var), 6)
        * blowto : bool. If True, the windrose will be pi rotated,
        to show where the wind blow to (usefull for pollutant rose).
        * colors : string or tuple - one string color ('k' or 'black'), in this
        case all bins will be plotted in this color; a tuple of matplotlib
        color args (string, float, rgb, etc), different levels will be plotted
        in different colors in the order specified.
        * cmap : a cm Colormap instance from matplotlib.cm.
          - if cmap == None and colors == None, a default Colormap is used.

        others kwargs : see help(pylab.plot)

        """

        bins, nbins, nsector, colors, angles, kwargs = self._init_plot(
            dir, var, **kwargs)

        #closing lines
        angles = N.hstack((angles, angles[0]))
        vals = N.hstack((self._info['table'],
                         N.reshape(self._info['table'][:, 0],
                                   (self._info['table'].shape[0], 1))))

        offset = 0
        for i in range(nbins):
            val = vals[i, :] + offset
            offset += vals[i, :]
            zorder = nbins - i
            patch = self.plot(angles,
                              val,
                              color=colors[i],
                              zorder=zorder,
                              **kwargs)
            self.patches_list.extend(patch)
        self._update()

    def contourf(self, dir, var, **kwargs):
        """
        Plot a windrose in filled mode. For each var bins, a line will be
        draw on the axes, a segment between each sector (center to center).
        Each line can be formated (color, width, ...) like with standard plot
        pylab command.

        Mandatory:
        * dir : 1D array - directions the wind blows from, North centred
        * var : 1D array - values of the variable to compute. Typically the wind
        speeds
        Optional:
        * nsector: integer - number of sectors used to compute the windrose
        table. If not set, nsectors=16, then each sector will be 360/16=22.5°,
        and the resulting computed table will be aligned with the cardinals
        points.
        * bins : 1D array or integer- number of bins, or a sequence of
        bins variable. If not set, bins=6, then
            bins=linspace(min(var), max(var), 6)
        * blowto : bool. If True, the windrose will be pi rotated,
        to show where the wind blow to (usefull for pollutant rose).
        * colors : string or tuple - one string color ('k' or 'black'), in this
        case all bins will be plotted in this color; a tuple of matplotlib
        color args (string, float, rgb, etc), different levels will be plotted
        in different colors in the order specified.
        * cmap : a cm Colormap instance from matplotlib.cm.
          - if cmap == None and colors == None, a default Colormap is used.

        others kwargs : see help(pylab.plot)

        """

        bins, nbins, nsector, colors, angles, kwargs = self._init_plot(
            dir, var, **kwargs)
        null = popd(kwargs, 'facecolor', None)
        null = popd(kwargs, 'edgecolor', None)
        offset = 0
        for i in range(nbins):
            val = self._info['table'][i, :] + offset
            offset += self._info['table'][i, :]
            zorder = nbins - i
            patch = self.fill(angles,
                              val,
                              facecolor=colors[i],
                              edgecolor=colors[i],
                              zorder=zorder,
                              **kwargs)
            self.patches_list.extend(patch)

    def bar(self, dir, var, **kwargs):
        """
        Plot a windrose in bar mode. For each var bins and for each sector,
        a colored bar will be draw on the axes.

        Mandatory:
        * dir : 1D array - directions the wind blows from, North centred
        * var : 1D array - values of the variable to compute. Typically the wind
        speeds
        Optional:
        * nsector: integer - number of sectors used to compute the windrose
        table. If not set, nsectors=16, then each sector will be 360/16=22.5°,
        and the resulting computed table will be aligned with the cardinals
        points.
        * bins : 1D array or integer- number of bins, or a sequence of
        bins variable. If not set, bins=6 between min(var) and max(var).
        * blowto : bool. If True, the windrose will be pi rotated,
        to show where the wind blow to (usefull for pollutant rose).
        * colors : string or tuple - one string color ('k' or 'black'), in this
        case all bins will be plotted in this color; a tuple of matplotlib
        color args (string, float, rgb, etc), different levels will be plotted
        in different colors in the order specified.
        * cmap : a cm Colormap instance from matplotlib.cm.
          - if cmap == None and colors == None, a default Colormap is used.
        edgecolor : string - The string color each edge bar will be plotted.
        Default : no edgecolor
        * opening : float - between 0.0 and 1.0, to control the space between
        each sector (1.0 for no space)

        """

        bins, nbins, nsector, colors, angles, kwargs = self._init_plot(
            dir, var, **kwargs)
        null = popd(kwargs, 'facecolor', None)
        edgecolor = popd(kwargs, 'edgecolor', None)
        if edgecolor is not None:
            if not isinstance(edgecolor, str):
                raise ValueError('edgecolor must be a string color')
        opening = popd(kwargs, 'opening', None)
        if opening is None:
            opening = 0.8
        dtheta = 2 * N.pi / nsector
        opening = dtheta * opening

        for j in range(nsector):
            offset = 0
            for i in range(nbins):
                if i > 0:
                    offset += self._info['table'][i - 1, j]
                val = self._info['table'][i, j]
                zorder = nbins - i
                patch = Rectangle((angles[j] - opening / 2, offset),
                                  opening,
                                  val,
                                  facecolor=colors[i],
                                  edgecolor=edgecolor,
                                  zorder=zorder,
                                  **kwargs)
                self.add_patch(patch)
                if j == 0:
                    self.patches_list.append(patch)
        self._update()

    def box(self, dir, var, **kwargs):
        """
        Plot a windrose in proportional bar mode. For each var bins and for each
        sector, a colored bar will be draw on the axes.

        Mandatory:
        * dir : 1D array - directions the wind blows from, North centred
        * var : 1D array - values of the variable to compute. Typically the wind
        speeds
        Optional:
        * nsector: integer - number of sectors used to compute the windrose
        table. If not set, nsectors=16, then each sector will be 360/16=22.5°,
        and the resulting computed table will be aligned with the cardinals
        points.
        * bins : 1D array or integer- number of bins, or a sequence of
        bins variable. If not set, bins=6 between min(var) and max(var).
        * blowto : bool. If True, the windrose will be pi rotated,
        to show where the wind blow to (usefull for pollutant rose).
        * colors : string or tuple - one string color ('k' or 'black'), in this
        case all bins will be plotted in this color; a tuple of matplotlib
        color args (string, float, rgb, etc), different levels will be plotted
        in different colors in the order specified.
        * cmap : a cm Colormap instance from matplotlib.cm.
          - if cmap == None and colors == None, a default Colormap is used.
        edgecolor : string - The string color each edge bar will be plotted.
        Default : no edgecolor

        """

        bins, nbins, nsector, colors, angles, kwargs = self._init_plot(
            dir, var, **kwargs)
        null = popd(kwargs, 'facecolor', None)
        edgecolor = popd(kwargs, 'edgecolor', None)
        if edgecolor is not None:
            if not isinstance(edgecolor, str):
                raise ValueError('edgecolor must be a string color')
        opening = N.linspace(0.0, N.pi / 16, nbins)

        for j in range(nsector):
            offset = 0
            for i in range(nbins):
                if i > 0:
                    offset += self._info['table'][i - 1, j]
                val = self._info['table'][i, j]
                zorder = nbins - i
                patch = Rectangle((angles[j] - opening[i] / 2, offset),
                                  opening[i],
                                  val,
                                  facecolor=colors[i],
                                  edgecolor=edgecolor,
                                  zorder=zorder,
                                  **kwargs)
                self.add_patch(patch)
                if j == 0:
                    self.patches_list.append(patch)
        self._update()
def plot_planform(c_r, c_k, c_t, b_k, b, Lambda_le_1, Lambda_le_2, *args,
                  **kwargs):

    fig = plt.subplots(figsize=(9, 9))

    # optional arguments
    c_mac = kwargs.get('mac', None)
    X_le_mac = kwargs.get('X_le_mac', None)
    Y_mac = kwargs.get('Y_mac', None)
    X_ac = kwargs.get('X_ac', None)

    xLineWing = [0, b_k / 2, b / 2, b / 2, b_k / 2, 0]
    dy_k = (b_k / 2) * math.tan(Lambda_le_1)
    dy = dy_k + (b / 2 - b_k / 2) * math.tan(Lambda_le_2)
    yLineWing = [0, dy_k, dy, dy + c_t, dy_k + c_k, c_r]

    # planform
    lineWing, = plt.plot(xLineWing, yLineWing, 'k-')

    plt.scatter(xLineWing, yLineWing, marker='o', s=40)

    # centerline
    centerLine, = plt.plot([0, 0], [-0.2 * c_r, 2.1 * c_r], 'b')
    centerLine.set_dashes([8, 4, 2, 4])
    # c/4 line
    pC4r = [0, 0.25 * c_r]
    pC4k = [b_k / 2, dy_k + 0.25 * c_k]
    pC4t = [b / 2, dy + 0.25 * c_t]
    quarterChordLine, = plt.plot([pC4r[0], pC4k[0], pC4t[0]],
                                 [pC4r[1], pC4k[1], pC4t[1]], 'k--')
    plt.scatter([pC4r[0], pC4k[0], pC4t[0]], [pC4r[1], pC4k[1], pC4t[1]],
                marker='o',
                s=40)

    if ('mac' in kwargs) and ('X_le_mac' in kwargs) and ('Y_mac' in kwargs):
        c_mac = kwargs['mac']
        X_le_mac = kwargs['X_le_mac']
        Y_mac = kwargs['Y_mac']
        #print(mac)
        #print(X_le_mac)
        #print(Y_mac)
        lineMAC, = plt.plot([Y_mac, Y_mac], [X_le_mac, X_le_mac + c_mac],
                            color="red",
                            linewidth=2.5,
                            linestyle="-")
        lineMAC.set_dashes([1000, 1])  # HUUUUGE
        lineLEMAC, = plt.plot([0, b / 2], [X_le_mac, X_le_mac],
                              color="orange",
                              linewidth=1.5,
                              linestyle="-")
        lineLEMAC.set_dashes([10, 2])
        lineTEMAC, = plt.plot([0, b / 2], [X_le_mac + c_mac, X_le_mac + c_mac],
                              color="orange",
                              linewidth=1.5,
                              linestyle="-")
        lineTEMAC.set_dashes([10, 2])
        plt.scatter(Y_mac, X_le_mac, marker='o', s=40)
        ax = plt.gca()  # gca stands for 'get current axis'
        ax.annotate(r'$(Y_{\bar{c}},X_{\mathrm{le},\bar{c}}) = ' +
                    r'( {0:.3}'.format(Y_mac) + r'\,\mathrm{m}' +
                    r',\,{0:.3}'.format(X_le_mac) + r'\,\mathrm{m} )$',
                    xy=(Y_mac, X_le_mac),
                    xycoords='data',
                    xytext=(20, 30),
                    textcoords='offset points',
                    fontsize=12,
                    arrowprops=dict(arrowstyle="->",
                                    connectionstyle="arc3,rad=.2"))  #

    if ('X_le_r_eq' in kwargs) and ('c_r_eq' in kwargs):
        X_le_r_eq = kwargs['X_le_r_eq']
        c_r_eq = kwargs['c_r_eq']
        vertices = [(0, X_le_r_eq)] + [(b / 2, dy)] + [(b / 2, dy + c_t)] + [
            (0, X_le_r_eq + c_r_eq)
        ]
        poly = Polygon(vertices, facecolor="yellow", alpha=0.5)
        poly.set_edgecolor("brown")
        poly.set_linewidth(2)
        ax0 = plt.gca()  # gca stands for 'get current axis'
        ax0.add_patch(poly)

    if 'X_ac' in kwargs:
        X_ac = kwargs['X_ac']
        #print(X_ac)
        plt.scatter(0, X_ac, marker='o', s=40)
        lineAC, = plt.plot([0, b / 2], [X_ac, X_ac],
                           color="brown",
                           linewidth=3.5,
                           linestyle="-")
        lineAC.set_dashes([10, 2.5, 3, 2.5])
        ax = plt.gca()  # gca stands for 'get current axis'
        ax.annotate(r'$X_{\mathrm{ac,W}} = ' + r'{0:.3}'.format(X_ac) +
                    r'\,\mathrm{m} $',
                    xy=(b / 2, X_ac),
                    xycoords='data',
                    xytext=(20, 30),
                    textcoords='offset points',
                    fontsize=12,
                    arrowprops=dict(arrowstyle="->",
                                    connectionstyle="arc3,rad=.2"))  #

    plt.axis('equal')

    #    xmajorLocator = MultipleLocator(2.0)
    #    xmajorFormatter = FormatStrFormatter('%.1f')
    #    xminorLocator = MultipleLocator(4)
    #    ax = plt.gca()  # gca stands for 'get current axis'
    #    ax.xaxis.set_major_locator(xmajorLocator)
    #    ax.xaxis.set_major_formatter(xmajorFormatter)
    #    # for the minor ticks, use no labels; default NullFormatter
    #    ax.xaxis.set_minor_locator(xminorLocator)

    plt.axis([-0.02 * b / 2, 1.1 * b / 2, -0.05 * c_r, 1.1 * (dy + c_t)])
    plt.gca().invert_yaxis()
    plt.title('Wing planform', fontsize=16)
    plt.xlabel('$y$ (m)', fontsize=16)
    plt.ylabel('$X$ (m)', fontsize=16)
    # Moving spines
    ax = plt.gca()  # gca stands for 'get current axis'
    ax.spines['right'].set_color('none')
    ax.spines['top'].set_color('none')
    ax.xaxis.set_ticks_position('bottom')
    ax.spines['bottom'].set_position(('outward', 10))  # outward by 10 points
    ax.yaxis.set_ticks_position('left')
    ax.spines['left'].set_position(('data', -0.07 * b / 2))

    plt.show()