Create a complex radar chart with different scales for each variable Args: fig (`matplotlib.figure`) : A matplotlib figure object to add the axes on. variables (`list`) : a list of variables to. plot ranges (`list` of `tuples`): A list of ranges (min, max) for each variable n_ri
| 6 | |
| 7 | |
| 8 | class ComplexRadar: |
| 9 | """Create a complex radar chart with different scales for each variable |
| 10 | Args: |
| 11 | fig (`matplotlib.figure`) : A matplotlib figure object to add the axes on. |
| 12 | variables (`list`) : a list of variables to. plot |
| 13 | ranges (`list` of `tuples`): A list of ranges (min, max) for each variable |
| 14 | n_ring_levels (`int): Number of ordinate or ring levels to draw. |
| 15 | Default: 5. |
| 16 | show_scales (`bool`): Indicates if we the ranges for each variable are plotted. |
| 17 | Default: True. |
| 18 | format_cfg (`dict`): A dictionary with formatting configurations. |
| 19 | Default: None. |
| 20 | Returns: |
| 21 | `matplotlib.figure.Figure`: a radar plot. |
| 22 | """ |
| 23 | |
| 24 | def __init__(self, fig, variables, ranges, n_ring_levels=5, show_scales=True, format_cfg=None): |
| 25 | |
| 26 | self.format_cfg = format_cfg |
| 27 | |
| 28 | # Calculate angles and create for each variable an axes |
| 29 | # Consider here the trick with having the first axes element twice (len+1) |
| 30 | angles = np.arange(0, 360, 360.0 / len(variables)) |
| 31 | axes = [ |
| 32 | fig.add_axes([0.1, 0.1, 0.9, 0.9], polar=True, label="axes{}".format(i), **self.format_cfg["axes_args"]) |
| 33 | for i in range(len(variables) + 1) |
| 34 | ] |
| 35 | |
| 36 | # Ensure clockwise rotation (first variable at the top N) |
| 37 | for ax in axes: |
| 38 | ax.set_theta_zero_location("N") |
| 39 | ax.set_theta_direction(-1) |
| 40 | ax.set_axisbelow(True) |
| 41 | |
| 42 | # Writing the ranges on each axes |
| 43 | for i, ax in enumerate(axes): |
| 44 | |
| 45 | # Here we do the trick by repeating the first iteration |
| 46 | j = 0 if (i == 0 or i == 1) else i - 1 |
| 47 | ax.set_ylim(*ranges[j]) |
| 48 | # Set endpoint to True if you like to have values right before the last circle |
| 49 | grid = np.linspace(*ranges[j], num=n_ring_levels, endpoint=self.format_cfg["incl_endpoint"]) |
| 50 | gridlabel = ["{}".format(round(x, 2)) for x in grid] |
| 51 | gridlabel[0] = "" # remove values from the center |
| 52 | lines, labels = ax.set_rgrids( |
| 53 | grid, labels=gridlabel, angle=angles[j], **self.format_cfg["rgrid_tick_lbls_args"] |
| 54 | ) |
| 55 | |
| 56 | ax.set_ylim(*ranges[j]) |
| 57 | ax.spines["polar"].set_visible(False) |
| 58 | ax.grid(visible=False) |
| 59 | |
| 60 | if show_scales is False: |
| 61 | ax.set_yticklabels([]) |
| 62 | |
| 63 | # Set all axes except the first one unvisible |
| 64 | for ax in axes[1:]: |
| 65 | ax.patch.set_visible(False) |
no outgoing calls
no test coverage detected
searching dependent graphs…