siat 3.10.132__py3-none-any.whl → 3.10.133__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (218) hide show
  1. siat/__init__.py +0 -0
  2. siat/allin.py +0 -0
  3. siat/assets_liquidity.py +0 -0
  4. siat/beta_adjustment.py +0 -0
  5. siat/beta_adjustment_china.py +0 -0
  6. siat/blockchain.py +0 -0
  7. siat/bond.py +0 -0
  8. siat/bond_base.py +0 -0
  9. siat/bond_china.py +0 -0
  10. siat/bond_zh_sina.py +0 -0
  11. siat/capm_beta.py +0 -0
  12. siat/capm_beta2.py +0 -0
  13. siat/compare_cross.py +0 -0
  14. siat/copyrights.py +0 -0
  15. siat/cryptocurrency.py +0 -0
  16. siat/economy.py +0 -0
  17. siat/economy2.py +0 -0
  18. siat/esg.py +0 -0
  19. siat/event_study.py +0 -0
  20. siat/exchange_bond_china.pickle +0 -0
  21. siat/fama_french.py +0 -0
  22. siat/fin_stmt2_yahoo.py +0 -0
  23. siat/financial_base.py +0 -0
  24. siat/financial_statements.py +0 -0
  25. siat/financials.py +0 -0
  26. siat/financials2.py +0 -0
  27. siat/financials_china.py +0 -0
  28. siat/financials_china2.py +0 -0
  29. siat/fund.py +0 -0
  30. siat/fund_china.pickle +0 -0
  31. siat/fund_china.py +0 -0
  32. siat/future_china.py +0 -0
  33. siat/google_authenticator.py +0 -0
  34. siat/grafix.py +0 -0
  35. siat/holding_risk.py +0 -0
  36. siat/luchy_draw.py +0 -0
  37. siat/market_china.py +0 -0
  38. siat/markowitz.py +0 -0
  39. siat/markowitz2.py +0 -0
  40. siat/markowitz2_20250704.py +0 -0
  41. siat/markowitz2_20250705.py +0 -0
  42. siat/markowitz_simple.py +0 -0
  43. siat/ml_cases.py +0 -0
  44. siat/ml_cases_example.py +0 -0
  45. siat/option_china.py +0 -0
  46. siat/option_pricing.py +0 -0
  47. siat/other_indexes.py +0 -0
  48. siat/risk_adjusted_return.py +0 -0
  49. siat/risk_adjusted_return2.py +0 -0
  50. siat/risk_evaluation.py +0 -0
  51. siat/risk_free_rate.py +0 -0
  52. siat/sector_china.py +0 -0
  53. siat/security_price2.py +0 -0
  54. siat/security_prices.py +40 -2
  55. siat/security_trend.py +0 -0
  56. siat/security_trend2.py +0 -0
  57. siat/stock.py +0 -0
  58. siat/stock_advice_linear.py +0 -0
  59. siat/stock_base.py +0 -0
  60. siat/stock_china.py +0 -0
  61. siat/stock_info.pickle +0 -0
  62. siat/stock_prices_kneighbors.py +0 -0
  63. siat/stock_prices_linear.py +0 -0
  64. siat/stock_profile.py +0 -0
  65. siat/stock_technical.py +0 -0
  66. siat/stooq.py +0 -0
  67. siat/transaction.py +0 -0
  68. siat/translate.py +0 -0
  69. siat/valuation.py +0 -0
  70. siat/valuation_china.py +0 -0
  71. siat/var_model_validation.py +0 -0
  72. siat/yf_name.py +0 -0
  73. {siat-3.10.132.dist-info/licenses → siat-3.10.133.dist-info}/LICENSE +0 -0
  74. {siat-3.10.132.dist-info → siat-3.10.133.dist-info}/METADATA +232 -235
  75. siat-3.10.133.dist-info/RECORD +78 -0
  76. {siat-3.10.132.dist-info → siat-3.10.133.dist-info}/WHEEL +1 -1
  77. {siat-3.10.132.dist-info → siat-3.10.133.dist-info}/top_level.txt +0 -1
  78. build/lib/build/lib/siat/__init__.py +0 -75
  79. build/lib/build/lib/siat/allin.py +0 -137
  80. build/lib/build/lib/siat/assets_liquidity.py +0 -915
  81. build/lib/build/lib/siat/beta_adjustment.py +0 -1058
  82. build/lib/build/lib/siat/beta_adjustment_china.py +0 -548
  83. build/lib/build/lib/siat/blockchain.py +0 -143
  84. build/lib/build/lib/siat/bond.py +0 -2900
  85. build/lib/build/lib/siat/bond_base.py +0 -992
  86. build/lib/build/lib/siat/bond_china.py +0 -100
  87. build/lib/build/lib/siat/bond_zh_sina.py +0 -143
  88. build/lib/build/lib/siat/capm_beta.py +0 -783
  89. build/lib/build/lib/siat/capm_beta2.py +0 -887
  90. build/lib/build/lib/siat/common.py +0 -5360
  91. build/lib/build/lib/siat/compare_cross.py +0 -642
  92. build/lib/build/lib/siat/copyrights.py +0 -18
  93. build/lib/build/lib/siat/cryptocurrency.py +0 -667
  94. build/lib/build/lib/siat/economy.py +0 -1471
  95. build/lib/build/lib/siat/economy2.py +0 -1853
  96. build/lib/build/lib/siat/esg.py +0 -536
  97. build/lib/build/lib/siat/event_study.py +0 -815
  98. build/lib/build/lib/siat/fama_french.py +0 -1521
  99. build/lib/build/lib/siat/fin_stmt2_yahoo.py +0 -982
  100. build/lib/build/lib/siat/financial_base.py +0 -1160
  101. build/lib/build/lib/siat/financial_statements.py +0 -598
  102. build/lib/build/lib/siat/financials.py +0 -2339
  103. build/lib/build/lib/siat/financials2.py +0 -1278
  104. build/lib/build/lib/siat/financials_china.py +0 -4433
  105. build/lib/build/lib/siat/financials_china2.py +0 -2212
  106. build/lib/build/lib/siat/fund.py +0 -629
  107. build/lib/build/lib/siat/fund_china.py +0 -3307
  108. build/lib/build/lib/siat/future_china.py +0 -551
  109. build/lib/build/lib/siat/google_authenticator.py +0 -47
  110. build/lib/build/lib/siat/grafix.py +0 -3636
  111. build/lib/build/lib/siat/holding_risk.py +0 -867
  112. build/lib/build/lib/siat/luchy_draw.py +0 -638
  113. build/lib/build/lib/siat/market_china.py +0 -1168
  114. build/lib/build/lib/siat/markowitz.py +0 -2363
  115. build/lib/build/lib/siat/markowitz2.py +0 -3150
  116. build/lib/build/lib/siat/markowitz2_20250704.py +0 -2969
  117. build/lib/build/lib/siat/markowitz2_20250705.py +0 -3158
  118. build/lib/build/lib/siat/markowitz_simple.py +0 -373
  119. build/lib/build/lib/siat/ml_cases.py +0 -2291
  120. build/lib/build/lib/siat/ml_cases_example.py +0 -60
  121. build/lib/build/lib/siat/option_china.py +0 -3069
  122. build/lib/build/lib/siat/option_pricing.py +0 -1925
  123. build/lib/build/lib/siat/other_indexes.py +0 -409
  124. build/lib/build/lib/siat/risk_adjusted_return.py +0 -1576
  125. build/lib/build/lib/siat/risk_adjusted_return2.py +0 -1900
  126. build/lib/build/lib/siat/risk_evaluation.py +0 -2218
  127. build/lib/build/lib/siat/risk_free_rate.py +0 -351
  128. build/lib/build/lib/siat/sector_china.py +0 -4140
  129. build/lib/build/lib/siat/security_price2.py +0 -727
  130. build/lib/build/lib/siat/security_prices.py +0 -3408
  131. build/lib/build/lib/siat/security_trend.py +0 -402
  132. build/lib/build/lib/siat/security_trend2.py +0 -646
  133. build/lib/build/lib/siat/stock.py +0 -4284
  134. build/lib/build/lib/siat/stock_advice_linear.py +0 -934
  135. build/lib/build/lib/siat/stock_base.py +0 -26
  136. build/lib/build/lib/siat/stock_china.py +0 -2095
  137. build/lib/build/lib/siat/stock_prices_kneighbors.py +0 -910
  138. build/lib/build/lib/siat/stock_prices_linear.py +0 -386
  139. build/lib/build/lib/siat/stock_profile.py +0 -707
  140. build/lib/build/lib/siat/stock_technical.py +0 -3305
  141. build/lib/build/lib/siat/stooq.py +0 -74
  142. build/lib/build/lib/siat/transaction.py +0 -347
  143. build/lib/build/lib/siat/translate.py +0 -5183
  144. build/lib/build/lib/siat/valuation.py +0 -1378
  145. build/lib/build/lib/siat/valuation_china.py +0 -2076
  146. build/lib/build/lib/siat/var_model_validation.py +0 -444
  147. build/lib/build/lib/siat/yf_name.py +0 -811
  148. build/lib/siat/__init__.py +0 -75
  149. build/lib/siat/allin.py +0 -137
  150. build/lib/siat/assets_liquidity.py +0 -915
  151. build/lib/siat/beta_adjustment.py +0 -1058
  152. build/lib/siat/beta_adjustment_china.py +0 -548
  153. build/lib/siat/blockchain.py +0 -143
  154. build/lib/siat/bond.py +0 -2900
  155. build/lib/siat/bond_base.py +0 -992
  156. build/lib/siat/bond_china.py +0 -100
  157. build/lib/siat/bond_zh_sina.py +0 -143
  158. build/lib/siat/capm_beta.py +0 -783
  159. build/lib/siat/capm_beta2.py +0 -887
  160. build/lib/siat/common.py +0 -5360
  161. build/lib/siat/compare_cross.py +0 -642
  162. build/lib/siat/copyrights.py +0 -18
  163. build/lib/siat/cryptocurrency.py +0 -667
  164. build/lib/siat/economy.py +0 -1471
  165. build/lib/siat/economy2.py +0 -1853
  166. build/lib/siat/esg.py +0 -536
  167. build/lib/siat/event_study.py +0 -815
  168. build/lib/siat/fama_french.py +0 -1521
  169. build/lib/siat/fin_stmt2_yahoo.py +0 -982
  170. build/lib/siat/financial_base.py +0 -1160
  171. build/lib/siat/financial_statements.py +0 -598
  172. build/lib/siat/financials.py +0 -2339
  173. build/lib/siat/financials2.py +0 -1278
  174. build/lib/siat/financials_china.py +0 -4433
  175. build/lib/siat/financials_china2.py +0 -2212
  176. build/lib/siat/fund.py +0 -629
  177. build/lib/siat/fund_china.py +0 -3307
  178. build/lib/siat/future_china.py +0 -551
  179. build/lib/siat/google_authenticator.py +0 -47
  180. build/lib/siat/grafix.py +0 -3636
  181. build/lib/siat/holding_risk.py +0 -867
  182. build/lib/siat/luchy_draw.py +0 -638
  183. build/lib/siat/market_china.py +0 -1168
  184. build/lib/siat/markowitz.py +0 -2363
  185. build/lib/siat/markowitz2.py +0 -3150
  186. build/lib/siat/markowitz2_20250704.py +0 -2969
  187. build/lib/siat/markowitz2_20250705.py +0 -3158
  188. build/lib/siat/markowitz_simple.py +0 -373
  189. build/lib/siat/ml_cases.py +0 -2291
  190. build/lib/siat/ml_cases_example.py +0 -60
  191. build/lib/siat/option_china.py +0 -3069
  192. build/lib/siat/option_pricing.py +0 -1925
  193. build/lib/siat/other_indexes.py +0 -409
  194. build/lib/siat/risk_adjusted_return.py +0 -1576
  195. build/lib/siat/risk_adjusted_return2.py +0 -1900
  196. build/lib/siat/risk_evaluation.py +0 -2218
  197. build/lib/siat/risk_free_rate.py +0 -351
  198. build/lib/siat/sector_china.py +0 -4140
  199. build/lib/siat/security_price2.py +0 -727
  200. build/lib/siat/security_prices.py +0 -3408
  201. build/lib/siat/security_trend.py +0 -402
  202. build/lib/siat/security_trend2.py +0 -646
  203. build/lib/siat/stock.py +0 -4284
  204. build/lib/siat/stock_advice_linear.py +0 -934
  205. build/lib/siat/stock_base.py +0 -26
  206. build/lib/siat/stock_china.py +0 -2095
  207. build/lib/siat/stock_prices_kneighbors.py +0 -910
  208. build/lib/siat/stock_prices_linear.py +0 -386
  209. build/lib/siat/stock_profile.py +0 -707
  210. build/lib/siat/stock_technical.py +0 -3305
  211. build/lib/siat/stooq.py +0 -74
  212. build/lib/siat/transaction.py +0 -347
  213. build/lib/siat/translate.py +0 -5183
  214. build/lib/siat/valuation.py +0 -1378
  215. build/lib/siat/valuation_china.py +0 -2076
  216. build/lib/siat/var_model_validation.py +0 -444
  217. build/lib/siat/yf_name.py +0 -811
  218. siat-3.10.132.dist-info/RECORD +0 -218
