text:
import numpy as np

class Slicer:
    def __init__(self, array, height, width):
        self.array = array
        self.height = height
        self.width = width

    def set_array(self, array):
        self.array = array

    def slice(self):
        mid_of_height = int(self.height / 2)
        mid_of_width = int(self.width / 2)

        top_left = self.array[:mid_of_height, :mid_of_width]
        top_right = self.array[:mid_of_height, mid_of_width:self.width]
        bottom_left = self.array[mid_of_height:self.height, :mid_of_width]
        bottom_right = self.array[mid_of_height:self.height, mid_of_width:self.width]

        return top_left, top_right, bottom_left, bottom_right

    @staticmethod
    def concatenate(en_image_top_left, en_image_top_right, en_image_bottom_left, en_image_bottom_right):
        top = np.concatenate((en_image_top_left, en_image_top_right), 1)
        bottom = np.concatenate((en_image_bottom_left, en_image_bottom_right), 1)
        son = np.concatenate((top, bottom), 0)
        return son

max_stars_repo_name: DevranCanikli/imsafe

max_issues_repo_name: alpsakaci/imsafe

max_forks_repo_name: alpsakaci/imsafe


text:
# -*- coding: utf-8 -*-
# @Author: yulidong
# @Date:   2018-06-20 14:37:27
# @Last Modified by:   yulidong
# @Last Modified time: 2018-10-29 20:17:52

import numpy as np
import os
import time
import matplotlib.pyplot as plt
from multiprocessing import Process,Lock
from multiprocessing import Pool
import cv2
import numpy
import os
import sys
from python_pfm import *

thread_num=10
def pre_processing(start,end):
    output_dir=r'/home/lidong/Documents/datasets/monkey/'
    train=np.load(os.path.join(output_dir,'train.npy'))
    left=train[0]
    right=train[1]
    length=len(left)
    for f in range(start,end):
        start_time=time.time()
        #print(left[f][0],right[f][0],left[f][1])
        l_image=np.array(cv2.imread(left[f][0]))[:,:,::-1]
        r_image=np.array(cv2.imread(right[f][0]))[:,:,::-1]
        disparity=np.array(readPFM(left[f][1])[0])

        data=np.concatenate([l_image,
                        r_image,
                        np.reshape(disparity,[disparity.shape[0],disparity.shape[1],1])
                        ],
                        axis=2)
        np.save(os.path.join(output_dir,r'train',str(f)+'.npy'),data)
        print(f,start,end,time.time()-start_time)
        print(os.path.join(output_dir,r'train',str(f)+'.npy'))

if __name__=='__main__':
    process = []
    output_dir=r'/home/lidong/Documents/datasets/monkey/'
    train=np.load(os.path.join(output_dir,'train.npy'))
    left=train[0]
    right=train[1]
    length=len(left)
    start=[]
    end=[]
    p = Pool(thread_num)
    for z in range(thread_num):
        start.append(int(np.floor(z*length/thread_num)))
        end.append(int(np.ceil((z+1)*length/thread_num)))
    for z in range(thread_num):
        p.apply_async(pre_processing, args=(start[z],end[z]))

    p.close()
    p.join()
    #pre_processing(0,4248)
    print('end')

ext: py

reason: import numpy


text:
from typing import List, Tuple, Union

import numpy
from PIL import Image

from constants import EC_LEVEL, ALIGNMENT_POSITIONS
import encoding

