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

import unittest

import lxml.html
from lxml.html import builder as html

from wiseguy import form_fields, wrappers

def test_add_class():
    d = html.DIV()
    wrappers._add_class(d, 'foo')
    assert d.attrib['class'] == 'foo'

def test_replace():
    tree = lxml.html.fromstring(
'''

  Hello World
  !

''')
    path = "//span[@class='foo']"
    new_element = lxml.html.fromstring('''Foo''')
    expected = '''

  Foo!

'''.strip()
    result = lxml.html.tostring(
        wrappers.replace(tree, path, new_element)).strip()
    assert expected == result

class TestWrappers(unittest.TestCase):
    bootstrap_form_fields = form_fields.BootstrapFormFields()

    def test_width_select(self):
        context = dict(data=None, errors=None)
        options = [('bar1', "Bar 1"), ('bar2', "Bar 2"), ('bar3', "Bar 3")]
        expected = '''
<fieldset class="control-group">
Foo:
<select id="foo" name="foo" class="span5">
<option value=""></option>
<option value="bar1">Bar 1</option>
<option value="bar2">Bar 2</option>
<option value="bar3">Bar 3</option></select>

</fieldset>'''.strip()
        result = wrappers.width(
            self.bootstrap_form_fields.select({}, 'foo', "Foo:", options),
            5)
        result = lxml.html.tostring(result, pretty_print=True).strip()
        assert expected == result

    def test_width_input(self):
        context = dict(data=None, errors=None)
        expected = '''
<fieldset class="control-group">
Foo:
<input type="text" id="foo" value="" name="foo" class="span5">

</fieldset>'''.strip()
        result = wrappers.width(
            self.bootstrap_form_fields.input(context, 'foo', "Foo:"),
            5)
        result = lxml.html.tostring(result, pretty_print=True).strip()
        assert expected == result

    def test_compulsory(self):
        context = dict()
        expected = '''
<fieldset class="control-group">
Foo:*
<input type="text" id="foo" value="" name="foo">

</fieldset>'''.strip()
        result = wrappers.compulsory(
            self.bootstrap_form_fields.input(context, 'foo', "Foo:"))
        result = lxml.html.tostring(result, pretty_print=True).strip()
        assert expected == result

    def test_with_class(self):
        context = dict()
        expected = '''
<fieldset class="control-group flamble">
Foo:
<input type="text" id="foo" value="" name="foo">

</fieldset>'''.strip()
        result = wrappers.with_class(
            self.bootstrap_form_fields.input(context, 'foo', "Foo:"),
            "//fieldset",
            "flamble")
        result = lxml.html.tostring(result, pretty_print=True).strip()
        assert expected == result


import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

### Create column names ###
def exportColName():
    handColName=['hand_temp', 'hand_acc16g_x', 'hand_acc16g_y', 'hand_acc16g_z', 'hand_acc6g_x', 'hand_acc6g_y', 'hand_acc6g_z',
                 'hand_gyro_x', 'hand_gyro_y', 'hand_gyro_z', 'hand_mag_x', 'hand_mag_y', 'hand_mag_z', 'hand_ori_0', 'hand_ori_1',
                 'hand_ori_2', 'hand_ori_3']
    chestColName=['chest_temp', 'chest_acc16g_x', 'chest_acc16g_y', 'chest_acc16g_z', 'chest_acc6g_x', 'chest_acc6g_y', 'chest_acc6g_z',
                  'chest_gyro_x', 'chest_gyro_y', 'chest_gyro_z', 'chest_mag_x', 'chest_mag_y', 'chest_mag_z', 'chest_ori_0', 'chest_ori_1',
                  'chest_ori_2', 'chest_ori_3']
    ankleColName=['ankle_temp', 'ankle_acc16g_x', 'ankle_acc16g_y', 'ankle_acc16g_z', 'ankle_acc6g_x', 'ankle_acc6g_y', 'ankle_acc6g_z',
                  'ankle_gyro_x', 'ankle_gyro_y', 'ankle_gyro_z', 'ankle_mag_x', 'ankle_mag_y', 'ankle_mag_z', 'ankle_ori_0', 'ankle_ori_1',
                  'ankle_ori_2', 'ankle_ori_3']
    return ['timestamp', 'activityID', 'heart_rate']+handColName+chestColName+ankleColName

### Load a single subject file & Return a dataframe ###
# subjectIndex=1,2,3...9
def loadSubject(subjectIndex):
    filename="PAMAP2_Dataset/Protocol/subject10"+str(subjectIndex)+".dat"
    col=exportColName()
    return pd.read_csv(filename, sep=' ', header=None, names=col)

### Load all subject files & Return a dataframe ###
def loadAllSubjects():
    allData=loadSubject(1)
    col=exportColName()
    for i in range(2, 10):
        filename="PAMAP2_Dataset/Protocol/subject10"+str(i)+".dat"
        tempData=pd.read_csv(filename, sep=' ', header=None, names=col)
        allData=allData.append(tempData)

    allData=allData.reset_index(drop=True)
    return allData

### Load listed subject files & Return a dataframe ###
# using listOfSubID=[1,2,3,4,5,6,7,8,9] is equivalent to loadAllSubjects()
def loadSubjects(listOfSubID):
    allData=loadSubject(listOfSubID[0])
    col=exportColName()
    for i in listOfSubID[1:]:
        filename="PAMAP2_Dataset/Protocol/subject10"+str(i)+".dat"
        tempData=pd.read_csv(filename, sep=' ', header=None, names=col)
        allData=allData.append(tempData)

    allData=allData.reset_index(drop=True)
    return allData

### Plot a pie chart of percentage of each activity ###
def plotActPercentage(data):
    activityAgg=pd.DataFrame(data, columns=['timestamp', 'activityID']).groupby('activityID').count()
    activityAgg['timestamp'].plot(kind='pie', autopct='%.2f', figsize=[6,6])
    plt.legend(loc=(1,0), labels=activityAgg.index);

### Remove activityID=0 data ###
# data is a pd.DataFrame
def removeAct0(data):
    return data.loc[lambda df: df.activityID>0, :].reset_index(drop=True)

### Remove acc6g and orientation ###
def removeAcc6gOri(data):
    colToDrop=['hand_acc6g_x', 'hand_acc6g_y', 'hand_acc6g_z', 'hand_ori_0', 'hand_ori_1', 'hand_ori_2', 'hand_ori_3',
               'chest_acc6g_x', 'chest_acc6g_y', 'chest_acc6g_z', 'chest_ori_0', 'chest_ori_1', 'chest_ori_2', 'chest_ori_3',
               'ankle_acc6g_x', 'ankle_acc6g_y', 'ankle_acc6g_z', 'ankle_ori_0', 'ankle_ori_1', 'ankle_ori_2', 'ankle_ori_3']
    return data.drop(colToDrop, axis=1)

### Return columen names without less useful data ###
def exportEffectiveColName():
    handColName=['hand_temp', 'hand_acc16g_x', 'hand_acc16g_y', 'hand_acc16g_z', 'hand_gyro_x', 'hand_gyro_y', 'hand_gyro_z',
                 'hand_mag_x', 'hand_mag_y', 'hand_mag_z']
    chestColName=['chest_temp', 'chest_acc16g_x', 'chest_acc16g_y', 'chest_acc16g_z', 'chest_gyro_x', 'chest_gyro_y', 'chest_gyro_z',
                  'chest_mag_x', 'chest_mag_y', 'chest_mag_z']
    ankleColName=['ankle_temp', 'ankle_acc16g_x', 'ankle_acc16g_y', 'ankle_acc16g_z', 'ankle_gyro_x', 'ankle_gyro_y', 'ankle_gyro_z',
                  'ankle_mag_x', 'ankle_mag_y', 'ankle_mag_z']
    return ['timestamp', 'activityID', 'heart_rate']+handColName+chestColName+ankleColName

### Fill NaN by (default) linear interpolation ###
def interpolateNaN(data, method='linear'):
    return data.interpolate(method=method, axis=0).ffill().bfill()

