siat 3.8.28__py3-none-any.whl → 3.8.35__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.
siat/grafix.py CHANGED
@@ -106,7 +106,7 @@ if __name__ =="__main__":
106
106
  power=0
107
107
  zeroline=False
108
108
  average_value=False
109
- resample_freq='H'
109
+ resample_freq='D'
110
110
  loc='best'
111
111
  date_range=False
112
112
  date_freq=False
@@ -122,9 +122,9 @@ def plot_line(df0,colname,collabel,ylabeltxt,titletxt,footnote,datatag=False, \
122
122
  attention_point='',attention_point_area='', \
123
123
  average_value=False, \
124
124
 
125
- resample_freq='H',loc='best', \
125
+ resample_freq='D',loc='best', \
126
126
  date_range=False,date_freq=False,date_fmt='%Y-%m-%d', \
127
- mark_top=True,mark_bottom=True,mark_end=True, \
127
+ mark_start=False,mark_top=True,mark_bottom=True,mark_end=True, \
128
128
  facecolor='whitesmoke',maxticks=15,translate=False):
129
129
  """
130
130
  功能:绘制折线图。如果power=0不绘制趋势图,否则绘制多项式趋势图
@@ -203,7 +203,7 @@ def plot_line(df0,colname,collabel,ylabeltxt,titletxt,footnote,datatag=False, \
203
203
 
204
204
  #绘制数据标签
205
205
  if datatag:
206
- mark_top=False; mark_bottom=False; mark_end=False
206
+ mark_start=False; mark_top=False; mark_bottom=False; mark_end=False
207
207
  for x, y in zip(df.index, df[colname]):
208
208
  plt.text(x,y*1.001,'%.2f' % y,ha='center',va='bottom',color='black')
209
209
 
@@ -243,6 +243,19 @@ def plot_line(df0,colname,collabel,ylabeltxt,titletxt,footnote,datatag=False, \
243
243
  plt.text(x,y1,s % y,ha='right',va='bottom',color='seagreen')
244
244
  plt.scatter(x,y, color='seagreen',marker='8',s=70)
245
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
+
246
259
  #标记曲线末端数值
247
260
  if mark_end:
248
261
  df_end=df.tail(1)
@@ -253,7 +266,7 @@ def plot_line(df0,colname,collabel,ylabeltxt,titletxt,footnote,datatag=False, \
253
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))
254
267
  plt.annotate(text=' '+y1,
255
268
  xy=(x_end, y_end),
256
- xytext=(x_end, y_end),fontsize=annotate_size)
269
+ xytext=(x_end, y_end*0.998),fontsize=annotate_size,ha='left',va='center')
257
270
 
258
271
  #是否绘制水平线
259
272
  if isinstance(zeroline,bool):#若zeroline为True
@@ -340,13 +353,15 @@ def plot_line(df0,colname,collabel,ylabeltxt,titletxt,footnote,datatag=False, \
340
353
  plt.fill_betweenx(yaxis_data,apa_list[0],apa_list[1],color='powderblue',alpha=0.5)
341
354
 
342
355
  if average_value:
343
- av=df[colname].mean()
344
- plt.axhline(y=av,ls="dashed",c="blueviolet",linewidth=2,label=text_lang("均值","Mean"))
345
356
  haveLegend=True
357
+
358
+ av=df[colname].mean()
346
359
  #av=str(round(av,2)) if av < 100 else str(int(av))
347
- av=str(int(av)) if abs(av) >= 100 else str(round(av,2)) if abs(av) >= 10 else str(round(av,3))
360
+ #av=str(int(av)) if abs(av) >= 100 else str(round(av,2)) if abs(av) >= 10 else str(round(av,3))
361
+ avstr=str(int(av)) if abs(av) >= 100 else str(round(av,2)) if abs(av) >= 10 else str(round(av,3))
362
+ plt.axhline(y=av,ls="dashed",c="blueviolet",linewidth=2,label=text_lang("本期间均值","Periodic mean")+avstr)
348
363
  #footnote=footnote + ",均值"+av
349
- footnote=text_lang("注:期间均值","Note: Periodic mean ")+av+"; "+footnote
364
+ #footnote=text_lang("注:期间均值","Note: Periodic mean ")+av+"; "+footnote
350
365
 
351
366
  #绘制趋势线
352
367
  #print("--Debug(plot_line): power=",power)
@@ -412,16 +427,17 @@ if __name__ =="__main__":
412
427
  twinx=False
413
428
  yline=999
414
429
  xline=999
415
- resample_freq='H'
430
+ resample_freq='D'
416
431
 
417
432
  def plot_line2(df1,ticker1,colname1,label1, \
418
433
  df2,ticker2,colname2,label2, \
419
434
  ylabeltxt,titletxt,footnote, \
420
435
  power=0,datatag1=False,datatag2=False,yscalemax=5, \
421
- zeroline=False,twinx=False, \
436
+ zeroline=False, \
437
+ twinx=False, \
422
438
  yline=999,attention_value_area='', \
423
439
  xline=999,attention_point_area='', \
424
- resample_freq='H',loc1='best',loc2='best', \
440
+ resample_freq='D',loc1='best',loc2='best', \
425
441
  color1='red',color2='blue',facecolor='whitesmoke', \
426
442
  maxticks=20):
427
443
  """
