added refractive index plot
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
|||||||
|
.conda-env
|
||||||
dispersion_config.toml
|
dispersion_config.toml
|
||||||
pyrightconfig.json
|
pyrightconfig.json
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ conda activate app-env
|
|||||||
|
|
||||||
3. The prompt should now read '(app-env)' on the left. The app is not published on Github or anywhere else. The link below points to my own personnal home server (I didn't find any way of getting a direct download link You are now ready to install everything with this command:
|
3. The prompt should now read '(app-env)' on the left. The app is not published on Github or anywhere else. The link below points to my own personnal home server (I didn't find any way of getting a direct download link You are now ready to install everything with this command:
|
||||||
|
|
||||||
pip install "git+file://<path to the git repository>"
|
pip install http://130.92.113.172/dispersionapp_v0.1.0.zip
|
||||||
|
|
||||||
# Usage
|
# Usage
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "dispersionapp"
|
name = "dispersionapp"
|
||||||
version = "0.1.0"
|
version = "0.1.3"
|
||||||
description = "Model hollow capillary and revolver fiber interactively"
|
description = "Model hollow capillary and revolver fiber interactively"
|
||||||
authors = [{ name = "Benoît Sierro", email = "benoit.sierro@unibe.ch" }]
|
authors = [{ name = "Benoît Sierro", email = "benoit.sierro@unibe.ch" }]
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"scgenerator @ git+https://github.com/bsierro/scgenerator.git",
|
"scgenerator @ git+https://github.com/bsierro/scgenerator.git",
|
||||||
"click",
|
"click",
|
||||||
"pydantic",
|
"pydantic < 2",
|
||||||
"tomli",
|
"tomli",
|
||||||
"tomli_w",
|
"tomli_w",
|
||||||
"PySide6 >= 6.4.0",
|
"PySide6 >= 6.4.0",
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import NamedTuple
|
from typing import NamedTuple
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import scgenerator as sc
|
import scgenerator as sc
|
||||||
@@ -17,6 +17,7 @@ class CurrentState(BaseModel):
|
|||||||
core_diameter_um: float
|
core_diameter_um: float
|
||||||
pressure_mbar: float
|
pressure_mbar: float
|
||||||
wall_thickness_um: float
|
wall_thickness_um: float
|
||||||
|
num_resonances: conint(ge=6, le=40) = 6
|
||||||
n_tubes: int
|
n_tubes: int
|
||||||
gap_um: float
|
gap_um: float
|
||||||
t_fwhm_fs: float
|
t_fwhm_fs: float
|
||||||
@@ -27,7 +28,6 @@ class Config(BaseModel):
|
|||||||
wl_max: confloat(ge=500, le=6000) = 1600
|
wl_max: confloat(ge=500, le=6000) = 1600
|
||||||
wl_pump: confloat(ge=200, le=6000) = 800
|
wl_pump: confloat(ge=200, le=6000) = 800
|
||||||
rep_rate: confloat(gt=0) = 8e3
|
rep_rate: confloat(gt=0) = 8e3
|
||||||
num_resonances: conint(ge=6, le=20) = 6
|
|
||||||
gas: str = "argon"
|
gas: str = "argon"
|
||||||
safety_factor: float = 10.0
|
safety_factor: float = 10.0
|
||||||
current_state: CurrentState | None = None
|
current_state: CurrentState | None = None
|
||||||
@@ -45,7 +45,7 @@ class Config(BaseModel):
|
|||||||
try:
|
try:
|
||||||
out = cls(**d)
|
out = cls(**d)
|
||||||
except ValidationError as e:
|
except ValidationError as e:
|
||||||
s = f"invalid input in config file {config_file}:\n{e}"
|
s = f"invalid input in config file {config_file}:\n{e}\ncreating new config"
|
||||||
print(s)
|
print(s)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
out._file_name = Path(config_file)
|
out._file_name = Path(config_file)
|
||||||
@@ -58,12 +58,20 @@ class Config(BaseModel):
|
|||||||
tmp.replace(self._file_name)
|
tmp.replace(self._file_name)
|
||||||
|
|
||||||
def update_current(
|
def update_current(
|
||||||
self, core_diameter_um, pressure_mbar, wall_thickness_um, n_tubes, gap_um, t_fwhm_fs
|
self,
|
||||||
|
core_diameter_um: float,
|
||||||
|
pressure_mbar: float,
|
||||||
|
wall_thickness_um: float,
|
||||||
|
num_resonances: int,
|
||||||
|
n_tubes: int,
|
||||||
|
gap_um: float,
|
||||||
|
t_fwhm_fs: float,
|
||||||
):
|
):
|
||||||
self.current_state = CurrentState(
|
self.current_state = CurrentState(
|
||||||
core_diameter_um=core_diameter_um,
|
core_diameter_um=core_diameter_um,
|
||||||
pressure_mbar=pressure_mbar,
|
pressure_mbar=pressure_mbar,
|
||||||
wall_thickness_um=wall_thickness_um,
|
wall_thickness_um=wall_thickness_um,
|
||||||
|
num_resonances=num_resonances,
|
||||||
n_tubes=n_tubes,
|
n_tubes=n_tubes,
|
||||||
gap_um=gap_um,
|
gap_um=gap_um,
|
||||||
t_fwhm_fs=t_fwhm_fs,
|
t_fwhm_fs=t_fwhm_fs,
|
||||||
|
|||||||
@@ -7,8 +7,9 @@ from functools import cache
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
import scgenerator as sc
|
import scgenerator as sc
|
||||||
|
|
||||||
from dispersionapp.core import Config, LimitValues, N_ion_max, N_sf_max, b2, energy
|
from dispersionapp.core import (Config, LimitValues, N_ion_max, N_sf_max, b2,
|
||||||
from dispersionapp.plotapp import PlotApp
|
energy)
|
||||||
|
from dispersionapp.plotapp import PlotApp, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
def app(config_file: os.PathLike | None = None):
|
def app(config_file: os.PathLike | None = None):
|
||||||
@@ -19,27 +20,34 @@ def app(config_file: os.PathLike | None = None):
|
|||||||
wl_ind = sc.math.argclosest(wl, config.wl_pump * 1e-9)
|
wl_ind = sc.math.argclosest(wl, config.wl_pump * 1e-9)
|
||||||
w0 = w[wl_ind]
|
w0 = w[wl_ind]
|
||||||
|
|
||||||
|
|
||||||
gas = sc.materials.Gas(config.gas)
|
gas = sc.materials.Gas(config.gas)
|
||||||
|
|
||||||
with PlotApp(
|
with PlotApp(
|
||||||
f"Dispersion design with {config.gas.title()}",
|
f"Dispersion design with {config.gas.title()}",
|
||||||
core_diameter_um=np.arange(50, 301, dtype=float),
|
core_diameter_um=np.arange(50, 301, dtype=float),
|
||||||
pressure_mbar=np.geomspace(1, 2000),
|
pressure_mbar=np.geomspace(1, 2000),
|
||||||
wall_thickness_um=np.geomspace(0.01, 10),
|
wall_thickness_um=np.geomspace(0.01, 10, 201),
|
||||||
|
num_resonances=np.arange(6, 41),
|
||||||
n_tubes=np.arange(6, 16),
|
n_tubes=np.arange(6, 16),
|
||||||
gap_um=np.arange(1, 15.5, 0.5),
|
gap_um=np.arange(1, 15.5, 0.5),
|
||||||
t_fwhm_fs=np.arange(10, 201, dtype=float),
|
t_fwhm_fs=np.arange(10, 201, dtype=float),
|
||||||
) as app:
|
) as app:
|
||||||
# initial setup
|
# initial setup
|
||||||
ax = app["Dispersion plot"]
|
beta_ax = app["Dispersion plot"]
|
||||||
ax.horizontal_line("reference", 0, color="gray")
|
beta_ax.horizontal_line("reference", 0, color="gray")
|
||||||
ax.set_xlabel("wavelength (nm)")
|
beta_ax.set_xlabel("wavelength (nm)")
|
||||||
ax.set_ylabel("beta2 (fs^2/cm)")
|
beta_ax.set_ylabel("beta2 (fs^2/cm)")
|
||||||
|
|
||||||
|
n_ax = app["Refractive index (real)"]
|
||||||
|
n_ax.link_x(beta_ax)
|
||||||
|
n_ax.set_xlabel("wavelength (nm)")
|
||||||
|
n_ax.set_ylabel("n")
|
||||||
|
|
||||||
if config.current_state is not None:
|
if config.current_state is not None:
|
||||||
app.params["core_diameter_um"].value = config.current_state.core_diameter_um
|
app.params["core_diameter_um"].value = config.current_state.core_diameter_um
|
||||||
app.params["pressure_mbar"].value = config.current_state.pressure_mbar
|
app.params["pressure_mbar"].value = config.current_state.pressure_mbar
|
||||||
app.params["wall_thickness_um"].value = config.current_state.wall_thickness_um
|
app.params["wall_thickness_um"].value = config.current_state.wall_thickness_um
|
||||||
|
app.params["num_resonances"].value = config.current_state.num_resonances
|
||||||
app.params["n_tubes"].value = config.current_state.n_tubes
|
app.params["n_tubes"].value = config.current_state.n_tubes
|
||||||
app.params["gap_um"].value = config.current_state.gap_um
|
app.params["gap_um"].value = config.current_state.gap_um
|
||||||
app.params["t_fwhm_fs"].value = config.current_state.t_fwhm_fs
|
app.params["t_fwhm_fs"].value = config.current_state.t_fwhm_fs
|
||||||
@@ -47,10 +55,19 @@ def app(config_file: os.PathLike | None = None):
|
|||||||
app.params["core_diameter_um"].value = 100
|
app.params["core_diameter_um"].value = 100
|
||||||
app.params["pressure_mbar"].value = 500
|
app.params["pressure_mbar"].value = 500
|
||||||
app.params["wall_thickness_um"].value = 1
|
app.params["wall_thickness_um"].value = 1
|
||||||
|
app.params["num_resonances"].value = 6
|
||||||
app.params["n_tubes"].value = 7
|
app.params["n_tubes"].value = 7
|
||||||
app.params["gap_um"].value = 5
|
app.params["gap_um"].value = 5
|
||||||
app.params["t_fwhm_fs"].value = 100
|
app.params["t_fwhm_fs"].value = 100
|
||||||
ax.set_lim(ylim=(-4, 2))
|
|
||||||
|
def reset_view():
|
||||||
|
# reseting beta_ax resets n_ax as well since they're linked
|
||||||
|
beta_ax.set_lim(ylim=(-4, 2))
|
||||||
|
|
||||||
|
reset_button = QtWidgets.QPushButton("Reset axes")
|
||||||
|
reset_button.clicked.connect(reset_view)
|
||||||
|
app.params_layout.addWidget(reset_button)
|
||||||
|
reset_view()
|
||||||
|
|
||||||
app.update(config.update_current)
|
app.update(config.update_current)
|
||||||
|
|
||||||
@@ -86,13 +103,14 @@ def app(config_file: os.PathLike | None = None):
|
|||||||
)
|
)
|
||||||
|
|
||||||
@cache
|
@cache
|
||||||
def compute_vincetti(
|
def compute_n_eff_vincetti(
|
||||||
wall_thickness_um: float,
|
wall_thickness_um: float,
|
||||||
core_diameter_um: float,
|
core_diameter_um: float,
|
||||||
pressure_mbar: float,
|
pressure_mbar: float,
|
||||||
|
num_resonances: int,
|
||||||
n_tubes: int,
|
n_tubes: int,
|
||||||
gap_um: float,
|
gap_um: float,
|
||||||
) -> np.ndarray:
|
):
|
||||||
core_diameter = core_diameter_um * 1e-6
|
core_diameter = core_diameter_um * 1e-6
|
||||||
wall_thickness = wall_thickness_um * 1e-6
|
wall_thickness = wall_thickness_um * 1e-6
|
||||||
gap = gap_um * 1e-6
|
gap = gap_um * 1e-6
|
||||||
@@ -100,15 +118,21 @@ def app(config_file: os.PathLike | None = None):
|
|||||||
|
|
||||||
tr = sc.fiber.tube_radius_from_gap(core_diameter / 2, gap, n_tubes)
|
tr = sc.fiber.tube_radius_from_gap(core_diameter / 2, gap, n_tubes)
|
||||||
n_gas_2 = gas.sellmeier.n_gas_2(wl, None, pressure)
|
n_gas_2 = gas.sellmeier.n_gas_2(wl, None, pressure)
|
||||||
n_eff_vinc = sc.fiber.n_eff_vincetti(
|
return sc.fiber.n_eff_vincetti(
|
||||||
wl,
|
wl, 800e-9, n_gas_2, wall_thickness, tr, gap, n_tubes, n_terms=num_resonances
|
||||||
800e-9,
|
)
|
||||||
n_gas_2,
|
|
||||||
wall_thickness,
|
@cache
|
||||||
tr,
|
def compute_vincetti_beta(
|
||||||
gap,
|
wall_thickness_um: float,
|
||||||
n_tubes,
|
core_diameter_um: float,
|
||||||
n_terms=config.num_resonances,
|
pressure_mbar: float,
|
||||||
|
num_resonances: int,
|
||||||
|
n_tubes: int,
|
||||||
|
gap_um: float,
|
||||||
|
) -> np.ndarray:
|
||||||
|
n_eff_vinc = compute_n_eff_vincetti(
|
||||||
|
wall_thickness_um, core_diameter_um, pressure_mbar, num_resonances, n_tubes, gap_um
|
||||||
)
|
)
|
||||||
return b2(w, n_eff_vinc)
|
return b2(w, n_eff_vinc)
|
||||||
|
|
||||||
@@ -121,22 +145,37 @@ def app(config_file: os.PathLike | None = None):
|
|||||||
return b2(w, n_eff_cap)
|
return b2(w, n_eff_cap)
|
||||||
|
|
||||||
@app.update
|
@app.update
|
||||||
def draw_vincetty(
|
def draw_vincetty_n_eff(
|
||||||
wall_thickness_um: float,
|
wall_thickness_um: float,
|
||||||
core_diameter_um: float,
|
core_diameter_um: float,
|
||||||
pressure_mbar: float,
|
pressure_mbar: float,
|
||||||
|
num_resonances: int,
|
||||||
n_tubes: int,
|
n_tubes: int,
|
||||||
gap_um: float,
|
gap_um: float,
|
||||||
):
|
):
|
||||||
b2 = compute_vincetti(
|
n_eff = compute_n_eff_vincetti(
|
||||||
wall_thickness_um, core_diameter_um, pressure_mbar, n_tubes, gap_um
|
wall_thickness_um, core_diameter_um, pressure_mbar, num_resonances, n_tubes, gap_um
|
||||||
)
|
)
|
||||||
ax.set_line_data("Vincetti", wl * 1e9, sc.units.beta2_fs_cm_inv(b2))
|
n_ax.set_line_data("Vincetti", wl * 1e9, n_eff)
|
||||||
|
|
||||||
|
@app.update
|
||||||
|
def draw_vincetty_beta(
|
||||||
|
wall_thickness_um: float,
|
||||||
|
core_diameter_um: float,
|
||||||
|
pressure_mbar: float,
|
||||||
|
num_resonances: int,
|
||||||
|
n_tubes: int,
|
||||||
|
gap_um: float,
|
||||||
|
):
|
||||||
|
b2 = compute_vincetti_beta(
|
||||||
|
wall_thickness_um, core_diameter_um, pressure_mbar, num_resonances, n_tubes, gap_um
|
||||||
|
)
|
||||||
|
beta_ax.set_line_data("Vincetti", wl * 1e9, sc.units.beta2_fs_cm_inv(b2))
|
||||||
|
|
||||||
@app.update
|
@app.update
|
||||||
def draw_capillary(core_diameter_um: float, pressure_mbar: float):
|
def draw_capillary(core_diameter_um: float, pressure_mbar: float):
|
||||||
b2 = compute_capillary(core_diameter_um, pressure_mbar)
|
b2 = compute_capillary(core_diameter_um, pressure_mbar)
|
||||||
ax.set_line_data("Capillary", wl * 1e9, sc.units.beta2_fs_cm_inv(b2))
|
beta_ax.set_line_data("Capillary", wl * 1e9, sc.units.beta2_fs_cm_inv(b2))
|
||||||
|
|
||||||
@app.update
|
@app.update
|
||||||
def draw_energy_limit(core_diameter_um: float, pressure_mbar: float, t_fwhm_fs: float):
|
def draw_energy_limit(core_diameter_um: float, pressure_mbar: float, t_fwhm_fs: float):
|
||||||
@@ -153,7 +192,7 @@ def app(config_file: os.PathLike | None = None):
|
|||||||
return
|
return
|
||||||
|
|
||||||
zdw = lim.wl_zero_disp * 1e9
|
zdw = lim.wl_zero_disp * 1e9
|
||||||
ax.set_line_data("zdw", [zdw, zdw], [-3, 3])
|
beta_ax.set_line_data("zdw", [zdw, zdw], [-3, 3])
|
||||||
|
|
||||||
info_lines.append(f"ZDW = {zdw:.0f}nm")
|
info_lines.append(f"ZDW = {zdw:.0f}nm")
|
||||||
if lim.ion_lim > lim.sf_lim:
|
if lim.ion_lim > lim.sf_lim:
|
||||||
@@ -170,6 +209,6 @@ def app(config_file: os.PathLike | None = None):
|
|||||||
f"N = {lim.soliton_sf_limit:.1f}",
|
f"N = {lim.soliton_sf_limit:.1f}",
|
||||||
"limited by ionization",
|
"limited by ionization",
|
||||||
]
|
]
|
||||||
app.info_label.setText("\n".join(info_lines))
|
app.info_label.setText(" ".join(info_lines))
|
||||||
|
|
||||||
config.save()
|
config.save()
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ import itertools
|
|||||||
from collections.abc import MutableMapping, Sequence
|
from collections.abc import MutableMapping, Sequence
|
||||||
from functools import cache
|
from functools import cache
|
||||||
from types import MethodType
|
from types import MethodType
|
||||||
from typing import Any, Callable, Iterable, Iterator, Optional, Type, Union, overload
|
from typing import (Any, Callable, Iterable, Iterator, Optional, Type, Union,
|
||||||
|
overload)
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import pyqtgraph as pg
|
import pyqtgraph as pg
|
||||||
@@ -29,30 +30,17 @@ MPL_COLORS = [
|
|||||||
key_type = Union[str, int]
|
key_type = Union[str, int]
|
||||||
|
|
||||||
|
|
||||||
class Field(QtWidgets.QWidget):
|
class SliderField(QtWidgets.QWidget):
|
||||||
dtype: Type
|
dtype: Type
|
||||||
value: Any
|
value: Any
|
||||||
value_changed: QtCore.Signal
|
value_changed: QtCore.Signal
|
||||||
timer: QtCore.QTimer
|
|
||||||
|
|
||||||
@property
|
|
||||||
def value(self) -> Any:
|
|
||||||
raise NotImplementedError()
|
|
||||||
|
|
||||||
def values(self) -> list[Any]:
|
|
||||||
raise NotImplementedError()
|
|
||||||
|
|
||||||
|
|
||||||
class SliderField(Field):
|
|
||||||
dtype: Type
|
dtype: Type
|
||||||
possible_values: np.ndarray
|
possible_values: np.ndarray
|
||||||
_slider_max = 100
|
_slider_max = 100
|
||||||
_tuple_signal = QtCore.Signal(tuple)
|
|
||||||
_int_signal = QtCore.Signal(int)
|
_int_signal = QtCore.Signal(int)
|
||||||
_float_signal = QtCore.Signal(float)
|
_float_signal = QtCore.Signal(float)
|
||||||
_str_signal = QtCore.Signal(str)
|
|
||||||
|
|
||||||
def __init__(self, name: str, values: Iterable) -> None:
|
def __init__(self, name: str, values: Iterable[float] | Iterable[int]) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.__value = None
|
self.__value = None
|
||||||
self.slider = QtWidgets.QSlider(QtCore.Qt.Orientation.Horizontal)
|
self.slider = QtWidgets.QSlider(QtCore.Qt.Orientation.Horizontal)
|
||||||
@@ -64,16 +52,18 @@ class SliderField(Field):
|
|||||||
self.field.editingFinished.connect(self.field_changed)
|
self.field.editingFinished.connect(self.field_changed)
|
||||||
|
|
||||||
self.step_backward_button = QtWidgets.QPushButton("<")
|
self.step_backward_button = QtWidgets.QPushButton("<")
|
||||||
|
self.step_backward_button.setFixedWidth(30)
|
||||||
self.step_backward_button.clicked.connect(self.step_backward)
|
self.step_backward_button.clicked.connect(self.step_backward)
|
||||||
|
|
||||||
self.step_forward_button = QtWidgets.QPushButton(">")
|
self.step_forward_button = QtWidgets.QPushButton(">")
|
||||||
|
self.step_forward_button.setFixedWidth(30)
|
||||||
self.step_forward_button.clicked.connect(self.step_forward)
|
self.step_forward_button.clicked.connect(self.step_forward)
|
||||||
|
|
||||||
self._layout = QtWidgets.QHBoxLayout()
|
self._layout = QtWidgets.QHBoxLayout()
|
||||||
self.setLayout(self._layout)
|
self.setLayout(self._layout)
|
||||||
self._layout.setContentsMargins(10, 0, 10, 0)
|
self._layout.setContentsMargins(10, 0, 10, 0)
|
||||||
|
|
||||||
pretty_name = " ".join(s.title() for s in name.split("_"))
|
pretty_name = " ".join(s for s in name.split("_"))
|
||||||
self.name_label = QtWidgets.QLabel(pretty_name + " :")
|
self.name_label = QtWidgets.QLabel(pretty_name + " :")
|
||||||
|
|
||||||
self._layout.addWidget(self.name_label)
|
self._layout.addWidget(self.name_label)
|
||||||
@@ -86,8 +76,6 @@ class SliderField(Field):
|
|||||||
self.value_changed = {
|
self.value_changed = {
|
||||||
int: self._int_signal,
|
int: self._int_signal,
|
||||||
float: self._float_signal,
|
float: self._float_signal,
|
||||||
str: self._str_signal,
|
|
||||||
tuple: self._tuple_signal,
|
|
||||||
}[self.dtype]
|
}[self.dtype]
|
||||||
self.value_changed.emit(self.__value)
|
self.value_changed.emit(self.__value)
|
||||||
|
|
||||||
@@ -130,11 +118,8 @@ class SliderField(Field):
|
|||||||
self.value_changed.emit(new_value)
|
self.value_changed.emit(new_value)
|
||||||
|
|
||||||
def field_changed(self):
|
def field_changed(self):
|
||||||
try:
|
new_val = self.dtype(self.field.text())
|
||||||
new_val = self.dtype(self.field.text())
|
new_val = min(self.value_to_slider_map, key=lambda el: abs(el - new_val))
|
||||||
except (ValueError, TypeError):
|
|
||||||
self.update_label()
|
|
||||||
return
|
|
||||||
self.value = new_val
|
self.value = new_val
|
||||||
|
|
||||||
def slider_changed(self):
|
def slider_changed(self):
|
||||||
@@ -168,7 +153,7 @@ class SliderField(Field):
|
|||||||
if self.dtype is int:
|
if self.dtype is int:
|
||||||
return format(self.value)
|
return format(self.value)
|
||||||
elif self.dtype is float:
|
elif self.dtype is float:
|
||||||
return format(self.value, ".3g")
|
return format(self.value, ".5g")
|
||||||
else:
|
else:
|
||||||
return format(self.value)
|
return format(self.value)
|
||||||
|
|
||||||
@@ -176,66 +161,6 @@ class SliderField(Field):
|
|||||||
return list(self.possible_values)
|
return list(self.possible_values)
|
||||||
|
|
||||||
|
|
||||||
class AnimatedSliderField(SliderField):
|
|
||||||
def __init__(self, name: str, values: Iterable) -> None:
|
|
||||||
super().__init__(name, values)
|
|
||||||
self.timer = QtCore.QTimer()
|
|
||||||
self.timer.timeout.connect(self.step_forward)
|
|
||||||
|
|
||||||
self.play_button = QtWidgets.QPushButton("⏯")
|
|
||||||
self.play_button.clicked.connect(self.toggle)
|
|
||||||
self.play_button.setMaximumWidth(30)
|
|
||||||
self.playing = False
|
|
||||||
|
|
||||||
self.interval_field = QtWidgets.QLineEdit()
|
|
||||||
self.interval_field.setMaximumWidth(60)
|
|
||||||
# self.interval_field.setValidator(QtGui.QIntValidator(1, 5000))
|
|
||||||
self.interval_field.editingFinished.connect(self.set_interval)
|
|
||||||
self.interval_field.inputRejected.connect(self.set_interval)
|
|
||||||
self.interval = 16
|
|
||||||
self.set_interval()
|
|
||||||
|
|
||||||
self._layout.addWidget(self.play_button)
|
|
||||||
self._layout.addWidget(self.interval_field)
|
|
||||||
|
|
||||||
def toggle(self):
|
|
||||||
if self.playing:
|
|
||||||
self.stop()
|
|
||||||
self.playing = False
|
|
||||||
else:
|
|
||||||
self.play()
|
|
||||||
self.playing = True
|
|
||||||
|
|
||||||
def play(self):
|
|
||||||
if self.slider.value() == self._slider_max:
|
|
||||||
self.slider.setValue(0)
|
|
||||||
self.timer.start(self.interval)
|
|
||||||
self.play_button.setStyleSheet("QPushButton {background-color: #DEF2DD;}")
|
|
||||||
|
|
||||||
def stop(self):
|
|
||||||
self.timer.stop()
|
|
||||||
self.play_button.setStyleSheet("QPushButton {background-color: none;}")
|
|
||||||
|
|
||||||
def set_interval(self):
|
|
||||||
try:
|
|
||||||
self.interval = max(1, int(self.interval_field.text()))
|
|
||||||
except ValueError:
|
|
||||||
self.interval_field.setText(str(self.interval))
|
|
||||||
if self.interval < 16:
|
|
||||||
self.increment = int(np.ceil(16 / self.interval))
|
|
||||||
self.interval *= self.increment
|
|
||||||
else:
|
|
||||||
self.increment = 1
|
|
||||||
|
|
||||||
def step_forward(self):
|
|
||||||
current = self.slider.value()
|
|
||||||
if current + self.increment <= self._slider_max:
|
|
||||||
self.slider.setValue(current + self.increment)
|
|
||||||
else:
|
|
||||||
self.slider.setValue(self._slider_max)
|
|
||||||
self.stop()
|
|
||||||
|
|
||||||
|
|
||||||
class Plot:
|
class Plot:
|
||||||
name: str
|
name: str
|
||||||
dock: Dock
|
dock: Dock
|
||||||
@@ -511,11 +436,12 @@ class PlotApp:
|
|||||||
self.params_widget = QtWidgets.QWidget()
|
self.params_widget = QtWidgets.QWidget()
|
||||||
self.header_widget = QtWidgets.QWidget()
|
self.header_widget = QtWidgets.QWidget()
|
||||||
self.info_label = QtWidgets.QLabel()
|
self.info_label = QtWidgets.QLabel()
|
||||||
|
# self.info_label.setMaximumWidth(120)
|
||||||
self.window.setCentralWidget(self.central_widget)
|
self.window.setCentralWidget(self.central_widget)
|
||||||
|
|
||||||
self.central_layout = QtWidgets.QVBoxLayout()
|
self.central_layout = QtWidgets.QVBoxLayout()
|
||||||
self.params_layout = QtWidgets.QVBoxLayout()
|
self.params_layout = QtWidgets.QGridLayout()
|
||||||
self.header_layout = QtWidgets.QHBoxLayout()
|
self.header_layout = QtWidgets.QVBoxLayout()
|
||||||
|
|
||||||
_pl = QtWidgets.QSizePolicy.Policy.Preferred
|
_pl = QtWidgets.QSizePolicy.Policy.Preferred
|
||||||
info_sp = QtWidgets.QSizePolicy(_pl, _pl)
|
info_sp = QtWidgets.QSizePolicy(_pl, _pl)
|
||||||
@@ -540,10 +466,10 @@ class PlotApp:
|
|||||||
|
|
||||||
self.__ran = False
|
self.__ran = False
|
||||||
self.params = {}
|
self.params = {}
|
||||||
for p_name, values in params.items():
|
for i, (p_name, values) in enumerate(params.items()):
|
||||||
field = AnimatedSliderField(p_name, values)
|
field = SliderField(p_name, values)
|
||||||
self.params[p_name] = field
|
self.params[p_name] = field
|
||||||
self.params_layout.addWidget(field)
|
self.params_layout.addWidget(field, *divmod(i, 2))
|
||||||
|
|
||||||
def set_antialiasing(self, val: bool):
|
def set_antialiasing(self, val: bool):
|
||||||
pg.setConfigOptions(antialias=val)
|
pg.setConfigOptions(antialias=val)
|
||||||
|
|||||||
Reference in New Issue
Block a user