import time

import cv2
import numpy as np
import torch
from mmcv.runner import get_dist_info

from ..builder import PIPELINES

@PIPELINES.register_module()
class SelectRays:
    """random select rays when training
    Args:
        keys (Sequence[str]): Required keys to be converted.
    """
    def __init__(self,
                 enable=True,
                 sel_n=1024,
                 precrop_iters=0,
                 precrop_frac=0.5,
                 include_radius=False,
                 **kwargs):
        self.enable = enable
        self.precrop_iters = precrop_iters
        self.precrop_frac = precrop_frac
        self.kwargs = kwargs
        self.sel_n = sel_n
        self.include_radius = include_radius

    def __call__(self, results):
        """random select rays when training, support precrop
        Args:
            results (dict): The resulting dict to be modified and passed
                to the next transform in pipeline.
        """
        if self.enable:
            H, W, K = self.kwargs['H'], self.kwargs['W'], self.kwargs['K']
            if self.precrop_iters != 0 and results[
                    'iter_n'] < self.precrop_iters:
                # print(results['iter_n'], "precrop now!", flush=True)
                # 在blender数据集的train时，靠前的iter，只取中间部分训练
                dH = int(H // 2 * self.precrop_frac)
                dW = int(W // 2 * self.precrop_frac)
                coords = torch.stack(
                    torch.meshgrid(
                        torch.linspace(H // 2 - dH, H // 2 + dH - 1, 2 * dH),
                        torch.linspace(W // 2 - dW, W // 2 + dW - 1, 2 * dW)),
                    -1)
            else:
                coords = torch.stack(
                    torch.meshgrid(torch.linspace(0, H - 1, H),
                                   torch.linspace(0, W - 1, W)),
                    -1)  # (H, W, 2)
            coords = torch.reshape(coords, [-1, 2])  # (H * W, 2)

            rank, _ = get_dist_info(
            )  # to aviod sampling same rays over different gpu cards in ddp
            np.random.seed(
                int(time.time() + rank)
            )  # fix a bug, for detials please ref to https://github.com/pytorch/pytorch/issues/5059

            select_inds = np.random.choice(coords.shape[0],
                                           size=[self.sel_n],
                                           replace=False)  # (N_rand,)
            select_coords = coords[select_inds].long()  # (N_rand, 2)
            results['rays_o'] = results['rays_o'][
                select_coords[:, 0], select_coords[:, 1]]  # (N_rand, 3)
            results['rays_d'] = results['rays_d'][
                select_coords[:, 0], select_coords[:, 1]]  # (N_rand, 3)
            results['target_s'] = results['target_s'][
                select_coords[:, 0], select_coords[:, 1]]  # (N_rand, 3)
            if self.include_radius:
                results['radii'] = results['radii'][
                    select_coords[:, 0], select_coords[:, 1]]  # (N_rand, 1)
        return results

    def __repr__(self):
        return '{}:random select rays when training'.format(
            self.__class__.__name__)

@PIPELINES.register_module()
class NBSelectRays:
    """random select rays when training
    Args:
        keys (Sequence[str]): Required keys to be converted.
    """
    def __init__(self,
                 enable=True,
                 sel_n=1024,
                 sel_all=False,
                 sel_rgb=True,
                 **kwargs):
        self.enable = enable
        self.kwargs = kwargs
        self.sel_n = sel_n
        self.sel_all = sel_all
        self.sel_rgb = sel_rgb

    @staticmethod
    def get_bound_2d_mask(bounds, K, pose, H, W):
        min_x, min_y, min_z = bounds[0]
        max_x, max_y, max_z = bounds[1]
        corners_3d = np.array([
            [min_x, min_y, min_z],
            [min_x, min_y, max_z],
            [min_x, max_y, min_z],
            [min_x, max_y, max_z],
            [max_x, min_y, min_z],
            [max_x, min_y, max_z],
            [max_x, max_y, min_z],
            [max_x, max_y, max_z],
        ])

        def project(xyz, K, RT):
            xyz = np.dot(xyz, RT[:, :3].T) + RT[:, 3:].T
            xyz = np.dot(xyz, K.T)
            xy = xyz[:, :2] / xyz[:, 2:]
            return xy

        corners_2d = project(corners_3d, K, pose)
        corners_2d = np.round(corners_2d).astype(int)

        mask = np.zeros((H, W), dtype=np.uint8)
        cv2.fillPoly(mask, [corners_2d[[0, 1, 3, 2, 0]]], 1)
        cv2.fillPoly(mask, [corners_2d[[4, 5, 7, 6, 5]]], 1)
        cv2.fillPoly(mask, [corners_2d[[0, 1, 5, 4, 0]]], 1)
        cv2.fillPoly(mask, [corners_2d[[2, 3, 7, 6, 2]]], 1)
        cv2.fillPoly(mask, [corners_2d[[0, 2, 6, 4, 0]]], 1)
        cv2.fillPoly(mask, [corners_2d[[1, 3, 7, 5, 1]]], 1)
        return mask

    @staticmethod
    def get_near_far(bounds, ray_o, ray_d):
        """calculate intersections with 3d bounding box."""
        norm_d = np.linalg.norm(ray_d, axis=-1, keepdims=True)
        viewdir = ray_d / norm_d
        viewdir[(viewdir < 1e-5) & (viewdir > -1e-10)] = 1e-5
        viewdir[(viewdir > -1e-5) & (viewdir < 1e-10)] = -1e-5
        tmin = (bounds[:1] - ray_o[:1]) / viewdir
        tmax = (bounds[1:2] - ray_o[:1]) / viewdir
        t1 = np.minimum(tmin, tmax)
        t2 = np.maximum(tmin, tmax)
        near = np.max(t1, axis=-1)
        far = np.min(t2, axis=-1)
        mask_at_box = near < far
        near = near[mask_at_box] / norm_d[mask_at_box, 0]
        far = far[mask_at_box] / norm_d[mask_at_box, 0]
        return near, far, mask_at_box

    def sample_rays(self, results, bounds, bound_mask, human_mask):
        # sample pixels and calculate the ray-box intersections
        ray_o_list = []
        ray_d_list = []
        rgb_list = []
        near_list = []
        far_list = []

        nsampled_rays = 0
        while nsampled_rays < self.sel_n:
            n_body = int((self.sel_n - nsampled_rays) * 0.5)
            n_rand = self.sel_n - nsampled_rays - n_body

            # sample rays on body
            coord_body = np.argwhere(human_mask != 0)
            coord_body = coord_body[np.random.randint(0, len(coord_body),
                                                      n_body)]

            # sample rays in the bound mask
            coord = np.argwhere(bound_mask == 1)
            coord = coord[np.random.randint(0, len(coord), n_rand)]
            coord = np.concatenate([coord_body, coord], axis=0)

            # calculate the ray info
            ray_o_ = results['rays_o'][coord[:, 0], coord[:, 1]]
            ray_d_ = results['rays_d'][coord[:, 0], coord[:, 1]]
            if self.sel_rgb:
                rgb_ = results['img'][coord[:, 0], coord[:, 1]]
            near_, far_, mask_at_box = self.get_near_far(
                bounds, ray_o_, ray_d_)

            ray_o_list.append(ray_o_[mask_at_box])
            ray_d_list.append(ray_d_[mask_at_box])
            rgb_list.append(rgb_[mask_at_box])
            near_list.append(near_)
            far_list.append(far_)
            nsampled_rays += len(near_)

        results['rays_o'] = np.concatenate(ray_o_list).astype(np.float32)
        results['rays_d'] = np.concatenate(ray_d_list).astype(np.float32)
        if self.sel_rgb:
            results['target_s'] = np.concatenate(rgb_list).astype(np.float32)
        results['near'] = np.concatenate(near_list).astype(np.float32)[:, None]
        results['far'] = np.concatenate(far_list).astype(np.float32)[:, None]

        return results

    def select_all_rays(self, results, bounds):
        src_shape = results['rays_d'].shape
        results['src_shape'] = torch.tensor(src_shape)

        ray_o = results['rays_o'].reshape(-1, 3).astype(np.float32)
        ray_d = results['rays_d'].reshape(-1, 3).astype(np.float32)
        near, far, mask_at_box = self.get_near_far(bounds, ray_o, ray_d)
        near = near.astype(np.float32)
        far = far.astype(np.float32)
        ray_o = ray_o[mask_at_box]
        ray_d = ray_d[mask_at_box]

        results['rays_o'] = ray_o.astype(np.float32)
        results['rays_d'] = ray_d.astype(np.float32)
        if self.sel_rgb:
            rgb = results['img'].reshape(-1, 3).astype(np.float32)
            rgb = rgb[mask_at_box]
            results['target_s'] = rgb.astype(np.float32)
        results['near'] = near.astype(np.float32)[:, None]
        results['far'] = far.astype(np.float32)[:, None]
        results['mask_at_box'] = mask_at_box

        return results

    def __call__(self, results):
        """random select rays when training, support precrop
        Args:
            results (dict): The resulting dict to be modified and passed
                to the next transform in pipeline.
        """
        if self.enable:
            # calculate the 3D box that bounds the human
            smpl_verts = results['smpl_verts']
            min_xyz = np.min(smpl_verts, axis=0) - 0.05
            max_xyz = np.max(smpl_verts, axis=0) + 0.05
            bounds = np.stack([min_xyz, max_xyz], axis=0)

            # generate regions for sampling
            cfg = results['cfg']
            if cfg.mode == 'render':
                H, W = cfg.render_H, cfg.render_W
            else:
                H, W = results['img'].shape[:2]
            K, R, T = results['cam_K'], results['cam_R'], results['cam_T']
            pose = np.concatenate([R, T], axis=1)
            bound_mask = self.get_bound_2d_mask(bounds, K, pose, H, W)

            if self.sel_all:
                results = self.select_all_rays(results, bounds)
            else:
                human_mask = results['msk'] * bound_mask
                results = self.sample_rays(results, bounds, bound_mask,
                                           human_mask)

        return results

    def __repr__(self):
        return '{}:random select rays when training'.format(
            self.__class__.__name__)

@PIPELINES.register_module()
class PerturbZvals:
    """apply perturb to zvals
    Args:
        keys (Sequence[str]): Required keys to be converted.
    """
    def __init__(self, enable=True, **kwargs):
        self.enable = enable

    def __call__(self, results):
        """get intervals between samples
        Args:
            results (dict): The resulting dict to be modified and passed
                to the next transform in pipeline.
        """
        if self.enable:
            z_vals = results['z_vals']
            # get intervals between samples
            mids = .5 * (z_vals[..., 1:] + z_vals[..., :-1])
            upper = torch.cat([mids, z_vals[..., -1:]], -1)
            lower = torch.cat([z_vals[..., :1], mids], -1)
            t_rand = torch.rand(z_vals.shape).to(z_vals.device)
            results['z_vals'] = lower + (upper - lower) * t_rand
        return results

    def __repr__(self):
        return '{}:apply perturb to zvals'.format(self.__class__.__name__)

@PIPELINES.register_module()
class RandomBGColor:
    """random set background color, used in ngp
    Args:
        keys (Sequence[str]): Required keys to be converted.
    """
    def __init__(self, enable=True, **kwargs):
        self.enable = enable
        self.kwargs = kwargs

    def __call__(self, results):
        """BatchSlice
        Args:
            results (dict): The resulting dict to be modified and passed
                to the next transform in pipeline.
        """
        if self.enable:
            alpha = results['alpha']
            target_s = results['target_s']
            bg_color = np.random.rand(*list(results['target_s'].shape))
            # bg_color = np.zeros(list(results['target_s'].shape))
            target_s = target_s * alpha + bg_color * (1 - alpha)
            results['target_s'] = target_s.astype(np.float32)
            results['bg_color'] = bg_color.astype(np.float32)
        return results

    def __repr__(self):
        return '{}:sample a batch of rays from all rays'.format(
            self.__class__.__name__)


from PySide6 import QtCore, QtWidgets

from numbers import Number

from cmlibs.zinc.element import Element
from cmlibs.zinc.glyph import Glyph
from cmlibs.zinc.graphics import Graphics, GraphicsStreamlines, Graphicslineattributes
from cmlibs.zinc.scenecoordinatesystem import SCENECOORDINATESYSTEM_LOCAL, ScenecoordinatesystemEnumFromString, ScenecoordinatesystemEnumToString
from cmlibs.zinc.spectrum import Spectrum
from cmlibs.zinc.status import OK as ZINC_OK

from cmlibs.argon.argonlogger import ArgonLogger
from cmlibs.argon.settings.mainsettings import FLOAT_STRING_FORMAT

from cmlibs.widgets.fieldconditions import *
from cmlibs.widgets.ui.ui_graphicseditorwidget import Ui_GraphicsEditorWidget

DOMAIN_TYPE_ENUM = [Field.DOMAIN_TYPE_POINT, Field.DOMAIN_TYPE_NODES, Field.DOMAIN_TYPE_DATAPOINTS,
                    Field.DOMAIN_TYPE_MESH1D, Field.DOMAIN_TYPE_MESH2D, Field.DOMAIN_TYPE_MESH3D, Field.DOMAIN_TYPE_MESH_HIGHEST_DIMENSION]
POINT_SAMPLING_DOMAIN_TYPE_ENUM = [Field.DOMAIN_TYPE_MESH1D, Field.DOMAIN_TYPE_MESH2D,
                                   Field.DOMAIN_TYPE_MESH3D, Field.DOMAIN_TYPE_MESH_HIGHEST_DIMENSION]

def faceTypeEnumFromString(enumString):
    enumString = enumString.replace('_=_', '_')
    return Element.FaceTypeEnumFromString(enumString)

def faceTypeEnumToString(faceTypeEnum):
    enumString = Element.FaceTypeEnumToString(faceTypeEnum)
    if not enumString:
        return None
    enumString = enumString.replace('_', ' = ')
    return enumString

class GraphicsEditorWidget(QtWidgets.QWidget):

    def __init__(self, parent=None):
        """
        Call the super class init functions
        """
        QtWidgets.QWidget.__init__(self, parent)
        self._graphics = None
        self._isRangeIsovalues = False
        # Using composition to include the visual element of the GUI.
        self._ui = Ui_GraphicsEditorWidget()
        self._ui.setupUi(self)
        # base graphics attributes
        self._ui.face_enumeration_chooser.setEnumsList(
            faceTypeEnumToString, faceTypeEnumFromString)
        self._ui.scenecoordinatesystem_chooser.setEnumsList(
            ScenecoordinatesystemEnumToString, ScenecoordinatesystemEnumFromString)
        self._ui.boundarymode_chooser.setEnumsList(
            Graphics.BoundaryModeEnumToString, Graphics.BoundaryModeEnumFromString)
        self._ui.streamlines_track_direction_chooser.setEnumsList(
            GraphicsStreamlines.TrackDirectionEnumToString, GraphicsStreamlines.TrackDirectionEnumFromString)
        self._ui.streamlines_colour_data_type_chooser.setEnumsList(
            GraphicsStreamlines.ColourDataTypeEnumToString, GraphicsStreamlines.ColourDataTypeEnumFromString)
        self._ui.line_shape_chooser.setEnumsList(
            Graphicslineattributes.ShapeTypeEnumToString, Graphicslineattributes.ShapeTypeEnumFromString)
        self._ui.domain_chooser.setEnumsList(
            Field.DomainTypeEnumToString, Field.DomainTypeEnumFromString, DOMAIN_TYPE_ENUM)
        self._ui.select_mode_enum_chooser.setEnumsList(
            Graphics.SelectModeEnumToString, Graphics.SelectModeEnumFromString)

        self._ui.subgroup_field_chooser.setNullObjectName('-')
        self._ui.subgroup_field_chooser.setConditional(FieldIsScalar)
        self._ui.coordinate_field_chooser.setNullObjectName('-')
        self._ui.coordinate_field_chooser.setConditional(
            FieldIsCoordinateCapable)
        self._ui.data_field_chooser.setNullObjectName('-')
        self._ui.data_field_chooser.setConditional(FieldIsRealValued)
        self._ui.spectrum_chooser.setNullObjectName('-')
        self._ui.tessellation_field_chooser.setNullObjectName('-')
        self._ui.texture_coordinates_chooser.setNullObjectName('-')
        # contours
        self._ui.isoscalar_field_chooser.setNullObjectName('- choose -')
        self._ui.isoscalar_field_chooser.setConditional(FieldIsScalar)
        self._ui.range_number_spinBox.valueChanged.connect(
            self.numberOfIsovalueRangeChanged)
        # streamlines
        self._ui.stream_vector_field_chooser.setNullObjectName('- choose -')
        self._ui.stream_vector_field_chooser.setConditional(
            FieldIsStreamVectorCapable)
        # line attributes
        self._ui.line_orientation_scale_field_chooser.setNullObjectName('-')
        self._ui.line_orientation_scale_field_chooser.setConditional(
            FieldIsScalar)
        # point attributes
        self._ui.glyph_chooser.setNullObjectName('-')
        self._ui.point_orientation_scale_field_chooser.setNullObjectName('-')
        self._ui.point_orientation_scale_field_chooser.setConditional(
            FieldIsOrientationScaleCapable)
        self._ui.label_field_chooser.setNullObjectName('-')
        self._ui.glyph_repeat_mode_chooser.setEnumsList(
            Glyph.RepeatModeEnumToString, Glyph.RepeatModeEnumFromString)
        self._ui.glyph_signed_scale_field_chooser.setNullObjectName('-')
        self._ui.glyph_signed_scale_field_chooser.setConditional(FieldIsScalar)
        self._ui.glyph_font_comboBox.currentIndexChanged.connect(
            self._fontChanged)
        # mesh point sampling
        self._ui.sampling_mode_chooser.setEnumsList(
            Element.PointSamplingModeEnumToString, Element.PointSamplingModeEnumFromString)
        self._ui.density_field_chooser.setNullObjectName('-')

    def _updateWidgets(self):
        # base graphics attributes
        subgroupField = None
        coordinateField = None
        material = None
        selectedMaterial = None
        tessellationField = None
        textureCoordinatesField = None
        dataField = None
        spectrum = None
        tessellation = None
        isWireframe = False
        pointattributes = None
        lineattributes = None
        samplingattributes = None
        contours = None
        streamlines = None
        if self._graphics:
            subgroupField = self._graphics.getSubgroupField()
            coordinateField = self._graphics.getCoordinateField()
            material = self._graphics.getMaterial()
            selectedMaterial = self._graphics.getSelectedMaterial()
            dataField = self._graphics.getDataField()
            spectrum = self._graphics.getSpectrum()
            tessellationField = self._graphics.getTessellationField()
            tessellation = self._graphics.getTessellation()
            textureCoordinatesField = self._graphics.getTextureCoordinateField()
            isWireframe = self._graphics.getRenderPolygonMode() == Graphics.RENDER_POLYGON_MODE_WIREFRAME
            contours = self._graphics.castContours()
            streamlines = self._graphics.castStreamlines()
            pointattributes = self._graphics.getGraphicspointattributes()
            lineattributes = self._graphics.getGraphicslineattributes()
            samplingattributes = self._graphics.getGraphicssamplingattributes()
            self._ui.general_groupbox.show()
        else:
            self._ui.general_groupbox.hide()
        self._ui.subgroup_field_chooser.setField(subgroupField)
        self._ui.coordinate_field_chooser.setField(coordinateField)
        self._scenecoordinatesystemDisplay()
        self._ui.material_chooser.setMaterial(material)
        self._ui.selected_material_chooser.setMaterial(selectedMaterial)
        self._ui.data_field_chooser.setField(dataField)
        self._ui.spectrum_chooser.setSpectrum(spectrum)
        self._ui.tessellation_field_chooser.setField(tessellationField)
        self._ui.tessellation_chooser.setTessellation(tessellation)
        self._ui.texture_coordinates_chooser.setField(textureCoordinatesField)
        self._renderLineWidthDisplay()
        self._renderPointSizeDisplay()
        self._boundarymodeDisplay()
        self._faceDisplay()
        self._domainTypeDisplay()
        self._selectModeDisplay()
        self._ui.wireframe_checkbox.setCheckState(
            QtCore.Qt.CheckState.Checked if isWireframe else QtCore.Qt.CheckState.Unchecked)
        # contours
        isoscalarField = None
        if contours and contours.isValid():
            isoscalarField = contours.getIsoscalarField()
            self._isRangeIsovalues = contours.getRangeNumberOfIsovalues()
            self._ui.range_number_spinBox.setEnabled(self._isRangeIsovalues)
            self._ui.contours_groupbox.show()
        else:
            self._ui.contours_groupbox.hide()
        self._ui.isoscalar_field_chooser.setField(isoscalarField)
        self._ui.range_isovalues_checkBox.setCheckState(
            QtCore.Qt.CheckState.Checked if self._isRangeIsovalues else QtCore.Qt.CheckState.Unchecked)
        self._isovaluesDisplay()
        # streamlines
        streamVectorField = None
        if streamlines and streamlines.isValid():
            streamVectorField = streamlines.getStreamVectorField()
            self._ui.streamlines_groupbox.show()
        else:
            self._ui.streamlines_groupbox.hide()
        self._ui.stream_vector_field_chooser.setField(streamVectorField)
        self._streamlinesTrackLengthDisplay()
        self._streamlinesTrackDirectionDisplay()
        self._streamlinesColourDataTypeDisplay()
        # line attributes
        lineOrientationScaleField = None
        if lineattributes and lineattributes.isValid():
            lineOrientationScaleField = lineattributes.getOrientationScaleField()
            self._ui.lines_groupbox.show()
        else:
            self._ui.lines_groupbox.hide()
        self._lineShapeDisplay()
        self._lineBaseSizeDisplay()
        self._ui.line_orientation_scale_field_chooser.setField(
            lineOrientationScaleField)
        self._lineScaleFactorsDisplay()
        isStreamline = (streamlines is not None) and streamlines.isValid()
        if not isStreamline:
            isStreamline = False
        model = self._ui.line_shape_chooser.model()
        model.item(1, 0).setEnabled(isStreamline)
        model.item(3, 0).setEnabled(isStreamline)
        self._ui.line_orientation_scale_field_label.setEnabled(
            not isStreamline)
        self._ui.line_orientation_scale_field_chooser.setEnabled(
            not isStreamline)
        self._ui.line_scale_factors_label.setEnabled(not isStreamline)
        self._ui.line_scale_factors_lineedit.setEnabled(not isStreamline)
        # point attributes
        glyph = None
        pointOrientationScaleField = None
        labelField = None
        glyphRepeatMode = None
        glyphSignedScaleField = None
        fontname = None
        if pointattributes and pointattributes.isValid():
            glyph = pointattributes.getGlyph()
            pointOrientationScaleField = pointattributes.getOrientationScaleField()
            labelField = pointattributes.getLabelField()
            glyphRepeatMode = pointattributes.getGlyphRepeatMode()
            glyphSignedScaleField = pointattributes.getSignedScaleField()
            fontname = pointattributes.getFont().getName()
            self._buildFontComboBox()
            self._ui.glyph_font_comboBox.setCurrentIndex(
                self._ui.glyph_font_comboBox.findText(fontname))
            self._ui.points_groupbox.show()
        else:
            self._ui.points_groupbox.hide()
        self._ui.glyph_chooser.setGlyph(glyph)
        self._pointBaseSizeDisplay()
        self._ui.point_orientation_scale_field_chooser.setField(
            pointOrientationScaleField)
        self._pointScaleFactorsDisplay()
        self._ui.label_field_chooser.setField(labelField)
        self._ui.glyph_repeat_mode_chooser.setEnum(glyphRepeatMode)
        self._glyphOffsetDisplay()
        self._ui.glyph_signed_scale_field_chooser.setField(
            glyphSignedScaleField)
        self._labelTextDisplay()
        self._labelTextOffsetDisplay()
        # sampling attributes
        if samplingattributes and samplingattributes.isValid() and self._graphics.getFieldDomainType() in POINT_SAMPLING_DOMAIN_TYPE_ENUM:
            self._ui.sampling_groupbox.show()
        else:
            self._ui.sampling_groupbox.hide()
        self._samplingModeDisplay()
        self._sampleLocationDisplay()
        self._densityFieldDisplay()

    def setScene(self, scene):
        """
        Set when scene changes to initialised widgets dependent on scene

        :param scene: zinc.scene
        """
        self._ui.material_chooser.setMaterialmodule(scene.getMaterialmodule())
        self._ui.selected_material_chooser.setMaterialmodule(scene.getMaterialmodule())
        self._ui.glyph_chooser.setGlyphmodule(scene.getGlyphmodule())
        self._ui.spectrum_chooser.setSpectrummodule(scene.getSpectrummodule())
        self._ui.tessellation_chooser.setTessellationmodule(scene.getTessellationmodule())

        region = scene.getRegion()
        self._ui.subgroup_field_chooser.setRegion(region)
        self._ui.coordinate_field_chooser.setRegion(region)
        self._ui.data_field_chooser.setRegion(region)
        self._ui.tessellation_field_chooser.setRegion(region)
        self._ui.texture_coordinates_chooser.setRegion(region)
        self._ui.isoscalar_field_chooser.setRegion(region)
        self._ui.stream_vector_field_chooser.setRegion(region)
        self._ui.point_orientation_scale_field_chooser.setRegion(region)
        self._ui.label_field_chooser.setRegion(region)
        self._ui.glyph_signed_scale_field_chooser.setRegion(region)
        self._ui.line_orientation_scale_field_chooser.setRegion(region)
        self._ui.density_field_chooser.setRegion(region)

    def getGraphics(self):
        """
        Get the graphics currently in the editor
        """
        return self._graphics

    def setGraphics(self, graphics):
        """
        Set the graphics to be edited

        :param graphics: zinc.graphics.
        """
        if graphics and graphics.isValid():
            self._graphics = graphics
        else:
            self._graphics = None
        self._updateWidgets()

    def _displayReal(self, widget, value):
        """
        Display real value in a widget
        """
        newText = FLOAT_STRING_FORMAT.format(value)
        widget.setText(newText)

    def _displayScale(self, widget, values, numberFormat=FLOAT_STRING_FORMAT):
        """
        Display vector values in a widget, separated by '*'
        """
        newText = "*".join(numberFormat.format(value) for value in values)
        widget.setText(newText)

    def _parseScale(self, widget):
        """
        Return real vector from comma separated text in line edit widget
        """
        text = widget.text()
        values = [float(value) for value in text.split('*')]
        return values

    def _parseScaleInteger(self, widget):
        """
        Return integer vector from comma separated text in line edit widget
        """
        text = widget.text()
        values = [int(value) for value in text.split('*')]
        return values

    def _displayVector(self, widget, values, numberFormat=FLOAT_STRING_FORMAT):
        """
        Display real vector values in a widget. Also handle scalar
        """
        if isinstance(values, Number):
            newText = FLOAT_STRING_FORMAT.format(values)
        else:
            newText = ", ".join(numberFormat.format(value) for value in values)
        widget.setText(newText)

    def _parseVector(self, widget):
        """
        Return real vector from comma separated text in line edit widget
        """
        text = widget.text()
        values = [float(value) for value in text.split(',')]
        return values

    def subgroupFieldChanged(self, index):
        """
        An item was selected at index in subgroup field chooser widget

        :param index: index of new item.
        """
        if self._graphics:
            subgroupField = self._ui.subgroup_field_chooser.getField()
            if subgroupField:
                self._graphics.setSubgroupField(subgroupField)
            else:
                self._graphics.setSubgroupField(Field())
            if self._refreshGraphicListCallback:
                self._refreshGraphicListCallback()

    def coordinateFieldChanged(self, index):
        """
        An item was selected at index in coordinate field chooser widget

        :param index: index of new item.
        """
        if self._graphics:
            coordinateField = self._ui.coordinate_field_chooser.getField()
            if coordinateField:
                self._graphics.setCoordinateField(coordinateField)
            else:
                self._graphics.setCoordinateField(Field())

    def _scenecoordinatesystemDisplay(self):
        """
        Show the current state of the scenecoordinatesystem combo box
        """
        scenecoordinatesystem = SCENECOORDINATESYSTEM_LOCAL
        if self._graphics:
            scenecoordinatesystem = self._graphics.getScenecoordinatesystem()
        self._ui.scenecoordinatesystem_chooser.setEnum(scenecoordinatesystem)

    def scenecoordinatesystemChanged(self, index):
        if self._graphics:
            scenecoordinatesystem = self._ui.scenecoordinatesystem_chooser.getEnum()
            self._graphics.setScenecoordinatesystem(scenecoordinatesystem)

    def dataFieldChanged(self, index):
        """
        An item was selected at index in data field chooser widget

        :param index: index of new item.
        """
        if self._graphics:
            dataField = self._ui.data_field_chooser.getField()
            if dataField:
                scene = self._graphics.getScene()
                scene.beginChange()
                spectrum = self._graphics.getSpectrum()
                if not spectrum.isValid():
                    spectrummodule = scene.getSpectrummodule()
                    spectrum = spectrummodule.getDefaultSpectrum()
                    self._graphics.setSpectrum(spectrum)
                    self._ui.spectrum_chooser.setSpectrum(spectrum)
                self._graphics.setDataField(dataField)
                scene.endChange()
            else:
                self._graphics.setDataField(Field())

    def spectrumChanged(self, index):
        if self._graphics:
            spectrum = self._ui.spectrum_chooser.getSpectrum()
            if spectrum:
                self._graphics.setSpectrum(spectrum)
            else:
                self._graphics.setSpectrum(Spectrum())

    def tessellationChanged(self, index):
        """
        An item was selected at index in tessellation chooser widget

        :param index: index of new item.
        """
        if self._graphics:
            tessellation = self._ui.tessellation_chooser.getTessellation()
            self._graphics.setTessellation(tessellation)

    def tessellationFieldChanged(self, index):
        """
        An item was selected at index in tessellation field chooser widget

        :param index: index of new item.
        """
        if self._graphics:
            tessellationField = self._ui.tessellation_field_chooser.getField()
            if tessellationField:
                self._graphics.setTessellationField(tessellationField)
            else:
                self._graphics.setTessellationField(Field())

    def textureCoordinateFieldChanged(self, index):
        """
        An item was selected at index in texture coordinate field chooser widget

        :param index: index of new item.
        """
        if self._graphics:
            textureCoordinateField = self._ui.texture_coordinates_chooser.getField()
            if textureCoordinateField:
                self._graphics.setTextureCoordinateField(textureCoordinateField)
            else:
                self._graphics.setTextureCoordinateField(Field())

    def _renderLineWidthDisplay(self):
        """
        Display the current render line width
        """
        if self._graphics:
            renderLineWidth = self._graphics.getRenderLineWidth()
            self._displayReal(self._ui.line_width_lineEdit, renderLineWidth)
            return
        self._ui.line_width_lineEdit.setText('')

    def renderLineWidthEntered(self):
        """
        Set render line width from text in widget
        """
        renderLineWidth = self._ui.line_width_lineEdit.text()
        try:
            renderLineWidth = float(renderLineWidth)
            if self._graphics.setRenderLineWidth(renderLineWidth) != ZINC_OK:
                raise
        except:
            print("Invalid render line width", renderLineWidth)
        self._renderLineWidthDisplay()

    def _renderPointSizeDisplay(self):
        """
        Display the current render point size
        """
        if self._graphics:
            renderPointSize = self._graphics.getRenderPointSize()
            self._displayReal(self._ui.point_size_lineEdit, renderPointSize)
            return
        self._ui.point_size_lineEdit.setText('')

    def renderPointSizeEntered(self):
        """
        Set render point size from text in widget
        """
        renderPointSize = self._ui.point_size_lineEdit.text()
        try:
            renderPointSize = float(renderPointSize)
            if self._graphics.setRenderPointSize(renderPointSize) != ZINC_OK:
                raise
        except:
            print("Invalid render point size", renderPointSize)
        self._renderPointSizeDisplay()

    def _boundarymodeDisplay(self):
        """
        Show the current state of the boundarymode enumeration chooser
        """
        boundarymode = Graphics.BOUNDARY_MODE_INVALID
        if self._graphics:
            boundarymode = self._graphics.getBoundaryMode()
        self._ui.boundarymode_chooser.setEnum(boundarymode)

    def boundarymodeChanged(self, index):
        """
        Change the current state of the boundarymode enumeration chooser

        :param index: The index of boundarymode enumeration after change.
        """
        if self._graphics:
            boundarymode = self._ui.boundarymode_chooser.getEnum()
            self._graphics.setBoundaryMode(boundarymode)

    def _faceDisplay(self):
        """
        Show the current state of the face combo box
        """
        faceType = Element.FACE_TYPE_ALL
        if self._graphics:
            faceType = self._graphics.getElementFaceType()
        self._ui.face_enumeration_chooser.setEnum(faceType)

    def faceChanged(self, index):
        """
        Element face combo box changed

        :param index: index of new item.
        """
        if self._graphics:
            faceType = self._ui.face_enumeration_chooser.getEnum()
            self._graphics.setElementFaceType(faceType)

    def _domainTypeDisplay(self):
        """
        Show the current state of the domain combo box
        """
        domainType = Field.DOMAIN_TYPE_INVALID
        if self._graphics:
            domainType = self._graphics.getFieldDomainType()
        self._ui.domain_chooser.setEnum(domainType)

    def domainChanged(self, index):
        """
        Element domain combo box changed

        :param index: index of new item.
        """
        if self._graphics:
            domainType = self._ui.domain_chooser.getEnum()
            self._graphics.setFieldDomainType(domainType)
            self._domainTypeDisplay()
            if self._refreshGraphicListCallback:
                self._refreshGraphicListCallback()

    def setRefreshGraphicListCallback(self, callback):
        self._refreshGraphicListCallback = callback

    def wireframeClicked(self, isChecked):
        """
        The wireframe surface render radiobutton was clicked

        :param isChecked: boolean
        """
        if self._graphics:
            self._graphics.setRenderPolygonMode(
                Graphics.RENDER_POLYGON_MODE_WIREFRAME if isChecked else Graphics.RENDER_POLYGON_MODE_SHADED)

    def glyphChanged(self, index):
        """
        An item was selected at index in glyph chooser widget

        :param index: index of new item.
        """
        if self._graphics:
            pointattributes = self._graphics.getGraphicspointattributes()
            if (pointattributes.isValid()):
                glyph = self._ui.glyph_chooser.getGlyph()
                if glyph:
                    pointattributes.setGlyph(glyph)
                else:
                    pointattributes.setGlyph(Glyph())

    def materialChanged(self, index):
        """
        An item was selected at index in material chooser widget

        :param index: index of new item.
        """
        if self._graphics:
            material = self._ui.material_chooser.getMaterial()
            self._graphics.setMaterial(material)

    def selectedMaterialChanged(self, index):
        """
        An item was selected at index in selected material chooser widget

        :param index: index of new item.
        """
        if self._graphics:
            selectedMaterial = self._ui.selected_material_chooser.getMaterial()
            self._graphics.setSelectedMaterial(selectedMaterial)

    def _selectModeDisplay(self):
        """
        Show the current state of the select mode enum chooser widget
        """
        selectMode = Graphics.SELECT_MODE_INVALID
        if self._graphics:
            selectMode = self._graphics.getSelectMode()
        self._ui.select_mode_enum_chooser.setEnum(selectMode)

    def selectModeChanged(self, index):
        """
        Element select mode enum chooser widget changed

        :param index: index of new item.
        """
        if self._graphics:
            selectMode = self._ui.select_mode_enum_chooser.getEnum()
            self._graphics.setSelectMode(selectMode)
            self._updateWidgets()

    def isoscalarFieldChanged(self, index):
        if self._graphics:
            contours = self._graphics.castContours()
            if contours.isValid():
                isoscalarField = self._ui.isoscalar_field_chooser.getField()
                if not isoscalarField:
                    isoscalarField = Field()
                contours.setIsoscalarField(isoscalarField)

    def rangeIsovaluesClicked(self, isChecked):
        """
        The range isovalues checkbox was clicked

        :param isChecked: boolean
        """
        if self._graphics:
            self._isRangeIsovalues = not self._isRangeIsovalues
            self._ui.range_number_spinBox.setEnabled(self._isRangeIsovalues)
            self._isovaluesDisplay()

    def _isovaluesDisplay(self):
        """
        Display the current iso values list
        """
        if self._graphics:
            contours = self._graphics.castContours()
            if contours.isValid():
                if self._isRangeIsovalues:
                    first = contours.getRangeFirstIsovalue()
                    last = contours.getRangeLastIsovalue()
                    rangeNum = contours.getRangeNumberOfIsovalues()
                    self._displayVector(self._ui.isovalues_lineedit, [first, last])
                    self._ui.range_number_spinBox.setValue(rangeNum)
                    return
                count, isovalues = contours.getListIsovalues(1)
                if count > 1:
                    count, isovalues = contours.getListIsovalues(count)
                if count > 0:
                    self._displayVector(self._ui.isovalues_lineedit, isovalues)
                    return
        self._ui.isovalues_lineedit.setText('')

    def numberOfIsovalueRangeChanged(self, value):
        """
        Set iso values list from text in widget
        """
        try:
            contours = self._graphics.castContours()
            if contours.isValid():
                isovalues = self._parseVector(self._ui.isovalues_lineedit)
                rangeNum = value
                firstIsovalue = isovalues[0]
                lastIsovalue = isovalues[1]
                if contours.setRangeIsovalues(rangeNum, firstIsovalue, lastIsovalue) != ZINC_OK:
                    raise
        except:
            ArgonLogger.getLogger().error("Invalid range number for isovalues")
        self._isovaluesDisplay()

    def isovaluesEntered(self):
        """
        Set iso values list from text in widget
        """
        try:
            isovalues = self._parseVector(self._ui.isovalues_lineedit)
            contours = self._graphics.castContours()
            if contours.isValid():
                if self._isRangeIsovalues:
                    rangeNum = self._ui.range_number_spinBox.value()
                    firstIsovalue = isovalues[0]
                    lastIsovalue = isovalues[1]
                    if contours.setRangeIsovalues(rangeNum, firstIsovalue, lastIsovalue) != ZINC_OK:
                        raise
                elif contours.setListIsovalues(isovalues) != ZINC_OK:
                    raise
        except:
            ArgonLogger.getLogger().error("Invalid isovalues")
        self._isovaluesDisplay()

    def streamVectorFieldChanged(self, index):
        if self._graphics:
            streamlines = self._graphics.castStreamlines()
            if streamlines.isValid():
                streamVectorField = self._ui.stream_vector_field_chooser.getField()
                if not streamVectorField:
                    streamVectorField = Field()
                streamlines.setStreamVectorField(streamVectorField)

    def _streamlinesTrackLengthDisplay(self):
        """
        Display the current streamlines length
        """
        if self._graphics:
            streamlines = self._graphics.castStreamlines()
            if streamlines.isValid():
                trackLength = streamlines.getTrackLength()
                self._displayReal(
                    self._ui.streamlines_track_length_lineedit, trackLength)
                return
        self._ui.streamlines_track_length_lineedit.setText('')

    def streamlinesTrackLengthEntered(self):
        """
        Set iso values list from text in widget
        """
        streamlinesLengthText = self._ui.streamlines_track_length_lineedit.text()
        try:
            trackLength = float(streamlinesLengthText)
            streamlines = self._graphics.castStreamlines()
            if streamlines.isValid():
                if streamlines.setTrackLength(trackLength) != ZINC_OK:
                    raise
        except:
            print("Invalid streamlines track length", streamlinesLengthText)
        self._streamlinesTrackLengthDisplay()

    def _streamlinesTrackDirectionDisplay(self):
        """
        Show the current state of the streamlines track direction combo box
        """
        streamlinesTrackDirection = GraphicsStreamlines.TRACK_DIRECTION_FORWARD
        if self._graphics:
            streamlines = self._graphics.castStreamlines()
            if streamlines.isValid():
                streamlinesTrackDirection = streamlines.getTrackDirection()
        self._ui.streamlines_track_direction_chooser.setEnum(streamlinesTrackDirection)

    def streamlinesTrackDirectionChanged(self, index):
        """
        Element streamlines track direction combo box changed

        :param index: index of new item.
        """
        if self._graphics:
            streamlines = self._graphics.castStreamlines()
            if streamlines.isValid():
                streamlines.setTrackDirection(
                    index + GraphicsStreamlines.TRACK_DIRECTION_FORWARD)

    def _streamlinesColourDataTypeDisplay(self):
        """
        Show the current state of the streamlines colour data type combo box
        """
        streamlinesColourDataType = GraphicsStreamlines.COLOUR_DATA_TYPE_FIELD
        if self._graphics:
            streamlines = self._graphics.castStreamlines()
            if streamlines.isValid():
                streamlinesColourDataType = streamlines.getColourDataType()
        self._ui.streamlines_colour_data_type_chooser.setEnum(
            streamlinesColourDataType)

    def streamlinesColourDataTypeChanged(self, index):
        """
        Element streamlines colour data type combo box changed

        :param index: index of new item.
        """
        if self._graphics:
            streamlines = self._graphics.castStreamlines()
            if streamlines.isValid():
                scene = self._graphics.getScene()
                scene.beginChange()
                spectrum = self._graphics.getSpectrum()
                if not spectrum.isValid():
                    spectrummodule = scene.getSpectrummodule()
                    spectrum = spectrummodule.getDefaultSpectrum()
                    self._graphics.setSpectrum(spectrum)
                streamlines.setColourDataType(
                    index + GraphicsStreamlines.COLOUR_DATA_TYPE_FIELD)
                scene.endChange()

    def _lineShapeDisplay(self):
        """
        Show the current state of the lineShape combo box
        """
        lineShapeType = Graphicslineattributes.SHAPE_TYPE_LINE
        if self._graphics:
            lineattributes = self._graphics.getGraphicslineattributes()
            if lineattributes.isValid():
                lineShapeType = lineattributes.getShapeType()
        self._ui.line_shape_chooser.setEnum(lineShapeType)

    def lineShapeChanged(self, index):
        """
        Element lineShape combo box changed

        :param index: index of new item.
        """
        if self._graphics:
            lineattributes = self._graphics.getGraphicslineattributes()
            if lineattributes.isValid():
                lineattributes.setShapeType(
                    index + Graphicslineattributes.SHAPE_TYPE_LINE)

    def _lineBaseSizeDisplay(self):
        """
        Display the current line base size
        """
        if self._graphics:
            lineattributes = self._graphics.getGraphicslineattributes()
            if lineattributes.isValid():
                _, baseSize = lineattributes.getBaseSize(2)
                self._displayScale(self._ui.line_base_size_lineedit, baseSize)
                return
        self._ui.line_base_size_lineedit.setText('0')

    def lineBaseSizeEntered(self):
        """
        Set line base size from text in widget
        """
        try:
            baseSize = self._parseScale(self._ui.line_base_size_lineedit)
            lineattributes = self._graphics.getGraphicslineattributes()
            if lineattributes.setBaseSize(baseSize) != ZINC_OK:
                raise
        except:
            print("Invalid line base size")
        self._lineBaseSizeDisplay()

    def lineOrientationScaleFieldChanged(self, index):
        if self._graphics:
            lineattributes = self._graphics.getGraphicslineattributes()
            if lineattributes.isValid():
                orientationScaleField = self._ui.line_orientation_scale_field_chooser.getField()
                if not orientationScaleField:
                    orientationScaleField = Field()
                lineattributes.setOrientationScaleField(orientationScaleField)

    def _lineScaleFactorsDisplay(self):
        """
        Display the current line scale factors
        """
        if self._graphics:
            lineattributes = self._graphics.getGraphicslineattributes()
            if lineattributes.isValid():
                _, scaleFactors = lineattributes.getScaleFactors(2)
                self._displayScale(
                    self._ui.line_scale_factors_lineedit, scaleFactors)
                return
        self._ui.line_scale_factors_lineedit.setText('0')

    def lineScaleFactorsEntered(self):
        """
        Set line scale factors from text in widget
        """
        try:
            scaleFactors = self._parseScale(
                self._ui.line_scale_factors_lineedit)
            lineattributes = self._graphics.getGraphicslineattributes()
            if lineattributes.setScaleFactors(scaleFactors) != ZINC_OK:
                raise
        except:
            print("Invalid line scale factors")
        self._lineScaleFactorsDisplay()

    def _pointBaseSizeDisplay(self):
        """
        Display the current point base size
        """
        if self._graphics:
            pointattributes = self._graphics.getGraphicspointattributes()
            if pointattributes.isValid():
                _, baseSize = pointattributes.getBaseSize(3)
                self._displayScale(self._ui.point_base_size_lineedit, baseSize)
                return
        self._ui.point_base_size_lineedit.setText('0')

    def pointBaseSizeEntered(self):
        """
        Set point base size from text in widget
        """
        try:
            baseSize = self._parseScale(self._ui.point_base_size_lineedit)
            pointattributes = self._graphics.getGraphicspointattributes()
            if pointattributes.setBaseSize(baseSize) != ZINC_OK:
                raise
        except:
            print("Invalid point base size")
        self._pointBaseSizeDisplay()

    def pointOrientationScaleFieldChanged(self, index):
        if self._graphics:
            pointattributes = self._graphics.getGraphicspointattributes()
            if pointattributes.isValid():
                orientationScaleField = self._ui.point_orientation_scale_field_chooser.getField()
                if not orientationScaleField:
                    orientationScaleField = Field()
                pointattributes.setOrientationScaleField(orientationScaleField)

    def _pointScaleFactorsDisplay(self):
        """
        Display the current point scale factors
        """
        if self._graphics:
            pointattributes = self._graphics.getGraphicspointattributes()
            if pointattributes.isValid():
                _, scaleFactors = pointattributes.getScaleFactors(3)
                self._displayScale(
                    self._ui.point_scale_factors_lineedit, scaleFactors)
                return
        self._ui.point_scale_factors_lineedit.setText('0')

    def pointScaleFactorsEntered(self):
        """
        Set point scale factors from text in widget
        """
        try:
            scaleFactors = self._parseScale(
                self._ui.point_scale_factors_lineedit)
            pointattributes = self._graphics.getGraphicspointattributes()
            if pointattributes.setScaleFactors(scaleFactors) != ZINC_OK:
                raise
        except:
            print("Invalid point scale factors")
        self._pointScaleFactorsDisplay()

    def labelFieldChanged(self, index):
        if self._graphics:
            pointattributes = self._graphics.getGraphicspointattributes()
            if pointattributes.isValid():
                labelField = self._ui.label_field_chooser.getField()
                if not labelField:
                    labelField = Field()
                pointattributes.setLabelField(labelField)

    def glyphRepeatModeChanged(self, index):
        """
        Glyph repeat mode combo box changed

        :param index: index of new item.
        """
        if self._graphics:
            pointattributes = self._graphics.getGraphicspointattributes()
            if pointattributes.isValid():
                glyphRepeatMode = self._ui.glyph_repeat_mode_chooser.getEnum()
                pointattributes.setGlyphRepeatMode(glyphRepeatMode)

    def glyphSignedScaleFieldChanged(self, index):
        if self._graphics:
            pointattributes = self._graphics.getGraphicspointattributes()
            if pointattributes.isValid():
                glyphSignedScaleField = self._ui.glyph_signed_scale_field_chooser.getField()
                if not glyphSignedScaleField:
                    glyphSignedScaleField = Field()
                pointattributes.setSignedScaleField(glyphSignedScaleField)

    def _glyphOffsetDisplay(self):
        """
        Display the current glyph offset
        """
        if self._graphics:
            pointattributes = self._graphics.getGraphicspointattributes()
            if pointattributes.isValid():
                _, glyphOffset = pointattributes.getGlyphOffset(3)
                self._displayVector(
                    self._ui.glyph_offset_lineedit, glyphOffset)
                return
        self._ui.glyph_offset_lineedit.setText('0')

    def glyphOffsetEntered(self):
        """
        Set glyph offset from text in widget
        """
        try:
            glyphOffset = self._parseVector(self._ui.glyph_offset_lineedit)
            pointattributes = self._graphics.getGraphicspointattributes()
            if pointattributes.setGlyphOffset(glyphOffset) != ZINC_OK:
                raise
        except:
            print("Invalid glyph offset")
        self._glyphOffsetDisplay()

    def _labelTextDisplay(self):
        """
        Display the current label offset
        """
        if self._graphics:
            pointattributes = self._graphics.getGraphicspointattributes()
            if pointattributes.isValid():
                labelTexts = []
                for i in range(3):
                    labelText = pointattributes.getLabelText(i + 1)
                    if labelText:
                        labelTexts.append(labelText)
                self._ui.glyph_label_text_lineedit.setText(
                    ",".join(labelTexts))
                return
        self._ui.glyph_label_text_lineedit.setText('')

    def labelTextEntered(self):
        """
        Set label text from text in widget
        """
        try:
            labelTexts = self._ui.glyph_label_text_lineedit.text().split(',')
            pointattributes = self._graphics.getGraphicspointattributes()
            for i in range(3):
                labelText = labelTexts[i] if i < len(labelTexts) else ''
                if pointattributes.setLabelText(i + 1, labelText) != ZINC_OK:
                    raise
        except:
            print("Invalid label text")
        self._labelTextDisplay()

    def _labelTextOffsetDisplay(self):
        """
        Display the current label text offset
        """
        if self._graphics:
            pointattributes = self._graphics.getGraphicspointattributes()
            if pointattributes.isValid():
                _, labelOffset = pointattributes.getLabelOffset(3)
                self._displayVector(
                    self._ui.glyph_label_text_offset_lineedit, labelOffset)
                return
        self._ui.glyph_label_text_offset_lineedit.setText('0')

    def labelTextOffsetEntered(self):
        """
        Set label text offset from text in widget
        """
        try:
            labelOffset = self._parseVector(
                self._ui.glyph_label_text_offset_lineedit)
            pointattributes = self._graphics.getGraphicspointattributes()
            if pointattributes.setLabelOffset(labelOffset) != ZINC_OK:
                raise
        except:
            print("Invalid label text offset")
        self._labelTextOffsetDisplay()

    def _buildFontComboBox(self):
        self._ui.glyph_font_comboBox.clear()
        self._ui.glyph_font_comboBox.addItems(["default"])

    def _fontChanged(self, index):
        """
        Set label text font to selected font in widget
        """
        try:
            pointattributes = self._graphics.getGraphicspointattributes()
            # Font, fake it till we make it
            # labelFont = findFontbyName(self._ui.glyph_font_comboBox.item(index).text())
            labelFont = pointattributes.getFont()
            if pointattributes.setFont(labelFont) != ZINC_OK:
                raise
        except:
            print("Invalid label text font")

    # Sampling Settings
    def _samplingModeDisplay(self):
        """
        Show the current state of the sampling mode combo box
        """
        samplingMode = Element.POINT_SAMPLING_MODE_CELL_CENTRES
        if self._graphics:
            samplingattributes = self._graphics.getGraphicssamplingattributes()
            if samplingattributes.isValid():
                samplingMode = samplingattributes.getElementPointSamplingMode()
        self._ui.sampling_mode_chooser.setEnum(samplingMode)

    def samplingModeChanged(self, index):
        """
        Sampling mode combo box changed
        """
        if self._graphics:
            samplingattributes = self._graphics.getGraphicssamplingattributes()
            if samplingattributes.isValid():
                samplingMode = self._ui.sampling_mode_chooser.getEnum()
                samplingattributes.setElementPointSamplingMode(samplingMode)
                self._sampleLocationDisplay()

    def _sampleLocationDisplay(self):
        """
        Show current sample location
        """
        self._ui.sample_location_lineedit.setEnabled(False)
        if self._graphics:
            samplingattributes = self._graphics.getGraphicssamplingattributes()
            if samplingattributes.isValid() and samplingattributes.getElementPointSamplingMode() == Element.POINT_SAMPLING_MODE_SET_LOCATION:
                self._ui.sample_location_lineedit.setEnabled(True)
                _, scaleFactors = samplingattributes.getLocation(3)
                self._displayVector(
                    self._ui.sample_location_lineedit, scaleFactors)
                return
        self._ui.sample_location_lineedit.setText('')

    def sampleLocationEntered(self):
        """
        Set sample location from text in widget
        """
        try:
            sampleLocation = self._parseVector(
                self._ui.sample_location_lineedit)
            samplingattributes = self._graphics.getGraphicssamplingattributes()
            if samplingattributes.setLocation(sampleLocation) != ZINC_OK:
                raise
        except:
            print("Invalid sample location")
        self._sampleLocationDisplay()

    def _densityFieldDisplay(self):
        """
        Show the current state of the density field combo box
        """
        if self._graphics:
            samplingattributes = self._graphics.getGraphicssamplingattributes()
            if samplingattributes.isValid():
                densityField = samplingattributes.getDensityField()
                self._ui.density_field_chooser.setField(densityField)
                return

    def densityFieldChanged(self):
        """
        Density field combo box changed
        """
        if self._graphics:
            samplingattributes = self._graphics.getGraphicssamplingattributes()
            if samplingattributes.isValid():
                densityField = self._ui.density_field_chooser.getField()
                samplingattributes.setDensityField(densityField)
                self._densityFieldDisplay()


# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations

class Migration(migrations.Migration):

    dependencies = [
        ('store', '0001_initial'),
    ]

    operations = [
        migrations.AlterModelOptions(
            name='category',
            options={'verbose_name_plural': 'Categories'},
        ),
        migrations.RemoveField(
            model_name='review',
            name='title',
        ),
    ]


import unittest

from decimal import Decimal
from unittest import TestCase

from pyspark.sql import types as T

class SparkTestCase(TestCase):

    '''
    Custom TestCase fully dedicated to the unit test between pyspark dataframes
    '''

    def __init__(self, methodName=None):

        if methodName:
            unittest.TestCase.__init__(self, methodName)

    def assertDataFrameEqual(self, df1, df2, verbose=True, msg=None):

        '''
        When two dataframes are equal it means that not only the data but also the metadata is the same
        '''

        df1.cache()
        df2.cache()

        if df1.schema != df2.schema:

            raise self.failureException('DFs schemas are not equal %s : %s' % (df1.schema, df2.schema))

        if any([
            df1.subtract(df2).count() != 0,
            df2.subtract(df1).count() != 0,
        ]):
            df1.show(truncate = False)
            df2.show(truncate = False)

            if verbose:
                print("'{df1} \ {df2}'")
                df1.subtract(df2).show(truncate = False)
                print("'{df2} \ {df1}'")
                df2.subtract(df1).show(truncate = False)

            raise self.failureException('DFs values are not equal %s : %s' %(df1.collect(), df2.collect()))

    def assertDictAlmostEqual(self, d1, d2, places=7):

        '''
        Function that guarantees that the keys and values are the same
        Values being compared up to specified precision
        '''

        self.assertListEqual(sorted(d1.keys()), sorted(d2.keys()))

        def loop(l):

            if not l:

                return None

            i, j = l[0]
            key1, value1 = i
            key2, value2 = j

            if type(value1) != type(value2):

                raise self.failureException('Values are not equal %s : %s' %(value1, value2, key1))

            elif isinstance(value1, dict):

                self.assertDictAlmostEqual(value1, value2, places)

            elif isinstance(value1, Decimal):

                self.assertAlmostEqual(value1, value2, places)

            else:

                self.assertEqual(value1, value2)

            loop(l[1:])

        items = zip(sorted(d1.items()), sorted(d2.items()))

        loop(items)

    def assertDataFrameAlmostEqual(self, df1, df2, places=7):

        '''
        Asserts two dataframes are equal up to an acceptable precision
        '''

        df1.cache()
        df2.cache()

        if df1.schema != df2.schema:

            raise self.failureException('DFs schemas are not equal %s : %s' %(df1.schema, df2.schema))

        if any([
            df1.subtract(df2).count() != 0,
            df2.subtract(df1).count() != 0,
        ]):
            has_decimals = any([isinstance(f.dataType, T.DecimalType) for f in df1.schema.fields])

            if not has_decimals:

                df1.show()
                df2.show()
                raise self.failureException('DFs values are not equal %s : %s' %(df1.collect(), df2.collect()))

            for r1, r2 in zip(sorted(df1.collect(), sorted(df2.collect()))):

                self.assertDictAlmostEqual(r1.asDict(), r2.asDict(), places)


import numpy as np
import cv2
import pandas as pd
import Read_data
from keras.preprocessing import image

def clean_data(img_raw,label_raw,threshold=25):
    bool_arr=np.array(map(lambda x:True if (x.shape[0]>threshold or x.shape[1]>threshold) else False,img_raw))
    return img_raw[bool_arr],label_raw[bool_arr]

def scale_data(img,full_shape=(129,129)):
    def pad_data(img):
        (fh, fw) = full_shape
        (h, w) = img.shape
        result = np.full(full_shape,0)
        result =result.astype(img.dtype)
        if h>w:
            img=cv2.resize(img,(int(w*fh/float(h)),fh))
            (h, w) = img.shape
            y=0 if (fw-w)==0 else np.random.randint(0,fw-w)
            result[:,y:img.shape[1]+y]=img
        else:
            img=cv2.resize(img,(fw,int(h*fw/float(w))))
            (h, w) = img.shape
            x=0 if (fh-h)==0 else np.random.randint(0,fh-h)
            result[x:img.shape[0]+x,:]=img
        return result.reshape(fh,fw,1)
    return np.array(map(pad_data,img))

class augment_class(object):
    def __init__(self):
        pass

    @staticmethod
    def rotate(x, row_axis=0, col_axis=1, channel_axis=2, fill_mode='nearest', cval=0.):
        rotate_limit=(-30, 30)
        theta = np.pi / 180 * np.random.uniform(rotate_limit[0], rotate_limit[1])
        rotation_matrix = np.array([[np.cos(theta), -np.sin(theta), 0],[np.sin(theta), np.cos(theta), 0],[0, 0, 1]])
        h, w = x.shape[row_axis], x.shape[col_axis]
        transform_matrix = image.transform_matrix_offset_center(rotation_matrix, h, w)
        x = image.apply_transform(x, transform_matrix, channel_axis, fill_mode, cval)
        return x

    @staticmethod
    def shear(x, row_axis=0, col_axis=1, channel_axis=2, fill_mode='nearest', cval=0.):
        intensity=0.5
        sh = np.random.uniform(-intensity, intensity)
        shear=sh
        shear_matrix = np.array([[1, -np.sin(shear), 0],[0, np.cos(shear), 0],[0, 0, 1]])
        h, w = x.shape[row_axis], x.shape[col_axis]
        transform_matrix = image.transform_matrix_offset_center(shear_matrix, h, w)
        x = image.apply_transform(x, transform_matrix, channel_axis, fill_mode, cval)
        return x

def augment_data(img):
    img_rotate=np.array(map(augment_class.rotate,img))
    img_shear=np.array(map(augment_class.shear,img))
    return img,img_rotate,img_shear

if __name__=='__main__':
    img_raw,label_raw=Read_data.load_data()
    img,label=clean_data(img_raw,label_raw)
    img=scale_data(img)
    img,img_rotate,img_shear=augment_data(img)


from pathlib import Path

from antarest.study.storage.rawstudy.io.reader import MultipleSameKeysIniReader
from antarest.study.storage.rawstudy.io.writer.ini_writer import IniWriter
from antarest.study.storage.rawstudy.model.filesystem.root.settings.generaldata import DUPLICATE_KEYS

GENERAL_DATA_PATH = "settings/generaldata.ini"

def upgrade_800(study_path: Path) -> None:
    """
    Upgrade the study configuration to version 800.

    NOTE:
        The file `study.antares` is not upgraded here.

    Args:
        study_path: path to the study directory.
    """

    reader = MultipleSameKeysIniReader(DUPLICATE_KEYS)
    data = reader.read(study_path / GENERAL_DATA_PATH)
    data["other preferences"]["hydro-heuristic-policy"] = "accommodate rule curves"
    data["optimization"]["include-exportstructure"] = False
    data["optimization"]["include-unfeasible-problem-behavior"] = "error-verbose"
    data["general"]["custom-scenario"] = data["general"]["custom-ts-numbers"]
    del data["general"]["custom-ts-numbers"]
    writer = IniWriter(special_keys=DUPLICATE_KEYS)
    writer.write(data, study_path / GENERAL_DATA_PATH)


#!/usr/bin/python3

from __future__ import annotations

from abc import ABCMeta
from typing import TYPE_CHECKING

from pollinatarr.logger.log import logger
from pollinatarr.torrents.torrent_container import TorrentContainer

if TYPE_CHECKING:
    from pollinatarr.config.config import Config
    from pollinatarr.config.torrent_clients_config import TorrentClientConfig

class FailedToConnect(Exception):
    pass

class AbstractTorrentClient(object, metaclass=ABCMeta):
    def __init__(self, config: TorrentClientConfig, name: str):
        self.name = name
        self.config = config
        self.logger = logger.get_sub("TORRENT CLIENT").get_sub(name)

    def get_torrents_using_config(self, config: Config) -> TorrentContainer:
        torrents = TorrentContainer()
        for _tracker_name, _tracker_config in config.trackers.items():
            categories = _tracker_config.categories or config.categories
            for category in categories:
                self.logger.info(f"Searching torrents that match {category} category and {_tracker_name} tracker")
                _torrents = self.get_torrents_from_tracker(_tracker_name, category)
                self.logger.info(f"Found {len(_torrents)} torrents")
                torrents.merge(_torrents)
        return torrents

    def get_torrents_from_tracker(self, tracker_name: str, category: str) -> TorrentContainer:
        raise NotImplementedError


import os

from models.params import COMMON_PARAMS as CP
from models.params import IM_DECODER_PARAMS as IDP
from models.basic_models.linear import DoublingLinearNetwork

import torch as T
import torch.nn as nn
import torch.optim as optim

class ImageDecoderNetwork(nn.Module):
    def __init__(self, input_dim, output_dim=IDP.OUTPUT_DIM, output_im_dims=IDP.OUTPUT_IM_DIMS,
                 alpha=IDP.LEARNING_RATE, in_activation=IDP.IN_ACTIVATION, out_activation=IDP.OUT_ACTIVATION,
                 chkpt_dir=CP.CHECKPOINT_DIR, chkpt_filename=IDP.CHKPT_FILE):
        super(ImageDecoderNetwork, self).__init__()
        self.out_activation = out_activation
        self.output_im_dims = output_im_dims
        self.d_linear = DoublingLinearNetwork(input_dim, output_dim=output_dim, activation=in_activation)

        self.checkpoint_file = os.path.join(chkpt_dir, chkpt_filename)
        self.optimizer = optim.Adam(self.parameters(), lr=alpha)
        self.device = T.device('cuda:0' if T.cuda.is_available() else 'cpu')
        self.to(self.device)

    def forward(self, x):
        x.to(self.device)
        features = self.d_linear(x)
        out = self.out_activation(features)
        return out.view(-1, self.output_im_dims[0], self.output_im_dims[1], self.output_im_dims[2])


#****************************************************************************
#* setup.py for debug-mgr
#****************************************************************************
import os
import subprocess
import sys
from setuptools import setup
from distutils.extension import Extension
from setuptools.command.build_ext import build_ext as _build_ext
from distutils.file_util import copy_file

if "-DDEBUG" in sys.argv:
    _DEBUG = True
    sys.argv.remove("-DDEBUG")
else:
    _DEBUG = False

_DEBUG_LEVEL = 0

version="0.0.1"

if "BUILD_NUM" in os.environ.keys():
    version += ".%s" % os.environ["BUILD_NUM"]

if "CMAKE_BUILD_TOOL" in os.environ.keys():
    cmake_build_tool = os.environ["CMAKE_BUILD_TOOL"]
else:
    cmake_build_tool = "Ninja"

# First need to establish where things are
debug_mgr_dir = os.path.dirname(os.path.abspath(__file__))

if os.path.isdir(os.path.join(debug_mgr_dir, "packages")):
    print("Packages are inside this directory")
    packages_dir = os.path.join(debug_mgr_dir, "packages")
else:
    parent = os.path.dirname(debug_mgr_dir)

    if os.path.isdir(os.path.join(parent, "debug-mgr")):
        print("debug-mgr is a peer")
        packages_dir = parent
    else:
        raise Exception("Unexpected source layout")

# Now, build the core tblink-rpc-hdl library
cwd = os.getcwd()
if not os.path.isdir(os.path.join(cwd, "build")):
    os.makedirs(os.path.join(cwd, "build"))

if _DEBUG:
    BUILD_TYPE = "-DCMAKE_BUILD_TYPE=Debug"
else:
    BUILD_TYPE = "-DCMAKE_BUILD_TYPE=Release"

env = os.environ.copy()
python_bindir = os.path.dirname(sys.executable)
print("python_bindir: %s" % str(python_bindir))

if "PATH" in env.keys():
    env["PATH"] = python_bindir + os.pathsep + env["PATH"]
else:
    env["PATH"] = python_bindir

# Run configure...
result = subprocess.run(
    ["cmake",
     debug_mgr_dir,
     "-G%s" % cmake_build_tool,
     BUILD_TYPE,
     "-DPACKAGES_DIR=%s" % packages_dir,
     "-DCMAKE_INSTALL_PREFIX=%s" % os.path.join(cwd, "build"),
     "-DCMAKE_OSX_ARCHITECTURES='x86_64;arm64'",
     ],
    cwd=os.path.join(cwd, "build"),
    env=env)

if result.returncode != 0:
    raise Exception("cmake configure failed")

if cmake_build_tool == "Ninja":
    result = subprocess.run(
        ["ninja",
         "-j",
         "%d" % os.cpu_count()
        ],
        cwd=os.path.join(cwd, "build"),
        env=env)
elif cmake_build_tool == "Unix Makefiles":
    result = subprocess.run(
        ["make",
         "-j%d" % os.cpu_count()
        ],
        cwd=os.path.join(cwd, "build"),
        env=env)
else:
    raise Exception("Unknown make system %s" % cmake_build_tool)

if result.returncode != 0:
    raise Exception("build failed")

if cmake_build_tool == "Ninja":
    result = subprocess.run(
        ["ninja",
         "-j",
         "%d" % os.cpu_count(),
         "install"
        ],
        cwd=os.path.join(cwd, "build"),
        env=env)
elif cmake_build_tool == "Unix Makefiles":
    result = subprocess.run(
        ["make",
         "-j%d" % os.cpu_count(),
         "install"
        ],
        cwd=os.path.join(cwd, "build"),
        env=env)
else:
    raise Exception("Unknown make system %s" % cmake_build_tool)

if result.returncode != 0:
    raise Exception("build failed")

extra_compile_args = []
if _DEBUG:
    extra_compile_args += ["-g", "-O0", "-DDEBUG=%s" % _DEBUG_LEVEL, "-UNDEBUG"]
else:
    extra_compile_args += ["-DNDEBUG", "-O3"]

if sys.platform == "darwin":
    extra_compile_args += ["-std=c++11"]

class build_ext(_build_ext):
    def run(self):
        super().run()

    # Needed for Windows to not assume python module (generate interface in def file)
    def get_export_symbols(self, ext):
        return None

    def copy_extensions_to_source(self):
        """ Like the base class method, but copy libs into proper directory in develop. """
        print("copy_extensions_to_source")
        super().copy_extensions_to_source()

        build_py = self.get_finalized_command("build_py")

        ext = self.extensions[0]
        fullname = self.get_ext_fullname(ext.name)
        filename = self.get_ext_filename(fullname)
        modpath = fullname.split(".")
        package = ".".join(modpath[:-1])
        package_dir = build_py.get_package_dir(package)

        if sys.platform == "darwin":
            ext = ".dylib"
        elif sys.platform == "win32":
            ext = ".dll"
        else:
            ext = ".so"

        if sys.platform == "win32":
            pref = ""
        else:
            pref = "lib"

        copy_file(
            os.path.join(cwd, "build", "src", "%sdebug-mgr%s" % (pref, ext)),
            os.path.join(package_dir, "%sdebug-mgr%s" % (pref, ext)))

        if sys.platform == "win32":
            copy_file(
                os.path.join(cwd, "build", "src", "debug-mgr.lib" ),
                os.path.join(package_dir, "debug-mgr.lib" % (pref, ext)))

        dest_filename = os.path.join(package_dir, filename)

        print("package_dir: %s dest_filename: %s" % (package_dir, dest_filename))

print("extra_compile_args=" + str(extra_compile_args))

if sys.platform == "darwin":
    libext = ".dylib"
    libpref = "lib"
elif sys.platform == "win32":
    libext = ".dll"
    libpref = "lib"
else:
    libext = ".so"
    libpref = "lib"

if sys.platform == "win32":
    package_data = [
        "debug-mgr.dll",
        "debug-mgr.lib"
    ]
else:
    package_data = [
        "%sdebug-mgr.%s" % (libpref, libext)
    ]

ext = Extension("debug_mgr.core",
            extra_compile_args=extra_compile_args,
            sources=[
                os.path.join(debug_mgr_dir, 'python', "core.pyx"),
            ],
            language="c++",
            include_dirs=[
                os.path.join(debug_mgr_dir, 'src'),
                os.path.join(debug_mgr_dir, 'src', 'include')
            ]
        )
ext.cython_directives={'language_level' : '3'}

setup(
  name = "debug-mgr",
  version=version,
  packages=['debug_mgr'],
  package_dir = {'' : 'python'},
  package_data={ 'debug_mgr': package_data },
  author = "Matthew Ballance",
  author_email = "matt.ballance@gmail.com",
  description = ("Simple debug manager for use of C++ Python extensions"),
  long_description="""
  Simple debug manager for use of C++ Python extensions
  """,
  license = "Apache 2.0",
  keywords = ["Debug", "C/C++", "Python"],
  url = "https://github.com/mballance/debug-mgr",
  install_requires=[
  ],
  setup_requires=[
    'setuptools_scm',
    'cython'
  ],
  cmdclass={'build_ext': build_ext},
  ext_modules=[ ext ]
)


import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import pandas_datareader as data
import streamlit as st

st.title('Stock Trend Prediction')

start = '2010-01-01'
end = '2019-12-31'

user_input = st.text_input('Enter Stock Ticker', 'AAPL')
df = data.DataReader(user_input, 'yahoo', start, end)

st.subheader('Data from 2010-2019')
st.write(df.describe())

st.subheader('Closing Price vs Time chart')
fig = plt.figure(figsize = (12,6))
plt.plot(df.Close)
st.pyplot(fig)

st.subheader('Closing Price vs Time chart 100MA')
ma100 = df.Close.rolling(100).mean()
fig = plt.figure(figsize = (12,6))
plt.plot(df.Close)
plt.plot(ma100,'r')
st.pyplot(fig)

st.subheader('Closing Price vs Time chart with 100MA & 200MA')
ma200 = df.Close.rolling(200).mean()
fig = plt.figure(figsize = (12,6))
plt.plot(df.Close)
plt.plot(ma100,'r')
plt.plot(ma200,'g')
st.pyplot(fig)


import allure
from utils.base_web_driver import BaseWebDriver
import pytest
from Common import Log
from Page.Telpo_MDM_Page import TelpoMDMPage

log = Log.MyLog()

class TestTelpoMDM:

    def setup_class(self):
        self.driver = BaseWebDriver().get_web_driver()
        self.page = TelpoMDMPage(self.driver, 40)

    def teardown_class(self):
        pass

    @allure.feature('MDM_test01 -- not run right now')
    @allure.title("Telpo_MDM main Page")  # 设置case的名字
    @pytest.mark.dependency(depends=["test_login_ok"], scope='package')
    @pytest.mark.dependency(name="test_TelpoMdM_Page", scope='package')
    def test_Telpo_page(self):
        exp_main_title = "Devices Map"
        try:
            # 验证当前页面
            log.info("当前页面标题为 %s" % self.driver.title)
            act_main_title = self.page.get_loc_main_title()
            assert exp_main_title in act_main_title
            log.info("当前默认的副标题为：%s" % act_main_title)
        except Exception as e:
            log.error(str(e))
            assert False


from imutils.video import VideoStream
import argparse
import datetime
import imutils
import time
import cv2

min_area = 250

vs = cv2.VideoCapture('case 6 (one after one).MOV')

firstFrame = None

while True:

	frame = vs.read()
	frame = frame if vs is None else frame[1]

	if frame is None:
		break

	frame = imutils.resize(frame, width=500)
	gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
	gray = cv2.GaussianBlur(gray, (21, 21), 0)

	if firstFrame is None:
		firstFrame = gray
		continue

	frameDelta = cv2.absdiff(firstFrame, gray)
	thresh = cv2.threshold(frameDelta, 25, 255, cv2.THRESH_BINARY)[1]

	thresh = cv2.dilate(thresh, None, iterations=2)
	cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,
		cv2.CHAIN_APPROX_SIMPLE)
	cnts = cnts[0] if imutils.is_cv2() else cnts[1]

	for c in cnts:
		if cv2.contourArea(c) < min_area:
			continue

		(x, y, w, h) = cv2.boundingRect(c)
		cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)

	cv2.imshow("Main", frame)
	cv2.imshow("Thresh", thresh)
	cv2.imshow("Delta", frameDelta)
	key = cv2.waitKey(10) & 0xFF
	if key == ord('q'):
		break

vs.stop() if vs is None else vs.release()
cv2.destroyAllWindows()


import json
import xmltodict
from StringIO import StringIO ##IF PYTHON3 from io import StringIO

from pyang.__init__ import Context, FileRepository
from pyang.translators.yin import YINPlugin

def create_yin(yang_model):
    yang_model = str(yang_model).replace('\n', '')

    yang_model_dict = _transform_yang_to_dict(yang_model)
    return json.dumps(yang_model_dict['module'], ensure_ascii=False)

def _transform_yang_to_dict(yang_model_string):
    class Opts(object):
        def __init__(self, yin_canonical=False, yin_pretty_strings=True):
            self.yin_canonical = yin_canonical
            self.yin_pretty_strings = yin_pretty_strings

    ctx = Context(FileRepository())
    yang_mod = ctx.add_module('yang', yang_model_string, format='yang')

    yin = YINPlugin()
    modules = []
    modules.append(yang_mod)
    ctx.opts = Opts()
    yin_string = StringIO()
    yin.emit(ctx=ctx, modules=modules, fd=yin_string)
    xml = yin_string.getvalue()
    return xmltodict.parse(xml)


import logging
import os
import sys

import pandas

from immuno_probs.cdr3.olga_container import OlgaContainer
from immuno_probs.model.default_models import get_default_model_file_paths
from immuno_probs.model.igor_interface import IgorInterface
from immuno_probs.model.igor_loader import IgorLoader
from immuno_probs.util.cli import dynamic_cli_options
from immuno_probs.util.conversion import nucleotides_to_aminoacids
from immuno_probs.util.constant import get_config_data
from immuno_probs.util.io import read_separated_to_dataframe, write_dataframe_to_separated, preprocess_separated_file, copy_to_dir

class GenerateSequences(object):
    """Commandline tool for generating sequences from and IGoR model.

    Parameters
    ----------
    subparsers : argparse.ArgumentParser
        A subparser object for appending the tool's parser and options.

    Methods
    -------
    run(args)
        Uses the given Namespace commandline arguments for generating sequences.

    """
    def __init__(self, subparsers):
        super(GenerateSequences, self).__init__()
        self.logger = logging.getLogger(__name__)
        self.subparsers = subparsers
        self._add_options()

    def _add_options(self):
        """Function for adding the parser and options to the given ArgumentParser.

        Notes
        -----
            Uses the class constructor's subparser object for appending the
            tool's parser and options.

        """
        # Create the description and options for the parser.
        description = "Generate VDJ or VJ sequences given a custom IGoR model (or build-in) by executing IGoR's " \
            "commandline tool via python subprocess. Or generate CDR3 sequences from the model by using OLGA."
        parser_options = {
            '-model': {
                'type': 'str.lower',
                'choices': get_default_model_file_paths(),
                'required': '-custom-model' not in sys.argv,
                'help': "Specify a pre-installed model for generation. (required if -custom-model NOT specified) "
                        "(select one: %(choices)s)."
            },
            '-type': {
                'type': 'str.lower',
                'choices': ['alpha', 'beta', 'light', 'heavy'],
                'required': ('-custom-model' in sys.argv),
                'help': 'The type of the custom model to use. (select one: %(choices)s) (required for -custom-model).'
            },
            '-anchor': {
                'metavar': ('<gene>', '<separated>'),
                'type': 'str',
                'action': 'append',
                'nargs': 2,
                'required': ('-cdr3' in sys.argv and '-custom-model' in sys.argv),
                'help': 'A gene (V or J) followed by a CDR3 anchor separated data file. Note: need to contain gene in the '
                        'first column, anchor index in the second and gene function in the third (required for -cdr3 and '
                        '-custom-model).'
            },
            '-custom-model': {
                'metavar': ('<parameters>', '<marginals>'),
                'type': 'str',
                'nargs': 2,
                'help': 'A IGoR parameters file followed by an IGoR marginals file.'
            },
            '-n-gen': {
                'type': 'int',
                'nargs': '?',
                'help': 'The number of sequences to generate (default: {}).'
                        .format(get_config_data('GENERATE', 'NUM_GENERATE', 'int'))
            },
            '-cdr3': {
                'action': 'store_true',
                'help': 'If specified (True), CDR3 sequences are generated, otherwise V(D)J sequences (default: {}).'
                        .format(get_config_data('GENERATE', 'EVAL_CDR3', 'bool'))
            },
        }

        # Add the options to the parser and return the updated parser.
        parser_tool = self.subparsers.add_parser('generate', help=description, description=description)
        parser_tool = dynamic_cli_options(parser=parser_tool, options=parser_options)

    @staticmethod
    def _process_realizations(data, model, v_gene_choice_col,
                              d_gene_choice_col, j_gene_choice_col):
        """Function for processing an IGoR realization dataframe with indices.

        Parameters
        ----------
        data : pandas.DataFrame
            A pandas dataframe object with the IGoR realization data.
        model : immuno_probs.model.igor_loader.IgorLoader
            Object containing the IGoR model.
        v_gene_choice_col : str
            The name of the V gene choice column to use.
        d_gene_choice_col : str
            The name of the D gene choice column to use.
        j_gene_choice_col : str
            The name of the J gene choice column to use.

        Returns
        -------
        pandas.DataFrame
            A pandas dataframe object with sequence index, the V(D)J gene choice columns containing the names of the
            selected genes.

        """
        # If the suplied model is VDJ, locate important columns and update index values.
        if model.get_type() == "VDJ":
            real_df = pandas.concat([data.filter(regex=("GeneChoice_V_gene_.*")),
                                     data.filter(regex=("GeneChoice_J_gene_.*")),
                                     data.filter(regex=("GeneChoice_D_gene_.*"))],
                                    axis=1, sort=False)
            real_df.columns = [v_gene_choice_col, j_gene_choice_col, d_gene_choice_col]
            real_df[v_gene_choice_col], real_df[j_gene_choice_col], \
                real_df[d_gene_choice_col] = zip(
                    *real_df.apply(lambda row: (
                        model.get_genomic_data().genV[int(row[v_gene_choice_col].strip('()'))][0],
                        model.get_genomic_data().genJ[int(row[j_gene_choice_col].strip('()'))][0],
                        model.get_genomic_data().genD[int(row[d_gene_choice_col].strip('()'))][0]
                    ), axis=1))

        # Or do the same if the model is VJ.
        elif model.get_type() == "VJ":
            real_df = pandas.concat([data.filter(regex=("GeneChoice_V_gene_.*")),
                                     data.filter(regex=("GeneChoice_J_gene_.*"))],
                                    axis=1, sort=False)
            real_df.columns = [v_gene_choice_col, j_gene_choice_col]
            real_df[v_gene_choice_col], real_df[j_gene_choice_col] = zip(
                *real_df.apply(lambda row: (
                    model.get_genomic_data().genV[int(row[v_gene_choice_col].strip('()'))][0],
                    model.get_genomic_data().genJ[int(row[j_gene_choice_col].strip('()'))][0]
                ), axis=1))
        return real_df

    def run(self, args, output_dir):
        """Function to execute the commandline tool.

        Parameters
        ----------
        args : Namespace
            Object containing our parsed commandline arguments.
        output_dir : str
            A directory path for writing output files to.

        """
        eval_cdr3 = get_config_data('GENERATE', 'EVAL_CDR3', 'bool')
        if args.cdr3:
            eval_cdr3 = args.cdr3

        # If the given type of sequences generation is not CDR3, use IGoR.
        if not eval_cdr3:

            # Add general igor commands.
            self.logger.info('Setting up initial IGoR command (1/3)')
            command_list = []
            working_dir = get_config_data('COMMON', 'WORKING_DIR')
            command_list.append(['set_wd', working_dir])
            command_list.append(['threads', str(get_config_data('COMMON', 'NUM_THREADS', 'int'))])

            # Add the model (build-in or custom) command.
            self.logger.info('Processing IGoR model files (2/3)')
            try:
                if args.model:
                    files = get_default_model_file_paths(name=args.model)
                    command_list.append([
                        'set_custom_model',
                        files['parameters'],
                        files['marginals']
                    ])
                elif args.custom_model:
                    command_list.append([
                        'set_custom_model',
                        copy_to_dir(working_dir, str(args.custom_model[0]), 'txt'),
                        copy_to_dir(working_dir, str(args.custom_model[1]), 'txt')
                    ])
            except IOError as err:
                self.logger.error(str(err))
                return

            # Add generate command.
            self.logger.info('Adding additional variables to IGoR command (3/3)')
            if args.n_gen:
                command_list.append(['generate', str(args.n_gen), ['noerr']])
            else:
                command_list.append(['generate', str(get_config_data('GENERATE', 'NUM_GENERATE', 'int')), ['noerr']])

            # Execute IGoR through command line and catch error code.
            self.logger.info('Executing IGoR (this might take a while)')
            try:
                igor_cline = IgorInterface(command=command_list)
                exit_code, _, stderr, _ = igor_cline.call()
                if exit_code != 0:
                    self.logger.error(
                        "An error occurred during execution of IGoR command (exit code %s):\n%s",
                        exit_code, stderr
                    )
                    return
            except OSError as err:
                self.logger.error(str(err))
                return

            # Merge the generated output files together (translated).
            self.logger.info('Processing sequence realizations')
            try:
                seqs_df = read_separated_to_dataframe(
                    file=os.path.join(working_dir, 'generated', 'generated_seqs_noerr.csv'),
                    separator=';',
                    index_col='seq_index',
                    cols=['nt_sequence'])
                seqs_df.index.names = [get_config_data('COMMON', 'I_COL')]
                seqs_df.columns = [get_config_data('COMMON', 'NT_COL')]
                seqs_df[get_config_data('COMMON', 'AA_COL')] = \
                    seqs_df[get_config_data('COMMON', 'NT_COL')].apply(nucleotides_to_aminoacids)
                real_df = read_separated_to_dataframe(
                    file=os.path.join(working_dir, 'generated', 'generated_realizations_noerr.csv'),
                    separator=';',
                    index_col='seq_index')
                real_df.index.names = [get_config_data('COMMON', 'I_COL')]
                if args.model:
                    files = get_default_model_file_paths(name=args.model)
                    model_type = files['type']
                    model = IgorLoader(model_type=model_type,
                                       model_params=files['parameters'],
                                       model_marginals=files['marginals'])
                elif args.custom_model:
                    model_type = args.type
                    model = IgorLoader(model_type=model_type,
                                       model_params=args.custom_model[0],
                                       model_marginals=args.custom_model[1])
                real_df = self._process_realizations(
                    data=real_df,
                    model=model,
                    v_gene_choice_col=get_config_data('COMMON', 'V_GENE_CHOICE_COL'),
                    d_gene_choice_col=get_config_data('COMMON', 'D_GENE_CHOICE_COL'),
                    j_gene_choice_col=get_config_data('COMMON', 'J_GENE_CHOICE_COL'))
                full_seqs_df = seqs_df.merge(real_df, left_index=True, right_index=True)
            except (IOError, KeyError, ValueError) as err:
                self.logger.error(str(err))
                return

            # Write the pandas dataframe to a separated file.
            try:
                self.logger.info('Writing generated sequences to file system')
                output_filename = get_config_data('COMMON', 'OUT_NAME')
                if not output_filename:
                    output_filename = 'generated_seqs_{}'.format(model_type)
                _, filename = write_dataframe_to_separated(
                    dataframe=full_seqs_df,
                    filename=output_filename,
                    directory=output_dir,
                    separator=get_config_data('COMMON', 'SEPARATOR'),
                    index_name=get_config_data('COMMON', 'I_COL'))
                self.logger.info("Written '%s'", filename)
            except IOError as err:
                self.logger.error(str(err))
                return

        # If the given type of sequences generation is CDR3, use OLGA.
        elif eval_cdr3:

            # Get the working directory.
            working_dir = get_config_data('COMMON', 'WORKING_DIR')

            # Load the model, create the sequence generator and generate the sequences.
            self.logger.info('Loading the IGoR model files')
            try:
                if args.model:
                    files = get_default_model_file_paths(name=args.model)
                    model_type = files['type']
                    model = IgorLoader(model_type=model_type,
                                       model_params=files['parameters'],
                                       model_marginals=files['marginals'])
                    args.anchor = [['V', files['v_anchors']],
                                   ['J', files['j_anchors']]]
                    separator = '\t'
                elif args.custom_model:
                    model_type = args.type
                    model = IgorLoader(model_type=model_type,
                                       model_params=args.custom_model[0],
                                       model_marginals=args.custom_model[1])
                    separator = get_config_data('COMMON', 'SEPARATOR')
                for gene in args.anchor:
                    anchor_file = preprocess_separated_file(
                        os.path.join(working_dir, 'cdr3_anchors'),
                        str(gene[1]),
                        separator,
                        ','
                    )
                    model.set_anchor(gene=gene[0], file=anchor_file)
                model.initialize_model()
            except (TypeError, OSError, IOError, KeyError, ValueError) as err:
                self.logger.error(str(err))
                return

            # Setup the sequence generator and generate sequences.
            self.logger.info('Generating sequences')
            try:
                seq_generator = OlgaContainer(
                    igor_model=model,
                    nt_col=get_config_data('COMMON', 'NT_COL'),
                    nt_p_col=get_config_data('COMMON', 'NT_P_COL'),
                    aa_col=get_config_data('COMMON', 'AA_COL'),
                    aa_p_col=get_config_data('COMMON', 'AA_P_COL'),
                    v_gene_choice_col=get_config_data('COMMON', 'V_GENE_CHOICE_COL'),
                    j_gene_choice_col=get_config_data('COMMON', 'J_GENE_CHOICE_COL'))
                n_generate = get_config_data('GENERATE', 'NUM_GENERATE', 'int')
                if args.n_gen:
                    n_generate = args.n_gen
                if n_generate > 0:
                    cdr3_seqs_df = seq_generator.generate(num_seqs=n_generate)
                else:
                    self.logger.error(
                        'Number of sequences to generate should be higher 0')
                    return
            except (TypeError, IOError) as err:
                self.logger.error(str(err))
                return

            # Write the pandas dataframe to a separated file with.
            try:
                self.logger.info('Writing generated sequences to file system')
                output_filename = get_config_data('COMMON', 'OUT_NAME')
                if not output_filename:
                    output_filename = 'generated_seqs_{}_CDR3'.format(model_type)
                _, filename = write_dataframe_to_separated(
                    dataframe=cdr3_seqs_df,
                    filename=output_filename,
                    directory=output_dir,
                    separator=get_config_data('COMMON', 'SEPARATOR'),
                    index_name=get_config_data('COMMON', 'I_COL'))
                self.logger.info("Written '%s'", filename)
            except IOError as err:
                self.logger.error(str(err))
                return

def main():
    """Function to be called when file executed via terminal."""
    print(__doc__)

if __name__ == "__main__":
    main()


# Create your views here.
from django.template import Context, loader
from agutoli.blog.models import Post, Category
from django.http import HttpResponse

def index(request):
    posts_list = Post.objects.filter(published=True)
    category_list = Category.objects.all()
    t = loader.get_template('blog/index.html')
    c = Context({
        'posts_list': posts_list,
        'category_list': category_list
    })
    return HttpResponse(t.render(c))

def detail(request, post_id):
    try:
        post = Post.objects.get(id=post_id)
        t = loader.get_template('blog/detail.html')
    except Post.DoesNotExist:
        post = None
        t = loader.get_template('blog/404.html')
    category_list = Category.objects.all()
    c = Context({
        'post': post,
        'category_list': category_list
    })
    return HttpResponse(t.render(c))


# -*- coding: utf-8 -*-

import pytest
import requests
from pathlib_mate import Path
from sfm.fingerprint import fingerprint
from superjson import json

from seedinvest_monitor.crawler import html_parser

def jprint(data):
    print(json.dumps(data, indent=4, sort_keys=True))

def get_html(url):
    fpath = Path(__file__).change(new_basename="{}.html".format(fingerprint.of_text(url)))
    if fpath.exists():
        html = fpath.read_text(encoding="utf-8")
    else:
        # i am lazy, I don't want to login, session_id is the key
        headers = {
            "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.97 Safari/537.36",
            "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3",
            "accept-encoding": "gzip, deflate, br",
            "accept-language": "en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7,zh-TW;q=0.6,ja;q=0.5",
            "sec-fetch-mode": "navigate",
            "sec-fetch-site": "none",
            # "cookie": "csrftoken=9999JP9mz49NwmqfykyrMupzywy3XZNGgq7Rly23j0u2QuEHdDcOreAnWIjGIhtj; _ga=GA1.2.1853091755.1574187377; _gid=GA1.2.909819738.1574187377; intercom-id-aaaa73km=aaaa1111-18b1-48af-849d-94ad2564a3bc; ga_cid=1853091755.1574187377; sessionid=t2xtsqy6pkf3mkndvd8oljs102ffp6bc; intercom-session-aaaa73km=bXI5eG01b1pJdHlmSk9mYU1jSzZPNGVpWng0KzR6Snk3MngwUjJtNVRzWHhzSHlEenBqTXYyNDRwMWZaekxydC0tUmtTUVo1bjlaNmo3SDVIVFVhcGpCZz09--d927dd0ff0f890889144d645e77525943c851cf5"
        }
        res = requests.get(url, headers=headers)
        html = res.text
        fpath.write_text(html, encoding="utf-8")
    return html

def test_parse_offering_page():
    results = html_parser.parse_offering_page(get_html("https://www.seedinvest.com/offerings"))
    assert len(results) >= 10

def test_parse_project_page():
    result = html_parser.parse_project_page(get_html("https://www.seedinvest.com/nowrx"))
    # jprint(result)

    result = html_parser.parse_project_page(get_html("https://www.seedinvest.com/have.need"))
    # jprint(result)

if __name__ == "__main__":
    import os

    basename = os.path.basename(__file__)
    pytest.main([basename, "-s", "--tb=native"])