# Note: To remove the starting and ending dt sec (=dt*100 timestamp data points) of each activity, the following functions would be helpful

### Create and return a dictionary to store the dataframes of each activity without heads and tails ###
def throwAllHeadsAndTails(data, dt=10):
    actDict = exportActDict(data)
    for a in list(actDict.keys()):
        actDict[a] = throwHeadAndTail(actDict[a], dt)
    return actDict

### Create a dictionary to store the dataframes of each activity ###
def exportActDict(data):
    actID = data.activityID.unique()
    actDict = {}
    for a in actID:
        actDict[a] = data.loc[lambda df: df.activityID==a, :].reset_index(drop=True)
    return actDict

### Return indices that show timestamp discondinuity:
# actDF is a dataframe that contains data with the same activityID
def findTimeDiscontinuity(actDF):
    time = actDF.timestamp
    tgap = np.where(abs(np.array(time[1:])-np.array(time[:-1]))>0.015)[0]
    return tgap

### Remove the head and tail of the activity from each subject ###
# dt=10 means to kill 10sec-long of data
def throwHeadAndTail(actDF, dt=10):
    # find indices that show timestamp discondinuity:
    tgap = findTimeDiscontinuity(actDF)
    n = dt*100

    indToDrop = np.linspace(0, n-1, n)
    for t in range(len(tgap)):
        indToDrop = np.append(indToDrop, np.linspace(tgap[t]-(n-1), tgap[t]+n, 2*n))
    # Need to take care of the case like act24. Use np.unique().
    indToDrop = np.unique(np.append(indToDrop, np.linspace(len(actDF.timestamp)-n, len(actDF.timestamp)-1, n)).astype(int))

    df = actDF.copy()
    df = df.drop(df.index[indToDrop]).reset_index(drop=True)
    return df

# Note: The following functions will be used for segregating spectra. Each segment will overlap the former with 1sec.

### Cut all spectra from all activities into segments ###
def chopAllSpectra(actDict, duration=5.12, withT=True):
    print('Checking discontinuity Count...')
    newActDict = {}
    for a in list(actDict.keys()):
        newActDict[a]=chopSpectrum(actDict[a], duration, withT)
        print('actID={},\t count={}/{}'.format(a, discontinuityCount(newActDict[a]), newActDict[a].shape[0]))
    return newActDict

### Check if there is any data in the 3D array whose timestamp is not continuous ###
# Should return 0 if segregate the data properly.
def discontinuityCount(db):
    t=db.shape[1]
    return np.array([((db[i][t-1][0]-db[i][0][0])>(t/100+0.1) or (db[i][t-1][0]-db[i][0][0])<(t/100-0.1)) for i in range(len(db))]).astype(int).sum()

### Return a 3D narray with many small chuncks of data ###
# duration = 5.12 sec
def chopSpectrum(actDF, duration=5.12, withT=True):
    t = int(duration*100)
    N = len(actDF)
    db = []
    if withT:
        for i in range(int(N/100)):
            if (i*100+t < N) and (actDF.timestamp[i*100+t]-actDF.timestamp[i*100]<duration+0.1) and (actDF.timestamp[i*100+t]-actDF.timestamp[i*100]>duration-0.1):
                db.append(np.array(actDF.loc[i*100:i*100+t-1, :]))
    else:
        for i in range(int(N/100)):
            delt = actDF.timestamp[i*100+t]-actDF.timestamp[i*100]
            if (i*100+t < N) and (delt<duration+0.1) and (delt>duration-0.1):
                db.append(np.array(actDF.loc[i*100:i*100+t-1, 'activityID':]))

    return np.array(db)

### Show the contour plot of the input spectrum segment ###
# segmentData would be a 512 x 34 array
def showContour(segmentData):
    nt, nf = segmentData.shape
    X, Y = np.meshgrid(np.linspace(0, nt-1, nt), np.linspace(0, nf-1, nf))
    Z = segmentData.transpose()

    fig = plt.figure(figsize=[8, 5])
    ax = plt.axes(projection='3d')
    ax.contour3D(X, Y, Z, 80, cmap='YlGnBu')
    ax.view_init(50, -35)
    ax.set_xlabel('time')
    ax.set_ylabel('feature')
    ax.set_zlabel('z');

### Transform a spectrum segment matrix to a tsfresh-compatible data format ###
# replaceT=True will replace timestamp data with index
def toTsfreshFormat(segmentMatrix, replaceT=False):
    effColName = exportEffectiveColName()
    reorderColName = ['activityID']+['timestamp']+effColName[2:]
    df = pd.DataFrame(segmentMatrix, columns=effColName)
    df = df[reorderColName]
    if replaceT:
        df.timestamp = df.index
    return df


# -*- coding: utf-8 -*-
# @Author: jingyuexing
# @Date:   2020-04-21 18:24:20
# @Last Modified by:   jingyuexing
# @Last Modified time: 2020-04-22 18:21:27

import json
import urllib3
http  =urllib3.PoolManager()

head = {
  "Sec-Fetch-Mode":"no-cors",
  "Cache-Control":"max-age=0",
  "Accept-Encoding":"gzip, deflate, br",
  "Accept-Language":"zh-CN,zh;q=0.9",
  "Accept":"application/json, text/plain, */*",
  "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36"
}

with open('data/API.json','r',encoding='utf-8') as file:
    api = json.loads(file.read())
    file.close()

def requests(method='',url='',param={}):
    req = http.request(method=method,url=url,fields=param)
    if(req.status==200):
        return json.loads(req.data.decode('utf-8'),encoding='utf-8')

def GetHotList(limit=30):
    config = api[0]
    method = config['method']
    url = config['link']
    param = {
        'limit':limit,
        "desktop":"true"
    }
    return requests(method=method,url=url,param=param)

def getUserActive(user='',limit=10):
    config = api[1]
    url = config['link'].format(user=user)
    method = config['method']
    param = {
        "limit":limit,
        'desktop':'true'
    }
    return requests(method=method,url=url,param=param)

def getAnswerComment(answerID=0,limit=20,offset=0,status='open'):
    config = api[3]
    url = config['link'].format(answersID=answerID)
    method = config['method']
    param = {
        "limit":limit,
        "offset":offset,
        "status":status
    }
    return requests(method=method,url=url,param=param)

def getUserInfo(username=''):
    if(username!=''):
        config = api[4]
        method = config['method']
        url = config['link'].format(username=username)
        param = {
            "include":"allow_message%2Cis_followed%2Cis_following%2Cfollowing_count%2Cis_org%2Cis_blocking%2Cemployments%2Canswer_count%2Cfollower_count%2Carticles_count%2Cgender"
        }
        return requests(method=method,url=url,param=param)
def getUserFollowers(username='',offset=0,limit=20):
    if(username!=''):
        config = api[5]
        method = config['method']
        url = config['link'].format(username=username)
        param = {
            "limit":limit,
            'offset':offset,
            "include":"data[*].answer_count,articles_count,gender,is_followed,following_count,is_following,badge[?(type=best_answerer)].topics"
        }
        return requests(method=method,url=url,param=param)

class User:
    userId = '' #用户id
    name = '' #名称
    fansNumber = 0 #粉丝数
    answerNumber = 0 #回答数
    following = 0  #关注的人
    articles = 0 #文章数
    face = '' #头像
    vip = False #是否是VIP
    """docstring for User"""
    def __init__(self,userName=''):
        data = getUserInfo(username=userName)
        if(data!=None):
            self.userId = data['id']
            self.articles = data['articles_count']
            self.answerNumber = data['answer_count']
            self.face = data['avatar_url_template']
            self.vip = data['vip_info']['is_vip']
            self.following = data['following_count']
            self.fansNumber = data['follower_count']

class Answer:
    """docstring for Answer"""
    answerID = 0
    def __init__(self, arg):
        pass

class Articles:
    """docstring for Articles"""
    def __init__(self, arg):
        pass


