From f205a7585d472c1918ed21a752e03a4c664364ac Mon Sep 17 00:00:00 2001 From: Gianluca Ficarelli <26835404+GianlucaFicarelli@users.noreply.github.com> Date: Fri, 23 Jun 2023 13:34:09 +0200 Subject: [PATCH] Prepare for release 1.0.7 (#225) - Fix changelog - Fix docs formatting - More tests for _logical_and and _logical_or --- CHANGELOG.rst | 5 +++- bluepysnap/_plotting.py | 8 +++-- bluepysnap/edges/edge_population.py | 40 +++++++++++++------------ bluepysnap/edges/edges.py | 45 +++++++++++++++-------------- bluepysnap/frame_report.py | 7 +++-- bluepysnap/nodes/node_population.py | 5 ++-- bluepysnap/nodes/nodes.py | 21 +++++++------- bluepysnap/spike_report.py | 2 +- tests/test_query.py | 2 ++ 9 files changed, 74 insertions(+), 61 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 717108cb..34a783c3 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -8,11 +8,14 @@ New Features ~~~~~~~~~~~~ - Added ``CircuitIds.intersection`` to take the intersection of two ``CircuitIds``. +Improvements +~~~~~~~~~~~~ +- Improve performance when querying a population with get() and ids(). + Bug Fixes ~~~~~~~~~ - Fix CircuitIds.sample() to always return different samples. - Ensure that the report DataFrames have the same schema even when empty. -- Improve performance when querying a population with get() and ids(). Version v1.0.6 -------------- diff --git a/bluepysnap/_plotting.py b/bluepysnap/_plotting.py index d2e51241..59d9f160 100644 --- a/bluepysnap/_plotting.py +++ b/bluepysnap/_plotting.py @@ -248,12 +248,13 @@ def spikes_firing_animation( ax(matplotlib.Axis): matplotlib Axis to draw on (if not specified, pyplot.gca() and plt.figure() are used). - Returns : + Returns: (matplotlib.animation.FuncAnimation, matplotlib.Axis): the matplotlib animation object and - the corresponding axis. + the corresponding axis. - Notes: + Examples: From scripts: + >>> import matplotlib.pyplot as plt >>> from bluepysnap import Simulation >>> report = Simulation("config.json").spikes["my_population"] @@ -262,6 +263,7 @@ def spikes_firing_animation( >>> # to save the animation : do not plt.show() and just anim.save('my_movie.mp4') From notebooks: + >>> from IPython.display import HTML >>> from bluepysnap import Simulation >>> report = Simulation("config.json").spikes["my_population"] diff --git a/bluepysnap/edges/edge_population.py b/bluepysnap/edges/edge_population.py index 3616d9b3..c785515f 100644 --- a/bluepysnap/edges/edge_population.py +++ b/bluepysnap/edges/edge_population.py @@ -121,7 +121,8 @@ def _topology_property_names(self): def config(self): """Access the configuration for the population. - This configuration is extended with + This configuration is extended with: + * 'components' of the circuit config * 'edges_file': the path the h5 file containing the population. """ @@ -154,7 +155,7 @@ def container_property_names(self, container): Returns: list: A list of strings corresponding to the properties that you can use from the - container class + container class Examples: >>> from bluepysnap.sonata_constants import Edge @@ -244,6 +245,7 @@ def ids(self, group=None, limit=None, sample=None, raise_missing_property=True): Args: group (None/int/CircuitEdgeId/CircuitEdgeIds/sequence): Which IDs will be returned depends on the type of the ``group`` argument: + - ``None``: return all IDs. - ``int``, ``CircuitEdgeId``: return a single edge ID. - ``CircuitEdgeIds`` return IDs of edges the edge population in an array. @@ -299,8 +301,8 @@ def get(self, edge_ids, properties): Returns: pandas.Series/pandas.DataFrame: - A pandas Series indexed by edge IDs if ``properties`` is scalar. - A pandas DataFrame indexed by edge IDs if ``properties`` is list. + - A pandas Series indexed by edge IDs if ``properties`` is scalar. + - A pandas DataFrame indexed by edge IDs if ``properties`` is list. Notes: The EdgePopulation.property_names function will give you all the usable properties @@ -394,9 +396,9 @@ def pathway_edges(self, source=None, target=None, properties=None): properties: None / edge property name / list of edge property names Returns: - List of edge IDs, if ``properties`` is None; - Pandas Series indexed by edge IDs if ``properties`` is string; - Pandas DataFrame indexed by edge IDs if ``properties`` is list. + - List of edge IDs, if ``properties`` is None; + - Pandas Series indexed by edge IDs if ``properties`` is string; + - Pandas DataFrame indexed by edge IDs if ``properties`` is list. """ if source is None and target is None: raise BluepySnapError("Either `source` or `target` should be specified") @@ -424,9 +426,9 @@ def afferent_edges(self, node_id, properties=None): Returns: pandas.Series/pandas.DataFrame/list: - A pandas Series indexed by edge ID if ``properties`` is a string. - A pandas DataFrame indexed by edge ID if ``properties`` is a list. - A list of edge IDs, if ``properties`` is None. + - A pandas Series indexed by edge ID if ``properties`` is a string. + - A pandas DataFrame indexed by edge ID if ``properties`` is a list. + - A list of edge IDs, if ``properties`` is None. """ return self.pathway_edges(source=None, target=node_id, properties=properties) @@ -438,9 +440,9 @@ def efferent_edges(self, node_id, properties=None): properties: None / edge property name / list of edge property names Returns: - List of edge IDs, if ``properties`` is None; - Pandas Series indexed by edge IDs if ``properties`` is string; - Pandas DataFrame indexed by edge IDs if ``properties`` is list. + - List of edge IDs, if ``properties`` is None; + - Pandas Series indexed by edge IDs if ``properties`` is string; + - Pandas DataFrame indexed by edge IDs if ``properties`` is list. """ return self.pathway_edges(source=node_id, target=None, properties=properties) @@ -453,9 +455,9 @@ def pair_edges(self, source_node_id, target_node_id, properties=None): properties: None / edge property name / list of edge property names Returns: - List of edge IDs, if ``properties`` is None; - Pandas Series indexed by edge IDs if ``properties`` is string; - Pandas DataFrame indexed by edge IDs if ``properties`` is list. + - List of edge IDs, if ``properties`` is None; + - Pandas Series indexed by edge IDs if ``properties`` is string; + - Pandas DataFrame indexed by edge IDs if ``properties`` is list. """ return self.pathway_edges( source=source_node_id, target=target_node_id, properties=properties @@ -554,9 +556,9 @@ def iter_connections( ``return_edge_count`` and ``return_edge_ids`` are mutually exclusive. Yields: - (source_node_id, target_node_id, edge_ids) if return_edge_ids == True; - (source_node_id, target_node_id, edge_count) if return_edge_count == True; - (source_node_id, target_node_id) otherwise. + - (source_node_id, target_node_id, edge_ids) if ``return_edge_ids`` is True; + - (source_node_id, target_node_id, edge_count) if ``return_edge_count`` is True; + - (source_node_id, target_node_id) otherwise. """ if return_edge_ids and return_edge_count: raise BluepySnapError( diff --git a/bluepysnap/edges/edges.py b/bluepysnap/edges/edges.py index d0a9682c..b3325ee4 100644 --- a/bluepysnap/edges/edges.py +++ b/bluepysnap/edges/edges.py @@ -51,14 +51,15 @@ def ids(self, group=None, sample=None, limit=None): Args: group (None/int/CircuitEdgeId/CircuitEdgeIds/sequence): Which IDs will be - returned depends on the type of the ``group`` argument: + returned depends on the type of the ``group`` argument: + - ``None``: return all CircuitEdgeIds. - ``CircuitEdgeId``: return the ID in a CircuitEdgeIds object. - ``CircuitEdgeIds``: return the IDs in a CircuitNodeIds object. - ``int``: returns a CircuitEdgeIds object containing the corresponding edge ID - for all populations. + for all populations. - ``sequence``: returns a CircuitEdgeIds object containing the corresponding edge - IDs for all populations. + IDs for all populations. sample (int): If specified, randomly choose ``sample`` number of IDs from the match result. If the size of the sample is greater than the size of all the EdgePopulations then all ids are taken and shuffled. @@ -68,8 +69,8 @@ def ids(self, group=None, sample=None, limit=None): Returns: CircuitEdgeIds: returns a CircuitEdgeIds containing all the edge IDs and the - corresponding populations. For performance reasons we do not test if the edge ids - are present or not in the circuit. + corresponding populations. For performance reasons we do not test if the edge ids + are present or not in the circuit. Notes: This envision also the maybe future selection of edges on queries. @@ -91,8 +92,8 @@ def get(self, edge_ids=None, properties=None): # pylint: disable=arguments-rena Returns: pandas.Series/pandas.DataFrame: - A pandas Series indexed by edge IDs if ``properties`` is scalar. - A pandas DataFrame indexed by edge IDs if ``properties`` is list. + - A pandas Series indexed by edge IDs if ``properties`` is scalar. + - A pandas DataFrame indexed by edge IDs if ``properties`` is list. Notes: The Edges.property_names function will give you all the usable properties @@ -171,9 +172,9 @@ def pathway_edges(self, source=None, target=None, properties=None): properties: None / edge property name / list of edge property names Returns: - CircuitEdgeIDs, if ``properties`` is None; - Pandas Series indexed by CircuitEdgeIDs if ``properties`` is string; - Pandas DataFrame indexed by CircuitEdgeIDs if ``properties`` is list. + - CircuitEdgeIDs, if ``properties`` is None; + - Pandas Series indexed by CircuitEdgeIDs if ``properties`` is string; + - Pandas DataFrame indexed by CircuitEdgeIDs if ``properties`` is list. """ if source is None and target is None: raise BluepySnapError("Either `source` or `target` should be specified") @@ -198,9 +199,9 @@ def afferent_edges(self, node_id, properties=None): Returns: pandas.Series/pandas.DataFrame/list: - A pandas Series indexed by edge ID if ``properties`` is a string. - A pandas DataFrame indexed by edge ID if ``properties`` is a list. - A list of edge IDs, if ``properties`` is None. + - A pandas Series indexed by edge ID if ``properties`` is a string. + - A pandas DataFrame indexed by edge ID if ``properties`` is a list. + - A list of edge IDs, if ``properties`` is None. """ return self.pathway_edges(source=None, target=node_id, properties=properties) @@ -212,9 +213,9 @@ def efferent_edges(self, node_id, properties=None): properties: None / edge property name / list of edge property names Returns: - List of edge IDs, if ``properties`` is None; - Pandas Series indexed by edge IDs if ``properties`` is string; - Pandas DataFrame indexed by edge IDs if ``properties`` is list. + - List of edge IDs, if ``properties`` is None; + - Pandas Series indexed by edge IDs if ``properties`` is string; + - Pandas DataFrame indexed by edge IDs if ``properties`` is list. """ return self.pathway_edges(source=node_id, target=None, properties=properties) @@ -227,9 +228,9 @@ def pair_edges(self, source_node_id, target_node_id, properties=None): properties: None / edge property name / list of edge property names Returns: - List of edge IDs, if ``properties`` is None; - Pandas Series indexed by edge IDs if ``properties`` is string; - Pandas DataFrame indexed by edge IDs if ``properties`` is list. + - List of edge IDs, if ``properties`` is None; + - Pandas Series indexed by edge IDs if ``properties`` is string; + - Pandas DataFrame indexed by edge IDs if ``properties`` is list. """ return self.pathway_edges( source=source_node_id, target=target_node_id, properties=properties @@ -282,9 +283,9 @@ def iter_connections( ``return_edge_count`` and ``return_edge_ids`` are mutually exclusive. Yields: - (source_node_id, target_node_id, edge_ids) if return_edge_ids == True; - (source_node_id, target_node_id, edge_count) if return_edge_count == True; - (source_node_id, target_node_id) otherwise. + - (source_node_id, target_node_id, edge_ids) if ``return_edge_ids`` is True; + - (source_node_id, target_node_id, edge_count) if ``return_edge_count`` is True; + - (source_node_id, target_node_id) otherwise. """ if return_edge_ids and return_edge_count: raise BluepySnapError( diff --git a/bluepysnap/frame_report.py b/bluepysnap/frame_report.py index 45cff8b0..92b20f9b 100644 --- a/bluepysnap/frame_report.py +++ b/bluepysnap/frame_report.py @@ -156,9 +156,10 @@ def report(self): Returns: pandas.DataFrame: A DataFrame containing the data from the report. Row's indices are the - different timestamps and the column's MultiIndex are : - - (population_name, node_id, compartment id) for the CompartmentReport - - (population_name, node_id) for the SomaReport + different timestamps and the column's MultiIndex are: + + - (population_name, node_id, compartment id) for the CompartmentReport + - (population_name, node_id) for the SomaReport """ dataframes = {} for population in self.frame_report.population_names: diff --git a/bluepysnap/nodes/node_population.py b/bluepysnap/nodes/node_population.py index 84f51700..298a790c 100644 --- a/bluepysnap/nodes/node_population.py +++ b/bluepysnap/nodes/node_population.py @@ -250,7 +250,8 @@ def target_in_edges(self): def config(self): """Access the configuration for the population. - This configuration is extended with + This configuration is extended with: + * 'components' of the circuit config * 'nodes_file': the path the h5 file containing the population. """ @@ -273,7 +274,7 @@ def container_property_names(self, container): Returns: list: A list of strings corresponding to the properties that you can use from the - container class + container class Examples: >>> from bluepysnap.sonata_constants import Node diff --git a/bluepysnap/nodes/nodes.py b/bluepysnap/nodes/nodes.py index 2ac61d63..146afdb4 100644 --- a/bluepysnap/nodes/nodes.py +++ b/bluepysnap/nodes/nodes.py @@ -59,20 +59,21 @@ def ids(self, group=None, sample=None, limit=None): Args: group (CircuitNodeId/CircuitNodeIds/int/sequence/str/mapping/None): Which IDs will be - returned depends on the type of the ``group`` argument: + returned depends on the type of the ``group`` argument: + - ``CircuitNodeId``: return the ID in a CircuitNodeIds object if it belongs to - the circuit. + the circuit. - ``CircuitNodeIds``: return the IDs in a CircuitNodeIds object if they belong to - the circuit. + the circuit. - ``int``: if the node ID is present in all populations, returns a CircuitNodeIds - object containing the corresponding node ID for all populations. + object containing the corresponding node ID for all populations. - ``sequence``: if all the values contained in the sequence are present in all - populations, returns a CircuitNodeIds object containing the corresponding node - IDs for all populations. + populations, returns a CircuitNodeIds object containing the corresponding node + IDs for all populations. - ``str``: use a node set name as input. Returns a CircuitNodeIds object containing - nodes selected by the node set. + nodes selected by the node set. - ``mapping``: Returns a CircuitNodeIds object containing nodes matching a - properties filter. + properties filter. - ``None``: return all node IDs of the circuit in a CircuitNodeIds object. sample (int): If specified, randomly choose ``sample`` number of IDs from the match result. If the size of the sample is greater than @@ -83,8 +84,8 @@ def ids(self, group=None, sample=None, limit=None): Returns: CircuitNodeIds: returns a CircuitNodeIds containing all the node IDs and the - corresponding populations. All the explicitly requested IDs must be present inside - the circuit. + corresponding populations. All the explicitly requested IDs must be present inside + the circuit. Raises: BluepySnapError: when a population from a CircuitNodeIds is not present in the circuit. diff --git a/bluepysnap/spike_report.py b/bluepysnap/spike_report.py index 4d7f9074..f5ddf537 100644 --- a/bluepysnap/spike_report.py +++ b/bluepysnap/spike_report.py @@ -156,7 +156,7 @@ def report(self): Returns: pandas.DataFrame: A DataFrame containing the data from the report. Row's indices are the - different timestamps and the columns are ids and population names. + different timestamps and the columns are ids and population names. """ res = pd.DataFrame() for population in self.spike_report.population_names: diff --git a/tests/test_query.py b/tests/test_query.py index 4416ea3f..0f2f1dde 100644 --- a/tests/test_query.py +++ b/tests/test_query.py @@ -74,6 +74,7 @@ def test_resolve_ids(): ([np.array([False])], np.array([False])), ([np.array([True, True]), np.array([True, False])], np.array([True, False])), ([np.array([100, 100]), np.array([True, False])], np.array([True, False])), + ([pd.Series([100, 100]), np.array([True, False])], np.array([True, False])), ( [np.array([True, False, True, False]), np.array([True, True, False, False])], np.array([True, False, False, False]), @@ -112,6 +113,7 @@ def test__logical_and(masks, expected): ([np.array([False])], np.array([False])), ([np.array([True, True]), np.array([True, False])], np.array([True, True])), ([np.array([100, 100]), np.array([True, False])], np.array([True, True])), + ([pd.Series([100, 100]), np.array([True, False])], np.array([True, True])), ( [np.array([True, False, True, False]), np.array([True, True, False, False])], np.array([True, True, True, False]),