@@ -450,7 +466,36 @@ def plot_line2(df1,ticker1,colname1,label1, \
450
466
  print("Going to plot_line2_coaxial")
451
467
  print("yline=",yline,"; xline=",xline)
452
468
 
453
- if not twinx:
469
+ #if not twinx:
470
+ if twinx == True: # 双轴会图
471
+ plot_line2_twinx(df1,ticker1,colname1,label1, \
472
+ df2,ticker2,colname2,label2, \
473
+ titletxt,footnote,power,datatag1,datatag2, \
474
+ resample_freq=resample_freq, \
475
+ xline=xline,attention_point_area=attention_point_area, \
476
+ loc1=loc1,loc2=loc2, \
477
+ color1=color1,color2=color2,facecolor=facecolor, \
478
+ maxticks=maxticks)
479
+ elif 'LR' in twinx.upper(): # 左右双图
480
+ plot_line2_LR(df1,ticker1,colname1,label1, \
481
+ df2,ticker2,colname2,label2, \
482
+ titletxt,footnote,power,datatag1,datatag2, \
483
+ resample_freq=resample_freq, \
484
+ xline=xline,attention_point_area=attention_point_area, \
485
+ loc1=loc1,loc2=loc2, \
486
+ color1=color1,color2=color2,facecolor=facecolor, \
487
+ maxticks=maxticks)
488
+ elif 'UD' in twinx.upper(): # 上下双图
489
+ plot_line2_UD(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
+
498
+ else: # twinx == False # 正常绘图
454
499
  plot_line2_coaxial(df1,ticker1,colname1,label1, \
455
500
  df2,ticker2,colname2,label2, \
456
501
  ylabeltxt,titletxt,footnote,power,datatag1,datatag2,zeroline, \
@@ -460,15 +505,7 @@ def plot_line2(df1,ticker1,colname1,label1, \
460
505
  loc1=loc1,loc2=loc2, \
461
506
  color1=color1,color2=color2,facecolor=facecolor, \
462
507
  maxticks=maxticks)
463
- else:
464
- plot_line2_twinx(df1,ticker1,colname1,label1, \
465
- df2,ticker2,colname2,label2, \
466
- titletxt,footnote,power,datatag1,datatag2, \
467
- resample_freq=resample_freq, \
468
- xline=xline,attention_point_area=attention_point_area, \
469
- loc1=loc1,loc2=loc2, \
470
- color1=color1,color2=color2,facecolor=facecolor, \
471
- maxticks=maxticks)
508
+
472
509
  return
473
510
 
474
511
 
@@ -480,7 +517,7 @@ def plot2_line2(df1,ticker1,colname1,label1, \
480
517
  zeroline=False,twinx=False, \
481
518
  yline=999,attention_value_area='', \
482
519
  xline=999,attention_point_area='', \
483
- resample_freq='H',loc1='best',loc2='best', \
520
+ resample_freq='D',loc1='best',loc2='best', \
484
521
  date_range=False,date_freq=False,date_fmt='%Y-%m-%d', \
485
522
  color1='red',color2='blue',facecolor='whitesmoke', \
486
523
  maxticks=20):
@@ -547,7 +584,7 @@ def plot_line2_coaxial(df01,ticker1,colname1,label1, \
547
584
  power=0,datatag1=False,datatag2=False,zeroline=False, \
548
585
  yline=999,attention_value_area='', \
549
586
  xline=999,attention_point_area='', \
550
- resample_freq='H', \
587
+ resample_freq='D', \
551
588
  loc1='best',loc2='best', \
552
589
  color1='red',color2='blue',facecolor='whitesmoke', \
553
590
  ticker_type='auto',maxticks=15):
@@ -760,7 +797,10 @@ def plot_line2_coaxial(df01,ticker1,colname1,label1, \
760
797
 
761
798
  # 使用 AutoDateLocator 自动选择最佳间隔,目的是显示最后一个日期,亲测有效!!!
762
799
  import matplotlib.dates as mdates
763
- ax.xaxis.set_major_locator(mdates.AutoDateLocator(maxticks=maxticks))
800
+ try:
801
+ ax.xaxis.set_major_locator(mdates.AutoDateLocator(maxticks=maxticks))
802
+ except:
803
+ pass
764
804
 
765
805
  plt.gcf().autofmt_xdate(ha="center") # 优化标注(自动倾斜)
766
806
  try:
@@ -802,7 +842,7 @@ def plot_line2_coaxial2(df01,ticker1,colname1,label1, \
802
842
  power=0,datatag1=False,datatag2=False,zeroline=False, \
803
843
  yline=999,attention_value_area='', \
804
844
  xline=999,attention_point_area='', \
805
- resample_freq='H', \
845
+ resample_freq='D', \
806
846
  loc1='best',loc2='best', \
807
847
  date_range=False,date_freq=False,date_fmt='%Y-%m-%d', \
808
848
  color1='red',color2='blue',facecolor='whitesmoke', \
@@ -1060,7 +1100,7 @@ def plot_line2_coaxial2(df01,ticker1,colname1,label1, \
1060
1100
  def plot_line2_twinx(df01,ticker1,colname1,label1, \
1061
1101
  df02,ticker2,colname2,label2, \
1062
1102
  titletxt,footnote,power=0,datatag1=False,datatag2=False, \
1063
- resample_freq='H', \
1103
+ resample_freq='D', \
1064
1104
  xline=999,attention_point_area='', \
1065
1105
  loc1='upper left',loc2='lower left', \
1066
1106
  color1='red',color2='blue',facecolor='whitesmoke', \
@@ -1280,16 +1320,507 @@ if __name__ =="__main__":
1280
1320
  df2,'600266.SS','Close','收盘价', \
1281
1321
  "证券价格走势对比图","数据来源:新浪/stooq")
1282
1322
 
1283
- plot_line2_twinx(df1,'000002.SZ','Close','收盘价', \
1323
+ plot_line2_LR(df1,'000002.SZ','Close','收盘价', \
1284
1324
  df2,'600266.SS','Close','收盘价', \
1285
1325
  "证券价格走势对比图","数据来源:新浪/stooq",power=3)
1286
1326
 
1327
+ #==============================================================================
1328
+ def plot_line2_LR(df01,ticker1,colname1,label1, \
1329
+ df02,ticker2,colname2,label2, \
1330
+ titletxt,footnote,power=0, \
1331
+ datatag1=False,datatag2=False, \
1332
+ resample_freq='D', \
1333
+ xline=999,attention_point_area='', \
1334
+ loc1='upper left',loc2='lower left', \
1335
+ color1='red',color2='blue',facecolor='whitesmoke', \
1336
+ ticker_type='auto', \
1337
+ maxticks=15):
1338
+ """
1339
+ 功能:绘制两个证券或指标的左右折线图。如果power=0不绘制趋势图,否则绘制多项式趋势图
1340
+ 假定:数据表有索引,且已经按照索引排序
1341
+ 输入:
1342
+ 证券1:数据表df1,证券代码ticker1,列名1,列名标签1;
1343
+ 证券2:数据表df2,证券代码ticker2,列名2,列名标签2;
1344
+ 标题titletxt,脚注footnote;是否在图中标记数据datatag;趋势图的多项式次数power
1345
+ 输出:绘制左右并列折线图
1346
+ 返回值:无
1347
+ 注意:需要日期类型作为df索引
1348
+ """
1349
+ DEBUG=False
1350
+
1351
+ #plt.rcParams['axes.grid']=False
1352
+
1353
+ #插值平滑
1354
+ try:
1355
+ df01x=df01[[colname1]].astype('float')
1356
+ df1=df_smooth_manual(df01x,resample_freq=resample_freq)
1357
+ except:
1358
+ df1=df01
1359
+ try:
1360
+ df02x=df02[[colname2]].astype('float')
1361
+ df2=df_smooth_manual(df02x,resample_freq=resample_freq)
1362
+ except:
1363
+ df2=df02
1364
+
1365
+ #预处理ticker_type
1366
+ ticker_type_list=ticker_type_preprocess_mticker_mixed([ticker1,ticker2],ticker_type)
1367
+
1368
+ #创建画布:绘制折线图,左右双子图
1369
+ fig, (ax, ax2) = plt.subplots(1, 2)
1370
+
1371
+ #设置主标题
1372
+ #plt.suptitle(titletxt,fontweight='bold',fontsize=title_txt_size, y=1.01) # y参数调整垂直位置
1373
+ plt.suptitle(titletxt,fontweight='bold',fontsize=title_txt_size)
1374
+
1375
+ # 绘制左子图================================================================
1376
+ #设置画布背景颜色
1377
+ try:
1378
+ ax.set_facecolor(facecolor)
1379
+ except:
1380
+ print(" #Warning(plot_line2_twinx): color",facecolor,"is unsupported")
1381
+ facecolor="whitesmoke"
1382
+ ax.set_facecolor(facecolor)
1383
+
1384
+ # 设置折线标签
1385
+ if ticker1 == '':
1386
+ label1txt=label1
1387
+ else:
1388
+ if label1 == '':
1389
+ label1txt=ticker_name(ticker1,ticker_type_list[0])
1390
+ else:
1391
+ label1txt=ticker_name(ticker1,ticker_type_list[0])+'('+label1+')'
1392
+
1393
+ # 设置子图标题
1394
+ if ticker1 != ticker2:
1395
+ ax.set_title(label1txt,fontsize=xlabel_txt_size)
1396
+ else:
1397
+ ax.set_title(ectranslate(colname1),fontsize=xlabel_txt_size)
1398
+
1399
+ # 绘图
1400
+ lwadjust=linewidth_adjust(df1)
1401
+ """
1402
+ ax.plot(df1.index,df1[colname1],'-',label=label1txt, \
1403
+ linestyle='-',color=color1,linewidth=lwadjust)
1404
+ """
1405
+ ax.plot(df1.index,df1[colname1],'-', \
1406
+ linestyle='-',color=color1,linewidth=lwadjust)
1407
+
1408
+ #证券1:绘制数据标签
1409
+ if datatag1:
1410
+ for x, y in zip(df1.index, df1[colname1]):
1411
+ ax.text(x,y+0.1,'%.2f' % y,ha='center',va='bottom',color='black')
1412
+
1413
+ #绘制关注点
1414
+ import pandas as pd
1415
+ from datetime import datetime; date_format="%Y-%m-%d"
1416
+ if xline != 999:
1417
+ attention_point=xline
1418
+
1419
+ #用于关注点的颜色列表
1420
+ atp_color_list=["crimson","dodgerblue","magenta","lightseagreen","chocolate"]
1421
+
1422
+ if isinstance(attention_point,str) or isinstance(attention_point,int) or isinstance(attention_point,float):
1423
+ atp_list=[attention_point]
1424
+ elif isinstance(attention_point,list):
1425
+ atp_list=attention_point
1426
+ else:
1427
+ atp_list=[]
1428
+ #去重,不打乱原来的顺序
1429
+ atp_list=list(dict.fromkeys(atp_list))
1430
+
1431
+ if DEBUG:
1432
+ print("In plot_line2_twinx")
1433
+ print("atp_list=",atp_list)
1434
+
1435
+ if not atp_list==[] and not atp_list==['']:
1436
+
1437
+ for at in atp_list:
1438
+ pos=atp_list.index(at)
1439
+ color=atp_color_list[pos]
1440
+
1441
+ #判断是否日期字符串
1442
+ try:
1443
+ at=datetime.strptime(at, date_format)
1444
+ atpd=pd.to_datetime(at)
1445
+ except:
1446
+ atpd=at
1447
+ ax.axvline(x=atpd,ls=":",c=color,linewidth=1.5,label=text_lang("关注点","Attention point ")+str(at))
1448
+
1449
+ if not attention_point_area=='':
1450
+ if isinstance(attention_point_area,list) and len(attention_point_area)>=2:
1451
+ apa_list=[]
1452
+ for ap in attention_point_area:
1453
+ try:
1454
+ ap=datetime.strptime(ap, date_format)
1455
+ appd=pd.to_datetime(ap)
1456
+ except:
1457
+ appd=ap
1458
+ apa_list=apa_list+[appd]
1459
+
1460
+ yaxis_data=plt.ylim()
1461
+ ax.fill_betweenx(yaxis_data,apa_list[0],apa_list[1],color='powderblue',alpha=0.5)
1462
+
1463
+ #绘证券1:制趋势线
1464
+ if power > 0:
1465
+ lang=check_language()
1466
+ trend_txt='趋势线'
1467
+ if lang == 'English':
1468
+ trend_txt='Trend line'
1469
+
1470
+ #生成行号,借此将横轴的日期数量化,以便拟合
1471
+ df1['id']=range(len(df1))
1472
+
1473
+ #设定多项式拟合,power为多项式次数
1474
+ import numpy as np
1475
+ parameter = np.polyfit(df1.id, df1[colname1], power)
1476
+ f = np.poly1d(parameter)
1477
+
1478
+ if ticker1 == '':
1479
+ label1txt=''
1480
+ else:
1481
+ label1txt=ticker_name(ticker1,ticker_type_list[0])+"("+trend_txt+")"
1482
+ ax.plot(df1.index, f(df1.id),"r--", label=label1txt,linewidth=1)
1483
+
1484
+ # 纵轴标签
1485
+ #ax.set_ylabel(label1txt,fontsize=ylabel_txt_size)
1486
+ #ax.legend(loc=loc1,fontsize=legend_txt_size)
1487
+
1488
+ # 横轴标签
1489
+ #ax.set_xlabel(text_lang("日期","Date"),fontsize=xlabel_txt_size,ha='center')
1490
+
1491
+ #绘图右图===================================================================
1492
+ #设置画布背景颜色
1493
+ ax2.set_facecolor(facecolor)
1494
+
1495
+ # 折线标签
1496
+ if ticker2 == '':
1497
+ label2txt=label2
1498
+ else:
1499
+ if label2 == '':
1500
+ label2txt=ticker_name(ticker2,ticker_type_list[1])
1501
+ else:
1502
+ label2txt=ticker_name(ticker2,ticker_type_list[1])+'('+label2+')'
1503
+
1504
+ # 设置子图标题
1505
+ if ticker1 != ticker2:
1506
+ ax2.set_title(label2txt,fontsize=xlabel_txt_size)
1507
+ else:
1508
+ ax2.set_title(ectranslate(colname2),fontsize=xlabel_txt_size)
1509
+
1510
+ # 绘图
1511
+ lwadjust=linewidth_adjust(df2)
1512
+ """
1513
+ ax2.plot(df2.index,df2[colname2],'-',label=label2txt, \
1514
+ linestyle='-.',color=color2,linewidth=lwadjust)
1515
+ """
1516
+ ax2.plot(df2.index,df2[colname2],'-', \
1517
+ linestyle='-.',color=color2,linewidth=lwadjust)
1518
+
1519
+ #证券2:绘制数据标签
1520
+ if datatag2:
1521
+ for x, y in zip(df2.index, df2[colname2]):
1522
+ ax2.text(x,y+0.1,'%.2f' % y,ha='center',va='bottom',color='black')
1523
+
1524
+ #绘证券2:制趋势线
1525
+ if power > 0:
1526
+ lang=check_language()
1527
+ trend_txt='趋势线'
1528
+ if lang == 'English':
1529
+ trend_txt='Trend line'
1530
+
1531
+ #生成行号,借此将横轴的日期数量化,以便拟合
1532
+ df2['id']=range(len(df2))
1533
+
1534
+ #设定多项式拟合,power为多项式次数
1535
+ import numpy as np
1536
+ parameter = np.polyfit(df2.id, df2[colname2], power)
1537
+ f = np.poly1d(parameter)
1538
+
1539
+ if ticker2 == '':
1540
+ label2txt=''
1541
+ else:
1542
+ label2txt=ticker_name(ticker2,ticker_type_list[1])+"("+trend_txt+")"
1543
+ ax2.plot(df2.index, f(df2.id),"c--", label=label2txt,linewidth=1)
1544
+
1545
+ # 纵轴标签
1546
+ #ax2.set_ylabel(label2txt,fontsize=ylabel_txt_size)
1547
+ #ax2.legend(loc=loc2,fontsize=legend_txt_size)
1548
+
1549
+ # 横轴标签
1550
+ #ax2.set_xlabel(text_lang("日期","Date"),fontsize=xlabel_txt_size,ha='center')
1551
+
1552
+ #自动优化x轴标签
1553
+ #ax2.autofmt_xdate(ha="center") # 优化标注(自动倾斜)
1554
+
1555
+ # 共同脚注==================================================================
1556
+ fig.text(0.5,-0.01,footnote,ha='center',fontsize=xlabel_txt_size,color='gray')
1557
+ #plt.xlabel(footnote,ha='center',fontsize=xlabel_txt_size,color='gray')
1558
+
1559
+ # 自动倾斜横轴日期
1560
+ fig.autofmt_xdate(ha="center")
1561
+
1562
+ # 调整布局防止重叠
1563
+ plt.tight_layout()
1564
+ plt.show()
1565
+
1566
+ return
1567
+
1568
+
1569
+ #==============================================================================
1570
+ def plot_line2_UD(df01,ticker1,colname1,label1, \
1571
+ df02,ticker2,colname2,label2, \
1572
+ titletxt,footnote,power=0, \
1573
+ datatag1=False,datatag2=False, \
1574
+ resample_freq='D', \
1575
+ xline=999,attention_point_area='', \
1576
+ loc1='upper left',loc2='lower left', \
1577
+ color1='red',color2='blue',facecolor='whitesmoke', \
1578
+ ticker_type='auto', \
1579
+ maxticks=15):
1580
+ """
1581
+ 功能:绘制两个证券或指标的上下折线图。如果power=0不绘制趋势图,否则绘制多项式趋势图
1582
+ 假定:数据表有索引,且已经按照索引排序
1583
+ 输入:
1584
+ 证券1:数据表df1,证券代码ticker1,列名1,列名标签1;
1585
+ 证券2:数据表df2,证券代码ticker2,列名2,列名标签2;
1586
+ 标题titletxt,脚注footnote;是否在图中标记数据datatag;趋势图的多项式次数power
1587
+ 输出:绘制上下并列折线图
1588
+ 返回值:无
1589
+ 注意:需要日期类型作为df索引
1590
+ """
1591
+ DEBUG=False
1592
+
1593
+ #plt.rcParams['axes.grid']=False
1594
+
1595
+ #插值平滑
1596
+ try:
1597
+ df01x=df01[[colname1]].astype('float')
1598
+ df1=df_smooth_manual(df01x,resample_freq=resample_freq)
1599
+ except:
1600
+ df1=df01
1601
+ try:
1602
+ df02x=df02[[colname2]].astype('float')
1603
+ df2=df_smooth_manual(df02x,resample_freq=resample_freq)
1604
+ except:
1605
+ df2=df02
1606
+
1607
+ #预处理ticker_type
1608
+ ticker_type_list=ticker_type_preprocess_mticker_mixed([ticker1,ticker2],ticker_type)
1609
+
1610
+ #创建画布:绘制折线图,上下双子图
1611
+ fig, (ax, ax2) = plt.subplots(2, 1)
1612
+
1613
+ #设置主标题
1614
+ #plt.suptitle(titletxt,fontweight='bold',fontsize=title_txt_size, y=1.01) # y参数调整垂直位置
1615
+ plt.suptitle(titletxt,fontweight='bold',fontsize=title_txt_size)
1616
+
1617
+ # 绘制左子图================================================================
1618
+ #设置画布背景颜色
1619
+ try:
1620
+ ax.set_facecolor(facecolor)
1621
+ except:
1622
+ print(" #Warning(plot_line2_twinx): color",facecolor,"is unsupported")
1623
+ facecolor="whitesmoke"
1624
+ ax.set_facecolor(facecolor)
1625
+
1626
+ # 设置折线标签
1627
+ if ticker1 == '':
1628
+ label1txt=label1
1629
+ else:
1630
+ if label1 == '':
1631
+ label1txt=ticker_name(ticker1,ticker_type_list[0])
1632
+ else:
1633
+ label1txt=ticker_name(ticker1,ticker_type_list[0])+'('+label1+')'
1634
+
1635
+ # 设置子图标题
1636
+ """
1637
+ if ticker1 != ticker2:
1638
+ ax.set_title(label1txt,fontsize=xlabel_txt_size)
1639
+ else:
1640
+ ax.set_title(ectranslate(colname1),fontsize=xlabel_txt_size)
1641
+ """
1642
+ # 绘图
1643
+ lwadjust=linewidth_adjust(df1)
1644
+ """
1645
+ ax.plot(df1.index,df1[colname1],'-',label=label1txt, \
1646
+ linestyle='-',color=color1,linewidth=lwadjust)
1647
+ """
1648
+ ax.plot(df1.index,df1[colname1],'-', \
1649
+ linestyle='-',color=color1,linewidth=lwadjust)
1650
+
1651
+ #证券1:绘制数据标签
1652
+ if datatag1:
1653
+ for x, y in zip(df1.index, df1[colname1]):
1654
+ ax.text(x,y+0.1,'%.2f' % y,ha='center',va='bottom',color='black')
1655
+
1656
+ #绘制关注点
1657
+ import pandas as pd
1658
+ from datetime import datetime; date_format="%Y-%m-%d"
1659
+ if xline != 999:
1660
+ attention_point=xline
1661
+
1662
+ #用于关注点的颜色列表
1663
+ atp_color_list=["crimson","dodgerblue","magenta","lightseagreen","chocolate"]
1664
+
1665
+ if isinstance(attention_point,str) or isinstance(attention_point,int) or isinstance(attention_point,float):
1666
+ atp_list=[attention_point]
1667
+ elif isinstance(attention_point,list):
1668
+ atp_list=attention_point
1669
+ else:
1670
+ atp_list=[]
1671
+ #去重,不打乱原来的顺序
1672
+ atp_list=list(dict.fromkeys(atp_list))
1673
+
1674
+ if DEBUG:
1675
+ print("In plot_line2_twinx")
1676
+ print("atp_list=",atp_list)
1677
+
1678
+ if not atp_list==[] and not atp_list==['']:
1679
+
1680
+ for at in atp_list:
1681
+ pos=atp_list.index(at)
1682
+ color=atp_color_list[pos]
1683
+
1684
+ #判断是否日期字符串
1685
+ try:
1686
+ at=datetime.strptime(at, date_format)
1687
+ atpd=pd.to_datetime(at)
1688
+ except:
1689
+ atpd=at
1690
+ ax.axvline(x=atpd,ls=":",c=color,linewidth=1.5,label=text_lang("关注点","Attention point ")+str(at))
1691
+
1692
+ if not attention_point_area=='':
1693
+ if isinstance(attention_point_area,list) and len(attention_point_area)>=2:
1694
+ apa_list=[]
1695
+ for ap in attention_point_area:
1696
+ try:
1697
+ ap=datetime.strptime(ap, date_format)
1698
+ appd=pd.to_datetime(ap)
1699
+ except:
1700
+ appd=ap
1701
+ apa_list=apa_list+[appd]
1702
+
1703
+ yaxis_data=plt.ylim()
1704
+ ax.fill_betweenx(yaxis_data,apa_list[0],apa_list[1],color='powderblue',alpha=0.5)
1705
+
1706
+ #绘证券1:制趋势线
1707
+ if power > 0:
1708
+ lang=check_language()
1709
+ trend_txt='趋势线'
1710
+ if lang == 'English':
1711
+ trend_txt='Trend line'
1712
+
1713
+ #生成行号,借此将横轴的日期数量化,以便拟合
1714
+ df1['id']=range(len(df1))
1715
+
1716
+ #设定多项式拟合,power为多项式次数
1717
+ import numpy as np
1718
+ parameter = np.polyfit(df1.id, df1[colname1], power)
1719
+ f = np.poly1d(parameter)
1720
+
1721
+ if ticker1 == '':
1722
+ label1txt=''
1723
+ else:
1724
+ label1txt=ticker_name(ticker1,ticker_type_list[0])+"("+trend_txt+")"
1725
+ ax.plot(df1.index, f(df1.id),"r--", label=label1txt,linewidth=1)
1726
+
1727
+ # 纵轴标签
1728
+ if ticker1 != ticker2:
1729
+ ax.set_ylabel(label1txt,fontsize=ylabel_txt_size)
1730
+ else:
1731
+ ax.set_ylabel(ectranslate(colname1),fontsize=ylabel_txt_size)
1732
+ #ax.legend(loc=loc1,fontsize=legend_txt_size)
1733
+
1734
+ # 横轴标签
1735
+ #ax.set_xlabel(text_lang("日期","Date"),fontsize=xlabel_txt_size,ha='center')
1736
+
1737
+ #绘图右图===================================================================
1738
+ #设置画布背景颜色
1739
+ ax2.set_facecolor(facecolor)
1740
+
1741
+ # 折线标签
1742
+ if ticker2 == '':
1743
+ label2txt=label2
1744
+ else:
1745
+ if label2 == '':
1746
+ label2txt=ticker_name(ticker2,ticker_type_list[1])
1747
+ else:
1748
+ label2txt=ticker_name(ticker2,ticker_type_list[1])+'('+label2+')'
1749
+
1750
+ # 设置子图标题
1751
+ """
1752
+ if ticker1 != ticker2:
1753
+ ax2.set_title(label2txt,fontsize=xlabel_txt_size)
1754
+ else:
1755
+ ax2.set_title(ectranslate(colname2),fontsize=xlabel_txt_size)
1756
+ """
1757
+ # 绘图
1758
+ lwadjust=linewidth_adjust(df2)
1759
+ """
1760
+ ax2.plot(df2.index,df2[colname2],'-',label=label2txt, \
1761
+ linestyle='-.',color=color2,linewidth=lwadjust)
1762
+ """
1763
+ ax2.plot(df2.index,df2[colname2],'-', \
1764
+ linestyle='-.',color=color2,linewidth=lwadjust)
1765
+
1766
+ #证券2:绘制数据标签
1767
+ if datatag2:
1768
+ for x, y in zip(df2.index, df2[colname2]):
1769
+ ax2.text(x,y+0.1,'%.2f' % y,ha='center',va='bottom',color='black')
1770
+
1771
+ #绘证券2:制趋势线
1772
+ if power > 0:
1773
+ lang=check_language()
1774
+ trend_txt='趋势线'
1775
+ if lang == 'English':
1776
+ trend_txt='Trend line'
1777
+
1778
+ #生成行号,借此将横轴的日期数量化,以便拟合
1779
+ df2['id']=range(len(df2))
1780
+
1781
+ #设定多项式拟合,power为多项式次数
1782
+ import numpy as np
1783
+ parameter = np.polyfit(df2.id, df2[colname2], power)
1784
+ f = np.poly1d(parameter)
1785
+
1786
+ if ticker2 == '':
1787
+ label2txt=''
1788
+ else:
1789
+ label2txt=ticker_name(ticker2,ticker_type_list[1])+"("+trend_txt+")"
1790
+ ax2.plot(df2.index, f(df2.id),"c--", label=label2txt,linewidth=1)
1791
+
1792
+ # 纵轴标签
1793
+ if ticker1 != ticker2:
1794
+ ax2.set_ylabel(label2txt,fontsize=ylabel_txt_size)
1795
+ else:
1796
+ ax2.set_ylabel(ectranslate(colname2),fontsize=ylabel_txt_size)
1797
+ #ax2.legend(loc=loc2,fontsize=legend_txt_size)
1798
+
1799
+ # 横轴标签
1800
+ #ax2.set_xlabel(text_lang("日期","Date"),fontsize=xlabel_txt_size,ha='center')
1801
+
1802
+ #自动优化x轴标签
1803
+ #ax2.autofmt_xdate(ha="center") # 优化标注(自动倾斜)
1804
+
1805
+ # 共同脚注==================================================================
1806
+ fig.text(0.5,-0.01,footnote,ha='center',fontsize=xlabel_txt_size,color='gray')
1807
+ #plt.xlabel(footnote,ha='center',fontsize=xlabel_txt_size,color='gray')
1808
+
1809
+ # 自动倾斜横轴日期
1810
+ fig.autofmt_xdate(ha="center")
1811
+
1812
+ # 调整布局防止重叠
1813
+ plt.tight_layout()
1814
+ plt.show()
1815
+
1816
+ return
1817
+
1287
1818
  #==============================================================================
1288
1819
  def plot_line2_twinx2(df01,ticker1,colname1,label1, \
1289
1820
  df02,ticker2,colname2,label2, \
1290
1821
  titletxt,footnote,power=0,datatag1=False,datatag2=False, \
1291
1822
  xline=999,attention_point_area='', \
1292
- resample_freq='H',loc1='upper left',loc2='lower left', \
1823
+ resample_freq='D',loc1='upper left',loc2='lower left', \
1293
1824
  date_range=False,date_freq=False,date_fmt='%Y-%m-%d', \
1294
1825
  color1='red',color2='blue',facecolor='whitesmoke', \
1295
1826
  ticker_type='auto', \
@@ -1532,7 +2063,7 @@ if __name__ =="__main__":
1532
2063
  axhline_value=0; axhline_label=''
1533
2064
  title_txt='Title'
1534
2065
  data_label=False
1535
- resample_freq='H'; smooth=True
2066
+ resample_freq='D'; smooth=True
1536
2067
  linewidth=1.5
1537
2068
  loc='best'
1538
2069
  annotate=True; annotate_value=True
@@ -1545,12 +2076,12 @@ if __name__ =="__main__":
1545
2076
 
1546
2077
 
1547
2078
  def draw_lines(df0,y_label,x_label,axhline_value,axhline_label,title_txt, \
1548
- data_label=True,resample_freq='H',smooth=True,linewidth=1.5, \
2079
+ data_label=False,resample_freq='D',smooth=False,linewidth=1.5, \
1549
2080
  band_area='',loc='best', \
1550
2081
  annotate=False,annotate_value=False,plus_sign=False, \
1551
2082
  attention_value='',attention_value_area='', \
1552
2083
  attention_point='',attention_point_area='', \
1553
- mark_top=False,mark_bottom=False,mark_end=False, \
2084
+ mark_start=False,mark_top=False,mark_bottom=False,mark_end=False, \
1554
2085
  ticker_type='auto',facecolor='whitesmoke', \
1555
2086
  maxticks_enable=True,maxticks=15, \
1556
2087
  translate=False):
@@ -1738,6 +2269,19 @@ def draw_lines(df0,y_label,x_label,axhline_value,axhline_label,title_txt, \
1738
2269
  plt.text(x,y1,s % y,ha='right',va='bottom',color=last_line_color)
1739
2270
  plt.scatter(x,y, color='seagreen',marker='8',s=70)
1740
2271
 
2272
+ #标记曲线开始数值
2273
+ if mark_start and (c not in ["平均值","中位数"]):
2274
+ df_end=dfg.head(1)
2275
+ y_end = df_end[c].min() # 开始的y坐标
2276
+ x_end = df_end[c].idxmin() # 开始值的x坐标
2277
+
2278
+ #y1=str(int(y_end)) if y_end >= 100 else str(round(y_end,2))
2279
+ 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))
2280
+ plt.annotate(text=' '+y1,
2281
+ xy=(x_end, y_end),
2282
+ xytext=(x_end, y_end*0.998),fontsize=annotate_size,
2283
+ color=last_line_color,ha='right',va='center')
2284
+
1741
2285
  #标记曲线末端数值
1742
2286
  if mark_end and (c not in ["平均值","中位数"]):
1743
2287
  df_end=dfg.tail(1)
@@ -1748,8 +2292,8 @@ def draw_lines(df0,y_label,x_label,axhline_value,axhline_label,title_txt, \
1748
2292
  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))
1749
2293
  plt.annotate(text=' '+y1,
1750
2294
  xy=(x_end, y_end),
1751
- xytext=(x_end, y_end),fontsize=annotate_size,
1752
- color=last_line_color)
2295
+ xytext=(x_end, y_end*0.998),fontsize=annotate_size,
2296
+ color=last_line_color,ha='left',va='center')
1753
2297
 
1754
2298
  #用于关注值的颜色列表
1755
2299
  atv_color_list=["lightgray","paleturquoise","wheat","khaki","lightsage","hotpink","mediumslateblue"]
@@ -1950,7 +2494,7 @@ def draw_lines2(df0,y_label,x_label,axhline_value,axhline_label,title_txt, \
1950
2494
  #指定两个横轴之间的区域
1951
2495
  attention_point_area='', \
1952
2496
  annotate=False,annotate_value=False, \
1953
- mark_top=False,mark_bottom=False,mark_end=False, \
2497
+ mark_start=False,mark_top=False,mark_bottom=False,mark_end=False, \
1954
2498
  facecolor='whitesmoke',maxticks=20,translate=False):
1955
2499
  """
1956
2500
  函数功能:根据df的内容绘制折线图
@@ -1973,6 +2517,7 @@ def draw_lines2(df0,y_label,x_label,axhline_value,axhline_label,title_txt, \
1973
2517
  band_area='':默认为空,否则为列表,第1个值为带状区域上边沿字段,第2个值为带状区域下边沿字段
1974
2518
  """
1975
2519
  import pandas as pd
2520
+
1976
2521
  DEBUG=False
1977
2522
  if DEBUG:
1978
2523
  print(f"band_area={band_area}")
@@ -2115,6 +2660,19 @@ def draw_lines2(df0,y_label,x_label,axhline_value,axhline_label,title_txt, \
2115
2660
  xy=(x_end, y_end),
2116
2661
  xytext=(x_end, y_end),fontsize=annotate_size,
2117
2662
  color=last_line_color)
2663
+
2664
+ #标记曲线开始数值
2665
+ if mark_start:
2666
+ df_start=df.head(1)
2667
+ y_start = df_start[c].min() # 开始的y坐标
2668
+ x_start = df_start[c].idxmin() # 开始值的x坐标
2669
+
2670
+ #y1=str(int(y_end)) if y_end >= 100 else str(round(y_end,2))
2671
+ 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))
2672
+ plt.annotate(text=y1,
2673
+ xy=(x_start, y_start),
2674
+ xytext=(x_start, y_start*0.998),fontsize=annotate_size,ha='right',va='center')
2675
+ # 特别注意:这里的left/right与实际图示的方向正好相反!!!
2118
2676
 
2119
2677
  #处理布林带的mark_end,仅标记上中下线
2120
2678
  if mark_end & (c in collist3):
@@ -2395,7 +2953,7 @@ if __name__=='__main__':
2395
2953
  #==============================================================================
2396
2954
  def plot_2lines(df01,colname1,label1, \
2397
2955
  df02,colname2,label2, \
2398
- ylabeltxt,titletxt,footnote,hline=0,vline=0,resample_freq='H', \
2956
+ ylabeltxt,titletxt,footnote,hline=0,vline=0,resample_freq='D', \
2399
2957
  date_range=False,date_freq=False,date_fmt='%Y-%m-%d', \
2400
2958
  facecolor='whitesmoke', \
2401
2959
  maxticks=15):
@@ -2584,7 +3142,7 @@ def df_smooth(df):
2584
3142
 
2585
3143
 
2586
3144
  #==============================================================================
2587
- def df_smooth_manual(df,method='linear',resample_freq='H',order=3):
3145
+ def df_smooth_manual(df,method='linear',resample_freq='D',order=3):
2588
3146
  """
2589
3147
  功能:对df中的第一个数值列样本进行插值,以便绘制的折线图相对平滑。
2590
3148
  要求:df的索引为pandas的datetime日期型