from sklearn import svm, metrics
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt
import pandas as pd

# read weight and height data
tbl = pd.read_csv("bmi.csv")

# normalize data by colums
label = tbl["label"]
w = tbl["weight"] / 100 # presume max weight is 100kg
h = tbl["height"] / 200 # presume max height is 200cm
wh = pd.concat([w, h], axis=1)

# split data into two parts: learn & test
data_train, data_test, label_train, label_test = \
  train_test_split(wh, label)

# make it learn
clf = svm.SVC()
clf.fit(data_train, label_train)

# predict
predict = clf.predict(data_test)

# result
ac_score = metrics.accuracy_score(label_test, predict)
cl_report = metrics.classification_report(label_test, predict)
print("right rate: ", ac_score)
print("report :\n", cl_report)


import torch
import torch.nn as nn
import numpy as np
import pennylane as qml
from qiskit.test.mock import FakeMelbourne
from qiskit.providers.aer.noise import NoiseModel
from qiskit import IBMQ
import qiskit.providers.aer.noise as noise

torch.manual_seed(0)

class Net(nn.Module):
    def __init__(self, n_qubits = None, n_layers = None, n_class = None, n_hidden_Q = 1, n_features = None, \
        noise = 0, shots = 1024):
        super(Net, self).__init__()
        assert n_features%n_qubits == 0
        self.n_hidden_Q = n_hidden_Q #number of hidden quantum layers
        self.n_qubits = n_qubits #number of qubits per parametric circuit
        self.n_layers = n_layers #number of layers in a parametric circuit
        self.n_class = n_class #number of classes in the dataset
        self.n_features = n_features #number of features in the dataset

        weight_shapes = {'weights': (self.n_layers, self.n_qubits)}

        if noise == 0:
            dev = qml.device("default.qubit", wires = self.n_qubits) #target pennylane device
            qnode = qml.QNode(self.circuit, dev, interface = 'torch', diff_method = 'adjoint') #circuit
        elif noise == 'hardware':
            QX_TOKEN = "XX"
            IBMQ.enable_account(QX_TOKEN)
            dev = qml.device('qiskit.ibmq', wires=self.n_qubits, backend='ibmq_bogota')
            qnode = qml.QNode(self.circuit, dev, interface = 'torch', diff_method = 'parameter-shift') #circuit
        else:
            noise_model = self.get_noise_model()
            dev = qml.device('qiskit.aer', wires = self.n_qubits, noise_model = noise_model, \
                shots = shots, basis_gates = noise_model.basis_gates)
            qnode = qml.QNode(self.circuit, dev, interface = 'torch', diff_method = 'parameter-shift') #circuit

        self.ql = nn.ModuleList([qml.qnn.TorchLayer(qnode, weight_shapes) for i in range(int(n_features/n_qubits)*n_hidden_Q)])
        self.lr = nn.ModuleList([nn.LeakyReLU(negative_slope=0.2) for i in range(int(n_features/n_qubits)*n_hidden_Q)])
        #self.drops = nn.ModuleList([nn.Dropout(p=0.33) for i in range(int(n_features/n_qubits)*n_hidden_Q)])
        self.fc1 = nn.Linear(n_features, n_class)

    def circuit(self, inputs, weights):
        assert len(inputs) == self.n_qubits
        #input data angle encoding
        for i, val in enumerate(inputs):
            qml.Hadamard(wires = i)
            qml.RZ(np.pi*val, wires = i)
        #parametric layers
        for l in range(self.n_layers):
            if self.n_qubits > 1:
                for i in range(self.n_qubits):
                    qml.CNOT(wires=[i, (i+1)%self.n_qubits])
            for j in range(self.n_qubits):
                qml.RY(weights[l, j], wires = j)
        #qubit pauli-Z expectation values taken as outputs
        _expectations = [qml.expval(qml.PauliZ(i)) for i in range(self.n_qubits)]
        return _expectations

    def forward(self, X):
        for hq in range(self.n_hidden_Q):
            x = torch.tensor_split(X, int(self.n_features/self.n_qubits), dim = 1)
            segs = []
            for seg, x_segment in enumerate(x):
                x_segment = self.ql[hq * int(self.n_features/self.n_qubits) + seg](x_segment)
                segs.append(x_segment)
            X = torch.cat(segs, dim = 1)
            #shuffling the tensor
            torch.manual_seed(hq)
            X = X[:,torch.randperm(X.size()[1])]
            X = self.lr[hq](X)
            #X = self.drops[hq](X)
        X = self.fc1(X)
        return X

    @staticmethod
    def get_noise_model():
        device_backend = FakeMelbourne()
        noise_model = NoiseModel.from_backend(device_backend)
        return noise_model

    @staticmethod
    def get_noise_model_simple(Noise_Scaling_Factor=None):
        assert Noise_Scaling_Factor is not None
        prob_1 = 0.001*Noise_Scaling_Factor  # 1-qubit gate
        prob_2 = 0.01*Noise_Scaling_Factor   # 2-qubit gate
        error_1 = noise.depolarizing_error(prob_1, 1)
        error_2 = noise.depolarizing_error(prob_2, 2)

        noise_model = NoiseModel()
        noise_model.add_all_qubit_quantum_error(error_1, ['rz', 'h', 'ry', 'rx'])
        noise_model.add_all_qubit_quantum_error(error_2, ['crz', 'cx', 'crx', 'cz'])

        return noise_model


from dataclasses import asdict, dataclass, field
from typing import Dict, List, Optional

ValidationErrorType = Dict[str, List[str]]
ResponseJson = Dict[str, any]

@dataclass
class ErrorDetail:
    error_message: str
    code: Optional[int]
    validation_error: ValidationErrorType = field(default_factory=list)

@dataclass(init=False)
class ErrorResponse:
    errors: ErrorDetail

    def __init__(
        self,
        error_message: str = "",
        validation_error: ValidationErrorType = None,
        code: int = None,
    ):
        validation_error = validation_error or {}
        self.errors = ErrorDetail(
            error_message=error_message, validation_error=validation_error, code=code
        )

    @property
    def error(self) -> ResponseJson:
        return asdict(self)


""" Helper functions for cci_plot.py.
"""

import sys
import math
import numpy as np
import pandas as pd
import matplotlib
import matplotlib.pyplot as plt
from matplotlib.axes import Axes
from matplotlib.patches import Arc, Wedge
from mpl_toolkits.axes_grid1 import make_axes_locatable

from matplotlib.path import Path
import matplotlib.patches as patches
import matplotlib.colors as plt_colors
import matplotlib.cm as cm

from ..tools.microenv.cci.het import get_edges

from anndata import AnnData

# Helper functions for overview plots of the LRs.

