| 22 | |
| 23 | |
| 24 | class BubbleChart: |
| 25 | def __init__(self, area, bubble_spacing=0): |
| 26 | """ |
| 27 | Setup for bubble collapse. |
| 28 | |
| 29 | Parameters |
| 30 | ---------- |
| 31 | area : array-like |
| 32 | Area of the bubbles. |
| 33 | bubble_spacing : float, default: 0 |
| 34 | Minimal spacing between bubbles after collapsing. |
| 35 | |
| 36 | Notes |
| 37 | ----- |
| 38 | If "area" is sorted, the results might look weird. |
| 39 | """ |
| 40 | area = np.asarray(area) |
| 41 | r = np.sqrt(area / np.pi) |
| 42 | |
| 43 | self.bubble_spacing = bubble_spacing |
| 44 | self.bubbles = np.ones((len(area), 4)) |
| 45 | self.bubbles[:, 2] = r |
| 46 | self.bubbles[:, 3] = area |
| 47 | self.maxstep = 2 * self.bubbles[:, 2].max() + self.bubble_spacing |
| 48 | self.step_dist = self.maxstep / 2 |
| 49 | |
| 50 | # calculate initial grid layout for bubbles |
| 51 | length = np.ceil(np.sqrt(len(self.bubbles))) |
| 52 | grid = np.arange(length) * self.maxstep |
| 53 | gx, gy = np.meshgrid(grid, grid) |
| 54 | self.bubbles[:, 0] = gx.flatten()[:len(self.bubbles)] |
| 55 | self.bubbles[:, 1] = gy.flatten()[:len(self.bubbles)] |
| 56 | |
| 57 | self.com = self.center_of_mass() |
| 58 | |
| 59 | def center_of_mass(self): |
| 60 | return np.average( |
| 61 | self.bubbles[:, :2], axis=0, weights=self.bubbles[:, 3] |
| 62 | ) |
| 63 | |
| 64 | def center_distance(self, bubble, bubbles): |
| 65 | return np.hypot(bubble[0] - bubbles[:, 0], |
| 66 | bubble[1] - bubbles[:, 1]) |
| 67 | |
| 68 | def outline_distance(self, bubble, bubbles): |
| 69 | center_distance = self.center_distance(bubble, bubbles) |
| 70 | return center_distance - bubble[2] - \ |
| 71 | bubbles[:, 2] - self.bubble_spacing |
| 72 | |
| 73 | def check_collisions(self, bubble, bubbles): |
| 74 | distance = self.outline_distance(bubble, bubbles) |
| 75 | return len(distance[distance < 0]) |
| 76 | |
| 77 | def collides_with(self, bubble, bubbles): |
| 78 | distance = self.outline_distance(bubble, bubbles) |
| 79 | return np.argmin(distance, keepdims=True) |
| 80 | |
| 81 | def collapse(self, n_iterations=50): |
no outgoing calls
no test coverage detected
searching dependent graphs…