Coverage for src/scrilla/gui/widgets/functions.py: 0%

343 statements  

« prev     ^ index     » next       coverage.py v6.4.2, created at 2022-07-18 18:14 +0000

1# This file is part of scrilla: https://github.com/chinchalinchin/scrilla. 

2 

3# scrilla is free software: you can redistribute it and/or modify 

4# it under the terms of the GNU General Public License version 3 

5# as published by the Free Software Foundation. 

6 

7# scrilla is distributed in the hope that it will be useful, 

8# but WITHOUT ANY WARRANTY; without even the implied warranty of 

9# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

10# GNU General Public License for more details. 

11 

12# You should have received a copy of the GNU General Public License 

13# along with scrilla. If not, see <https://www.gnu.org/licenses/> 

14# or <https://github.com/chinchalinchin/scrilla/blob/develop/main/LICENSE>. 

15 

16from typing import Union 

17from PySide6 import QtGui, QtCore, QtWidgets 

18 

19 

20from scrilla import settings, services 

21from scrilla.static import keys 

22from scrilla.static import formats as app_formats 

23# TODO: conditional import based on ANALYSIS_MODE 

24from scrilla.analysis import estimators, markets, optimizer, plotter 

25from scrilla.analysis.models.geometric import statistics 

26from scrilla.analysis.objects.portfolio import Portfolio 

27from scrilla.analysis.objects.cashflow import Cashflow 

28 

29from scrilla.util import dater, outputter, helper 

30 

31from scrilla.gui import formats, utilities 

32from scrilla.gui.widgets import factories, components 

33 

34logger = outputter.Logger('gui.functions', settings.LOG_LEVEL) 

35 

36 

37class DistributionWidget(components.SkeletonWidget): 

38 def __init__(self, layer: str, parent: Union[QtWidgets.QWidget, None] = None): 

39 super().__init__(function='plot_return_dist', parent=parent) 

40 self.setObjectName(layer) 

41 self._init_widgets() 

42 self._arrange_widgets() 

43 self._stage_widgets() 

44 

45 def _init_widgets(self): 

46 self.arg_widget = components.ArgumentWidget(calculate_function=self.calculate, 

47 clear_function=self.clear, 

48 controls=self.controls, 

49 layer=utilities.get_next_layer(self.objectName())) 

50 self.title = factories.atomic_widget_factory( 

51 component='heading', title='Distribution of Returns') 

52 self.tab_container = factories.layout_factory(layout='vertical-box') 

53 self.tab_widget = QtWidgets.QTabWidget() 

54 self.setLayout(QtWidgets.QHBoxLayout()) 

55 

56 def _arrange_widgets(self): 

57 self.tab_container.layout().addWidget(self.tab_widget) 

58 self.layout().addWidget(self.tab_container) 

59 self.layout().addWidget(self.arg_widget) 

60 

61 def _stage_widgets(self): 

62 self.arg_widget.prime() 

63 

64 def resizeEvent(self, event: QtGui.QResizeEvent) -> None: 

65 for i in range(self.tab_widget.count()): 

66 if self.tab_widget.widget(i).figure.isVisible(): 

67 self.tab_widget.widget(i).set_pixmap() 

68 return super().resizeEvent(event) 

69 

70 @QtCore.Slot() 

71 def calculate(self): 

72 symbols = self.arg_widget.get_symbol_input() 

73 start_date = self.arg_widget.get_control_input('start_date') 

74 end_date = self.arg_widget.get_control_input('end_date') 

75 

76 for symbol in symbols: 

77 qq_plot = components.GraphWidget(tmp_graph_key=f'{keys.keys["GUI"]["TEMP"]["QQ"]}_{symbol}', 

78 layer=utilities.get_next_layer(self.objectName())) 

79 dist_plot = components.GraphWidget(tmp_graph_key=f'{keys.keys["GUI"]["TEMP"]["DIST"]}_{symbol}', 

80 layer=utilities.get_next_layer(self.objectName())) 

81 returns = statistics.get_sample_of_returns(ticker=symbol, 

82 start_date=start_date, 

83 end_date=end_date, 

84 daily=True) 

85 qq_series = estimators.qq_series_for_sample(sample=returns) 