def lr_scatter(
    data,
    feature,
    highlight_lrs=None,
    show_text=True,
    n_top=50,
    color="gold",
    alpha=0.5,
    lr_text_fp=None,
    axis_text_fp=None,
    ax=None,
    show=True,
    max_text=100,
    highlight_color="red",
    figsize: tuple = None,
    show_all: bool = False,
):
    """General plotting of the LR features."""
    highlight = type(highlight_lrs) != type(None)
    if not highlight:
        show_text = show_text if n_top <= max_text else False
    else:
        highlight_lrs = highlight_lrs[0:max_text]

    lr_df = data.uns["lr_summary"]
    lrs = lr_df.index.values.astype(str)[0:n_top]
    lr_features = data.uns["lrfeatures"]
    lr_df = pd.concat([lr_df, lr_features], axis=1).loc[lrs, :]
    if feature not in lr_df.columns:
        raise Exception(f"Inputted {feature}; must be one of " f"{list(lr_df.columns)}")

    rot = 90 if feature != "n_spots_sig" else 70

    n_spots = lr_df.loc[:, feature].values[0:n_top]

    return rank_scatter(
        lrs,
        n_spots,
        y_label=feature,
        x_label="LR Rank (n_sig_spots)",
        figsize=figsize,
        highlight_items=highlight_lrs,
        show_text=show_text,
        color=color,
        alpha=alpha,
        lr_text_fp=lr_text_fp,
        axis_text_fp=axis_text_fp,
        ax=ax,
        show=show,
        highlight_color=highlight_color,
        rot=rot,
        pad=0,
        show_all=show_all,
    )
    # ranks = np.array(list(range(len(n_spots))))
    #
    # if type(lr_text_fp)==type(None):
    #     lr_text_fp = {'weight': 'bold', 'size': 8}
    # if type(axis_text_fp)==type(None):
    #     axis_text_fp = {'weight': 'bold', 'size': 12}
    #
    # if type(ax)==type(None):
    #     width = (7.5 / 50) * n_top if show_text and not highlight else 7.5
    #     if width > 20:
    #         width = 20
    #     fig, ax = plt.subplots(figsize=(width, 4))
    #
    # # Plotting the points #
    # ax.scatter(ranks, n_spots, alpha=alpha, c=color)
    #
    # if show_text:
    #     if highlight:
    #         ranks = ranks[[np.where(lrs==lr)[0][0] for lr in highlight_lrs]]
    #         ax.scatter(ranks, n_spots[ranks], alpha=alpha, c=highlight_color)
    #
    #     for i in ranks:
    #         ax.text(i-.2, n_spots[i], lrs[i], rotation=rot, fontdict=lr_text_fp)
    #
    # ax.spines['top'].set_visible(False)
    # ax.spines['right'].set_visible(False)
    # ax.set_xlabel('LR Rank', axis_text_fp)
    # ax.set_ylabel(feature, axis_text_fp)
    #
    # if show:
    #     plt.show()
    # else:
    #     return ax

def rank_scatter(
    items,
    y,
    y_label: str = "",
    x_label: str = "",
    highlight_items=None,
    show_text=True,
    color="gold",
    alpha=0.5,
    lr_text_fp=None,
    axis_text_fp=None,
    ax=None,
    show=True,
    highlight_color="red",
    rot: float = 90,
    point_sizes: np.array = None,
    pad=0.2,
    figsize=None,
    width_ratio=7.5 / 50,
    height=4,
    point_size_name="Sizes",
    point_size_exp=2,
    show_all: bool = False,
):
    """General plotting function for showing ranked list of items."""
    ranks = np.array(list(range(len(items))))

    highlight = type(highlight_items) != type(None)
    if type(lr_text_fp) == type(None):
        lr_text_fp = {"weight": "bold", "size": 8}
    if type(axis_text_fp) == type(None):
        axis_text_fp = {"weight": "bold", "size": 12}

    if type(ax) == type(None):
        if type(figsize) == type(None):
            width = width_ratio * len(ranks) if show_text and not highlight else 7.5
            if width > 20:
                width = 20
            figsize = (width, height)
        fig, ax = plt.subplots(figsize=figsize)

    # Plotting the points #
    scatter = ax.scatter(
        ranks,
        y,
        alpha=alpha,
        c=color,
        s=None if type(point_sizes) == type(None) else point_sizes ** point_size_exp,
        edgecolors="none",
    )
    y_min, y_max = ax.get_ylim()
    y_max = y_max + y_max * pad
    ax.set_ylim(y_min, y_max)
    if type(point_sizes) != type(None):
        # produce a legend with a cross section of sizes from the scatter
        handles, labels = scatter.legend_elements(prop="sizes", alpha=0.6, num=4)
        [handle.set_markeredgecolor("none") for handle in handles]
        starts = [label.find("{") for label in labels]
        ends = [label.find("}") + 1 for label in labels]
        sizes = [
            float(label[(starts[i] + 1) : (ends[i] - 1)])
            for i, label in enumerate(labels)
        ]
        counts = [int(size ** (1 / point_size_exp)) for size in sizes]
        labels2 = [
            label.replace(label[(starts[i]) : (ends[i])], "{" + str(counts[i]) + "}")
            for i, label in enumerate(labels)
        ]
        legend2 = ax.legend(
            handles,
            labels2,
            frameon=False,
            # bbox_to_anchor=(0.1, 0.05, 1., 1.),
            handletextpad=1.6,
            loc="upper right",
            title=point_size_name,
        )

    if show_text:
        if highlight:
            ranks_ = ranks[[np.where(items == item)[0][0] for item in highlight_items]]
            ax.scatter(
                ranks_,
                y[ranks_],
                alpha=alpha,
                c=highlight_color,
                s=None
                if type(point_sizes) == type(None)
                else (point_sizes[ranks_] ** point_size_exp),
                edgecolors=color,
            )
            ranks = ranks_ if not show_all else ranks

        for i in ranks:
            ax.text(i - 0.2, y[i], items[i], rotation=rot, fontdict=lr_text_fp)

    ax.spines["top"].set_visible(False)
    ax.spines["right"].set_visible(False)
    ax.set_xlabel(x_label, axis_text_fp)
    ax.set_ylabel(y_label, axis_text_fp)

    if show:
        plt.show()
    else:
        return ax

# Helper functions for lr_plot

def add_arrows(
    adata: AnnData,
    l_expr: np.array,
    r_expr: np.array,
    min_expr: float,
    sig_bool: np.array,
    fig,
    ax: Axes,
    use_label: str,
    int_df: pd.DataFrame,
    head_width=4,
    width=0.001,
    arrow_cmap=None,
    arrow_vmax=None,
):
    """ Adds arrows to the current plot for significant spots to neighbours \
        which is interacting with.
        Parameters
        ----------
        adata: AnnData          The anndata object.
        L_bool: np.array
        Returns
        -------
        counts: int   Total number of interactions satisfying the conditions, \
                      or np.array<set> if return_edges=True, where each set is \
                      an edge, only returns unique edges.
    """

    library_id = list(adata.uns["spatial"].keys())[0]
    res = adata.uns["spatial"][library_id]["use_quality"]
    scale_factor = adata.uns["spatial"][library_id]["scalefactors"][
        f"tissue_{res}_scalef"
    ]
    # scale_factor = 1
    # scale_factor = 1 # scale factor pretty much isn't used since always parsed as 1
    # in the base plotting function class.
    # Reason why is because scale_factor refers to scaling the
    # image to match the spot spatial coordinates, not the
    # the spots to match the image coordinates!!!

    L_bool = l_expr > min_expr
    R_bool = r_expr > min_expr

    # Getting the edges, from sig-L->R and sig-R<-L #
    forward_edges, reverse_edges = get_edges(adata, L_bool, R_bool, sig_bool)

    # If int_df specified, means need to subset to CCIs which are significant #
    if type(int_df) != type(None):
        spot_bcs = adata.obs_names.values.astype(str)
        spot_labels = adata.obs[use_label].values.astype(str)
        label_set = int_df.index.values.astype(str)
        interact_bool = int_df.values > 0

        # Subsetting to only significant CCI #
        edges_sub = [[], []]  # forward, reverse
        # ints_2 = np.zeros(int_df.shape) # Just for debugging make sure edge
        # list re-capitulates edge-counts.
        for i, edges in enumerate([forward_edges, reverse_edges]):
            for j, edge in enumerate(edges):
                k_ = [0, 1] if i == 0 else [1, 0]
                celltype0 = np.where(label_set == spot_labels[spot_bcs == edge[k_[0]]])[
                    0
                ][0]
                celltype1 = np.where(label_set == spot_labels[spot_bcs == edge[k_[1]]])[
                    0
                ][0]
                celltypes = np.array([celltype0, celltype1])
                # For debugging purposes, used to find indexing bug #
                # print(label_set[celltypes[k_[0]]],
                #       label_set[celltypes[k_[1]]])
                # print( celltypes[k_[0]], celltypes[k_[1]] )
                # print( interact_bool[celltypes[k_[0]], celltypes[k_[1]]] )
                if interact_bool[celltypes[k_[0]], celltypes[k_[1]]]:
                    edges_sub[i].append(edge)
                    # ints_2[celltypes[k_[0]], celltypes[k_[1]]] += 1

        forward_edges, reverse_edges = edges_sub

    # If cmap specified, colour arrows by average LR expression on edge #
    if type(arrow_cmap) != type(None):
        edges_means = [[], []]
        all_means = []
        for i, edges in enumerate([forward_edges, reverse_edges]):
            for j, edge in enumerate(edges):
                edge0_bool = spot_bcs == edge[0]
                edge1_bool = spot_bcs == edge[1]
                l_expr0 = l_expr[edge0_bool]
                l_expr1 = l_expr[edge1_bool]
                r_expr0 = r_expr[edge0_bool]
                r_expr1 = r_expr[edge1_bool]
                mean_expr = np.mean([l_expr0, l_expr1, r_expr0, r_expr1])
                edges_means[i].append(mean_expr)
                all_means.append(mean_expr)

        # Determining the color maps #
        arrow_vmax = np.max(all_means) if type(arrow_vmax) == type(None) else arrow_vmax
        cmap = plt.get_cmap(arrow_cmap)
        c_norm = plt_colors.Normalize(vmin=0, vmax=arrow_vmax)
        scalar_map = cm.ScalarMappable(norm=c_norm, cmap=cmap)

        # Determining the edge colors #
        edges_colors = [[], []]
        for i, edges in enumerate([forward_edges, reverse_edges]):
            for j, edge in enumerate(edges):
                color_val = scalar_map.to_rgba(edges_means[i][j])
                edges_colors[i].append(color_val)

        # Need to add new axes #
        # xlims = ax.get_xlim()
        # ylims = ax.get_ylim()
        # left, bottom = xlims[0]*0.025, ylims[0]*0.17
        # axc = fig.add_axes([0, 0, 0.28, 0.015])
        divider = make_axes_locatable(ax)
        cax = divider.new_vertical(size="2%", pad=0.1, pack_start=True)
        axc = fig.add_axes(cax)

    else:
        edges_colors = [None, None]

    # Now performing the plotting #
    # The arrows #
    # Now converting the edges to coordinates #
    add_arrows_by_edges(
        ax,
        adata,
        forward_edges,
        scale_factor,
        head_width,
        width,
        edge_colors=edges_colors[0],
    )
    add_arrows_by_edges(
        ax,
        adata,
        reverse_edges,
        scale_factor,
        head_width,
        width,
        forward=False,
        edge_colors=edges_colors[1],
    )
    # Adding the color map #
    if type(arrow_cmap) != type(None):
        cb1 = matplotlib.colorbar.ColorbarBase(
            axc, cmap=cmap, norm=c_norm, orientation="horizontal"
        )

