From 365118bc22ee0ce3391c6261a051258c35c89eeb Mon Sep 17 00:00:00 2001 From: Andrew Date: Tue, 17 Dec 2024 16:14:07 +0300 Subject: [PATCH] =?UTF-8?q?chore:=20=D1=87=D0=B0=D1=81=D1=82=D1=8C=20?= =?UTF-8?q?=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D0=B9=20plotter=20=D0=BF?= =?UTF-8?q?=D0=B5=D1=80=D0=B5=D0=BD=D0=B5=D1=81=D0=B5=D0=BD=D0=B0=20=D0=B2?= =?UTF-8?q?=20base?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ConstantCalculator.cpython-310.pyc | Bin 1351 -> 1351 bytes .../__pycache__/OptAlgorithm.cpython-310.pyc | Bin 15521 -> 15521 bytes .../OptTimeCalculator.cpython-310.pyc | Bin 8927 -> 8927 bytes .../__pycache__/controller.cpython-310.pyc | Bin 1086 -> 1086 bytes .../__pycache__/converter.cpython-310.pyc | Bin 1222 -> 1222 bytes .../__pycache__/mediator.cpython-310.pyc | Bin 1346 -> 1346 bytes .../__pycache__/monitor.cpython-310.pyc | Bin 2591 -> 2591 bytes .../passportFormer.cpython-310.pyc | Bin 4299 -> 4299 bytes src/gui/__pycache__/mainGui.cpython-310.pyc | Bin 3434 -> 3434 bytes src/gui/__pycache__/plotter.cpython-310.pyc | Bin 12262 -> 9205 bytes .../settings_window.cpython-310.pyc | Bin 5558 -> 5558 bytes src/gui/plotter.py | 86 ------------------ .../base/__pycache__/base.cpython-310.pyc | Bin 16594 -> 19913 bytes src/utils/base/base.py | 86 +++++++++++++++++- 14 files changed, 83 insertions(+), 89 deletions(-) diff --git a/src/OptAlgorithm/__pycache__/ConstantCalculator.cpython-310.pyc b/src/OptAlgorithm/__pycache__/ConstantCalculator.cpython-310.pyc index 1dac74885b2a755fefbc77235b7792d2f3721f78..de8f5fb2814630f83da3867159e2ab5b4ab0e7b2 100644 GIT binary patch delta 20 acmX@kb)1VkpO=@50SLb3C2r)lVFds-qXh#1 delta 20 acmX@kb)1VkpO=@50SGGZ$8Y4eVFds+)CBba diff --git a/src/OptAlgorithm/__pycache__/OptAlgorithm.cpython-310.pyc b/src/OptAlgorithm/__pycache__/OptAlgorithm.cpython-310.pyc index 33a7e937c64c67aad1bbef16aff27bd0b40a1d3e..cc95fdd05d532b2abe65ab42cc4e9e6316e84200 100644 GIT binary patch delta 20 acmZ2jxv-KupO=@50SLb3C2r)NW&;30h6W}8 delta 20 acmZ2jxv-KupO=@50SGGZ$8Y4GW&;2~w+0vh diff --git a/src/OptAlgorithm/__pycache__/OptTimeCalculator.cpython-310.pyc b/src/OptAlgorithm/__pycache__/OptTimeCalculator.cpython-310.pyc index 01aa6e0434d6c5b4c6961e5f4561aa7030dfa081..980cdccda2126e3083addda6c654d5c02665e10f 100644 GIT binary patch delta 20 acmccbdf$~hpO=@50SLb3C2r)tq67d#%m!Wn delta 20 acmccbdf$~hpO=@50SGGZ$8Y4mq67d!{RU6~ diff --git a/src/controller/__pycache__/controller.cpython-310.pyc b/src/controller/__pycache__/controller.cpython-310.pyc index c93d105a1a245ce979100541e7d9585eff997a86..f7576ab22bae9fe7ccc44faafb0916df3415da4b 100644 GIT binary patch delta 20 acmdnTv5$j0pO=@50SLb3C2r(4W&r>+@&w}m delta 20 acmdnTv5$j0pO=@50SGeX5;k%hvj6}uG6V$x diff --git a/src/controller/__pycache__/converter.cpython-310.pyc b/src/controller/__pycache__/converter.cpython-310.pyc index 6ae3490fea947a6a6bd776f8ca173087c4e2b3b4..58eb89564bd9795b03d1cb7e21857050cba0467c 100644 GIT binary patch delta 20 acmX@cd5n`gpO=@50SLb3C2r*2%>n>7Rt0?k delta 20 acmX@cd5n`gpO=@50SLmI12=N-W&r>*D+J>J diff --git a/src/controller/__pycache__/mediator.cpython-310.pyc b/src/controller/__pycache__/mediator.cpython-310.pyc index e85d657765714d257f471f5deacce84cea3078f4..6717f3d71eea6aa759aa4488c6b22ec16ef92a4a 100644 GIT binary patch delta 26 gcmX@ab%={QpO=@50SLb3C2r(C$ijGQ@>!Nr0AW-JF#rGn delta 26 gcmX@ab%={QpO=@50SKNh58KFnkcBa7@>!Nr0AMNy&Hw-a diff --git a/src/controller/__pycache__/monitor.cpython-310.pyc b/src/controller/__pycache__/monitor.cpython-310.pyc index b2d9573144d137b14abeb693031be8b451b94352..c007b611bdc3c8f1018242ef6f5146515999f920 100644 GIT binary patch delta 20 acmbO)GGBx{pO=@50SLb3C2r&v;Q|0L&;+Ca delta 20 acmbO)GGBx{pO=@50SHzoBy8js;Q|0H)dU9s diff --git a/src/controller/__pycache__/passportFormer.cpython-310.pyc b/src/controller/__pycache__/passportFormer.cpython-310.pyc index 0447683b6666d3c7d318100469c6622a3696f5df..4bfe60a8b5eaef714396113509bbf7c704315917 100644 GIT binary patch delta 20 acmX@Dcv_J=pO=@50SLb3C2r(CAOHY6iUr63 delta 20 acmX@Dcv_J=pO=@50SFlN6E<=m5C8x(SOk** diff --git a/src/gui/__pycache__/mainGui.cpython-310.pyc b/src/gui/__pycache__/mainGui.cpython-310.pyc index 8a61220f019628105144e1390b75d7f30cab7975..01f607126225decb25e3e04eea70dc6ec76a7056 100644 GIT binary patch delta 20 acmaDQ^-796pO=@50SLb3C2r)7=LG;hV+E7| delta 20 acmaDQ^-796pO=@50SJC5By8l4=LG;fm<2}w diff --git a/src/gui/__pycache__/plotter.cpython-310.pyc b/src/gui/__pycache__/plotter.cpython-310.pyc index ec565abe16df2fade8de178e60052c8abf049ed4..d4c52ba4b35467550232f13a0cac2bbefa225721 100644 GIT binary patch delta 2316 zcmZ`*&2Jk;6!+L`$Dg$w$4Q*;G)a?flBO*x5-4etegx7cO-P&4u4pzJ&)D8%y>@5U zX~HEcL|l-7GD4h?5C@QRDmbRA}qQV%lQgX8lnw5iWa9~rtIq@EU{;ENZLec3~Z7tMdM%qKjcB>Pq7WaK$Y2Qz$2R;+2T3ach&Ft zt3@x4kuJL=$P;eUMlt6JA5PvSF-ROjRCH zwCMX6JPN>64e<_md8t{`W(HqmMYCdK7BQFX8i5GwXL-#jsSUgfoqG`K*>KbgfYqRr zcqchR4vVjory9JVYq}N_zb9`i_Xr;m)l_?^4ISFW-P9225MQO1$%x3MpC>28RlxDx zx6|*D7L{D)NwB*IWgj~(vw{DVn8>t}3*uU4abg%VMjYm9*9@!1yat0(*_3E~f#aBE z5@8CVzCgz{ip=3X;`>ZfOhq{+;pg9N>VV9hP4mQ<27wo0cCE~~;WCbS_=^ZL0BZb+ z=(6LJsKV%4!lcZwbl64HE;{@o$UI`!J9P=IW)W1mIS;crGPnCj_98ij33)fdL6-1; zX1R(+JqV3rt7Vkv;**wh?Ouce9||046X&>sI>Q`3A%1T8#cD-|76jzcRn;%wo>DLz zmlF_O1|Bu!D^{&+J6_1GSf=B8N)?FqKP$R{!8C*k1leCn!DU(7Qm&CWyQSP4B(#M3 zKJmEiK~}P61?L9BDned-+rC0x6Qdo|Uv_UO$MYcc!rZWnOrN{pMc4I`!Kuw0hmV3v z3twTbE1S#Eor;h9&ctMCSO;GczxH*vW8e81G>_b_@b#+6@=Wv3o-}_7h@<^I$$n6& z#0%awsat}@-RNIBDc31uNIsmECUy2mK?($3bR0XAuav8&zw?QQ{YzwCJUcLz@gilz zv~}4qbh zY@1n*7c}7*I{Y-M8uhZtd4=mv$t<`!ZoQ}EE7dJ8Oc|@nQP8w0+tgxD+61gho=d9D zVVWR<t-~b-o5u zEv@H)fG*Q*W5X;OZiVv_%Dcp0v92jE1;o6*h`W0ZN-Hvow1X1!t~|)I##W`~s>AhW ztz-NUY!Y0Wd<7=_h9HAIDdY&Z5XuNs;>6&QHhI{Qj2f<}PLVpz#I3=_Zh25`REMT@ z+(0c_t(dl}n{*RzgC7Q0RTtHf{e^4M#rYY%exb=r0?y4OnD8#KGSoue7n?($@7_83 zn2f#&Qc#{l{}}Fv?il5&#rOuA@9#NxU>Xx2jm)T$46?q4dVNmaOgc!a1y^gPMTuw{ z?ad*TRl+ahtDEEh0vC9W=$iR5b4wKp7j+HSoJRF?2*@_RfFKF8PXW2{9KRU2=Z!w@$00U>zlD$#z0ph> z<6tGurvPD}-!E<+`!L&_?OKy5)U+0=8a6c?epgJ6sp%~+^CH!)TW*mX)e`RzuZ~&& E08K+fJpcdz delta 5337 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 bD@&5i6WG=bm5v;=282;MAd=3RCAt3sl^^BS diff --git a/src/gui/__pycache__/settings_window.cpython-310.pyc b/src/gui/__pycache__/settings_window.cpython-310.pyc index d6c61f44824aecdfa98dc160c871c55dda5b8548..0edf48f943576e08899460a951aff885019e8c0e 100644 GIT binary patch delta 32 lcmdm{y-k}tpO=@50SLb3C2r(CAi{WS@);2eAjvAa5dfZA3UvSg delta 32 lcmdm{y-k}tpO=@50SLI}hHd0NAi@|m`HYAKkYp9z2mps^2(17B diff --git a/src/gui/plotter.py b/src/gui/plotter.py index 8526ad5..29e99c5 100644 --- a/src/gui/plotter.py +++ b/src/gui/plotter.py @@ -1,8 +1,6 @@ import pandas as pd from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel, QGraphicsRectItem import copy - - import pyqtgraph as pg from typing import Optional, Any @@ -14,56 +12,6 @@ class ProcessStage(): finish_index:int class PlotWidget(BasePlotWidget): - - def _create_navigator(self, - time_region:tuple[float, float], - main_plot: pg.PlotWidget, - dataframe: pd.DataFrame, - real_signals: list[dict[str, Any]]) -> list[pg.PlotWidget, pg.LinearRegionItem]: - """ - Создаёт график-навигатор, отображающий все данные в уменьшенном масштабе. - """ - navigator = pg.PlotWidget(title="Navigator") - navigator.setFixedHeight(100) - - for signal in real_signals: - if signal["name"] in dataframe.columns: - x = dataframe["time"] - y = dataframe[signal["name"]] - - x_downsampled, y_downsampled = self._downsample_data(x, y, max_points=1000) - navigator.plot(x_downsampled, y_downsampled, pen=signal["pen"], name=signal["name"]) - - ROI_region = pg.LinearRegionItem(values=time_region, movable=True, brush=pg.mkBrush(0, 0, 255, 100)) - navigator.addItem(ROI_region) - - # Связываем изменение региона навигатора с обновлением области просмотра основного графика - ROI_region.sigRegionChanged.connect(lambda: self._sync_main_plot_with_navigator(main_plot, ROI_region)) - - return navigator, ROI_region - - def _downsample_data(self, x, y, max_points=5000): - """ - Понижает разрешение данных до заданного количества точек для улучшения производительности навигатора. - """ - if len(x) > max_points: - factor = len(x) // max_points - x_downsampled = x[::factor] - y_downsampled = y[::factor] - return x_downsampled, y_downsampled - return x, y - - def _sync_main_plot_with_navigator(self, - main_plot: pg.PlotWidget, - region: pg.LinearRegionItem): - """ - Синхронизирует область просмотра основного графика с регионом навигатора. - """ - x_min, x_max = region.getRegion() - if main_plot: - main_plot.blockSignals(True) - main_plot.setXRange(x_min, x_max, padding=0) - main_plot.blockSignals(False) def _create_curve_ideal(self, signal: dict[str, Any], @@ -197,29 +145,6 @@ class PlotWidget(BasePlotWidget): layout.addWidget(performance_label) performance_label.update() - def _mirror_shift_data(self, - valid_str: str, - signals: list[dict], - dataframe: pd.DataFrame, - shift: float) -> pd.DataFrame: - keys = dataframe.keys() - for signal in signals: - if valid_str in signal["name"] and signal["name"] in keys: - dataframe[signal["name"]] = dataframe[signal["name"]].apply(lambda x: shift-x) - return dataframe - - def _shift_data(self, - valid_str: str, - signals: list[dict], - dataframe: pd.DataFrame, - shift: float) -> pd.DataFrame: - keys = dataframe.keys() - for signal in signals: - if valid_str in signal["name"] and signal["name"] in keys: - dataframe[signal["name"]] = dataframe[signal["name"]].apply(lambda x: x + shift) - return dataframe - - def _build_widget(self, data: list[Any]) -> QWidget: """ Собирает графический виджет для одного набора данных. @@ -324,16 +249,6 @@ class PlotWidget(BasePlotWidget): widget.setLayout(layout) return widget - - def _sync_navigator_with_main(self, main_plot: pg.PlotWidget, region:pg.LinearRegionItem): - """ - Синхронизирует регион навигатора с областью просмотра основного графика. - """ - if region: - x_min, x_max = main_plot - region.blockSignals(True) # Предотвращаем рекурсию - region.setRegion([x_min, x_max]) - region.blockSignals(False) def build(self, data: list[list[Any]]) -> None: """ @@ -348,4 +263,3 @@ class PlotWidget(BasePlotWidget): widgets = [self._build_widget(data_sample) for data_sample in data] self._mediator.notify(self, widgets) - diff --git a/src/utils/base/__pycache__/base.cpython-310.pyc b/src/utils/base/__pycache__/base.cpython-310.pyc index b6502bab018aede3efa3f9f953eacec18dc8cd5b..5a76e8b45513882274453a9f8b8daa92bc41a632 100644 GIT binary patch delta 5486 zcma)A32>9g75;bi|FSL%8K3egz#IbG+~&qyg`6aTTnId>@XAI;mc>do*oX*YXY4c( z0$Y+cNvCGgc7~a@IB^_1TxpxM4W&(_9F+b|JIzd*hNNkdk{%&f-&^_Q$W$7=|Gl@n zZ{O~F@7w+LY8yHGII%aTr&|>GJip6VcW}cYdm*8RX6%h;dvch= z_gQa4Ed`Q8L>zQKv~Ee?0OBRo*-5KYTA5_qOzskKTMN0j_fwmTkm(}d{x;bnzOwHi zUa@0bJ*g3Ij@v@IKLvRS<1m>>TsSnw+z!W0iR6Sj~o>Qrh8Q<>J0?lG{%%)+c4 zsz+r@T`E71>{K`of*Mb!ylP9_GDoiMg7xi9f_ zqQ?b~GpIltZmzy)j% zG!MXJJ<=?AS~0wm^=_gYg8q;@jTgZRb+U_x@o8!B?ec~j1EFX{H`e-UqK#Zn-{obE zJ3|p)LpbPXdU}gDK1$}rFfK(((1K%BXD{3fVZBU7D9%usJ=R``OLfoYJBX)!}e54@?1)~m6!n28x#+5y8By2rf7 z64UCnm^mJ^KsOT%mqwWRfJ&4d=`f)Y(%TYMy3+s|0UKdTm8BmrJfMIBrY;2?=u+y< z-Ih+JlXTKr1GBSn9VY3R)}_d#cQic)-Vdir;wa=;KW1<85M+F!H@PC6{ewvkNt`(40%Z^6au*ou zNj#P48%bVIt$Dq#IZ)?=?1VhlqJe18&o_b7ya9-=V(MIc7XslXd_Sr~K-^S5WS2WR zLG>0?8+2o{FWBUd=xGg&&AzQczpicNO_6OihcdF_fHOp9Zx`)Wx(I9`-~xBzK%y6W zBQ2pC?{FG=cLt){yrCiAWK|q9=#~w)-8h)ZT;RM|a-&Mdv^3~z*vfp%jo_8Uf1A=e zM-~WV`f!ERK<-BUBjziX1{-T2jh6$H8t=C1G+d`!Mpc46;*YKk?DDf4{DHb{Q9Z4u zG1$})itvZghio9aV^4CP& z*3^0qp+UL4Bgj39rp?29p&L_0#~;K-#2Wq(l7mPjgd9aqLP&;pc&YKhFnq$oC}!x`;z);%>;0j zI28cq#gkKPOao!EL}zGlD&0h0pCIH2oO$3rBqm?;PS!r+-S6UieJp#)XZ zI^kL#&Kl$5b%Vf9g0*Y!Sqye9cg&vgQ|O%Za3ra4zue##KLbo_*_FP0-8S*((cUkR zNPF>-#al=1?*z2|B3jSCzV)jxWcWr}2_s{aJ7Z)JLI6$%;e&Q#{-||Sf(ea7gJc;b z68_xkRp;^b(PMPgU-Jrx&@dKak`Il+m>d6JkQq6T?*y!%{25rHgoPAd@Mp!2g3L|M z)Dby+4y2AqJTc2)Mo+?oGg(?ki+wge+LQ1l7AP7TOHLCk&i!xT1%?L5R+1MhIll}lB~EBr~^wY6fVsp z4)HsHfWLBrmr^`B%#nx5CL#YjB(lfLsLc?*{QS8Oqw+YCZX_=t`6ZHHBf(clj)y1T zh(wxvMLe88p=3MAktsk-3Z;&(ER7bk#cCLqmkUlwFJ$V&>nHDL3Bj4%~?a<@BP)B)gu@wF-RD3C1^YW+u1zFrrXe&Zq z4u=<_!J31Mn8GO$zIpS>rQS#9Z6f!eIf%r+vG;$F*oJKC2DrKCTA0Hdu-lxnH*88b z`kVdmX6&)cH)QXQCSM5NJz6;4XSkJ!b(IyAQn9mgAEfBz%D%<2)P93Aj6_SuNQO)X z>LYB$XhBs-_p{L01#xk~T{jSHgNiMSmT3}>dXF#i6Y{CZ zUNVzbQn7YPg9IT_ u9t-?q(XwJj*)))Ciiu{yYY|chJb{C+U9~&yv+WKg?)av|=9oTy{{H~4Rd8nj delta 2172 zcmZ`)d2o|e5dZdTlICg}+R&z@7xW^%FX&J#Oz90Rf?OIbH1bjmmK46m;kGIr5v*ca zu8N|Ckr@;O$#6KMBcR|^6b}xa2vr0TP*Fr-2A$&W7p@t#fBf?M?e5$C-tK#^JsaT5 zr@+z@7G{*_FEgQWrc~Z(i34M2=96s(r%^~kZod87-x*ac34<`UOTxHRc1Dvj2{S1( zDLbh!VIgH96+t)#gghLB1lEJ!yRWJf4|cujrRR8MYXj zp%PCS=0hz`GPXlK28`V>9v7RIz(l-ZS`1Tgo_PT{{a4IM09hDeIS145x@9i7&=Woj z+;}|vVenwSbqzG&N7f;23iZe>IYCHH*#II|3|J;LfzSwTdzdps#0jG?wQHOjw^qcf zz0fQLr_QaL6)F;_868?5whJ$aLajk=?1F;Lh=3}rDalQfdkI6-m@QlhBv zSjE4$U!exP{-63M$Z#5s_Q5zUrAj_8;g%Gad`Ut>s!P5sVRLF6bl^CL4SPpNhOMBr zTV*Alev}RzA0DaeAo{z6CsP&qnuMd%O52oi>>VGB9LjuokaMWY9U3K>`3nqc#7bfg zlak4XEQV}`B!*`h9$<)Nn82WBdXd>ghJ-s%BuUs%5Q;m~HIcK)+RAJ6k}O+q8e3!o z9!vL{xK^<0DB4#cti~_&k>Tc6w^vM`=MgjAzSh4b+%$LwtW|gDp!k~-COQPH<4|1Z z=m#=xb!2C+=2Z9OBT0K(%hq%Tb#J4B)^!+?kz!rLX3nUrXGl;h*ooeda9qZASdM)e zo1qIgWfp@T1DPW-0@|kL7MCxeX?ol{BcNyWd0M<`?i=PgBB#RTb5$v>*={V(S`~Kj zLI{0?E}-#w$Z{fUFuaU?S%V^9;c~AsaO(r$Q8r^?b{>SI$ZmsZ{5&@qLvtR4SZvH$ z1o5iAnKK!ZaB}VfNG3fW(y%sfBVCrpoMbfR*T62En4eFF{h9otwk}T1n|A0Fwbn*9 zs0CkRrnaJ+{qn#0+xOUcox}20_5Y$LLU^Prl?N$4u|jKDQKgK4)=SDrf6X#9v+qpd-2+^H0Z?m zlIp}guOetDO128XnIXNJ*69aMr_j^Aggi^7mcid4gUQj%OUzh zwj3gG=#?Y9CZyTzRSsipS#0|2>{C0Y4_-=j`6p~W$k4;^v4m60hQMZjXW2u+bTp%P z+4CO535L%Q%A<9`g_uwt7kZ4X$0aN)&yjZl&MkkMPURovyGzu&_Z)lgPGSd3bsXvp zcC+L`&}C4ciqmZ9!m|~Hau1-ra-ZpI>ZOuF=7niEy~>VPD{Cn~jRD71Y2Gv*7~6 zFb4I3NM!ai!6mN!3lWDLFf=JG3*FvUw=bae_}sHwsWs{+pOf%v&7*QJU_)&s9iYaP zbXb7{^P)r5*XLKji?ykDUq&6jjLP%810#3nD%YsM#PC|vb*96~wlGQE>Y>rK@?U_~ zF}Ah?yok?1a9Z8W)Qj=~F&g(>zdD&u|0D7!N9vUS^`B(FJa#O_s8i_W9Jem(nA_#P zRfB@1&oI{nL(X!r`a!oIv2$$r;g0n@vsDa;m&c?y_;?1-(hXX+Z@Fy3DuZ{>Td@P$)s3<>I^yRzN_8Mv`N#-<00))HgM Qw^*e%tHo-zW<(762Q9rUY5)KL diff --git a/src/utils/base/base.py b/src/utils/base/base.py index 1029b54..8d499e6 100644 --- a/src/utils/base/base.py +++ b/src/utils/base/base.py @@ -9,10 +9,8 @@ from PyQt5.QtCore import QThread, QObject, QTimer from PyQt5.QtWidgets import QWidget, QTabWidget from PyQt5.QtOpenGL import QGLWidget from OptAlgorithm import OptAlgorithm -import pandas as pd -import pandas as pd import numpy as np - +import pyqtgraph as pg @@ -227,6 +225,88 @@ class BasePlotWidget: font-family: "Segoe UI", sans-serif; }""") + def _downsample_data(self, x, y, max_points=5000): + """ + Понижает разрешение данных до заданного количества точек для улучшения производительности навигатора. + """ + if len(x) > max_points: + factor = len(x) // max_points + x_downsampled = x[::factor] + y_downsampled = y[::factor] + return x_downsampled, y_downsampled + return x, y + + def _create_navigator(self, + time_region:tuple[float, float], + main_plot: pg.PlotWidget, + dataframe: pd.DataFrame, + real_signals: list[dict[str, Any]]) -> list[pg.PlotWidget, pg.LinearRegionItem]: + """ + Создаёт график-навигатор, отображающий все данные в уменьшенном масштабе. + """ + navigator = pg.PlotWidget(title="Navigator") + navigator.setFixedHeight(100) + + for signal in real_signals: + if signal["name"] in dataframe.columns: + x = dataframe["time"] + y = dataframe[signal["name"]] + + x_downsampled, y_downsampled = self._downsample_data(x, y, max_points=1000) + navigator.plot(x_downsampled, y_downsampled, pen=signal["pen"], name=signal["name"]) + + ROI_region = pg.LinearRegionItem(values=time_region, movable=True, brush=pg.mkBrush(0, 0, 255, 100)) + navigator.addItem(ROI_region) + + # Связываем изменение региона навигатора с обновлением области просмотра основного графика + ROI_region.sigRegionChanged.connect(lambda: self._sync_main_plot_with_navigator(main_plot, ROI_region)) + + return navigator, ROI_region + + def _sync_main_plot_with_navigator(self, + main_plot: pg.PlotWidget, + region: pg.LinearRegionItem): + """ + Синхронизирует область просмотра основного графика с регионом навигатора. + """ + x_min, x_max = region.getRegion() + if main_plot: + main_plot.blockSignals(True) + main_plot.setXRange(x_min, x_max, padding=0) + main_plot.blockSignals(False) + + def _mirror_shift_data(self, + valid_str: str, + signals: list[dict], + dataframe: pd.DataFrame, + shift: float) -> pd.DataFrame: + keys = dataframe.keys() + for signal in signals: + if valid_str in signal["name"] and signal["name"] in keys: + dataframe[signal["name"]] = dataframe[signal["name"]].apply(lambda x: shift-x) + return dataframe + + def _shift_data(self, + valid_str: str, + signals: list[dict], + dataframe: pd.DataFrame, + shift: float) -> pd.DataFrame: + keys = dataframe.keys() + for signal in signals: + if valid_str in signal["name"] and signal["name"] in keys: + dataframe[signal["name"]] = dataframe[signal["name"]].apply(lambda x: x + shift) + return dataframe + + def _sync_navigator_with_main(self, main_plot: pg.PlotWidget, region:pg.LinearRegionItem): + """ + Синхронизирует регион навигатора с областью просмотра основного графика. + """ + if region: + x_min, x_max = main_plot + region.blockSignals(True) # Предотвращаем рекурсию + region.setRegion([x_min, x_max]) + region.blockSignals(False) + @property def mediator(self) -> BaseMediator: return self._mediator