{ "info": { "author": "Erik van Haeringen", "author_email": "e.s.van.haeringen@student.rug.nl", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.7", "Topic :: Scientific/Engineering :: Bio-Informatics" ], "description": "# Dominance Hierarchy Development Analysis Tools (DHDAT)\n\n\n\n\n\n
AuthorErik van Haeringen
Emaile.s.van.haeringen@vu.nl
DateJuly 4th 2019
DescriptionDHDAT is a python package with basic tools to produce interaction matrices and calculate several dominance hierarchy related metrics
\n\n## Licence\nCopyright (C) 2019, van Haeringen. This package is published under an MIT licence and you are welcome to use or improve upon it. For any publication, whether research or software that uses or includes (partial) copies of (modules of) this package, please cite this work.\n\n## Prerequisites\n* [Python 3](https://www.python.org/)\n* [Pandas](https://pandas.pydata.org/)\n\n## Install\nTo install the package for your default Python installation use your terminal to execute the command below.\n\n```\npip install dhdat\n```\n\nFor other Python installations replace `pip` with the path to its respective pip executable\n\n## Contents\n1. [Matrix](#1-matrix)\n2. [CombinationMaker](#2-combinationmaker)\n3. [Triads](#3-triads)\n4. [Ttri](#4-ttri)\n5. [NetworkState](#5-networkstate)\n6. [ADI](#6-adi)\n7. [Xi](#7-xi)\n8. [Bursts](#8-bursts)\n9. [PairFlips](#9-pairflips)\n10. [TauKr](#10-taukr)\n\n## Modules\n### 1. Matrix\n#### Description\nBuilds an interaction matrix based on a list of actors and fills this with rows from a pandas dataset.\nThese Matrix objects are used by the other modules, for example to calculate the dominance index Xi.\nInteraction winners are the rows and the losers are the columns.\n\n#### How to use\nCreate a new matrix object by initiating matrix with a list of the actors identifiers.\nThis matrix object contains three Pandas DataFrames, one interaction matrix of initiations of aggression (**d_mI**), one cumulative matrix of the outcomes of fights (**d_mC**), a another that is a non-cumulative matrix of the outcome of fights (**d_mNC**).\n\n```python\nfrom dhdat import Matrix\n\nactorIDs = [1,2,3,4]\nmatrix = Matrix(actorIDs) #new interaction matrix of size len(actorIDs)\n\nprint(matrix.d_mC) #shows cumulative matrix\nprint(matrix.d_mNC) #shows non-cumulative matrix\n```\n\nThe matrix can be updated with a row from a Pandas DataFrame. This DataFrame should be structured with one row per interaction, containing at least the columns **'actor.id'**, **'actor.behavior'**, **'receiver.id'** and **'receiver.behavior'**.\nThe **'actor.id'** and **'receiver.id'** columns should contain a actorID provided to the matrix object on initialization to indicate who who initiated the dominance interaction (actor.id) and who was the receiver (receiver.id).\nThe **'actor.behavior'** and **'receiver.behavior'** columns should contian either the string \"Fight\" or \"Flee\", indicating the outcome of the fight (Fight = win and Flee = loss).\nThus actor can be the one who initialized the interaction but then lose the interaction and flee. The Pandas DataFrame should look similar to the example below.\n\n```python\nimport pandas as pd\n #load data from csv file\ndf = pd.read_csv(\"exampleDataSet.csv\", delimiter=\"\\t\")\n\nprint(df)\n```\n\nExample data set:\n```\n run time actor.id receiver.id actor.behavior receiver.behavior\n0 0 23 4 2 Fight Flee\n1 0 112 2 3 Flee Fight\n2 0 278 1 3 Fight Flee\n3 0 315 4 2 Fight Flee\n4 0 801 4 2 Flee Fight\n5 0 932 1 3 Fight Flee\n6 0 966 3 1 Flee Fight\n```\n\nInteractions can be added to the matrix by calling either `update()` which updates all matrices, or by calling the update functions for the individual matrices (`updateInitiated()`, `updateCumulative()`, `updateNonCumulative()`). \nThe update functions require a row (interaction) of the Pandas DataFrame as described above. The example below shows a simple for-based loop adding all interactions in the DataFrame *df* using the update functions of the individual matrices. \nNote that the update statement from the example below can also be written out as 3 seperate matrix specific update statements with the same result (for example `matrix.updateCumulative(df.loc[interaction,:])`).\n\n```python\nfrom dhdat import Matrix\nimport pandas as pd\n\ndf = pd.read_csv(\"exampleDataSet.csv\", delimiter=\"\\t\", index_col=0)\n\nactorIDs = [1, 2, 3, 4] #list of actor identifiers\nmatrix = Matrix(actorIDs) #setup matrix object with actor identifiers\n\nfor interaction in df.index:\n #add new interaction to the matrices\n matrix.update(df.loc[interaction,:])\n\nprint(\"Initiations matrix\\n\", matrix.d_mI)\nprint(\"\\nCumulative interaction matrix\\n\", matrix.d_mC)\nprint(\"\\nNon-cumulative interaction matrix\\n\", matrix.d_mNC)\n```\n\nOutput:\n```\nInitiations matrix\n 1 2 3 4\n1 0 0 2 0\n2 0 0 1 0\n3 1 0 0 0\n4 0 3 1 0\n\nCumulative interaction matrix\n 1 2 3 4\n1 0 0 3 0\n2 0 0 0 1\n3 0 1 0 1\n4 0 2 0 0\n\nNon-cumulative interaction matrix\n 1 2 3 4\n1 0 0 1 0\n2 0 0 0 1\n3 0 1 0 1\n4 0 0 0 0\n```\n\nThe dataframes containing the matrices can directly be accessed as shown in the example above.\nThere are also the functions `exportInitiated()`, `exportCumulative()` and `exportNonCumulative()` that store the respective matrix as a tab-separated csv file.\nThe functions arguments are *filename* and *run_number*.\nThis results in the following filename structure: `[filename][run_number]_matrix[type].csv` where matrix type is I for initiated, C for cumulative and NC for non-cumulative.\n\n```python\n #produces 'test_5_matrixNC.csv'\nmatrix.exportNonCumulative(\"test_\", 5)\n\n #produces 'test2_14_matrixC.csv' in subdirectory 'figures'\nmatrix.exportCumulative(\"figures/test2_\", 14)\n```\n\n-----------------------\n### 2. CombinationMaker\n#### Description\nClass that uses a recursive function to generate all possible triangles based on a set of actors, and stores these combinations in a pandas dataframe.\nThe recursive algorithm was inspired on a example (in C) by [Bateesh](https://www.geeksforgeeks.org/print-all-possible-combinations-of-r-elements-in-a-given-array-of-size-n/).\n\n#### How to use\n\nA combination object is initialized with a list of the elements (actors) that will be combined, and the number of elements per combination. Below is an example for all combinations of three individuals that can be made with four individuals.\n\n```python\nfrom dhdat import CombinationMaker\n\nactorIDs = [1, 2, 3, 4]\n #calculate all triad combinations of 4 actors\ncombinations = CombinationMaker(actorIDs, 3)\n```\n\nThe combinations are stored in a Pandas DataFrame **d_result**.\nThis member can be accessed directly, or alternatively the function `getResults()` returns this member.\n\n```python\ncombinations.getResults()\n```\nOutput:\n```\n 0 1 2\n0 1 2 3\n1 1 2 4\n2 1 3 4\n3 2 3 4\n```\n\n-----------------------\n### 3. Triads\n#### Description\nCounts triad motifs in a dominance network read from an interaction matrix.\nSee Wasserman & Faust (1994), or Shizuka & McDonald (2012) for details on triad coding.\nThis class can count either triad motifs with only directed relationships, in which case mutual (equal) relationships are ignored.\nOr it can also count triad motifs that contain one or more mutual relationships.\n\n#### How to use\nTriads is initialized with the option for mutual triad motif count (False or True) and a [CombinationMaker](#2-combinationmaker) object containing all possible combinations of actors for triads.\n\n```python\nfrom dhdat import Matrix\nfrom dhdat import CombinationMaker\nfrom dhdat import Triads\nimport pandas as pd\n\ndf = pd.read_csv(\"exampleDataSet.csv\", delimiter=\"\\t\")\n\nactorIDs = [1, 2, 3, 4]\nmatrix = Matrix(actorIDs)\n #calculate all triad combinations of 4 actors\ncombinations = CombinationMaker(actorIDs, 3)\n #setup triads object without mutual relationships\ntriads = Triads(False, combinations.getResults())\n```\n\nA Triads object counts triads with the function `count()`, which requires either a cumulative or non-cumulative [matrix](#1-matrix) and the index of the current interaction.\nThe resulting motif count is stored in a Pandas DataFrame **d_triadCount** at the index supplied to the `count()` function.\n\n```python\nfor interaction in df.index:\n #adds interaction to non-cumulative matrix\n matrix.updateNonCumulative(df.loc[interaction,:]) \n\n triads.count(matrix.d_mNC, interaction)\n\n #shows triad count of interaction \nprint(triads.d_triadCount)\n```\n\nOutput:\n\n```\n TRI_003 TRI_012 TRI_021D TRI_021U TRI_021C TRI_030T TRI_030C\n0 2.0 2.0 0.0 0.0 0.0 0.0 0.0\n1 1.0 2.0 0.0 1.0 0.0 0.0 0.0\n2 0.0 2.0 0.0 1.0 1.0 0.0 0.0\n3 0.0 2.0 0.0 1.0 1.0 0.0 0.0\n4 0.0 2.0 0.0 0.0 2.0 0.0 0.0\n5 0.0 2.0 0.0 0.0 2.0 0.0 0.0\n6 0.0 2.0 0.0 0.0 2.0 0.0 0.0\n7 0.0 1.0 0.0 0.0 2.0 1.0 0.0\n```\n\n-----------------------\n### 4. Ttri\n#### Description\nCalculates Ttri as described in Shizuka and McDonald (2012), based on the triad motif count of a dominance network.\nIf option 'mutual' is chosen, mutual triads are included in the calculation of Ttri.\nOtherwise Ttri is calculated only over triads that have directed edges.\n\n#### How to use\nTo calculate Ttri first a Ttri object must be initialized with the option for triad count of mutual relations (True or False).\nThis option should correspond to the option chosen to [count](#3-triads) the triad motifs. Because triad count can be either over a cumulative matrix or a non-cumulative matrix, the Ttri value either measures linearity over the last interaction in each pair (non-cumulative), or includes all previous interactions in each pair (cumulative) to determine the direction of a pair relation. In the paper cited above by Shizuka and McDonald, Ttri is calculated over the final cumulative interaction matrix including all recorded interactions.\n\n```python\nfrom dhdat import Matrix\nfrom dhdat import CombinationMaker\nfrom dhdat import Triads\nfrom dhdat import Ttri\nimport pandas as pd\n\ndf = pd.read_csv(\"exampleDataSet.csv\", delimiter=\"\\t\")\n\nactorIDs = [1, 2, 3, 4]\nmatrix = Matrix(actorIDs)\n #calculate all triad combinations of 4 actors\ncombinations = CombinationMaker(actorIDs, 3)\n #setup triads object without mutual relationships\ntriads = Triads(False, combinations.getResults())\n #setup ttri object without mutual relationships\nttri = Ttri(False)\n```\n\nThen the Ttri object can be fed with the triad count from a [Triads](#3-triads) object, and the index of the current interaction.\nTtri is stored in a Pandas DataFrame d_ttri with one column *'T_tri'*, which can be accessed directly.\nTtri can by definition only be determined when there is at least one complete triad (containing 3 links).\nThus the [example data set](#1-matrix) used in this manual results in no value for *'T_tri'* as there are no complete triads, as was shown in the demonstration of the previous module [Triads](#3-triads).\n\n```python\nfor interaction in df.index:\n #adds interaction to non-cumulative matrix\n matrix.updateNonCumulative(df.loc[interaction,:]) \n triads.count(matrix.d_mNC, interaction)\n\n ttri.calculate(triads.d_triadCount, interaction) \n\n #shows Ttri of interactions\nprint(ttri.d_Ttri)\n```\n\nOutput:\n```\n T_tri\n0 None\n1 None\n2 None\n3 None\n4 None\n5 None\n6 None\n7 1\n```\nTtri in a directed (non-mutual) network is a scaled ratio of transitive triad motifs divided by the transitive + cyclic triad motifs. In a mutual network it uses the ratio of transitive weights divided by the total number of complete triad motifs, as some mutual triad motifs are defined as partially transitive. This measure ignores motifs with missing links (also called relations or edges). In example given here of Ttri calculated for a directed network, there are no complete motifs (either transitive, cyclic), which results in a empty field. See Shizuka and McDonald (2012) for further details.\n\n-----------------------\n### 5. NetworkState\n#### Description\nDetermines the state of a network of 4 individuals based on triad motif count.\nSee Lindquist and Chase (2009) for an explanation of triad motifs network\nstates and nomenclature. Currently only networks of 4 individuals are supported.\nIncreasing the group size results in an exponential growth of possible network states, and thus quickly becomes unfeasible.\n\n#### How to use\nA NetworkState object is created with a list of the actors.\nTo determine the network state of an interaction matrix, member function `determine()` requires the triad state count **d_triadState** of a [Triads](#3-triads) object, and the number of the current interaction as an index to store the result.\nBecause for some states triads motif count alone is not enough to determine the network state, additionally the non-cumulative matrix **d_mNC** of a [Matrix](#1-matrix) object is a required argument.\nStates are stored in data member **d_state** as a Pandas DataFrame and can be accessed directly.\n\n```python\nfrom dhdat import Matrix\nfrom dhdat import CombinationMaker\nfrom dhdat import Triads\nfrom dhdat import NetworkState\nimport pandas as pd\n\ndf = pd.read_csv(\"exampleDataSet.csv\", delimiter=\"\\t\")\n\nactorIDs = [1, 2, 3, 4]\nmatrix = Matrix(actorIDs)\n #calculate all triad combinations of 4 actors\ncombinations = CombinationMaker(actorIDs, 3)\n #setup Triads object without mutual relationships\ntriads = Triads(False, combinations.getResults())\nstate = NetworkState(actorIDs) #setup NetworkState object\n\nfor interaction in df.index:\n #adds interaction to non-cumulative matrix\n matrix.updateNonCumulative(df.loc[interaction,:]) \n triads.count(matrix.d_mNC, interaction)\n\n state.determine(triads.d_triadState, interaction, matrix.d_mNC)\n\n #shows network state of interaction \nprint(state.d_state)\n```\n\nOutput:\n```\n State\n0 1\n1 4\n2 13\n3 13\n4 15\n5 15\n6 15\n7 20\n```\n\n\n-----------------------\n### 6. ADI\n#### Description\nCalculates the average dominance index (ADI) from a cumulative interaction matrix as described in Hemelrijk et al. (2005).\n\n#### How to use\nA ADI object is created with a list of the actors.\nThen to calculate the ADI for an interaction call member function `calculate()` with a cumulative interaction matrix **d_mC** from a [Matrix](#1-matrix) object, and the number of the current interaction that is used as an index to store the calculated ADI value.\nADI values are stored in Pandas DataFrame **d_ADI** with a column *ADI_[actorID]* for each actor, and can be accessed directly.\n\n```python\nfrom dhdat import Matrix\nfrom dhdat import ADI\nimport pandas as pd\n\ndf = pd.read_csv(\"exampleDataSet.csv\", delimiter=\"\\t\")\n\nactorIDs = [1, 2, 3, 4] #list of actor identifiers\nmatrix = Matrix(actorIDs) \nadi = ADI(actorIDs)\n\nfor interaction in df.index:\n #adds interaction to cumulative matrix\n matrix.updateCumulative(df.loc[interaction,:]) \n\n adi.calculate(matrix.d_mC, interaction)\n\nprint(adi.d_ADI) #shows ADI values for all interactions\n```\n\nOutput:\n```\n ADI_1 ADI_2 ADI_3 ADI_4\n0 NaN 0.000000 NaN 1.000000\n1 NaN 0.000000 1.000000 1.000000\n2 1.0 0.000000 0.500000 1.000000\n3 1.0 0.000000 0.500000 1.000000\n4 1.0 0.166667 0.500000 0.666667\n5 1.0 0.166667 0.500000 0.666667\n6 1.0 0.166667 0.500000 0.666667\n7 1.0 0.166667 0.666667 0.333333\n```\n\n-----------------------\n### 7. Xi\n#### Description\nCalculates the dominance index Xi, which is the proportion of aggressive\ninteraction won, for a cumulative interaction matrix as described in Lindquist\nand Chase (2009)\n\n#### How to use\nA Xi object is created with a list of the actors.\nThen to calculate the Xi for an interaction call member function `calculate()` with a cumulative interaction matrix **d_mC** from a [Matrix](#1-matrix) object,\nand the number of the current interaction that is used as an index to store the calculated Xi value.\nXi values are stored in Pandas DataFrame **d_Xi** with a column *Xi_[actorID]* for each actor, and can be accessed directly.\n\n```python\nfrom dhdat import Matrix\nfrom dhdat import Xi\nimport pandas as pd\n\ndf = pd.read_csv(\"exampleDataSet.csv\", delimiter=\"\\t\")\n\nactorIDs = [1, 2, 3, 4] #list of actor identifiers\nmatrix = Matrix(actorIDs) \nxi = Xi(actorIDs)\n\nfor interaction in df.index:\n #adds interaction to cumulative matrix\n matrix.updateCumulative(df.loc[interaction,:]) \n\n xi.calculate(matrix.d_mC, interaction)\n\nprint(xi.d_Xi) #shows Xi values for all interactions\n```\n\nOutput:\n```\n Xi_1 Xi_2 Xi_3 Xi_4\n0 NaN 0 NaN 1\n1 NaN 0 1 1\n2 1 0 0.5 1\n3 1 0 0.5 1\n4 1 0.25 0.5 0.666667\n5 1 0.25 0.333333 0.666667\n6 1 0.25 0.25 0.666667\n```\n\n-----------------------\n### 8. Bursts\n#### Description\nDetects whether bursts occur, a pattern of repeated consecutive attacks in the same direction within a dyad, as described by Lindquist and Chase (2009).\nIt does this by comparing the direction of the current interaction with the previous interaction. Note that this definition does not include a time component.\n\n#### How to use\nA new Bursts object can by defined without any arguments.\nTo determine a interaction is part of a burst event, the member function `detect()` requires a row of a Pandas DataFrame containing the current interaction, and the row containing the previous interaction, as well as the number of the current interaction to use as a index to store the resulting burst value.\nThe result (True or False) is stored in data member **d_bursts** and can be accesed directly as shown below.\nThis example shows how with a simple for loop burst events can be detected for a set of interactions, by storing the previous interaction index.\nThe first interaction can by definition never be a burst, and thus is skipped.\n\n```python\nfrom dhdat import Bursts\nimport pandas as pd\n\ndf = pd.read_csv(\"exampleDataSet.csv\", delimiter=\"\\t\")\n\nbursts = Bursts() #define a new Bursts object\nprevInteraction = None #holds index of previous interaction\n\nfor interaction in df.index:\n if prevInteraction != None: #first interaction cannot be a burst\n bursts.detect(df.loc[interaction,:], df.loc[prevInteraction,:], interaction)\n\n prevInteraction = interaction\n\nprint(bursts.d_bursts) #shows burst values for all interactions\n```\n\nOutput:\n```\n burst\n1 False\n2 False\n3 False\n4 False\n5 False\n6 True\n7 False\n```\nThe field of the first interaction is empty as a burst is a series of interactions, and thus can only occur if there is a previous interaction.\n\n-----------------------\n### 9. PairFlips\n#### Description\nDetects pair-flip events, which is the reversal of the relationship of pair based on a non-cumulative interaction matrix.\nThis means that one counter attack is enough to reverse the relation and be marked as a pair-flip event. To detect these events\nthe direction of the relation of the pair involved in the current interaction, is compared to the non-cumulative interaction matrix of the previous interaction.\n\n#### How to use\nA new PairFlips object can by defined without any arguments.\nTo determine whether a interaction is a pair-flip event, the member function `detect()` requires the non-cumulative matrix **d_mC** from a [Matrix](#1-matrix) object of the _previous_ interaction, a row of a Pandas DataFrame containing the current interaction, and the number of the current interaction to use as a index to store the resulting pair-flip value.\nThe result (True or False) is stored in data member **d_pairFlips** and can be accesed directly as shown below.\nThis example shows how with a simple for loop pair-flip events can be detected for a set of interactions, by storing the previous non-cumulative matrix.\nThe first interaction can by definition never be a pair-flip, and thus is skipped.\n\n```python\nfrom dhdat import Matrix\nfrom dhdat import PairFlips\nimport pandas as pd\n\ndf = pd.read_csv(\"exampleDataSet.csv\", delimiter=\"\\t\")\n\nactorIDs = [1, 2, 3, 4] #list of actor identifiers\nmatrix = Matrix(actorIDs) \npairFlips = PairFlips()\n #will hold matrix previous interaction\nprevNCMatrix = pd.DataFrame(index=actorIDs, columns=actorIDs) \nprevNCMatrix = prevNCMatrix.fillna(0) \n\nfor interaction in df.index:\n #adds interaction to non-cumulative matrix\n matrix.updateNonCumulative(df.loc[interaction,:]) \n\n pairFlips.detect(prevNCMatrix, df.loc[interaction, :], interaction)\n\n #make sure to copy, not assign a reference\n prevNCMatrix = matrix.d_mNC.copy()\n\nprint(pairFlips.d_pairFlips) #shows burst values for all interactions\n```\n\nOutput:\n```\n pairFlip\n0 False\n1 False\n2 False\n3 False\n4 True\n5 False\n6 False\n7 False \n```\nThe field of the first interaction is empty as a pair-flip is a reversal of the direction of attack, and thus per definition requires a previous interaction.\n\n-----------------------\n### 10. TauKr\n#### Description\nCalculates TauKr as defined in Hemelrijk (1989), which measures unidirectionality between a set of matrices.\nThe example below demonstrates how reciprocity of aggression (initiation) can be calculated using this module.\n\n#### How to use\nA new TauKr object can be defined without any arguments. With the function `calculate()` TauKr can be calculated from two matrices directly, or by supplying one matrix to `calculate_T()` TauKr is calculated against the transposed version of the supplied matrix.\nThe matrix that is supplied must be a Pandas DataFrame as used by the [Matrix](#1-matrix) object. Both functions also require the interaction number to use as an index to store the outcome at.\nIn the example below reciprocity of aggression (initiations of fights) is determined by calculating the TauKr from the **d_mI** matrix from a [Matrix](#1-matrix) object.\n\n```python\nfrom dhdat import Matrix\nfrom dhdat import TauKr\nimport pandas as pd\n\ndf = pd.read_csv(\"exampleDataSet.csv\", delimiter=\"\\t\")\n\nactorIDs = [1, 2, 3, 4] #list of actor identifiers\nmatrix = Matrix(actorIDs) \ntaukr = TauKr()\n\nfor interaction in df.index:\n #adds current interaction to initiations of aggression matrix\n matrix.updateInitiated(df.loc[interaction,:])\n\n #calculate reciprocity of aggression\n taukr.calculate_T(interaction, matrix.d_mI)\n\nprint(taukr.d_TauKr) #shows TauKr values for all interactions\n```\n\nOutput:\n```\n TauKr\n1 -0.5\n2 -0.5\n3 -0.5\n4 -0.5\n5 -0.5\n6 0.465153\n7 0.5 \n```\nNote index 0 is empty as there are insufficient values to calculate TauKr\n\n\n", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/esvanhaeringen/DHDAT", "keywords": "", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "dhdat", "package_url": "https://pypi.org/project/dhdat/", "platform": "", "project_url": "https://pypi.org/project/dhdat/", "project_urls": { "Homepage": "https://github.com/esvanhaeringen/DHDAT" }, "release_url": "https://pypi.org/project/dhdat/0.6.2/", "requires_dist": [ "pandas" ], "requires_python": "", "summary": "DHDAT is a python package with basic tools to produce interaction matrices and calculate several dominance hierarchy related metrics", "version": "0.6.2" }, "last_serial": 5679384, "releases": { "0.5.0": [ { "comment_text": "", "digests": { "md5": "8184f7ec7e9739c596812843207dcf03", "sha256": "d08649fb9437c52fed6b47c86a295b404446f95d984aee7eb4946f28e7658e35" }, "downloads": -1, "filename": "dhdat-0.5.0-py3-none-any.whl", "has_sig": false, "md5_digest": "8184f7ec7e9739c596812843207dcf03", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 15863, "upload_time": "2019-08-13T13:17:57", "url": "https://files.pythonhosted.org/packages/73/18/f45745f462a2ae311e714d2b524e03f028dd983e2a3515a7257bfb326fd9/dhdat-0.5.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "dac3ebbc48006c6a29de4283aa39707b", "sha256": "ad28370bb17bf1d7f5c616a1e3e447c9e5f9e33e232cb5c6bb96ca70a0984607" }, "downloads": -1, "filename": "dhdat-0.5.0.tar.gz", "has_sig": false, "md5_digest": "dac3ebbc48006c6a29de4283aa39707b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 14814, "upload_time": "2019-08-13T13:18:00", "url": "https://files.pythonhosted.org/packages/8a/71/53be28bf56f6730402a4a99a65cf173b465ee1315770ec99b7fc7243aa73/dhdat-0.5.0.tar.gz" } ], "0.6.0": [ { "comment_text": "", "digests": { "md5": "b0fb97838d763c1123188c078275251b", "sha256": "586ced02f9e61445ab153ad86de1db925a1ccfa2a6880bba8834fc7e17b78457" }, "downloads": -1, "filename": "dhdat-0.6.0.tar.gz", "has_sig": false, "md5_digest": "b0fb97838d763c1123188c078275251b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 14826, "upload_time": "2019-08-13T13:18:01", "url": "https://files.pythonhosted.org/packages/81/c7/77858608942df0a21f9388507333926cfb21f8906b9721044bcb500486db/dhdat-0.6.0.tar.gz" } ], "0.6.1": [ { "comment_text": "", "digests": { "md5": "6d5674fab645f8f80bfeb18e06d40133", "sha256": "881382fb16afdb66a6fb7e4358d446fb1b8d813b544f5a924bf81625eacb9042" }, "downloads": -1, "filename": "dhdat-0.6.1.tar.gz", "has_sig": false, "md5_digest": "6d5674fab645f8f80bfeb18e06d40133", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 15052, "upload_time": "2019-08-13T14:04:57", "url": "https://files.pythonhosted.org/packages/55/3a/3bf2c815c58f901c53ad73f8d3c942938bff37f22939692f8d34bba73061/dhdat-0.6.1.tar.gz" } ], "0.6.2": [ { "comment_text": "", "digests": { "md5": "4d03db30b005328bc6eb59a048269fda", "sha256": "a652230dbdce3cd03da415b905d9d380240122a05fccf0fb76b0815665b2fc76" }, "downloads": -1, "filename": "dhdat-0.6.2-py3-none-any.whl", "has_sig": false, "md5_digest": "4d03db30b005328bc6eb59a048269fda", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 18206, "upload_time": "2019-08-14T21:33:04", "url": "https://files.pythonhosted.org/packages/ad/d7/9a237bb7b98fc74d6f1c02ddbd0edd360f0acc11e76971cd63fda29e7257/dhdat-0.6.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "f8abadf7f1ad79887b8b552025eb8790", "sha256": "7131e2dd807182bcb7dec234caba857df276f604abe161fede560b6478629c64" }, "downloads": -1, "filename": "dhdat-0.6.2.tar.gz", "has_sig": false, "md5_digest": "f8abadf7f1ad79887b8b552025eb8790", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 21008, "upload_time": "2019-08-14T21:33:06", "url": "https://files.pythonhosted.org/packages/68/bd/b5997dff56ae1f9ac2f89e06ccbd2c22eb96b42d9928c7501900a96ec168/dhdat-0.6.2.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "4d03db30b005328bc6eb59a048269fda", "sha256": "a652230dbdce3cd03da415b905d9d380240122a05fccf0fb76b0815665b2fc76" }, "downloads": -1, "filename": "dhdat-0.6.2-py3-none-any.whl", "has_sig": false, "md5_digest": "4d03db30b005328bc6eb59a048269fda", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 18206, "upload_time": "2019-08-14T21:33:04", "url": "https://files.pythonhosted.org/packages/ad/d7/9a237bb7b98fc74d6f1c02ddbd0edd360f0acc11e76971cd63fda29e7257/dhdat-0.6.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "f8abadf7f1ad79887b8b552025eb8790", "sha256": "7131e2dd807182bcb7dec234caba857df276f604abe161fede560b6478629c64" }, "downloads": -1, "filename": "dhdat-0.6.2.tar.gz", "has_sig": false, "md5_digest": "f8abadf7f1ad79887b8b552025eb8790", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 21008, "upload_time": "2019-08-14T21:33:06", "url": "https://files.pythonhosted.org/packages/68/bd/b5997dff56ae1f9ac2f89e06ccbd2c22eb96b42d9928c7501900a96ec168/dhdat-0.6.2.tar.gz" } ] }