def add_arrows_by_edges(
    ax,
    adata,
    edges,
    scale_factor,
    head_width,
    width,
    forward=True,
    edge_colors=None,
    axc=None,
):
    """Adds the arrows using an edge list."""
    for i, edge in enumerate(edges):
        # cols = ["imagecol", "imagerow"]
        if forward:
            edge0, edge1 = edge
        else:
            edge0, edge1 = edge[::-1]

        # Arrow details #
        # x1, y1 = adata.obs.loc[edge0, cols].values.astype(float) * scale_factor
        # x2, y2 = adata.obs.loc[edge1, cols].values.astype(float) * scale_factor
        edge0_index = np.where(adata.obs_names.values == edge0)[0][0]
        edge1_index = np.where(adata.obs_names.values == edge1)[0][0]
        x1, y1 = adata.obsm["spatial"][edge0_index, :] * scale_factor
        x2, y2 = adata.obsm["spatial"][edge1_index, :] * scale_factor
        dx, dy = (x2 - x1) * 0.75, (y2 - y1) * 0.75
        arrow_color = "k" if type(edge_colors) == type(None) else edge_colors[i]

        ax.arrow(
            x1,
            y1,
            dx,
            dy,
            head_width=head_width,
            width=width,
            linewidth=0.01,
            facecolor=arrow_color,
        )

# Helper functions for cci_map

def get_int_df(adata, lr, use_label, sig_interactions, title):
    """Retrieves the relevant interaction count matrix."""
    no_title = type(title) == type(None)
    labels_ordered = adata.obs[use_label].cat.categories
    if type(lr) == type(None):  # No LR inputted, so just use all
        int_df = (
            adata.uns[f"lr_cci_{use_label}"]
            if sig_interactions
            else adata.uns[f"lr_cci_raw_{use_label}"]
        )[labels_ordered].loc[labels_ordered]
        title = "Cell-Cell LR Interactions" if no_title else title
    else:

        labels_ordered = adata.obs[use_label].cat.categories
        int_df = (
            adata.uns[f"per_lr_cci_{use_label}"][lr]
            if sig_interactions
            else adata.uns[f"per_lr_cci_raw_{use_label}"][lr]
        )[labels_ordered].loc[labels_ordered]

        title = f"Cell-Cell {lr} interactions" if no_title else title

    return int_df, title

def create_flat_df(int_df):
    """Reformats a dataframe representing interactions to a flat format."""
    n_rows = int_df.shape[0] * int_df.shape[1]
    flat_df = pd.DataFrame(index=list(range(n_rows)), columns=["x", "y", "value"])
    row_i = 0
    for i, cell_typei in enumerate(int_df.index.values):
        for j, cell_typej in enumerate(int_df.columns.values):
            flat_df.iloc[row_i, :] = [cell_typei, cell_typej, int_df.values[i, j]]
            row_i += 1

    return flat_df

def _box_map(x, y, size, ax=None, figsize=(6.48, 4.8), cmap=None, square_scaler=700):
    """Main underlying helper function for generating the heatmaps."""
    if type(cmap) == type(None):
        cmap = "Spectral_r"

    if type(ax) == type(None):
        fig, ax = plt.subplots(figsize=figsize)

    # Mapping from column names to integer coordinates
    x_labels = list(x.values)  # [v for v in sorted(x.unique())]
    y_labels = list(y.values)  # [v for v in sorted(y.unique())]
    x_to_num = {p[1]: p[0] for p in enumerate(x_labels)}
    y_to_num = {p[1]: p[0] for p in enumerate(y_labels)}

    out = ax.scatter(
        x=x.map(x_to_num),  # Use mapping for x
        y=y.map(y_to_num),  # Use mapping for y
        s=size / sum(size) * square_scaler,
        c=size,
        cmap=cmap,
        # Vector of square sizes, proportional to size parameter
        marker="s",  # Use square as scatterplot marker
    )
    out.set_array(size.values.astype(int))
    out.set_clim(min(size), max(size))
    cbar = plt.colorbar(out)
    cbar.ax.get_yaxis().labelpad = 15
    cbar.ax.set_ylabel("# of interactions", rotation=270)

    # Show column labels on the axes
    ax.set_xticks([x_to_num[v] for v in x_labels])
    ax.set_xticklabels(x_labels, rotation=45, horizontalalignment="right")
    ax.set_yticks([y_to_num[v] for v in y_labels])
    ax.set_yticklabels(y_labels)

    return ax

# Matplotlib chord diagram, adapted & refactored from:
# https://github.com/fengwangPhysics/matplotlib-chord-diagram/blob/master/matplotlib-chord.py

###################
# chord diagram
LW = 0.3

def polar2xy(r, theta):
    return np.array([r * np.cos(theta), r * np.sin(theta)])

def hex2rgb(c):
    return tuple(int(c[i : i + 2], 16) / 256.0 for i in (1, 3, 5))