86 plotter.plot_qq_series(ticker=symbol, 

87 qq_series=qq_series, 

88 show=False, 

89 savefile=f'{settings.TEMP_DIR}/{keys.keys["GUI"]["TEMP"]["QQ"]}_{symbol}') 

90 plotter.plot_return_histogram(ticker=symbol, 

91 sample=returns, 

92 show=False, 

93 savefile=f'{settings.TEMP_DIR}/{keys.keys["GUI"]["TEMP"]["DIST"]}_{symbol}',) 

94 dist_plot.set_pixmap() 

95 qq_plot.set_pixmap() 

96 self.tab_widget.addTab(qq_plot, f'{symbol} QQ Plot') 

97 self.tab_widget.addTab(dist_plot, f'{symbol} Distribution') 

98 self.tab_widget.show() 

99 self.arg_widget.fire() 

100 

101 @QtCore.Slot() 

102 def clear(self): 

103 self.arg_widget.prime() 

104 total = self.tab_widget.count() 

105 for _ in range(total): 

106 self.tab_widget.removeTab(0) 

107 

108 

109class YieldCurveWidget(components.SkeletonWidget): 

110 def __init__(self, layer: str, parent: Union[QtWidgets.QWidget, None] = None): 

111 super().__init__(function='yield_curve', parent=parent) 

112 self.setObjectName(layer) 

113 self._init_widgets() 

114 self._arrange_widgets() 

115 self._stage_widgets() 

116 

117 def _init_widgets(self): 

118 self.graph_widget = components.GraphWidget(tmp_graph_key=keys.keys['GUI']['TEMP']['YIELD'], 

119 layer=utilities.get_next_layer(self.objectName())) 

120 self.arg_widget = components.ArgumentWidget(calculate_function=self.calculate, 

121 clear_function=self.clear, 

122 controls=self.controls, 

123 layer=utilities.get_next_layer( 

124 self.objectName()), 

125 mode=components.SYMBOLS_NONE) 

126 # TODO: initialize arg widget WITHOUT tickers 

127 

128 self.setLayout(QtWidgets.QHBoxLayout()) 

129 

130 def _arrange_widgets(self): 

131 self.layout().addWidget(self.graph_widget) 

132 self.layout().addWidget(self.arg_widget) 

133 

134 def _stage_widgets(self): 

135 self.arg_widget.prime() 

136 

137 def resizeEvent(self, event: QtGui.QResizeEvent) -> None: 

138 if self.graph_widget.figure.isVisible(): 

139 self.graph_widget.set_pixmap() 

140 return super().resizeEvent(event) 

141 

142 @QtCore.Slot() 

143 def calculate(self): 

144 if self.graph_widget.figure.isVisible(): 

145 self.graph_widget.figure.hide() 

146 

147 yield_curve = {} 

148 start_date = dater.this_date_or_last_trading_date( 

149 self.arg_widget.get_control_input('start_date')) 

150 start_string = dater.to_string(start_date) 

151 yield_curve[start_string] = [] 

152 for maturity in keys.keys['YIELD_CURVE']: 

153 rate = services.get_daily_interest_history(maturity=maturity, 

154 start_date=start_date, 

155 end_date=start_date) 

156 yield_curve[start_string].append(rate[start_string]) 

157 

158 plotter.plot_yield_curve(yield_curve=yield_curve, 

159 show=False, 

160 savefile=f'{settings.TEMP_DIR}/{keys.keys["GUI"]["TEMP"]["YIELD"]}') 

161 self.graph_widget.set_pixmap() 

162 self.arg_widget.fire() 

163 

164 @QtCore.Slot() 

165 def clear(self): 

166 self.graph_widget.clear() 

167 self.arg_widget.prime() 

168 

169 

170class DiscountDividendWidget(components.SkeletonWidget): 

171 def __init__(self, layer: str, parent: Union[QtWidgets.QWidget, None] = None): 

172 super().__init__(function='discount_dividend', parent=parent) 

173 self.setObjectName(layer) 

174 self._init_widgets() 

175 self._arrange_widgets() 

176 self._stage_widgets() 

177 

178 def _init_widgets(self): 

179 self.tab_container = factories.layout_factory(layout='vertical-box') 

180 self.tab_widget = QtWidgets.QTabWidget() 

181 self.arg_widget = components.ArgumentWidget(calculate_function=self.calculate, 

182 clear_function=self.clear, 

183 controls=self.controls, 

184 layer=utilities.get_next_layer(self.objectName())) 