class QRImage:
    def __init__(self, version: int, ec_level: Union[EC_LEVEL, str], message: str, mask=-1):
        """
        Create a QRImage object with the given arguments.

        :param version: The QR version to use
        :param ec_level: The error correction level to use
        :param message: The message to write to the QR code
        """
        self._size = version * 4 + 17
        self._version = version
        self._message = message
        self._mask = mask  # -1 if we want to find optimal mask, otherwise force mask value
        self._used_mask = 0

        # Cast ec_level to EC_LEVEL enum if needed
        if type(ec_level) is str:
            self._ecl = EC_LEVEL[ec_level]
        else:
            self._ecl = ec_level

        # Create 2 arrays with correct size based on the version
        self._array = [[-1 for _ in range(self._size)] for _ in range(self._size)]
        self._unmasked = [[-1 for _ in range(self._size)] for _ in range(self._size)]

        # Compute the codewords for the message
        self._data = encoding.generate_codewords(self._message, self._version, self._ecl)

        # Create the qr code
        self._draw_initial()  # drawing the static modules (finder patterns, etc)
        self._write_data()  # draw the data and apply masking

        # Create the PIL image
        self._image = self._generate_image()
        self._need_regen: bool = False

    def _draw_initial(self):
        """
        Writes the static patterns to the unmasked array
        """

        def draw_timing_patterns():
            # As defined in 7.3.4
            # Vertical pattern
            for y in range(self._size):
                self._unmasked[y][6] = (y + 1) % 2

            # Horizontal pattern
            for x in range(self._size):
                self._unmasked[6][x] = (x + 1) % 2

        def draw_finder_patterns():
            # As defined in 7.3.2
            x_offset = [0, self._size - 7, 0]
            y_offset = [0, 0, self._size - 7]

            for pattern in range(3):
                for x in range(7):
                    for y in range(7):
                        color = 0

                        if x in [0, 6] or y in [0, 6]:  # in outer pattern
                            color = 1
                        elif x not in [1, 5] and y not in [1, 5]:  # not in middle pattern (in inner pattern)
                            color = 1

                        self._unmasked[y + y_offset[pattern]][x + x_offset[pattern]] = color

        def draw_spacing_and_format():
            # top left
            for x in range(9):
                self._unmasked[7][x] = 0
                self._unmasked[8][x] = x == 6  # doesn't overwrite existing timing pattern
            for y in range(9):
                self._unmasked[y][7] = 0
                self._unmasked[y][8] = y == 6

            # top right
            for x in range(self._size - 8, self._size):
                self._unmasked[7][x] = 0
                self._unmasked[8][x] = 0
            for y in range(9):
                self._unmasked[y][self._size - 8] = 0

            # bottom left
            for y in range(self._size - 8, self._size):
                self._unmasked[y][7] = 0
                self._unmasked[y][8] = 0
            for x in range(9):
                self._unmasked[self._size - 8][x] = x == 8  # write the format black module

        def draw_alignment_patterns():
            pos = ALIGNMENT_POSITIONS[self._version]

            for pair in pos:
                x_offset, y_offset = pair
                for x in range(5):
                    for y in range(5):
                        if x in [0, 4] or y in [0, 4] or x == y == 2:
                            # outer square or inner dot
                            self._unmasked[y + y_offset][x + x_offset] = 1
                        else:
                            self._unmasked[y + y_offset][x + x_offset] = 0

        def draw_version_information():
            table = [""] * 7 + [
                "000111110010010100",
                "001000010110111100",
                "001001101010011001",
                "001010010011010011",  # v10
                "001011101111110110",
                "001100011101100010",
                "001101100001000111",
                "001110011000001101",
                "001111100100101000",  # v15
                "010000101101111000",
                "010001010001011101",
                "010010101000010111",
                "010011010100110010",
                "010100100110100110",  # v20
                "010101011010000011",
                "010110100011001001",
                "010111011111101100",
                "011000111011000100",
                "011001000111100001",  # v25
                "011010111110101011",
                "011011000010001110",
                "011100110000011010",
                "011101001100111111",
                "011110110101110101",  # v30
                "011111001001010000",
                "100000100111010101",
                "100001011011110000",
                "100010100010111010",
                "100011011110011111",  # v35
                "100100101100001011",
                "100101010000101110",
                "100110101001100100",
                "100111010101000001",
                "101000110001101001",  # v40
            ]

            version_info = table[self._version]

            # top right
            x = y = 0
            for i in range(len(version_info)):
                self._unmasked[y + 5][self._size + x - 9] = int(version_info[i])

                if x == -2:
                    x = 0
                    y -= 1
                else:
                    x -= 1

            # bottom left
            x = y = 0
            for i in range(len(version_info)):
                self._unmasked[self._size + y - 9][x + 5] = int(version_info[i])

                if y == - 2:
                    y = 0
                    x -= 1
                else:
                    y -= 1

        draw_timing_patterns()
        draw_finder_patterns()
        draw_spacing_and_format()
        if self._version > 1:
            draw_alignment_patterns()  # not needed for version 1
        if self._version >= 7:
            draw_version_information()

    def get_version(self) -> int:
        return self._version

    def set_version(self, new_version: int):
        """
        Set a new version for the instance

        :param new_version: The new version to use
        :raise ValueError: if the current message is too long for the instance's error correction level and new version
        """
        self._version = new_version
        self._size = self._version * 4 + 17

        # Recreate array and unmasked since new version means new size
        self._array = [[-1 for _ in range(self._size)] for _ in range(self._size)]
        self._unmasked = [[-1 for _ in range(self._size)] for _ in range(self._size)]

        # regen encoded data with new version
        self._data = encoding.generate_codewords(self._message, self._version, self._ecl)
        self._need_regen = True  # Set need_regen to True to only generate image when requested for the first time.
        self._write_data()

    def get_error_correction_level(self) -> EC_LEVEL:
        return self._ecl

    def set_error_correction_level(self, new_ecl: Union[EC_LEVEL, str]):
        """
        Set a new error correction level for the instance

        :param new_ecl: The new error correction level to use
        :raise ValueError: if the current message is too long for the instance's version and new error correction level
        """
        if type(new_ecl) is str:
            self._ecl = EC_LEVEL[new_ecl]  # Cast to enum
        else:
            self._ecl = new_ecl

        self._data = encoding.generate_codewords(self._message, self._version, self._ecl)
        self._need_regen = True
        self._write_data()

    def get_message(self) -> str:
        return self._message

    def set_message(self, new_msg: str):
        """
        Set a new message for the instance

        :param new_msg: The new message to use
        :raise ValueError: if the new message is too long for the instance's version and error correction level
        """
        self._message = new_msg
        self._data = encoding.generate_codewords(self._message, self._version, self._ecl)
        self._need_regen = True
        self._write_data()

    def get_mask(self) -> int:
        if self._mask == -1:
            # not using forced mask
            return self._used_mask
        else:
            return self._mask

    def set_mask(self, new_mask: int):
        if not 0 <= new_mask <= 7:
            raise ValueError("Illegal mask pattern, must be between 0 and 7")

        self._mask = new_mask
        self._write_best_mask()
        self._need_regen = True

    def _write_data(self):
        """
        Write the contents of _data to the _unmasked matrix
        """

        def next_move(x: int, y: int) -> Tuple[int, int]:
            """
            Calculates the new position based on the current one.

            :param x: The current x position
            :param y: The current y position
            :return: A tuple containing the new x and y coordinates
            """
            if x is None and y is None:
                # initial
                return self._size - 1, self._size - 1

            # edge-case: transition between normal zone and left zone
            if y == 0 and x == 7:
                return 5, 0

            if x >= 7:
                # normal zone
                up = ((x + 1) // 2) % 2 == 0  # boolean checking if we're moving up

                if up:
                    if x % 2 == 0:
                        # going left
                        return x - 1, y
                    else:
                        # going up right
                        if y == 0:
                            # already at top, switch lane
                            return x - 1, y
                        else:
                            return x + 1, y - 1
                else:
                    # down
                    if x % 2 == 0:
                        # going left
                        return x - 1, y
                    else:
                        # going down right
                        if y == self._size - 1:
                            # bottom, switch lane
                            return x - 1, y
                        else:
                            return x + 1, y + 1

            else:
                # left-most zone
                up = x in [2, 3]

                if up:
                    if x % 2 == 1:
                        # going left
                        return x - 1, y
                    else:
                        # up-right
                        if y == 0:
                            # top
                            return x - 1, y
                        else:
                            return x + 1, y - 1
                else:
                    # down
                    if x % 2 == 1:
                        return x - 1, y
                    else:
                        if y == self._size - 1:
                            return x - 1, y
                        else:
                            return x + 1, y + 1

        x = y = None

        for i in range(len(self._data)):
            x, y = next_move(x, y)

            while self._unmasked[y][x] != -1:  # if not -1, has been written to (static pattern)
                x, y = next_move(x, y)  # go to next position until we're not in a static pattern anymore

            self._unmasked[y][x] = int(self._data[i])  # write bit to current position

        self._write_best_mask()  # Find the optimal mask for the unmasked matrix

    def _write_best_mask(self):
        """
        Reads the _unmasked matrix to determine the best mask and writes the masked matrix to _array unless the
        instance has a specific mask value set.
        """

        def is_protected(x: int, y: int) -> bool:
            """
            Checks if we can make changes to the coordinates
            :param x: The x coordinate
            :param y: The y coordinate
            :return: True if it is protected, false if it is not and we can make changes
            """
            if x == 6 or y == 6:
                # Timing pattern
                return True
            if x <= 8 and y <= 8 or x >= (self._size - 8) and y <= 8 or x <= 8 and y >= (self._size - 8):
                # Finder pattern
                return True

            if self._version > 1:
                # Alignment pattern
                positions = ALIGNMENT_POSITIONS[self._version]
                for position in positions:
                    x_pos, y_pos = position
                    if x_pos <= x <= x_pos + 4 and y_pos <= y <= y_pos + 4:
                        return True
            if self._version >= 7:
                # version info section
                if x <= 5 and y >= self._size - 11 or x >= self._size - 11 and y <= 5:
                    return True

        def mask_pattern(pattern: int) -> List[List[int]]:
            masked_array = [row[:] for row in self._unmasked]  # deep copy
            self._write_format_information(masked_array, pattern)

            if pattern == 0:
                def pattern_formula(x, y): return (y + x) % 2 == 0
            elif pattern == 1:
                def pattern_formula(x, y): return y % 2 == 0
            elif pattern == 2:
                def pattern_formula(x, y): return x % 3 == 0
            elif pattern == 3:
                def pattern_formula(x, y): return (y + x) % 3 == 0
            elif pattern == 4:
                def pattern_formula(x, y): return ((y // 2) + (x // 3)) % 2 == 0
            elif pattern == 5:
                def pattern_formula(x, y): return (y * x) % 2 + (y * x) % 3 == 0
            elif pattern == 6:
                def pattern_formula(x, y): return ((y * x) % 2 + (y * x) % 3) % 2 == 0
            elif pattern == 7:
                def pattern_formula(x, y): return ((y + x) % 2 + (y * x) % 3) % 2 == 0
            else:
                raise ValueError("Illegal mask pattern")  # technically should not be called

            # Xor the unmasked array with the pattern formula to get a masked matrix
            for x in range(self._size):
                for y in range(self._size):
                    if not is_protected(x, y):  # check coordinates aren't static pattern, if not, proceed
                        masked_array[y][x] ^= pattern_formula(x, y)
            return masked_array

        if self._mask != -1:
            # Forced mask, use specified one
            self._array = mask_pattern(self._mask)
            return

        # No forced mask, find best one
        # initialize values by computing mask 0, loop for mask 1-7
        self._array = mask_pattern(0)
        lowest_score = self._calculate_mask_score(self._array)
        self._used_mask = 0

        for mask in range(1, 8):
            masked = mask_pattern(mask)
            score = self._calculate_mask_score(masked)
            if score < lowest_score:
                lowest_score = score
                self._array = masked
                self._used_mask = mask

    def _write_format_information(self, array: List[List[int]], mask_pattern: int):
        # Using hardcoded table since there is only a few options and computing the bits would be time consuming.
        table = dict({
            "L": [
                "111011111000100", "111001011110011", "111110110101010", "111100010011101",
                "110011000101111", "110001100011000", "110110001000001", "110100101110110"
            ],
            "M": [
                "101010000010010", "101000100100101", "101111001111100", "101101101001011",
                "100010111111001", "100000011001110", "100111110010111", "100101010100000"
            ],
            "Q": [
                "011010101011111", "011000001101000", "011111100110001", "011101000000110",
                "010010010110100", "010000110000011", "010111011011010", "010101111101101"
            ],
            "H": [
                "001011010001001", "001001110111110", "001110011100111", "001100111010000",
                "000011101100010", "000001001010101", "000110100001100", "000100000111011"
            ]
        })

        info = table[self._ecl.name][mask_pattern]

        # Write the format information as described in Figure 19

        i = 0
        # left horizontal
        for x in range(9):
            if x != 6:
                array[8][x] = int(info[i])
                i += 1

        # top vertical
        for y in range(7, -1, -1):
            if y != 6:
                array[y][8] = int(info[i])
                i += 1

        i = 0
        # bottom vertical
        for y in range(self._size - 1, self._size - 8, -1):
            array[y][8] = int(info[i])
            i += 1

        # right horizontal
        for x in range(self._size - 8, self._size):
            array[8][x] = int(info[i])
            i += 1

        # dark module
        array[self._size - 8][8] = 1

    def _calculate_mask_score(self, array: List[List[int]]) -> int:
        """
        Calculates the mask score of the array

        :param array: The array to use in the calculation
        :return: The overall mask score of the array
        """

        def colored_rows() -> int:
            """
            Checks for groups of 5+ adjacent modules in rows
            """
            score = 0
            for y in range(self._size):
                x = 0
                color = array[y][x]
                current_length = 1
                x += 1
                while x < self._size:
                    if array[y][x] == color:
                        current_length += 1
                    else:
                        if current_length >= 5:
                            score += 3 + (current_length - 5)
                        current_length = 1
                        color = array[y][x]
                    x += 1

                # need to check again after the loop in case the last module is part of a group
                if current_length >= 5:
                    score += 3 + (current_length - 5)

            return score

        def colored_cols() -> int:
            """
            Checks for groups of 5+ adjacent modules in columns
            """
            score = 0
            for x in range(self._size):
                y = 0
                color = array[y][x]
                current_length = 1
                y += 1
                while y < self._size:
                    if array[y][x] == color:
                        current_length += 1
                    else:
                        if current_length >= 5:
                            score += 3 + (current_length - 5)
                        current_length = 1
                        color = array[y][x]
                    y += 1
                # need to check again after the loop in case the last module is part of a group
                if current_length >= 5:
                    score += 3 + (current_length - 5)
            return score

        def colored_boxes() -> int:
            """
            Checks for 2x2 blocks of same color modules
            """
            score = 0
            for y in range(self._size - 1):
                for x in range(self._size - 1):
                    if array[y][x] == array[y][x + 1] == array[y + 1][x] == array[y + 1][x + 1]:
                        score += 3
            return score

        def finder_pattern() -> int:
            """
            Checks for patterns of dark:light:dark:dark:dark:light:dark (similar to finder pattern)
            """
            score = 0
            pad_before = [0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1]
            pad_after = [1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0]

            for row in array:
                for i in range(self._size - 11):
                    sub_row = row[i:i + 11]
                    if sub_row in [pad_before, pad_after]:
                        # pattern match
                        score += 40

            for i in range(self._size):
                col = [row[i] for row in array]
                for j in range(self._size - 11):
                    sub_col = col[j:j + 11]
                    if sub_col in [pad_before, pad_after]:
                        score += 40

            return score

        def color_proportion() -> int:
            """
            Checks if the proportion of black and white modules are near 50%
            """
            black_modules = 0
            for x in range(self._size):
                for y in range(self._size):
                    black_modules += array[y][x]

            proportion = (black_modules * 100) / (self._size ** 2)  # proportion in %

            i = 0
            while not ((50 - 5 * (i + 1)) <= proportion <= (50 + 5 * (i + 1))):
                # 0 if 45 <= x <= 55, 1 if 40 <= x <= 50, etc...
                i += 1

            return i * 10

        return colored_rows() + colored_cols() + colored_boxes() + finder_pattern() + color_proportion()

    def _generate_image(self) -> Image:
        """
        Creates a PIL image object from the _array variable
        """
        np_array = [[255 if i != 1 else 0 for i in row] for row in self._array]

        # Upscaling
        # TODO remove / implement better
        np_array = numpy.kron(np_array, numpy.ones((20, 20)))

        return Image.fromarray(np_array.astype(numpy.uint8), mode='L')

    def get_image(self) -> Image:
        """
        Returns the representation of the QR code as an image

        :return: A PIL Image object
        """
        if self._need_regen:
            self._image = self._generate_image()
        return self._image

max_stars_repo_name: paamm/qrcode

max_issues_repo_name: paamm/qrcode

max_forks_repo_name: paamm/qrcode


text:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Wed Jan 29 14:23:17 2020

@author: stan
"""
import cv2
import imutils
import numpy as np

from frame_loader import CameraFrameLoader
from vis import Detector

class GraspingEnv(object):
    def __init__(self, visualise_vision=False):
        self.fl = CameraFrameLoader(source=4)
        self.det = Detector(visualise=visualise_vision)
        self.hue_min = 20.0
        self.last_frame = None

    def calibrate_env(self):
        self.det.calibrate(self.fl)

    def get_frame(self):
        # Resize and blur for detection
        frame= self.fl._get_frame()
        frame = imutils.resize(frame, width=900)
        self.last_frame = cv2.GaussianBlur(frame, (11, 11), 0)

    def get_object_z_coord(self):
        x,y,w,h = self.det.detect_rect_from_hue(self.last_frame, self.hue_min)
        if y:
            return self.last_frame.shape[0]-y
        else:
            return None

    def get_marker_coords_and_angle(self):
        centres, radius = self.det.detect_markers_from_hue(self.last_frame,
                                                           self.hue_min)
        vert_angle = None
        if centres[0] and radius[0]:
        # First one is the larger contour
            dx = abs(centres[0][0]-centres[1][0])
            dy = abs(centres[0][1]-centres[1][1])
            vert_angle = np.arctan(dy/dx)
        return vert_angle

    def get_reward(self, reward_idx):
        # Normalised height
        if reward_idx == 1:
            z = self.get_object_z_coord()
            if z:
                return self.get_object_z_coord()/self.last_frame.shape[0]
            else:
                return 0

graspingEnv = GraspingEnv(visualise_vision=True)
#graspingEnv.calibrate_env()

while True:
    graspingEnv.get_frame()
    graspingEnv.det.detect_markers_from_hue(graspingEnv.last_frame, graspingEnv.hue_min)
    #print(graspingEnv.get_reward(1))
    key = cv2.waitKey(1) & 0xFF
    # if the 'q' key is pressed, stop the loop
    if key == ord("q"):
        break

# Run action 1
# Run action 2
# Run action 3
# Get reward

# close all windows
cv2.destroyAllWindows()


text:
import grpc
import image_pb2
import image_pb2_grpc
import numpy as np

# options = [('grpc.max_send_message_length', 10 * 1024 * 1024),
#           ('grpc.max_receive_message_length', 10 * 1024 * 1024)
#           ] # Message size is up to 10MB

from merge_far_near_images import MergeFarNearImage

class MergedWDRImageManager:
    def __init__(self, options):
        self.channel = grpc.insecure_channel('localhost:50051',
                                             options=options)
        self.rgb_img = None
        self.depth_img = None
        self.depth_image_merger = MergeFarNearImage()  # MERGE_QUEUE_SIZE = 5

    def update_depth_range1(self, response):
        w = response.image_depth_range1.width
        h = response.image_depth_range1.height
        if w == 0:
            return False
        img_np = np.frombuffer(response.image_depth_range1.data, np.uint16)
        self.img_depth_range1 = img_np.reshape(h, w)
        return True

    def update_depth_range2(self, response):
        w = response.image_depth_range2.width
        h = response.image_depth_range2.height
        if w == 0:
            return False
        img_np = np.frombuffer(response.image_depth_range2.data, np.uint16)
        self.img_depth_range2 = img_np.reshape(h, w)
        return True

    def update(self):
        stub = image_pb2_grpc.ImageServiceStub(self.channel)
        response = stub.SendWDRImage(image_pb2.ImageRequest())
        status = self.update_depth_range1(response)
        status &= self.update_depth_range2(response)
        return status

    def get_merger_result(self):
        if self.update():
            return self.depth_image_merger.update(
                self.img_depth_range1, self.img_depth_range2
            )

        else:
            return False

    @property
    def filtered_fused_depth(self):
        #count = 0
        while not self.get_merger_result():
            #count += 1
            pass
        return self.depth_image_merger.merged_depth_image


text:
import networkx as nx

def reorder_labels(labels, new_order):

    new_labels = []

    for x in labels:
       new_labels.append( sorted(x,  key = lambda i: new_order.index(i)) )

    return new_labels

def find_ordering(labels, order_type, root_node):

    edges = []
    added_edges = []
    for label in labels:
        x,name,y = label.split('.')

        i=-1
        if (x,y) in added_edges:
            i = added_edges.index((x,y))
        elif (y,x) in added_edges:
            i = added_edges.index((y,x))

        if i!=-1:
            edges[i][2]['name'].append(name)
        else:
            edges.append((x,y,{'name':[name]}))
            added_edges.append((x,y))

    G = nx.Graph()
    G.add_edges_from(edges)

    if root_node=='none':
        degrees = nx.degree_centrality(G)
        root_node =  max(degrees, key=degrees.get)

    if order_type == 'bfs':
         new_labels = nx.edge_bfs(G, root_node)
    if order_type == 'dfs':
        new_labels = nx.edge_dfs(G, root_node)

    names = nx.get_edge_attributes(G, 'name')

    ordered_labels = []
    for label in new_labels:

        x,y = label

        if label in names:
            edge_names = names[label]
        else:
            edge_names = names[(y, x)]

        for name in edge_names:
            new_label = '.'.join([x,name,y])

            if new_label in labels:
                ordered_labels.append(new_label)
            else:
                new_label = '.'.join([y, name, x])
                ordered_labels.append(new_label)

    return ordered_labels

max_stars_repo_name: christofid/DomainUnderstanding

max_issues_repo_name: christofid/DomainUnderstanding

max_forks_repo_name: christofid/DomainUnderstanding

reason: import networkx


text:
"""Raw Data View: show raw data traces."""

# -----------------------------------------------------------------------------
# Imports
# -----------------------------------------------------------------------------
import numpy as np
import pandas as pd

import bisect

from galry import (Manager, PlotPaintManager, EventProcessor, PlotInteractionManager, Visual,
    QtGui, QtCore, NavigationEventProcessor, PlotVisual, GridVisual, TextVisual, DataNormalizer,
    process_coordinates)
from klustaviewa.views.common import KlustaViewaBindings, KlustaView
from kwiklib.utils import logger as log
from kwiklib.dataio import get_array
from qtools import inthread
from kwiklib.utils.colors import COLORS_COUNT, generate_colors, COLORMAP

__all__ = ['TraceView']

# -----------------------------------------------------------------------------
# Data manager
# -----------------------------------------------------------------------------

class TraceManager(Manager):
    info = {}

    # initialization
    def set_data(self, trace=None, freq=None, channel_height=None, channel_names=None, ignored_channels=None, channel_colors=None, spiketimes=None,
        spikemasks=None, cluster_colors=None, spikeclusters=None, s_before=16, s_after=16):

        # TODO: fix bug where view cannot be opened before file
        # if hasattr(self, 'paintinitialized'):
        #     if self.paintinitialized == True: # we need to clear up some things
        #         pass

        # default settings
        self.max_size = 6000
        self.duration_initial = 10.
        self.default_channel_height = 0.25
        self.channel_height_limits = (0.01, 20.)
        self.nticks = 10
        self.spikes_visible = False

        # these variables will be overwritten after initialization (used to check if init is complete)
        self.slice_ref = (-1, -1) # slice paging
        self.paintinitialized = False # to stop first slice from being loaded until correctly-shaped data drawn
        self.real_data = True # hides grid and painting if we've made up false data of zeros
        self.size = 1

        if trace is None:
            # make up some data to keep the GPU happy, warm, and feeling loved
            trace = np.zeros((self.duration_initial * 2, 1))
            freq = 1

            # don't worry, we won't tell the GPU that it's not actually rendering any useful data, but we need to keep track
            self.real_data = False

        # same with spikes
        if spiketimes is None:
            spiketimes = np.array([0])

        # same with spike masks
        if spikemasks is None:
            spikemasks = np.zeros([0,1])

        if channel_colors is None:
            channel_colors = pd.Series(generate_colors(trace.shape[1]))

        if spikeclusters is None:
            spikeclusters = np.array([0])

        # load initial variables
        self.trace = trace
        self.channel_colors = channel_colors
        self.ignored_channels = ignored_channels
        self.spiketimes = spiketimes
        self.spikemasks = spikemasks.astype(bool)
        self.spikeclusters = spikeclusters
        self.cluster_colors = cluster_colors
        self.freq = freq
        self.totalduration = (self.trace.shape[0] - 1) / self.freq
        self.totalsamples, self.nchannels = self.trace.shape
        self.channels = np.arange(self.nchannels)
        self.s_before = s_before
        self.s_after = s_after

        if channel_height is None:
            channel_height = self.default_channel_height
        else:
            self.default_channel_height = channel_height
        self.channel_height = channel_height

        if channel_names is None:
            channel_names = pd.Series(['ch{0:d}'.format(i) for i in xrange(self.nchannels)])
        self.channel_names = channel_names

        x = np.tile(np.linspace(0., self.totalduration, 2), (self.nchannels, 1))
        y = np.zeros_like(x)+ np.linspace(-1, 1, self.nchannels).reshape((-1, 1))

        self.position, self.shape = process_coordinates(x=x, y=y)

        # activate the grid
        if self.real_data == True:
            self.interaction_manager.get_processor('viewport').update_viewbox()
            self.interaction_manager.activate_grid()

        # register the updater threads
        self.slice_retriever = inthread(SliceRetriever)(impatient=True)
        self.slice_retriever.sliceLoaded.connect(self.slice_loaded)

    def load_correct_slices(self, force=False):
        # dirty hack to make sure that we don't redraw the window until it's been drawn once, otherwise Galry automatically rescales
        if not self.paintinitialized:
            return

        # dur is a paged version of the duration (using e^round(log(duration))) to avoid loading slices for every integer change in zoom level
        dur = np.exp(np.ceil(np.log(self.xlim[1] - self.xlim[0])))
        zoom_index = int(np.round(1 + np.log(self.duration_initial / dur)))
        index = int(np.floor(self.xlim[0] / (dur)))
        i = (index, zoom_index)

        if (i != self.slice_ref) or force==True: # we need to load a new slice
            self.slice_ref = i
            # Find needed slice(s) of data

            xlim_ext = self.get_buffered_viewlimits(self.xlim)
            slice = self.get_viewslice(xlim_ext)

            # this executes in a new thread, and calls slice_loaded when done
            self.slice_retriever.load_new_slice(self.trace, slice, xlim_ext, self.totalduration, self.duration_initial,
                self.spiketimes, self.channel_colors, self.spikes_visible, self.cluster_colors,
                self.spikemasks, self.spikeclusters, self.s_before, self.s_after)

    def get_buffered_viewlimits(self, xlim):
        d = self.xlim[1] - self.xlim[0]
        x0_ext = np.clip(self.xlim[0] - 3 * d, 0, self.totalduration)
        x1_ext = np.clip(self.xlim[1] + 3 * d, 0, self.totalduration)
        return (x0_ext, x1_ext)

    def get_viewslice(self, xlim):
        d = self.xlim[1] - self.xlim[0]
        zoom = max(self.totalduration/ d, 1)
        view_size = self.totalsamples / zoom
        step = int(np.ceil(view_size / self.max_size))

        i0 = np.clip(int(np.round(xlim[0] * self.freq)), 0, self.totalsamples)
        i1 = np.clip(int(np.round(xlim[1] * self.freq)), 0, self.totalsamples)
        return slice(i0, i1, step)

    def get_undersampled_data(self, xlim, slice):
        """
        Arguments:

          * data: a HDF5 dataset of size Nsamples x Nchannels.
          * xlim: (x0, x1) of the desired data view.
        """
        total_size = self.trace.shape[0]

        samples = self.trace[slice, :]

        # Convert the data into floating points.
        samples = np.array(samples, dtype=np.float32)

        # Normalize the data.
        samples *= (1. / 65535)

        # Size of the slice.
        nsamples, nchannels = samples.shape
        # Create the data array for the plot visual.
        M = np.empty((nsamples * nchannels, 2))
        samples = samples.T
        M[:, 1] = samples.ravel()
        # Generate the x coordinates.
        x = np.arange(slice.start, slice.stop, slice.step) / float(total_size - 1)

        x = x * 2 * self.totalduration/ self.duration_initial - 1
        M[:, 0] = np.tile(x, nchannels)

        self.bounds = np.arange(nchannels + 1) * nsamples
        size = self.bounds[-1]
        return M, self.bounds, size

    def slice_loaded(self, samples, bounds, size, slice, color_index, color_index_spikes):

        self.color_index = color_index
        self.color_index_spikes = color_index_spikes
        self.samples = samples
        self.bounds = bounds
        self.size = size

        self.channel_index = np.repeat(self.channels, self.samples.shape[0] / self.nchannels)

        self.position = self.samples

        self.paint_manager.update_slice()
        self.paint_manager.updateGL()

class SliceRetriever(QtCore.QObject):
    sliceLoaded = QtCore.pyqtSignal(object, object, long, object, object, object)

    def __init__(self, parent=None):
        super(SliceRetriever, self).__init__(parent)

    def load_new_slice(self, trace, slice, xlim, totalduration, duration_initial, spiketimes, channel_colors, spikes_visible,
        cluster_colors, spikemasks, spikeclusters, s_before, s_after):

        total_size = trace.shape[0]
        samples = trace[slice, :]

        # Convert the data into floating points.
        samples = np.array(samples, dtype=np.float32)

        # Normalize the data.
        samples *= (1. / 65535)

        # Size of the slice.
        nsamples, nchannels = samples.shape
        # Create the data array for the plot visual.
        M = np.empty((nsamples * nchannels, 2))
        samples = samples.T
        M[:, 1] = samples.ravel()
        # Generate the x coordinates.
        x = np.arange(slice.start, slice.stop, slice.step) / float(total_size - 1)

        x = x * 2 * totalduration/ duration_initial - 1
        M[:, 0] = np.tile(x, nchannels)

        bounds = np.arange(nchannels + 1) * nsamples
        size = bounds[-1]

        color_index = np.repeat(get_array(channel_colors), M.shape[0] / nchannels)

        color_index_spikes = np.full((nchannels, M.shape[0]/nchannels), COLORS_COUNT+1)

        spikestart = bisect.bisect_left(spiketimes, slice.start)
        spikestop = bisect.bisect_right(spiketimes, slice.stop, lo=spikestart) + 1

        spikeclusters = spikeclusters[spikestart:spikestop]
        spikemasks = spikemasks[spikestart:spikestop]
        spiketimes = spiketimes[spikestart:spikestop]
        nds = ((spiketimes - slice.start)/slice.step).astype(int) # nearest displayed sample, rounded to integer

        s_before = max(int(s_before / slice.step), 2)
        s_after = max(int(s_after / slice.step), 2)

        for x in range(0, nds.shape[0]-1):
                color_index_spikes[spikemasks[x], max(nds[x]-s_before, 0):\
                min(nds[x]+s_after, color_index_spikes.shape[1])] = cluster_colors[spikeclusters[x]]

        color_index_spikes = np.ravel(color_index_spikes)

        self.sliceLoaded.emit(M, bounds, size, slice, color_index, color_index_spikes)

# -----------------------------------------------------------------------------
# Visuals
# -----------------------------------------------------------------------------
class TracePaintManager(PlotPaintManager):

    def initialize(self):
        self.add_visual(MultiChannelVisual,
            position=self.data_manager.position,
            name='trace_waveforms',
            shape=self.data_manager.shape,
            channel_height=self.data_manager.channel_height,
            visible=self.data_manager.real_data)

        self.add_visual(GridVisual, name='grid', background_transparent=False,
            letter_spacing=350.,)

        self.data_manager.paintinitialized = True

    def update(self):
        if getattr(self.data_manager, 'paintinitialized', True):
            self.reinitialize_visual(visual='trace_waveforms',
                channel_height=self.data_manager.channel_height,
                position=self.data_manager.position,
                shape=self.data_manager.shape,
                size=self.data_manager.size,
                visible=self.data_manager.real_data)

        self.data_manager.paintinitialized = True

    def update_slice(self):
        if self.data_manager.spikes_visible == True:
                self.set_data(visual='trace_waveforms',
                channel_height=self.data_manager.channel_height,
                position0=self.data_manager.position,
                shape=self.data_manager.shape,
                size=self.data_manager.size,
                channel_index=self.data_manager.channel_index,
                color_index=self.data_manager.color_index_spikes,
                bounds=self.data_manager.bounds,
                visible=self.data_manager.real_data)
        else:
            self.set_data(visual='trace_waveforms',
                channel_height=self.data_manager.channel_height,
                position0=self.data_manager.position,
                shape=self.data_manager.shape,
                size=self.data_manager.size,
                channel_index=self.data_manager.channel_index,
                color_index=self.data_manager.color_index,
                bounds=self.data_manager.bounds,
                visible=self.data_manager.real_data)

class MultiChannelVisual(Visual):
    def initialize(self, color=None, point_size=1.0,
            position=None, shape=None, nprimitives=None,
            color_index=None, channel_height=None,
            options=None, autocolor=1):

        # register the size of the data
        self.size = np.prod(shape)

        # there is one plot per row
        if not nprimitives:
            nprimitives = shape[0]
            nsamples = shape[1]
        else:
            nsamples = self.size // nprimitives

        # register the bounds
        if nsamples <= 1:
            self.bounds = [0, self.size]
        else:
            self.bounds = np.arange(0, self.size + 1, nsamples)

        color = np.vstack((COLORMAP, (0.4, 0.4, 0.4))) # fixed value for non-highlighted traces when spikes are highlighted

        # set position attribute
        self.add_attribute("position0", ndim=2, data=position, autonormalizable=True)

        if color_index is None:
            color_index = np.repeat(np.arange(nprimitives), nsamples)
        color_index = np.array(color_index)

        # if channel_index is None:
        channel_index = np.repeat(np.arange(nprimitives), nsamples)
        channel_index = np.array(channel_index)

        ncolors = color.shape[0]
        ncomponents = color.shape[1]
        color = color.reshape((1, ncolors, ncomponents))

        dx = 1. / ncolors
        offset = dx / 2.

        self.add_texture('colormap', ncomponents=ncomponents, ndim=1, data=color)
        self.add_attribute('color_index', ndim=1, vartype='int', data=color_index)
        self.add_attribute('channel_index', ndim=1, vartype='int', data=channel_index)
        self.add_varying('vindex', vartype='int', ndim=1)
        self.add_uniform('nchannels', vartype='float', ndim=1, data=float(nprimitives))
        self.add_uniform('channel_height', vartype='float', ndim=1, data=channel_height)

        self.add_vertex_main("""
        vec2 position = position0;
        position.y = channel_height * position.y - .9 * (2 * channel_index - (nchannels - 1)) / (nchannels - 1);
        vindex = color_index;
        """)

        self.add_fragment_main("""
        float coord = %.5f + vindex * %.5f;
        vec4 color = texture1D(colormap, coord);
        out_color = color;
        """ % (offset, dx))

        # add point size uniform (when it's not specified, there might be some
        # bugs where its value is obtained from other datasets...)
        self.add_uniform("point_size", data=point_size)
        self.add_vertex_main("""gl_PointSize = point_size;""")

# -----------------------------------------------------------------------------
# Grid
# -----------------------------------------------------------------------------

class GridEventProcessor(EventProcessor):
    def update_axes(self, parameter):

        viewbox = self.interaction_manager.get_processor('viewport').viewbox

        text, coordinates, n = self.get_ticks_text(*viewbox)

        coordinates[:,0] = self.interaction_manager.get_processor('viewport').normalizer.normalize_x(coordinates[:,0])
        coordinates[:,1] = self.interaction_manager.get_processor('viewport').normalizer.normalize_y(coordinates[:,1])

        # here: coordinates contains positions centered on the static
        # xy=0 axes of the screen
        position = np.repeat(coordinates, 2, axis=0)
        position[:2 * n:2,1] = -1
        position[1:2 * n:2,1] = 1
        position[2 * n::2,0] = -1
        position[2 * n + 1::2,0] = 1

        axis = np.zeros(len(position))
        axis[2 * n:] = 1

        self.set_data(visual='grid_lines', position=position, axis=axis)

        coordinates[n:, 0] = -.95
        coordinates[:n, 1] = -.95

        t = "".join(text)
        n1 = len("".join(text[:n]))
        n2 = len("".join(text[n:]))

        axis = np.zeros(n1+n2)
        axis[n1:] = 1

        self.set_data(visual='grid_text', text=text,
            coordinates=coordinates,
            axis=axis)

    def nicenum(self, x, round=False):
        e = np.floor(np.log10(x))
        f = x / 10 ** e
        eps = 1e-6
        if round:
            if f < 1.5:
                nf = 1.
            elif f < 3:
                nf = 2.
            elif f < 7.:
                nf = 5.
            else:
                nf = 10.
        else:
            if f < 1 - eps:
                nf = 1.
            elif f < 2 - eps:
                nf = 2.
            elif f < 5 - eps:
                nf = 5.
            else:
                nf = 10.

        return nf * 10 ** e

    def get_ticks(self, x0, x1):
        x0 = self.interaction_manager.get_processor('viewport').normalizer.unnormalize_x(x0)
        x1 = self.interaction_manager.get_processor('viewport').normalizer.unnormalize_x(x1)
        r = self.nicenum(x1 - x0 - 1e-6, False)
        d = self.nicenum(r / (self.parent.data_manager.nticks - 1), True)
        g0 = np.floor(x0 / d) * d
        g1 = np.ceil(x1 / d) * d
        nfrac = int(max(-np.floor(np.log10(d)), 0))
        return np.arange(g0, g1 + .5 * d, d), nfrac

    def format_number(self, x, nfrac=None):
        if nfrac is None:
            nfrac = 2

        if np.abs(x) < 1e-15:
            return "0"

        # elif np.abs(x) > 1000.001:
        #     return "%.3e" % x

        # regular decimal notation (scientific notation for < 0.001s is not going to be used frequently if at all)
        return ("%." + str(nfrac) + "f") % x

    def get_ticks_text(self, x0, y0, x1, y1):

        ticksx, nfracx = self.get_ticks(x0, x1)
        ticksy = np.linspace(-0.9, 0.9, self.parent.data_manager.nchannels)

        n = len(ticksx)
        text = [self.format_number(x, nfracx) for x in ticksx]
        text += [str(get_array(self.parent.data_manager.channel_names)[y]) for y in reversed(range(self.parent.data_manager.nchannels))]

        # position of the ticks
        coordinates = np.zeros((len(text), 2))
        coordinates[:n, 0] = ticksx
        coordinates[n:, 1] = ticksy
        return text, coordinates, n

class ViewportUpdateProcessor(EventProcessor):
    def initialize(self):
        self.register('Initialize', self.update_viewport)
        self.register('Pan', self.update_viewport)
        self.register('Zoom', self.update_viewport)
        self.register('Reset', self.update_viewport)
        self.register('Animate', self.update_viewport)
        self.register(None, self.update_viewport)

    def update_viewbox(self):

        # normalization viewbox
        self.normalizer = DataNormalizer()
        self.normalizer.normalize((0, -1, self.parent.data_manager.duration_initial, 1))

        nav = self.get_processor('navigation')

        self.viewbox = nav.get_viewbox()

        nav.constrain_navigation = True
        nav.xmin = -1
        nav.xmax = 2 * (self.parent.data_manager.totalduration / self.parent.data_manager.duration_initial) - 1
        nav.sxmin = 1.

        self.parent.data_manager.xlim = ((self.viewbox[0] + 1) / 2. * (self.parent.data_manager.duration_initial),\
        (self.viewbox[2] + 1) / 2. * (self.parent.data_manager.duration_initial))

        # now we know the viewport has been updated, update the grid
        self.interaction_manager.get_processor('grid').update_axes(None)

        # check if we need to load/unload any slices
        self.parent.data_manager.load_correct_slices()

    def update_viewport(self, parameter):
        self.update_viewbox()

# -----------------------------------------------------------------------------
# Interactivity
# -----------------------------------------------------------------------------
class TraceInteractionManager(PlotInteractionManager):
    def initialize(self):
        self.register('ChangeChannelHeight', self.change_channel_height)
        self.register('ToggleSpikeShow', self.toggle_spike_show)
        self.register('Reset', self.reset_channel_height)

    def initialize_default(self, constrain_navigation=None,
        momentum=True,
        ):

        super(PlotInteractionManager, self).initialize_default()
        self.add_processor(NavigationEventProcessor,
            constrain_navigation=constrain_navigation,
            momentum=momentum,
            name='navigation')

        self.add_processor(ViewportUpdateProcessor, name='viewport')
        self.add_processor(GridEventProcessor, name='grid')

    def activate_grid(self):
        self.paint_manager.set_data(visual='grid_lines',
            visible=True)
        self.paint_manager.set_data(visual='grid_text',
            visible=True)
        processor = self.get_processor('grid')
        if processor:
            processor.activate(True)
            processor.update_axes(None)

    def toggle_spike_show(self, parameter):
        if(self.data_manager.spikes_visible==True):
            self.data_manager.spikes_visible=False
        else:
            self.data_manager.spikes_visible=True

        self.paint_manager.update_slice()

    def change_channel_height(self, parameter):
        # get limits
        ll, ul = self.data_manager.channel_height_limits

        # increase/decrease channel height between limits
        if ll <= self.data_manager.channel_height <= ul:
            self.data_manager.channel_height *= (1 + parameter)

        # restore limits to ensure it never exceeds them
        if self.data_manager.channel_height > ul:
            self.data_manager.channel_height = ul
        elif self.data_manager.channel_height < ll:
            self.data_manager.channel_height = ll

        self.paint_manager.set_data(channel_height=self.data_manager.channel_height, visual='trace_waveforms')

    def reset_channel_height(self, parameter):
        self.data_manager.channel_height = self.data_manager.default_channel_height
        self.paint_manager.set_data(channel_height=self.data_manager.channel_height, visual='trace_waveforms')

class TraceBindings(KlustaViewaBindings):
    def initialize(self):
        self.set('Wheel', 'ChangeChannelHeight', key_modifier='Control',
                   param_getter=lambda p: p['wheel'] * .001)

        self.set('KeyPress',
                 'ToggleSpikeShow',
                 key='S')

# -----------------------------------------------------------------------------
# Top-level widget
# -----------------------------------------------------------------------------
class TraceView(KlustaView):

    # Initialization
    # --------------
    def initialize(self):
        self.set_bindings(TraceBindings)
        self.set_companion_classes(
            paint_manager=TracePaintManager,
            interaction_manager=TraceInteractionManager,
            data_manager=TraceManager)

    def set_data(self, *args, **kwargs):
        self.data_manager.set_data(*args, **kwargs)

        # update?
        if self.initialized:
            self.paint_manager.update()
            self.data_manager.load_correct_slices()
            self.updateGL()

    # Save and restore geometry
    # -------------------------
    def save_geometry(self):
        # pref = self.position_manager.get_geometry_preferences()
        # SETTINGS.set('trace_view.geometry', pref)
        pass

    def restore_geometry(self):
        """Return a dictionary with the user preferences regarding geometry
        in the WaveformView."""
        # pref = SETTINGS.get('trace_view.geometry')
        # self.position_manager.set_geometry_preferences(pref)
        pass

    def closeEvent(self, e):
        self.save_geometry()
        super(TraceView, self).closeEvent(e)

max_stars_repo_name: fiath/test

max_issues_repo_name: fiath/test

max_forks_repo_name: fiath/test


text:
"""
Provides access to PCO cameras.

..
    ### BEGIN NODE INFO
    [info]
    name = pco
    version = 1
    description =
    instancename = %LABRADNODE%_pco

    [startup]
    cmdline = %PYTHON3% %FILE%
    timeout = 20

    [shutdown]
    message = 987654321
    timeout = 20
    ### END NODE INFO
"""
import os, sys
from labrad.server import LabradServer, setting
from twisted.internet import reactor
from twisted.internet.error import AlreadyCalled, AlreadyCancelled
from datetime import datetime

import json
import numpy as np
from warnings import warn
import time
import re

sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), '..'))
from server_tools.hardware_interface_server import HardwareInterfaceServer
from cameras.lib import pco

PCO_TRIGGER_MODES = [
    'auto sequence',
    'software trigger',
    'external exposure start & software trigger',
    'external exposure control',
    'external synchronized',
    'fast external exposure control',
    'external CDS control',
    'slow external exposure control',
    'external synchronized HDSDI'
]

PCO_RECORD_MODES = [
    'sequence',
    'sequence non blocking',
    'ring buffer',
    'fifo',
]

PCO_RECORD_UNINIT = 0
PCO_RECORD_READY = 1
PCO_RECORD_RUNNING = 2

POLL_TIME = 1.0 # seconds

class PcoConfigError(Exception):
    """
    An error raised by an issue with the configuration of a PCO camera
    """
    def __init__(self, msg=''):
        super().__init__(msg)

class PcoRecordError(Exception):
    """
    An error raised by an issue with recording an image with a PCO camera
    """
    def __init__(self, msg=''):
        super().__init__(msg)

class PcoSaveError(Exception):
    """
    An error raised by an issue with saving an image with a PCO camera
    """
    def __init__(self, msg=''):
        super().__init__(msg)

class PcoServer(HardwareInterfaceServer):
    """Provides access to PCO cameras.

    Uses a modified version of the PCO Python library, found in :code:`cameras/lib/pco`. For more information, refer to the `PCO SDK <https://www.pco.de/fileadmin/fileadmin/user_upload/pco-manuals/pco.sdk_manual.pdf>`_ and `PCO Python library <https://pypi.org/project/pco/>`_ documentation.
    """
    name = '%LABRADNODE%_pco'
    cam_info = {}
    callbacks = {}

    path_base = "K:/data/{}/Pixelfly/"
    pattern = r"pixelfly_(\d+).npz"
    fname_base = "pixelfly_{}.npz"

    n_images = 0
    saved = False

    @staticmethod
    def get_camera_identifier(cam):
        """
        get_camera_identifier(cam)

        Args:
            cam (pco.Camera()): A PCO camera object

        Returns:
            str: Returns a string containing the camera type and serial number of the camera.
        """
        name = cam.sdk.get_camera_name()['camera name']
        serial = cam.sdk.get_camera_type()['serial number']
        return name + " ({})".format(serial)

    def refresh_available_interfaces(self):
        """
        refresh_available_interfaces(self)

        Fill :code:`self.interfaces` with available connections using PCO dll
        """
        for k, cam in self.interfaces.items():
            try:
                key = self.get_camera_identifier(cam)
                print('{} is still connected'.format(k))
            except:
                print('{} disconnected'.format(k))
                try:
                    cam.close()
                    del self.interfaces[key]
                    del self.cam_info[key]
                except Exception as e:
                    warn("Error closing {}: {}".format(k, e))

        while True:
            # pco.Camera() gets next available camera
            try:
                cam = pco.Camera()
                key = self.get_camera_identifier(cam)
                self.interfaces[key] = cam
                self.cam_info[key] = {
                    'caps': cam.sdk.get_camera_description(),'record_status': PCO_RECORD_UNINIT
                }
                print('connected to pco {}'.format(key))
            except ValueError: # If no camera found
                break
            except Exception as e:
                warn(e)
                break

    # Overwriting the version in HardwareInterfaceServer
    # to avoid calling refresh_available_interfaces on Exception
    def call_if_available(self, f, c, *args, **kwargs):
        try:
            interface = self.get_interface(c)
            ans = getattr(interface, f)(*args, **kwargs)
            return ans
        except:
            self.interface = self.get_interface(c)
            return getattr(interface, f)

    @setting(2)
    def close_camera(self, c):
        """close_camera(self, c)

        Close the PCO camera opened via :meth:`~server_tools.hardware_interface_server.HardwareInterfaceServer.select_interface`.

        Args:
            c: Labrad context
        """
        try:
            self.call_if_available('close', c)
            del self.interfaces[c['address']]
        except KeyError as e:
            warn('Camera not found: {}'.format(e))

    def _get_config(self, c):
        return self.call_if_available('configuration', c)

    @setting(3, returns='s')
    def get_config(self, c):
        """get_config(self, c)

        Get the camera configuration opened via :meth:`~server_tools.hardware_interface_server.HardwareInterfaceServer.select_interface`.

        Args:
            c: Labrad context

        Returns:
            str: JSON-dumped configuration dictionary
        """
        return json.dumps(self._get_config(c))

    def set_cam_config(self, c, key, val):
        if self._is_running(c):
            raise(PcoConfigError("Can't update configuration of {} while camera is recording.".format(c['address'])))
        else:
            cam = self.get_interface(c)
            config = cam.configuration
            config.update({key: val})
            cam.configuration = config

    @setting(4, returns='s')
    def get_capabilities(self, c):
        """
        get_capabilities(self, c)

        Gets a description of the camera, including available image sizes, readout rates, etc.

        Args:
            c: Labrad context

        Returns:
            str: JSON-dumped camera description dictionary
        """
        return json.dumps(self.cam_info[c['address']]['caps'])

    @setting(5, exposure='v', returns='v')
    def set_exposure(self, c, exposure):
        """
        set_exposure(self, c, exposure)

        Sets the camera exposure. If the specified exposure is outside the camera's exposure range, clips to the range and warns the user.

        Note that if interframing is enabled, the provided exposure is only used for the first frame, while the second has an exposure of 74 ms (for the pixelfly camera).

        Args:
            c: Labrad context
            exposure (numeric): Exposure in seconds.

        Returns:
            float: the camera's actual exposure setting in seconds.
        """
        caps = self.cam_info[c['address']]['caps']
        min_exp = caps['Min Expos DESC']*1e-9
        max_exp = caps['Max Expos DESC']*1e-3

        if exposure < min_exp:
            warn("Requested exposure {} is too short; setting to minimum: {}".format(exposure, min_exp))
            exposure = min_exp
        elif exposure > max_exp:
            warn("Requested exposure {} is too long; setting to maximum: {}".format(exposure, max_exp))
            exposure = max_exp
        self.set_cam_config(c, 'exposure time', exposure)
        return exposure

    ### Set ROI not supported on pixelfly!!! ###
    # @setting(6, xmin='i', xmax='i', ymin='i', ymax='i', returns='s')
    # def set_roi(self, c, xmin=None, ymin=None, xmax=None, ymax=None):
    #     caps = self.cam_info[c['address']]['caps']
    #     cam_xmin = cam_ymin = 1
    #     cam_xmax = caps['max. horizontal resolution standard']
    #     cam_ymax = caps['max. vertical resolution standard']

    #     if xmin is None:
    #         xmin = cam_xmin
    #     if ymin is None:
    #         ymin = cam_ymin
    #     if xmax is None:
    #         xmax = cam_xmax
    #     if ymax is None:
    #         ymax = cam_ymax

    #     xmin = min(max(cam_xmin, xmin), cam_xmax)
    #     xmax = max(min(cam_xmax, xmax), xmin)
    #     ymin = min(max(cam_ymin, ymin), cam_ymax)
    #     ymax = max(min(cam_ymax, ymax), ymin)

    #     self.set_cam_config(c, 'roi', [xmin, ymin, xmax, ymax])
    #     config = self.get_config(c)
    #     return json.dumps({'roi': config['roi']})

    @setting(7, returns='*i')
    def get_readout_rates(self, c):
        """get_readout_rates(self, c)

        Gets the possible readout rates for the selected camera, in pixels per second.

        Args:
            c: Labrad context

        Returns:
            [int]: the possible readout rates for the camera, in pixels per second
        """
        rates = self.cam_info[c['address']]['caps']['pixel rate']
        nonzero = [i for i in rates if i > 0]
        return nonzero

    @setting(8, readout='i', returns='i')
    def set_readout_rate(self, c, readout):
        """
        set_readout_rate(self, c, readout)

        Sets the readout rate for the selected camera, in pixels per second.

        Args:
            c: Labrad context
            readout (int): the readout rates for the camera, in pixels per second. Must be one of the values returned by :meth:`get_readout_rates`

        Returns:
            int: the camera's actual readout rate, in pixels per second
        """
        rates = self.get_readout_rates(c)
        if readout in rates:
            self.set_cam_config(c, 'pixel rate', readout)
        else:
            raise(PcoConfigError("Readout rate \"{}\" not supported on {}.".format(readout, c['address'])))
        return self._get_config(c)['pixel rate']

    @setting(9, returns='*s')
    def get_trigger_modes(self, c):
        """
        get_trigger_modes(self, c)

        Returns a list of the possible trigger modes for PCO cameras. Not all trigger modes may be compatible with the selected camera.

        Args:
            c: Labrad context

        Returns:
            [str]: a list of the possible trigger modes for PCO cameras.
        """
        return PCO_TRIGGER_MODES

    @setting(10, mode='s', returns='s')
    def set_trigger_mode(self, c, mode):
        """
        set_trigger_mode(self, c, mode)

        Sets the trigger mode for the selected camera.

        Args:
            c: Labrad context
            mode (str): The trigger mode for the camera. Must be one of the values returned by :meth:`get_trigger_modes`. Not all trigger modes work for all cameras.

        Returns:
            str: the camera's actual trigger mode
        """
        if mode in PCO_TRIGGER_MODES:
            try:
                self.set_cam_config(c, 'trigger', mode)
            except PcoConfigError as e:
                raise(e)
            except Exception as e:
                raise(PcoConfigError("Trigger mode \"{}\" not supported on {}.".format(mode, c['address'])))
        else:
            warn("Trigger mode \"{}\" not found; supported modes: {}.".format(mode, PCO_TRIGGER_MODES))
        return self._get_config(c)['trigger']

    @setting(11, xbins='i', ybins='i', returns='*i')
    def set_binning(self, c, xbins, ybins=None):
        """
        set_binning(self, c, xbins, ybins=None)

        Sets the selected camera's binning mode.

        Args:
            c: Labrad context
            xbins (int): horizontal bin size
            ybins (int, optional): vertical bin size. Defaults to None, in which case it is set equal to xbins.

        Returns:
            [int]: the camera's actual horizontal and vertical bin sizes
        """
        if ybins is None:
            ybins = xbins
        try:
            self.set_cam_config(c, 'binning', [xbins, ybins])
        except PcoConfigError as e:
            raise(e)
        except Exception:
            raise(PcoConfigError("Binning [{}, {}] is not supported on {}".format(xbins, ybins, c['address'])))
        return self._get_config(c)['binning']

    @setting(12, returns='b')
    def get_interframing_enabled(self, c):
        """
        get_interframing_enabled(self, c)

        Checks whether interframing mode is enabled for the selected camera.

        Args:
            c: Labrad context

        Returns:
            bool: whether interframing mode is enabled for the selected camera
        """
        sdk = self.call_if_available('sdk', c)
        try:
            s = sdk.get_double_image_mode()['double image']
            return 'on' in s
        except Exception:
            warn('Interframing mode not available for {}'.format(c['address']))
            return False

    @setting(13, enable='b', returns='b')
    def set_interframing_enabled(self, c, enable):
        """
        set_interframing_enabled(self, c, enable)

        Sets whether interframing mode is enabled for the selected camera.

        Args:
            c: Labrad context
            enable (bool): [description]

        Returns:
            bool: whether interframing mode is actually enabled for the selected camera
        """
        sdk = self.call_if_available('sdk', c)
        s = 'on' if enable else 'off'

        if self._is_running(c):
            raise(PcoConfigError("Can't change interframing of {} while camera is recording.").format(c['address']))
        else:
            try:
                sdk.set_double_image_mode(s)
                return 'on' in sdk.get_double_image_mode()['double image']
            except:
                warn('Interframing mode not available for {}'.format(c['address']))
                return False

    def _is_running(self, c):
        status = self.cam_info[c['address']]['record_status']
        return status == PCO_RECORD_RUNNING

    @setting(14, returns='b')
    def is_running(self, c):
        """
        is_running(self, c)

        Checks whether the selected camera is currently recording.

        Args:
            c: Labrad context

        Returns:
            bool: whether the selected camera is currently recording
        """
        try:
            status = self._get_status(c)['is running']
            self.cam_info[c['address']]['record_status'] = PCO_RECORD_RUNNING if status else PCO_RECORD_READY
            return status
        except PcoRecordError:
            self.cam_info[c['address']]['record_status'] = PCO_RECORD_UNINIT
            warn("Recording not initialized.")
            return False

    # @setting(15, n_images='i', mode='s')
    def start_record(self, c, n_images=1, mode='sequence non blocking'):
        """
        start_record(self, c, n_images=1, mode='sequence non blocking')

        Starts recording images on the selected camera.

        Args:
            c: Labrad context
            n_images (int, optional): The number of images to return. Defaults to 1.
            mode (str, optional): The recording mode; see `PCO Python library <https://pypi.org/project/pco/>`_ documentation for options. Defaults to 'sequence non blocking'.
        """
        self.call_if_available('record', c, n_images, mode)
        print("Recording {} images in mode `{}` started".format(n_images, mode))
        time.sleep(0.01)
        self.is_running(c)

    @setting(19, returns='i')
    def available_images(self, c):
        """
        available_images(self, c)

        Returns the number of acquired images. Images with interframing count as one.

        Args:
            c: Labrad context

        Returns:
            int: Number of acquired images.
        """
        return self._get_status(c)['dwProcImgCount']

    def check_roi(self, c, xmin, ymin, xmax, ymax):
        """
        check_roi(self, c, xmin, ymin, xmax, ymax)

        Checks that the roi defined by (xmin, ymin, xmax, ymax) is allowed for the currently selected camera.

        Note that the camera pixels are 1-indexed in the PCO software.

        Args:
            c: Labrad context
            xmin (int): First selected horizontal pixel, 1-indexed
            ymin (int): Last selected horizontal pixel
            xmax (int): First selected vertical pixel, 1-indexed
            ymax (int): Last selected vertical pixel (inclusive)

        Returns:
            (int, int, int, int): Bounds-checked roi (xmin, ymin, xmax, ymax)
        """
        caps = self.cam_info[c['address']]['caps']
        cam_xmin = cam_ymin = 1
        cam_xmax = caps['max. horizontal resolution standard']
        cam_ymax = caps['max. vertical resolution standard']

        out_xmin = min(max(cam_xmin, xmin), cam_xmax)
        out_xmax = max(min(cam_xmax, xmax), cam_xmin)
        out_ymin = min(max(cam_ymin, ymin), cam_ymax)
        out_ymax = max(min(cam_ymax, ymax), cam_ymin)

        if out_xmin > out_xmax:
            temp = out_xmax
            out_xmax = out_xmin
            out_xmin = temp
        if out_ymin > out_ymax:
            temp = out_ymax
            out_ymax = out_ymin
            out_ymin = temp

        ins = (xmin, ymin, xmax, ymax)
        outs = (out_xmin, out_ymin, out_xmax, out_ymax)

        if any(i != o for (i, o) in zip(ins, outs)):
            warn("Requested roi {} is invalid; setting to {}".format(ins, outs))
        return outs

    def get_images(self, c, roi=None):
        """
        get_images(self, c)

        Provides the images stored in the camera buffer, if any. If :meth:`record` has not been run, throws a :class:`PcoRecordError`. If no images are available, returns empty metadata and image array.

        Args:
            c: Labrad context
            roi ((int), optional): A 4-tuple of integers (xmin, ymin, xmax, ymax) representing the bounds of the image to be saved. Defaults to None, in which case the whole image is saved.

        Returns:
            ([numpy array]): A list of numpy arrays of the images.
        """
        if self.available_images(c) > 0:
            res = self.call_if_available('images', c, roi=roi)
            (images, _) = res
            out = images
        else:
            warn("No images acquired.")
            out = []
        return out

    # @setting(16, path='s', n_images='i', roi='*i', returns='s')
    def save_images(self, c, path, n_images, roi=None):
        """
        save_images(self, c, path, n_images, roi)

        Saves the latest :code:`n_image` images if available. If :meth:`record` has not been run, throws a :class:`PcoRecordError`. If fewer than :code:`n_image` have been acquired, throws a :class:`PcoSaveError`.

        The images are saved as a compressed `npz <https://numpy.org/doc/stable/reference/generated/numpy.lib.format.html#module-numpy.lib.format>`_ file with fields "meta" containing a zero-dimensional array with a metadata dictionary (stored pickled) and a 3-dimensional integer ndarray "data" of dimension (n_images (\*2 if interframing enabled), y dimension, x dimension) containing the images.

        Args:
            c: Labrad context
            path (str): Path to saved images. The extension is automatically changed to ".npz"
            n_images (int): Number of images to save. An image taken with interframing enabled will only count as one here, but will be saved as two images, one for each frame.
            roi ((int), optional): A 4-tuple of integers (xmin, ymin, xmax, ymax) representing the bounds of the image to be saved. Defaults to None, in which case the whole image is saved.

        Returns:
            str: Path to saved image
        """
        if roi is not None:
            if len(roi) != 4:
                roi = None
            else:
                roi = self.check_roi(c, *roi)
        images = self.get_images(c, roi)

        if len(images) < n_images:
            raise(PcoSaveError("Fewer than {} images were recorded; only got {} images").format(n_images, len(images)))
        if len(images) > n_images:
            images = images[-n_images:]

        interframing_enabled = self.get_interframing_enabled(c)
        if interframing_enabled:
            new_images = []
            for image in images:
                frame_height = image.shape[0] // 2
                new_images.append(image[:frame_height, :])
                new_images.append(image[frame_height:, :])
            images = new_images

        images = np.array(images)

        config = self._get_config(c)
        metadata = {
            'images': n_images * (2 if interframing_enabled else 1),
            'interframing': 'on' if interframing_enabled else 'off',
            'exposure': config['exposure time'],
            'acquire': config['acquire'],
            'binning': config['binning'],
            'roi': roi if roi is not None else config['roi'],
            'readout': config['pixel rate'],
            'trigger': config['trigger'],
            'timestamp': time.strftime("%H:%M:%S", time.localtime())
        }

        # Define a temporary path to avoid conflicts when writing file
		# Otherwise, fitting program autoloads the file before writing is complete
        path = os.path.splitext(path)[0]+".npz"
        path_temp = path + "_temp"
        with open(path_temp, 'wb') as f:
            np.savez_compressed(f, data=images, meta=metadata)
        # Once file is written, rename to the correct filename
        os.rename(path_temp, path)
        return path

    def _get_status(self, c):
        try:
            rec = self.call_if_available('rec', c)
            status = rec.get_status()
            return status
        except:
            raise(PcoRecordError("Recording not started!"))

    @setting(17, returns='s')
    def get_status(self, c):
        """
        get_status(self, c)

        Gets the recording status of the current camera. Returns an empty JSON if recording is not initialized.

        Args:
            c: Labrad context

        Returns:
            str: JSON-dumped recording status
        """
        try:
            out = self._get_status(c)
        except PcoRecordError as e:
            warn("Recording not initialized.")
            out = {}
        return json.dumps(out)

    @setting(18)
    def stop_record(self, c):
        """
        stop_record(self, c)

        Stop recording on the current camera.

        Args:
            c: Labrad context
        """

        self.call_if_available('stop', c)

        # Try to cancel poll_for_images call
        try:
            self.callbacks[c['address']].cancel()

            still_running = self.is_running(c) # sets self.cam_info[c['address']]['record_status']
            if still_running:
                raise(PcoRecordError("Problem stopping record."))
        except KeyError: # self.record_and_save never called
            pass
        except AlreadyCalled: # Callback already finished
            pass
        except AlreadyCancelled: # Callback already cancelled
            pass

    @setting(20, path='s', n_images='i', mode='s', roi='*i')
    def record_and_save(self, c, path, n_images=1, mode='sequence non blocking', roi=None, timeout=None):
        """
        record_and_save(self, c, path, n_images=1, mode='sequence non blocking', roi=None, timeout=None)

        Records and saves a series of images. Stops recording when done. Non-blocking, but must be stopped with :func:`stop_record` if the configuration must be set before it completes.

        Args:
            c: Labrad context
            path (str): Path to saved images. The extension is automatically changed to ".npz"
            n_images (int, optional): The number of images to record and save. An image taken with interframing enabled will only count as one here, but will be saved as two images, one for each frame. Defaults to 1.
            mode (str, optional): The recording mode; see `PCO Python library <https://pypi.org/project/pco/>`_ documentation for options. Defaults to 'sequence non blocking'.
            roi ((int), optional): A 4-tuple of integers (xmin, ymin, xmax, ymax) representing the bounds of the image to be saved. Defaults to None, in which case the whole image is saved.
            timeout (float, optional): The time, in seconds, before acquisition is cancelled and an error is thrown. Defaults to None.
        """
        self.n_images = 0
        self.saved = False

        if not self._is_running(c):
            self.start_record(c, n_images=n_images, mode=mode)
            self.callbacks[c['address']] = reactor.callLater(POLL_TIME, self.poll_for_images, c, path, n_images, roi, timeout, datetime.now())

    def poll_for_images(self, c, path, n_images, roi, timeout, start_time):
        if self.saved:
            return
        n_old = self.n_images
        self.n_images = self.available_images(c)
        if self.n_images != n_old:
            print("Polling for images, have {}".format(self.n_images))
        timed_out = timeout is not None and (datetime.now() - start_time).TotalSeconds > timeout
        if self.available_images(c) >= n_images:
            print("Saving images!")
            self.saved = True
            self.save_images(c, path, n_images, roi=roi)
            self.stop_record(c)
        elif not timed_out:
            reactor.callLater(POLL_TIME, self.poll_for_images, c, path, n_images, roi, timeout, start_time)
        else:
            raise(PcoRecordError("record_and_save for {} timed out after {} seconds".format(c['address'], timeout)))

    @setting(21, returns='s')
    def get_fname(self, c):
        """get_fname(self, c)

        Gets the filename to save the next image

        Args:
            c: Labrad context

        Returns:
            str: the filename to save the next image
        """
        path = self.path_base.format(datetime.now().strftime('%Y/%m/%Y%m%d'))
        if not os.path.exists(path):
            os.makedirs(path)
        file_number = 0
        for f in os.listdir(path):
            match = re.match(self.pattern, f)
            if match:
                file_number = max(file_number, 1+int(match.groups()[0]))
        path += self.fname_base.format(file_number)
        return path

    def stopServer(self):
        """
        stopServer(self)

        Closes camera connections and shuts down the Labrad server.
        """
        for cam in self.interfaces.values():
            try:
                cam.stop()
            except Exception as e:
                warn(e)
        super().stopServer()

    # @setting(6, timeout='v', returns='v')
    # def timeout(self, c, timeout=None):
    #     """Sets the timeout associated with the interface

    #     Args:
    #         c: The LabRAD context
    #         timeout (numeric, optional): The timeout for the interface in seconds. Defaults to None.

    #     Returns:
    #         The timeout in seconds
    #     """
    #     interface = self.get_interface(c)
    #     if timeout is not None:
    #         interface.timeout = timeout
    #     return interface.timeout

if __name__ == '__main__':
    from labrad import util
    util.runServer(PcoServer())