PyQt5_pyqtgraph例子_绘制最小方差边界

目录

效果:

代码:

使用:

数据


效果:

1. 绿色线段为CML线,即最优投资组合,也叫切线组合

2. 红色星星是GMVP点,即最小方差组合

3. 玫瑰色是鼠标单击该点,获取当前点的风险与收益

代码:

import sys
import pandas as pd
from PyQt5 import QtGui,QtWidgets
from PyQt5.QtCore import Qt
from typing import Any,Dict
import pyqtgraph as pg
pg.setConfigOption('background', 'w')
pg.setConfigOption('foreground', 'k')

class PyQtGraphWidget(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        self.init_data()
        self.init_ui()

    def init_data(self):
        self.color_line = (30, 144, 255)
        self.color_scatter = (0,0,128)
        self.color_star = (220,20,60)
        self.color_hover = (0,191,255)
        self.color_circle = (255,0,255)
        self.color_cml = (0,128,128)
        pass

    def init_ui(self):
        self.title_label = QtWidgets.QLabel('最小方差边界')
        self.title_label.setAlignment(Qt.AlignCenter)
        self.pw = pg.PlotWidget()
        self.pw.setMouseEnabled(x=True, y=False)
        # self.pw.enableAutoRange(x=False,y=True)
        self.pw.setAutoVisible(x=False, y=True)
        self.pw.setLabel('left', 'R')
        self.pw.setLabel('bottom', 'Var')
        layout = QtWidgets.QVBoxLayout()
        layout.addWidget(self.title_label)
        layout.addWidget(self.pw)
        self.setLayout(layout)
        pass
    def set_data(self,data:Dict[str,Any]):
        # 绘制最小方差边界
        ef = data['ef']
        gmvp = data['gmvp']
        cml = data['cml']
        cml_start = cml[0]
        cml_end = cml[1]
        x_var = ef['Var'].values.tolist()
        y_r = ef['R'].values.tolist()

        # 计算横轴覆盖点的半径
        x_temp_min = ef['Var'].min()
        x_temp_max = ef['Var'].max()
        x_unique_len = len(ef['Var'].unique())
        x_radius = (x_temp_max-x_temp_min)/(x_unique_len*2)

        y_temp_min = ef['R'].min()
        y_temp_max = ef['R'].max()
        y_unique_len = len(ef['R'].unique())
        y_radius = (y_temp_max - y_temp_min)/(y_unique_len*2)

        self.cover_xy = []
        self.center_circle = []
        for x,y in zip(x_var,y_r):
            self.center_circle.append([x,y])
            self.cover_xy.append([[x-x_radius,x+x_radius],[y-y_radius,y+y_radius]])

        font = QtGui.QFont()
        font.setPixelSize(9)
        self.label = pg.TextItem()
        self.label.setFont(font)
        self.label.setPos(x_var[0],y_r[0])
        self.label.setZValue(-90)

        self.pw.addItem(self.label)

        self.pw.plot(x_var, y_r, connect='finite', pen=pg.mkPen({'color': self.color_line, 'width': 4}),symbol='o')

        gmvp_targetItem = pg.TargetItem(
            pos=gmvp,
            movable=False,
            size=30,
            symbol='star',
            pen=self.color_star,
            brush=self.color_star,
            label=f"GMVP:Var={gmvp[0]}\nR={gmvp[1]}",
            labelOpts={'color':self.color_star}
        )
        self.pw.addItem(gmvp_targetItem)

        # cml
        cml_x = [cml_start[0],cml_end[0]]
        cml_y = [cml_start[1],cml_end[1]]
        cml_lr = pg.PlotCurveItem(x=cml_x,y=cml_y,pen=pg.mkPen({'color':self.color_cml,'width':2}),symbol='o')
        self.pw.addItem(cml_lr)

        cml_targetItem = pg.TargetItem(
            pos=(cml_end[0],cml_end[1]),
            movable=False,
            size=30,
            # symbol='star',
            pen=self.color_cml,
            brush=self.color_cml,
            label=f"CML:Var={cml_end[0]}\nR={cml_end[1]}",
            labelOpts={'color': self.color_cml}
        )
        self.pw.addItem(cml_targetItem)

        self.current_point_targetItem = pg.TargetItem(
            pos=(cml_end[0], cml_end[1]),
            movable=False,
            size=20,
            symbol='o',
            pen=self.color_circle,
            brush=self.color_circle,
            label=f"Var:{cml_end[0]}\nR:{cml_end[1]}",
            labelOpts={'color': self.color_circle}
        )
        self.pw.addItem(self.current_point_targetItem)

        self.vb = self.pw.getViewBox()
        self.proxy = pg.SignalProxy(self.pw.scene().sigMouseMoved, rateLimit=60, slot=self.mouseMoved)
        self.proxy_clicked = pg.SignalProxy(self.pw.scene().sigMouseClicked,rateLimit=60, slot=self.mouseClicked)
        self.pw.enableAutoRange()
        pass
    def mouseMoved(self,evt):
        pos = evt[0]
        if self.pw.sceneBoundingRect().contains(pos):
            mousePoint = self.vb.mapSceneToView(pos)
            cur_x = mousePoint.x()
            cur_y = mousePoint.y()
            # print(mousePoint.x(),mousePoint.y())
            for xy_i,item in enumerate(self.cover_xy):
                cur_x_radius = item[0]
                cur_y_radius = item[1]
                if cur_x >= cur_x_radius[0] and cur_x <= cur_x_radius[1]:
                    if cur_y >= cur_y_radius[0] and cur_y <= cur_y_radius[1]:
                        cur_center_circle = self.center_circle[xy_i]
                        self.label.setPos(cur_center_circle[0],cur_center_circle[1])
                        self.label.setText(text=f"Var:{cur_center_circle[0]}\nR:{cur_center_circle[1]}",color=self.color_line)
                        pass
        pass
    def mouseClicked(self,evt):
        pos = evt[0].pos()
        cur_x = pos[0]
        cur_y = pos[1]
        for xy_i, item in enumerate(self.cover_xy):
            cur_x_radius = item[0]
            cur_y_radius = item[1]
            if cur_x >= cur_x_radius[0] and cur_x <= cur_x_radius[1]:
                if cur_y >= cur_y_radius[0] and cur_y <= cur_y_radius[1]:
                    cur_center_circle = self.center_circle[xy_i]
                    self.current_point_targetItem.setPos(cur_center_circle[0], cur_center_circle[1])
                    self.current_point_targetItem.setLabel(text=f"Var:{cur_center_circle[0]}\nR:{cur_center_circle[1]}",labelOpts={'color': self.color_circle})


        if self.pw.sceneBoundingRect().contains(pos):
            mousePoint = self.vb.mapSceneToView(pos)
            cur_x = mousePoint.x()
            cur_y = mousePoint.y()

使用:

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)

    temp_csv = r'E:/temp000/ef.csv'
    ef = pd.read_csv(temp_csv,encoding='utf-8')
    pre_data = {
        'ef':ef,
        'gmvp': (0.2848851343955465, 0.0839279326985379),
        'cml':[(0,0.0135),(0.39621410853251293, 0.17920659296170613)]
    }

    temp_w = PyQtGraphWidget()
    temp_w.show()
    temp_w.set_data(pre_data)
    sys.exit(app.exec_())
    pass

数据

ef.csv中的数据为

RVar
-0.0160040070.435932686
-0.0091909570.408593056
-0.0023779070.385133031
0.0044351430.364447366
0.0112481930.346697221
0.0180612440.331717701
0.0248742940.319874604
0.0316873440.3115225
0.0385003940.305240296
0.0453134440.299729682
0.0521264940.295033655
0.0589395440.29119161
0.0657525940.288237708
0.0725656440.286199423
0.0793786940.285095621
0.0861917440.284938658
0.0930047940.285728847
0.0998178440.287459369
0.1066308940.290112941
0.1134439440.293664542
0.1202569940.298463038
0.1270700440.304887331
0.1338830940.312838281
0.1406961440.322202888
0.1475091940.332861855
0.1543222440.344695126
0.1611352940.357586136
0.1679483440.371424054
0.1747613950.386108372
0.1815744440.401902036
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值