holoviz / holoviews

With Holoviews, your data visualizes itself.
https://holoviews.org
BSD 3-Clause "New" or "Revised" License
2.68k stars 402 forks source link

Arrowhead edges for directed graphs do not point properly #3562

Open jaco0797 opened 5 years ago

jaco0797 commented 5 years ago

As the title states, arrowhead edges do not point properly for all directed graphs... at least mine. Their lengths and direction are off. The dimensions of my graph are width = 900, height = 400. Arrowhead_length = 0.01. See attachment. Can the arrowhead edge length and size be dependent on the edge they are associated with instead of the size of the total plot? ugly arrowheads

cbarokk commented 5 years ago

When xrange is low, the arrows get displayed correctly. This is ok. (1st attachment)

x = [1,2,3,4]
y = [1,2,3,4]
node_indexes = np.arange(4)
node_indexes
nodes = hv.Nodes((x, y, node_indexes, node_indexes))
source,target = [0,1,2],[1,2,3]
graph = hv.Graph(((source, target, ), nodes, ))
graph.opts(directed=True, arrowhead_length=0.05)

However, when xrange is high, the arrows get disproportionally long. This is not ok. (2nd attachment)

x = [100,200,300,400]
y = [1,2,3,4]
node_indexes = np.arange(4)
node_indexes
nodes = hv.Nodes((x, y, node_indexes, node_indexes))
source,target = [0,1,2],[1,2,3]
graph = hv.Graph(((source, target, ), nodes, ))
graph.opts(directed=True, arrowhead_length=0.05)

When x axis is Datetime, then the graph is not displayed.

from datetime import datetime, timedelta
now = datetime.now()
x = [now + timedelta(days=i) for i in [1,2,3,4]]
y = [1,2,3,4]
node_indexes = np.arange(4)
node_indexes
nodes = hv.Nodes((x, y, node_indexes, node_indexes))
source,target = [0,1,2],[1,2,3]
graph = hv.Graph(((source, target, ), nodes, ))
graph

However displaying edges and nodes separately works. (3rd attachment) graph.edgepaths * graph.nodes

But calling graph.opts(directed=True, arrowhead_length=0.05) gives a

TypeError: ufunc 'hypot' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe''
cbarokk commented 5 years ago

bokeh_plot bokeh_plot (1) bokeh_plot (2)

philippjfr commented 5 years ago

The way arrows are drawn is really not ideal and it would be great if we could switch to using the arrow annotation in bokeh but that's not currently looking too promising since it doesn't support many of the style mapping features we'd need.

jbednar commented 5 years ago

I don't suppose Bokeh offers the ability to draw lines whose lengths and angles are specified in screen coordinates (pixels) but anchored on one end at a location in data coordinates?

poplarShift commented 5 years ago

I think Rays (https://bokeh.pydata.org/en/latest/docs/reference/models/glyphs/ray.html) would fit the bill, I used those for #3504.

jbednar commented 5 years ago

Interesting. The length of a Ray says that it defaults to data coordinates, which suggests that there must be a way to specify it in screen coordinates? The angle doesn't seem to specify what coordinates it's in, but I guess it's in screen coordinates? If so then that seems like it would work and would avoid this problem.

cbarokk commented 5 years ago

Are you guys gonna work on it anytime soon? Or do we, users, have to figure out if the Ray approach is feasible?

poplarShift commented 5 years ago

@jbednar Yup, if I understand the docs correctly (https://bokeh.pydata.org/en/latest/docs/reference/core/properties.html#bokeh.core.properties.DistanceSpec) then distances can be given in data or screen units.

jbednar commented 5 years ago

It's open source; we are all both users and developers potentially. :-) I can't speak for all other users, but it's not something on my personal to-do list. Seems fun to play around with, if anyone does get time!

poplarShift commented 5 years ago

There is this PR by me https://github.com/pyviz/holoviews/pull/3653 where I started using bokeh's Arrow for vectorfield (and hence potentially the graphs), but as @philippjfr pointed out there are less style options, so that doesn't look too promising at the moment.

I'm not sure if it's worth first checking out whether or not to enhance the Arrow style options on the bokeh side. Drawing the arrowheads with Ray looks like a better option to me than what is being done now, but it's still a workaround.

Personally, it doesn't presently look like I'll have a lot of vector fields to plot in the near future so I doubt I'll be spending a lot of time with this anytime soon.

Edit: As a side note, all this is about the bokeh interface. The matplotlib interface should deal a lot better with arrows.

gpo-atlas commented 4 years ago

Any update on this issue?

hosford42 commented 3 years ago

There is also the issue that the arrow heads terminate at the centers of the nodes, rather than radius distance from them. So if you need a larger radius for the nodes, the arrow heads are chopped off.

hosford42 commented 3 years ago

As a workaround for the misshapen arrow heads, you can set graph.opts(aspect='equal'). The arrow heads are then drawn correctly, at the expense of the graph coordinate axes being restricted to precisely equal aspect ratio.

hosford42 commented 3 years ago

This is actually a strong clue as to why the arrow heads are misshapen to begin with.