드디어 데이타를 읽고 화면에 내보내기 시작했습니다.     

아직 거리 배율값이 정확히 맞지 않습니다.    형태와 방향은 정확한 듯 합니다.

이젠 그 문제만 해결하면 됩니다.

 

영상 :

# -*- coding: utf-8 -*-
"""
From main library's example, ScatterPlot.py, 
I have taken out one of chart to make it for lidar data display.
The lidar related codes were taken from working code of Vidicon@DISCORD.
Last updated : Aug. 26, 2021 
"""
from pyqtgraph.Qt import QtGui, QtCore
import pyqtgraph as pg
import numpy as np
from collections import namedtuple
from itertools import chain
import sys

import serial   # For this one, you must install pyserial, not serial
from enum import Enum
import time
import math

#SERIAL_PORT = "/dev/ttyS5"   # for Orange Pi Zero 2's serial port
SERIAL_PORT = "/dev/ttyUSB0"  # for Other PC's USB to Serial module

class State(Enum):
   START1 = 0
   START2 = 1
   HEADER = 2
   DATA = 3

def readbytes(file, count):
   data = ser.read(count)
   #data = f.read(count)
   if len(data) != count:
      print("End of file")
      return False
   return data
   
step = (math.pi*2)   
anglePlus = math.pi / 2
fullround = 1300     # max dots in 1 round, it is larger than the real max dots in slowest mode
pos = np.zeros(shape=(2, fullround))
spots = [{'pos': pos[:,i], 'data': 1} for i in range(fullround)] + [{'pos': [0,0], 'data': 1}]
   
file_name = "RAW_DATA.LOG"
try:
   #f = open(file_name, "rb")
   ser = serial.Serial(SERIAL_PORT, 153600, timeout=0.1) 
   time.sleep(1)
except:
   print("could not connect to device")
   exit()

app = QtGui.QApplication([])
mw = QtGui.QMainWindow()
mw.resize(530,500)
view = pg.GraphicsLayoutWidget()  ## GraphicsView with GraphicsLayout inserted by default
mw.setCentralWidget(view)
mw.show()
mw.setWindowTitle('Lidar Test, unit in mm')

## create areas to add plots
w1 = view.addPlot()
w1.setAspectLocked()
  
###### Refresh Screen   
def RefreshScreen():
   global spots   # using globla spots array will ensure that it stores & clears data in same spot
   # Add polar grid lines
   w1.clear()   # clear screen and start drawing basic lines
   w1.addLine(x=0, pen=0.3)  # draw vertical center line
   w1.addLine(y=0, pen=0.3)  # draw horizontal center line
   for radius in range(200, 2000, 200):   # Draw 9 circles 200 ~ 2000 step 200
      # Adding circle (x, y, width, height)
      circleWidth = radius * 2
      circleHeight = radius * 2
      circle = pg.QtGui.QGraphicsEllipseItem(-radius, -radius, circleWidth, circleHeight)
      circle.setPen(pg.mkPen(0.3))
      w1.addItem(circle)  # addItem means draw or plot.  Here, draw circle
   # clear all data in the global spots array, make sure there will be no residue dots from previous round
   emptyone = np.zeros(shape=(2, fullround))   
   spots = [{'pos': emptyone[:,i], 'data': 1} for i in range(fullround)] + [{'pos': [0,0], 'data': 1}]   
      
