美文网首页报告自动化生成Python
5.4 图表绘制 : 作图模板的扩展 : 添加副轴及细分类

5.4 图表绘制 : 作图模板的扩展 : 添加副轴及细分类

作者: 数据成长之路 | 来源:发表于2018-07-26 16:15 被阅读18次
# -*- coding:utf-8 -*-
import numpy as np
import pandas as pd
from IPython.display import Image as ShowImage
import matplotlib.pyplot as plt
import matplotlib as mpl
import matplotlib.font_manager as mfm
import matplotlib.gridspec as gridspec
import matplotlib.ticker as plticker

目标图表形式

ShowImage('./source/twinx.png')
data = pd.read_csv('./source/data_4.csv', index_col=0)
data.head()

继承模板

观察多线图和上一章中柱形图的差异,可以发现以下结构有不同:

  • 画图方式:由折线图和柱状图组成
  • Tick显示:显示日期
  • Legend在上侧
  • y轴的Major tick label左右侧都有,而且还有y轴Label

所以在这些部分我们需要进行相关的自定义

首先我们定义双轴的通用Image类

%run Images.py
class ImageTwinx(Image):
    def __init__(self, title=None, labels=None, data=None, image_path=None, xticks_rotation=40, 
                 legend_name=[], y2=None, title_y=1.2, ylabel_show=True):
        self.ylabel_show = ylabel_show
        self.legend_name = legend_name
        self.marker_style = dict(color=self.default_colors['blue'], linestyle='-')
        # 副轴所用数据
        self.y2 = y2
        super(ImageTwinx, self).__init__(title=title, labels=labels, data=data,
        image_path=image_path, xticks_rotation=xticks_rotation, title_y=title_y, legend_name=legend_name)
     
    
    def config_add(self):
        self.set_ylabel()

    # 此处使用Legend作为y轴的Label
    def set_ylabel(self):
        if self.ylabel_show:
            self.ax.set_ylabel(self.legend_name[0], fontproperties=self.ylable_font)
            self.ax2.set_ylabel(self.legend_name[1], fontproperties=self.ylable_font)

    # 添加副轴,要加入init函数中set_xticks之后,作为初始化的一部分
    def add_ax(self):
        self.ax2 = self.ax.twinx()

    def plot(self):
        self.ax.plot(self.x, self.y, label=self.legend_name[0], **self.marker_style)
        self.ax2.bar(self.x, self.y2, 0.4, zorder=3, label=self.legend_name[1], color=self.default_colors['red'])
        
    def set_spines(self):
        for _ax in [self.ax, self.ax2]:
            _ax.margins(0) # 设置留白
            _ax.spines['right'].set_visible(False)
            _ax.spines['top'].set_visible(False)
            _ax.spines['left'].set_visible(False)
    def set_tick_marks(self):
        self.ax.tick_params(axis='both', which='both', bottom=False, top=False, 
            labelbottom=True, left=False, right=False, labelleft=True)
        self.ax2.tick_params(axis='both', which='both', bottom=False, top=False, 
            labelbottom=True, left=False, right=False)

    def add_legend(self):
        if not (self.legend_name is None):
            if len(self.legend_name) == 2:
                lines1, labels1 = self.ax.get_legend_handles_labels()
                lines2, labels2 = self.ax2.get_legend_handles_labels()
                self.ax.legend(lines1+lines2, labels1+labels2, loc='upper center', ncol=2, bbox_to_anchor=(0.5, 1.27), prop=self.legend_font, frameon=False)
image = ImageTwinx(data=data[u'平均价格($)'],
                        y2=data[u'平均价格变动量($)'],
                        labels=data[u'日期'],
                        title=u'Top100商品每日平均价格',
                        legend_name=[u'平均价格($)', 
                                     u'平均价格变动量($)'],
                        xticks_rotation=0
                        )

image.init()
image.fig
有双轴需要设置副轴grid

此时图表大部分已经符合要求,但是X轴的ticks需要设置下显示方式,对于labels需要间隔显示

def set_xticks(self):
    plt.xticks(range(0,self.length,30), 
               self.labels.loc[[0, 30, 60, 90, 120, 150, 180]], 
               fontproperties=self.xticks_font, 
               rotation=self.xticks_rotation
              )

然后我们需要把set_xticks方法加入ImageTwinx中,这里有三种方式可供选择:

  1. 继承ImageTwinx类做一个新的子类,使用set_xticks方法
  2. 用新的set_xticks方法替换掉ImageTwinx类中的set_xticks方法,相当于对类直接改变
  3. 在实例化之后的ImageTwinx类中bound新的set_xticks方法,需要使用MethodType function in the types module,具体可以参考stackoverflow
class ImageFluctuation(ImageTwinx):
    def set_xticks(self):
        plt.xticks(range(0,self.length,30), self.labels.loc[[0, 30, 60, 90, 120, 150, 180]], fontproperties=self.xticks_font, rotation=self.xticks_rotation)
image = ImageFluctuation(data=data[u'平均价格($)'],
                        y2=data[u'平均价格变动量($)'],
                        labels=data[u'日期'],
                        title=u'Top100商品每日平均价格',
                        legend_name=[u'平均价格($)', 
                                     u'平均价格变动量($)'],
                        xticks_rotation=12 # 设置x轴ticks的倾斜角度为12度
                        )

image.init()
image.fig
有双轴需要设置副轴grid

手动设置Y轴取值范围

# image.fig.savefig('./source/twinx.png',  dpi=160, bbox_inches='tight')

作业

作为作业,可以自行构造一个双轴Bar形图

相关文章

网友评论

    本文标题:5.4 图表绘制 : 作图模板的扩展 : 添加副轴及细分类

    本文链接:https://www.haomeiwen.com/subject/wevbmftx.html