Source code for qf_lib.plotting.charts.pie_chart

#     Copyright 2016-present CERN – European Organization for Nuclear Research
#
#     Licensed under the Apache License, Version 2.0 (the "License");
#     you may not use this file except in compliance with the License.
#     You may obtain a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#     Unless required by applicable law or agreed to in writing, software
#     distributed under the License is distributed on an "AS IS" BASIS,
#     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#     See the License for the specific language governing permissions and
#     limitations under the License.
from typing import Tuple

import numpy as np

from qf_lib.containers.series.qf_series import QFSeries
from qf_lib.plotting.charts.chart import Chart


[docs]class PieChart(Chart): """ Pie chart util class, it can plot only QFSeries. Parameters ---------- data: QFSeries The series to plot in the pie chart. slices_distance: float The distance between slices. Default is 0.01 plot_settings Options to pass to the ``pie`` function. """ def __init__(self, data: QFSeries, slices_distance: float = 0.01, **plot_settings): super().__init__() self.plot_settings = plot_settings self.distance = slices_distance self.assert_is_qfseries(data) self.data = data.sort_values(ascending=False)
[docs] def plot(self, figsize: Tuple[float, float] = None) -> None: self._setup_axes_if_necessary(figsize) plot_kwargs = self.plot_settings separate = ((self.distance, ) * len(self.data)) wedges, _ = self.axes.pie(self.data, startangle=90, counterclock=False, explode=separate, **plot_kwargs) arrow_props = { 'arrowstyle': '-', 'color': 'black' } bbox_props = { "boxstyle": "square,pad=0.3", "fc": "w", "ec": "k", "lw": 0.72 } kw = { 'arrowprops': arrow_props, 'bbox': bbox_props, 'zorder': 0, 'va': 'center' } sum_series = self.data.sum() labels = [f"{index}, {value / sum_series:.1%}" for index, value in self.data.items()] for i, p in enumerate(wedges): angle = (p.theta2 - p.theta1) / 2. + p.theta1 y = np.sin(np.deg2rad(angle)) x = np.cos(np.deg2rad(angle)) yc = np.arcsin(y) / (np.pi / 2) connection_style = f"angle,angleA=0,angleB={angle}" kw["arrowprops"].update({"connectionstyle": connection_style}) horizontal_alignment = "right" if x <= 0 else "left" self.axes.annotate(labels[i], xy=(0.8 * x, 0.8 * y), xytext=((1.3 + (i % 2) * 0.4) * np.sign(x), 1.4 * yc), horizontalalignment=horizontal_alignment, **kw) self._apply_decorators() self._adjust_style()