kopia lustrzana https://github.com/NanoVNA-Saver/nanovna-saver
Linting Charts
rodzic
d86cbec7c4
commit
8bc452d48f
|
@ -19,7 +19,7 @@
|
|||
import logging
|
||||
|
||||
from dataclasses import dataclass, replace
|
||||
from typing import List, Set, Tuple, ClassVar, Any
|
||||
from typing import List, Set, Tuple, ClassVar, Any, Optional
|
||||
|
||||
from PyQt5 import QtWidgets, QtGui, QtCore
|
||||
from PyQt5.QtCore import pyqtSignal
|
||||
|
@ -37,12 +37,13 @@ class ChartColors: # pylint: disable=too-many-instance-attributes
|
|||
foreground: QtGui.QColor = QtGui.QColor(QtCore.Qt.lightGray)
|
||||
reference: QtGui.QColor = QtGui.QColor(0, 0, 255, 64)
|
||||
reference_secondary: QtGui.QColor = QtGui.QColor(0, 0, 192, 48)
|
||||
sweep: QtGui.QColor = QtGui.QColor(QtCore.Qt.darkYellow)
|
||||
sweep: QtGui.QColor = QtGui.QColor(QtCore.Qt.darkYellow)
|
||||
sweep_secondary: QtGui.QColor = QtGui.QColor(QtCore.Qt.darkMagenta)
|
||||
swr: QtGui.QColor = QtGui.QColor(255, 0, 0, 128)
|
||||
text: QtGui.QColor = QtGui.QColor(QtCore.Qt.black)
|
||||
bands: QtGui.QColor = QtGui.QColor(128, 128, 128, 48)
|
||||
|
||||
|
||||
@dataclass
|
||||
class ChartDimensions:
|
||||
height: int = 200
|
||||
|
@ -52,14 +53,16 @@ class ChartDimensions:
|
|||
line: int = 1
|
||||
point: int = 2
|
||||
|
||||
|
||||
@dataclass
|
||||
class ChartDragBox:
|
||||
pos: Tuple[int] = (-1, -1)
|
||||
pos: Tuple[int] = (-1, -1)
|
||||
pos_start: Tuple[int] = (0, 0)
|
||||
state: bool = False
|
||||
move_x: int = -1
|
||||
move_y: int = -1
|
||||
|
||||
|
||||
@dataclass
|
||||
class ChartFlags:
|
||||
draw_lines: bool = False
|
||||
|
@ -121,7 +124,8 @@ class Chart(QtWidgets.QWidget):
|
|||
self.swrMarkers: Set[float] = set()
|
||||
|
||||
self.action_popout = QtWidgets.QAction("Popout chart")
|
||||
self.action_popout.triggered.connect(lambda: self.popoutRequested.emit(self))
|
||||
self.action_popout.triggered.connect(
|
||||
lambda: self.popoutRequested.emit(self))
|
||||
self.addAction(self.action_popout)
|
||||
|
||||
self.action_save_screenshot = QtWidgets.QAction("Save image")
|
||||
|
@ -176,8 +180,8 @@ class Chart(QtWidgets.QWidget):
|
|||
None,
|
||||
)
|
||||
|
||||
def getNearestMarker(self, x, y) -> Marker:
|
||||
if len(self.data) == 0:
|
||||
def getNearestMarker(self, x, y) -> Optional[Marker]:
|
||||
if not self.data:
|
||||
return None
|
||||
shortest = 10**6
|
||||
nearest = None
|
||||
|
@ -218,13 +222,13 @@ class Chart(QtWidgets.QWidget):
|
|||
def mouseReleaseEvent(self, a0: QtGui.QMouseEvent):
|
||||
self.draggedMarker = None
|
||||
if self.dragbox.state:
|
||||
self.zoomTo(self.dragbox.pos_start[0], self.dragbox.pos_start[1], a0.x(), a0.y())
|
||||
self.zoomTo(
|
||||
self.dragbox.pos_start[0], self.dragbox.pos_start[1], a0.x(), a0.y())
|
||||
self.dragbox.state = False
|
||||
self.dragbox.pos = (-1, -1)
|
||||
self.dragbox.pos_start = (0, 0)
|
||||
self.update()
|
||||
|
||||
|
||||
def wheelEvent(self, a0: QtGui.QWheelEvent) -> None:
|
||||
delta = a0.angleDelta().y()
|
||||
if not delta or (not self.data and not self.reference):
|
||||
|
@ -305,7 +309,7 @@ class Chart(QtWidgets.QWidget):
|
|||
@staticmethod
|
||||
def drawMarker(x: int, y: int,
|
||||
qp: QtGui.QPainter, color: QtGui.QColor,
|
||||
number: int=0):
|
||||
number: int = 0):
|
||||
cmarker = ChartMarker(qp)
|
||||
cmarker.draw(x, y, color, f"{number}")
|
||||
|
||||
|
@ -314,7 +318,7 @@ class Chart(QtWidgets.QWidget):
|
|||
if position is None:
|
||||
qf = QtGui.QFontMetricsF(self.font())
|
||||
width = qf.boundingRect(self.sweepTitle).width()
|
||||
position = QtCore.QPointF(self.width()/2 - width/2, 15)
|
||||
position = QtCore.QPointF(self.width() / 2 - width / 2, 15)
|
||||
qp.drawText(position, self.sweepTitle)
|
||||
|
||||
def update(self):
|
||||
|
|
|
@ -236,8 +236,7 @@ class FrequencyChart(Chart):
|
|||
self.logarithmicY = logarithmic and self.logarithmicYAllowed()
|
||||
self.update()
|
||||
|
||||
@staticmethod
|
||||
def logarithmicYAllowed() -> bool:
|
||||
def logarithmicYAllowed(self) -> bool:
|
||||
return False
|
||||
|
||||
def setMinimumFrequency(self):
|
||||
|
|
|
@ -88,8 +88,8 @@ class GroupDelayChart(FrequencyChart):
|
|||
phase_change = unwrapped[-1] - unwrapped[-2]
|
||||
freq_change = d.freq - data[-2].freq
|
||||
else:
|
||||
phase_change = unwrapped[i+1] - unwrapped[i-1]
|
||||
freq_change = data[i+1].freq - data[i-1].freq
|
||||
phase_change = unwrapped[i + 1] - unwrapped[i - 1]
|
||||
freq_change = data[i + 1].freq - data[i - 1].freq
|
||||
delay = (-phase_change / (freq_change * 360)) * 10e8
|
||||
if not self.reflective:
|
||||
delay /= 2
|
||||
|
@ -124,7 +124,8 @@ class GroupDelayChart(FrequencyChart):
|
|||
tickcount = math.floor(self.dim.height / 60)
|
||||
for i in range(tickcount):
|
||||
delay = min_delay + span * i / tickcount
|
||||
y = self.topMargin + round((self.maxDelay - delay) / self.span * self.dim.height)
|
||||
y = self.topMargin + \
|
||||
round((self.maxDelay - delay) / self.span * self.dim.height)
|
||||
if delay not in {min_delay, max_delay}:
|
||||
qp.setPen(QtGui.QPen(Chart.color.text))
|
||||
# TODO use format class
|
||||
|
@ -133,7 +134,8 @@ class GroupDelayChart(FrequencyChart):
|
|||
delaystr = str(round(delay, digits if digits != 0 else None))
|
||||
qp.drawText(3, y + 3, delaystr)
|
||||
qp.setPen(QtGui.QPen(Chart.color.foreground))
|
||||
qp.drawLine(self.leftMargin - 5, y, self.leftMargin + self.dim.width, y)
|
||||
qp.drawLine(self.leftMargin - 5, y,
|
||||
self.leftMargin + self.dim.width, y)
|
||||
|
||||
qp.drawLine(self.leftMargin - 5,
|
||||
self.topMargin,
|
||||
|
|
|
@ -160,8 +160,8 @@ class LogMagChart(FrequencyChart):
|
|||
def getYPosition(self, d: Datapoint) -> int:
|
||||
logMag = self.logMag(d)
|
||||
if math.isinf(logMag):
|
||||
return None
|
||||
return self.topMargin + round(
|
||||
return self.topMargin
|
||||
return self.topMargin + int(
|
||||
(self.maxValue - logMag) / self.span * self.dim.height)
|
||||
|
||||
def valueAtPosition(self, y) -> List[float]:
|
||||
|
|
|
@ -33,18 +33,15 @@ class MagnitudeChart(FrequencyChart):
|
|||
super().__init__(name)
|
||||
|
||||
self.minDisplayValue = 0
|
||||
self.maxDisplayValue = 1
|
||||
|
||||
self.fixedValues = True
|
||||
self.y_action_fixed_span.setChecked(True)
|
||||
self.y_action_automatic.setChecked(False)
|
||||
|
||||
self.minValue = 0
|
||||
self.maxValue = 1
|
||||
self.span = 1
|
||||
|
||||
def drawValues(self, qp: QtGui.QPainter):
|
||||
if len(self.data) == 0 and len(self.reference) == 0:
|
||||
if not self.data and not self.reference:
|
||||
return
|
||||
|
||||
self._set_start_stop()
|
||||
|
@ -54,71 +51,62 @@ class MagnitudeChart(FrequencyChart):
|
|||
self.drawBands(qp, self.fstart, self.fstop)
|
||||
|
||||
if self.fixedValues:
|
||||
maxValue = self.maxDisplayValue
|
||||
minValue = self.minDisplayValue
|
||||
self.maxValue = maxValue
|
||||
self.minValue = minValue
|
||||
max_value = self.maxDisplayValue
|
||||
min_value = self.minDisplayValue
|
||||
else:
|
||||
# Find scaling
|
||||
minValue = 100
|
||||
maxValue = 0
|
||||
min_value = 100
|
||||
max_value = 0
|
||||
for d in self.data:
|
||||
mag = self.magnitude(d)
|
||||
if mag > maxValue:
|
||||
maxValue = mag
|
||||
if mag < minValue:
|
||||
minValue = mag
|
||||
max_value = max(max_value, mag)
|
||||
min_value = min(min_value, mag)
|
||||
for d in self.reference: # Also check min/max for the reference sweep
|
||||
if d.freq < self.fstart or d.freq > self.fstop:
|
||||
continue
|
||||
mag = self.magnitude(d)
|
||||
if mag > maxValue:
|
||||
maxValue = mag
|
||||
if mag < minValue:
|
||||
minValue = mag
|
||||
max_value = max(max_value, mag)
|
||||
min_value = min(min_value, mag)
|
||||
min_value = 10 * math.floor(min_value / 10)
|
||||
max_value = 10 * math.ceil(max_value / 10)
|
||||
|
||||
minValue = 10*math.floor(minValue/10)
|
||||
self.minValue = minValue
|
||||
maxValue = 10*math.ceil(maxValue/10)
|
||||
self.maxValue = maxValue
|
||||
self.maxValue = max_value
|
||||
self.minValue = min_value
|
||||
|
||||
span = maxValue-minValue
|
||||
if span == 0:
|
||||
span = 0.01
|
||||
self.span = span
|
||||
|
||||
target_ticks = math.floor(self.dim.height / 60)
|
||||
self.span = (max_value - min_value) or 0.01
|
||||
|
||||
target_ticks = int(self.dim.height // 60)
|
||||
for i in range(target_ticks):
|
||||
val = minValue + i / target_ticks * span
|
||||
y = self.topMargin + round((self.maxValue - val) / self.span * self.dim.height)
|
||||
val = min_value + i / target_ticks * self.span
|
||||
y = self.topMargin + int((self.maxValue - val) / self.span
|
||||
* self.dim.height)
|
||||
qp.setPen(Chart.color.text)
|
||||
if val != minValue:
|
||||
if val != min_value:
|
||||
digits = max(0, min(2, math.floor(3 - math.log10(abs(val)))))
|
||||
if digits == 0:
|
||||
vswrstr = str(round(val))
|
||||
else:
|
||||
vswrstr = str(round(val, digits))
|
||||
vswrstr = (str(round(val)) if digits == 0 else
|
||||
str(round(val, digits)))
|
||||
qp.drawText(3, y + 3, vswrstr)
|
||||
qp.setPen(QtGui.QPen(Chart.color.foreground))
|
||||
qp.drawLine(self.leftMargin - 5, y, self.leftMargin + self.dim.width, y)
|
||||
qp.drawLine(self.leftMargin - 5, y,
|
||||
self.leftMargin + self.dim.width, y)
|
||||
|
||||
qp.setPen(QtGui.QPen(Chart.color.foreground))
|
||||
qp.drawLine(self.leftMargin - 5, self.topMargin,
|
||||
self.leftMargin + self.dim.width, self.topMargin)
|
||||
qp.setPen(Chart.color.text)
|
||||
qp.drawText(3, self.topMargin + 4, str(maxValue))
|
||||
qp.drawText(3, self.dim.height+self.topMargin, str(minValue))
|
||||
qp.drawText(3, self.topMargin + 4, str(max_value))
|
||||
qp.drawText(3, self.dim.height + self.topMargin, str(min_value))
|
||||
self.drawFrequencyTicks(qp)
|
||||
|
||||
qp.setPen(Chart.color.swr)
|
||||
for vswr in self.swrMarkers:
|
||||
if vswr <= 1:
|
||||
continue
|
||||
mag = (vswr-1)/(vswr+1)
|
||||
y = self.topMargin + round((self.maxValue - mag) / self.span * self.dim.height)
|
||||
qp.drawLine(self.leftMargin, y, self.leftMargin + self.dim.width, y)
|
||||
qp.drawText(self.leftMargin + 3, y - 1, "VSWR: " + str(vswr))
|
||||
mag = (vswr - 1) / (vswr + 1)
|
||||
y = self.topMargin + int((self.maxValue - mag) / self.span
|
||||
* self.dim.height)
|
||||
qp.drawLine(self.leftMargin, y,
|
||||
self.leftMargin + self.dim.width, y)
|
||||
qp.drawText(self.leftMargin + 3, y - 1, f"VSWR: {vswr}")
|
||||
|
||||
self.drawData(qp, self.data, Chart.color.sweep)
|
||||
self.drawData(qp, self.reference, Chart.color.reference)
|
||||
|
|
|
@ -45,7 +45,7 @@ class MagnitudeZChart(FrequencyChart):
|
|||
self.span = 1
|
||||
|
||||
def drawValues(self, qp: QtGui.QPainter):
|
||||
if len(self.data) == 0 and len(self.reference) == 0:
|
||||
if not self.data and not self.reference:
|
||||
return
|
||||
|
||||
self._set_start_stop()
|
||||
|
@ -56,8 +56,9 @@ class MagnitudeZChart(FrequencyChart):
|
|||
|
||||
if self.fixedValues:
|
||||
self.maxValue = self.maxDisplayValue
|
||||
self.minValue = max(
|
||||
self.minDisplayValue, 0.01) if self.logarithmicY else self.minDisplayValue
|
||||
self.minValue = (
|
||||
max(self.minDisplayValue, 0.01) if self.logarithmicY else
|
||||
self.minDisplayValue)
|
||||
else:
|
||||
# Find scaling
|
||||
self.minValue = 100
|
||||
|
@ -85,7 +86,7 @@ class MagnitudeZChart(FrequencyChart):
|
|||
self.span = (self.maxValue - self.minValue) or 0.01
|
||||
|
||||
# We want one horizontal tick per 50 pixels, at most
|
||||
horizontal_ticks = math.floor(self.dim.height/50)
|
||||
horizontal_ticks = int(self.dim.height / 50)
|
||||
fmt = Format(max_nr_digits=4)
|
||||
for i in range(horizontal_ticks):
|
||||
y = self.topMargin + round(i * self.dim.height / horizontal_ticks)
|
||||
|
@ -122,7 +123,8 @@ class MagnitudeZChart(FrequencyChart):
|
|||
absy = y - self.topMargin
|
||||
if self.logarithmicY:
|
||||
span = math.log(self.maxValue) - math.log(self.minValue)
|
||||
val = math.exp(math.log(self.maxValue) - absy * span / self.dim.height)
|
||||
val = math.exp(math.log(self.maxValue) -
|
||||
absy * span / self.dim.height)
|
||||
else:
|
||||
val = self.maxValue - (absy / self.dim.height * self.span)
|
||||
return [val]
|
||||
|
|
|
@ -48,9 +48,6 @@ class PermeabilityChart(FrequencyChart):
|
|||
def logarithmicYAllowed(self) -> bool:
|
||||
return True
|
||||
|
||||
def copy(self):
|
||||
return super().copy()
|
||||
|
||||
def drawChart(self, qp: QtGui.QPainter):
|
||||
qp.setPen(QtGui.QPen(Chart.color.text))
|
||||
qp.drawText(self.leftMargin + 5, 15, self.name +
|
||||
|
@ -58,15 +55,20 @@ class PermeabilityChart(FrequencyChart):
|
|||
qp.drawText(10, 15, "R")
|
||||
qp.drawText(self.leftMargin + self.dim.width + 10, 15, "X")
|
||||
qp.setPen(QtGui.QPen(Chart.color.foreground))
|
||||
qp.drawLine(self.leftMargin, self.topMargin - 5,
|
||||
self.leftMargin, self.topMargin + self.dim.height + 5)
|
||||
qp.drawLine(self.leftMargin-5, self.topMargin + self.dim.height,
|
||||
self.leftMargin + self.dim.width + 5, self.topMargin + self.dim.height)
|
||||
qp.drawLine(self.leftMargin,
|
||||
self.topMargin - 5,
|
||||
self.leftMargin,
|
||||
self.topMargin + self.dim.height + 5)
|
||||
qp.drawLine(self.leftMargin - 5,
|
||||
self.topMargin + self.dim.height,
|
||||
self.leftMargin + self.dim.width + 5,
|
||||
self.topMargin + self.dim.height)
|
||||
self.drawTitle(qp)
|
||||
|
||||
def drawValues(self, qp: QtGui.QPainter):
|
||||
if len(self.data) == 0 and len(self.reference) == 0:
|
||||
if not self.data and not self.reference:
|
||||
return
|
||||
|
||||
pen = QtGui.QPen(Chart.color.sweep)
|
||||
pen.setWidth(self.dim.point)
|
||||
line_pen = QtGui.QPen(Chart.color.sweep)
|
||||
|
@ -90,14 +92,10 @@ class PermeabilityChart(FrequencyChart):
|
|||
re, im = imp.real, imp.imag
|
||||
re = re * 10e6 / d.freq
|
||||
im = im * 10e6 / d.freq
|
||||
if re > max_val:
|
||||
max_val = re
|
||||
if re < min_val:
|
||||
min_val = re
|
||||
if im > max_val:
|
||||
max_val = im
|
||||
if im < min_val:
|
||||
min_val = im
|
||||
max_val = max(max_val, re)
|
||||
max_val = max(max_val, im)
|
||||
min_val = min(min_val, re)
|
||||
min_val = min(min_val, im)
|
||||
for d in self.reference: # Also check min/max for the reference sweep
|
||||
if d.freq < self.fstart or d.freq > self.fstop:
|
||||
continue
|
||||
|
@ -105,27 +103,19 @@ class PermeabilityChart(FrequencyChart):
|
|||
re, im = imp.real, imp.imag
|
||||
re = re * 10e6 / d.freq
|
||||
im = im * 10e6 / d.freq
|
||||
if re > max_val:
|
||||
max_val = re
|
||||
if re < min_val:
|
||||
min_val = re
|
||||
if im > max_val:
|
||||
max_val = im
|
||||
if im < min_val:
|
||||
min_val = im
|
||||
max_val = max(max_val, re)
|
||||
max_val = max(max_val, im)
|
||||
min_val = min(min_val, re)
|
||||
min_val = min(min_val, im)
|
||||
|
||||
if self.logarithmicY:
|
||||
min_val = max(0.01, min_val)
|
||||
|
||||
self.max = max_val
|
||||
|
||||
span = max_val - min_val
|
||||
if span == 0:
|
||||
span = 0.01
|
||||
self.span = span
|
||||
self.span = (max_val - min_val) or 0.01
|
||||
|
||||
# We want one horizontal tick per 50 pixels, at most
|
||||
horizontal_ticks = math.floor(self.dim.height/50)
|
||||
horizontal_ticks = math.floor(self.dim.height / 50)
|
||||
fmt = Format(max_nr_digits=4)
|
||||
for i in range(horizontal_ticks):
|
||||
y = self.topMargin + round(i * self.dim.height / horizontal_ticks)
|
||||
|
@ -163,10 +153,10 @@ class PermeabilityChart(FrequencyChart):
|
|||
secondary_pen.setWidth(self.dim.point)
|
||||
line_pen.setWidth(self.dim.line)
|
||||
|
||||
for i in range(len(self.data)):
|
||||
x = self.getXPosition(self.data[i])
|
||||
y_re = self.getReYPosition(self.data[i])
|
||||
y_im = self.getImYPosition(self.data[i])
|
||||
for i, data in enumerate(self.data):
|
||||
x = self.getXPosition(data)
|
||||
y_re = self.getReYPosition(data)
|
||||
y_im = self.getImYPosition(data)
|
||||
qp.setPen(primary_pen)
|
||||
if self.isPlotable(x, y_re):
|
||||
qp.drawPoint(x, y_re)
|
||||
|
@ -175,8 +165,8 @@ class PermeabilityChart(FrequencyChart):
|
|||
qp.drawPoint(x, y_im)
|
||||
if self.flag.draw_lines and i > 0:
|
||||
prev_x = self.getXPosition(self.data[i - 1])
|
||||
prev_y_re = self.getReYPosition(self.data[i-1])
|
||||
prev_y_im = self.getImYPosition(self.data[i-1])
|
||||
prev_y_re = self.getReYPosition(self.data[i - 1])
|
||||
prev_y_im = self.getImYPosition(self.data[i - 1])
|
||||
|
||||
# Real part first
|
||||
line_pen.setColor(Chart.color.sweep)
|
||||
|
@ -221,12 +211,12 @@ class PermeabilityChart(FrequencyChart):
|
|||
qp.drawLine(self.leftMargin + self.dim.width, 14,
|
||||
self.leftMargin + self.dim.width + 5, 14)
|
||||
|
||||
for i in range(len(self.reference)):
|
||||
if self.reference[i].freq < self.fstart or self.reference[i].freq > self.fstop:
|
||||
for i, reference in enumerate(self.reference):
|
||||
if reference.freq < self.fstart or reference.freq > self.fstop:
|
||||
continue
|
||||
x = self.getXPosition(self.reference[i])
|
||||
y_re = self.getReYPosition(self.reference[i])
|
||||
y_im = self.getImYPosition(self.reference[i])
|
||||
x = self.getXPosition(reference)
|
||||
y_re = self.getReYPosition(reference)
|
||||
y_im = self.getImYPosition(reference)
|
||||
qp.setPen(primary_pen)
|
||||
if self.isPlotable(x, y_re):
|
||||
qp.drawPoint(x, y_re)
|
||||
|
@ -235,8 +225,8 @@ class PermeabilityChart(FrequencyChart):
|
|||
qp.drawPoint(x, y_im)
|
||||
if self.flag.draw_lines and i > 0:
|
||||
prev_x = self.getXPosition(self.reference[i - 1])
|
||||
prev_y_re = self.getReYPosition(self.reference[i-1])
|
||||
prev_y_im = self.getImYPosition(self.reference[i-1])
|
||||
prev_y_re = self.getReYPosition(self.reference[i - 1])
|
||||
prev_y_im = self.getImYPosition(self.reference[i - 1])
|
||||
|
||||
line_pen.setColor(Chart.color.reference)
|
||||
qp.setPen(line_pen)
|
||||
|
@ -269,8 +259,10 @@ class PermeabilityChart(FrequencyChart):
|
|||
y_re = self.getReYPosition(self.data[m.location])
|
||||
y_im = self.getImYPosition(self.data[m.location])
|
||||
|
||||
self.drawMarker(x, y_re, qp, m.color, self.markers.index(m)+1)
|
||||
self.drawMarker(x, y_im, qp, m.color, self.markers.index(m)+1)
|
||||
self.drawMarker(x, y_re, qp, m.color,
|
||||
self.markers.index(m) + 1)
|
||||
self.drawMarker(x, y_im, qp, m.color,
|
||||
self.markers.index(m) + 1)
|
||||
|
||||
def getImYPosition(self, d: Datapoint) -> int:
|
||||
im = d.impedance().imag
|
||||
|
@ -326,7 +318,7 @@ class PermeabilityChart(FrequencyChart):
|
|||
myr = self.getReYPosition(self.data[m.location])
|
||||
myi = self.getImYPosition(self.data[m.location])
|
||||
dx = abs(x - mx)
|
||||
dy = min(abs(y - myr), abs(y-myi))
|
||||
dy = min(abs(y - myr), abs(y - myi))
|
||||
distance = math.sqrt(dx**2 + dy**2)
|
||||
if distance < shortest:
|
||||
shortest = distance
|
||||
|
|
|
@ -49,19 +49,17 @@ class QualityFactorChart(FrequencyChart):
|
|||
# Make up some sensible scaling here
|
||||
if self.fixedValues:
|
||||
maxQ = self.maxDisplayValue
|
||||
minQ = self.minDisplayValue
|
||||
else:
|
||||
minQ = 0
|
||||
maxQ = 0
|
||||
for d in self.data:
|
||||
Q = d.qFactor()
|
||||
if Q > maxQ:
|
||||
maxQ = Q
|
||||
maxQ = max(maxQ, Q)
|
||||
scale = 0
|
||||
if maxQ > 0:
|
||||
scale = max(scale, math.floor(math.log10(maxQ)))
|
||||
maxQ = math.ceil(maxQ / 10 ** scale) * 10 ** scale
|
||||
self.minQ = minQ
|
||||
|
||||
self.minQ = self.minDisplayValue
|
||||
self.maxQ = maxQ
|
||||
self.span = self.maxQ - self.minQ
|
||||
if self.span == 0:
|
||||
|
@ -71,28 +69,30 @@ class QualityFactorChart(FrequencyChart):
|
|||
|
||||
for i in range(tickcount):
|
||||
q = self.minQ + i * self.span / tickcount
|
||||
y = self.topMargin + round((self.maxQ - q) / self.span * self.dim.height)
|
||||
y = self.topMargin + int((self.maxQ - q) / self.span *
|
||||
self.dim.height)
|
||||
q = round(q)
|
||||
if q < 10:
|
||||
q = round(q, 2)
|
||||
elif q < 20:
|
||||
if q < 20:
|
||||
q = round(q, 1)
|
||||
else:
|
||||
q = round(q)
|
||||
qp.setPen(QtGui.QPen(Chart.color.text))
|
||||
qp.drawText(3, y+3, str(q))
|
||||
qp.drawText(3, y + 3, str(q))
|
||||
qp.setPen(QtGui.QPen(Chart.color.foreground))
|
||||
qp.drawLine(self.leftMargin-5, y, self.leftMargin + self.dim.width, y)
|
||||
qp.drawLine(self.leftMargin - 5, y,
|
||||
self.leftMargin + self.dim.width, y)
|
||||
qp.drawLine(self.leftMargin - 5,
|
||||
self.topMargin,
|
||||
self.leftMargin + self.dim.width, self.topMargin)
|
||||
self.leftMargin + self.dim.width,
|
||||
self.topMargin)
|
||||
qp.setPen(Chart.color.text)
|
||||
|
||||
max_q = round(maxQ)
|
||||
if maxQ < 10:
|
||||
qstr = str(round(maxQ, 2))
|
||||
max_q = round(maxQ, 2)
|
||||
elif maxQ < 20:
|
||||
qstr = str(round(maxQ, 1))
|
||||
else:
|
||||
qstr = str(round(maxQ))
|
||||
qp.drawText(3, 35, qstr)
|
||||
max_q = round(maxQ, 1)
|
||||
qp.drawText(3, 35, f"{max_q}")
|
||||
|
||||
def drawValues(self, qp: QtGui.QPainter):
|
||||
if len(self.data) == 0 and len(self.reference) == 0:
|
||||
|
@ -119,7 +119,8 @@ class QualityFactorChart(FrequencyChart):
|
|||
|
||||
def getYPosition(self, d: Datapoint) -> int:
|
||||
Q = d.qFactor()
|
||||
return self.topMargin + round((self.maxQ - Q) / self.span * self.dim.height)
|
||||
return self.topMargin + int((self.maxQ - Q) / self.span *
|
||||
self.dim.height)
|
||||
|
||||
def valueAtPosition(self, y) -> List[float]:
|
||||
absy = y - self.topMargin
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
import math
|
||||
import logging
|
||||
from typing import List
|
||||
from typing import List, Optional
|
||||
|
||||
from PyQt5 import QtWidgets, QtGui
|
||||
|
||||
|
@ -120,7 +120,7 @@ class RealImaginaryChart(FrequencyChart):
|
|||
self.topMargin - 5,
|
||||
self.leftMargin,
|
||||
self.topMargin + self.dim.height + 5)
|
||||
qp.drawLine(self.leftMargin-5,
|
||||
qp.drawLine(self.leftMargin - 5,
|
||||
self.topMargin + self.dim.height,
|
||||
self.leftMargin + self.dim.width + 5,
|
||||
self.topMargin + self.dim.height)
|
||||
|
@ -195,13 +195,13 @@ class RealImaginaryChart(FrequencyChart):
|
|||
step_size = span / 8
|
||||
if max_imag < step_size:
|
||||
# The 0 line is the first step after the top. Scale accordingly.
|
||||
max_imag = -min_imag/7
|
||||
max_imag = -min_imag / 7
|
||||
elif -min_imag < step_size:
|
||||
# The 0 line is the last step before the bottom. Scale accordingly.
|
||||
min_imag = -max_imag/7
|
||||
min_imag = -max_imag / 7
|
||||
else:
|
||||
# Scale max_imag to be a whole factor of min_imag
|
||||
num_min = math.floor(min_imag/step_size * -1)
|
||||
num_min = math.floor(min_imag / step_size * -1)
|
||||
num_max = 8 - num_min
|
||||
max_imag = num_max * (min_imag / num_min) * -1
|
||||
|
||||
|
@ -257,10 +257,10 @@ class RealImaginaryChart(FrequencyChart):
|
|||
secondary_pen.setWidth(self.dim.point)
|
||||
line_pen.setWidth(self.dim.line)
|
||||
|
||||
for i in range(len(self.data)):
|
||||
x = self.getXPosition(self.data[i])
|
||||
y_re = self.getReYPosition(self.data[i])
|
||||
y_im = self.getImYPosition(self.data[i])
|
||||
for i, data in enumerate(self.data):
|
||||
x = self.getXPosition(data)
|
||||
y_re = self.getReYPosition(data)
|
||||
y_im = self.getImYPosition(data)
|
||||
qp.setPen(primary_pen)
|
||||
if self.isPlotable(x, y_re):
|
||||
qp.drawPoint(x, y_re)
|
||||
|
@ -269,8 +269,8 @@ class RealImaginaryChart(FrequencyChart):
|
|||
qp.drawPoint(x, y_im)
|
||||
if self.flag.draw_lines and i > 0:
|
||||
prev_x = self.getXPosition(self.data[i - 1])
|
||||
prev_y_re = self.getReYPosition(self.data[i-1])
|
||||
prev_y_im = self.getImYPosition(self.data[i-1])
|
||||
prev_y_re = self.getReYPosition(self.data[i - 1])
|
||||
prev_y_im = self.getImYPosition(self.data[i - 1])
|
||||
|
||||
# Real part first
|
||||
line_pen.setColor(Chart.color.sweep)
|
||||
|
@ -315,12 +315,12 @@ class RealImaginaryChart(FrequencyChart):
|
|||
qp.drawLine(self.leftMargin + self.dim.width, 14,
|
||||
self.leftMargin + self.dim.width + 5, 14)
|
||||
|
||||
for i in range(len(self.reference)):
|
||||
if self.reference[i].freq < self.fstart or self.reference[i].freq > self.fstop:
|
||||
for i, reference in enumerate(self.reference):
|
||||
if reference.freq < self.fstart or reference.freq > self.fstop:
|
||||
continue
|
||||
x = self.getXPosition(self.reference[i])
|
||||
y_re = self.getReYPosition(self.reference[i])
|
||||
y_im = self.getImYPosition(self.reference[i])
|
||||
x = self.getXPosition(reference)
|
||||
y_re = self.getReYPosition(reference)
|
||||
y_im = self.getImYPosition(reference)
|
||||
qp.setPen(primary_pen)
|
||||
if self.isPlotable(x, y_re):
|
||||
qp.drawPoint(x, y_re)
|
||||
|
@ -329,8 +329,8 @@ class RealImaginaryChart(FrequencyChart):
|
|||
qp.drawPoint(x, y_im)
|
||||
if self.flag.draw_lines and i > 0:
|
||||
prev_x = self.getXPosition(self.reference[i - 1])
|
||||
prev_y_re = self.getReYPosition(self.reference[i-1])
|
||||
prev_y_im = self.getImYPosition(self.reference[i-1])
|
||||
prev_y_re = self.getReYPosition(self.reference[i - 1])
|
||||
prev_y_im = self.getImYPosition(self.reference[i - 1])
|
||||
|
||||
line_pen.setColor(Chart.color.reference)
|
||||
qp.setPen(line_pen)
|
||||
|
@ -363,8 +363,10 @@ class RealImaginaryChart(FrequencyChart):
|
|||
y_re = self.getReYPosition(self.data[m.location])
|
||||
y_im = self.getImYPosition(self.data[m.location])
|
||||
|
||||
self.drawMarker(x, y_re, qp, m.color, self.markers.index(m)+1)
|
||||
self.drawMarker(x, y_im, qp, m.color, self.markers.index(m)+1)
|
||||
self.drawMarker(x, y_re, qp, m.color,
|
||||
self.markers.index(m) + 1)
|
||||
self.drawMarker(x, y_im, qp, m.color,
|
||||
self.markers.index(m) + 1)
|
||||
|
||||
def getImYPosition(self, d: Datapoint) -> int:
|
||||
im = self.impedance(d).imag
|
||||
|
@ -405,17 +407,17 @@ class RealImaginaryChart(FrequencyChart):
|
|||
|
||||
self.update()
|
||||
|
||||
def getNearestMarker(self, x, y) -> Marker:
|
||||
if len(self.data) == 0:
|
||||
def getNearestMarker(self, x, y) -> Optional[Marker]:
|
||||
if not self.data:
|
||||
return None
|
||||
shortest = 10**6
|
||||
shortest = 10e6
|
||||
nearest = None
|
||||
for m in self.markers:
|
||||
mx, _ = self.getPosition(self.data[m.location])
|
||||
myr = self.getReYPosition(self.data[m.location])
|
||||
myi = self.getImYPosition(self.data[m.location])
|
||||
dx = abs(x - mx)
|
||||
dy = min(abs(y - myr), abs(y-myi))
|
||||
dy = min(abs(y - myr), abs(y - myi))
|
||||
distance = math.sqrt(dx**2 + dy**2)
|
||||
if distance < shortest:
|
||||
shortest = distance
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
import math
|
||||
import logging
|
||||
from typing import List
|
||||
|
||||
|
@ -54,7 +53,7 @@ class SParameterChart(FrequencyChart):
|
|||
qp.drawText(self.leftMargin + self.dim.width - 15, 15, "Imag")
|
||||
qp.setPen(QtGui.QPen(Chart.color.foreground))
|
||||
qp.drawLine(self.leftMargin, self.topMargin - 5,
|
||||
self.leftMargin, self.topMargin + self.dim.height+5)
|
||||
self.leftMargin, self.topMargin + self.dim.height + 5)
|
||||
qp.drawLine(self.leftMargin - 5, self.topMargin + self.dim.height,
|
||||
self.leftMargin + self.dim.width, self.topMargin + self.dim.height)
|
||||
|
||||
|
|
|
@ -20,8 +20,7 @@ import logging
|
|||
import math
|
||||
from typing import List
|
||||
|
||||
from PyQt5 import QtGui, QtCore
|
||||
from PyQt5 import QtWidgets, QtGui
|
||||
from PyQt5 import QtGui, QtCore, QtWidgets
|
||||
|
||||
from NanoVNASaver.Charts.Chart import Chart
|
||||
from NanoVNASaver.RFTools import Datapoint
|
||||
|
@ -55,7 +54,7 @@ class SquareChart(Chart):
|
|||
raise NotImplementedError()
|
||||
|
||||
def draw_data(self, qp: QtGui.QPainter, color: QtGui.QColor,
|
||||
data: List[Datapoint], fstart: int=0, fstop: int=0):
|
||||
data: List[Datapoint], fstart: int = 0, fstop: int = 0):
|
||||
if not data:
|
||||
return
|
||||
fstop = fstop or data[-1].freq
|
||||
|
@ -66,10 +65,11 @@ class SquareChart(Chart):
|
|||
|
||||
qp.setPen(pen)
|
||||
prev_x = self.getXPosition(data[0])
|
||||
prev_y = int(self.height() / 2 + data[0].im * -1 * self.dim.height / 2)
|
||||
prev_y = int(self.height() / 2 + data[0].im * -1 *
|
||||
self.dim.height / 2)
|
||||
for i, d in enumerate(data):
|
||||
x = self.getXPosition(d)
|
||||
y = int(self.height()/2 + d.im * -1 * self.dim.height/2)
|
||||
y = int(self.height() / 2 + d.im * -1 * self.dim.height / 2)
|
||||
if d.freq > fstart and d.freq < fstop:
|
||||
qp.drawPoint(x, y)
|
||||
if self.flag.draw_lines and i > 0:
|
||||
|
@ -85,19 +85,21 @@ class SquareChart(Chart):
|
|||
|
||||
fstart = self.data[0].freq if self.data else 0
|
||||
fstop = self.data[-1].freq if self.data else 0
|
||||
self.draw_data(qp, Chart.color.reference, self.reference, fstart, fstop)
|
||||
self.draw_data(qp, Chart.color.reference,
|
||||
self.reference, fstart, fstop)
|
||||
|
||||
for m in self.markers:
|
||||
if m.location != -1 and m.location < len(self.data):
|
||||
x = self.getXPosition(self.data[m.location])
|
||||
y = self.height() / 2 + self.data[m.location].im * -1 * self.dim.height / 2
|
||||
self.drawMarker(x, y, qp, m.color, self.markers.index(m)+1)
|
||||
y = self.height() / 2 + \
|
||||
self.data[m.location].im * -1 * self.dim.height / 2
|
||||
self.drawMarker(x, y, qp, m.color, self.markers.index(m) + 1)
|
||||
|
||||
def resizeEvent(self, a0: QtGui.QResizeEvent) -> None:
|
||||
if not self.flag.is_popout:
|
||||
self.setFixedWidth(a0.size().height())
|
||||
self.dim.width = a0.size().height()-40
|
||||
self.dim.height = a0.size().height()-40
|
||||
self.dim.width = a0.size().height() - 40
|
||||
self.dim.height = a0.size().height() - 40
|
||||
else:
|
||||
min_dimension = min(a0.size().height(), a0.size().width())
|
||||
self.dim.width = self.dim.height = min_dimension - 40
|
||||
|
@ -138,12 +140,11 @@ class SquareChart(Chart):
|
|||
m.setFrequency(str(round(target[minimum_position].freq)))
|
||||
m.frequencyInput.setText(str(round(target[minimum_position].freq)))
|
||||
|
||||
|
||||
def getXPosition(self, d: Datapoint) -> int:
|
||||
return int(self.width()/2 + d.re * self.dim.width/2)
|
||||
return int(self.width() / 2 + d.re * self.dim.width / 2)
|
||||
|
||||
def getYPosition(self, d: Datapoint) -> int:
|
||||
return int(self.height()/2 + d.im * -1 * self.dim.height/2)
|
||||
return int(self.height() / 2 + d.im * -1 * self.dim.height / 2)
|
||||
|
||||
def zoomTo(self, x1, y1, x2, y2):
|
||||
pass
|
||||
|
|
|
@ -44,14 +44,15 @@ class VSWRChart(FrequencyChart):
|
|||
return True
|
||||
|
||||
def drawValues(self, qp: QtGui.QPainter):
|
||||
if len(self.data) == 0 and len(self.reference) == 0:
|
||||
if not self.data and not self.reference:
|
||||
return
|
||||
|
||||
if self.fixedSpan:
|
||||
fstart = self.minFrequency
|
||||
fstop = self.maxFrequency
|
||||
elif len(self.data) > 0:
|
||||
fstart = self.data[0].freq
|
||||
fstop = self.data[len(self.data)-1].freq
|
||||
fstop = self.data[len(self.data) - 1].freq
|
||||
else:
|
||||
fstart = self.reference[0].freq
|
||||
fstop = self.reference[len(self.reference) - 1].freq
|
||||
|
@ -78,10 +79,7 @@ class VSWRChart(FrequencyChart):
|
|||
except OverflowError:
|
||||
maxVSWR = self.maxDisplayValue
|
||||
self.maxVSWR = maxVSWR
|
||||
span = maxVSWR-minVSWR
|
||||
if span == 0:
|
||||
span = 0.01
|
||||
self.span = span
|
||||
self.span = (maxVSWR - minVSWR) or 0.01
|
||||
|
||||
target_ticks = math.floor(self.dim.height / 60)
|
||||
|
||||
|
@ -91,53 +89,49 @@ class VSWRChart(FrequencyChart):
|
|||
vswr = self.valueAtPosition(y)[0]
|
||||
qp.setPen(Chart.color.text)
|
||||
if vswr != 0:
|
||||
digits = max(0, min(2, math.floor(3 - math.log10(abs(vswr)))))
|
||||
if digits == 0:
|
||||
vswrstr = str(round(vswr))
|
||||
else:
|
||||
vswrstr = str(round(vswr, digits))
|
||||
qp.drawText(3, y+3, vswrstr)
|
||||
digits = max(
|
||||
0, min(2, math.floor(3 - math.log10(abs(vswr)))))
|
||||
v_text = f"{round(vswr, digits)}" if digits else "0"
|
||||
qp.drawText(3, y + 3, v_text)
|
||||
qp.setPen(QtGui.QPen(Chart.color.foreground))
|
||||
qp.drawLine(self.leftMargin-5, y, self.leftMargin+self.dim.width, y)
|
||||
qp.drawLine(self.leftMargin - 5, self.topMargin + self.dim.height,
|
||||
self.leftMargin + self.dim.width, self.topMargin + self.dim.height)
|
||||
qp.drawLine(self.leftMargin - 5, y,
|
||||
self.leftMargin + self.dim.width, y)
|
||||
qp.drawLine(self.leftMargin - 5,
|
||||
self.topMargin + self.dim.height,
|
||||
self.leftMargin + self.dim.width,
|
||||
self.topMargin + self.dim.height)
|
||||
qp.setPen(Chart.color.text)
|
||||
digits = max(0, min(2, math.floor(3 - math.log10(abs(minVSWR)))))
|
||||
if digits == 0:
|
||||
vswrstr = str(round(minVSWR))
|
||||
else:
|
||||
vswrstr = str(round(minVSWR, digits))
|
||||
qp.drawText(3, self.topMargin + self.dim.height, vswrstr)
|
||||
digits = max(
|
||||
0, min(2, math.floor(3 - math.log10(abs(minVSWR)))))
|
||||
v_text = f"{round(minVSWR, digits)}" if digits else "0"
|
||||
qp.drawText(3, self.topMargin + self.dim.height, v_text)
|
||||
else:
|
||||
for i in range(target_ticks):
|
||||
vswr = minVSWR + i * self.span/target_ticks
|
||||
vswr = minVSWR + i * self.span / target_ticks
|
||||
y = self.getYPositionFromValue(vswr)
|
||||
qp.setPen(Chart.color.text)
|
||||
if vswr != 0:
|
||||
digits = max(0, min(2, math.floor(3 - math.log10(abs(vswr)))))
|
||||
if digits == 0:
|
||||
vswrstr = str(round(vswr))
|
||||
else:
|
||||
vswrstr = str(round(vswr, digits))
|
||||
qp.drawText(3, y+3, vswrstr)
|
||||
digits = max(
|
||||
0, min(2, math.floor(3 - math.log10(abs(vswr)))))
|
||||
vswrstr = f"{round(vswr, digits)}" if digits else "0"
|
||||
qp.drawText(3, y + 3, vswrstr)
|
||||
qp.setPen(QtGui.QPen(Chart.color.foreground))
|
||||
qp.drawLine(self.leftMargin-5, y, self.leftMargin+self.dim.width, y)
|
||||
qp.drawLine(self.leftMargin - 5, y,
|
||||
self.leftMargin + self.dim.width, y)
|
||||
qp.drawLine(self.leftMargin - 5,
|
||||
self.topMargin,
|
||||
self.leftMargin + self.dim.width,
|
||||
self.topMargin)
|
||||
qp.setPen(Chart.color.text)
|
||||
digits = max(0, min(2, math.floor(3 - math.log10(abs(maxVSWR)))))
|
||||
if digits == 0:
|
||||
vswrstr = str(round(maxVSWR))
|
||||
else:
|
||||
vswrstr = str(round(maxVSWR, digits))
|
||||
qp.drawText(3, 35, vswrstr)
|
||||
v_text = f"{round(maxVSWR, digits)}" if digits else "0"
|
||||
qp.drawText(3, 35, v_text)
|
||||
|
||||
qp.setPen(Chart.color.swr)
|
||||
for vswr in self.swrMarkers:
|
||||
y = self.getYPositionFromValue(vswr)
|
||||
qp.drawLine(self.leftMargin, y, self.leftMargin + self.dim.width, y)
|
||||
qp.drawLine(self.leftMargin, y,
|
||||
self.leftMargin + self.dim.width, y)
|
||||
qp.drawText(self.leftMargin + 3, y - 1, str(vswr))
|
||||
|
||||
self.drawFrequencyTicks(qp)
|
||||
|
|
Ładowanie…
Reference in New Issue