###### Get Full Circle of Data 
def GetDataFromOneFullCycle():
   counter = 0
   ThisRoundCount = 0 # counts within one round
   maxThisRound = 0   # Number of good numbers for this cycle
   global pos         # using globla pos array will ensure we as storing data in same spot
   global spots       # using globla spots array will ensure we as storing data in same spot
   run = True
   try:
      state = State.START1
      while run:
         if state == State.START1:
            data = ser.read(1)
            #data = readbytes(f, 1)
            if data[0] == 0xAA:
               state = State.START2
            continue
         elif state == State.START2:
            data = ser.read(1)
            #data = readbytes(f, 1)
            if data[0] == 0x55:
               state = State.HEADER
            else:
               state = State.START1           
            continue
         elif state == State.HEADER:
            data = ser.read(8)
            #data = readbytes(f, 8)
            pack_type = data[0]
            data_lenght = int(data[1])
            start_angle = int(data[3] << 8) + int(data[2])
            stop_angle = int(data[5] << 8) + int(data[4])
            #unknown = int(data[7] << 8) + int(data[6])

            diff = stop_angle - start_angle
            if stop_angle < start_angle:
               diff =  0xB400 - start_angle + stop_angle
             
            angle_per_sample = 0
            if diff > 1 and (data_lenght-1) > 0:
               angle_per_sample = diff / (data_lenght-1)      
				
            #print("[{}]\ttype:{},\tlenght {},\tstart: {},\tstop: {}, \tdiff: {} \tdiff: {}"
            #   .format(counter, pack_type, data_lenght, start_angle, stop_angle, diff, angle_per_sample), end="\n")
				
            counter += 1
            #if pack_type != 40:
            #   counter = 0

            state = State.DATA
            continue
            
         elif state == State.DATA:
            state = State.START1
            #read data
            data = ser.read(data_lenght * 3)
            #data = readbytes(f, data_lenght * 3) 
            if data == False:
               break

            for i in range(0, data_lenght):

               data0 = int(data[i*3 + 0]) 
               data1 = int(data[i*3 + 1])
               data2 = int(data[i*3 + 2]) 
               distance = (data2  << 8) + data1

               angle = (start_angle + angle_per_sample * i)
               anglef = step * (angle / 0xB400) 
               #print("[{}]\tangle:{},\tanglef {},\tdist: {}".format(i, data0, (anglef + anglePlus), (distance/1000)), end="\n")
               distanceDivided = distance / 1000   # div to convert mm to meter
               #if (data0 != 1) & (distanceDivided < 3) :
               if (distanceDivided < 60) :
                  distanceDivided = (distance/5)   # Adjust distance ratio.  It is too large
          
                  x = distanceDivided * np.cos(anglef)
                  y = distanceDivided * np.sin(anglef)   
                  pos[0][ThisRoundCount] = y
                  pos[1][ThisRoundCount] = x
                  #print("[{}]\tDistance:{},\tanglef {},\tx:y: {}{}".format(ThisRoundCount, distanceDivided, anglef, x, y), end="\n")
                  ThisRoundCount += 1

            if pack_type != 40:  # After 1 full round
               spots = [{'pos': pos[:,i], 'data': 1} for i in range(ThisRoundCount)] + [{'pos': [0,0], 'data': 1}]
               ThisRoundCount = 0   
               ser.reset_input_buffer()    # This will clear serial line buffer, make update almost realtime.
               run = False   # Completed the mission of filling data in spots, now exit to draw step.
         else:
            print("error")

   except KeyboardInterrupt:
      run = False
      exit()               
   
   
######  I have to focus on putting data here.   
def _update():
   RefreshScreen()  # Draw basic chart with no data dots
   
   GetDataFromOneFullCycle()  # Get Full cycle of data from either File or Serial, prepare "spots"
   
   s1 = pg.ScatterPlotItem(size=5, pen=pg.mkPen(None), brush=pg.mkBrush(127, 255, 127, 120))
   s1.addPoints(spots)
   # addItem means draw or plot.  Here, plot all points
   w1.addItem(s1, ignoreBounds = True)  # ignoreBounds will prevent annoying rescaling

timer = QtCore.QTimer(interval=1)
timer.timeout.connect(_update)
#timer.start(0.1)  # duration number in millisecond
timer.start()  # A.S.A.P.

if __name__ == '__main__':
    import sys
    if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
        QtGui.QApplication.instance().exec_()

360도마다 스크린을 새로 시작하게 만들기.

# -*- coding: utf-8 -*-
"""
From main library's example, ScatterPlot.py, 
I will take out one of chart to make it for Lidar data display.
"""
from pyqtgraph.Qt import QtGui, QtCore
import pyqtgraph as pg
import numpy as np
from collections import namedtuple
from itertools import chain
import sys

app = QtGui.QApplication([])
mw = QtGui.QMainWindow()
mw.resize(530,500)
view = pg.GraphicsLayoutWidget()  ## GraphicsView with GraphicsLayout inserted by default
mw.setCentralWidget(view)
mw.show()
mw.setWindowTitle('Lidar Test, unit in mm')

## create areas to add plots
w1 = view.addPlot()
  
###### Refresh Screen   
def RefreshScreen():
   # Add polar grid lines
   w1.clear()   # clear screen and start drawing basic lines
   w1.addLine(x=0, pen=0.3)  # draw vertical center line
   w1.addLine(y=0, pen=0.3)  # draw horizontal center line
   for radius in range(200, 2000, 200):   # Draw 9 circles 200 ~ 2000 step 200
      # Adding circle (x, y, width, height)
      circleWidth = radius * 2
      circleHeight = radius * 2
      circle = pg.QtGui.QGraphicsEllipseItem(-radius, -radius, circleWidth, circleHeight)
      circle.setPen(pg.mkPen(0.3))
      w1.addItem(circle)  # addItem means draw or plot.  Here, draw circle
   