185 # TODO: restrict arg symbol input to one symbol somehow 

186 self.setLayout(QtWidgets.QHBoxLayout()) 

187 

188 def _arrange_widgets(self): 

189 self.tab_container.layout().addWidget(self.tab_widget) 

190 self.layout().addWidget(self.tab_container) 

191 self.layout().addWidget(self.arg_widget) 

192 

193 def _stage_widgets(self): 

194 self.arg_widget.prime() 

195 

196 def resizeEvent(self, event: QtGui.QResizeEvent) -> None: 

197 for i in range(self.tab_widget.count()): 

198 if self.tab_widget.widget(i).figure.isVisible(): 

199 self.tab_widget.widget(i).set_pixmap() 

200 return super().resizeEvent(event) 

201 

202 @QtCore.Slot() 

203 def calculate(self): 

204 symbols = self.arg_widget.get_symbol_input() 

205 discount = self.arg_widget.get_control_input('discount') 

206 

207 for symbol in symbols: 

208 if discount is None: 

209 discount = markets.cost_of_equity(ticker=symbol, 

210 start_date=self.arg_widget.get_control_input( 

211 'start_date'), 

212 end_date=self.arg_widget.get_control_input('end_date')) 

213 dividends = services.get_dividend_history(ticker=symbol) 

214 cashflow = Cashflow(sample=dividends, discount_rate=discount) 

215 graph_widget = components.GraphWidget(tmp_graph_key=f'{keys.keys["GUI"]["TEMP"]["DIVIDEND"]}_{symbol}', 

216 layer=utilities.get_next_layer(self.objectName())) 

217 plotter.plot_cashflow(ticker=symbol, 

218 cashflow=cashflow, 

219 show=False, 

220 savefile=f'{settings.TEMP_DIR}/{keys.keys["GUI"]["TEMP"]["DIVIDEND"]}_{symbol}') 

221 

222 graph_widget.set_pixmap() 

223 self.tab_widget.addTab(graph_widget, f'{symbol} DDM PLOT') 

224 self.tab_widget.show() 

225 self.arg_widget.fire() 

226 

227 @QtCore.Slot() 

228 def clear(self): 

229 self.arg_widget.prime() 

230 total = self.tab_widget.count() 

231 for _ in range(total): 

232 self.tab_widget.removeTab(0) 

233 

234 

235class RiskProfileWidget(components.SkeletonWidget): 

236 def __init__(self, layer: str, parent: Union[QtWidgets.QWidget, None] = None): 

237 super().__init__(function='risk_profile', parent=parent) 

238 self.setObjectName(layer) 

239 self._init_widgets() 

240 self._arrange_widgets() 

241 self._stage_widgets() 

242 

243 def _init_widgets(self): 

244 self.composite_widget = components.CompositeWidget(keys.keys['GUI']['TEMP']['PROFILE'], 

245 widget_title="Risk Analysis", 

246 table_title="CAPM Risk Profile", 

247 graph_title="Risk-Return Plane", 

248 layer=utilities.get_next_layer(self.objectName())) 

249 self.arg_widget = components.ArgumentWidget(calculate_function=self.calculate, 

250 clear_function=self.clear, 

251 controls=self.controls, 

252 layer=utilities.get_next_layer(self.objectName())) 

253 self.setLayout(QtWidgets.QHBoxLayout()) 

254 

255 def _arrange_widgets(self): 

256 self.layout().addWidget(self.composite_widget) 

257 self.layout().addWidget(self.arg_widget) 

258 

259 def _stage_widgets(self): 

260 self.arg_widget.prime() 

261 

262 @QtCore.Slot() 

263 def calculate(self): 

264 if self.composite_widget.graph_widget.figure.isVisible(): 

265 self.composite_widget.graph_widget.figure.hide() 

266 

267 symbols = self.arg_widget.get_symbol_input() 

268 

269 self.composite_widget.table_widget.init_table(rows=symbols, 

270 columns=['Return', 'Volatility', 'Sharpe', 'Beta', 'Equity Cost']) 

271 

272 profiles = {} 

273 start_date = start_date = self.arg_widget.get_control_input( 

274 'start_date') 

275 end_date = self.arg_widget.get_control_input('end_date') 

276 for i, symbol in enumerate(symbols): 

