From 8f8b53613193754075f21a398284ed48b00f37f5 Mon Sep 17 00:00:00 2001 From: Utkarsha Dunde Date: Sat, 14 Mar 2026 18:02:27 +0530 Subject: [PATCH 1/7] Fix: correctly pipe keyword arguments to plot_dendrogram --- brian2tools/plotting/base.py | 5 +---- brian2tools/plotting/morphology.py | 12 ++++++++---- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/brian2tools/plotting/base.py b/brian2tools/plotting/base.py index 28bb385d..83749c15 100644 --- a/brian2tools/plotting/base.py +++ b/brian2tools/plotting/base.py @@ -106,10 +106,7 @@ def brian_plot(brian_obj, kwds['rate_unit'] = _get_best_unit(smooth_rate) return plot_rate(brian_obj.t, smooth_rate, axes=axes, **kwds) elif isinstance(brian_obj, Morphology): - if kwds: - logger.warn('plot_dendrogram does not take any additional keyword ' - 'arguments, ignoring them.') - return plot_dendrogram(brian_obj, axes=axes) + return plot_dendrogram(brian_obj, axes=axes, **kwds) elif isinstance(brian_obj, Synapses): if len(brian_obj) == 0: raise TypeError('Synapses object does not have any synapses.') diff --git a/brian2tools/plotting/morphology.py b/brian2tools/plotting/morphology.py index 08cdbfdf..49b380fa 100644 --- a/brian2tools/plotting/morphology.py +++ b/brian2tools/plotting/morphology.py @@ -353,7 +353,7 @@ def plot_morphology(morphology, plot_3d=None, show_compartments=False, return axes -def plot_dendrogram(morphology, axes=None): +def plot_dendrogram(morphology, axes=None, **kwds): ''' Plot a "dendrogram" of a morphology, i.e. an abstract representation which visualizes the branching structure and the length of each section. @@ -366,6 +366,10 @@ def plot_dendrogram(morphology, axes=None): The `~matplotlib.axes.Axes` instance used for plotting. Defaults to ``None`` which means that a new `~matplotlib.axes.Axes` will be created for the plot. + kwds : dict, optional + Any additional keywords command will be handed over to matplotlib's + `~matplotlib.axes.Axes.plot` command. This can be used to set plot + properties such as the ``color``. Returns ------- @@ -427,7 +431,7 @@ def plot_dendrogram(morphology, axes=None): # Plot the dendogram with lengths of the vertical lines representing the # total distance to the root - plt.plot(x_values[0], length_metric[0], 'ko', clip_on=False) + plt.plot(x_values[0], length_metric[0], marker='o', clip_on=False, **kwds) for sec, (x, depth) in enumerate(zip(x_values, length_metric)): child_start_idx = (sec+1)*max_children num_children = flat_morpho.morph_children_num[sec+1] @@ -435,8 +439,8 @@ def plot_dendrogram(morphology, axes=None): child_indices = children[child_start_idx:child_start_idx+num_children] child_depth = length_metric[child_indices-1] child_x = x_values[child_indices-1] - axes.vlines(child_x, depth, child_depth, clip_on=False, lw=2) - axes.hlines(depth, min(child_x), max(child_x), lw=2) + axes.vlines(child_x, depth, child_depth, clip_on=False, lw=2, **kwds) + axes.hlines(depth, min(child_x), max(child_x), lw=2, **kwds) axes.set_xticks([]) axes.set_ylabel('distance from root (um)') axes.set_xlim(-1, terminal_counter) From 9344604fa65e80b399d11b7094f90e4b7cc4759b Mon Sep 17 00:00:00 2001 From: Utkarsha Dunde Date: Sat, 14 Mar 2026 18:26:48 +0530 Subject: [PATCH 2/7] Test: fix unimplemented device export test --- brian2tools/tests/test_baseexport.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/brian2tools/tests/test_baseexport.py b/brian2tools/tests/test_baseexport.py index ea5b1926..6c680b63 100644 --- a/brian2tools/tests/test_baseexport.py +++ b/brian2tools/tests/test_baseexport.py @@ -873,9 +873,18 @@ def test_ExportDevice_unsupported(): g :1 ''' G = NeuronGroup(1, eqn) - _ = PoissonInput(G, 'g', 1, 1 * Hz, 1) - # with pytest.raises(NotImplementedError): - run(10 * ms) + run(1*ms) + + from brian2.core.base import BrianObject + class UnsupportedObject(BrianObject): + def __init__(self): + super().__init__(name='unsupported*') + + obj = UnsupportedObject() + net = Network(obj) + with pytest.raises(NotImplementedError): + net.run(10 * ms) + device.reinit() if __name__ == '__main__': From f9ba7403ae9f4209369774b141fd2d4badc60b79 Mon Sep 17 00:00:00 2001 From: Utkarsha Dunde Date: Sat, 21 Mar 2026 19:51:29 +0530 Subject: [PATCH 3/7] Addressing review comments --- brian2tools/tests/test_baseexport.py | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/brian2tools/tests/test_baseexport.py b/brian2tools/tests/test_baseexport.py index dc587540..910d4d58 100644 --- a/brian2tools/tests/test_baseexport.py +++ b/brian2tools/tests/test_baseexport.py @@ -4,6 +4,7 @@ PopulationRateMonitor, EventMonitor, set_device, run, device, Network, Synapses, PoissonInput, TimedArray, Function) +from brian2.core.base import BrianObject from brian2.core.namespace import get_local_namespace from brian2.equations.equations import (DIFFERENTIAL_EQUATION, FLOAT, SUBEXPRESSION, @@ -898,14 +899,7 @@ def test_ExportDevice_unsupported(): """ start_scope() set_device('exporter') - eqn = ''' - v = 1 :1 - g :1 - ''' - G = NeuronGroup(1, eqn) - run(1*ms) - - from brian2.core.base import BrianObject + class UnsupportedObject(BrianObject): def __init__(self): super().__init__(name='unsupported*') @@ -935,7 +929,6 @@ def __init__(self): test_Synapses() test_ExportDevice_options() test_ExportDevice_basic() - test_ExportDevice_unsupported() # TODO: not checking anything test_synapse_init() test_synapse_connect_cond() test_synapse_connect_generator() From 1cf325526a170576502383a8eb300c19b1a73b9a Mon Sep 17 00:00:00 2001 From: Utkarsha Dunde Date: Sat, 21 Mar 2026 20:23:37 +0530 Subject: [PATCH 4/7] Addressing review comments : Fix pipeline --- brian2tools/mdexport/expander.py | 15 ++++++++------- brian2tools/plotting/morphology.py | 16 ++++++++-------- brian2tools/tests/test_baseexport.py | 7 ++++--- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/brian2tools/mdexport/expander.py b/brian2tools/mdexport/expander.py index 75085d43..500ae746 100644 --- a/brian2tools/mdexport/expander.py +++ b/brian2tools/mdexport/expander.py @@ -704,8 +704,9 @@ def expand_initializer(self, initializer): (initializer['index'] != 'True' and initializer['index'] != 'False')): init_str += ' if ' + self.render_expression(initializer['index']) elif (isinstance(initializer['index'], bool) or - (initializer['index'] == 'True' or - initializer['index'] == 'False')): + (isinstance(initializer['index'], str) and + (initializer['index'] == 'True' or + initializer['index'] == 'False'))): if initializer['index'] is True or initializer['index'] == 'True': init_str += '' # "to all members" implied else: @@ -796,10 +797,10 @@ def expand_connector(self, connector): self.expand_identifiers(connector['identifiers'])) return con_str + '.' + endll - - - + + + def expand_pathway(self, pathway): """ Expand `SynapticPathway` @@ -864,7 +865,7 @@ def expand_summed_variables(self, sum_variables): sum_var_str += self.expand_summed_variable(sum_var) return sum_var_str - + def expand_runregularly(self, run_reg): """ @@ -880,4 +881,4 @@ def expand_runregularly(self, run_reg): ' code: ' + self.prepare_math_statements(run_reg['code'], separate=True) + ' will be executed' + endll) - return md_str + return md_str \ No newline at end of file diff --git a/brian2tools/plotting/morphology.py b/brian2tools/plotting/morphology.py index 4cf6b5c9..24d8cc6f 100644 --- a/brian2tools/plotting/morphology.py +++ b/brian2tools/plotting/morphology.py @@ -34,15 +34,15 @@ def _plot_morphology2D(morpho, axes, colors, color = colors[color_counter % len(colors)] if isinstance(morpho, Soma): - x, y = morpho.x/um, morpho.y/um - radius = morpho.diameter/um/2 + x, y = float(morpho.x/um), float(morpho.y/um) + radius = float(morpho.diameter/um/2) circle = Circle((x, y), radius=radius, color=color) axes.add_patch(circle) - - + + else: coords = morpho.coordinates/um - + if show_diameter: coords_2d = coords[:, :2] directions = np.diff(coords_2d, axis=0) @@ -56,7 +56,7 @@ def _plot_morphology2D(morpho, axes, colors, (coords_2d - orthogonal*radius[:, np.newaxis])[::-1]]) patch = Polygon(points, color=color) axes.add_patch(patch) - + else: axes.plot(coords[:, 0], coords[:, 1], color=color, lw=2) if show_compartments: @@ -74,7 +74,7 @@ def _plot_morphology2D(morpho, axes, colors, show_compartments=show_compartments, show_diameter=show_diameter, colors=colors, color_counter=color_counter+1) - + def _plot_morphology3D(morpho, figure, colors, values, value_norm, value_colormap, show_diameters=True, @@ -439,4 +439,4 @@ def plot_dendrogram(morphology, axes=None): axes.set_xticks([]) axes.set_ylabel('distance from root (um)') axes.set_xlim(-1, terminal_counter) - return axes + return axes \ No newline at end of file diff --git a/brian2tools/tests/test_baseexport.py b/brian2tools/tests/test_baseexport.py index 910d4d58..c0c73598 100644 --- a/brian2tools/tests/test_baseexport.py +++ b/brian2tools/tests/test_baseexport.py @@ -237,7 +237,7 @@ def test_spikegenerator(): assert spike_gen_dict['indices'] == [0] assert spike_gen_dict['indices'].dtype == int - assert float(spike_gen_dict['times']) == float(time) + assert float(spike_gen_dict['times'][0]) == float(time[0]) assert spike_gen_dict['times'][:].dimensions == second assert spike_gen_dict['times'].dtype == float @@ -903,7 +903,7 @@ def test_ExportDevice_unsupported(): class UnsupportedObject(BrianObject): def __init__(self): super().__init__(name='unsupported*') - + obj = UnsupportedObject() net = Network(obj) with pytest.raises(NotImplementedError): @@ -929,7 +929,8 @@ def __init__(self): test_Synapses() test_ExportDevice_options() test_ExportDevice_basic() + test_ExportDevice_unsupported() test_synapse_init() test_synapse_connect_cond() test_synapse_connect_generator() - test_synapse_connect_ij() + test_synapse_connect_ij() \ No newline at end of file From 3183e284dca074538c76589730f1228bfc6fce1a Mon Sep 17 00:00:00 2001 From: Utkarsha Dunde Date: Sat, 21 Mar 2026 20:32:04 +0530 Subject: [PATCH 5/7] Addressing review comments : Fix pipeline 2 --- brian2tools/plotting/morphology.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/brian2tools/plotting/morphology.py b/brian2tools/plotting/morphology.py index 24d8cc6f..b912ae86 100644 --- a/brian2tools/plotting/morphology.py +++ b/brian2tools/plotting/morphology.py @@ -34,8 +34,8 @@ def _plot_morphology2D(morpho, axes, colors, color = colors[color_counter % len(colors)] if isinstance(morpho, Soma): - x, y = float(morpho.x/um), float(morpho.y/um) - radius = float(morpho.diameter/um/2) + x, y = float(np.squeeze(morpho.x/um)), float(np.squeeze(morpho.y/um)) + radius = float(np.squeeze(morpho.diameter/um/2)) circle = Circle((x, y), radius=radius, color=color) axes.add_patch(circle) From 56982fcf7681b71aceb15dfa15d6c7ad1d34695f Mon Sep 17 00:00:00 2001 From: Utkarsha Dunde Date: Sat, 21 Mar 2026 22:59:06 +0530 Subject: [PATCH 6/7] Addressing review comments. --- brian2tools/plotting/morphology.py | 10 ++++++---- brian2tools/tests/test_plotting.py | 14 ++++++++++++++ docs_sphinx/user/plotting.rst | 8 +++++--- 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/brian2tools/plotting/morphology.py b/brian2tools/plotting/morphology.py index 69b2b5db..43c3477b 100644 --- a/brian2tools/plotting/morphology.py +++ b/brian2tools/plotting/morphology.py @@ -365,10 +365,12 @@ def plot_dendrogram(morphology, axes=None, **kwds): The `~matplotlib.axes.Axes` instance used for plotting. Defaults to ``None`` which means that a new `~matplotlib.axes.Axes` will be created for the plot. - kwds : dict, optional - Any additional keywords command will be handed over to matplotlib's - `~matplotlib.axes.Axes.plot` command. This can be used to set plot - properties such as the ``color``. + **kwds + Any additional keyword arguments are passed to matplotlib's + `~matplotlib.axes.Axes.plot`, `~matplotlib.axes.Axes.vlines`, and + `~matplotlib.axes.Axes.hlines` calls. Only arguments accepted by all + three functions should be used (e.g. ``color``, ``alpha``, + ``linewidth``). Returns ------- diff --git a/brian2tools/tests/test_plotting.py b/brian2tools/tests/test_plotting.py index 1b6fd085..e1ec6a29 100644 --- a/brian2tools/tests/test_plotting.py +++ b/brian2tools/tests/test_plotting.py @@ -122,6 +122,20 @@ def test_plot_morphology(): ax = plot_dendrogram(morpho) assert isinstance(ax, matplotlib.axes.Axes) plt.close() + # Test that styling kwargs are accepted and forwarded without error + ax = plot_dendrogram(morpho, color='red') + assert isinstance(ax, matplotlib.axes.Axes) + plt.close() + ax = plot_dendrogram(morpho, color='blue', alpha=0.5) + assert isinstance(ax, matplotlib.axes.Axes) + plt.close() + ax = plot_dendrogram(morpho, color='green', linewidth=3) + assert isinstance(ax, matplotlib.axes.Axes) + plt.close() + # brian_plot routes Morphology to plot_dendrogram, so kwargs must work there too + ax = brian_plot(morpho, color='purple') + assert isinstance(ax, matplotlib.axes.Axes) + plt.close() ax = plot_morphology(morpho) assert isinstance(ax, matplotlib.axes.Axes) plt.close() diff --git a/docs_sphinx/user/plotting.rst b/docs_sphinx/user/plotting.rst index 0b8420f4..815c489c 100644 --- a/docs_sphinx/user/plotting.rst +++ b/docs_sphinx/user/plotting.rst @@ -228,9 +228,11 @@ dendogram:: .. image:: ../images/plot_dendrogram.svg -The `~brian2tools.plotting.morphology.plot_dendrogram` function does the same thing, but in contrast to the other -plot functions it does not allow any customization at the moment, so there is no benefit over using -`~brian2tools.plotting.base.brian_plot`. +The `~brian2tools.plotting.morphology.plot_dendrogram` function does the same thing, but also accepts additional +keyword arguments (e.g. ``color``, ``alpha``, ``linewidth``) that are forwarded to the underlying +`~matplotlib.axes.Axes.plot`, `~matplotlib.axes.Axes.vlines`, and `~matplotlib.axes.Axes.hlines` calls:: + + plot_dendrogram(morpho, color='red', alpha=0.7) .. _plotting_morphologies: From 3ec09366965d25363185421ccb8948be02546bbe Mon Sep 17 00:00:00 2001 From: Utkarsha Dunde Date: Thu, 26 Mar 2026 17:24:11 +0530 Subject: [PATCH 7/7] Addressing review comments. --- brian2tools/plotting/morphology.py | 9 ++++++--- docs_sphinx/user/plotting.rst | 14 +++++++++++--- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/brian2tools/plotting/morphology.py b/brian2tools/plotting/morphology.py index e0b0caa8..a42f78cf 100644 --- a/brian2tools/plotting/morphology.py +++ b/brian2tools/plotting/morphology.py @@ -430,9 +430,12 @@ def plot_dendrogram(morphology, axes=None, **kwds): x_values = (np.array(min_index) + np.array(max_index)) / 2.0 + clip_on = kwds.pop('clip_on', False) + lw = kwds.pop('lw', kwds.pop('linewidth', 2)) + # Plot the dendogram with lengths of the vertical lines representing the # total distance to the root - plt.plot(x_values[0], length_metric[0], marker='o', clip_on=False, **kwds) + plt.plot(x_values[0], length_metric[0], marker='o', clip_on=clip_on, **kwds) for sec, (x, depth) in enumerate(zip(x_values, length_metric)): child_start_idx = (sec+1)*max_children num_children = flat_morpho.morph_children_num[sec+1] @@ -440,8 +443,8 @@ def plot_dendrogram(morphology, axes=None, **kwds): child_indices = children[child_start_idx:child_start_idx+num_children] child_depth = length_metric[child_indices-1] child_x = x_values[child_indices-1] - axes.vlines(child_x, depth, child_depth, clip_on=False, lw=2, **kwds) - axes.hlines(depth, min(child_x), max(child_x), lw=2, **kwds) + axes.vlines(child_x, depth, child_depth, clip_on=clip_on, lw=lw, **kwds) + axes.hlines(depth, min(child_x), max(child_x), lw=lw, **kwds) axes.set_xticks([]) axes.set_ylabel('distance from root (um)') axes.set_xlim(-1, terminal_counter) diff --git a/docs_sphinx/user/plotting.rst b/docs_sphinx/user/plotting.rst index 815c489c..2e87c2b2 100644 --- a/docs_sphinx/user/plotting.rst +++ b/docs_sphinx/user/plotting.rst @@ -228,12 +228,20 @@ dendogram:: .. image:: ../images/plot_dendrogram.svg -The `~brian2tools.plotting.morphology.plot_dendrogram` function does the same thing, but also accepts additional -keyword arguments (e.g. ``color``, ``alpha``, ``linewidth``) that are forwarded to the underlying -`~matplotlib.axes.Axes.plot`, `~matplotlib.axes.Axes.vlines`, and `~matplotlib.axes.Axes.hlines` calls:: +The `~brian2tools.plotting.morphology.plot_dendrogram` function does the same thing, but in contrast to the other +plot functions it does not allow any customization that is not also available via +`~brian2tools.plotting.base.brian_plot`. Both functions accept additional keyword arguments (e.g. ``color``, +``alpha``, ``linewidth``) that are forwarded to the underlying `~matplotlib.axes.Axes.plot`, +`~matplotlib.axes.Axes.vlines`, and `~matplotlib.axes.Axes.hlines` calls:: plot_dendrogram(morpho, color='red', alpha=0.7) +.. image:: ../images/plot_dendrogram_custom.svg + +The same customization is also possible via `~brian2tools.plotting.base.brian_plot`:: + + brian_plot(morpho, color='red', alpha=0.7) + .. _plotting_morphologies: Morphologies in 2D or 3D