# -*- 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
目標(biāo)圖表形式
ShowImage('./source/twinx.png')
data = pd.read_csv('./source/data_4.csv', index_col=0)
data.head()
繼承模板
觀察多線圖和上一章中柱形圖的差異,可以發(fā)現(xiàn)以下結(jié)構(gòu)有不同:
- 畫圖方式:由折線圖和柱狀圖組成
- Tick顯示:顯示日期
- Legend在上側(cè)
- y軸的Major tick label左右側(cè)都有瘤礁,而且還有y軸Label
所以在這些部分我們需要進(jìn)行相關(guān)的自定義
首先我們定義雙軸的通用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='-')
# 副軸所用數(shù)據(jù)
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函數(shù)中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) # 設(shè)置留白
_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
有雙軸需要設(shè)置副軸grid
此時圖表大部分已經(jīng)符合要求菲驴,但是X軸的ticks需要設(shè)置下顯示方式凄杯,對于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中,這里有三種方式可供選擇:
- 繼承ImageTwinx類做一個新的子類菠秒,使用set_xticks方法
- 用新的set_xticks方法替換掉ImageTwinx類中的set_xticks方法疙剑,相當(dāng)于對類直接改變
- 在實(shí)例化之后的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 # 設(shè)置x軸ticks的傾斜角度為12度
)
image.init()
image.fig
有雙軸需要設(shè)置副軸grid
手動設(shè)置Y軸取值范圍
# image.fig.savefig('./source/twinx.png', dpi=160, bbox_inches='tight')
作業(yè)
作為作業(yè)言缤,可以自行構(gòu)造一個雙軸Bar形圖