277 profiles[symbol] = statistics.calculate_risk_return(ticker=symbol, 

278 start_date=start_date, 

279 end_date=end_date) 

280 profiles[symbol][keys.keys['APP']['PROFILE'] 

281 ['SHARPE']] = markets.sharpe_ratio(ticker=symbol, 

282 start_date=start_date, 

283 end_date=end_date) 

284 profiles[symbol][keys.keys['APP']['PROFILE'] 

285 ['BETA']] = markets.market_beta(ticker=symbol, 

286 start_date=start_date, 

287 end_date=end_date) 

288 profiles[symbol][keys.keys['APP']['PROFILE'] 

289 ['EQUITY']] = markets.cost_of_equity(ticker=symbol, 

290 start_date=start_date, 

291 end_date=end_date) 

292 

293 formatted_profile = formats.format_profile(profiles[symbol]) 

294 

295 for j, statistic in enumerate(formatted_profile.keys()): 

296 table_item = factories.atomic_widget_factory( 

297 component='table-item', title=formatted_profile[statistic]) 

298 self.composite_widget.table_widget.table.setItem( 

299 i, j, table_item) 

300 

301 plotter.plot_profiles(symbols=symbols, profiles=profiles, show=False, 

302 savefile=f'{settings.TEMP_DIR}/{keys.keys["GUI"]["TEMP"]["PROFILE"]}') 

303 

304 self.composite_widget.graph_widget.set_pixmap() 

305 self.composite_widget.table_widget.show_table() 

306 self.arg_widget.fire() 

307 

308 def resizeEvent(self, event: QtGui.QResizeEvent) -> None: 

309 if self.composite_widget.graph_widget.figure.isVisible(): 

310 self.composite_widget.graph_widget.set_pixmap() 

311 return super().resizeEvent(event) 

312 

313 @QtCore.Slot() 

314 def clear(self): 

315 self.composite_widget.graph_widget.clear() 

316 self.composite_widget.table_widget.table.clear() 

317 self.composite_widget.table_widget.table.hide() 

318 self.arg_widget.prime() 

319 

320 

321class CorrelationWidget(components.SkeletonWidget): 

322 def __init__(self, layer: str, parent: Union[QtWidgets.QWidget, None] = None): 

323 super().__init__(function='correlation', parent=parent) 

324 self.setObjectName(layer) 

325 self._init_widgets() 

326 self._arrange_widgets() 

327 self._stage_widgets() 

328 

329 def _init_widgets(self): 

330 self.table_widget = components.TableWidget(widget_title="Correlation Matrix", 

331 layer=utilities.get_next_layer(self.objectName())) 

332 self.arg_widget = components.ArgumentWidget(calculate_function=self.calculate, 

333 clear_function=self.clear, 

334 controls=self.controls, 

335 layer=utilities.get_next_layer(self.objectName())) 

336 self.setLayout(QtWidgets.QHBoxLayout()) 

337 

338 def _arrange_widgets(self): 

339 self.layout().addWidget(self.table_widget) 

340 self.layout().addWidget(self.arg_widget) 

341 

342 def _stage_widgets(self): 

343 self.arg_widget.prime() 

344 

345 @QtCore.Slot() 

346 def calculate(self): 

347 if self.table_widget.table.isVisible(): 

348 self.table_widget.table.clear() 

349 self.table_widget.table.hide() 

350 

351 symbols = self.arg_widget.get_symbol_input() 

352 

353 if len(symbols) > 1: 

354 self.table_widget.init_table(rows=symbols, columns=symbols) 

355 

356 matrix = statistics.correlation_matrix(tickers=symbols, 

357 start_date=self.arg_widget.get_control_input( 

358 'start_date'), 

359 end_date=self.arg_widget.get_control_input('end_date')) 

360 for i in range(0, len(symbols)): 

361 for j in range(i, len(symbols)): 

362 item_upper = factories.atomic_widget_factory( 

363 component='table-item', title=app_formats.format_float_percent(matrix[i][j])) 

364 item_lower = factories.atomic_widget_factory( 

365 component='table-item', title=app_formats.format_float_percent(matrix[j][i])) 

366 self.table_widget.table.setItem(j, i, item_upper) 

367 self.table_widget.table.setItem(i, j, item_lower) 

368 else: 

