wiheto / netplotbrain Goto Github PK
View Code? Open in Web Editor NEWA package to create simple 3D network visualizations on a brain.
License: Apache License 2.0
A package to create simple 3D network visualizations on a brain.
License: Apache License 2.0
Two small improvements needed.
Both above issues should be fixed.
Hi!
I'm trying to plot multiple plots in a figure, but I encounted an error when I try to pass the parameter ax
. Here below is a example:
import netplotbrain
import pandas as pd
import matplotlib.pyplot as plt
import netplotbrain
import pandas as pd
# Define the nodes
nodes_df = pd.DataFrame({'x': [40, 10, 30, -15, -25],
'y': [50, 40, -10, -20, 20],
'z': [20, 30, -10, -15, 30]})
# Call netplotbrain to plot
fig, ax = plt.subplots(1,1,figsize=(5,5))
netplotbrain.plot(ax = ax, nodes=nodes_df, arrowaxis=None)
The error:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
File [d:\Softwares\Mambaforge\envs\gl\Lib\site-packages\netplotbrain\plot.py:200](file:///D:/Softwares/Mambaforge/envs/gl/Lib/site-packages/netplotbrain/plot.py:200), in plot(nodes, fig, ax, view, edge_weights, frames, edges, template, network, edge_color, node_size, node_color, node_type, hemisphere, highlight_nodes, highlight_edges, **kwargs)
[198](file:///d%3A/Softwares/Mambaforge/envs/gl/Lib/site-packages/netplotbrain/plot.py?line=197) affine = None
[199](file:///d%3A/Softwares/Mambaforge/envs/gl/Lib/site-packages/netplotbrain/plot.py?line=198) if template is not None and viewtype[fi]=='b':
--> [200](file:///d%3A/Softwares/Mambaforge/envs/gl/Lib/site-packages/netplotbrain/plot.py?line=199) affine = _plot_template(ax, template_style_frame, template,
[201](file:///d%3A/Softwares/Mambaforge/envs/gl/Lib/site-packages/netplotbrain/plot.py?line=200) hemisphere=hemi_frame,
[202](file:///d%3A/Softwares/Mambaforge/envs/gl/Lib/site-packages/netplotbrain/plot.py?line=201) azim=azim[fi], elev=elev[fi],
[203](file:///d%3A/Softwares/Mambaforge/envs/gl/Lib/site-packages/netplotbrain/plot.py?line=202) **profile)
[205](file:///d%3A/Softwares/Mambaforge/envs/gl/Lib/site-packages/netplotbrain/plot.py?line=204) # Template voxels will have origin at 0,0,0
[206](file:///d%3A/Softwares/Mambaforge/envs/gl/Lib/site-packages/netplotbrain/plot.py?line=205) # It is easier to scale the nodes from the image affine
[207](file:///d%3A/Softwares/Mambaforge/envs/gl/Lib/site-packages/netplotbrain/plot.py?line=206) # Then to rescale the ax.voxels function
[208](file:///d%3A/Softwares/Mambaforge/envs/gl/Lib/site-packages/netplotbrain/plot.py?line=207) # So if affine is not None, nodes get scaled in relation to origin and voxelsize,
[209](file:///d%3A/Softwares/Mambaforge/envs/gl/Lib/site-packages/netplotbrain/plot.py?line=208) # If node coords are derived from nodeimg, this has already been taken care of.
[210](file:///d%3A/Softwares/Mambaforge/envs/gl/Lib/site-packages/netplotbrain/plot.py?line=209) if nodes is not None and nodeimg is None and viewtype[fi]=='b' and scaled_nodes == False:
...
[1448](file:///d%3A/Softwares/Mambaforge/envs/gl/Lib/site-packages/matplotlib/__init__.py?line=1447) bound = new_sig.bind(ax, *args, **kwargs)
[1449](file:///d%3A/Softwares/Mambaforge/envs/gl/Lib/site-packages/matplotlib/__init__.py?line=1448) auto_label = (bound.arguments.get(label_namer)
[1450](file:///d%3A/Softwares/Mambaforge/envs/gl/Lib/site-packages/matplotlib/__init__.py?line=1449) or bound.kwargs.get(label_namer))
TypeError: Axes.scatter() got multiple values for argument 's'
I'm not sure if I am doing it wrong. Thanks a lot!
For the templateflow, some templatestyles (surface) can be ready made and packaged to save on time.
An additional flag called can be added to use cached templates
Hi,
I would like to ask if this is possible to modify the edge_color input to get the list or NumPy array that represents each edge color?
I think these is only two lines of modifications where:
if isinstance(edgecolor, np.ndarray): if edgecolor.shape[0] == len(edges): ec = edgecolor[eci, :]
can be changed to:
if isinstance(edgecolor, np.ndarray) or isinstance(edgecolor, list): if len(edgecolor) == len(edges): ec = edgecolor[eci]
When I am using the current code and I want to pass the NumPy array with the colors for each edge then I have an error:
ValueError: array(['#6c1fff', '#68fcc1', '#1dd1e2', '#149df1', '#08bee9', '#2adddd', '#4a53fb', '#08bee9', '#4a53fb', '#622ffe', '#149df1', '#622ffe', '#6c1fff', '#68fcc1', '#1dd1e2', '#2adddd'], dtype='<U7') is not a valid value for color
I would like to have the color for each edge based on the connectivity values.
Best,
Marta
Subtitles still remain when setting title to None.
The following code results with a subtitle superior.
import netplotbrain
netplotbrain.plot(template='MNI152NLin6Asym', view='S', title=None)
This is not the expected behaivour as title=None should suppress the automatic subtitle behaviour (as discussed previously). @silviafan since it was you who added the subtitle behaivour, can you look into this?
Current state: At the moment, you can specify a view as a multi letter argument, e.g. view='LR' and frames=5. This will produce 5 frames going from L to R.
Problem: Currently it is not possible to specify 360 degree rotation without some subpotimal hacking of arguments (which may even be broken).
Desired implementation: view='L', frames=5, will plot 5 figures going from L view around and excluding L view.
Potential problems Rotation can be along the rotation axis xy, xz or yz axes. I think 360 arguments only makes sense for L, R, A, and P along the x.y axis. Maybe the arguments has to be "L360", "R360", "A360", "P360"
Difficulty: maybe not the easiest to do. But relatively easy. Good first issue for someone with programming experience wanting to learn more about the package.
I would like to ask whether the coordinates XYZ in the node represent the index of the image, similar to IJK, or represent the world coordinate system, such as the RAS coordinate system or the LPS coordinate system. The situation is not explained in the document
Some string argument to views that specify a default multi panel layout.
For example: view=”sides”
may great a 2x2 figure where you see:
row1: L, R
row 2: R (left hemisphere only), L (right hemisphere only)
motivation: otherwise to plot this type of figure you need to type
views=[[“L” ,”R”], [“L”, “R”]]
hemi=[[“” ,””], [“R”, “L”]]
A selection of different default view combinations can then be created (Eg 6 and 8 panel figures) with a single string.
difficulty to implement: easy to moderate.
Observation: Saving a 3-panel svg results in large files being created (60mb).
What is needed:
Check template compatibility with all atlases. If not, make json for special settings for each
Note: heavily edited comment
Not sure when this happened or why but the previous code is no longer run. Should be fixed asap
Instead of default strings that map to certain arguments, allow for user to supply an entire dictionary.
Difficulty: Easy, (if templateflow.api.get() is known)
Based on the templatestyle the number of padded zeros around images changes, which changes figure size.
Possible solution: if MNI is provided, rescale XYZ to the size of the input MNI at the end of netplotbrain.plot.
The following example
atlasinfo = tf.get(template='MNI152NLin2009cAsym',
atlas='Schaefer2018',
desc='400Parcels7Networks',
extension='.tsv')
atlasinfo = pd.read_csv(atlasinfo, sep='\t')
networks = list(map(lambda x: x.split('_')[2], atlasinfo.name.values))
atlasinfo['yeo7networks'] = networks
netplotbrain.plot(nodes=atlasinfo,
nodeimg={'atlas': 'Schaefer2018',
'desc': '400Parcels7Networks',
'resolution': 1},
template='MNI152NLin2009cAsym',
templatestyle=None,
view=['LSA'],
nodetype='parcels',
nodecmap='tab20b',
nodecolorby='yeo7networks',
title='',
arrowaxis=[],
nodealpha = 0.8,
highlightnodes={'yeo7networks': 'Cont'},
highlightlevel=0.95,
nodecolorlegend=True,
nodesizelegend=False)
results in the following figure and cluttered legend
Have option to only plot in single hemisphere.
Following code
import netplotbrain
# Get 100 node atlas from templateflow
node_dict = {'atlas': 'Schaefer2018',
'desc': '100Parcels7Networks',
'extension': '.nii.gz',
'resolution': 1}
netplotbrain.plot(template = 'MNI152NLin2009cAsym',
nodes = node_dict,
nodetype = 'parcels',
view = 'S',
hemisphere = 'L')
Leads to
RuntimeError: No surface found at the given iso value.
Problem seems to be that some voxels that some voxels for R hemisphere nodes are still included and too small to plot as parcel surfaces.
Solution: Need to add checks about parcel center's hemisphere when getting single hemisphere. OR different non-surface method to plot parcels (just voxels takes too long)
Difficulty to solve: medium to hard
Problem with set_rasterized and alpha interacting. Works when template_style='surface' but not with glass.
Gifs can only go 180 degrees at the moment. Should allow 360 through one argument
Add bctpy's NBS implementation as possible edge input that interacts with highlightnodes.
From showcase_image.py:
netplotbrain.plot(template='MNI152NLin2009cAsym',
templatestyle='surface',
view='L',
nodes='./examples/example_nodes.tsv',
hemisphere=['R'],
nodescale=5,
edges='./examples/example_edges.tsv',
templatealpha=0.05,
title='Highlight results',
templatecolor='gray',
highlightlevel=0.9,
highlightnodes=[6, 8, 25, 29],
fig=fig, ax=ax,
nodecolorlegend=False,
nodesizelegend=False,)
In general, this happens when nodetype
is 'circles' or 'spheres'.
Following code
import netplotbrain
import pandas as pd
edges = pd.read_csv('./examples/example_edges.tsv', sep='\t', index_col=0)
nodes = pd.read_csv('./examples/example_nodes.tsv', sep='\t', index_col=0)
netplotbrain.plot(template='MNI152NLin2009cAsym', view='LS', templatestyle='glass', nodes=nodes, edges=edges, nodecolor='community')
Leads to an error message:
TypeError Traceback (most recent call last)
Input In [11], in <cell line: 7>()
4 edges = pd.read_csv('./examples/example_edges.tsv', sep='\t', index_col=0)
5 nodes = pd.read_csv('./examples/example_nodes.tsv', sep='\t', index_col=0)
----> 7 netplotbrain.plot(template='MNI152NLin2009cAsym', view='LS', templatestyle='glass', nodes=nodes, edges=edges, nodecolor='community')
File ~/packages/netplotbrain/netplotbrain/plot.py:261, in plot(nodes, fig, ax, view, frames, edges, template, templatestyle, network, arrowaxis, arroworigin, edgecolor, nodesize, nodecolor, nodetype, nodecmap, edgecmap, edgeweights, nodes_df, hemisphere, title, highlightnodes, highlightedges, showlegend, **kwargs)
259 else:
260 legend_subplotp_colind = int(np.round(spind / 2) - 1)
--> 261 ax = fig.add_subplot(gridspec[nrows + li, legend_subplotp_colind])
262 if legend == 'nodesize':
263 ax = _add_nodesize_legend(ax, nodes, nodesize, **profile)
File ~/anaconda3/lib/python3.9/site-packages/matplotlib/gridspec.py:257, in GridSpecBase.__getitem__(self, key)
254 except ValueError as err:
255 raise ValueError("Unrecognized subplot spec") from err
256 num1, num2 = np.ravel_multi_index(
--> 257 [_normalize(k1, nrows, 0), _normalize(k2, ncols, 1)],
258 (nrows, ncols))
259 else: # Single key
260 num1, num2 = _normalize(key, nrows * ncols, None)
File ~/anaconda3/lib/python3.9/site-packages/matplotlib/gridspec.py:240, in GridSpecBase.__getitem__.<locals>._normalize(key, size, axis)
237 raise IndexError("GridSpec slice would result in no space "
238 "allocated for subplot")
239 else:
--> 240 if key < 0:
241 key = key + size
242 if 0 <= key < size:
TypeError: '<' not supported between instances of 'list' and 'int'
No error if nodecolor is not specified or string to views is 1 or 3 in length.
Includes:
Allow users to specify colors from dataframe column or matplotlib color.
This is a collection of the long term roadmap (will start to use projects if more people contribute to this)
Not really a bug, but kinda. Title is currently one of the variables that has the behaviour that is asked for in #27 however it is the one variable where this behaviour is not wanted to be repeated if given a singular string.
When specifying title in a multi-axis figure it has to be something like (here 3 panels):
['', 'This is the title', '']
For it to only appear once. Otherwise, if:
title='This is the title'
is given to netplotbrain.plot, it will generate:
['This is the title', 'This is the title', 'This is the title']
when the desired behaviours is going to generally be:
['', 'This is the title', '']
Additionally, we would probably want a titlealign
argument where, if "left" will make
['This is the title', '', '']
And so on.
For the user's sake we should have consistent input for view and hemisphere.
Currently working on #31 and noticed some weirdness in user interface. For a 2x2 view plotting L/R hemispheres form L/R views.
At the moment:
view = [['L' 'R'], ['R', 'L']]
hemisphere = [['L', 'R'], ['L', 'R']]
and
view = [['LR'], ['RL']]
hemisphere = [['LR'], ['LR']]
will both lead to an error
At present what is needed to get the above to work is:
view = [['LR'], ['RL']]
hemisphere = [['L', 'R'], ['L', 'R']]
Both the invalid examples should work.
_get_frame_input
moderate (cause modifications to _get_frame_input could change other functions)
Provided template files are not load.
ImageFileError: Cannot work out file type of ".cache\templateflow\tpl-MNI152NLin2009cAsym\tpl-MNI152NLin2009cAsym_res-01_desc-brain_T1w.nii.gz"
Code that I am using:
netplotbrain.plot(template='MNI152NLin2009cAsym', templatestyle='surface', nodes=new_nodes, edges=edges, templatealpha=1, nodecolor='blue', templatecolor='gray', view='L') plt.show()
I have tried also to download the file and load this as a template but then the surface is not showing.
Take examples (or amended examples) from the examples in README.md or ./examples/showcase.py and move them to new documentation.
See how examples in docs/gallary/*.md and docs/gallary.md are written for inspiration.
Desired outcome: Allow nodes and edges to be plotted from a networkx network.
Proposed implementation: Add argument network
to plot with a function that converts networkx.Graph to create (or add to) nodes and edges dataframes at the start of netplotbrain.plot.
Difficulty: Easy (some networkx knowledge probably needed)
This looks like a great python alternative to other options (e.g., BrainNet Viewer). One feature that is helpful in BrainNet Viewer is the ability to add a text label to certain nodes in the figure. Is this a feature that could be added (or is this already implemented and I have missed it)?
Thanks so much.
Make it possible for the discrete legend to be bigger.
Some ideas:
Allow legend_size = ‘large’ to span all subplots. Alternatively, allow the legend to be longer
Have an argument like legend_discrete_Boer row to allow multiple rows and set it to 3 or 4
Make default text higher
Try and detect when text overlaps.
None of these are decided, just writing notes to myself (and allowing others to contribute idea about how to make them better)
Probabilistic atlases (e.g., difumo) are not piecewise smooth.
It would be interesting to weigh the colors of the ROIs and modify the alpha channel to make them transparent as you move away from the ROI and enter a different one.
From the example currently in the readme:
fig = plt.figure()
ax_m2 = fig.add_subplot(121, projection='3d')
netplotbrain.plot(template='MNI152NLin2009cAsym',
templatestyle='surface',
fig = fig,
ax = ax_m2,
view='A',
nodes=nodes,
nodesize='centrality_measure1',
nodecolor='red',
edges=edges)
ax_m2 = fig.add_subplot(122, projection='3d')
netplotbrain.plot(template='MNI152NLin2009cAsym',
templatestyle='surface',
fig = fig,
ax = ax_m2,
view='A',
nodes=nodes,
nodesize='centrality_measure2',
nodecolor='blue',
edges=edges)
plt.show()
We could make arguments be lists across views. So the above would be
netplotbrain.plot(template='MNI152NLin2009cAsym',
templatestyle='surface',
view=['A', 'A'],
nodes=nodes,
nodesize=['centrality_measure1', 'centrality_measure2'],
nodecolor=['red', 'blue'],
edges=edges)
plt.show()
Benfitis:
Negatives:
The following minimal example
import netplotbrain
netplotbrain.plot(nodes=None,
edges=None,
template=None,
view=['SS'])
results in the following error:
~/packages/netplotbrain/netplotbrain/plot.py in plot(nodes, fig, ax, view, frames, edges, template, templatestyle, templatevoxsize, arrowaxis, arroworigin, edgecolor, nodesize, nodecolor, nodetype, nodecolorby, nodecmap, edgeweights, nodecols, nodeimg, hemisphere, title, highlightnodes, showlegend, **kwargs)
244 for ri in range(nrows):
245 # Get the azim, elev and arrowaxis for each row
--> 246 azim, elev, arrowaxis_row = _get_view(
247 view[ri], frames, arrowaxis=arrowaxis)
248 for fi in range(frames):
~/packages/netplotbrain/netplotbrain/utils/plot_utils.py in _get_view(views, frames, arrowaxis)
78 for n in range(frames):
79 if direction == '+':
---> 80 vx.append(v1x + n * ((v2x - v1x) / (frames - 1)))
81 vy.append(v1y + n * ((v2y - v1y) / (frames - 1)))
82 elif direction == '-':
ZeroDivisionError: division by zero
Improvement to make input more unified.
Hello,
I'd like to visualise a weighted network (weight varies from 0-1) by colour. With the following code:
netplotbrain.plot(
template=template
nodes=nodes
edges=data_array,
edge_cmap='viridis',
edge_colorvminvmax=[0,1])
I get a network with only black edges. Please let me know what I'm doing wrong! Thanks very much for your time.
Currently gif duration is in ms regardless of number of figures. Since gif will generally be combined with the frames argument, a gifframerate to replace gifduration is probably better.
Or at least as a possible alternative. So that if gifframerate is not None, gifduration = (framerate * 1000) * n_frames.
I think multiply with a 1000 cause framerate is natural in seconds and gifduration is currently in ms.
Theoretically should not be hard to do.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.