Getting trace from figure

Hi there,

So far I’ve been manually inspecting the Figure obj to get trace, e.g. here, I generate a quiver fig, and an image using Express.imshow, and “hack” quivers out of the quiver fig and add to img fig.

quiver_fig = ff.create_quiver(X, Y, grad_X, grad_Y, scale=0.05, arrow_scale=0.1, scaleratio=1.0)    
fig = draw_img(im)
fig.add_trace(quiver_fig["data"][0])

This seems to work:

However this is error prone I guess because it needs to reverse engineer the structure of Figure. I wonder do we have a proper API that allows querying trace data? Thanks!

Hi @danielyan86129 ,

I don’t think so. As I understand, the traces (data) of a figure are stored in a list. So if you are interested in the trace data only, you could change to this:

quiver_data = ff.create_quiver(X, Y, grad_X, grad_Y, scale=0.05, arrow_scale=0.1, scaleratio=1.0).data[0]    
fig = draw_img(im)
fig.add_trace(quiver_data)

It is obviously the same, the only thing is that you dont have to worry about the list index as the initial figure has only one trace.

@AIMPED You are not right! quiver_data is an instance of the class go.Figure, while fig.add_trace requires an instance of a trace type, go.Scatter, go.Bar, go,Heatmap, and so on.
Please don’t answer questions, by giving an untested code.

@danielyan86129
When you have a fig defined by fig=go.Figure() and a ff_fig retuned by a function from plotly.figure_factory,
then inspect L= len(ff_fig.data), and display each ff_fig.data[k] for k equal to 0, 1, … L-1, and decide which trace from those listed, you want to add to the initial fig, via:
fig.add_trace(ff.fig.data[j]) for some j.

Hi @empet thanks for your input and the clarification. I actually tested the code before posting it, so here is what I tested.

import plotly.graph_objects as go
import plotly.figure_factory as ff
import numpy as np

# quiver example from help
x,y = np.meshgrid(np.arange(0, 2, .2), np.arange(0, 2, .2))
u = np.cos(x)*y
v = np.sin(x)*y

# just the data (trace)
figure_data = ff.create_quiver(x, y, u, v).data[0]

# create actual figure
fig = go.Figure(data=go.Bar(y=[1,2,3]))
fig.add_trace(figure_data)

# show figure
fig.show()

which produces:

Unluckily, the key change to the initial code is hidden in the code block, one has to scroll all to the right to see what I actually changed (at least on my PC).

@AIMPED Yes, now when you stressed that data[0] is appended at the row end, it’ s OK (although it was invisible), but your answer just repeated the solution given by @danielyan86129 himself, and did not answer his more general question.

Hi @empet. You are right, my answer repeats @danielyan86129 solution which I mentioned in my last sentence.

It is obviously the same, the only thing is that you dont have to worry about the list index as the initial figure has only one trace.

I tried to answer his question, or at least add this information:

As I understand, the traces (data) of a figure are stored in a list.

I know, pretty basic information given in a simple sentence. You described the same much more precise (better):

inspect L= len(ff_fig.data), and display each ff_fig.data[k] for k equal to 0, 1, … L-1, and decide which trace from those listed, you want to add to the initial fig, via:
fig.add_trace(ff.fig.data[j]) for some j.

In this case I just wanted to help as nobody responded until then. BTW, I test all code in my answers before posting them.

Anyways, I really appreciate the depth of all your answers in this forum, thank you for that.

Thanks for pitching in guys. I really appreciate the responsiveness of the forum.

I’ll use .data[0] thanks to the fact that there is only one data trace in the quiver fig the moment it’s created (as pointed out by @AIMPED ).

Let me ask a related question: do we have a plan to add official API to query a trace? Inspecting each data in the data list is not an “API” IMO. Maybe we can allow user to “tag” a trace when a trace is added? E.g.

fig.add_trace(trace_data, tag="my_trace")

# later retrieve it
my_trace_data = fig.get_trace("my_trace")

Similar approach should be applicable when a fig is created with provided trace.

Kind of convoluted, but allows you to retrieve a trace by name for altering

fig.data.index([x for x in fig.data if x.name == "trace_name" ][0])

Just make sure to give your traces unique names for altering later.