######  I have to focus on putting data here.   
def _update():
   RefreshScreen()  # Draw basic graph with no data dots
   
   n = 360
   
   s1 = pg.ScatterPlotItem(size=5, pen=pg.mkPen(None), brush=pg.mkBrush(255, 255, 255, 120))
   # Make 2 Dimension (X,Y) points array of 360 dots on scale of 500 for 500 mm.
   pos = np.random.normal(size=(2,n), scale=500)
   spots = [{'pos': pos[:,i], 'data': 1} for i in range(n)] + [{'pos': [0,0], 'data': 1}]
   s1.addPoints(spots)
   # addItem means draw or plot.  Here, plot all points
   w1.addItem(s1, ignoreBounds = True)  # ignoreBounds will prevent annoying rescaling
   

timer = QtCore.QTimer(interval=1)
timer.timeout.connect(_update)
timer.start(500)  # duration number in millisecond

# RefreshScreen()  # Calling once, later it will be called from _update every 360 degree
_update()   # Calling only once, timer will keep calling them 


if __name__ == '__main__':
    import sys
    if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
        QtGui.QApplication.instance().exec_()

이젠 마구 Timer가 마구 계속 찍어내기 시작.

Timer가 지속적으로 부르는 _Update 안에 Lidar 데이타를 업데이트해 줘야만 한다.

 

 

# -*- coding: utf-8 -*-
"""
From main library's example, ScatterPlot.py, 
I will take out one of chart to make it for Lidar data display.
"""
from pyqtgraph.Qt import QtGui, QtCore
import pyqtgraph as pg
import numpy as np
from collections import namedtuple
from itertools import chain
import sys

app = QtGui.QApplication([])
mw = QtGui.QMainWindow()
mw.resize(530,500)
view = pg.GraphicsLayoutWidget()  ## GraphicsView with GraphicsLayout inserted by default
mw.setCentralWidget(view)
mw.show()
mw.setWindowTitle('Lidar Test ')

## create four areas to add plots
w1 = view.addPlot()

# Add polar grid lines
w1.addLine(x=0, pen=0.3)
w1.addLine(y=0, pen=0.3)
for r in range(2, 2000, 200):   # Draw 10 circles
   # Adding circle (x, y, width, height)
   cwidth = r * 2
   cheight = r * 2
   circle = pg.QtGui.QGraphicsEllipseItem(-r, -r, cwidth, cheight)
   circle.setPen(pg.mkPen(0.3))
   w1.addItem(circle)  
   
   
######  I have to focus on putting data here.   
def _update():
   n = 360
   
   s1 = pg.ScatterPlotItem(size=5, pen=pg.mkPen(None), brush=pg.mkBrush(255, 255, 255, 120))
   # Make 2 Dimension (X,Y) points array of 360 dots on scale of 500 for 500 mm.
   pos = np.random.normal(size=(2,n), scale=500)
   spots = [{'pos': pos[:,i], 'data': 1} for i in range(n)] + [{'pos': [0,0], 'data': 1}]
   s1.addPoints(spots)
   w1.addItem(s1)

timer = QtCore.QTimer(interval=1)
timer.timeout.connect(_update)
timer.start(300)  # Update every 300 millisecond

_update()   # Calling only once, timer will keep calling them 


if __name__ == '__main__':
    import sys
    if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
        QtGui.QApplication.instance().exec_()

 

# -*- coding: utf-8 -*-
"""
From main library's example, ScatterPlot.py, 
I will take out one of chart to make it for Lidar data display.
"""
from pyqtgraph.Qt import QtGui, QtCore
import pyqtgraph as pg
import numpy as np
from collections import namedtuple
from itertools import chain

app = QtGui.QApplication([])
mw = QtGui.QMainWindow()
mw.resize(530,500)
view = pg.GraphicsLayoutWidget()  ## GraphicsView with GraphicsLayout inserted by default
mw.setCentralWidget(view)
mw.show()
mw.setWindowTitle('Lidar Test')

## create four areas to add plots
w1 = view.addPlot()

# Add polar grid lines
w1.addLine(x=0, pen=0.3)
w1.addLine(y=0, pen=0.3)
for r in range(2, 2000, 200):   # Draw 10 circles
   # Adding circle (x, y, width, height)
   cwidth = r * 2
   cheight = r * 2
   circle = pg.QtGui.QGraphicsEllipseItem(-r, -r, cwidth, cheight)
   circle.setPen(pg.mkPen(0.3))
   w1.addItem(circle)  