def IdeogramArc(
    start=0, end=60, radius=1.0, width=0.2, ax=None, color=(1, 0, 0), curve_steps=1
):
    # start, end should be in [0, 360)
    if start > end:
        start, end = end, start
    start *= np.pi / 180.0
    end *= np.pi / 180.0
    # optimal distance to the control points
    # https://stackoverflow.com/questions/1734745/how-to-create-circle-with-b%C3%A9zier-curves
    opt = 4.0 / 3.0 * np.tan((end - start) / 4.0) * radius
    inner = radius * (1 - width)

    # Defines descrete points along the arc #
    # The outter part of the arc #

    val = 0.5
    verts_upper_start = [polar2xy(radius, start)]
    verts_upper_curve = [
        polar2xy(radius, start)
        + polar2xy(opt, start + (np.pi * ((val * i) / curve_steps)))
        for i in range(1, curve_steps + 1)
    ]
    verts_upper_curve += [
        polar2xy(radius, end) + polar2xy(opt, end - (np.pi * ((val * i) / curve_steps)))
        for i in range(1, curve_steps + 1)
    ]
    verts_upper = verts_upper_start + verts_upper_curve + [polar2xy(radius, end)]

    verts_inner_start = [polar2xy(inner, end)]
    verts_inner_curve = [
        polar2xy(inner, end)
        + polar2xy(opt * (1 - width), end - (np.pi * ((val * i) / curve_steps)))
        for i in range(1, curve_steps + 1)
    ]
    verts_inner_curve += [
        polar2xy(inner, start)
        + polar2xy(opt * (1 - width), start + (np.pi * ((val * i) / curve_steps)))
        for i in range(1, curve_steps + 1)
    ]
    verts_inner = (
        verts_inner_start
        + verts_inner_curve
        + [polar2xy(inner, start), polar2xy(radius, start)]
    )

    verts = verts_upper + verts_inner

    codes = (
        [Path.MOVETO]
        + [Path.CURVE4] * curve_steps * 2
        + [Path.CURVE4, Path.LINETO]
        + [Path.CURVE4] * curve_steps * 2
        + [
            Path.CURVE4,
            Path.CLOSEPOLY,
        ]
    )

    if ax == None:
        return verts, codes
    else:
        path = Path(verts, codes)
        patch = patches.PathPatch(
            path, facecolor=color + (0.5,), edgecolor=color + (0.4,), lw=LW
        )
        ax.add_patch(patch)

def ChordArc(
    start1=0,
    end1=60,
    start2=180,
    end2=240,
    radius=1.0,
    chordwidth=0.7,
    ax=None,
    color=(1, 0, 0),
):
    # start, end should be in [0, 360)
    if start1 > end1:
        start1, end1 = end1, start1
    if start2 > end2:
        start2, end2 = end2, start2
    start1 *= np.pi / 180.0
    end1 *= np.pi / 180.0
    start2 *= np.pi / 180.0
    end2 *= np.pi / 180.0
    opt1 = 4.0 / 3.0 * np.tan((end1 - start1) / 4.0) * radius
    opt2 = 4.0 / 3.0 * np.tan((end2 - start2) / 4.0) * radius
    rchord = radius * (1 - chordwidth)
    verts = [
        polar2xy(radius, start1),
        polar2xy(radius, start1) + polar2xy(opt1, start1 + 0.5 * np.pi),
        polar2xy(radius, end1) + polar2xy(opt1, end1 - 0.5 * np.pi),
        polar2xy(radius, end1),
        polar2xy(rchord, end1),
        polar2xy(rchord, start2),
        polar2xy(radius, start2),
        polar2xy(radius, start2) + polar2xy(opt2, start2 + 0.5 * np.pi),
        polar2xy(radius, end2) + polar2xy(opt2, end2 - 0.5 * np.pi),
        polar2xy(radius, end2),
        polar2xy(rchord, end2),
        polar2xy(rchord, start1),
        polar2xy(radius, start1),
    ]

    codes = [
        Path.MOVETO,
        Path.CURVE4,
        Path.CURVE4,
        Path.CURVE4,
        Path.CURVE4,
        Path.CURVE4,
        Path.CURVE4,
        Path.CURVE4,
        Path.CURVE4,
        Path.CURVE4,
        Path.CURVE4,
        Path.CURVE4,
        Path.CURVE4,
    ]

    if ax == None:
        return verts, codes
    else:
        path = Path(verts, codes)
        patch = patches.PathPatch(
            path, facecolor=color + (0.5,), edgecolor=color + (0.4,), lw=LW
        )
        ax.add_patch(patch)

def selfChordArc(start=0, end=60, radius=1.0, chordwidth=0.7, ax=None, color=(1, 0, 0)):
    # start, end should be in [0, 360)
    if start > end:
        start, end = end, start
    start *= np.pi / 180.0
    end *= np.pi / 180.0
    opt = 4.0 / 3.0 * np.tan((end - start) / 4.0) * radius
    rchord = radius * (1 - chordwidth)
    verts = [
        polar2xy(radius, start),
        polar2xy(radius, start) + polar2xy(opt, start + 0.5 * np.pi),
        polar2xy(radius, end) + polar2xy(opt, end - 0.5 * np.pi),
        polar2xy(radius, end),
        polar2xy(rchord, end),
        polar2xy(rchord, start),
        polar2xy(radius, start),
    ]

    codes = [
        Path.MOVETO,
        Path.CURVE4,
        Path.CURVE4,
        Path.CURVE4,
        Path.CURVE4,
        Path.CURVE4,
        Path.CURVE4,
    ]

    if ax == None:
        return verts, codes
    else:
        path = Path(verts, codes)
        patch = patches.PathPatch(
            path, facecolor=color + (0.5,), edgecolor=color + (0.4,), lw=LW
        )
        ax.add_patch(patch)

def chordDiagram(X, ax, colors=None, width=0.1, pad=2, chordwidth=0.7, lim=1.1):
    """Plot a chord diagram
    Parameters
    ----------
    X :
        flux data, X[i, j] is the flux from i to j
    ax :
        matplotlib `axes` to show the plot
    colors : optional
        user defined colors in rgb format. Use function hex2rgb() to convert hex color to rgb color. Default: d3.js category10
    width : optional
        width/thickness of the ideogram arc
    pad : optional
        gap pad between two neighboring ideogram arcs, unit: degree, default: 2 degree
    chordwidth : optional
        position of the control points for the chords, controlling the shape of the chords
    """
    # X[i, j]:  i -> j
    x = X.sum(axis=1)  # sum over rows
    ax.set_xlim(-lim, lim)
    ax.set_ylim(-lim, lim)
    diam = 1.8

    if colors is None:
        # use d3.js category10 https://github.com/d3/d3-3.x-api-reference/blob/master/Ordinal-Scales.md#category10
        colors = [
            "#1f77b4",
            "#ff7f0e",
            "#2ca02c",
            "#d62728",
            "#9467bd",
            "#8c564b",
            "#e377c2",
            "#7f7f7f",
            "#bcbd22",
            "#17becf",
        ]
        if len(x) > 10:
            print("x is too large! Use x smaller than 10")
    if type(colors[0]) == str:
        colors = [hex2rgb(colors[i]) for i in range(len(x))]

    # find position for each start and end
    y = x / np.sum(x).astype(float) * (360 - pad * len(x))

    pos = {}
    arc = []
    nodePos = []
    start = 0
    for i in range(len(x)):
        end = start + y[i]
        arc.append((start, end))
        angle = 0.5 * (start + end)
        # print(start, end, angle)
        if -30 <= angle <= 210:
            angle -= 90
        else:
            angle -= 270
        nodePos.append(
            tuple(
                polar2xy((diam / 2) + diam * 0.05, 0.5 * (start + end) * np.pi / 180.0)
            )
            + (angle,)
        )
        z = (X[i, :] / x[i].astype(float)) * (end - start)
        ids = np.argsort(z)
        z0 = start
        for j in ids:
            pos[(i, j)] = (z0, z0 + z[j])
            z0 += z[j]
        start = end + pad

    for i in range(len(x)):
        start, end = arc[i]
        # This draws the outter ring #
        # IdeogramArc(start=start, end=end, radius=1.0, ax=ax,
        #            color=colors[i], width=width)
        a = Arc((0, 0), diam, diam, 0, start, end, color=colors[i], lw=10)
        ax.add_patch(a)
        start, end = pos[(i, i)]
        # This draws the paths to itself #
        if end - start < 180:  # Indicates this method will work fine !
            selfChordArc(
                start,
                end,
                radius=1.0 - width,
                color=colors[i],
                chordwidth=chordwidth * 0.7,
                ax=ax,
            )
        else:  # Need to use a wedge because the arch distorts past 180-degrees
            path = Wedge(0, diam / 2, start, end, color=colors[i] + (0.5,))
            ax.add_patch(path)
        for j in range(i):
            if X[i, j] == 0 and X[j, i] == 0:  # don't draw anything for no interaction
                continue
            color = colors[i]
            if X[i, j] > X[j, i]:  # Color by the dominant signal #
                color = colors[j]
            start1, end1 = pos[(i, j)]
            start2, end2 = pos[(j, i)]
            ChordArc(
                start1,
                end1,
                start2,
                end2,
                radius=1.0 - width,
                color=color,
                chordwidth=chordwidth,
                ax=ax,
            )

    return nodePos