369 print('error handling goes here') 

370 

371 self.table_widget.show_table() 

372 self.arg_widget.fire() 

373 

374 @QtCore.Slot() 

375 def clear(self): 

376 self.arg_widget.prime() 

377 self.table_widget.table.clear() 

378 self.table_widget.table.hide() 

379 self.table_widget.download_button.hide() 

380 

381 

382class OptimizerWidget(components.SkeletonWidget): 

383 def __init__(self, layer: str, parent: Union[QtWidgets.QWidget, None] = None): 

384 super().__init__(function='optimize_portfolio', parent=parent) 

385 self.setObjectName(layer) 

386 self._init_widgets() 

387 self._arrange_widgets() 

388 self._stage_widgets() 

389 

390 def _init_widgets(self): 

391 self.title = factories.atomic_widget_factory( 

392 component='heading', title=None) 

393 self.table_widget = components.TableWidget(widget_title="Optimization Results", 

394 layer=utilities.get_next_layer(self.objectName())) 

395 self.arg_widget = components.ArgumentWidget(calculate_function=self.optimize, 

396 clear_function=self.clear, 

397 controls=self.controls, 

398 layer=utilities.get_next_layer(self.objectName())) 

399 self.setLayout(QtWidgets.QHBoxLayout()) 

400 

401 def _arrange_widgets(self): 

402 self.layout().addWidget(self.table_widget) 

403 self.layout().addWidget(self.arg_widget) 

404 

405 def _stage_widgets(self): 

406 self.arg_widget.prime() 

407 

408 @QtCore.Slot() 

409 def optimize(self): 

410 if self.table_widget.table.isVisible(): 

411 self.table_widget.table.clear() 

412 self.table_widget.table.hide() 

413 

414 symbols = self.arg_widget.get_symbol_input() 

415 

416 # TODO: better error checking 

417 if len(symbols) > 1: 

418 investment = self.arg_widget.get_control_input('investment') 

419 this_portfolio = Portfolio(tickers=symbols, 

420 start_date=self.arg_widget.get_control_input( 

421 'start_date'), 

422 end_date=self.arg_widget.get_control_input('end_date')) 

423 allocation = optimizer.optimize_portfolio_variance(portfolio=this_portfolio, 

424 target_return=self.arg_widget.get_control_input('target')) 

425 self.title.setText(formats.format_allocation_profile_title( 

426 allocation, this_portfolio)) 

427 

428 prices = services.get_daily_prices_latest(tickers=symbols) 

429 

430 if investment is None: 

431 self.table_widget.init_table( 

432 rows=symbols, columns=['Allocation']) 

433 else: 

434 self.table_widget.init_table(rows=symbols, columns=[ 

435 'Allocation', 'Shares']) 

436 shares = this_portfolio.calculate_approximate_shares( 

437 allocation, float(investment), prices) 

438 

439 for i in range(len(symbols)): 

440 item = factories.atomic_widget_factory( 

441 component='table-item', title=app_formats.format_float_percent(allocation[i])) 

442 self.table_widget.table.setItem(i, 0, item) 

443 

444 if investment is not None: 

445 share_item = factories.atomic_widget_factory( 

446 component='table-item', title=str(shares[i])) 

447 self.table_widget.table.setItem(i, 1, share_item) 

448 

449 # TODO: display amount vested per equity 

450 # TODO: display total portfolio return and volatility 

451 # TODO: display actual investment 

452 self.table_widget.show_table() 

453 self.arg_widget.fire() 

454 

455 else: 

456 print('error handling goes here') 

457 

458 @QtCore.Slot() 

459 def clear(self): 

460 self.table_widget.table.clear() 

461 self.table_widget.table.hide() 

462 self.arg_widget.prime() 

463 

464 

465class EfficientFrontierWidget(components.SkeletonWidget): 

466 def __init__(self, layer: str, parent: Union[QtWidgets.QWidget, None] = None): 

467 super().__init__(function='efficient_frontier', parent=parent) 

468 self.setObjectName(layer) 

469 self._init_widgets() 

470 self._arrange_widgets() 

471 self._stage_widgets() 

472 

473 def _init_widgets(self): 

474 self.graph_widget = components.GraphWidget(tmp_graph_key=keys.keys['GUI']['TEMP']['FRONTIER'], 

475 layer=utilities.get_next_layer(self.objectName())) 