build/lib/siat/grafix.py DELETED
@@ -1,3636 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- """
3
- 本模块功能:绘制折线图,单线,双线,多线
4
- 所属工具包:证券投资分析工具SIAT
5
- SIAT:Security Investment Analysis Tool
6
- 创建日期:2020年9月16日
7
- 最新修订日期:2020年9月16日
8
- 作者:王德宏 (WANG Dehong, Peter)
9
- 作者单位:北京外国语大学国际商学院
10
- 作者邮件:wdehong2000@163.com
11
- 版权所有:王德宏
12
- 用途限制:仅限研究与教学使用,不可商用!商用需要额外授权。
13
- 特别声明:作者不对使用本工具进行证券投资导致的任何损益负责!
14
- """
15
-
16
- #==============================================================================
17
- #关闭所有警告
18
- import warnings; warnings.filterwarnings('ignore')
19
- from siat.common import *
20
- from siat.translate import *
21
- import pandas as pd
22
- #==============================================================================
23
- import matplotlib.pyplot as plt
24
- import matplotlib.dates as mdate
25
- #import matplotlib.font_manager as fm
26
- #==============================================================================
27
-
28
- #设置刻度线风格:in,out,inout
29
- plt.rcParams['xtick.direction'] = 'inout' # 将x轴的刻度线方向设置向内
30
- plt.rcParams['ytick.direction'] = 'inout' # 将y轴的刻度方向设置向内内
31
-
32
- #统一设定绘制的图片大小:数值为英寸,1英寸=100像素
33
- #plt.rcParams['figure.figsize']=(12.8,7.2)
34
- plt.rcParams['figure.figsize']=(12.8,6.4)
35
- plt.rcParams['figure.dpi']=300
36
- plt.rcParams['font.size'] = 13
37
- plt.rcParams['xtick.labelsize']=11 #横轴字体大小
38
- plt.rcParams['ytick.labelsize']=11 #纵轴字体大小
39
-
40
- plt.rcParams['figure.facecolor']='whitesmoke' #背景颜色
41
- #plt.rcParams['axes.facecolor']='whitesmoke' #背景颜色
42
- #plt.figure(facecolor='whitesmoke')
43
-
44
- title_txt_size=16
45
- ylabel_txt_size=12
46
- xlabel_txt_size=12
47
- legend_txt_size=12
48
- annotate_size=11
49
-
50
- if check_language() == "English":
51
- title_txt_size=20
52
- ylabel_txt_size=16
53
- xlabel_txt_size=16
54
- legend_txt_size=16
55
- annotate_size=13
56
-
57
- #设置绘图风格:网格虚线
58
- plt.rcParams['axes.grid']=False
59
- #plt.rcParams['grid.color']='steelblue'
60
- #plt.rcParams['grid.linestyle']='dashed'
61
- #plt.rcParams['grid.linewidth']=0.5
62
-
63
-
64
- #设置x,y 的主刻度定位器
65
- #from matplotlib.pyplot import MultipleLocator
66
-
67
-
68
- #处理绘图汉字乱码问题
69
- import sys; czxt=sys.platform
70
- if czxt in ['win32','win64']:
71
- #设置中文字体
72
- """
73
- plt.rcParams['font.sans-serif'] = ['SimHei'] # 设置默认字体
74
- mpfrc={'font.family': 'SimHei'}
75
- """
76
- plt.rcParams['font.sans-serif'] = ['SimHei'] # 设置默认字体
77
- mpfrc={'font.family': 'SimHei'}
78
-
79
- if check_language() == "English":
80
- #设置英文字体
81
- plt.rcParams['font.sans-serif'] = ['Times New Roman'] # 设置默认字体
82
- mpfrc={'font.family': 'Times New Roman'}
83
-
84
- if czxt in ['darwin']: #MacOSX
85
- plt.rcParams['font.family']= ['Heiti TC']
86
- mpfrc={'font.family': 'Heiti TC'}
87
-
88
- if czxt in ['linux']: #website Jupyter
89
- plt.rcParams['font.family']= ['Heiti TC']
90
- mpfrc={'font.family':'Heiti TC'}
91
-
92
- # 解决保存图像时'-'显示为方块的问题
93
- plt.rcParams['axes.unicode_minus'] = False
94
- #==============================================================================
95
- if __name__ =="__main__":
96
- df0=get_price('000001.SS','2023-1-1','2024-3-22')
97
- df0=get_price('sz149995','2020-1-1','2024-3-31')
98
- df0,_=get_price_1ticker('sz149976',fromdate='2024-1-1',todate='2024-4-6',fill=True)
99
-
100
- colname='Close'
101
- collabel='Close'
102
- ylabeltxt='Close'
103
- titletxt='Title'
104
- footnote='footnote'
105
- datatag=False
106
- power=0
107
- zeroline=False
108
- average_value=False
109
- resample_freq='D'
110
- loc='best'
111
- date_range=False
112
- date_freq=False
113
- date_fmt='%Y-%m-%d'
114
- mark_top=True
115
- mark_bottom=True
116
-
117
- plot_line(df0,colname,collabel,ylabeltxt,titletxt,footnote,mark_top=True,mark_bottom=True)
118
-
119
- def plot_line(df0,colname,collabel,ylabeltxt,titletxt,footnote,datatag=False, \
120
- power=0,zeroline=False, \
121
- attention_value='',attention_value_area='', \
122
- attention_point='',attention_point_area='', \
123
- average_value=False, \
124
-
125
- resample_freq='D',loc='best', \
126
- date_range=False,date_freq=False,date_fmt='%Y-%m-%d', \
127
- mark_start=False,mark_top=True,mark_bottom=True,mark_end=True, \
128
- facecolor='whitesmoke',maxticks=15,translate=False):
129
- """
130
- 功能:绘制折线图。如果power=0不绘制趋势图,否则绘制多项式趋势图
131
- 假定:数据表有索引,且已经按照索引排序
132
- 输入:数据表df,数据表中的列名colname,列名的标签collabel;y轴标签ylabeltxt;
133
- 标题titletxt,脚注footnote;是否在图中标记数据datatag;趋势图的多项式次数power
134
- mark_top,mark_bottom:是否标记最高最低点
135
- 输出:折线图
136
- 返回值:无
137
- 注意1:需要日期类型作为df索引
138
- 注意2:date_freq不为False时,必须设置date_range=True,否则无法完成日期设置!
139
- """
140
- DEBUG=False
141
-
142
- import pandas as pd
143
-
144
- #空值判断
145
- if len(df0) ==0:
146
- print (" #Warning(plot_line): no data to plot.")
147
- return
148
-
149
- #插值平滑:未填充时
150
- #if 'filled' not in list(df0):
151
- try:
152
- df0x=df0[[colname]].astype('float')
153
- df=df_smooth_manual(df0x,resample_freq=resample_freq)
154
- except:
155
- df=df0
156
- #else: df=df0
157
-
158
- print('')
159
- #先绘制折线图
160
- date_start=df.index[0]
161
- date_end=df.index[-1]
162
- ax=plt.gca()
163
-
164
- if date_range and not date_freq:
165
- ax.xaxis.set_major_formatter(mdate.DateFormatter(date_fmt))
166
- plt.xticks(pd.date_range(date_start,date_end))
167
- if not date_range and date_freq:
168
- ax.xaxis.set_major_formatter(mdate.DateFormatter(date_fmt))
169
- plt.xticks(pd.date_range(freq=date_freq))
170
- if date_range and date_freq:
171
- ax.xaxis.set_major_formatter(mdate.DateFormatter(date_fmt))
172
- plt.xticks(pd.date_range(date_start,date_end,freq=date_freq))
173
-
174
- if ylabeltxt != '' or ylabeltxt == "stooq_MB":
175
- collabel=''
176
- if ylabeltxt == "stooq_MB":
177
- ylabeltxt=''
178
-
179
- lwadjust=linewidth_adjust(df)
180
-
181
- #if 'filled' not in list(df):
182
- if translate:
183
- collabel=lang_auto2(collabel)
184
-
185
- if DEBUG: print(f"df.index: {df.index}")
186
- plt.plot(df.index,df[colname],'-',label=collabel, \
187
- linestyle='-',color='blue', linewidth=lwadjust)
188
- """
189
- else:
190
- #区分实际有数据部分和填充部分
191
- df_raw=df[df['filled'] == False] #原有数据
192
- df_filled=df[df['filled'] != False] #填充的数据
193
-
194
- plt.plot(df_filled.index,df_filled[colname],'-',label=collabel, \
195
- linestyle=':',color='black', linewidth=lwadjust)
196
-
197
- plt.plot(df_raw.index,df_raw[colname],'-',label=collabel, \
198
- linestyle='-',color='blue', linewidth=lwadjust)
199
- """
200
- haveLegend=True
201
- if collabel == '':
202
- haveLegend=False
203
-
204
- #绘制数据标签
205
- if datatag:
206
- mark_start=False; mark_top=False; mark_bottom=False; mark_end=False
207
- for x, y in zip(df.index, df[colname]):
208
- plt.text(x,y*1.001,'%.2f' % y,ha='center',va='bottom',color='black')
209
-
210
- #标记最高点/最低点
211
- if mark_top or mark_bottom:
212
- df_mark=df[[colname]].copy() #避免影响原df
213
- df_mark.sort_values(by=colname,ascending=False,inplace=True)
214
-
215
- high_poit=df_mark[colname].head(1).values[0]
216
- low_poit=df_mark[colname].tail(1).values[0]
217
- high_low=high_poit - low_poit
218
- if mark_top:
219
- df_mark_top=df_mark[:1]
220
- for x, y in zip(df_mark_top.index, df_mark_top[colname]):
221
- #plt.text(x,y+0.1,'%.2f' % y,ha='center',va='bottom',color='red')
222
- #y1=round(y+high_low*0.01,2)
223
- y1=y+high_low*0.01
224
- #s='%.0f' if y >= 100 else '%.2f'
225
- s='%.1f' if abs(y) >= 100 else '%.2f' if abs(y) >= 1 else '%.4f'
226
- plt.text(x,y1,s % y,ha='right',va='bottom',color='red')
227
- """
228
- s='%.0f' if y >= 100 else '%.2f'
229
- plt.text(x,y,s % y,ha='right',va='bottom',color='red')
230
- """
231
- plt.scatter(x,y, color='red',marker='8',s=70)
232
-
233
- if mark_bottom:
234
- df_mark_bottom=df_mark[-1:]
235
- for x, y in zip(df_mark_bottom.index, df_mark_bottom[colname]):
236
- #plt.text(x,y-0.1,'%.2f' % y,ha='center',va='bottom',color='black')
237
- #y1=round(y-high_low*0.055,2) #标记位置对应y1的底部
238
- y1=y-high_low*0.050 #标记位置对应y1的底部
239
- #s='%.0f' if y >= 100 else '%.2f'
240
- #s='%.2f' if abs(y) >= 100 else '%.2f' if abs(y) >= 10 else '%.4f'
241
- s='%.1f' if abs(y) >= 100 else '%.2f' if abs(y) >= 1 else '%.4f'
242
- #plt.text(x,y1,s % y,ha='center',va='bottom',color='seagreen')
243
- plt.text(x,y1,s % y,ha='right',va='bottom',color='seagreen')
244
- plt.scatter(x,y, color='seagreen',marker='8',s=70)
245
-
246
- #标记曲线开始数值
247
- if mark_start:
248
- df_start=df.head(1)
249
- y_start = df_start[colname].min() # 开始的y坐标
250
- x_start = df_start[colname].idxmin() # 开始值的x坐标
251
-
252
- #y1=str(int(y_end)) if y_end >= 100 else str(round(y_end,2))
253
- y1=str(round(y_start,1)) if abs(y_start) >= 100 else str(round(y_start,2)) if abs(y_start) >= 1 else str(round(y_start,3))
254
- plt.annotate(text=y1,
255
- xy=(x_start, y_start),
256
- xytext=(x_start, y_start*0.998),fontsize=annotate_size,ha='right',va='center')
257
- # 特别注意:这里的left/right与实际图示的方向正好相反!!!
258
-
259
- #标记曲线末端数值
260
- if mark_end:
261
- df_end=df.tail(1)
262
- y_end = df_end[colname].min() # 末端的y坐标
263
- x_end = df_end[colname].idxmin() # 末端值的x坐标
264
-
265
- #y1=str(int(y_end)) if y_end >= 100 else str(round(y_end,2))
266
- y1=str(round(y_end,1)) if abs(y_end) >= 100 else str(round(y_end,2)) if abs(y_end) >= 1 else str(round(y_end,3))
267
- plt.annotate(text=' '+y1,
268
- xy=(x_end, y_end),
269
- xytext=(x_end, y_end*0.998),fontsize=annotate_size,ha='left',va='center')
270
-
271
- #是否绘制水平线
272
- if isinstance(zeroline,bool):#若zeroline为True
273
- if zeroline:
274
- hline=0
275
- #plt.axhline(y=hline,ls=":",c="green",linewidth=2,label="零线")
276
- plt.axhline(y=hline,ls=":",c="black",linewidth=2,label='')
277
- haveLegend=False
278
- else:
279
- #不在必要,被attention_value的逻辑替代
280
- if isinstance(zeroline,float) or isinstance(zeroline,int):
281
- hline=zeroline
282
- plt.axhline(y=hline,ls=":",c="darkorange",linewidth=3,label=text_lang("关注值","Attention"))
283
- haveLegend=True
284
- footnote=footnote + text_lang(",关注值",", Attention ")+str(hline)
285
-
286
- #用于关注值的颜色列表
287
- atv_color_list=["lightgray","paleturquoise","wheat","khaki","lightsage"]
288
- #用于关注点的颜色列表
289
- atp_color_list=["crimson","dodgerblue","magenta","lightseagreen","chocolate"]
290
-
291
- if not attention_value=='':
292
- if isinstance(attention_value,int) or isinstance(attention_value,float):
293
- atv_list=[attention_value]
294
- elif isinstance(attention_value,list):
295
- atv_list=attention_value
296
- else:
297
- atv_list=[]
298
- if not atv_list==[] and not atv_list==['']:
299
- for at in atv_list:
300
- pos=atv_list.index(at)
301
- color=atv_color_list[pos]
302
- plt.axhline(y=at,ls=":",c=color,linewidth=2,label=text_lang("关注值","Attention value ")+str(at))
303
-
304
- if not attention_value_area=='':
305
- if isinstance(attention_value_area,list) and len(attention_value_area)>=2:
306
- plt.fill_between(df.index,attention_value_area[0],attention_value_area[1],color='lightgray',alpha=0.5)
307
-
308
- import pandas as pd
309
- from datetime import datetime; date_format="%Y-%m-%d"
310
- if not attention_point=='':
311
- if isinstance(attention_point,str) or isinstance(attention_point,int) or isinstance(attention_point,float):
312
- atp_list=[attention_point]
313
- elif isinstance(attention_point,list):
314
- atp_list=attention_point
315
- else:
316
- atp_list=[]
317
- #去重,不打乱原来的顺序
318
- atp_list=list(dict.fromkeys(atp_list))
319
-
320
- if not atp_list==[] and not atp_list==['']:
321
-
322
- for at in atp_list:
323
- pos=atp_list.index(at)
324
- color=atp_color_list[pos]
325
-
326
- #判断是否日期字符串
327
- try:
328
- #at=datetime.strptime(at, date_format)
329
- atpd=pd.to_datetime(at)
330
- except:
331
- atpd=at
332
-
333
- if DEBUG: print(f"atpd={atpd}")
334
-
335
- try:
336
- at_str=atpd.strftime('%Y-%m-%d')
337
- except:
338
- at_str=atpd
339
- #plt.axvline(x=atpd,ls=":",c=color,linewidth=1.5,label=text_lang("关注点","Attention point ")+str(at))
340
- plt.axvline(x=atpd,ls=":",c=color,linewidth=1.5,label=text_lang("关注点","Attention point ")+at_str)
341
-
342
- if not attention_point_area=='':
343
- if isinstance(attention_point_area,list) and len(attention_point_area)>=2:
344
- apa_list=[]
345
- for ap in attention_point_area:
346
- try:
347
- #ap=datetime.strptime(ap, date_format)
348
- appd=pd.to_datetime(ap)
349
- except:
350
- appd=ap
351
- apa_list=apa_list+[appd]
352
-
353
- yaxis_data=plt.ylim()
354
-
355
- if DEBUG:
356
- print(f"yaxis_data={yaxis_data}")
357
- print(f"apa_list[0]={apa_list[0]}")
358
- print(f"apa_list[1]={apa_list[1]}")
359
- plt.fill_betweenx(yaxis_data,apa_list[0],apa_list[1],color='powderblue',alpha=0.5)
360
-
361
- if average_value:
362
- haveLegend=True
363
-
364
- av=df[colname].mean()
365
- #av=str(round(av,2)) if av < 100 else str(int(av))
366
- #av=str(int(av)) if abs(av) >= 100 else str(round(av,2)) if abs(av) >= 10 else str(round(av,3))
367
- avstr=str(int(av)) if abs(av) >= 100 else str(round(av,2)) if abs(av) >= 10 else str(round(av,3))
368
- plt.axhline(y=av,ls="dashed",c="blueviolet",linewidth=2,label=text_lang("本期间均值","Periodic mean ")+avstr)
369
- #footnote=footnote + ",均值"+av
370
- #footnote=text_lang("注:期间均值","Note: Periodic mean ")+av+"; "+footnote
371
-
372
- #绘制趋势线
373
- #print("--Debug(plot_line): power=",power)
374
- if power > 0:
375
- trend_txt=text_lang('趋势线','Trend line')
376
-
377
- try:
378
- #生成行号,借此将横轴的日期数量化,以便拟合
379
- df['id']=range(len(df))
380
-
381
- #设定多项式拟合,power为多项式次数
382
- import numpy as np
383
- parameter = np.polyfit(df.id, df[colname], power)
384
- f = np.poly1d(parameter)
385
- plt.plot(df.index, f(df.id),"r--", label=trend_txt,linewidth=1)
386
- haveLegend=True
387
- except:
388
- print(" #Warning(plot_line): failed to converge trend line, try a smaller power.")
389
-
390
- if ylabeltxt != '' or average_value or isinstance(zeroline,bool):
391
- if haveLegend:
392
- plt.legend(loc=loc,fontsize=legend_txt_size)
393
-
394
- # 使用 AutoDateLocator 自动选择最佳间隔,目的是显示最后一个日期,亲测有效!!!
395
- import matplotlib.dates as mdates
396
- ax.xaxis.set_major_locator(mdates.AutoDateLocator(maxticks=maxticks))
397
-
398
- plt.gcf().autofmt_xdate(ha="center") # 优化标注(自动倾斜)
399
- try:
400
- plt.gca().set_facecolor(facecolor) #设置画布背景颜色
401
- except:
402
- print(" #Warning(plot_line): color",facecolor,"is unsupported, changed to default setting")
403
- plt.gca().set_facecolor("whitesmoke")
404
-
405
- if '基金' in titletxt and '收盘价' in ylabeltxt and not ('基金指数' in titletxt):
406
- ylabeltxt=ylabeltxt.replace('收盘价','单位净值')
407
-
408
- if translate:
409
- ylabeltxt=lang_auto2(ylabeltxt)
410
- footnote=lang_auto2(footnote)
411
- titletxt=lang_auto2(titletxt)
412
-
413
- plt.ylabel(ylabeltxt,fontsize=ylabel_txt_size)
414
- plt.xlabel(footnote,fontsize=xlabel_txt_size,ha='center')
415
- plt.title(titletxt,fontweight='bold',fontsize=title_txt_size)
416
-
417
- if haveLegend:
418
- plt.legend(loc=loc,fontsize=legend_txt_size)
419
-
420
- plt.show()
421
- plt.close()
422
-
423
- return
424
-
425
-
426
- #==============================================================================
427
- if __name__ =="__main__":
428
- df1=df2=option_comm_china(symbol='黄金期权',contract='au2508',printout=False,graph=False)
429
-
430
- ticker1='看涨期权'; ticker2='看跌期权'
431
- colname1='最新价C'; colname2='最新价P'
432
- label1=label2=ylabeltxt='价格'
433
- twinx=True
434
-
435
- power=0
436
- datatag1=False
437
- datatag2=False
438
- yscalemax=5
439
- zeroline=False
440
- twinx=False
441
- yline=999
442
- xline=999
443
- resample_freq='D'
444
-
445
- attention_value_area=''; attention_point_area=''
446
- loc1='best'; loc2='best'
447
- color1='red'; color2='blue'; facecolor='whitesmoke'; maxticks=20
448
-
449
- def plot_line2(df1,ticker1,colname1,label1, \
450
- df2,ticker2,colname2,label2, \
451
- ylabeltxt,titletxt,footnote, \
452
- power=0,datatag1=False,datatag2=False,yscalemax=5, \
453
- zeroline=False, \
454
- twinx=False, \
455
- yline=999,attention_value_area='', \
456
- xline=999,attention_point_area='', \
457
- resample_freq='D',loc1='best',loc2='best', \
458
- color1='red',color2='blue',facecolor='whitesmoke', \
459
- maxticks=20):
460
- """
461
- 功能:绘制两个证券的折线图。如果power=0不绘制趋势图,否则绘制多项式趋势图
462
- 假定:数据表有索引,且已经按照索引排序
463
- 输入:
464
- 证券1:数据表df1,证券代码ticker1,列名1,列名标签1;
465
- 证券2:数据表df2,证券代码ticker2,列名2,列名标签2;
466
- 标题titletxt,脚注footnote;是否在图中标记数据datatag;趋势图的多项式次数power
467
- 输出:默认绘制同轴折线图,若twinx=True则绘制双轴折线图
468
- 返回值:无
469
- 注意:需要日期类型作为df索引
470
- """
471
- DEBUG=False
472
-
473
- #空值判断
474
- if len(df1) ==0:
475
- print (" #Warning(plot_line2): no data to plot df1.")
476
- if len(df2) ==0:
477
- print (" #Warning(plot_line2): no data to plot df2.")
478
- if (len(df1) ==0) and (len(df2) ==0):
479
- pass
480
- return
481
-
482
- if DEBUG:
483
- print("In plot_line2")
484
- print("Going to plot_line2_coaxial")
485
- print("yline=",yline,"; xline=",xline)
486
-
487
- #if not twinx:
488
- if twinx == True: # 双轴会图
489
- plot_line2_twinx(df1,ticker1,colname1,label1, \
490
- df2,ticker2,colname2,label2, \
491
- titletxt,footnote,power,datatag1,datatag2, \
492
- resample_freq=resample_freq, \
493
- xline=xline,attention_point_area=attention_point_area, \
494
- loc1=loc1,loc2=loc2, \
495
- color1=color1,color2=color2,facecolor=facecolor, \
496
- maxticks=maxticks)
497
- elif twinx == False: # twinx == False # 正常绘图
498
- plot_line2_coaxial(df1,ticker1,colname1,label1, \
499
- df2,ticker2,colname2,label2, \
500
- ylabeltxt,titletxt,footnote,power,datatag1,datatag2,zeroline, \
501
- yline=yline,attention_value_area=attention_value_area, \
502
- xline=xline,attention_point_area=attention_point_area, \
503
- resample_freq=resample_freq, \
504
- loc1=loc1,loc2=loc2, \
505
- color1=color1,color2=color2,facecolor=facecolor, \
506
- maxticks=maxticks)
507
-
508
- elif 'LR' in twinx.upper(): # 左右双图
509
- plot_line2_LR(df1,ticker1,colname1,label1, \
510
- df2,ticker2,colname2,label2, \
511
- titletxt,footnote,power,datatag1,datatag2, \
512
- resample_freq=resample_freq, \
513
- xline=xline,attention_point_area=attention_point_area, \
514
- loc1=loc1,loc2=loc2, \
515
- color1=color1,color2=color2,facecolor=facecolor, \
516
- maxticks=maxticks)
517
- elif 'UD' in twinx.upper(): # 上下双图
518
- plot_line2_UD(df1,ticker1,colname1,label1, \
519
- df2,ticker2,colname2,label2, \
520
- titletxt,footnote,power,datatag1,datatag2, \
521
- resample_freq=resample_freq, \
522
- xline=xline,attention_point_area=attention_point_area, \
523
- loc1=loc1,loc2=loc2, \
524
- color1=color1,color2=color2,facecolor=facecolor, \
525
- maxticks=maxticks)
526
-
527
- else: # twinx == False # 正常绘图
528
- plot_line2_coaxial(df1,ticker1,colname1,label1, \
529
- df2,ticker2,colname2,label2, \
530
- ylabeltxt,titletxt,footnote,power,datatag1,datatag2,zeroline, \
531
- yline=yline,attention_value_area=attention_value_area, \
532
- xline=xline,attention_point_area=attention_point_area, \
533
- resample_freq=resample_freq, \
534
- loc1=loc1,loc2=loc2, \
535
- color1=color1,color2=color2,facecolor=facecolor, \
536
- maxticks=maxticks)
537
-
538
- return
539
-
540
-
541
- #==============================================================================
542
- def plot2_line2(df1,ticker1,colname1,label1, \
543
- df2,ticker2,colname2,label2, \
544
- ylabeltxt,titletxt,footnote, \
545
- power=0,datatag1=False,datatag2=False,yscalemax=5, \
546
- zeroline=False,twinx=False, \
547
- yline=999,attention_value_area='', \
548
- xline=999,attention_point_area='', \
549
- resample_freq='D',loc1='best',loc2='best', \
550
- date_range=False,date_freq=False,date_fmt='%Y-%m-%d', \
551
- color1='red',color2='blue',facecolor='whitesmoke', \
552
- maxticks=20):
553
- """
554
- 注意:可能有bug,twinx=True时左纵坐标轴和横坐标轴标记可能发生重叠!!!暂不建议使用
555
- facecolor不起作用
556
- 目前的解决方案:改用函数plot_line2
557
-
558
- 功能:绘制两个证券的折线图。如果power=0不绘制趋势图,否则绘制多项式趋势图
559
- 假定:数据表有索引,且已经按照索引排序
560
- 输入:
561
- 证券1:数据表df1,证券代码ticker1,列名1,列名标签1;
562
- 证券2:数据表df2,证券代码ticker2,列名2,列名标签2;
563
- 标题titletxt,脚注footnote;是否在图中标记数据datatag;趋势图的多项式次数power
564
- 输出:默认绘制同轴折线图,若twinx=True则绘制双轴折线图
565
- 返回值:无
566
- 注意:需要日期类型作为df索引
567
-
568
- date_range:表示绘图横轴是否需要尽量绘制开始和结束日期
569
- date_freq:定义绘图横轴的日期间隔,False表示自动间隔,'1Y'表示以1年为单位间隔,
570
- '1M'表示间隔一个月,'3M'表示间隔3个月等
571
- date_fmt:定义绘图横轴日期的格式,'%Y-%m-%d'表示YYYY-mm-dd,'%Y-%m'表示YYYY-mm,
572
- '%Y'表示YYYY
573
- """
574
- #空值判断
575
- if len(df1) ==0:
576
- print (" #Warning(plot2_line2): no data to plot df1.")
577
- if len(df2) ==0:
578
- print (" #Warning(plot2_line2): no data to plot df2.")
579
- if (len(df1) ==0) and (len(df2) ==0):
580
- return
581
-
582
- if not twinx:
583
- plot_line2_coaxial2(df1,ticker1,colname1,label1, \
584
- df2,ticker2,colname2,label2, \
585
- ylabeltxt,titletxt,footnote,power,datatag1,datatag2,zeroline, \
586
- yline=yline,attention_value_area=attention_value_area, \
587
- xline=xline,attention_point_area=attention_point_area, \
588
- resample_freq=resample_freq, \
589
- loc1=loc1,loc2=loc2, \
590
- date_range=date_range,date_freq=date_freq,date_fmt=date_fmt, \
591
- color1=color1,color2=color2,facecolor=facecolor, \
592
- maxticks=maxticks)
593
- else:
594
- plot_line2_twinx2(df1,ticker1,colname1,label1, \
595
- df2,ticker2,colname2,label2, \
596
- titletxt,footnote,power,datatag1,datatag2, \
597
- xline,attention_point_area=attention_point_area, \
598
- resample_freq=resample_freq, \
599
- loc1=loc1,loc2=loc2, \
600
- date_range=date_range,date_freq=date_freq,date_fmt=date_fmt, \
601
- color1=color1,color2=color2,facecolor=facecolor, \
602
- maxticks=maxticks)
603
-
604
- return
605
-
606
-
607
- #==============================================================================
608
-
609
-
610
- def plot_line2_coaxial(df01,ticker1,colname1,label1, \
611
- df02,ticker2,colname2,label2, \
612
- ylabeltxt,titletxt,footnote, \
613
- power=0,datatag1=False,datatag2=False,zeroline=False, \
614
- yline=999,attention_value_area='', \
615
- xline=999,attention_point_area='', \
616
- resample_freq='D', \
617
- loc1='best',loc2='best', \
618
- color1='red',color2='blue',facecolor='whitesmoke', \
619
- ticker_type='auto',maxticks=15):
620
- """
621
- 功能:绘制两个证券的折线图。如果power=0不绘制趋势图,否则绘制多项式趋势图
622
- 假定:数据表有索引,且已经按照索引排序
623
- 输入:
624
- 证券1:数据表df1,证券代码ticker1,列名1,列名标签1;
625
- 证券2:数据表df2,证券代码ticker2,列名2,列名标签2;
626
- 标题titletxt,脚注footnote;是否在图中标记数据datatag;趋势图的多项式次数power
627
- 输出:绘制同轴折线图
628
- 返回值:无
629
- 注意:需要日期类型作为df索引
630
- """
631
- DEBUG=False
632
-
633
- #插值平滑:如果横轴不为日期型时不可平滑,否则数据会丢失!
634
- if not isinstance(maxticks,bool):
635
- try:
636
- df01x=df01[[colname1]].astype('float')
637
- df1=df_smooth_manual(df01x,resample_freq=resample_freq)
638
- except:
639
- df1=df01
640
- try:
641
- df02x=df02[[colname2]].astype('float')
642
- df2=df_smooth_manual(df02x,resample_freq=resample_freq)
643
- except:
644
- df2=df02
645
- else:
646
- df1=df01; df2=df02
647
-
648
- #预处理ticker_type
649
- ticker_type_list=ticker_type_preprocess_mticker_mixed([ticker1,ticker2],ticker_type)
650
-
651
- #证券1:先绘制折线图
652
-
653
- if ticker1 == '':
654
- label1txt=label1
655
- else:
656
- if label1 == '':
657
- label1txt=ticker_name(ticker1,ticker_type_list[0])
658
- else:
659
- label1txt=ticker_name(ticker1,ticker_type_list[0])+'('+label1+')'
660
-
661
- lwadjust=linewidth_adjust(df1)
662
- plt.plot(df1.index,df1[colname1],'-',label=label1txt, \
663
- linestyle='-',linewidth=lwadjust,color=color1)
664
-
665
- #证券1:绘制数据标签
666
- if datatag1:
667
- for x, y in zip(df1.index, df1[colname1]):
668
- plt.text(x,y+0.1,'%.2f' % y,ha='center',va='bottom',color='black')
669
-
670
- #是否绘制水平0线
671
- df_max=max([df1[colname1].max(),df2[colname2].max()])
672
- df_min=min([df1[colname1].min(),df2[colname2].min()])
673
- if df_max * df_min >=0: #同正同负
674
- zeroline=False
675
- else:
676
- zeroline=True
677
-
678
- #if zeroline and ((min(df1[colname1]) < 0) or (min(df2[colname2]) < 0)):
679
- if zeroline:
680
- plt.axhline(y=0,ls=":",c="black",linewidth=2)
681
-
682
- if DEBUG:
683
- print("In plot_line2_coaxial:")
684
- print("yline=",yline,"; xline=",xline)
685
-
686
- #是否绘制水平线
687
- if yline != 999:
688
- attention_value=yline
689
-
690
- #用于关注值的颜色列表
691
- atv_color_list=["lightgray","paleturquoise","wheat","khaki","lightsage"]
692
-
693
- if isinstance(attention_value,int) or isinstance(attention_value,float):
694
- atv_list=[attention_value]
695
- elif isinstance(attention_value,list):
696
- atv_list=attention_value
697
- else:
698
- atv_list=[]
699
-
700
- if DEBUG:
701
- print("atv_list=",atv_list)
702
-
703
- if not atv_list==[] and not atv_list==['']:
704
- for at in atv_list:
705
- pos=atv_list.index(at)
706
- color=atv_color_list[pos]
707
- plt.axhline(y=at,ls=":",c=color,linewidth=2,label=text_lang("关注值","Attention value ")+str(at))
708
-
709
- if not attention_value_area=='':
710
- if isinstance(attention_value_area,list) and len(attention_value_area)>=2:
711
- plt.fill_between(df1.index,attention_value_area[0],attention_value_area[1],color='lightgray',alpha=0.5)
712
-
713
- #是否绘制垂直线
714
- import pandas as pd
715
- from datetime import datetime; date_format="%Y-%m-%d"
716
- if xline != 999:
717
- attention_point=xline
718
- #用于关注点的颜色列表
719
- atp_color_list=["crimson","dodgerblue","magenta","lightseagreen","chocolate"]
720
-
721
- if isinstance(attention_point,str) or isinstance(attention_point,int) or isinstance(attention_point,float):
722
- atp_list=[attention_point]
723
- elif isinstance(attention_point,list):
724
- atp_list=attention_point
725
- else:
726
- atp_list=[]
727
-
728
- #去重,不打乱原来的顺序
729
- atp_list=list(dict.fromkeys(atp_list))
730
-
731
- if not atp_list==[] and not atp_list==['']:
732
-
733
- for at in atp_list:
734
- pos=atp_list.index(at)
735
- color=atp_color_list[pos]
736
-
737
- #判断是否日期字符串
738
- try:
739
- at=datetime.strptime(at, date_format)
740
- atpd=pd.to_datetime(at)
741
- except:
742
- atpd=at
743
-
744
- if DEBUG:
745
- print("atpd=",atpd)
746
-
747
- try:
748
- at_str=atpd.strftime('%Y-%m-%d')
749
- except:
750
- at_str=atpd
751
- plt.axvline(x=atpd,ls=":",c=color,linewidth=1.5,label=text_lang("关注点","Attention point ")+at_str)
752
-
753
- if not attention_point_area=='':
754
- if isinstance(attention_point_area,list) and len(attention_point_area)>=2:
755
- apa_list=[]
756
- for ap in attention_point_area:
757
- try:
758
- ap=datetime.strptime(ap, date_format)
759
- appd=pd.to_datetime(ap)
760
- except:
761
- appd=ap
762
- apa_list=apa_list+[appd]
763
-
764
- yaxis_data=plt.ylim()
765
- plt.fill_betweenx(yaxis_data,apa_list[0],apa_list[1],color='powderblue',alpha=0.5)
766
-
767
- #绘证券1:制趋势线
768
- if power > 0:
769
- trend_txt=text_lang('趋势线','Trend line')
770
-
771
- try:
772
- #生成行号,借此将横轴的日期数量化,以便拟合
773
- df1['id']=range(len(df1))
774
-
775
- #设定多项式拟合,power为多项式次数
776
- import numpy as np
777
- parameter = np.polyfit(df1.id, df1[colname1], power)
778
- f = np.poly1d(parameter)
779
-
780
- if ticker1 == '':
781
- label1txt=''
782
- else:
783
- label1txt=ticker_name(ticker1,ticker_type_list[0])+"("+trend_txt+")"
784
-
785
- #plt.plot(df1.index, f(df1.id),"g--", label=label1txt,linewidth=1)
786
- plt.plot(df1.index, f(df1.id),"g--", label='',linewidth=1)
787
- except: pass
788
-
789
- #证券2:先绘制折线图
790
- if ticker2 == '':
791
- label2txt=label2
792
- else:
793
- if label2 == '':
794
- label2txt=ticker_name(ticker2,ticker_type_list[1])
795
- else:
796
- label2txt=ticker_name(ticker2,ticker_type_list[1])+'('+label2+')'
797
-
798
- lwadjust=linewidth_adjust(df2)
799
- plt.plot(df2.index,df2[colname2],'-',label=label2txt, \
800
- linestyle='-.',linewidth=lwadjust,color=color2)
801
- #证券2:绘制数据标签
802
- if datatag2:
803
- for x, y in zip(df2.index, df2[colname2]):
804
- plt.text(x,y+0.1,'%.2f' % y,ha='center',va='bottom',color='black')
805
-
806
- #绘证券2:制趋势线
807
- if power > 0:
808
- lang=check_language()
809
- trend_txt='趋势线'
810
- if lang == 'English':
811
- trend_txt='Trend line'
812
-
813
- try:
814
- #生成行号,借此将横轴的日期数量化,以便拟合
815
- df2['id']=range(len(df2))
816
-
817
- #设定多项式拟合,power为多项式次数
818
- import numpy as np
819
- parameter = np.polyfit(df2.id, df2[colname2], power)
820
- f = np.poly1d(parameter)
821
-
822
- if ticker2 == '':
823
- label2txt=''
824
- else:
825
- label2txt=ticker_name(ticker2,ticker_type_list[1])+"("+trend_txt+")"
826
-
827
- #plt.plot(df2.index, f(df2.id),"r--", label=label2txt,linewidth=1)
828
- plt.plot(df2.index, f(df2.id),"r--", label='',linewidth=1)
829
- except: pass
830
-
831
- # 同轴绘图时,loc2未用上!
832
- plt.legend(loc=loc1,fontsize=legend_txt_size)
833
-
834
- # 使用 AutoDateLocator 自动选择最佳间隔,目的是显示最后一个日期,亲测有效!!!
835
- if not isinstance(maxticks,bool):
836
- import matplotlib.dates as mdates
837
- try:
838
- ax=plt.gca()
839
- ax.xaxis.set_major_locator(mdates.AutoDateLocator(maxticks=maxticks))
840
- except:
841
- pass
842
-
843
- plt.gcf().autofmt_xdate(ha="center") # 优化标注(自动倾斜)
844
-
845
- try:
846
- plt.gca().set_facecolor(facecolor)
847
- except:
848
- print(" #Warning(plot_line2_coaxial): color",facecolor,"is unsupported, changed to default setting")
849
- plt.gca().set_facecolor("whitesmoke")
850
-
851
- plt.ylabel(ylabeltxt,fontsize=ylabel_txt_size)
852
- plt.xlabel(footnote,fontsize=xlabel_txt_size,ha='center')
853
- plt.title(titletxt,fontweight='bold',fontsize=title_txt_size)
854
- plt.show()
855
- plt.close()
856
-
857
- return
858
-
859
- if __name__ =="__main__":
860
- df1 = get_price('000002.SZ', '2020-1-1', '2020-3-16')
861
- df2 = get_price('600266.SS', '2020-1-1', '2020-3-16')
862
- ticker1='000002.SZ'; ticker2='600266.SS'
863
- colname1='Close'; colname2='Close'
864
- label1="收盘价"; label2="收盘价"
865
- ylabeltxt="价格"
866
- plot_line2_coaxial(df1,'000002.SZ','High','最高价', \
867
- df1,'000002.SZ','Low','最低价',"价格", \
868
- "证券价格走势对比图","数据来源:新浪/stooq")
869
- plot_line2_coaxial(df1,'000002.SZ','Open','开盘价', \
870
- df1,'000002.SZ','Close','收盘价',"价格", \
871
- "证券价格走势对比图","数据来源:新浪/stooq")
872
-
873
- plot_line2_coaxial(df2,'600266.SS','Open','开盘价', \
874
- df2,'600266.SS','Close','收盘价',"价格", \
875
- "证券价格走势对比图","数据来源:新浪/stooq")
876
-
877
- #==============================================================================
878
- def plot_line2_coaxial2(df01,ticker1,colname1,label1, \
879
- df02,ticker2,colname2,label2, \
880
- ylabeltxt,titletxt,footnote, \
881
- power=0,datatag1=False,datatag2=False,zeroline=False, \
882
- yline=999,attention_value_area='', \
883
- xline=999,attention_point_area='', \
884
- resample_freq='D', \
885
- loc1='best',loc2='best', \
886
- date_range=False,date_freq=False,date_fmt='%Y-%m-%d', \
887
- color1='red',color2='blue',facecolor='whitesmoke', \
888
- ticker_type='auto', \
889
- maxticks=15):
890
- """
891
- 功能:绘制两个证券的折线图。如果power=0不绘制趋势图,否则绘制多项式趋势图
892
- 假定:数据表有索引,且已经按照索引排序
893
- 输入:
894
- 证券1:数据表df1,证券代码ticker1,列名1,列名标签1;
895
- 证券2:数据表df2,证券代码ticker2,列名2,列名标签2;
896
- 标题titletxt,脚注footnote;是否在图中标记数据datatag;趋势图的多项式次数power
897
- 输出:绘制同轴折线图
898
- 返回值:无
899
- 注意:需要日期类型作为df索引
900
- """
901
- import pandas as pd
902
- DEBUG=False
903
-
904
- #插值平滑:对于df索引为非日期型的不能进行插值平滑,否则会丢失数据!!!
905
- if not isinstance(maxticks,bool):
906
- try:
907
- df01x=df01[[colname1]].astype('float')
908
- df1=df_smooth_manual(df01x,resample_freq=resample_freq)
909
- except:
910
- df1=df01
911
- try:
912
- df02x=df02[[colname2]].astype('float')
913
- df2=df_smooth_manual(df02x,resample_freq=resample_freq)
914
- except:
915
- df2=df02
916
- else:
917
- df1=df01; df2=df02
918
-
919
- #预处理ticker_type
920
- ticker_type_list=ticker_type_preprocess_mticker_mixed([ticker1,ticker2],ticker_type)
921
-
922
- #证券1:先绘制折线图
923
- if ticker1 == '':
924
- label1txt=label1
925
- else:
926
- if label1 == '':
927
- label1txt=ticker_name(ticker1,ticker_type_list[0])
928
- else:
929
- label1txt=ticker_name(ticker1,ticker_type_list[0])+'('+label1+')'
930
-
931
- ax=plt.gca()
932
- date_start=df1.index[0]
933
- date_end=df1.index[-1]
934
- import pandas as pd
935
-
936
- if date_range and not date_freq:
937
- ax.xaxis.set_major_formatter(mdate.DateFormatter(date_fmt))
938
- plt.xticks(pd.date_range(date_start,date_end))
939
- if not date_range and date_freq:
940
- ax.xaxis.set_major_formatter(mdate.DateFormatter(date_fmt))
941
- plt.xticks(pd.date_range(freq=date_freq))
942
- if date_range and date_freq:
943
- ax.xaxis.set_major_formatter(mdate.DateFormatter(date_fmt))
944
- plt.xticks(pd.date_range(date_start,date_end,freq=date_freq))
945
-
946
- lwadjust=linewidth_adjust(df1)
947
- plt.plot(df1.index,df1[colname1],'-',label=label1txt, \
948
- linestyle='-',linewidth=lwadjust,color=color1)
949
- #证券1:绘制数据标签
950
- if datatag1:
951
- for x, y in zip(df1.index, df1[colname1]):
952
- plt.text(x,y+0.1,'%.2f' % y,ha='center',va='bottom',color='black')
953
-
954
- #是否绘制水平0线
955
- if zeroline and ((min(df1[colname1]) < 0) or (min(df2[colname2]) < 0)):
956
- plt.axhline(y=0,ls=":",c="black",linewidth=2.5)
957
-
958
- """
959
- #是否绘制水平线
960
- if yline != 999:
961
- plt.axhline(y=yline,ls=":",c="black",linewidth=2.5)
962
-
963
- #是否绘制垂直线
964
- if xline != 999:
965
- plt.axvline(x=xline,ls=":",c="black",linewidth=2.5)
966
- """
967
- #是否绘制水平线
968
- if yline != 999:
969
- attention_value=yline
970
-
971
- #用于关注值的颜色列表
972
- atv_color_list=["lightgray","paleturquoise","wheat","khaki","lightsage"]
973
-
974
- if isinstance(attention_value,int) or isinstance(attention_value,float):
975
- atv_list=[attention_value]
976
- elif isinstance(attention_value,list):
977
- atv_list=attention_value
978
- else:
979
- atv_list=[]
980
-
981
- if DEBUG:
982
- print("atv_list=",atv_list)
983
-
984
- if not atv_list==[] and not atv_list==['']:
985
- for at in atv_list:
986
- pos=atv_list.index(at)
987
- color=atv_color_list[pos]
988
- plt.axhline(y=at,ls=":",c=color,linewidth=2,label=text_lang("关注值","Attention value ")+str(at))
989
-
990
- if not attention_value_area=='':
991
- if isinstance(attention_value_area,list) and len(attention_value_area)>=2:
992
- plt.fill_between(df1.index,attention_value_area[0],attention_value_area[1],color='lightgray',alpha=0.5)
993
-
994
- #是否绘制垂直线
995
- import pandas as pd
996
- from datetime import datetime; date_format="%Y-%m-%d"
997
- if xline != 999:
998
- attention_point=xline
999
- #用于关注点的颜色列表
1000
- atp_color_list=["crimson","dodgerblue","magenta","lightseagreen","chocolate"]
1001
-
1002
- if isinstance(attention_point,str) or isinstance(attention_point,int) or isinstance(attention_point,float):
1003
- atp_list=[attention_point]
1004
- elif isinstance(attention_point,list):
1005
- atp_list=attention_point
1006
- else:
1007
- atp_list=[]
1008
- #去重,不打乱原来的顺序
1009
- atp_list=list(dict.fromkeys(atp_list))
1010
-
1011
- if not atp_list==[] and not atp_list==['']:
1012
-
1013
- for at in atp_list:
1014
- pos=atp_list.index(at)
1015
- color=atp_color_list[pos]
1016
-
1017
- #判断是否日期字符串
1018
- try:
1019
- at=datetime.strptime(at, date_format)
1020
- atpd=pd.to_datetime(at)
1021
- except:
1022
- atpd=at
1023
-
1024
- if DEBUG:
1025
- print("atpd=",atpd)
1026
-
1027
- try:
1028
- at_str=atpd.strftime('%Y-%m-%d')
1029
- except:
1030
- at_str=atpd
1031
- #plt.axvline(x=atpd,ls=":",c=color,linewidth=1.5,label=text_lang("关注点","Attention point ")+str(at))
1032
- plt.axvline(x=atpd,ls=":",c=color,linewidth=1.5,label=text_lang("关注点","Attention point ")+at_str)
1033
-
1034
- if not attention_point_area=='':
1035
- if isinstance(attention_point_area,list) and len(attention_point_area)>=2:
1036
- apa_list=[]
1037
- for ap in attention_point_area:
1038
- try:
1039
- ap=datetime.strptime(ap, date_format)
1040
- appd=pd.to_datetime(ap)
1041
- except:
1042
- appd=ap
1043
- apa_list=apa_list+[appd]
1044
-
1045
- yaxis_data=plt.ylim()
1046
- plt.fill_betweenx(yaxis_data,apa_list[0],apa_list[1],color='powderblue',alpha=0.5)
1047
-
1048
-
1049
- #绘证券1:制趋势线
1050
- if power > 0:
1051
- lang=check_language()
1052
- trend_txt='趋势线'
1053
- if lang == 'English':
1054
- trend_txt='Trend line'
1055
-
1056
- try:
1057
- #生成行号,借此将横轴的日期数量化,以便拟合
1058
- df1['id']=range(len(df1))
1059
-
1060
- #设定多项式拟合,power为多项式次数
1061
- import numpy as np
1062
- parameter = np.polyfit(df1.id, df1[colname1], power)
1063
- f = np.poly1d(parameter)
1064
-
1065
- if ticker1 == '':
1066
- label1txt=''
1067
- else:
1068
- label1txt=ticker_name(ticker1,ticker_type_list[0])+"("+trend_txt+")"
1069
- plt.plot(df1.index, f(df1.id),"g--", label=label1txt,linewidth=1)
1070
- except: pass
1071
-
1072
- #证券2:先绘制折线图
1073
- if ticker2 == '':
1074
- label2txt=label2
1075
- else:
1076
- if label2 == '':
1077
- label2txt=ticker_name(ticker2,ticker_type_list[1])
1078
- else:
1079
- label2txt=ticker_name(ticker2,ticker_type_list[1])+'('+label2+')'
1080
-
1081
- date_start=df2.index[0]
1082
- date_end=df2.index[-1]
1083
- if date_range and not date_freq:
1084
- ax.xaxis.set_major_formatter(mdate.DateFormatter(date_fmt))
1085
- plt.xticks(pd.date_range(date_start,date_end))
1086
- if not date_range and date_freq:
1087
- ax.xaxis.set_major_formatter(mdate.DateFormatter(date_fmt))
1088
- plt.xticks(pd.date_range(freq=date_freq))
1089
- if date_range and date_freq:
1090
- ax.xaxis.set_major_formatter(mdate.DateFormatter(date_fmt))
1091
- plt.xticks(pd.date_range(date_start,date_end,freq=date_freq))
1092
-
1093
- lwadjust=linewidth_adjust(df2)
1094
- plt.plot(df2.index,df2[colname2],'-',label=label2txt, \
1095
- linestyle='-.',linewidth=lwadjust,color=color2)
1096
- #证券2:绘制数据标签
1097
- if datatag2:
1098
- for x, y in zip(df2.index, df2[colname2]):
1099
- plt.text(x,y+0.1,'%.2f' % y,ha='center',va='bottom',color='black')
1100
-
1101
- #绘证券2:制趋势线
1102
- if power > 0:
1103
- lang=check_language()
1104
- trend_txt='趋势线'
1105
- if lang == 'English':
1106
- trend_txt='Trend line'
1107
-
1108
- try:
1109
- #生成行号,借此将横轴的日期数量化,以便拟合
1110
- df2['id']=range(len(df2))
1111
-
1112
- #设定多项式拟合,power为多项式次数
1113
- import numpy as np
1114
- parameter = np.polyfit(df2.id, df2[colname2], power)
1115
- f = np.poly1d(parameter)
1116
-
1117
- if ticker2 == '':
1118
- label2txt=''
1119
- else:
1120
- label2txt=ticker_name(ticker2,ticker_type_list[1])+"("+trend_txt+")"
1121
- plt.plot(df2.index, f(df2.id),"r--", label=label2txt,linewidth=1)
1122
- except: pass
1123
-
1124
- # 同轴绘图时,loc1/loc2未用上!
1125
- plt.legend(loc=loc1,fontsize=legend_txt_size)
1126
-
1127
- # 使用 AutoDateLocator 自动选择最佳间隔,目的是显示最后一个日期,亲测有效!!!
1128
- if not isinstance(maxticks,bool):
1129
- import matplotlib.dates as mdates
1130
- ax.xaxis.set_major_locator(mdates.AutoDateLocator(maxticks=maxticks))
1131
-
1132
- plt.gcf().autofmt_xdate(ha="center") # 优化标注(自动倾斜)
1133
- try:
1134
- plt.gca().set_facecolor(facecolor)
1135
- except:
1136
- print(" #Warning(plot_line2_coaxial2): color",facecolor,"is unsupported, changed to default setting")
1137
- plt.gca().set_facecolor("whitesmoke")
1138
-
1139
- plt.ylabel(ylabeltxt,fontsize=ylabel_txt_size)
1140
- plt.xlabel(footnote,fontsize=xlabel_txt_size,ha='center')
1141
- plt.title(titletxt,fontweight='bold',fontsize=title_txt_size)
1142
- plt.show()
1143
- plt.close()
1144
-
1145
- return
1146
-
1147
- #==============================================================================
1148
- if __name__ =="__main__":
1149
- df01=df1; df02=df2
1150
- maxticks=False
1151
-
1152
- def plot_line2_twinx(df01,ticker1,colname1,label1, \
1153
- df02,ticker2,colname2,label2, \
1154
- titletxt,footnote,power=0,datatag1=False,datatag2=False, \
1155
- resample_freq='D', \
1156
- xline=999,attention_point_area='', \
1157
- loc1='upper left',loc2='lower left', \
1158
- color1='red',color2='blue',facecolor='whitesmoke', \
1159
- ticker_type='auto', \
1160
- maxticks=15):
1161
- """
1162
- 功能:绘制两个证券的折线图。如果power=0不绘制趋势图,否则绘制多项式趋势图
1163
- 假定:数据表有索引,且已经按照索引排序
1164
- 输入:
1165
- 证券1:数据表df1,证券代码ticker1,列名1,列名标签1;
1166
- 证券2:数据表df2,证券代码ticker2,列名2,列名标签2;
1167
- 标题titletxt,脚注footnote;是否在图中标记数据datatag;趋势图的多项式次数power
1168
- 输出:绘制双轴折线图
1169
- 返回值:无
1170
- 注意:需要日期类型作为df索引
1171
- """
1172
- DEBUG=False
1173
-
1174
- #plt.rcParams['axes.grid']=False
1175
-
1176
- #插值平滑
1177
- if not isinstance(maxticks,bool):
1178
- try:
1179
- df01x=df01[[colname1]].astype('float')
1180
- df1=df_smooth_manual(df01x,resample_freq=resample_freq)
1181
- except:
1182
- df1=df01
1183
- try:
1184
- df02x=df02[[colname2]].astype('float')
1185
- df2=df_smooth_manual(df02x,resample_freq=resample_freq)
1186
- except:
1187
- df2=df02
1188
- else:
1189
- df1=df01; df2=df02
1190
-
1191
- #预处理ticker_type
1192
- ticker_type_list=ticker_type_preprocess_mticker_mixed([ticker1,ticker2],ticker_type)
1193
-
1194
- #证券1:绘制折线图,双坐标轴
1195
- fig = plt.figure()
1196
- ax = fig.add_subplot(111)
1197
- try:
1198
- fig.gca().set_facecolor(facecolor)
1199
- except:
1200
- print(" #Warning(plot_line2_twinx): color",facecolor,"is unsupported, changed to default setting")
1201
- fig.gca().set_facecolor("whitesmoke")
1202
-
1203
- if ticker1 == '':
1204
- label1txt=label1
1205
- else:
1206
- if label1 == '':
1207
- label1txt=ticker_name(ticker1,ticker_type_list[0])
1208
- else:
1209
- label1txt=ticker_name(ticker1,ticker_type_list[0])+'('+label1+')'
1210
-
1211
- lwadjust=linewidth_adjust(df1)
1212
- ax.plot(df1.index,df1[colname1],'-',label=label1txt, \
1213
- linestyle='-',color=color1,linewidth=lwadjust)
1214
-
1215
- #证券1:绘制数据标签
1216
- if datatag1:
1217
- for x, y in zip(df1.index, df1[colname1]):
1218
- ax.text(x,y+0.1,'%.2f' % y,ha='center',va='bottom',color='black')
1219
-
1220
- #绘制关注点
1221
- import pandas as pd
1222
- from datetime import datetime; date_format="%Y-%m-%d"
1223
- if xline != 999:
1224
- attention_point=xline
1225
-
1226
- #用于关注点的颜色列表
1227
- atp_color_list=["crimson","dodgerblue","magenta","lightseagreen","chocolate"]
1228
-
1229
- if isinstance(attention_point,str) or isinstance(attention_point,int) or isinstance(attention_point,float):
1230
- atp_list=[attention_point]
1231
- elif isinstance(attention_point,list):
1232
- atp_list=attention_point
1233
- else:
1234
- atp_list=[]
1235
- #去重,不打乱原来的顺序
1236
- atp_list=list(dict.fromkeys(atp_list))
1237
-
1238
- if DEBUG:
1239
- print("In plot_line2_twinx")
1240
- print("atp_list=",atp_list)
1241
-
1242
- if not atp_list==[] and not atp_list==['']:
1243
-
1244
- for at in atp_list:
1245
- pos=atp_list.index(at)
1246
- color=atp_color_list[pos]
1247
-
1248
- #判断是否日期字符串
1249
- try:
1250
- at=datetime.strptime(at, date_format)
1251
- atpd=pd.to_datetime(at)
1252
- except:
1253
- atpd=at
1254
-
1255
- try:
1256
- at_str=atpd.strftime('%Y-%m-%d')
1257
- except:
1258
- at_str=atpd
1259
- plt.axvline(x=atpd,ls=":",c=color,linewidth=1.5,label=text_lang("关注点","Attention point ")+at_str)
1260
-
1261
- if not attention_point_area=='':
1262
- if isinstance(attention_point_area,list) and len(attention_point_area)>=2:
1263
- apa_list=[]
1264
- for ap in attention_point_area:
1265
- try:
1266
- ap=datetime.strptime(ap, date_format)
1267
- appd=pd.to_datetime(ap)
1268
- except:
1269
- appd=ap
1270
- apa_list=apa_list+[appd]
1271
-
1272
- yaxis_data=plt.ylim()
1273
- plt.fill_betweenx(yaxis_data,apa_list[0],apa_list[1],color='powderblue',alpha=0.5)
1274
-
1275
- #绘证券1:制趋势线
1276
- if power > 0:
1277
- lang=check_language()
1278
- trend_txt='趋势线'
1279
- if lang == 'English':
1280
- trend_txt='Trend line'
1281
-
1282
- #生成行号,借此将横轴的日期数量化,以便拟合
1283
- df1['id']=range(len(df1))
1284
-
1285
- #设定多项式拟合,power为多项式次数
1286
- import numpy as np
1287
- parameter = np.polyfit(df1.id, df1[colname1], power)
1288
- f = np.poly1d(parameter)
1289
-
1290
- if ticker1 == '':
1291
- label1txt=''
1292
- else:
1293
- label1txt=ticker_name(ticker1,ticker_type_list[0])+"("+trend_txt+")"
1294
- ax.plot(df1.index, f(df1.id),"r--", label=label1txt,linewidth=1)
1295
-
1296
- #绘证券2:建立第二y轴
1297
- ax2 = ax.twinx()
1298
-
1299
- if ticker2 == '':
1300
- label2txt=label2
1301
- else:
1302
- if label2 == '':
1303
- label2txt=ticker_name(ticker2,ticker_type_list[1])
1304
- else:
1305
- label2txt=ticker_name(ticker2,ticker_type_list[1])+'('+label2+')'
1306
-
1307
- lwadjust=linewidth_adjust(df2)
1308
- ax2.plot(df2.index,df2[colname2],'-',label=label2txt, \
1309
- linestyle='-.',color=color2,linewidth=lwadjust)
1310
- #证券2:绘制数据标签
1311
- if datatag2:
1312
- for x, y in zip(df2.index, df2[colname2]):
1313
- ax2.text(x,y+0.1,'%.2f' % y,ha='center',va='bottom',color='black')
1314
-
1315
- #绘证券2:制趋势线
1316
- if power > 0:
1317
- lang=check_language()
1318
- trend_txt='趋势线'
1319
- if lang == 'English':
1320
- trend_txt='Trend line'
1321
-
1322
- #生成行号,借此将横轴的日期数量化,以便拟合
1323
- df2['id']=range(len(df2))
1324
-
1325
- #设定多项式拟合,power为多项式次数
1326
- import numpy as np
1327
- parameter = np.polyfit(df2.id, df2[colname2], power)
1328
- f = np.poly1d(parameter)
1329
-
1330
- if ticker2 == '':
1331
- label2txt=''
1332
- else:
1333
- label2txt=ticker_name(ticker2,ticker_type_list[1])+"("+trend_txt+")"
1334
- ax2.plot(df2.index, f(df2.id),"c--", label=label2txt,linewidth=1)
1335
-
1336
- ax.set_xlabel(footnote,fontsize=xlabel_txt_size,ha='center')
1337
-
1338
- if ticker1 == '':
1339
- label1txt=label1
1340
- else:
1341
- if label1 == "":
1342
- label1txt=ticker_name(ticker1,ticker_type_list[0])
1343
- else:
1344
- label1txt=label1+'('+ticker_name(ticker1,ticker_type_list[0])+')'
1345
- ax.set_ylabel(label1txt,fontsize=ylabel_txt_size)
1346
- ax.legend(loc=loc1,fontsize=legend_txt_size)
1347
-
1348
- if ticker2 == '':
1349
- label2txt=label2
1350
- else:
1351
- if label2 == "":
1352
- label2txt=ticker_name(ticker2,ticker_type_list[1])
1353
- else:
1354
- label2txt=label2+'('+ticker_name(ticker2,ticker_type_list[1])+')'
1355
- ax2.set_ylabel(label2txt,fontsize=ylabel_txt_size)
1356
- ax2.legend(loc=loc2,fontsize=legend_txt_size)
1357
-
1358
- # 使用 AutoDateLocator 自动选择最佳间隔,目的是显示最后一个日期,亲测有效!!!
1359
- if not isinstance(maxticks,bool):
1360
- import matplotlib.dates as mdates
1361
- ax.xaxis.set_major_locator(mdates.AutoDateLocator(maxticks=maxticks))
1362
- ax2.xaxis.set_major_locator(mdates.AutoDateLocator(maxticks=maxticks))
1363
-
1364
- #自动优化x轴标签
1365
- plt.gcf().autofmt_xdate(ha="center") # 优化标注(自动倾斜)
1366
-
1367
- plt.title(titletxt,fontweight='bold',fontsize=title_txt_size)
1368
- plt.show()
1369
-
1370
- return
1371
-
1372
-
1373
- if __name__ =="__main__":
1374
- df1 = get_price('000002.SZ', '2020-1-1', '2020-3-16')
1375
- df2 = get_price('600266.SS', '2020-1-1', '2020-3-16')
1376
- ticker1='000002.SZ'; ticker2='600266.SS'
1377
- colname1='Close'; colname2='Close'
1378
- label1="收盘价"; label2="收盘价"
1379
- ylabeltxt="价格"
1380
- plot_line2_twinx(df1,'000002.SZ','Close','收盘价', \
1381
- df2,'600266.SS','Close','收盘价', \
1382
- "证券价格走势对比图","数据来源:新浪/stooq")
1383
-
1384
- plot_line2_LR(df1,'000002.SZ','Close','收盘价', \
1385
- df2,'600266.SS','Close','收盘价', \
1386
- "证券价格走势对比图","数据来源:新浪/stooq",power=3)
1387
-
1388
- #==============================================================================
1389
- def plot_line2_LR(df01,ticker1,colname1,label1, \
1390
- df02,ticker2,colname2,label2, \
1391
- titletxt,footnote,power=0, \
1392
- datatag1=False,datatag2=False, \
1393
- resample_freq='D', \
1394
- xline=999,attention_point_area='', \
1395
- loc1='upper left',loc2='lower left', \
1396
- color1='red',color2='blue',facecolor='whitesmoke', \
1397
- ticker_type='auto', \
1398
- maxticks=15):
1399
- """
1400
- 功能:绘制两个证券或指标的左右折线图。如果power=0不绘制趋势图,否则绘制多项式趋势图
1401
- 假定:数据表有索引,且已经按照索引排序
1402
- 输入:
1403
- 证券1:数据表df1,证券代码ticker1,列名1,列名标签1;
1404
- 证券2:数据表df2,证券代码ticker2,列名2,列名标签2;
1405
- 标题titletxt,脚注footnote;是否在图中标记数据datatag;趋势图的多项式次数power
1406
- 输出:绘制左右并列折线图
1407
- 返回值:无
1408
- 注意:需要日期类型作为df索引
1409
- """
1410
- DEBUG=False
1411
-
1412
- #plt.rcParams['axes.grid']=False
1413
-
1414
- #插值平滑:若df索引为非日期型,不能进行插值平滑
1415
- if not isinstance(maxticks,bool):
1416
- try:
1417
- df01x=df01[[colname1]].astype('float')
1418
- df1=df_smooth_manual(df01x,resample_freq=resample_freq)
1419
- except:
1420
- df1=df01
1421
- try:
1422
- df02x=df02[[colname2]].astype('float')
1423
- df2=df_smooth_manual(df02x,resample_freq=resample_freq)
1424
- except:
1425
- df2=df02
1426
- else:
1427
- df1=df01; df2=df02
1428
-
1429
- #预处理ticker_type
1430
- ticker_type_list=ticker_type_preprocess_mticker_mixed([ticker1,ticker2],ticker_type)
1431
-
1432
- #创建画布:绘制折线图,左右双子图
1433
- fig, (ax, ax2) = plt.subplots(1, 2)
1434
-
1435
- #设置主标题
1436
- #plt.suptitle(titletxt,fontweight='bold',fontsize=title_txt_size, y=1.01) # y参数调整垂直位置
1437
- plt.suptitle(titletxt,fontweight='bold',fontsize=title_txt_size)
1438
-
1439
- # 绘制左子图================================================================
1440
- #设置画布背景颜色
1441
- try:
1442
- ax.set_facecolor(facecolor)
1443
- except:
1444
- print(" #Warning(plot_line2_twinx): color",facecolor,"is unsupported")
1445
- facecolor="whitesmoke"
1446
- ax.set_facecolor(facecolor)
1447
-
1448
- # 设置折线标签
1449
- if ticker1 == '':
1450
- label1txt=label1
1451
- else:
1452
- if label1 == '':
1453
- label1txt=ticker_name(ticker1,ticker_type_list[0])
1454
- else:
1455
- label1txt=ticker_name(ticker1,ticker_type_list[0])+'('+label1+')'
1456
-
1457
- # 设置子图标题
1458
- if ticker1 != ticker2:
1459
- ax.set_title(label1txt,fontsize=xlabel_txt_size)
1460
- else:
1461
- ax.set_title(ectranslate(colname1),fontsize=xlabel_txt_size)
1462
-
1463
- # 绘图
1464
- lwadjust=linewidth_adjust(df1)
1465
- """
1466
- ax.plot(df1.index,df1[colname1],'-',label=label1txt, \
1467
- linestyle='-',color=color1,linewidth=lwadjust)
1468
- """
1469
- ax.plot(df1.index,df1[colname1],'-', \
1470
- linestyle='-',color=color1,linewidth=lwadjust)
1471
-
1472
- #证券1:绘制数据标签
1473
- if datatag1:
1474
- for x, y in zip(df1.index, df1[colname1]):
1475
- ax.text(x,y+0.1,'%.2f' % y,ha='center',va='bottom',color='black')
1476
-
1477
- #绘制关注点
1478
- import pandas as pd
1479
- from datetime import datetime; date_format="%Y-%m-%d"
1480
- if xline != 999:
1481
- attention_point=xline
1482
-
1483
- #用于关注点的颜色列表
1484
- atp_color_list=["crimson","dodgerblue","magenta","lightseagreen","chocolate"]
1485
-
1486
- if isinstance(attention_point,str) or isinstance(attention_point,int) or isinstance(attention_point,float):
1487
- atp_list=[attention_point]
1488
- elif isinstance(attention_point,list):
1489
- atp_list=attention_point
1490
- else:
1491
- atp_list=[]
1492
- #去重,不打乱原来的顺序
1493
- atp_list=list(dict.fromkeys(atp_list))
1494
-
1495
- if DEBUG:
1496
- print("In plot_line2_twinx")
1497
- print("atp_list=",atp_list)
1498
-
1499
- if not atp_list==[] and not atp_list==['']:
1500
-
1501
- for at in atp_list:
1502
- pos=atp_list.index(at)
1503
- color=atp_color_list[pos]
1504
-
1505
- #判断是否日期字符串
1506
- try:
1507
- at=datetime.strptime(at, date_format)
1508
- atpd=pd.to_datetime(at)
1509
- except:
1510
- atpd=at
1511
-
1512
- try:
1513
- at_str=atpd.strftime('%Y-%m-%d')
1514
- except:
1515
- at_str=atpd
1516
- #ax.axvline(x=atpd,ls=":",c=color,linewidth=1.5,label=text_lang("关注点","Attention point ")+str(at))
1517
- ax.axvline(x=atpd,ls=":",c=color,linewidth=1.5,label=text_lang("关注点","Attention point ")+at_str)
1518
-
1519
- if not attention_point_area=='':
1520
- if isinstance(attention_point_area,list) and len(attention_point_area)>=2:
1521
- apa_list=[]
1522
- for ap in attention_point_area:
1523
- try:
1524
- ap=datetime.strptime(ap, date_format)
1525
- appd=pd.to_datetime(ap)
1526
- except:
1527
- appd=ap
1528
- apa_list=apa_list+[appd]
1529
-
1530
- yaxis_data=plt.ylim()
1531
- ax.fill_betweenx(yaxis_data,apa_list[0],apa_list[1],color='powderblue',alpha=0.5)
1532
-
1533
- #绘证券1:制趋势线
1534
- if power > 0:
1535
- lang=check_language()
1536
- trend_txt='趋势线'
1537
- if lang == 'English':
1538
- trend_txt='Trend line'
1539
-
1540
- #生成行号,借此将横轴的日期数量化,以便拟合
1541
- df1['id']=range(len(df1))
1542
-
1543
- #设定多项式拟合,power为多项式次数
1544
- import numpy as np
1545
- parameter = np.polyfit(df1.id, df1[colname1], power)
1546
- f = np.poly1d(parameter)
1547
-
1548
- if ticker1 == '':
1549
- label1txt=''
1550
- else:
1551
- label1txt=ticker_name(ticker1,ticker_type_list[0])+"("+trend_txt+")"
1552
- ax.plot(df1.index, f(df1.id),"r--", label=label1txt,linewidth=1)
1553
-
1554
- # 纵轴标签
1555
- #ax.set_ylabel(label1txt,fontsize=ylabel_txt_size)
1556
- #ax.legend(loc=loc1,fontsize=legend_txt_size)
1557
-
1558
- # 横轴标签
1559
- #ax.set_xlabel(text_lang("日期","Date"),fontsize=xlabel_txt_size,ha='center')
1560
-
1561
- #绘图右图===================================================================
1562
- #设置画布背景颜色
1563
- ax2.set_facecolor(facecolor)
1564
-
1565
- # 折线标签
1566
- if ticker2 == '':
1567
- label2txt=label2
1568
- else:
1569
- if label2 == '':
1570
- label2txt=ticker_name(ticker2,ticker_type_list[1])
1571
- else:
1572
- label2txt=ticker_name(ticker2,ticker_type_list[1])+'('+label2+')'
1573
-
1574
- # 设置子图标题
1575
- if ticker1 != ticker2:
1576
- ax2.set_title(label2txt,fontsize=xlabel_txt_size)
1577
- else:
1578
- ax2.set_title(ectranslate(colname2),fontsize=xlabel_txt_size)
1579
-
1580
- # 绘图
1581
- lwadjust=linewidth_adjust(df2)
1582
- """
1583
- ax2.plot(df2.index,df2[colname2],'-',label=label2txt, \
1584
- linestyle='-.',color=color2,linewidth=lwadjust)
1585
- """
1586
- ax2.plot(df2.index,df2[colname2],'-', \
1587
- linestyle='-.',color=color2,linewidth=lwadjust)
1588
-
1589
- #证券2:绘制数据标签
1590
- if datatag2:
1591
- for x, y in zip(df2.index, df2[colname2]):
1592
- ax2.text(x,y+0.1,'%.2f' % y,ha='center',va='bottom',color='black')
1593
-
1594
- #绘证券2:制趋势线
1595
- if power > 0:
1596
- lang=check_language()
1597
- trend_txt='趋势线'
1598
- if lang == 'English':
1599
- trend_txt='Trend line'
1600
-
1601
- #生成行号,借此将横轴的日期数量化,以便拟合
1602
- df2['id']=range(len(df2))
1603
-
1604
- #设定多项式拟合,power为多项式次数
1605
- import numpy as np
1606
- parameter = np.polyfit(df2.id, df2[colname2], power)
1607
- f = np.poly1d(parameter)
1608
-
1609
- if ticker2 == '':
1610
- label2txt=''
1611
- else:
1612
- label2txt=ticker_name(ticker2,ticker_type_list[1])+"("+trend_txt+")"
1613
- ax2.plot(df2.index, f(df2.id),"c--", label=label2txt,linewidth=1)
1614
-
1615
- # 纵轴标签
1616
- #ax2.set_ylabel(label2txt,fontsize=ylabel_txt_size)
1617
- #ax2.legend(loc=loc2,fontsize=legend_txt_size)
1618
-
1619
- # 横轴标签
1620
- #ax2.set_xlabel(text_lang("日期","Date"),fontsize=xlabel_txt_size,ha='center')
1621
-
1622
- #自动优化x轴标签
1623
- #ax2.autofmt_xdate(ha="center") # 优化标注(自动倾斜)
1624
-
1625
- # 共同脚注==================================================================
1626
- fig.text(0.5,-0.01,footnote,ha='center',fontsize=xlabel_txt_size,color='gray')
1627
- #plt.xlabel(footnote,ha='center',fontsize=xlabel_txt_size,color='gray')
1628
-
1629
- # 自动倾斜横轴日期
1630
- if not isinstance(maxticks,bool):
1631
- fig.autofmt_xdate(ha="center")
1632
-
1633
- # 调整布局防止重叠
1634
- plt.tight_layout()
1635
- plt.show()
1636
-
1637
- return
1638
-
1639
-
1640
- #==============================================================================
1641
- def plot_line2_UD(df01,ticker1,colname1,label1, \
1642
- df02,ticker2,colname2,label2, \
1643
- titletxt,footnote,power=0, \
1644
- datatag1=False,datatag2=False, \
1645
- resample_freq='D', \
1646
- xline=999,attention_point_area='', \
1647
- loc1='upper left',loc2='lower left', \
1648
- color1='red',color2='blue',facecolor='whitesmoke', \
1649
- ticker_type='auto', \
1650
- maxticks=15):
1651
- """
1652
- 功能:绘制两个证券或指标的上下折线图。如果power=0不绘制趋势图,否则绘制多项式趋势图
1653
- 假定:数据表有索引,且已经按照索引排序
1654
- 输入:
1655
- 证券1:数据表df1,证券代码ticker1,列名1,列名标签1;
1656
- 证券2:数据表df2,证券代码ticker2,列名2,列名标签2;
1657
- 标题titletxt,脚注footnote;是否在图中标记数据datatag;趋势图的多项式次数power
1658
- 输出:绘制上下并列折线图
1659
- 返回值:无
1660
- 注意:需要日期类型作为df索引
1661
- """
1662
- DEBUG=False
1663
-
1664
- #plt.rcParams['axes.grid']=False
1665
-
1666
- #插值平滑
1667
- if not isinstance(maxticks,bool):
1668
- try:
1669
- df01x=df01[[colname1]].astype('float')
1670
- df1=df_smooth_manual(df01x,resample_freq=resample_freq)
1671
- except:
1672
- df1=df01
1673
- try:
1674
- df02x=df02[[colname2]].astype('float')
1675
- df2=df_smooth_manual(df02x,resample_freq=resample_freq)
1676
- except:
1677
- df2=df02
1678
- else:
1679
- df1=df01; df2=df02
1680
-
1681
- #预处理ticker_type
1682
- ticker_type_list=ticker_type_preprocess_mticker_mixed([ticker1,ticker2],ticker_type)
1683
-
1684
- #创建画布:绘制折线图,上下双子图
1685
- fig, (ax, ax2) = plt.subplots(2, 1)
1686
-
1687
- #设置主标题
1688
- #plt.suptitle(titletxt,fontweight='bold',fontsize=title_txt_size, y=1.01) # y参数调整垂直位置
1689
- plt.suptitle(titletxt,fontweight='bold',fontsize=title_txt_size)
1690
-
1691
- # 绘制左子图================================================================
1692
- #设置画布背景颜色
1693
- try:
1694
- ax.set_facecolor(facecolor)
1695
- except:
1696
- print(" #Warning(plot_line2_twinx): color",facecolor,"is unsupported")
1697
- facecolor="whitesmoke"
1698
- ax.set_facecolor(facecolor)
1699
-
1700
- # 设置折线标签
1701
- if ticker1 == '':
1702
- label1txt=label1
1703
- else:
1704
- if label1 == '':
1705
- label1txt=ticker_name(ticker1,ticker_type_list[0])
1706
- else:
1707
- label1txt=ticker_name(ticker1,ticker_type_list[0])+'('+label1+')'
1708
-
1709
- # 设置子图标题
1710
- """
1711
- if ticker1 != ticker2:
1712
- ax.set_title(label1txt,fontsize=xlabel_txt_size)
1713
- else:
1714
- ax.set_title(ectranslate(colname1),fontsize=xlabel_txt_size)
1715
- """
1716
- # 绘图
1717
- lwadjust=linewidth_adjust(df1)
1718
- """
1719
- ax.plot(df1.index,df1[colname1],'-',label=label1txt, \
1720
- linestyle='-',color=color1,linewidth=lwadjust)
1721
- """
1722
- ax.plot(df1.index,df1[colname1],'-', \
1723
- linestyle='-',color=color1,linewidth=lwadjust)
1724
-
1725
- #证券1:绘制数据标签
1726
- if datatag1:
1727
- for x, y in zip(df1.index, df1[colname1]):
1728
- ax.text(x,y+0.1,'%.2f' % y,ha='center',va='bottom',color='black')
1729
-
1730
- #绘制关注点
1731
- import pandas as pd
1732
- from datetime import datetime; date_format="%Y-%m-%d"
1733
- if xline != 999:
1734
- attention_point=xline
1735
-
1736
- #用于关注点的颜色列表
1737
- atp_color_list=["crimson","dodgerblue","magenta","lightseagreen","chocolate"]
1738
-
1739
- if isinstance(attention_point,str) or isinstance(attention_point,int) or isinstance(attention_point,float):
1740
- atp_list=[attention_point]
1741
- elif isinstance(attention_point,list):
1742
- atp_list=attention_point
1743
- else:
1744
- atp_list=[]
1745
- #去重,不打乱原来的顺序
1746
- atp_list=list(dict.fromkeys(atp_list))
1747
-
1748
- if DEBUG:
1749
- print("In plot_line2_twinx")
1750
- print("atp_list=",atp_list)
1751
-
1752
- if not atp_list==[] and not atp_list==['']:
1753
-
1754
- for at in atp_list:
1755
- pos=atp_list.index(at)
1756
- color=atp_color_list[pos]
1757
-
1758
- #判断是否日期字符串
1759
- try:
1760
- at=datetime.strptime(at, date_format)
1761
- atpd=pd.to_datetime(at)
1762
- except:
1763
- atpd=at
1764
-
1765
- try:
1766
- at_str=atpd.strftime('%Y-%m-%d')
1767
- except:
1768
- at_str=atpd
1769
- #ax.axvline(x=atpd,ls=":",c=color,linewidth=1.5,label=text_lang("关注点","Attention point ")+str(at))
1770
- ax.axvline(x=atpd,ls=":",c=color,linewidth=1.5,label=text_lang("关注点","Attention point ")+at_str)
1771
-
1772
- if not attention_point_area=='':
1773
- if isinstance(attention_point_area,list) and len(attention_point_area)>=2:
1774
- apa_list=[]
1775
- for ap in attention_point_area:
1776
- try:
1777
- ap=datetime.strptime(ap, date_format)
1778
- appd=pd.to_datetime(ap)
1779
- except:
1780
- appd=ap
1781
- apa_list=apa_list+[appd]
1782
-
1783
- yaxis_data=plt.ylim()
1784
- ax.fill_betweenx(yaxis_data,apa_list[0],apa_list[1],color='powderblue',alpha=0.5)
1785
-
1786
- #绘证券1:制趋势线
1787
- if power > 0:
1788
- lang=check_language()
1789
- trend_txt='趋势线'
1790
- if lang == 'English':
1791
- trend_txt='Trend line'
1792
-
1793
- #生成行号,借此将横轴的日期数量化,以便拟合
1794
- df1['id']=range(len(df1))
1795
-
1796
- #设定多项式拟合,power为多项式次数
1797
- import numpy as np
1798
- parameter = np.polyfit(df1.id, df1[colname1], power)
1799
- f = np.poly1d(parameter)
1800
-
1801
- if ticker1 == '':
1802
- label1txt=''
1803
- else:
1804
- label1txt=ticker_name(ticker1,ticker_type_list[0])+"("+trend_txt+")"
1805
- ax.plot(df1.index, f(df1.id),"r--", label=label1txt,linewidth=1)
1806
-
1807
- # 纵轴标签
1808
- if ticker1 != ticker2:
1809
- ax.set_ylabel(label1txt,fontsize=ylabel_txt_size)
1810
- else:
1811
- ax.set_ylabel(ectranslate(colname1),fontsize=ylabel_txt_size)
1812
- #ax.legend(loc=loc1,fontsize=legend_txt_size)
1813
-
1814
- # 横轴标签
1815
- #ax.set_xlabel(text_lang("日期","Date"),fontsize=xlabel_txt_size,ha='center')
1816
-
1817
- #绘图右图===================================================================
1818
- #设置画布背景颜色
1819
- ax2.set_facecolor(facecolor)
1820
-
1821
- # 折线标签
1822
- if ticker2 == '':
1823
- label2txt=label2
1824
- else:
1825
- if label2 == '':
1826
- label2txt=ticker_name(ticker2,ticker_type_list[1])
1827
- else:
1828
- label2txt=ticker_name(ticker2,ticker_type_list[1])+'('+label2+')'
1829
-
1830
- # 设置子图标题
1831
- """
1832
- if ticker1 != ticker2:
1833
- ax2.set_title(label2txt,fontsize=xlabel_txt_size)
1834
- else:
1835
- ax2.set_title(ectranslate(colname2),fontsize=xlabel_txt_size)
1836
- """
1837
- # 绘图
1838
- lwadjust=linewidth_adjust(df2)
1839
- """
1840
- ax2.plot(df2.index,df2[colname2],'-',label=label2txt, \
1841
- linestyle='-.',color=color2,linewidth=lwadjust)
1842
- """
1843
- ax2.plot(df2.index,df2[colname2],'-', \
1844
- linestyle='-.',color=color2,linewidth=lwadjust)
1845
-
1846
- #证券2:绘制数据标签
1847
- if datatag2:
1848
- for x, y in zip(df2.index, df2[colname2]):
1849
- ax2.text(x,y+0.1,'%.2f' % y,ha='center',va='bottom',color='black')
1850
-
1851
- #绘证券2:制趋势线
1852
- if power > 0:
1853
- lang=check_language()
1854
- trend_txt='趋势线'
1855
- if lang == 'English':
1856
- trend_txt='Trend line'
1857
-
1858
- #生成行号,借此将横轴的日期数量化,以便拟合
1859
- df2['id']=range(len(df2))
1860
-
1861
- #设定多项式拟合,power为多项式次数
1862
- import numpy as np
1863
- parameter = np.polyfit(df2.id, df2[colname2], power)
1864
- f = np.poly1d(parameter)
1865
-
1866
- if ticker2 == '':
1867
- label2txt=''
1868
- else:
1869
- label2txt=ticker_name(ticker2,ticker_type_list[1])+"("+trend_txt+")"
1870
- ax2.plot(df2.index, f(df2.id),"c--", label=label2txt,linewidth=1)
1871
-
1872
- # 纵轴标签
1873
- if ticker1 != ticker2:
1874
- ax2.set_ylabel(label2txt,fontsize=ylabel_txt_size)
1875
- else:
1876
- ax2.set_ylabel(ectranslate(colname2),fontsize=ylabel_txt_size)
1877
- #ax2.legend(loc=loc2,fontsize=legend_txt_size)
1878
-
1879
- # 横轴标签
1880
- #ax2.set_xlabel(text_lang("日期","Date"),fontsize=xlabel_txt_size,ha='center')
1881
-
1882
- #自动优化x轴标签
1883
- #ax2.autofmt_xdate(ha="center") # 优化标注(自动倾斜)
1884
-
1885
- # 共同脚注==================================================================
1886
- fig.text(0.5,-0.01,footnote,ha='center',fontsize=xlabel_txt_size,color='gray')
1887
- #plt.xlabel(footnote,ha='center',fontsize=xlabel_txt_size,color='gray')
1888
-
1889
- # 自动倾斜横轴日期
1890
- if not isinstance(maxticks,bool):
1891
- fig.autofmt_xdate(ha="center")
1892
-
1893
- # 调整布局防止重叠
1894
- plt.tight_layout()
1895
- plt.show()
1896
-
1897
- return
1898
-
1899
- #==============================================================================
1900
- def plot_line2_twinx2(df01,ticker1,colname1,label1, \
1901
- df02,ticker2,colname2,label2, \
1902
- titletxt,footnote,power=0,datatag1=False,datatag2=False, \
1903
- xline=999,attention_point_area='', \
1904
- resample_freq='D',loc1='upper left',loc2='lower left', \
1905
- date_range=False,date_freq=False,date_fmt='%Y-%m-%d', \
1906
- color1='red',color2='blue',facecolor='whitesmoke', \
1907
- ticker_type='auto', \
1908
- maxticks=15):
1909
- """
1910
- 功能:绘制两个证券的折线图。如果power=0不绘制趋势图,否则绘制多项式趋势图
1911
- 假定:数据表有索引,且已经按照索引排序
1912
- 输入:
1913
- 证券1:数据表df1,证券代码ticker1,列名1,列名标签1;
1914
- 证券2:数据表df2,证券代码ticker2,列名2,列名标签2;
1915
- 标题titletxt,脚注footnote;是否在图中标记数据datatag;趋势图的多项式次数power
1916
- 输出:绘制双轴折线图
1917
- 返回值:无
1918
- 注意:需要日期类型作为df索引
1919
- """
1920
- import pandas as pd
1921
- #plt.rcParams['axes.grid']=False
1922
-
1923
- #插值平滑
1924
- if not isinstance(maxticks,bool):
1925
- try:
1926
- df01x=df01[[colname1]].astype('float')
1927
- df1=df_smooth_manual(df01x,resample_freq=resample_freq)
1928
- except:
1929
- df1=df01
1930
- try:
1931
- df02x=df02[[colname2]].astype('float')
1932
- df2=df_smooth_manual(df02x,resample_freq=resample_freq)
1933
- except:
1934
- df2=df02
1935
- else:
1936
- df1=df01; df2=df02
1937
-
1938
- #预处理ticker_type
1939
- ticker_type_list=ticker_type_preprocess_mticker_mixed([ticker1,ticker2],ticker_type)
1940
-
1941
- #证券1:绘制折线图,双坐标轴
1942
- fig = plt.figure()
1943
- try:
1944
- fig.gca().set_facecolor(facecolor)
1945
- except:
1946
- print(" #Warning(plot_line2_twinx2): color",facecolor,"is unsupported, changed to default setting")
1947
- fig.gca().set_facecolor("whitesmoke")
1948
-
1949
- ax = fig.add_subplot(111)
1950
-
1951
- if ticker1 == '':
1952
- label1txt=label1
1953
- else:
1954
- if label1 == '':
1955
- label1txt=ticker_name(ticker1,ticker_type_list[0])
1956
- else:
1957
- label1txt=ticker_name(ticker1,ticker_type_list[0])+'('+label1+')'
1958
-
1959
- date_start=df1.index[0]
1960
- date_end=df1.index[-1]
1961
-
1962
- if date_range and not date_freq:
1963
- ax.xaxis.set_major_formatter(mdate.DateFormatter(date_fmt))
1964
- plt.xticks(pd.date_range(date_start,date_end))
1965
- if not date_range and date_freq:
1966
- ax.xaxis.set_major_formatter(mdate.DateFormatter(date_fmt))
1967
- plt.xticks(pd.date_range(freq=date_freq))
1968
- if date_range and date_freq:
1969
- ax.xaxis.set_major_formatter(mdate.DateFormatter(date_fmt))
1970
- plt.xticks(pd.date_range(date_start,date_end,freq=date_freq))
1971
-
1972
- lwadjust=linewidth_adjust(df1)
1973
- ax.plot(df1.index,df1[colname1],'-',label=label1txt, \
1974
- linestyle='-',color=color1,linewidth=lwadjust)
1975
- #证券1:绘制数据标签
1976
- if datatag1:
1977
- for x, y in zip(df1.index, df1[colname1]):
1978
- ax.text(x,y+0.1,'%.2f' % y,ha='center',va='bottom',color='black')
1979
-
1980
- #绘制关注点
1981
- import pandas as pd
1982
- from datetime import datetime; date_format="%Y-%m-%d"
1983
- if xline != 999:
1984
- attention_point=xline
1985
-
1986
- #用于关注点的颜色列表
1987
- atp_color_list=["crimson","dodgerblue","magenta","lightseagreen","chocolate"]
1988
-
1989
- if isinstance(attention_point,str) or isinstance(attention_point,int) or isinstance(attention_point,float):
1990
- atp_list=[attention_point]
1991
- elif isinstance(attention_point,list):
1992
- atp_list=attention_point
1993
- else:
1994
- atp_list=[]
1995
- #去重,不打乱原来的顺序
1996
- atp_list=list(dict.fromkeys(atp_list))
1997
-
1998
- if DEBUG:
1999
- print("In plot_line2_twinx")
2000
- print("atp_list=",atp_list)
2001
-
2002
- if not atp_list==[] and not atp_list==['']:
2003
-
2004
- for at in atp_list:
2005
- pos=atp_list.index(at)
2006
- color=atp_color_list[pos]
2007
-
2008
- #判断是否日期字符串
2009
- try:
2010
- at=datetime.strptime(at, date_format)
2011
- atpd=pd.to_datetime(at)
2012
- except:
2013
- atpd=at
2014
-
2015
- try:
2016
- at_str=atpd.strftime('%Y-%m-%d')
2017
- except:
2018
- at_str=atpd
2019
- #plt.axvline(x=atpd,ls=":",c=color,linewidth=1.5,label=text_lang("关注点","Attention point ")+str(at))
2020
- plt.axvline(x=atpd,ls=":",c=color,linewidth=1.5,label=text_lang("关注点","Attention point ")+at_str)
2021
-
2022
- if not attention_point_area=='':
2023
- if isinstance(attention_point_area,list) and len(attention_point_area)>=2:
2024
- apa_list=[]
2025
- for ap in attention_point_area:
2026
- try:
2027
- ap=datetime.strptime(ap, date_format)
2028
- appd=pd.to_datetime(ap)
2029
- except:
2030
- appd=ap
2031
- apa_list=apa_list+[appd]
2032
-
2033
- yaxis_data=plt.ylim()
2034
- plt.fill_betweenx(yaxis_data,apa_list[0],apa_list[1],color='powderblue',alpha=0.5)
2035
-
2036
-
2037
- #绘证券1:制趋势线
2038
- if power > 0:
2039
- lang=check_language()
2040
- trend_txt='趋势线'
2041
- if lang == 'English':
2042
- trend_txt='Trend line'
2043
-
2044
- #生成行号,借此将横轴的日期数量化,以便拟合
2045
- df1['id']=range(len(df1))
2046
-
2047
- #设定多项式拟合,power为多项式次数
2048
- import numpy as np
2049
- parameter = np.polyfit(df1.id, df1[colname1], power)
2050
- f = np.poly1d(parameter)
2051
-
2052
- if ticker1 == '':
2053
- label1txt=''
2054
- else:
2055
- label1txt=ticker_name(ticker1,ticker_type_list[0])+"("+trend_txt+")"
2056
- ax.plot(df1.index, f(df1.id),"r--", label=label1txt,linewidth=1)
2057
-
2058
- ax.set_xlabel(footnote,fontsize=xlabel_txt_size,ha='center')
2059
-
2060
- if ticker1 == '':
2061
- label1txt=label1
2062
- else:
2063
- if label1 == "":
2064
- label1txt=ticker_name(ticker1,ticker_type_list[0])
2065
- else:
2066
- label1txt=label1+'('+ticker_name(ticker1,ticker_type_list[0])+')'
2067
- ax.set_ylabel(label1txt,fontsize=ylabel_txt_size)
2068
- ax.legend(loc=loc1,fontsize=legend_txt_size)
2069
-
2070
- #绘证券2:建立第二y轴
2071
- ax2 = ax.twinx()
2072
-
2073
- if ticker2 == '':
2074
- label2txt=label2
2075
- else:
2076
- if label2 == '':
2077
- label2txt=ticker_name(ticker2,ticker_type_list[1])
2078
- else:
2079
- label2txt=ticker_name(ticker2,ticker_type_list[1])+'('+label2+')'
2080
-
2081
- date_start=df2.index[0]
2082
- date_end=df2.index[-1]
2083
- if date_range and not date_freq:
2084
- ax2.xaxis.set_major_formatter(mdate.DateFormatter(date_fmt))
2085
- plt.xticks(pd.date_range(date_start,date_end))
2086
- if not date_range and date_freq:
2087
- ax2.xaxis.set_major_formatter(mdate.DateFormatter(date_fmt))
2088
- plt.xticks(pd.date_range(freq=date_freq))
2089
- if date_range and date_freq:
2090
- ax2.xaxis.set_major_formatter(mdate.DateFormatter(date_fmt))
2091
- plt.xticks(pd.date_range(date_start,date_end,freq=date_freq))
2092
-
2093
- lwadjust=linewidth_adjust(df2)
2094
- ax2.plot(df2.index,df2[colname2],'-',label=label2txt, \
2095
- linestyle='-.',color=color2,linewidth=lwadjust)
2096
- #证券2:绘制数据标签
2097
- if datatag2:
2098
- for x, y in zip(df2.index, df2[colname2]):
2099
- ax2.text(x,y+0.1,'%.2f' % y,ha='center',va='bottom',color='black')
2100
-
2101
- #绘证券2:制趋势线
2102
- if power > 0:
2103
- lang=check_language()
2104
- trend_txt='趋势线'
2105
- if lang == 'English':
2106
- trend_txt='Trend line'
2107
-
2108
- #生成行号,借此将横轴的日期数量化,以便拟合
2109
- df2['id']=range(len(df2))
2110
-
2111
- #设定多项式拟合,power为多项式次数
2112
- import numpy as np
2113
- parameter = np.polyfit(df2.id, df2[colname2], power)
2114
- f = np.poly1d(parameter)
2115
-
2116
- if ticker2 == '':
2117
- label2txt=''
2118
- else:
2119
- label2txt=ticker_name(ticker2,ticker_type_list[1])+"("+trend_txt+")"
2120
-
2121
- ax2.plot(df2.index, f(df2.id),"c--", label=label2txt,linewidth=1)
2122
-
2123
- if ticker2 == '':
2124
- label2txt=label2
2125
- else:
2126
- if label2 == "":
2127
- label2txt=ticker_name(ticker2,ticker_type_list[1])
2128
- else:
2129
- label2txt=label2+'('+ticker_name(ticker2,ticker_type_list[1])+')'
2130
- ax2.set_ylabel(label2txt,fontsize=ylabel_txt_size)
2131
- ax2.legend(loc=loc2,fontsize=legend_txt_size)
2132
-
2133
- # 使用 AutoDateLocator 自动选择最佳间隔,目的是显示最后一个日期,亲测有效!!!
2134
- import matplotlib.dates as mdates
2135
- ax.xaxis.set_major_locator(mdates.AutoDateLocator(maxticks=maxticks))
2136
- ax2.xaxis.set_major_locator(mdates.AutoDateLocator(maxticks=maxticks))
2137
-
2138
- #自动优化x轴标签
2139
- #格式化时间轴标注
2140
- #plt.gca().xaxis.set_major_formatter(mdate.DateFormatter('%y-%m-%d'))
2141
- if not isinstance(maxticks,bool):
2142
- plt.gcf().autofmt_xdate(ha="center") # 优化标注(自动倾斜)
2143
-
2144
- plt.title(titletxt,fontweight='bold',fontsize=title_txt_size)
2145
- plt.show()
2146
-
2147
- return
2148
-
2149
- #==============================================================================
2150
- if __name__ =="__main__":
2151
- df0=security_trend(['PDD','JD'],annotate=True,graph=False)
2152
-
2153
- y_label=''; x_label='Footnote'
2154
- axhline_value=0; axhline_label=''
2155
- title_txt='Title'
2156
- data_label=False
2157
- resample_freq='D'; smooth=True
2158
- linewidth=1.5
2159
- loc='best'
2160
- annotate=True; annotate_value=True
2161
- plus_sign=False
2162
- attention_value=''; attention_value_area=''
2163
- attention_point=''; attention_point_area=''
2164
- mark_top=False; mark_bottom=False; mark_end=False
2165
- ticker_type='auto'
2166
- facecolor='whitesmoke'
2167
-
2168
-
2169
- def draw_lines(df0,y_label,x_label,axhline_value,axhline_label,title_txt, \
2170
- data_label=False,resample_freq='D',smooth=False,linewidth=1.5, \
2171
- band_area='',loc='best', \
2172
- annotate=False,annotate_value=False,plus_sign=False, \
2173
- attention_value='',attention_value_area='', \
2174
- attention_point='',attention_point_area='', \
2175
- mark_start=False,mark_top=False,mark_bottom=False,mark_end=False, \
2176
- ticker_type='auto',facecolor='whitesmoke', \
2177
- maxticks_enable=True,maxticks=15, \
2178
- translate=False, \
2179
- precision=2):
2180
- """
2181
- 函数功能:根据df的内容绘制折线图
2182
- 输入参数:
2183
- df:数据框。有几个字段就绘制几条折现。必须索引,索引值将作为X轴标记点
2184
- 要求:df的索引为pandas的datetime日期型
2185
- axhline_label: 水平辅助线标记。如果为空值则不绘制水平辅助线
2186
- axhline_value: 水平辅助线的y轴位置
2187
- y_label:y轴标记
2188
- x_label:x轴标记
2189
- title_txt:标题。如需多行,中间用\n分割
2190
-
2191
- 输出:
2192
- 绘制折线图
2193
- 无返回数据
2194
- 注意:需要日期类型作为df索引
2195
- """
2196
- DEBUG=False
2197
- if DEBUG:
2198
- print(f"band_area={band_area}")
2199
- print(f"df0={df0}")
2200
-
2201
-
2202
- if DEBUG:
2203
- print("annotate=",annotate,"annotate_value=",annotate_value)
2204
- print("mark_top=",mark_top,"mark_bottom=",mark_bottom)
2205
- print(df0)
2206
-
2207
- #空值判断
2208
- if len(df0) ==0:
2209
- print (" #Warning(draw_lines): no data to plot.")
2210
- return
2211
-
2212
- #插值平滑
2213
- if smooth and not isinstance(maxticks,bool):
2214
- #print(" Rendering graphics ...")
2215
- try:
2216
- df=df_smooth_manual(df0,resample_freq=resample_freq)
2217
- except:
2218
- df=df0
2219
- else:
2220
- df=df0
2221
-
2222
- #取得df字段名列表
2223
- collist=df.columns.values.tolist()
2224
- if len(collist) > 16:
2225
- print (" #Warning(draw_lines): too many columns to draw lines, max 16 lines")
2226
- return
2227
-
2228
- lslist=['-','--','-.',':','-','--','-.',':','-','--','-.',':','-','--','-.',':',]
2229
- #mklist=[',','d','_','.','o','v','^','<','>','1','2','3','4','s','p','*','h','H','+','x','D']
2230
- mklist=[',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',',']
2231
-
2232
- # 所有字段转换为数值类型,以防万一
2233
- for c in collist:
2234
- try:
2235
- df[c]=df[c].astype('float')
2236
- except:
2237
- del df[c]
2238
-
2239
- # 计算所有列中的最大最小差距,所有列必须为数值型!
2240
- dfmax=df.max().max(); dfmin=df.min().min()
2241
- high_low=dfmax - dfmin
2242
-
2243
- # 将末端值最大的排在第一列,优先绘图
2244
- dftt=df.T
2245
- lastrow=list(dftt)[-1]
2246
- dftt.sort_values(lastrow,ascending=False,inplace=True)
2247
- df2=dftt.T
2248
-
2249
- # 最上层线标志
2250
- firstline=True
2251
-
2252
- #绘制折线图
2253
- ax=plt.gca()
2254
- print('')
2255
- y_end_list=[]
2256
- for c in collist:
2257
- pos=collist.index(c)
2258
- try:
2259
- lsc=lslist[pos]
2260
- except:
2261
- print(" #Bug(draw_lines): lslist=",lslist,",pos=",pos)
2262
- mkc=mklist[pos]
2263
-
2264
- # 连接折线中非交易日的断开区间
2265
- import pandas as pd
2266
- dfg=pd.DataFrame(df2[c]).copy(deep=True)
2267
-
2268
- # 慎用dropna
2269
- #dfg=dfg.dropna(inplace=True)
2270
- if dfg is None:
2271
- print(" #Error(draw_lines): null dataframe for graphics in column",c)
2272
- continue
2273
- if len(dfg)==0:
2274
- print(" #Error(draw_lines): no data for graphics in column",c)
2275
- continue
2276
-
2277
- #plt.plot(dfg,label=c,linewidth=linewidth,ls=lsc,marker=mkc,markersize=3)
2278
- lwadjust=linewidth_adjust(dfg)
2279
-
2280
- """
2281
- if not annotate:
2282
-
2283
- #注意:许多传入的df字段名已经不是证券代码,此处调用codetranslate将会导致
2284
- #股票名称字典重新下载,耗费时间,且出现黄条。
2285
- #建议:在调用draw_lines之前,先调用codetranslate,将证券代码翻译为证券名称。
2286
- #本函数仅负责绘图,不负责翻译证券名称。
2287
-
2288
- #plt.plot(dfg,label=codetranslate(c),linewidth=linewidth,ls=lsc,marker=mkc,markersize=3)
2289
- plt.plot(dfg,label=c,linewidth=lwadjust,ls=lsc,marker=mkc,markersize=3)
2290
- else:
2291
- #plt.plot(dfg[c],label=codetranslate(c),linewidth=linewidth,ls=lsc,marker=mkc,markersize=3)
2292
- #plt.plot(dfg,label=codetranslate(c),linewidth=linewidth,ls=lsc,marker=mkc,markersize=3)
2293
- plt.plot(dfg,label=c,linewidth=lwadjust,ls=lsc,marker=mkc,markersize=3)
2294
- """
2295
- if not annotate or c in ["平均值","中位数"]:
2296
- if c in ["平均值","中位数"]:
2297
- clabel=c+str(round(dfg[c].values[0],2))
2298
- else:
2299
- clabel=c
2300
- plt.plot(dfg,label=auto_translate2(clabel,translate),linewidth=lwadjust,ls=lsc,marker=mkc,markersize=3)
2301
- else:
2302
- plt.plot(dfg,linewidth=lwadjust,ls=lsc,marker=mkc,markersize=3)
2303
-
2304
- lines = plt.gca().lines
2305
- last_line_color = lines[-1].get_color()
2306
-
2307
- if annotate and (c not in ["平均值","中位数"]):
2308
- mark_end=False
2309
- df_end=dfg.tail(1)
2310
- # df_end[c]必须为数值类型,否则可能出错
2311
- y_end = df_end[c].min() # 末端的y坐标
2312
- x_end = df_end[c].idxmin() # 末端值的x坐标
2313
-
2314
- if annotate_value: #在标记曲线名称的同时标记其末端数值
2315
- #y1=str(int(y_end)) if y_end >= 100 else str(round(y_end,2))
2316
- y1=str(round(y_end,2)) if abs(y_end) >= 100 else str(round(y_end,precision)) if abs(y_end) >= 1 else str(round(y_end,precision))
2317
- plt.annotate(text=' '+auto_translate2(c,translate)+': '+y1,
2318
- xy=(x_end, y_end),
2319
- xytext=(x_end, y_end),fontsize=annotate_size,
2320
- color=last_line_color)
2321
- else:
2322
- plt.annotate(text=' '+auto_translate2(c,translate),
2323
- xy=(x_end, y_end),
2324
- #xytext=(x_end, y_end),fontsize=9)
2325
- xytext=(x_end, y_end),fontsize=annotate_size,
2326
- color=last_line_color)
2327
-
2328
- #plt.plot(df[c],label=c,linewidth=1.5,marker=mkc,markersize=3)
2329
- #为折线加数据标签
2330
- if data_label==True:
2331
- mark_top=False; mark_bottom=False; mark_end=False
2332
- for a,b in zip(dfg.index,df2[c]):
2333
- plt.text(a,b+0.02,str(round(b,2)), \
2334
- ha='center',va='bottom',fontsize=7)
2335
-
2336
- #标记最高点/最低点
2337
- if (mark_top or mark_bottom) and (c not in ["平均值","中位数"]):
2338
- df_mark=dfg[[c]].copy() #避免影响原df
2339
- df_mark.dropna(inplace=True)
2340
- df_mark.sort_values(by=c,ascending=False,inplace=True)
2341
-
2342
- if mark_top:
2343
- df_mark_top=df_mark[:1]
2344
- for x, y in zip(df_mark_top.index, df_mark_top[c]):
2345
- #y1=round(y+high_low*0.01,2)
2346
- y1=y+high_low*0.01
2347
- #s='%.0f' if y >= 100 else '%.2f'
2348
- s='%.1f' if abs(y) >= 100 else '%.2f' if abs(y) >= 1 else '%.4f'
2349
- #plt.text(x,y1,s % y,ha='center',va='bottom',color='red')
2350
- plt.text(x,y1,s % y,ha='right',va='bottom',color=last_line_color)
2351
- plt.scatter(x,y, color='red',marker='8',s=70)
2352
-
2353
- if mark_bottom:
2354
- df_mark_bottom=df_mark[-1:]
2355
- for x, y in zip(df_mark_bottom.index, df_mark_bottom[c]):
2356
- #y1=round(y-high_low*0.055,2) #标记位置对应y1的底部
2357
- y1=y-high_low*0.050 #标记位置对应y1的底部
2358
- #s='%.0f' if y >= 100 else '%.2f'
2359
- s='%.1f' if abs(y) >= 100 else '%.2f' if abs(y) >= 1 else '%.4f'
2360
- #plt.text(x,y1,s % y,ha='center',va='bottom',color='seagreen')
2361
- plt.text(x,y1,s % y,ha='right',va='bottom',color=last_line_color)
2362
- plt.scatter(x,y, color='seagreen',marker='8',s=70)
2363
-
2364
- #标记曲线开始数值
2365
- if mark_start and (c not in ["平均值","中位数"]):
2366
- df_end=dfg.head(1)
2367
- y_end = df_end[c].min() # 开始的y坐标
2368
- x_end = df_end[c].idxmin() # 开始值的x坐标
2369
-
2370
- #y1=str(int(y_end)) if y_end >= 100 else str(round(y_end,2))
2371
- y1=str(round(y_end,1)) if abs(y_end) >= 100 else str(round(y_end,precision)) if abs(y_end) >= 1 else str(round(y_end,precision))
2372
- plt.annotate(text=' '+y1,
2373
- xy=(x_end, y_end),
2374
- xytext=(x_end, y_end*0.998),fontsize=annotate_size,
2375
- color=last_line_color,ha='right',va='center')
2376
-
2377
- #标记曲线末端数值
2378
- if mark_end and (c not in ["平均值","中位数"]):
2379
- df_end=dfg.tail(1)
2380
- y_end = df_end[c].min() # 末端的y坐标
2381
- x_end = df_end[c].idxmin() # 末端值的x坐标
2382
-
2383
- #y1=str(int(y_end)) if y_end >= 100 else str(round(y_end,2))
2384
- y1=str(round(y_end,1)) if abs(y_end) >= 100 else str(round(y_end,precision)) if abs(y_end) >= 1 else str(round(y_end,precision))
2385
- plt.annotate(text=' '+y1,
2386
- xy=(x_end, y_end),
2387
- xytext=(x_end, y_end*0.998),fontsize=annotate_size,
2388
- color=last_line_color,ha='left',va='center')
2389
-
2390
- #用于关注值的颜色列表
2391
- atv_color_list=["lightgray","paleturquoise","wheat","khaki","lightsage","hotpink","mediumslateblue"]
2392
- #用于关注点的颜色列表
2393
- atp_color_list=["crimson","dodgerblue","magenta","lightseagreen","chocolate","hotpink","mediumslateblue"]
2394
-
2395
- if not attention_value=='':
2396
- if isinstance(attention_value,int) or isinstance(attention_value,float):
2397
- atv_list=[attention_value]
2398
- elif isinstance(attention_value,list):
2399
- atv_list=attention_value
2400
- else:
2401
- atv_list=[]
2402
- if not atv_list==[] and not atv_list==['']:
2403
- for at in atv_list:
2404
- pos=atv_list.index(at)
2405
- color=atv_color_list[pos]
2406
- plt.axhline(y=at,ls=":",c=color,linewidth=2,label=text_lang("关注值","Attention value ")+str(at))
2407
-
2408
- if not attention_value_area=='':
2409
- if isinstance(attention_value_area,list) and len(attention_value_area)>=2:
2410
- plt.fill_between(dfg.index,attention_value_area[0],attention_value_area[1],color='lightgray',alpha=0.5)
2411
-
2412
- #绘制曲线之间的带状区域
2413
- if DEBUG:
2414
- print(f"dfg={dfg}")
2415
-
2416
- if band_area != '' and isinstance(band_area,list) and len(band_area)>=2:
2417
- upper_line=band_area[0]; lower_line=band_area[1]
2418
- if upper_line not in collist:
2419
- upper_line=ectranslate(upper_line)
2420
- lower_line=ectranslate(lower_line)
2421
-
2422
- if upper_line not in collist:
2423
- upper_line=ticker_name(upper_line)
2424
- lower_line=ticker_name(lower_line)
2425
-
2426
- if upper_line not in collist:
2427
- upper_line=None
2428
- lower_line=None
2429
-
2430
- if not (upper_line is None) and not (lower_line is None):
2431
- try:
2432
- plt.fill_between(df2.index,df2[upper_line],df2[lower_line],df2[upper_line] > df2[lower_line],color='aquamarine',alpha=0.5,label='',interpolate=True)
2433
- plt.fill_between(df2.index,df2[upper_line],df2[lower_line],df2[upper_line] < df2[lower_line],color='lightcoral',alpha=0.5,label='',interpolate=True)
2434
- except:
2435
- print(f" #Warning(draw_lines): band area elements {upper_line} or {lower_line} not found")
2436
-
2437
- import pandas as pd
2438
- from datetime import datetime; date_format="%Y-%m-%d"
2439
- from datetime import datetime; date_format="%Y-%m-%d"
2440
- if not attention_point=='':
2441
- if isinstance(attention_point,str) or isinstance(attention_point,int) or isinstance(attention_point,float):
2442
- atp_list=[attention_point]
2443
- elif isinstance(attention_point,list):
2444
- atp_list=attention_point
2445
- else:
2446
- atp_list=[]
2447
- #去重,不打乱原来的顺序
2448
- atp_list=list(dict.fromkeys(atp_list))
2449
-
2450
- if not atp_list==[] and not atp_list==['']:
2451
-
2452
- for at in atp_list:
2453
- try:
2454
- pos=atp_list.index(at)
2455
- color=atp_color_list[pos]
2456
- except:
2457
- print("*** in draw_lines:")
2458
- print("atp_list={0},at={1},pos={2}".format(atp_list,at,pos))
2459
- print("atp_color_list={0}".format(atp_color_list))
2460
-
2461
- color=atp_color_list[-1]
2462
-
2463
- try:
2464
- #判断是否日期字符串
2465
- at=datetime.strptime(at, date_format)
2466
- #若是日期字符串
2467
- atpd=pd.to_datetime(at)
2468
- except:
2469
- #不是日期字符串
2470
- atpd=at
2471
-
2472
- """
2473
- #纵轴最小值
2474
- yaxis_min=plt.ylim()[0]
2475
- arrow_dx=0
2476
- #各曲线在关注点的最大值
2477
- point_max=dfg.loc[atpd].max()
2478
- arrow_dy=point_max - yaxis_min
2479
-
2480
- if DEBUG:
2481
- print("*** In draw_lines:")
2482
- print("dfg.loc[atpd]",dfg.loc[atpd].values)
2483
- print("yaxis_min=",yaxis_min)
2484
- print("point_max=",point_max)
2485
- print("arrow_dy=",arrow_dy)
2486
-
2487
- plt.arrow(atpd,yaxis_min,arrow_dx,arrow_dy,ls=':',lw=2,fc=color,ec=color,alpha=0.5,shape='full', \
2488
- width=0.05,length_includes_head=True)
2489
- """
2490
-
2491
- try:
2492
- at_str=atpd.strftime('%Y-%m-%d')
2493
- except:
2494
- at_str=atpd
2495
- #plt.axvline(x=atpd,ls=":",c=color,linewidth=1.5,label=text_lang("关注点","Attention point ")+str(at))
2496
- plt.axvline(x=atpd,ls=":",c=color,linewidth=1.5,label=text_lang("关注点","Attention point ")+at_str)
2497
-
2498
- if not attention_point_area=='':
2499
- if isinstance(attention_point_area,list) and len(attention_point_area)>=2:
2500
- apa_list=[]
2501
- for ap in attention_point_area:
2502
- try:
2503
- ap=datetime.strptime(ap, date_format)
2504
- appd=pd.to_datetime(ap)
2505
- except:
2506
- appd=ap
2507
- apa_list=apa_list+[appd]
2508
-
2509
- yaxis_data=plt.ylim()
2510
- plt.fill_betweenx(yaxis_data,apa_list[0],apa_list[1],color='powderblue',alpha=0.5)
2511
-
2512
- #绘制水平辅助线
2513
- if axhline_label !="":
2514
- if '零线' in axhline_label:
2515
- axhline_label=''
2516
-
2517
- max_values = df2.max(numeric_only=True); global_max_values=max_values.max()
2518
- min_values = df2.min(numeric_only=True); global_min_values=min_values.min()
2519
- if global_max_values >= axhline_value and global_min_values <= axhline_value:
2520
- plt.axhline(y=axhline_value,label=auto_translate2(axhline_label,translate),color='black',linestyle=':',linewidth=2)
2521
- #plt.axhline(y=axhline_value,color='purple',linestyle=':',linewidth=1.5)
2522
-
2523
- #坐标轴标记
2524
- y_label_t=ectranslate(y_label)
2525
- plt.ylabel(auto_translate2(y_label_t,translate),fontweight='bold',fontsize=ylabel_txt_size)
2526
-
2527
- x_label_t=ectranslate(x_label)
2528
- if x_label != "":
2529
- plt.xlabel(auto_translate2(x_label_t,translate),fontweight='bold',fontsize=xlabel_txt_size,ha='center')
2530
- #图示标题
2531
- plt.title(auto_translate2(title_txt,translate),fontweight='bold',fontsize=title_txt_size)
2532
-
2533
- if not isinstance(maxticks,bool):
2534
- if maxticks_enable:
2535
- # 使用 AutoDateLocator 自动选择最佳间隔,目的是显示最后一个日期,亲测有效!!!
2536
- import matplotlib.dates as mdates
2537
- ax.xaxis.set_major_locator(mdates.AutoDateLocator(maxticks=maxticks))
2538
-
2539
- plt.gcf().autofmt_xdate(ha="center") # 优化标注(自动倾斜)
2540
- try:
2541
- plt.gca().set_facecolor(facecolor)
2542
- except:
2543
- print(" #Warning(draw_lines): color",facecolor,"is unsupported, changed to default setting")
2544
- plt.gca().set_facecolor("whitesmoke")
2545
-
2546
- # 若不绘制annotate,则绘制图例
2547
- #if not annotate:
2548
- #检查是否存在可绘制的标签,若有则绘制
2549
- if DEBUG:
2550
- have_label=False
2551
- for line in plt.gca().lines:
2552
- print(f" DEBUG: plt.gca().lines, line={line.get_label()}")
2553
- if line.get_label() != '':
2554
- have_label=True
2555
-
2556
- #plt.legend没有图例标签时会提示信息No artists...
2557
- if not annotate or attention_value !='' or attention_point !='':
2558
- plt.legend(loc=loc,fontsize=legend_txt_size)
2559
-
2560
- """
2561
- if any([line.get_label() != '' for line in plt.gca().lines]):
2562
- tuli=plt.legend(loc=loc,fontsize=legend_txt_size)
2563
- if DEBUG:
2564
- print(f" DEBUG: result of plt.legend is {tuli}")
2565
- """
2566
- if plus_sign:
2567
- # 尝试改变纵轴刻度格式:给正数添加正号+,以便突出显示增减幅度
2568
- import matplotlib.ticker as ticker
2569
- ax = plt.gca()
2570
- bare0 = lambda y, pos: ('%+g' if y>0 else '%g')%y
2571
- #bare0 = lambda y, pos: ('%+g%' if y>0 else '%g%')%y #此处%为全角,无法适配英文环境,放弃!
2572
- ax.yaxis.set_major_formatter(ticker.FuncFormatter(bare0))
2573
-
2574
- plt.show()
2575
-
2576
- return
2577
-
2578
- if __name__=='__main__':
2579
- title_txt="Stock Risk \nCAPM Beta Trends"
2580
- draw_lines(df,"market line",1.0,"Beta coefficient","",title_txt)
2581
-
2582
- #==============================================================================
2583
- def draw_lines2(df0,y_label,x_label,axhline_value,axhline_label,title_txt, \
2584
- data_label=False,resample_freq='1D',smooth=True, \
2585
- date_range=False,date_freq=False,date_fmt='%Y-%m-%d', \
2586
- colorlist=[],lslist=[],lwlist=[], \
2587
- #指定纵轴两个变量之间的区域
2588
- band_area='',loc='best', \
2589
- attention_value='', \
2590
- #指定纵轴两个数值之间的区域
2591
- attention_value_area='', \
2592
- attention_point='', \
2593
- #指定两个横轴之间的区域
2594
- attention_point_area='', \
2595
- annotate=False,annotate_value=False, \
2596
- mark_start=False,mark_top=False,mark_bottom=False,mark_end=False, \
2597
- facecolor='whitesmoke',maxticks=20,translate=False):
2598
- """
2599
- 函数功能:根据df的内容绘制折线图
2600
- 输入参数:
2601
- df:数据框。有几个字段就绘制几条折现。必须索引,索引值将作为X轴标记点
2602
- 要求:df的索引为pandas的datetime日期型
2603
- axhline_label: 水平辅助线标记。如果为空值则不绘制水平辅助线
2604
- axhline_value: 水平辅助线的y轴位置
2605
- y_label:y轴标记
2606
- x_label:x轴标记
2607
- title_txt:标题。如需多行,中间用\n分割
2608
-
2609
- smooth=True:默认进行曲线平滑处理,对于部分长期停牌的股票/债券,应选择不进行平滑处理False,否则曲线会严重失真。
2610
-
2611
- 输出:
2612
- 绘制折线图
2613
- 无返回数据
2614
- 注意:需要日期类型作为df索引
2615
-
2616
- band_area='':默认为空,否则为列表,第1个值为带状区域上边沿字段,第2个值为带状区域下边沿字段
2617
- """
2618
- import pandas as pd
2619
-
2620
- DEBUG=False
2621
- if DEBUG:
2622
- print(f"band_area={band_area}")
2623
- print(f"df0={df0}")
2624
-
2625
- #空值判断
2626
- if len(df0) ==0:
2627
- print (" #Warning(draw_lines): no data to plot.")
2628
- return
2629
-
2630
- #插值平滑
2631
- if smooth and not isinstance(maxticks,bool):
2632
- print(" Smoothening curves ...")
2633
- try:
2634
- df=df_smooth_manual(df0,resample_freq=resample_freq)
2635
- except:
2636
- df=df0
2637
- else:
2638
- df=df0
2639
-
2640
- # 所有字段转换为数值类型,以防万一
2641
- for c in list(df):
2642
- try:
2643
- df[c]=df[c].astype('float')
2644
- except:
2645
- del df[c]
2646
-
2647
- # 计算所有列中的最大最小差距,假设所有列均为数值型!
2648
- dfmax=df.max().max(); dfmin=df.min().min()
2649
- high_low=dfmax - dfmin
2650
-
2651
- #定义横轴标签:显示完整开始、结束日期
2652
- if not isinstance(maxticks,bool):
2653
- ax=plt.gca()
2654
- date_start=df.index[0]
2655
- date_end=df.index[-1]
2656
- if date_range and not date_freq:
2657
- ax.xaxis.set_major_formatter(mdate.DateFormatter(date_fmt))
2658
- plt.xticks(pd.date_range(date_start,date_end))
2659
- if not date_range and date_freq:
2660
- ax.xaxis.set_major_formatter(mdate.DateFormatter(date_fmt))
2661
- plt.xticks(pd.date_range(freq=date_freq))
2662
- if date_range and date_freq:
2663
- ax.xaxis.set_major_formatter(mdate.DateFormatter(date_fmt))
2664
- plt.xticks(pd.date_range(date_start,date_end,freq=date_freq))
2665
-
2666
- #取得df字段名列表
2667
- collist=df.columns.values.tolist()
2668
- collist3=collist[:3] #专用于绘制布林带,取前3个字段
2669
-
2670
- if lslist==[]:
2671
- lslist=['-','--','-.',':','-','--','-.',':','-','--','-.',':','-','--','-.',':',]
2672
- if colorlist==[]:
2673
- colorlist=['blue','tomato','green','chocolate','darksage','cyan','blueviolet','violet','darkcyan','gold','wheat','silver','darkred','brown','coral','pink',]
2674
-
2675
- print('')
2676
- #绘制折线图
2677
- for c in collist:
2678
- pos=collist.index(c)
2679
- try:
2680
- lcolor=colorlist[pos]
2681
- except:
2682
- lcolor=''
2683
- try:
2684
- lls=lslist[pos]
2685
- except:
2686
- lls=''
2687
- try:
2688
- llw=lwlist[pos]
2689
- except:
2690
- llw=linewidth_adjust(df)
2691
-
2692
- if (lcolor !='') and (lls !=''):
2693
- if not annotate:
2694
- plt.plot(df[c],label=auto_translate2(c,translate),linewidth=llw,ls=lls,color=lcolor)
2695
- else:
2696
- plt.plot(df[c],linewidth=llw,ls=lls,color=lcolor)
2697
- elif (lcolor !=''):
2698
- if not annotate:
2699
- plt.plot(df[c],label=auto_translate2(c,translate),linewidth=llw,color=lcolor)
2700
- else:
2701
- plt.plot(df[c],linewidth=llw,color=lcolor)
2702
- else:
2703
- if not annotate:
2704
- plt.plot(df[c],label=auto_translate2(c,translate),linewidth=llw)
2705
- else:
2706
- plt.plot(df[c],linewidth=llw)
2707
-
2708
- lines = plt.gca().lines; last_line_color = lines[-1].get_color()
2709
-
2710
- #为折线加数据标签
2711
- if data_label==True:
2712
- mark_top=False; mark_bottom=False; mark_end=False
2713
- for a,b in zip(df.index,df[c]):
2714
- plt.text(a,b+0.02,str(round(b,2)), \
2715
- ha='center',va='bottom',fontsize=7)
2716
-
2717
- #标记最高点/最低点
2718
- if mark_top or mark_bottom:
2719
- df_mark=df[[c]].copy() #避免影响原df
2720
- df_mark.dropna(inplace=True)
2721
- df_mark.sort_values(by=c,ascending=False,inplace=True)
2722
-
2723
- if mark_top:
2724
- df_mark_top=df_mark[:1]
2725
- for x, y in zip(df_mark_top.index, df_mark_top[c]):
2726
- #y1=round(y+high_low*0.01,2)
2727
- y1=y+high_low*0.01
2728
- #s='%.0f' if y >= 100 else '%.2f'
2729
- s='%.1f' if abs(y) >= 100 else '%.2f' if abs(y) >= 1 else '%.4f'
2730
- #plt.text(x,y1,s % y,ha='center',va='bottom',color='red')
2731
- plt.text(x,y1,s % y,ha='right',va='bottom',color=last_line_color)
2732
- plt.scatter(x,y, color='red',marker='8',s=70)
2733
-
2734
- if mark_bottom:
2735
- df_mark_bottom=df_mark[-1:]
2736
- for x, y in zip(df_mark_bottom.index, df_mark_bottom[c]):
2737
- #y1=round(y-high_low*0.055,2) #标记位置对应y1的底部
2738
- y1=y-high_low*0.050 #标记位置对应y1的底部
2739
- #s='%.0f' if y >= 100 else '%.2f'
2740
- s='%.1f' if abs(y) >= 100 else '%.2f' if abs(y) >= 1 else '%.4f'
2741
- #plt.text(x,y1,s % y,ha='center',va='bottom',color='seagreen')
2742
- plt.text(x,y1,s % y,ha='right',va='bottom',color=last_line_color)
2743
- plt.scatter(x,y, color='seagreen',marker='8',s=70)
2744
-
2745
- #曲线末端标记:不建议用于布林带
2746
- if annotate:
2747
- df_end=df.tail(1)
2748
- y_end = df_end[c].min() # 末端的y坐标
2749
- x_end = df_end[c].idxmin() # 末端值的x坐标
2750
-
2751
- if annotate_value: #在标记曲线名称的同时标记其末端数值
2752
- #y1=str(int(y_end)) if y_end >= 100 else str(round(y_end,2))
2753
- y1=str(int(y_end)) if abs(y_end) >= 100 else str(round(y_end,2)) if abs(y_end) >= 10 else str(round(y_end,4))
2754
- plt.annotate(text=auto_translate2(c,translate)+': '+y1,
2755
- xy=(x_end, y_end),
2756
- xytext=(x_end, y_end),fontsize=annotate_size,
2757
- color=last_line_color)
2758
- else:
2759
- plt.annotate(text=auto_translate2(c,translate),
2760
- xy=(x_end, y_end),
2761
- xytext=(x_end, y_end),fontsize=annotate_size,
2762
- color=last_line_color)
2763
-
2764
- #标记曲线开始数值
2765
- if mark_start:
2766
- df_start=df.head(1)
2767
- y_start = df_start[c].min() # 开始的y坐标
2768
- x_start = df_start[c].idxmin() # 开始值的x坐标
2769
-
2770
- #y1=str(int(y_end)) if y_end >= 100 else str(round(y_end,2))
2771
- y1=str(round(y_start,1)) if abs(y_start) >= 100 else str(round(y_start,2)) if abs(y_start) >= 1 else str(round(y_start,3))
2772
- plt.annotate(text=y1,
2773
- xy=(x_start, y_start),
2774
- xytext=(x_start, y_start*0.998),fontsize=annotate_size,ha='right',va='center')
2775
- # 特别注意:这里的left/right与实际图示的方向正好相反!!!
2776
-
2777
- #处理布林带的mark_end,仅标记上中下线
2778
- if mark_end & (c in collist3):
2779
- df_end=df.tail(1)
2780
- y_end = df_end[c].min() # 末端的y坐标
2781
- x_end = df_end[c].idxmin() # 末端值的x坐标
2782
-
2783
- #y1=str(int(y_end)) if y_end >= 100 else str(round(y_end,2))
2784
- y1=str(round(y_end,1)) if abs(y_end) >= 100 else str(round(y_end,2)) if abs(y_end) >= 1 else str(round(y_end,3))
2785
- plt.annotate(text=y1,
2786
- xy=(x_end, y_end),
2787
- xytext=(x_end, y_end),fontsize=annotate_size,
2788
- color=last_line_color)
2789
-
2790
- #绘制带状区域
2791
- if band_area != '' and isinstance(band_area,list) and len(band_area)>=2:
2792
- upper_line=band_area[0]; lower_line=band_area[1]
2793
- if upper_line not in collist:
2794
- upper_line=ectranslate(upper_line)
2795
- lower_line=ectranslate(lower_line)
2796
-
2797
- if upper_line not in collist:
2798
- upper_line=ticker_name(upper_line)
2799
- lower_line=ticker_name(lower_line)
2800
-
2801
- if upper_line not in collist:
2802
- upper_line=None
2803
- lower_line=None
2804
-
2805
- if not (upper_line is None) and not (lower_line is None):
2806
- try:
2807
- """
2808
- plt.fill_between(df.index,df[upper_line],df[lower_line],color='moccasin',alpha=0.5,label='',where=df[upper_line]>=df[lower_line])
2809
- plt.fill_between(df.index,df[upper_line],df[lower_line],color='aquamarine',alpha=0.5,label='',where=df[upper_line]<=df[lower_line])
2810
- """
2811
- #plt.fill_between(df.index,df[upper_line],df[lower_line],color='aquamarine',alpha=0.5,label='')
2812
- plt.fill_between(df.index,df[upper_line],df[lower_line],df[upper_line] > df[lower_line],color='aquamarine',alpha=0.5,label='',interpolate=True)
2813
- plt.fill_between(df.index,df[upper_line],df[lower_line],df[upper_line] < df[lower_line],color='lightcoral',alpha=0.5,label='',interpolate=True)
2814
- #plt.fill_between(df.index,df[upper_line],df[lower_line],df[upper_line] == df[lower_line],color='lightgray',alpha=0.5,label='')
2815
- except:
2816
- print(f" #Warning(draw_lines2): lack of data for either {upper_line} or {lower_line}")
2817
- #return None
2818
-
2819
- #绘制水平辅助线
2820
- if axhline_label !="":
2821
- if DEBUG:
2822
- print("DEBUG: draw axhline_label=",axhline_label)
2823
-
2824
- if "零线" in axhline_label:
2825
- plt.axhline(y=axhline_value,color='black',linestyle='--',linewidth=2)
2826
- else:
2827
- plt.axhline(y=axhline_value,label=axhline_label,color='black',linestyle='--',linewidth=2)
2828
-
2829
- #用于关注值的颜色列表
2830
- atv_color_list=["lightgray","paleturquoise","wheat","khaki","lightsage"]
2831
- #用于关注点的颜色列表
2832
- atp_color_list=["crimson","dodgerblue","magenta","lightseagreen","chocolate"]
2833
-
2834
- if not attention_value=='':
2835
- if isinstance(attention_value,int) or isinstance(attention_value,float):
2836
- atv_list=[attention_value]
2837
- elif isinstance(attention_value,list):
2838
- atv_list=attention_value
2839
- else:
2840
- atv_list=[]
2841
- if not atv_list==[] and not atv_list==['']:
2842
- for at in atv_list:
2843
- pos=atv_list.index(at)
2844
- color=atv_color_list[pos]
2845
- plt.axhline(y=at,ls=":",c=color,linewidth=2,label=text_lang("关注值","Attention value ")+str(at))
2846
-
2847
- if not attention_value_area=='':
2848
- if isinstance(attention_value_area,list) and len(attention_value_area)>=2:
2849
- plt.fill_between(df.index,attention_value_area[0],attention_value_area[1],color='lightgray',alpha=0.5)
2850
-
2851
- import pandas as pd
2852
- from datetime import datetime; date_format="%Y-%m-%d"
2853
- if not attention_point=='':
2854
- if isinstance(attention_point,str) or isinstance(attention_point,int) or isinstance(attention_point,float):
2855
- atp_list=[attention_point]
2856
- elif isinstance(attention_point,list):
2857
- atp_list=attention_point
2858
- else:
2859
- atp_list=[]
2860
- #去重,不打乱原来的顺序
2861
- atp_list=list(dict.fromkeys(atp_list))
2862
-
2863
- if not atp_list==[] and not atp_list==['']:
2864
- for at in atp_list:
2865
- pos=atp_list.index(at)
2866
- color=atp_color_list[pos]
2867
-
2868
- #判断是否日期字符串
2869
- try:
2870
- at=datetime.strptime(at, date_format)
2871
- atpd=pd.to_datetime(at)
2872
- except:
2873
- atpd=at
2874
-
2875
- try:
2876
- at_str=atpd.strftime('%Y-%m-%d')
2877
- except:
2878
- at_str=atpd
2879
-
2880
- #plt.axvline(x=atpd,ls=":",c=color,linewidth=1.5,label=text_lang("关注点","Attention point ")+str(at))
2881
- plt.axvline(x=atpd,ls=":",c=color,linewidth=1.5,label=text_lang("关注点","Attention point ")+at_str)
2882
-
2883
- if not attention_point_area=='':
2884
- if isinstance(attention_point_area,list) and len(attention_point_area)>=2:
2885
- apa_list=[]
2886
- for ap in attention_point_area:
2887
- try:
2888
- ap=datetime.strptime(ap, date_format)
2889
- appd=pd.to_datetime(ap)
2890
- except:
2891
- appd=ap
2892
- apa_list=apa_list+[appd]
2893
-
2894
- yaxis_data=plt.ylim()
2895
- plt.fill_betweenx(yaxis_data,apa_list[0],apa_list[1],color='powderblue',alpha=0.5)
2896
-
2897
- #坐标轴标记
2898
- plt.ylabel(auto_translate2(y_label,translate),fontweight='bold',fontsize=ylabel_txt_size)
2899
- if x_label != "":
2900
- plt.xlabel(auto_translate2(x_label,translate),fontweight='bold',fontsize=xlabel_txt_size,ha='center')
2901
- #图示标题
2902
- plt.title(auto_translate2(title_txt,translate),fontweight='bold',fontsize=title_txt_size)
2903
-
2904
- # 使用 AutoDateLocator 自动选择最佳间隔,目的是显示最后一个日期,亲测有效!!!
2905
- if not isinstance(maxticks,bool):
2906
- import matplotlib.dates as mdates
2907
- ax.xaxis.set_major_locator(mdates.AutoDateLocator(maxticks=maxticks))
2908
-
2909
- plt.gcf().autofmt_xdate(ha="center") # 优化标注(自动倾斜)
2910
- try:
2911
- plt.gca().set_facecolor(facecolor)
2912
- except:
2913
- print(" #Warning(draw_lines2): color",facecolor,"is unsupported, changed to default setting")
2914
- plt.gca().set_facecolor("whitesmoke")
2915
-
2916
- #if not annotate:
2917
- #plt.legend没有图例标签时会提示信息No artists...
2918
- if not annotate or attention_value !='' or attention_point !='':
2919
- plt.legend(loc=loc,fontsize=legend_txt_size)
2920
-
2921
- #设置绘图风格:关闭网格虚线
2922
- plt.rcParams['axes.grid']=False
2923
-
2924
- plt.show()
2925
-
2926
- return
2927
-
2928
- #==============================================================================
2929
- def plot_barh(df,colname,titletxt,footnote,datatag=True, \
2930
- colors=['r','g','b','c','m','y','aquamarine','dodgerblue', \
2931
- 'deepskyblue','silver'],tag_offset=0.01,axisamp=1.3, \
2932
- facecolor='whitesmoke'):
2933
- """
2934
- 功能:绘制水平单值柱状图,并可标注数据标签。
2935
- 输入:数据集df;列名colname;标题titletxt;脚注footnote;
2936
- 是否绘制数据标签datatag,默认是;柱状图柱子色彩列表。
2937
- 输出:水平柱状图
2938
- """
2939
- #空值判断
2940
- if len(df) ==0:
2941
- print (" #Warning(plot_barh): no data to plot.")
2942
- return
2943
-
2944
- plt.barh(df.index,df[colname],align='center',color=colors,alpha=0.8)
2945
- coltxt=ectranslate(colname)
2946
- plt.xlabel(footnote,fontsize=xlabel_txt_size,ha='center')
2947
- plt.title(titletxt,fontweight='bold',fontsize=title_txt_size)
2948
-
2949
- #xmin=int(min(df[colname]))
2950
- xmin0=min(df[colname])
2951
- if xmin0 > 0:
2952
- xmin=xmin0*0.8
2953
- else:
2954
- xmin=xmin0*1.05
2955
- #xmax=(int(max(df[colname]))+1)*1.1
2956
- xmax0=max(df[colname])
2957
- if not (xmax0 == 0):
2958
- scale_max=abs((xmax0-xmin0)/xmax0)*axisamp #经验值放大倍数
2959
- xmax=xmax0*scale_max
2960
- else:
2961
- scale_max=abs((xmax0-xmin0))*axisamp
2962
- xmax=xmax0+scale_max
2963
-
2964
- """
2965
- if xmax0 > 0:
2966
- xmax=xmax0*1.8
2967
- else:
2968
- xmax=xmax0*1.2
2969
- """
2970
- plt.xlim([xmin,xmax])
2971
-
2972
- tag_off=tag_offset * xmax
2973
- for x,y in enumerate(list(df[colname])):
2974
- #plt.text(y+0.1,x,'%s' % y,va='center')
2975
- plt.text(y+tag_off,x,'%s' % y,va='center')
2976
-
2977
- """
2978
- yticklist=list(df.index)
2979
- yticknames=[]
2980
- for yt in yticklist:
2981
- ytname=codetranslate(yt)
2982
- yticknames=yticknames+[ytname]
2983
- """
2984
- yticknames=list(df.index)
2985
- plt.yticks(df.index,yticknames)
2986
-
2987
- try:
2988
- plt.gca().set_facecolor(facecolor)
2989
- except:
2990
- print(" #Warning(plot_barh): color",facecolor,"is unsupported, changed to default setting")
2991
- plt.gca().set_facecolor("whitesmoke")
2992
-
2993
- plt.show(); plt.close()
2994
-
2995
- return
2996
-
2997
- #==============================================================================
2998
- if __name__=='__main__':
2999
- import pandas as pd
3000
- df = pd.read_excel('S:/QTEMP/px_test.xlsx',header=0, index_col=0)
3001
-
3002
- colname='Exp Ret%'
3003
- titletxt="This is a title"
3004
- footnote="This is a footnote"
3005
-
3006
- def plot_barh2(df,colname,titletxt,footnote,facecolor='lightblue'):
3007
- """
3008
- 功能:绘制水平单值柱状图,并在外侧标注数据标签。
3009
- 输入:数据集df;列名colname;标题titletxt;脚注footnote;
3010
- 输出:水平柱状图
3011
- 注意:在Spyder中可能工作不正常,使用plotly_express.bar
3012
- """
3013
- #空值判断
3014
- if len(df) ==0:
3015
- print (" #Warning(plot_barh): no data to plot.")
3016
- return
3017
-
3018
- #改造df
3019
- df['ycolname']=df.index
3020
- df['xcolname']=df[colname]
3021
- xlabel=colname+'颜色棒'
3022
- df[xlabel]=df[colname]
3023
-
3024
- #import plotly_express as px
3025
- import plotly.express as px
3026
-
3027
- fig=px.bar(data_frame = df,
3028
- y='ycolname', #纵轴绘制的字段
3029
- x=colname, #横轴绘制的字段
3030
- color=xlabel, #基于df中xlabel字段的数值大小配色,并将xlabel作为颜色棒顶部的标注
3031
- orientation='h', #绘制水平直方图
3032
- text=colname, #在直方图顶端标数字
3033
- labels={'ycolname':'',colname:footnote,xlabel:''} #将字段改名作为纵轴、横轴或颜色棒的标注
3034
- )
3035
-
3036
- fig.update_coloraxes(showscale=False) # 隐藏颜色条
3037
-
3038
- fig.update_traces(textposition='outside',#直方图顶端的数值标在外侧
3039
- )
3040
-
3041
- fig.update_layout(
3042
- title={
3043
- 'text': titletxt, # 标题名称
3044
- 'y':0.95, # 位置,坐标轴的长度看做1
3045
- 'x':0.5,
3046
- 'xanchor': 'center', # 相对位置
3047
- 'yanchor': 'top'},
3048
- plot_bgcolor=facecolor, #设置画布背景颜色
3049
- coloraxis_showscale=False, #彻底移除颜色条,需要升级plotly!
3050
- )
3051
-
3052
- fig.show()
3053
-
3054
- return
3055
-
3056
- if __name__=='__main__':
3057
- plot_barh2(df,colname,titletxt,footnote)
3058
- #==============================================================================
3059
-
3060
- #==============================================================================
3061
- #==============================================================================
3062
- def plot_2lines(df01,colname1,label1, \
3063
- df02,colname2,label2, \
3064
- ylabeltxt,titletxt,footnote,hline=0,vline=0,resample_freq='D', \
3065
- date_range=False,date_freq=False,date_fmt='%Y-%m-%d', \
3066
- facecolor='whitesmoke', \
3067
- maxticks=15):
3068
- """
3069
- 功能:绘制两个证券的折线图。如果hline=0不绘制水平虚线,vline=0不绘制垂直虚线
3070
- 假定:数据表有日期索引,且已经按照索引排序
3071
- 输入:
3072
- 证券1:数据表df1,列名1,列名标签1;
3073
- 证券2:数据表df2,列名2,列名标签2;
3074
- 标题titletxt,脚注footnote
3075
- 输出:绘制同轴折线图
3076
-
3077
- 若date_range=True,尽量在横轴上标注日期的起止时间
3078
- 若date_freq不为False,可以为类似于'3m'或'1Y'等
3079
- date_fmt可以为'%Y-%m-%d'或'%Y-%m'或'%Y'等
3080
-
3081
- 返回值:无
3082
- """
3083
- import pandas as pd
3084
-
3085
- #空值判断
3086
- if len(df01) ==0:
3087
- print (" #Warning(plot_2lines): no data to plot df01.")
3088
- if len(df02) ==0:
3089
- print (" #Warning(plot_2lines): no data to plot df02.")
3090
- if (len(df01) ==0) and (len(df02) ==0):
3091
- return
3092
-
3093
- #插值平滑
3094
- if not isinstance(maxticks,bool):
3095
- try:
3096
- df01x=df01[[colname1]].astype('float')
3097
- df1=df_smooth_manual(df01x,resample_freq=resample_freq)
3098
- except:
3099
- df1=df01
3100
-
3101
- try:
3102
- df02x=df02[[colname2]].astype('float')
3103
- df2=df_smooth_manual(df02x,resample_freq=resample_freq)
3104
- except:
3105
- df2=df02
3106
- else:
3107
- df1=df01; df2=df02
3108
-
3109
- plt.title(titletxt,fontweight='bold',fontsize=title_txt_size)
3110
-
3111
- #证券1:先绘制折线图
3112
- if not isinstance(maxticks,bool):
3113
- date_start=df1.index[0]
3114
- date_end=df1.index[-1]
3115
- if date_range and not date_freq:
3116
- ax=plt.gca()
3117
- ax.xaxis.set_major_formatter(mdate.DateFormatter(date_fmt))
3118
- plt.xticks(pd.date_range(date_start,date_end))
3119
- if not date_range and date_freq:
3120
- ax=plt.gca()
3121
- ax.xaxis.set_major_formatter(mdate.DateFormatter(date_fmt))
3122
- plt.xticks(pd.date_range(freq=date_freq))
3123
- if date_range and date_freq:
3124
- ax=plt.gca()
3125
- ax.xaxis.set_major_formatter(mdate.DateFormatter(date_fmt))
3126
- plt.xticks(pd.date_range(date_start,date_end,freq=date_freq))
3127
-
3128
- lwadjust=linewidth_adjust(df1)
3129
- plt.plot(df1.index,df1[colname1],label=label1,linestyle='-',linewidth=lwadjust)
3130
-
3131
- #证券2:先绘制折线图
3132
- if not isinstance(maxticks,bool):
3133
- date_start=df2.index[0]
3134
- date_end=df2.index[-1]
3135
- if date_range and not date_freq:
3136
- ax=plt.gca()
3137
- ax.xaxis.set_major_formatter(mdate.DateFormatter(date_fmt))
3138
- plt.xticks(pd.date_range(date_start,date_end))
3139
- if not date_range and date_freq:
3140
- ax=plt.gca()
3141
- ax.xaxis.set_major_formatter(mdate.DateFormatter(date_fmt))
3142
- plt.xticks(pd.date_range(freq=date_freq))
3143
- if date_range and date_freq:
3144
- ax=plt.gca()
3145
- ax.xaxis.set_major_formatter(mdate.DateFormatter(date_fmt))
3146
- plt.xticks(pd.date_range(date_start,date_end,freq=date_freq))
3147
-
3148
- lwadjust=linewidth_adjust(df2)
3149
- plt.plot(df2.index,df2[colname2],label=label2,linestyle='-.',linewidth=lwadjust)
3150
-
3151
- #是否绘制水平虚线
3152
- if not (hline == 0):
3153
- plt.axhline(y=hline,ls=":",c="black")
3154
- #是否绘制垂直虚线
3155
- if not (vline == 0):
3156
- plt.axvline(x=vline,ls=":",c="black")
3157
-
3158
- plt.ylabel(ylabeltxt,fontsize=ylabel_txt_size)
3159
- plt.xlabel(footnote,fontsize=xlabel_txt_size,ha='center')
3160
- plt.legend(loc='best',fontsize=legend_txt_size)
3161
-
3162
- # 使用 AutoDateLocator 自动选择最佳间隔,目的是显示最后一个日期,亲测有效!!!
3163
- if not isinstance(maxticks,bool):
3164
- import matplotlib.dates as mdates
3165
- ax=plt.gca()
3166
- ax.xaxis.set_major_locator(mdates.AutoDateLocator(maxticks=maxticks))
3167
-
3168
- plt.gcf().autofmt_xdate(ha="center") # 优化标注(自动倾斜)
3169
- try:
3170
- plt.gca().set_facecolor(facecolor)
3171
- except:
3172
- print(" #Warning(plot_2lines): color",facecolor,"is unsupported, changed to default setting")
3173
- plt.gca().set_facecolor("whitesmoke")
3174
-
3175
- plt.show()
3176
-
3177
- return
3178
-
3179
- if __name__ =="__main__":
3180
- df1=bsm_call_maturity(42,40,[50,200],0.015,0.23,90,1.5)
3181
- df2=bsm_put_maturity(42,40,[50,200],0.015,0.23,90,1.5)
3182
- ticker1='A'; colname1='Option Price'; label1='A1'
3183
- ticker2='B'; colname2='Option Price'; label2='B2'
3184
- ylabeltxt='ylabel'; titletxt='title'; footnote='\n\n\n\n4lines'
3185
- power=0; datatag1=False; datatag2=False; zeroline=False
3186
-
3187
- #==============================================================================
3188
- def df_smooth(df):
3189
- """
3190
- 功能:对df中的数值型样本进行插值,以便绘制的折线图相对平滑。
3191
- 要求:df的索引为pandas的datetime日期型
3192
- 注意1:如果样本数量较多,例如多于100个,平滑效果不明显。
3193
- 注意2:order阶数仅对'spline'和'polynomial'方法有效,其中'polynomial'方法的阶数只能为奇数。
3194
- """
3195
-
3196
- # df索引项若非日期型,不适合采用本函数进行插值
3197
- import pandas as pd
3198
- if not pd.api.types.is_datetime64_any_dtype(df.index):
3199
- return df
3200
-
3201
- #如果样本个数多于100个,其实没必要进行平滑,因为看不出效果
3202
- if len(df) >= 100: return df
3203
-
3204
- #定义重采样频率
3205
- """
3206
- 常用的采样频率:
3207
- H: hourly, BH: business hour, T: minutely, S: secondly, B: business day, W: weekly,
3208
- SM: semi-month end, SMS: semi-month start,
3209
- BMS: business month start,BM: business month end,
3210
- BQ: business quarter end, BQS: business quarter start,
3211
- BA/BY: business year end, BAS/BYS: business year start.
3212
-
3213
- 例如:
3214
- df2=df.resample('2D').sum()
3215
- df2=df.resample('W').mean()
3216
- """
3217
- #将索引转换为Datetimeindex,不然resample会失败
3218
- df['date']=pd.to_datetime(df.index)
3219
- df.set_index('date',inplace=True)
3220
-
3221
- #重新采样
3222
- rflag=False
3223
- freqlist=['H','B','W','M','Q']
3224
- for f in freqlist:
3225
- try:
3226
- #dfh=df.resample(f).ffill()
3227
- dfh=df.resample(f)
3228
- except:
3229
- continue
3230
- else:
3231
- rflag=True
3232
- break
3233
-
3234
- if not rflag:
3235
- #print(' #Warning(df_smooth): resampling failed for frequency',freqlist)
3236
- dfh=df
3237
-
3238
- #重采样后插值
3239
- methodlist=['pchip','nearest','cubic','quadratic','slinear','linear','zero','time','index', \
3240
- 'piecewise_polynomial','akima','from_derivatives','spline','polynomial']
3241
- methodlist_order=['spline','polynomial']
3242
- order=3
3243
- for method in methodlist:
3244
- if method in methodlist_order:
3245
- try:
3246
- dfm=dfh.interpolate(method=method,order=order)
3247
- except:
3248
- #print(' #Warning(df_smooth): interpolate failed for method',method,'with order',order)
3249
- #若出错就原样返回
3250
- return df
3251
- else: break
3252
- else:
3253
- try:
3254
- dfm=dfh.interpolate(method=method)
3255
- except:
3256
- #print(' #Warning(df_smooth): interpolate failed for method',method)
3257
- return df
3258
- else: break
3259
-
3260
- #成功返回经过重采样的df
3261
- return dfm
3262
-
3263
-
3264
- #==============================================================================
3265
- def df_smooth_manual(df,method='linear',resample_freq='D',order=3):
3266
- """
3267
- 功能:对df中的第一个数值列样本进行插值,以便绘制的折线图相对平滑。
3268
- 要求:df的索引为pandas的datetime日期型
3269
- 注意1:如果样本数量较多,例如多于100个,平滑效果不明显。
3270
- 注意2:order阶数仅对'spline'和'polynomial'方法有效,其中'polynomial'方法的阶数只能为奇数。
3271
- 注意3:pchip方法经常失败,可改为cubic
3272
- """
3273
-
3274
- # df索引项若非日期型,不适合采用本函数进行插值
3275
- import pandas as pd
3276
- if not pd.api.types.is_datetime64_any_dtype(df.index):
3277
- return df
3278
-
3279
- #如果样本个数多于100个,没必要进行平滑,完全看不出效果
3280
- if len(df) >= 100: return df
3281
-
3282
- #检查插值方法是否支持
3283
- methodlist=['quadratic','cubic','slinear','linear','zero','nearest','time','index', \
3284
- 'piecewise_polynomial','pchip','akima','from_derivatives','spline','polynomial']
3285
- if not (method in methodlist): return df
3286
-
3287
- #定义重采样频率
3288
- """
3289
- 常用的采样频率:
3290
- H: hourly, BH: business hour, T: minutely, S: secondly, B: business day, W: weekly,
3291
- SM: semi-month end, SMS: semi-month start,
3292
- BMS: business month start,BM: business month end,
3293
- BQ: business quarter end, BQS: business quarter start,
3294
- BA/BY: business year end, BAS/BYS: business year start.
3295
-
3296
- 例如:
3297
- df2=df.resample('2D').sum()
3298
- df2=df.resample('W').mean()
3299
- """
3300
- #将索引转换为Datetimeindex,不然resample会失败
3301
- try:
3302
- df['date']=pd.to_datetime(df.index)
3303
- except:
3304
- return df
3305
- df.set_index('date',inplace=True)
3306
-
3307
- #重新采样
3308
- try:
3309
- dfh=df.resample(resample_freq)
3310
- except:
3311
- print(' #Warning(df_smooth): resampling failed for frequency',resample_freq)
3312
- return df
3313
-
3314
- #重采样后插值(不然太多nan):是否methodlist_o里面的特别插值方法
3315
- methodlist_o=['spline','polynomial']
3316
- if method in methodlist_o:
3317
- try:
3318
- dfm=dfh.interpolate(method=method,order=order)
3319
- except:
3320
- print(' #Warning(df_smooth_manual): interpolate failed for method',method,'with order',order)
3321
- #若出错就原样返回
3322
- return df
3323
- #成功返回经过重采样的df
3324
- return dfm
3325
-
3326
- #重采样后插值:其他插值方法
3327
- try:
3328
- dfm=dfh.interpolate(method=method)
3329
- except:
3330
- #print(' #Warning(df_smooth_manual): interpolate failed for method',method)
3331
- #print(' Possible reason: interpolating row must be int or float instead of string')
3332
- """
3333
- #改为cubic方法
3334
- if not (method == 'cubic'):
3335
- try:
3336
- dfm=dfh.interpolate(method='cubic')
3337
- except:
3338
- print(' #Warning(df_smooth_manual): interpolate failed for method cubic')
3339
- return df
3340
- else:
3341
- return df
3342
- """
3343
- return df
3344
-
3345
- # check whether dfm becomes empty
3346
- if len(dfm)==0:
3347
- return df
3348
- else:
3349
- return dfm
3350
- #==============================================================================
3351
- if __name__=='__main__':
3352
- wid=5
3353
- mu=0
3354
- sd=1
3355
- obs_num=100
3356
-
3357
- def plot_norm(mu,sd,graph='pdf',obs_num=100,facecolor='whitesmoke'):
3358
- """
3359
- 绘制正态分布图形
3360
- mu:均值
3361
- sd:标准差
3362
- graph:图形种类,pdf,cdf,ppf
3363
- """
3364
- if not (graph in ['pdf','cdf','ppf']):
3365
- print(" #Warning(plot_norm): support pdf/cdf/ppf only")
3366
- return
3367
-
3368
- #计算概率密度:连续分布用pdf,离散分布用pmf
3369
- import scipy.stats as st
3370
- import numpy as np
3371
-
3372
- if graph=='pdf':
3373
- wid=4*sd+mu
3374
- X=np.linspace(-wid,wid,obs_num)
3375
- y_pdf=st.norm.pdf(X,mu,sd)
3376
-
3377
- if graph=='cdf':
3378
- wid=3*sd+mu
3379
- X=np.linspace(-wid,wid,obs_num)
3380
- y_cdf=st.norm.cdf(X,mu,sd)
3381
-
3382
- if graph=='ppf':
3383
- X=np.linspace(0,1,obs_num)
3384
- y_ppf=st.norm.ppf(X,mu,sd)
3385
-
3386
- #绘图
3387
- if graph=='pdf':
3388
- plt.plot(X,y_pdf,c="red",label='pdf')
3389
- if graph=='cdf':
3390
- plt.plot(X,y_cdf,c="blue",label='cdf')
3391
- if graph=='ppf':
3392
- plt.plot(X,y_ppf,c="green",label='ppf')
3393
-
3394
- if graph=='pdf':
3395
- wid1=5*sd+mu
3396
- wid2=1*sd+mu
3397
- plt.xticks(np.arange(-wid,wid1,wid2))
3398
- plt.xlabel('分位点',fontsize=xlabel_txt_size,ha='center') #x轴文本
3399
- plt.yticks(np.arange(0,0.45,0.05))
3400
- plt.ylabel('概率密度',fontsize=ylabel_txt_size) #y轴文本
3401
-
3402
- if graph=='cdf':
3403
- wid1=3.5*sd+mu
3404
- wid2=0.5*sd+mu
3405
- plt.xticks(np.arange(-wid,wid1,wid2))
3406
- plt.xlabel('分位点',fontsize=xlabel_txt_size,ha='center') #x轴文本
3407
- plt.yticks(np.arange(0,1.1,0.1))
3408
- plt.ylabel('累积概率密度',fontsize=ylabel_txt_size) #y轴文本
3409
-
3410
- if graph=='ppf':
3411
- wid=2.5*sd+mu
3412
- wid1=3*sd+mu
3413
- wid2=0.5*sd+mu
3414
- plt.yticks(np.arange(-wid,wid1,wid2))
3415
- plt.ylabel('分位点',fontsize=ylabel_txt_size) #y轴文本
3416
- plt.xticks(np.arange(0,1.1,0.1))
3417
- plt.xlabel('累积概率密度',fontsize=xlabel_txt_size,ha='center') #x轴文本
3418
-
3419
- plt.title('正态分布示意图: $\mu$=%.1f, $\sigma$=%.1f'%(mu,sd),fontweight='bold',fontsize=title_txt_size) #标题
3420
- plt.tight_layout()
3421
- #plt.grid() #网格
3422
- plt.legend(loc='best',fontsize=legend_txt_size)
3423
-
3424
- try:
3425
- plt.gca().set_facecolor(facecolor)
3426
- except:
3427
- print(" #Warning(plot_norm): color",facecolor,"is unsupported, changed to default setting")
3428
- plt.gca().set_facecolor("whitesmoke")
3429
-
3430
- plt.show() #显示图形
3431
-
3432
- return
3433
-
3434
- if __name__=='__main__':
3435
- plot_norm(4,mu,sd,graph='pdf')
3436
- plot_norm(3,mu,sd,graph='cdf')
3437
- plot_norm(3,mu,sd,graph='ppf')
3438
-
3439
- #==============================================================================
3440
- #==============================================================================
3441
-
3442
- if __name__=='__main__':
3443
- firstColSpecial=True
3444
- colWidth=0.1
3445
- tabScale=2
3446
- figsize=(12.8,6.4)
3447
- cellLoc='right'
3448
- fontsize=10
3449
-
3450
- firstColSpecial=False
3451
- cellLoc='center'
3452
- auto_len=True
3453
-
3454
- df=market_detail_china(category='price')
3455
- pandas2plttable(df)
3456
-
3457
- def pandas2plttable(df,titletxt,firstColSpecial=True,colWidth=0.1,tabScale=2,cellLoc='right', \
3458
- figsize=(12.8,6.4),fontsize=13,auto_len=False,title_x=0.5):
3459
- """
3460
- 功能:将一个df转换为matplotlib表格格式,打印图形表格,适应性广
3461
- firstColSpecial:第一列是否特殊处理,默认True
3462
-
3463
- 注意1:引入表格的字段不包括索引字段
3464
- """
3465
-
3466
- #列名列表
3467
- col=list(df)
3468
- numOfCol=len(col)
3469
-
3470
- # 第一列长度取齐处理
3471
- if firstColSpecial:
3472
- #第一列的最长长度
3473
- firstcol=col[0]
3474
- maxlen=0
3475
- for f in firstcol:
3476
- flen=hzlen(f.strip())
3477
- if flen > maxlen:
3478
- maxlen=flen
3479
-
3480
- #将第一列内容的长度取齐
3481
- df[col[0]]=df[col[0]].apply(lambda x:equalwidth(x.strip(),maxlen=maxlen,extchar=' ',endchar=' '))
3482
-
3483
- #设置每列的宽度
3484
- col_len_list=[]
3485
- col_len_list_rel=[]
3486
- if auto_len:
3487
-
3488
- # 计算每列的相对宽度
3489
- for c in col:
3490
- heading_len=hzlen(c.strip())
3491
- df['col_len']=df[c].apply(lambda x: hzlen(x.strip()))
3492
- field_len=df['col_len'].max()
3493
- col_len=max([heading_len,field_len])
3494
-
3495
- col_len_list=col_len_list+[col_len]
3496
-
3497
- col_len_min=min(col_len_list)
3498
- for l in col_len_list:
3499
- rel_len=l / col_len_min
3500
- col_len_list_rel=col_len_list_rel+[round(rel_len*colWidth,3)]
3501
-
3502
- del df['col_len']
3503
-
3504
-
3505
- #表格里面的具体值
3506
- vals=[]
3507
- for i in range(0,len(df)):
3508
- vals=vals+[list(df.iloc[i])]
3509
-
3510
- plt.figure(figsize=figsize)
3511
-
3512
- if not auto_len:
3513
- tab = plt.table(cellText=vals,
3514
- colLabels=col,
3515
- loc='best',
3516
- cellLoc=cellLoc)
3517
- else:
3518
- tab = plt.table(cellText=vals,
3519
- colLabels=col,
3520
- colWidths=col_len_list_rel,
3521
- loc='best',
3522
- rowLoc='center',
3523
- cellLoc=cellLoc)
3524
-
3525
-
3526
- tab.scale(1,tabScale) #让表格纵向扩展tabScale倍数
3527
-
3528
- # 试验参数:查询tab对象的属性使用dir(tab)
3529
- tab.auto_set_font_size(False)
3530
- tab.set_fontsize(fontsize)
3531
-
3532
- if auto_len:
3533
- tab.auto_set_column_width(True) #此功能有bug,只能对前几列起作用
3534
-
3535
- plt.axis('off') #关闭plt绘制纵横轴线
3536
-
3537
- #plt.xlabel(footnote,fontsize=xlabel_txt_size)
3538
- if not auto_len:
3539
- plt.title(titletxt,fontweight='bold',fontsize=title_txt_size)
3540
- else:
3541
- plt.title(titletxt,fontweight='bold',fontsize=title_txt_size,x=title_x)
3542
-
3543
- plt.gca().set_facecolor('whitesmoke')
3544
-
3545
- plt.show()
3546
-
3547
- return
3548
-
3549
- #==============================================================================
3550
-
3551
- if __name__=='__main__':
3552
- firstColSpecial=True
3553
- colWidth=0.1
3554
- tabScale=2
3555
- figsize=(10,6)
3556
- cellLoc='right'
3557
- fontsize=10
3558
-
3559
- firstColSpecial=False
3560
- cellLoc='center'
3561
- auto_len=True
3562
-
3563
- df=market_detail_china(category='price')
3564
- pandas2plttable(df)
3565
-
3566
- def pandas2plttable2(df,titletxt,firstColSpecial=True,cellLoc='right'):
3567
- """
3568
- 功能:将一个df转换为matplotlib表格格式,打印图形表格,适应性广,自动适应列宽和字体大小
3569
- firstColSpecial:第一列是否特殊处理,默认True
3570
-
3571
- 注意1:引入表格的字段不包括索引字段
3572
- """
3573
-
3574
- df.fillna('',inplace=True)
3575
-
3576
- #列名列表
3577
- col=list(df)
3578
- numOfCol=len(col)
3579
-
3580
- # 第一列长度取齐处理
3581
- if firstColSpecial:
3582
-
3583
- #第一列的最长长度
3584
- firstcol=col[0]
3585
- maxlen=0
3586
- for f in df[firstcol]:
3587
- flen=hzlen(f)
3588
- if flen > maxlen:
3589
- maxlen=flen
3590
-
3591
- #将第一列内容的长度取齐
3592
- extchar='.'
3593
- df[firstcol]=df[firstcol].apply(lambda x: str(x) + extchar*(maxlen-hzlen(x)))
3594
-
3595
-
3596
- #表格里面的具体值
3597
- vals=[]
3598
- for i in range(0,len(df)):
3599
- vals=vals+[list(df.iloc[i])]
3600
-
3601
- plt.figure()
3602
-
3603
- tab = plt.table(cellText=vals,
3604
- colLabels=col,
3605
- loc='best',
3606
- rowLoc='center',
3607
- cellLoc=cellLoc)
3608
-
3609
- #tab.scale(1,tabScale) #让表格纵向扩展tabScale倍数
3610
-
3611
- # 试验参数:查询tab对象的属性使用dir(tab)
3612
- tab.auto_set_font_size(True)
3613
-
3614
- tab.auto_set_column_width(True) #此功能有bug,只能对前几列起作用
3615
-
3616
- plt.axis('off') #关闭plt绘制纵横轴线
3617
-
3618
- plt.title(titletxt)
3619
-
3620
- plt.gca().set_facecolor('whitesmoke')
3621
-
3622
- plt.show()
3623
-
3624
- return
3625
-
3626
-
3627
- #==============================================================================
3628
- #==============================================================================
3629
-
3630
-
3631
-
3632
-
3633
-
3634
-
3635
-
3636
-