###### 이제 여기 아래만 집중적으로 공략하면 라이다 데이타를 적을수 있게 될 듯 하다.  #######
n = 360
s1 = pg.ScatterPlotItem(size=5, pen=pg.mkPen(None), brush=pg.mkBrush(255, 255, 255, 120))
# Make 2 Dimension (X,Y) points array of 360 dots on scale of 500 for 500 mm.
pos = np.random.normal(size=(2,n), scale=500)
spots = [{'pos': pos[:,i], 'data': 1} for i in range(n)] + [{'pos': [0,0], 'data': 1}]
s1.addPoints(spots)
w1.addItem(s1)

if __name__ == '__main__':
    import sys
    if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
        QtGui.QApplication.instance().exec_()

 

 

원래 프로그램에서 기초 점찍는 부분들만 뽑아낸 기둥.

(my local file name :  ~/py/pyqtgraph/l-01_basic_dots.py

 

# -*- coding: utf-8 -*-
"""
From main library's example, ScatterPlot.py, 
I will take out one of chart to make it for Lidar data display.
"""
from pyqtgraph.Qt import QtGui, QtCore
import pyqtgraph as pg
import numpy as np
from collections import namedtuple
from itertools import chain

app = QtGui.QApplication([])
mw = QtGui.QMainWindow()
mw.resize(500,800)
view = pg.GraphicsLayoutWidget()  ## GraphicsView with GraphicsLayout inserted by default
mw.setCentralWidget(view)
mw.show()
mw.setWindowTitle('Lidar Test')

## create four areas to add plots
w1 = view.addPlot()
view.nextRow()
w4 = view.addPlot()
print("Generating data, this takes a few seconds...")

## There are a few different ways we can draw scatter plots; each is optimized for different types of data:

## 1) All spots identical and transform-invariant (top-left plot).
## In this case we can get a huge performance boost by pre-rendering the spot
## image and just drawing that image repeatedly.

n = 360
s1 = pg.ScatterPlotItem(size=5, pen=pg.mkPen(None), brush=pg.mkBrush(255, 255, 255, 120))
pos = np.random.normal(size=(2,n), scale=1e-5)
spots = [{'pos': pos[:,i], 'data': 1} for i in range(n)] + [{'pos': [0,0], 'data': 1}]
s1.addPoints(spots)
w1.addItem(s1)

## Test performance of large scatterplots

s4 = pg.ScatterPlotItem(
    size=10,
    pen=pg.mkPen(None),
    brush=pg.mkBrush(255, 255, 255, 20),
    hoverable=True,
    hoverSymbol='s',
    hoverSize=15,
    hoverPen=pg.mkPen('r', width=2),
    hoverBrush=pg.mkBrush('g'),
)
n = 10000
pos = np.random.normal(size=(2, n), scale=1e-9)
s4.addPoints(
    x=pos[0],
    y=pos[1],
    #size=(np.random.random(n) * 20.).astype(int),
    #brush=[pg.mkBrush(x) for x in np.random.randint(0, 256, (n, 3))],
    data=np.arange(n)
)
w4.addItem(s4)

if __name__ == '__main__':
    import sys
    if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
        QtGui.QApplication.instance().exec_()

원래 따라오는 데모를 혼자 돌게 고친 내용.   그 과정에서 2줄을 블락을 시켰는데 전체 과정에 큰 차이가 없어서 다행입니다.

 

 

# -*- coding: utf-8 -*-
"""
Example demonstrating a variety of scatter plot features.
"""


from pyqtgraph.Qt import QtGui, QtCore
import pyqtgraph as pg
import numpy as np
from collections import namedtuple
from itertools import chain

app = QtGui.QApplication([])
mw = QtGui.QMainWindow()
mw.resize(800,800)
view = pg.GraphicsLayoutWidget()  ## GraphicsView with GraphicsLayout inserted by default
mw.setCentralWidget(view)
mw.show()
mw.setWindowTitle('pyqtgraph example: ScatterPlot')

## create four areas to add plots
w1 = view.addPlot()
w2 = view.addViewBox()
w2.setAspectLocked(True)
view.nextRow()
w3 = view.addPlot()
w4 = view.addPlot()
print("Generating data, this takes a few seconds...")

## Make all plots clickable
clickedPen = pg.mkPen('b', width=2)
lastClicked = []
def clicked(plot, points):
    global lastClicked
    for p in lastClicked:
        p.resetPen()
    print("clicked points", points)
    for p in points:
        p.setPen(clickedPen)
    lastClicked = points


## There are a few different ways we can draw scatter plots; each is optimized for different types of data:

## 1) All spots identical and transform-invariant (top-left plot).
## In this case we can get a huge performance boost by pre-rendering the spot
## image and just drawing that image repeatedly.

n = 300
s1 = pg.ScatterPlotItem(size=10, pen=pg.mkPen(None), brush=pg.mkBrush(255, 255, 255, 120))
pos = np.random.normal(size=(2,n), scale=1e-5)
spots = [{'pos': pos[:,i], 'data': 1} for i in range(n)] + [{'pos': [0,0], 'data': 1}]
s1.addPoints(spots)
w1.addItem(s1)
s1.sigClicked.connect(clicked)


## 2) Spots are transform-invariant, but not identical (top-right plot).
## In this case, drawing is almsot as fast as 1), but there is more startup
## overhead and memory usage since each spot generates its own pre-rendered
## image.

TextSymbol = namedtuple("TextSymbol", "label symbol scale")

def createLabel(label, angle):
    symbol = QtGui.QPainterPath()
    #symbol.addText(0, 0, QFont("San Serif", 10), label)
    f = QtGui.QFont()
    f.setPointSize(10)
    symbol.addText(0, 0, f, label)
    br = symbol.boundingRect()
    scale = min(1. / br.width(), 1. / br.height())
    tr = QtGui.QTransform()
    tr.scale(scale, scale)
    tr.rotate(angle)
    tr.translate(-br.x() - br.width()/2., -br.y() - br.height()/2.)
    return TextSymbol(label, tr.map(symbol), 0.1 / scale)

random_str = lambda : (''.join([chr(np.random.randint(ord('A'),ord('z'))) for i in range(np.random.randint(1,5))]), np.random.randint(0, 360))

s2 = pg.ScatterPlotItem(size=10, pen=pg.mkPen('w'), pxMode=True)
pos = np.random.normal(size=(2,n), scale=1e-5)
spots = [{'pos': pos[:,i], 'data': 1, 'brush':pg.intColor(i, n), 'symbol': i%10, 'size': 5+i/10.} for i in range(n)]
s2.addPoints(spots)
spots = [{'pos': pos[:,i], 'data': 1, 'brush':pg.intColor(i, n), 'symbol': label[1], 'size': label[2]*(5+i/10.)} for (i, label) in [(i, createLabel(*random_str())) for i in range(n)]]
s2.addPoints(spots)
w2.addItem(s2)
s2.sigClicked.connect(clicked)


## 3) Spots are not transform-invariant, not identical (bottom-left).
## This is the slowest case, since all spots must be completely re-drawn
## every time because their apparent transformation may have changed.

s3 = pg.ScatterPlotItem(
    pxMode=False,  # Set pxMode=False to allow spots to transform with the view
    hoverable=True,
    hoverPen=pg.mkPen('g'),
    hoverSize=1e-6
)
spots3 = []
for i in range(10):
    for j in range(10):
        spots3.append({'pos': (1e-6*i, 1e-6*j), 'size': 1e-6, 'pen': {'color': 'w', 'width': 2}, 'brush':pg.intColor(i*10+j, 100)})
s3.addPoints(spots3)
w3.addItem(s3)
s3.sigClicked.connect(clicked)

## Test performance of large scatterplots

s4 = pg.ScatterPlotItem(
    size=10,
    pen=pg.mkPen(None),
    brush=pg.mkBrush(255, 255, 255, 20),
    hoverable=True,
    hoverSymbol='s',
    hoverSize=15,
    hoverPen=pg.mkPen('r', width=2),
    hoverBrush=pg.mkBrush('g'),
)
n = 10000
pos = np.random.normal(size=(2, n), scale=1e-9)
s4.addPoints(
    x=pos[0],
    y=pos[1],
    # size=(np.random.random(n) * 20.).astype(int),
    # brush=[pg.mkBrush(x) for x in np.random.randint(0, 256, (n, 3))],
    data=np.arange(n)
)
w4.addItem(s4)
s4.sigClicked.connect(clicked)

if __name__ == '__main__':
    import sys
    if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
        QtGui.QApplication.instance().exec_()

원래 따라오는 데모를 혼자서도 돌게 고친 내용.

 

# -*- coding: utf-8 -*-
"""
Demonstrates a variety of uses for ROI. This class provides a user-adjustable
region of interest marker. It is possible to customize the layout and 
function of the scale/rotate handles in very flexible ways. 
"""

import pyqtgraph as pg
from pyqtgraph.Qt import QtCore, QtGui
import numpy as np

pg.setConfigOptions(imageAxisOrder='row-major')

## Create image to display
arr = np.ones((100, 100), dtype=float)
arr[45:55, 45:55] = 0
arr[25, :] = 5
arr[:, 25] = 5
arr[75, :] = 5
arr[:, 75] = 5
arr[50, :] = 10
arr[:, 50] = 10
arr += np.sin(np.linspace(0, 20, 100)).reshape(1, 100)
arr += np.random.normal(size=(100,100))

# add an arrow for asymmetry
arr[10, :50] = 10
arr[9:12, 44:48] = 10
arr[8:13, 44:46] = 10


## create GUI
QtGui.QApplication([])
w = pg.GraphicsLayoutWidget(show=True, size=(1000,800), border=True)
w.setWindowTitle('pyqtgraph example: ROI Examples')

text = """Data Selection From Image.<br>\n
Drag an ROI or its handles to update the selected image.<br>
Hold CTRL while dragging to snap to pixel boundaries<br>
and 15-degree rotation angles.
"""
w1 = w.addLayout(row=0, col=0)
label1 = w1.addLabel(text, row=0, col=0)
v1a = w1.addViewBox(row=1, col=0, lockAspect=True)
v1b = w1.addViewBox(row=2, col=0, lockAspect=True)
img1a = pg.ImageItem(arr)
v1a.addItem(img1a)
img1b = pg.ImageItem()
v1b.addItem(img1b)
v1a.disableAutoRange('xy')
v1b.disableAutoRange('xy')
v1a.autoRange()
v1b.autoRange()

rois = []
rois.append(pg.RectROI([20, 20], [20, 20], pen=(0,9)))
rois[-1].addRotateHandle([1,0], [0.5, 0.5])
rois.append(pg.LineROI([0, 60], [20, 80], width=5, pen=(1,9)))
#rois.append(pg.TriangleROI([80, 75], 20, pen=(5, 9)))
rois.append(pg.MultiRectROI([[20, 90], [50, 60], [60, 90]], width=5, pen=(2,9)))
rois.append(pg.EllipseROI([60, 10], [30, 20], pen=(3,9)))
rois.append(pg.CircleROI([80, 50], [20, 20], pen=(4,9)))
#rois.append(pg.LineSegmentROI([[110, 50], [20, 20]], pen=(5,9)))
rois.append(pg.PolyLineROI([[80, 60], [90, 30], [60, 40]], pen=(6,9), closed=True))

def update(roi):
    img1b.setImage(roi.getArrayRegion(arr, img1a), levels=(0, arr.max()))
    v1b.autoRange()
    
for roi in rois:
    roi.sigRegionChanged.connect(update)
    v1a.addItem(roi)

update(rois[-1])
    


text = """User-Modifiable ROIs<br>
Click on a line segment to add a new handle.
Right click on a handle to remove.
"""
w2 = w.addLayout(row=0, col=1)
label2 = w2.addLabel(text, row=0, col=0)
v2a = w2.addViewBox(row=1, col=0, lockAspect=True)
r2a = pg.PolyLineROI([[0,0], [10,10], [10,30], [30,10]], closed=True)
v2a.addItem(r2a)
r2b = pg.PolyLineROI([[0,-20], [10,-10], [10,-30]], closed=False)
v2a.addItem(r2b)
v2a.disableAutoRange('xy')
#v2b.disableAutoRange('xy')
v2a.autoRange()
#v2b.autoRange()

text = """Building custom ROI types<Br>
ROIs can be built with a variety of different handle types<br>
that scale and rotate the roi around an arbitrary center location
"""
w3 = w.addLayout(row=1, col=0)
label3 = w3.addLabel(text, row=0, col=0)
v3 = w3.addViewBox(row=1, col=0, lockAspect=True)

r3a = pg.ROI([0,0], [10,10])
v3.addItem(r3a)
## handles scaling horizontally around center
r3a.addScaleHandle([1, 0.5], [0.5, 0.5])
r3a.addScaleHandle([0, 0.5], [0.5, 0.5])

## handles scaling vertically from opposite edge
r3a.addScaleHandle([0.5, 0], [0.5, 1])
r3a.addScaleHandle([0.5, 1], [0.5, 0])

## handles scaling both vertically and horizontally
r3a.addScaleHandle([1, 1], [0, 0])
r3a.addScaleHandle([0, 0], [1, 1])

r3b = pg.ROI([20,0], [10,10])
v3.addItem(r3b)
## handles rotating around center
r3b.addRotateHandle([1, 1], [0.5, 0.5])
r3b.addRotateHandle([0, 0], [0.5, 0.5])

## handles rotating around opposite corner
r3b.addRotateHandle([1, 0], [0, 1])
r3b.addRotateHandle([0, 1], [1, 0])

## handles rotating/scaling around center
r3b.addScaleRotateHandle([0, 0.5], [0.5, 0.5])

# handles rotating/scaling around arbitrary point
#r3b.addScaleRotateHandle([0.3, 0], [0.9, 0.7])

v3.disableAutoRange('xy')
v3.autoRange()


text = """Transforming objects with ROI"""
w4 = w.addLayout(row=1, col=1)
label4 = w4.addLabel(text, row=0, col=0)
v4 = w4.addViewBox(row=1, col=0, lockAspect=True)
g = pg.GridItem()
v4.addItem(g)
r4 = pg.ROI([0,0], [100,100], resizable=False, removable=True)
r4.addRotateHandle([1,0], [0.5, 0.5])
r4.addRotateHandle([0,1], [0.5, 0.5])
img4 = pg.ImageItem(arr)
v4.addItem(r4)
img4.setParentItem(r4)

v4.disableAutoRange('xy')
v4.autoRange()

# Provide a callback to remove the ROI (and its children) when
# "remove" is selected from the context menu.
def remove():
    v4.removeItem(r4)
r4.sigRemoveRequested.connect(remove)

if __name__ == '__main__':
    import sys
    if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
        QtGui.QApplication.instance().exec_()

SetRange, Items, AutoRange : To keep only latest certain number of data on graph.   

출처 : ????

 

from pyqtgraph.Qt import QtGui, QtCore
import numpy as np
import pyqtgraph as pg

QtGui.QApplication([])

win = pg.GraphicsLayoutWidget(show=True, title="Plot auto-range examples")
win.resize(800,600)
win.setWindowTitle('pyqtgraph example: PlotAutoRange')

d = np.random.normal(size=100)
d[50:54] += 10
p1 = win.addPlot(title="95th percentile range", y=d)
p1.enableAutoRange('y', 0.95)


p2 = win.addPlot(title="Auto Pan Only")
p2.setAutoPan(y=True)
curve = p2.plot()
def update():
    t = pg.time()
    
    data = np.ones(100) * np.sin(t)
    data[50:60] += np.sin(t)
    global curve
    curve.setData(data)
    
timer = QtCore.QTimer()
timer.timeout.connect(update)
timer.start(50)

if __name__ == '__main__':
    import sys
    if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
        QtGui.QApplication.instance().exec_()

 

 

# 출처: https://mc10sw.tistory.com/10 [Make it possible]

# -*- coding: utf-8 -*-
"""
This example demonstrates many of the 2D plotting capabilities
in pyqtgraph. All of the plots may be panned/scaled by dragging with
the left/right mouse buttons. Right click on any plot to show a context menu.
"""
from pyqtgraph.Qt import QtGui, QtCore
import numpy as np
import pyqtgraph as pg



#QtGui.QApplication.setGraphicsSystem('raster')
app = QtGui.QApplication([])

#mw = QtGui.QMainWindow()
#mw.resize(800,800)



win = pg.GraphicsWindow(title="Basic plotting examples")    # PyQtGraph grahical window
win.resize(1000,600)
win.setWindowTitle('pyqtgraph example: Plotting')           # Title of python window



# Enable antialiasing for prettier plots
pg.setConfigOptions(antialias=True)


# Basic Array Plotting
p1 = win.addPlot(title="Basic array plotting", y=np.random.normal(size=100))


# Multiple Curves
p2 = win.addPlot(title="Multiple curves")
p2.plot(np.random.normal(size=100), pen=(255,0,0), name="Red curve")
p2.plot(np.random.normal(size=110)+5, pen=(0,255,0), name="Green curve")
p2.plot(np.random.normal(size=120)+10, pen=(0,0,255), name="Blue curve")


# Drawing with Points
p3 = win.addPlot(title="Drawing with points")
p3.plot(np.random.normal(size=100), pen=(200,200,200), symbolBrush=(255,0,0), symbolPen='w')


# Next Row
win.nextRow()


# Parametric, Grid Enabled
p4 = win.addPlot(title="Parametric, grid enabled")
x = np.cos(np.linspace(0, 2*np.pi, 1000))
y = np.sin(np.linspace(0, 4*np.pi, 1000))
p4.plot(x, y)
p4.showGrid(x=True, y=True)


# Scatter Plot, Axis Labels, Log Scale
p5 = win.addPlot(title="Scatter plot, axis labels, log scale")
x = np.random.normal(size=1000) * 1e-5
y = x*1000 + 0.005 * np.random.normal(size=1000)
y -= y.min()-1.0
mask = x > 1e-15
x = x[mask]
y = y[mask]
p5.plot(x, y, pen=None, symbol='t', symbolPen=None, symbolSize=10, symbolBrush=(100, 100, 255, 50))
p5.setLabel('left', "Y Axis", units='A')
p5.setLabel('bottom', "Y Axis", units='s')
p5.setLogMode(x=True, y=False)


# Updating Plot
p6 = win.addPlot(title="Updating plot")
curve = p6.plot(pen='y')
data = np.random.normal(size=(10,1000))
ptr = 0
def update():
    global curve, data, ptr, p6
    curve.setData(data[ptr%10])
    if ptr == 0:
        p6.enableAutoRange('xy', False)  ## stop auto-scaling after the first data set is plotted
    ptr += 1
timer = QtCore.QTimer()
timer.timeout.connect(update)
timer.start(50)


# Next Row
win.nextRow()


# Filled Plot, Axis Disabled
p7 = win.addPlot(title="Filled plot, axis disabled")
y = np.sin(np.linspace(0, 10, 1000)) + np.random.normal(size=1000, scale=0.1)
p7.plot(y, fillLevel=-0.3, brush=(50,50,200,100))
p7.showAxis('bottom', False)


# Region Selection
x2 = np.linspace(-100, 100, 1000)
data2 = np.sin(x2) / x2
p8 = win.addPlot(title="Region Selection")
p8.plot(data2, pen=(255,255,255,200))
lr = pg.LinearRegionItem([400,700])
lr.setZValue(-10)
p8.addItem(lr)


# Zoom on Selected Region
p9 = win.addPlot(title="Zoom on selected region")
p9.plot(data2)
def updatePlot():
    p9.setXRange(*lr.getRegion(), padding=0)
def updateRegion():
    lr.setRegion(p9.getViewBox().viewRange()[0])
lr.sigRegionChanged.connect(updatePlot)
p9.sigXRangeChanged.connect(updateRegion)
updatePlot()


## Start Qt event loop unless running in interactive mode or using pyside.
if __name__ == '__main__':
    import sys
    if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
        QtGui.QApplication.instance().exec_()

 

** AxisItem class 를 subclass 하여, 원하는 axis 만들수 있다. 

    --> 특히, tickStrings( ) 메소드를 override 하여, tick 에 원하는 양식으로 출력 변경가능하다.

 

 

** 최근 시간만 보여주기

  --> setData( ) 로 실시간 chart 그리기전에, setXRange( ) 이용하여, 최근 시간만 설정하면 ok!!!

# https://freeprog.tistory.com/373?category=716617

from PyQt5.QtCore import QTimer
from PyQt5.QtWidgets import *

import pyqtgraph as pg

import time


class TimeAxisItem(pg.AxisItem):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.setLabel(text='Time(초)', units=None)
        self.enableAutoSIPrefix(False)

    def tickStrings(self, values, scale, spacing):
        """ override 하여, tick 옆에 써지는 문자를 원하는대로 수정함.
            values --> x축 값들   ; 숫자로 이루어진 Itarable data --> ex) List[int]
        """
        # print("--tickStrings valuse ==>", values)
        return [time.strftime("%H:%M:%S", time.localtime(local_time)) for local_time in values]


class ExampleWidget(QWidget):
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        self.pw = pg.PlotWidget(
            title="Example plot",
            labels={'left': 'y 축'},
            axisItems={'bottom': TimeAxisItem(orientation='bottom')}
        )

        hbox = QHBoxLayout()
        hbox.addWidget(self.pw)
        self.setLayout(hbox)

        self.pw.setYRange(0, 70, padding=0)

        time_data = int(time.time())
        self.pw.setXRange(time_data - 10, time_data + 1)  # 생략 가능.

        self.pw.showGrid(x=True, y=True)
        # self.pw.enableAutoRange()

        self.pdi = self.pw.plot(pen='y')   # PlotDataItem obj 반환.

        self.plotData = {'x': [], 'y': []}

    def update_plot(self, new_time_data: int):
        data_sec = time.strftime("%S", time.localtime(new_time_data))
        self.plotData['y'].append(int(data_sec))
        self.plotData['x'].append(new_time_data)

        self.pw.setXRange(new_time_data - 10, new_time_data + 1, padding=0)   # 항상 x축 시간을 최근 범위만 보여줌.

        self.pdi.setData(self.plotData['x'], self.plotData['y'])


if __name__ == "__main__":
    import sys

    app = QApplication(sys.argv)

    ex = ExampleWidget()

    def get_data():
        new_time_data = int(time.time())
        ex.update_plot(new_time_data)

    mytimer = QTimer()
    mytimer.start(1000)  # 1초마다 갱신 위함...
    mytimer.timeout.connect(get_data)

    ex.show()
    sys.exit(app.exec_())

 

 

+ Recent posts