def subtract_and_intersect_circle(self, center, radius): '''Will throw a VennRegionException if the circle to be subtracted is completely inside and not touching the given region.''' # Check whether the target circle intersects us center = np.asarray(center, float) d = np.linalg.norm(center - self.center) if d > (radius + self.radius - tol): return [self, VennEmptyRegion()] # The circle does not intersect us elif d < tol: if radius > self.radius - tol: # We are completely covered by that circle or we are the same circle return [VennEmptyRegion(), self] else: # That other circle is inside us and smaller than us - we can't deal with it raise VennRegionException( "Invalid configuration of circular regions (holes are not supported)." ) else: # We *must* intersect the other circle. If it is not the case, then it is inside us completely, # and we'll complain. intersections = circle_circle_intersection(self.center, self.radius, center, radius) if intersections is None: raise VennRegionException( "Invalid configuration of circular regions (holes are not supported)." ) elif np.all(abs(intersections[0] - intersections[1]) < tol) and self.radius < radius: # There is a single intersection point (i.e. we are touching the circle), # the circle to be subtracted is not outside of us (this was checked before), and is larger than us. # This is a particular corner case that is not dealt with correctly by the general-purpose code below and must # be handled separately return [VennEmptyRegion(), self] else: # Otherwise the subtracted region is a 2-arc-gon # Before we need to convert the intersection points as angles wrt each circle. a_1 = vector_angle_in_degrees(intersections[0] - self.center) a_2 = vector_angle_in_degrees(intersections[1] - self.center) b_1 = vector_angle_in_degrees(intersections[0] - center) b_2 = vector_angle_in_degrees(intersections[1] - center) # We must take care of the situation where the intersection points happen to be the same if (abs(b_1 - b_2) < tol): b_1 = b_2 - tol / 2 if (abs(a_1 - a_2) < tol): a_2 = a_1 + tol / 2 # The subtraction is a 2-arc-gon [(AB, B-), (BA, A+)] s_arc1 = Arc(center, radius, b_1, b_2, False) s_arc2 = Arc(self.center, self.radius, a_2, a_1, True) subtraction = VennArcgonRegion([s_arc1, s_arc2]) # .. and the intersection is a 2-arc-gon [(AB, A+), (BA, B+)] i_arc1 = Arc(self.center, self.radius, a_1, a_2, True) i_arc2 = Arc(center, radius, b_2, b_1, True) intersection = VennArcgonRegion([i_arc1, i_arc2]) return [subtraction, intersection]
def intersect_circle(self, center, radius): ''' Given a circle, finds the intersection point(s) of the arc with the circle. Returns a list of 2x1 numpy arrays. The list has length 0, 1 or 2, depending on how many intesection points there are. If the circle touches the arc, it is reported as two intersection points (which are equal). Points are ordered along the arc. Intersection with the same circle as the arc's own (which means infinitely many points usually) is reported as no intersection at all. >>> a = Arc((0, 0), 1, -60, 60, True) >>> a.intersect_circle((1, 0), 1) [array([ 0.5..., -0.866...]), array([ 0.5..., 0.866...])] >>> a.intersect_circle((0.9, 0), 1) [] >>> a.intersect_circle((1,-0.1), 1) [array([ 0.586..., 0.810...])] >>> a.intersect_circle((1, 0.1), 1) [array([ 0.586..., -0.810...])] >>> a.intersect_circle((0, 0), 1) # Infinitely many intersection points [] >>> a.intersect_circle((2, 0), 1) # Touching point, hence repeated twice [array([ 1., 0.]), array([ 1., 0.])] >>> a = Arc((0, 0), 1, 60, -60, False) # Same arc, different direction >>> a.intersect_circle((1, 0), 1) [array([ 0.5..., 0.866...]), array([ 0.5..., -0.866...])] >>> a = Arc((0, 0), 1, 120, -120, True) >>> a.intersect_circle((-1, 0), 1) [array([-0.5..., 0.866...]), array([-0.5..., -0.866...])] >>> a.intersect_circle((-0.9, 0), 1) [] >>> a.intersect_circle((-1,-0.1), 1) [array([-0.586..., 0.810...])] >>> a.intersect_circle((-1, 0.1), 1) [array([-0.586..., -0.810...])] >>> a.intersect_circle((-2, 0), 1) [array([-1., 0.]), array([-1., 0.])] >>> a = Arc((0, 0), 1, -120, 120, False) >>> a.intersect_circle((-1, 0), 1) [array([-0.5..., -0.866...]), array([-0.5..., 0.866...])] ''' intersections = circle_circle_intersection(self.center, self.radius, center, radius) if intersections is None: return [] # Check whether the points lie on the arc and order them accordingly _len = self.length_degrees() isections = [[self.sign * (self.point_as_angle(pt) - self.from_angle) % 360.0, pt] for pt in intersections] # Try to find as many candidate intersections as possible (i.e. +- tol within arc limits) # Unless arc's length is 360, interpret intersections just before the arc's starting point as belonging to the starting point. if _len < 360.0 - tol: for isec in isections: if isec[0] > 360.0 - tol: isec[0] = 0.0 isections = [(a, pt[0], pt[1]) for (a, pt) in isections if a < _len + tol or a > 360 - tol] isections.sort() return [np.array([b, c]) for (a, b, c) in isections]
def subtract_and_intersect_circle(self, center, radius): '''Will throw a VennRegionException if the circle to be subtracted is completely inside and not touching the given region.''' # Check whether the target circle intersects us center = np.asarray(center, float) d = np.linalg.norm(center - self.center) if d > (radius + self.radius - tol): return [self, VennEmptyRegion()] # The circle does not intersect us elif d < tol: if radius > self.radius - tol: # We are completely covered by that circle or we are the same circle return [VennEmptyRegion(), self] else: # That other circle is inside us and smaller than us - we can't deal with it raise VennRegionException("Invalid configuration of circular regions (holes are not supported).") else: # We *must* intersect the other circle. If it is not the case, then it is inside us completely, # and we'll complain. intersections = circle_circle_intersection(self.center, self.radius, center, radius) if intersections is None: raise VennRegionException("Invalid configuration of circular regions (holes are not supported).") elif np.all(abs(intersections[0] - intersections[1]) < tol) and self.radius < radius: # There is a single intersection point (i.e. we are touching the circle), # the circle to be subtracted is not outside of us (this was checked before), and is larger than us. # This is a particular corner case that is not dealt with correctly by the general-purpose code below and must # be handled separately return [VennEmptyRegion(), self] else: # Otherwise the subtracted region is a 2-arc-gon # Before we need to convert the intersection points as angles wrt each circle. a_1 = vector_angle_in_degrees(intersections[0] - self.center) a_2 = vector_angle_in_degrees(intersections[1] - self.center) b_1 = vector_angle_in_degrees(intersections[0] - center) b_2 = vector_angle_in_degrees(intersections[1] - center) # We must take care of the situation where the intersection points happen to be the same if (abs(b_1 - b_2) < tol): b_1 = b_2 - tol/2 if (abs(a_1 - a_2) < tol): a_2 = a_1 + tol/2 # The subtraction is a 2-arc-gon [(AB, B-), (BA, A+)] s_arc1 = Arc(center, radius, b_1, b_2, False) s_arc2 = Arc(self.center, self.radius, a_2, a_1, True) subtraction = VennArcgonRegion([s_arc1, s_arc2]) # .. and the intersection is a 2-arc-gon [(AB, A+), (BA, B+)] i_arc1 = Arc(self.center, self.radius, a_1, a_2, True) i_arc2 = Arc(center, radius, b_2, b_1, True) intersection = VennArcgonRegion([i_arc1, i_arc2]) return [subtraction, intersection]
def plot_venn(search_one, search_two, output_location): """ search_one and search_two should both be dictionaries, mapping each scan to the peptide """ spectra_one = set(search_one.keys()) print('spectra one:') print(spectra_one) spectra_two = set(search_two.keys()) common_spectra = spectra_one.intersection(spectra_two) print('common spectra') print(common_spectra) #the number of spectra shared between the two searches that match against different peptides discordant_spectra = 0 #the number of spectra shared between the two searches that match against the same peptide concordant_spectra = 0 for spectra in common_spectra: if search_one[spectra] == search_two[spectra]: concordant_spectra += 1 else: discordant_spectra += 1 circles = venn2_circles([spectra_one, spectra_two]) sorted_circles = sorted(circles, key=lambda x: x.center[0]) bigger_circle = max(circles, key=lambda x: x.radius) bigger_radius = bigger_circle.radius left_point = np.array([sorted_circles[0].center[0] - sorted_circles[0].radius, sorted_circles[0].center[1]]) right_point = np.array([sorted_circles[1].center[0] + sorted_circles[1].radius, sorted_circles[1].center[1]]) left_intersection = max(_math.circle_line_intersection(sorted_circles[0].center, sorted_circles[0].radius, left_point, right_point), key=lambda x: x[0]) right_intersection = min(_math.circle_line_intersection(sorted_circles[1].center, sorted_circles[1].radius, left_point, right_point), key=lambda x: x[0]) line = ConnectionPatch(left_intersection, right_intersection, 'data', 'data') plt.gca().add_patch(line) print(sorted_circles[0].center) print(sorted_circles[1].center) circle_intersections = _math.circle_circle_intersection(sorted_circles[0].center, sorted_circles[0].radius, sorted_circles[1].center, sorted_circles[1].radius) upper_circle_intersection = max(circle_intersections, key=lambda x: x[1]) #take the centroid upper_text_location = (left_intersection + right_intersection + upper_circle_intersection)/3.0 #plt.rc('text', usetex=True) plt.text(upper_text_location[0], upper_text_location[1], str(concordant_spectra) + '\n' + r'$p_i = p_j$') lower_circle_intersection = min(circle_intersections, key=lambda x: x[1]) lower_text_location = (left_intersection + right_intersection + lower_circle_intersection)/3.0 plt.text(lower_text_location[0], lower_text_location[1], str(discordant_spectra) + '\n' + r'$p_i \neq p_j$') venn_diagram = venn2([spectra_one, spectra_two], ['Unfiltered', 'Filtered']) venn_diagram.get_label_by_id('11').set_text('') matplotlib.pyplot.savefig(output_location, format='png')