from django.urls import path, include
from rest_framework_nested import routers

from . import views

router = routers.SimpleRouter()
router.register('dosen', views.DosenViewSet, basename='dosen')
router.register('gedung', views.GedungKuliahViewSet, basename='gedung')
router.register('jurusan', views.JurusanViewSet, basename='jurusan')
router.register('karya_ilmiah', views.KaryaIlmiahViewSet, basename='karya_ilmiah')
router.register('kelas', views.KelasViewSet, basename='kelas')
router.register('mahasiswa', views.MahasiswaViewSet, basename='mahasiswa')
router.register('makul', views.MataKuliahViewSet, basename='makul')
router.register('prodi', views.ProgramStudiViewSet, basename='prodi')
router.register('program_pendidikan', views.ProgramPendidikanViewSet, basename='program_pendidikan')
router.register('semester', views.SemesterViewSet, basename='semester')
router.register('staff_prodi', views.StaffProdiViewSet, basename='staff_prodi')

router.register('ruangan', views.RuanganViewSet, basename='ruangan')
ruangan_aduan = routers.NestedSimpleRouter(router, 'ruangan', lookup='ruangan')
ruangan_aduan.register('aduan', views.AduanRuanganViewSet, basename='ruangan-aduan')

router.register('pemberitahuan', views.PemberitahuanViewSet, basename='pemberitahuan')
pemberitahuan_prodi = routers.NestedDefaultRouter(router, 'pemberitahuan', lookup='pemberitahuan')
pemberitahuan_prodi.register('prodi', views.PemberitahuanProdiViewSet, basename='pemberitahuan-prodi')
pemberitahuan_jurusan = routers.NestedDefaultRouter(router, 'pemberitahuan', lookup='pemberitahuan')
pemberitahuan_jurusan.register('jurusan', views.PemberitahuanJurusanViewSet, basename='pemberitahuan-jurusan')

router.register('jadwal', views.JadwalViewSet, basename='jadwal')
jadwal_makul = routers.NestedDefaultRouter(router, 'jadwal', lookup='jadwal')
jadwal_makul.register('makul', views.JadwalMakulViewSet, basename='jadwal-makul')

router.register('khs', views.KHSViewSet, basename='khs')
nilai_khs = routers.NestedDefaultRouter(router, 'khs', lookup='khs')
nilai_khs.register('nilai', views.NilaiKHSViewSet, basename='nilai')

urlpatterns = [
    path('', include(router.urls)),
    path('', include(ruangan_aduan.urls)),
    path('', include(pemberitahuan_prodi.urls)),
    path('', include(pemberitahuan_jurusan.urls)),
    path('', include(jadwal_makul.urls)),
    path('', include(nilai_khs.urls))
]


from urllib.request import urlopen
from bs4 import BeautifulSoup
import ssl
import re

# Ignore SSL certificate errors
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE

url = input('Enter - ')
html = urlopen(url, context=ctx).read()
soup = BeautifulSoup(html, "html.parser")

# Retrieve all of the anchor tags
count = 0
lista = list()
tags = soup('span')
#print(tags)
for tag in tags:
    cut = tag.contents[0]
    cuts = re.findall('[0-9]+',cut)
    if len(cuts) == 0 : continue

    for num in cuts:
        nums = int(num)
        #print("esto es nums",nums)
        lista.append(nums)
        count = sum(lista)

print("Este es el resultado:",count)


import os
import numpy as np
import cv2
from sklearn import cluster
from sklearn.model_selection import StratifiedKFold

original_dataset_path = '/home/ghivi/yt_dataset'
raw_dataset_path = '/home/ghivi/Raw'
processed_dataset_path = '/home/ghivi/Processed'

def create_dirs(save_path, subdirs):
    for subdir in subdirs:
        dir_path = os.path.join(save_path, subdir)
        if not os.path.exists(dir_path):
            os.makedirs(dir_path)

def resize_2d_coords(old_width, old_height, new_width, new_height, points):
    x_factor = new_width / old_width
    y_factor = new_height / old_height
    scaling_matrix = np.array([[x_factor, 0, 0], # sx  0   0
                               [0, y_factor, 0], # 0   sy  0
                               [0, 0, 1]])       # 0   0   1

    points_matrix = points.transpose()
    points_matrix = np.vstack((points_matrix, np.ones(len(points)))) # [x_coords,
                                                                     #  y_coords,
                                                                     #  1]

    scaled_points = scaling_matrix @ points_matrix
    scaled_points = np.delete(scaled_points, obj=2, axis=0)
    scaled_points = scaled_points.transpose()

    return scaled_points

def draw(img, bbox, kps):
    cv2.rectangle(img, tuple(bbox[0].astype(int)), tuple(bbox[3].astype(int)), (0,0,255), 1)
    for pt in kps:
        cv2.circle(img, tuple(pt.astype(int)), 1, (255,0,0), 1)

def task_1(original_path, save_path):
    create_dirs(save_path, ['images', 'bounding_boxes', 'landmarks2D'])
    batches = next(os.walk(original_path))[1]
    for batch in batches:
        batch_path = os.path.join(original_path, batch)
        samples = os.listdir(batch_path)
        for sample in samples:
            sample_path = os.path.join(batch_path, sample)
            sample_data = np.load(sample_path)
            imgs = sample_data['colorImages']
            bboxes = sample_data['boundingBox']
            lm2d = sample_data['landmarks2D']
            lm2d = np.moveaxis(lm2d, -1, 0)
            bboxes = np.moveaxis(bboxes, -1, 0)
            imgs = np.moveaxis(imgs, -1, 0)

            assert(len(imgs) == len(bboxes) == len(lm2d))
            for index in range(len(imgs)):
                img = imgs[index]
                img = img[..., ::-1]  #rgb2bgr
                cv2.imwrite(os.path.join(save_path, 'images', sample + str(index) + '.png'), img)

                bbox = bboxes[index]
                np.save(os.path.join(save_path, 'bounding_boxes', sample + str(index) + '.npy'), bbox)

                keypoints2d = lm2d[index]
                np.save(os.path.join(save_path, 'landmarks2D', sample + str(index) + '.npy'), keypoints2d)

def task_2(original_path, save_path, new_width, new_height):

    create_dirs(save_path, ['images', 'bounding_boxes', 'landmarks2D'])
    images_path = os.path.join(original_path, 'images')
    images = os.scandir(images_path)
    bboxes_path = os.path.join(original_path, 'bounding_boxes')
    lms_path = os.path.join(original_path, 'landmarks2D')
    for image in images:
        img = cv2.imread(os.path.join(images_path, image.name))
        old_width = img.shape[1]
        old_height = img.shape[0]
        new_dim = (new_width, new_height)
        resized = cv2.resize(img, new_dim, interpolation=cv2.INTER_AREA)

        old_bbox = np.load(os.path.join(bboxes_path, image.name.replace('.png', '.npy')))
        new_bbox = resize_2d_coords(old_width, old_height, new_width, new_height, old_bbox)

        old_keypoints = np.load(os.path.join(lms_path, image.name.replace('.png', '.npy')))
        new_keypoints = resize_2d_coords(old_width, old_height, new_width, new_height, old_keypoints)

        draw(resized, new_bbox, new_keypoints)
        cv2.imwrite(os.path.join(save_path, 'images', image.name), resized)
        np.save(os.path.join(save_path, 'bounding_boxes', image.name.replace('.png', '.npy')), new_bbox)
        np.save(os.path.join(save_path, 'landmarks2D', image.name.replace('.png', '.npy')), new_keypoints)

