Python - zutil.py


import base64
from datetime import date
from io import BytesIO

from matplotlib.ticker import MaxNLocator


def fig_to_html(fig):
    """
    Convert a matplotlib.Figure object to html image source
    :param fig:
    :return: the returned value can be used in html like this: 
    """

    buf = BytesIO()
    fig.savefig(buf, format="png")
    figure = base64.b64encode(buf.getbuffer()).decode("ascii")

    return figure


def axes_show_y_value(axes, x_data, y_data):
    for x, y in zip(x_data, y_data):
        axes.annotate(str(y),                       # this is the text
                      (x, y),                       # these are the coordinates to position the label
                      textcoords="offset points",   # how to position the text
                      xytext=(0, 4),                # distance from text to points (x,y)
                      size=8,                       # font size of the text
                      ha='center')                  # horizontal alignment can be left, right or center


def axes_rotate_xticklabels(axes):
    for tick in axes.get_xticklabels():
        tick.set_rotation(45)
        tick.set_size(8)
        tick.set_ha('right')


def axes_general_setting(axes):
    axes.grid(axis='y', linestyle='--', alpha=0.5)
    axes.set_title(axes.get_title(), pad=15)
    axes.set_ylim(ymin=0)                           # make y=0 start from bottom
    axes.yaxis.set_major_locator(MaxNLocator(min_n_ticks=1, integer=True))

    _, y_max = axes.get_ylim()
    if y_max > 1000:
        space = 150
    elif y_max > 100:
        space = 50
    elif y_max > 10:
        space = 5
    else:
        space = 2
    axes.set_ylim(ymax=y_max+space)                 # add some space at the top


def fig_adjust_width(fig, data_points_num, interval=6.4/20):
    if data_points_num * interval > 6.4:
        fig.set_figwidth(data_points_num * interval)


def axes_adjust_xmargins(ax, fig_width, margin=6.4*0.05):
    ax.margins(x=margin/fig_width)


def fig_adjust_xpaddings(fig, padding=6.4*0.1):
    left = padding / fig.get_figwidth()
    right = 1 - left
    fig.subplots_adjust(left=left, right=right)


def get_first_day_of_month(dt: date):
    return date(dt.year, dt.month, 1)


def get_list_span(l: list):
    """
    :param l: 
    :return:
    Example:
        For list ['a', 'a', 'a', 'b', 'c', 'c', 'd', 'd', 'd', 'd'],
        its span list is [3, 0, 0, 1, 2, 0, 4, 0, 0, 0] .
    """

    span_list = []
    span = 1
    for i in range(len(l)):
        if i == 0:                            # 第一项span设为1
            span_list.append(1)
        else:
            if l[i] == l[i-span]:             # 与之前项相等,之前项的span值加1,本项span设为0,span值加1
                span_list[i-span] += 1
                span_list.append(0)
                span += 1
            else:                             # 与之前项不等,本项span设为1,span值恢复为1
                span_list.append(1)
                span = 1
    return span_list


def get_rows_span(rows):
    col_1_list = [row[0] for row in rows]
    return get_list_span(col_1_list)