Giter Club home page Giter Club logo

netplotbrain's People

Contributors

silviafan avatar syamgadde avatar wiheto avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

netplotbrain's Issues

Minor bugs - legends in small figures and test figures

Two small improvements needed.

  • Tests sometimes fail after small changes (currently after nodealpha was implemented baseline figures and test figures do not always match). Why this is the case is unknown at the moment. Perhaps some different matplotlib version weirdness. Needs to be investigated. This seems to include titles on figure sometimes becoming too close to the figure in one version.
  • One-panel figures with node property legends (see the tutorial in the documentation) have overlapping text/figures despite tight_layout on. Not sure why this is happening.

Both above issues should be fixed.

Error when using self-defined axes

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!

Create cache of templatestyles.

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

Edgecolor

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

Bug: when title=None, automatic/view subtitles are still printed.

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?

ENH: Full brain rotation

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.

node coordinates(x,y,z) definition

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

ENH: default views

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.

ENH: Check templateflow compatibility

Check template compatibility with all atlases. If not, make json for special settings for each

  • glass
  • cloudy
  • surface
  • filled

Note: heavily edited comment

Improvement: have color-coded legend display only the highlightnodes={ } selection

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

image

BUG: problem plotting some parcel atlas with 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

highlightnode argument does not highlight nodes

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,)

image

In general, this happens when nodetype is 'circles' or 'spheres'.

Multiple minor bugs in text behaviour

  • fix subplot title. Can intersect with figure when no template argument is given
  • Legend font often too small
  • Legend title often intersecting with figure,
  • showcase image title too large
  • fix documentation and examples after subtitle/title change
  • if title is list, make it none and subtitles=title (will also fix old behaviour and make documentation correct)

Error when 2 views + legend (via e.g. nodecolor) leads to an error

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.

Fix: Fix coord arrows

Includes:

  • Dynamically place origin of arrows based on view. (i.e. make sure the arrows are always in front of brain)
  • Dynamically choose which arrows are shown (e.g. calculate the 6 letter placements in relation to view, and remove letters with smallest distance)
  • Fix rotation bug

the color setting is failed

image
the data is below:
image
I have reinstalled the package netplotbrain and matplotlib, but it still show me error.

"Gallary" tab in documentation

All examples in

Should have explanations to how to achieve the effects in a specific page in the documentation where each the unique concept in each plot is explained as a tutorial.

Roadmap

This is a collection of the long term roadmap (will start to use projects if more people contribute to this)

Released in #60

  • Improve svg saving for all templates (ensure all template backgrounds are rasteriszed)
  • More legend freedom (increase sizes) (see #57) -> currently on develop branch
  • Link published article in docs
  • Plot from bids
  • Include connectivity matrices (like spring plots) that can be specified in views
  • Experienced some a bug with pybids layout.get_entities() sometimes failing. Need to investigate/create minimal example of to report/find workaround. -> unsure why but was caused but getting unique entities from the main folder and not the derivative folder was causing the error

Bug fixes

  • #52 Parcel plots with single hemisphere
    ... And any others found

Enhancements

  • Better arrows for directions. Consider no arrows but just lines or lines with sphere (see #7)
  • Improve gif plots (see #29)
  • Improve continuous colorbar use/flexibility (specify cbar tick range instead of just being extremes).
  • If node_color organizes connectivity matrix, then add color lines to connectivity matrix diagonal

New features

  • Include surface plots - no reasons they can't be included #49
  • Allow to shuffle parcel id numbers to improve colorbar distirbution (e.g. sequential)
  • More BIDSoperations

Improved Documentation

  • Add BIDS and CM feature in README/Main page as a major feature.
  • Tutorial: BIDS
  • Gallery example of BIDS
  • Gallery example of legend_span
  • Gallery example, rotated cm

Bug(ish): Multi panel figures with one title should only generate one title

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.

BUG/ENH: consistent input for view and hemisphere

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']]

Desired outcome:

Both the invalid examples should work.

Function that needs modifying:

_get_frame_input

Difficulty:

moderate (cause modifications to _get_frame_input could change other functions)

Provided template files not loading

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.

ENH: NetworkX integration

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)

Feature Request: Label nodes with ROI name

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.

ENH: improve figure legend

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)

Visualization of the ROIs in a probabilistic atlas

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.

Enh: specify different properties for different views

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:

  • Less code for user to write
  • Less figure management by user.

Negatives:

  • All input arguments would have to be checked for this behaviour. (So quite a bit of work. Although the function get_frame_input could do most of the work, if modified.)
  • Breaks legend behaviour if multiple legends are needed (e.g. example above) unless there is some way to detect when a legend would needed to be repeated or not.

BUG: 2 column plot error leads to an error

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

Rename nodesimg to nodes, allow for nodes_df and edges_df input

Improvement to make input more unified.

  • nodesimg should be specified using nodes. If nodes is a dictionary, valid path, or nifti, assume it is nodesimg.
  • nodes_df should be allowed to supplement a nodsimg file for colour/size/highlighting. Implementation: Depends how the above is implemented
  • edges_df should also be allowed for when the input is a numpy array. Implementation: if edges is numpy array, edges_df outer merges with it after it is converted edges.merge(edges_df, how='outer').

Issue with colouring edges by weight

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.

ENH Gif duration as framerate instead of duration

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.

Enhancement: add surface templates

Theoretically should not be hard to do.

  • Add gifti/cifti loading of the file.
  • check each templatestyles or throw errors for templatestyles that are not compatible. Perhaps only allow surface as a templatestyle for surface images.
  • plot surfaces in resource effective way.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.