def task_3(original_path):
    lm2d_path = os.path.join(original_path, 'landmarks2D')
    landmarks = os.scandir(lm2d_path)
    all_kps = None
    names = []
    for lm in landmarks:
        names.append(lm.name.replace('.npy', ''))
        keypoints = np.load(os.path.join(lm2d_path, lm.name))
        keypoints = np.expand_dims(keypoints, axis=2)
        if all_kps is None:
            all_kps = keypoints
        else:
            all_kps = np.concatenate((all_kps, keypoints), axis=2)

    kps_centered = all_kps - np.tile(all_kps.mean(axis=0), [68, 1, 1])

    kps_normlized = kps_centered / np.tile(
        np.sqrt((kps_centered ** 2).sum(axis=1)).mean(axis=0), [68, 2, 1])

    numClusters = 16
    normalizedShapesTable = np.reshape(kps_normlized, [68 * 2, kps_normlized.shape[2]]).T

    shapesModel = cluster.KMeans(n_clusters=numClusters, n_init=5, random_state=1).fit(normalizedShapesTable[::2, :])
    clusterAssignment = shapesModel.predict(normalizedShapesTable)

    skf = StratifiedKFold(n_splits=10)
    folds = skf.split(names, clusterAssignment)
    return folds

task_1(original_dataset_path, raw_dataset_path)
task_2(raw_dataset_path, processed_dataset_path, 200, 200)
folds = task_3(raw_dataset_path)


from django.conf import settings
from django.conf.urls.static import static
from django.urls import path
from . import views

urlpatterns = [
    path('', views.EventListView.as_view(), name="events-list"),
    path('manage/', views.EventManageView.as_view(), name="events-manage"),
    path('create/', views.EventCreateView.as_view(), name="events-create"),
    path('<int:event_pk>/event_register/', views.EventRegisterView.as_view(), name="event-register"),
    path("<int:pk>/detail/", views.EventDetailView.as_view(), name="event-detail"),
    path("<int:pk>/delete/", views.EventDeleteView.as_view(), name="events-delete"),
    path("<int:pk>/update/", views.EventUpdateView.as_view(), name="events-update"),
]

if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)


"""
    AVRO/PARQUET/JSON converter
"""
import copy
import json
import avro.schema
# from avro.datafile import DataFileWriter, DataFileReader
# from avro.io import DatumWriter, DatumReader
import pandas as pd
import datetime
import json, time, sys
import pandas as pd
import apache_beam as beam
import pyarrow
import os
import glob
import shutil, avro
import argparse
import fastavro
from fastavro import parse_schema
from fastavro import writer
from fastavro.schema import load_schema

# from file "schema.avsc"
default_schema = '''
{
 "namespace": "example.avro",
 "type": "record",
 "name": "User",
 "fields": [
     {"name": "objectUai", "type": "string"},
     {"name": "sourceTimestamp",    "type": {   "type": "long",   "logicalType": "timestamp-micros" }},
     {"name": "variableName", "type": "string"},
     {"name": "dataValue", "type": "string"},
     {"name": "siteCode", "type": "string"},
     {"name": "objectType", "type": "string"}
 ]
}
'''
fa_default_schema = {
    "namespace": "example.avro",
    "type": "record",
    "name": "User",
    "fields": [
        {"name": "objectUai", "type": "string"},
        {"name": "sourceTimestamp", "type": {"type": "long", "logicalType": "timestamp-micros"}},
        {"name": "variableName", "type": "string"},
        {"name": "dataValue", "type": "string"},
        {"name": "siteCode", "type": "string"},
        {"name": "objectType", "type": "string"}
    ]
}

# parquet_schema = pyarrow.schema(
#     [('objectUai', pyarrow.string()),
#      ('objectType', pyarrow.string()),
#      ('variableName', pyarrow.string()),
#      ('sourceTimestamp', pyarrow.timestamp('s', tz='+00:00')),
#      ('dataValue', pyarrow.string()),
#      ('siteCode', pyarrow.string())
#      ]
# )

def timestamp_as_string(d):
    """ replace timestamp as string"""
    r = {}
    for k, v in d.items():
        r[k] = str(v) if isinstance(v, datetime.datetime) else v
    return r

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='AVRO/PARQUET/JSON converter ')
    parser.add_argument('-s', '--src', default="gs://vkunitki-dev/test_1.parquet")
    # parser.add_argument('--src',
    #                     default="/temp/udc/initial/METADATA_INPUT_BATTERYCHARGER_part-00000-5c8d9274-5572-46a1-8e29-95fd4ed9b4b5-c000.snappy.parquet")
    # parser.add_argument('--dest', default="out_1/test_2.avro")
    parser.add_argument('-d', '--dest', default="gs://vkunitki-dev/test_1.avro")
    parser.add_argument('-sc', '--schema', default="dafault")
    # parser.add_argument('-sc', '--schema', default="schema.avsc")
    parser.add_argument('-i', '--div', default="")
    parser.add_argument('-t', '--time', default=[])
    args = parser.parse_args()

    print(args.time)
    if args.schema == "dafault":
        avro_schema = fastavro.parse_schema(fa_default_schema)
        # avro_schema = load_schema("schema.avsc")
        parquet_schema = avro.schema.parse(default_schema)
    else:
        avro_schema = load_schema(args.schema)
        parquet_schema = avro.schema.parse(open(args.schema, "rb").read())
    # print(schema)
    with beam.Pipeline() as p:
        if args.src.find(".json") > 0:
            records = p | 'Read parquet' >> beam.io.ReadFromText(args.src)
            records | "OUTss" >> beam.Map(lambda line: print("****> ", args.div, line))
            # records | 'Count all elements' >> beam.combiners.Count.Globally() | beam.Map(print)

        if args.src.find(".parquet") > 0:
            records = p | 'Read parquet' >> beam.io.ReadFromParquet(args.src)
            # records | 'Count all elements' >> beam.combiners.Count.Globally() | beam.Map(print)

        if args.src.find(".avro") > 0:
            records = p | 'Read avro' >> beam.io.ReadFromAvro(args.src)
            # records | 'Count all elements' >> beam.combiners.Count.Globally() | beam.Map(print)

        if args.dest == "json":
            records | "OUT" >> beam.Map(lambda line: print(args.div, timestamp_as_string(line)))

        if args.dest in ["count", "null"]:
            records | 'Count ' >> beam.combiners.Count.Globally() | beam.Map(print)

        if args.dest.find(".avro") > 0:
            output = records | beam.Map(lambda line: line)
            # output | "OUT" >> beam.Map(lambda line: print("******>", line))
            _ = output | 'Write avro' >> beam.io.WriteToAvro(args.dest,
                                                             avro_schema,
                                                             num_shards=1,
                                                             shard_name_template='')

        if args.dest.find(".parquet") > 0:
            parquet_schema = avro.schema.parse(open(args.schema, "rb").read())
            output = records | beam.Map(lambda line: line)
            output | "OUT" >> beam.Map(lambda line: print("parquet>", line))
            _ = output | 'Write' >> beam.io.WriteToParquet(args.dest, avro_schema,  # parquet_schema,
                                                           shard_name_template='', num_shards=1)
            # output | "OUT" >> beam.Map(lambda line: print(args.div, line))

        # records | 'Count ' >> beam.combiners.Count.Globally() | beam.Map(print)
    result = p.run()
    result.wait_until_finish()