476 self.arg_widget = components.ArgumentWidget(calculate_function=self.calculate, 

477 clear_function=self.clear, 

478 controls=self.controls, 

479 layer=utilities.get_next_layer(self.objectName())) 

480 self.setLayout(QtWidgets.QHBoxLayout()) 

481 # TODO: portfolio tabs 

482 

483 def _arrange_widgets(self): 

484 self.layout().addWidget(self.graph_widget) 

485 self.layout().addWidget(self.arg_widget) 

486 

487 def _stage_widgets(self): 

488 self.arg_widget.prime() 

489 

490 def resizeEvent(self, event: QtGui.QResizeEvent) -> None: 

491 if self.graph_widget.figure.isVisible(): 

492 self.graph_widget.set_pixmap() 

493 return super().resizeEvent(event) 

494 

495 @QtCore.Slot() 

496 def calculate(self): 

497 if self.graph_widget.figure.isVisible(): 

498 self.graph_widget.figure.hide() 

499 

500 this_portfolio = Portfolio(tickers=self.arg_widget.get_symbol_input(), 

501 start_date=self.arg_widget.get_control_input( 

502 'start_date'), 

503 end_date=self.arg_widget.get_control_input('end_date')) 

504 frontier = optimizer.calculate_efficient_frontier(portfolio=this_portfolio, 

505 steps=self.arg_widget.get_control_input('steps')) 

506 plotter.plot_frontier(portfolio=this_portfolio, 

507 frontier=frontier, 

508 show=False, 

509 savefile=f'{settings.TEMP_DIR}/{keys.keys["GUI"]["TEMP"]["FRONTIER"]}') 

510 

511 self.graph_widget.set_pixmap() 

512 self.arg_widget.fire() 

513 

514 @QtCore.Slot() 

515 def clear(self): 

516 self.graph_widget.figure.hide() 

517 self.arg_widget.prime() 

518 

519 

520class MovingAverageWidget(components.SkeletonWidget): 

521 def __init__(self, layer: str, parent: Union[QtWidgets.QWidget, None] = None): 

522 super().__init__(function='moving_averages', parent=parent) 

523 self.setObjectName(layer) 

524 self._init_widgets() 

525 self._arrange_widgets() 

526 self._stage_widgets() 

527 

528 def _init_widgets(self): 

529 self.graph_widget = components.GraphWidget(keys.keys['GUI']['TEMP']['AVERAGES'], 

530 layer=utilities.get_next_layer(self.objectName())) 

531 self.arg_widget = components.ArgumentWidget(calculate_function=self.calculate, 

532 clear_function=self.clear, 

533 controls=self.controls, 

534 layer=utilities.get_next_layer( 

535 self.objectName()), 

536 mode=components.SYMBOLS_SINGLE) 

537 self.setLayout(QtWidgets.QHBoxLayout()) 

538 

539 def _arrange_widgets(self): 

540 self.layout().addWidget(self.graph_widget) 

541 self.layout().addWidget(self.arg_widget) 

542 

543 def _stage_widgets(self): 

544 self.arg_widget.prime() 

545 

546 def resizeEvent(self, event: QtGui.QResizeEvent) -> None: 

547 if self.graph_widget.figure.isVisible(): 

548 self.graph_widget.set_pixmap() 

549 return super().resizeEvent(event) 

550 

551 @QtCore.Slot() 

552 def calculate(self): 

553 if self.graph_widget.figure.isVisible(): 

554 self.graph_widget.figure.hide() 

555 

556 moving_averages = statistics.calculate_moving_averages(ticker=self.arg_widget.get_symbol_input()[0], 

557 start_date=self.arg_widget.get_control_input( 

558 'start_date'), 

559 end_date=self.arg_widget.get_control_input('end_date')) 

560 

561 plotter.plot_moving_averages(ticker=self.arg_widget.get_symbol_input()[0], 

562 averages=moving_averages, 

563 show=False, 

564 savefile=f'{settings.TEMP_DIR}/{keys.keys["GUI"]["TEMP"]["AVERAGES"]}') 

565 self.graph_widget.set_pixmap() 

566 self.arg_widget.fire() 

567 

568 @QtCore.Slot() 

569 def clear(self): 

570 self.arg_widget.prime() 

571 self.graph_widget.clear()