Draw lines dynamically on a time series

I want to draw a time series of stock data.
and then be able to manually draw a line / lines on the graph.

I want to save my line and be able to come back to it later on. delete etc…

is that possible out of the box?

thank you

Hi @koren88i,

In the Python library it’s not possible to use the mouse to draw annotations on a plot. This is something that is possible in the online plot.ly chart studio using “Shapes”.

Looking ahead, we’re planning to work out how to best integrate plotly.py with the new open source version of the plot editor, integrated into JupyterLab (https://github.com/plotly/jupyterlab-chart-editor). So the goal is for this kind of chart editing workflow would be available fully offline as well.

If you’re interested, please take a look at the Figure file editor workflow issue and see if you think that would cover your use-case.

Hope that helps!

1 Like

Hey, thank you for responding so quickly.

How do I get to this shapes thing? I’m kinda lost in the plotly site…

My ultimate goal is

  1. plot several windows of plots (3x3 grid is ok for my screen), each is a plot of stock close prices for some defined period

  2. for each plot to be able to draw lines

  3. have those lines the next time I load the data (even if i change the period, still see the lines)

I am using tradingview platform today but having to manually do this for every stock is very time consuming…

Is that possible? with the shapes? with plotly?

Hi @koren88i,

I’m not sure that I have a full picture of what you have in mind, but here are something to try to see if gets you to the workflow you’re after.

  1. Setup plotly.py with a Plot.ly account by following these instructions: https://plot.ly/python/getting-started/
  2. Create you’re grid plot using the make_subplots approach described here: https://plot.ly/python/subplots/
  3. After you’ve created the base plot that you like, display it in the notebook using plotly.plotly.iplot (not the offline variant)
  4. In the resulting plot there will be an “EDIT CHART” button in the bottom right, click this.
  5. This will launch the online chart editor (the interface I was showing in the GIF above).
  6. Like I do above, expand the “Style” menu and then click on “Shapes”.
  7. If you want the line to stick to the data (not stay fixed on the figure canvas), then change the “Relative To” toggle from “Canvas” to “Axis” for both the vertical and horizontal boundaries.
  8. Save it using the save button on the bottom left.
  9. Later, you can view all of your saved plots at https://plot.ly/organize/home and then reopen the figure online and pan and zoom to browse your data again.

Hope that helps get you started :slight_smile:

1 Like

Thank you very much. That sounds a good start for me.

Will report.

  1. After saving a graph. Can I load updated data (e.g a week later) and still see my lines?

  2. I want a “dash board” with 6 graphs in 2 columns - each graph being an interactive one. - is that possible?

Hi @koren88i,

So, to update a graph with new data you could pull it back into plotly.py using the plotly.plotly.get_figure function (Examples). Then you could update the data properties in Python and your lines would remain fixed. If you can copy and paste your data as a table, you could probably also update the data directly in the web interface in the “Grid” pane (The spreadsheet above the plot that holds the raw data).

And yes, you can create a 3x3 grid using the make_subplots approach I linked to above. You would just configure the subplots to have 3 rows and 3 columns.

Good luck!

1 Like

Ok so I have managed to do almost everything. Great explanation man! Thank you.

Question regarding the update - currently what I am doing is

fig_from_site[‘data’][1][‘x’] = updated_df.index

fig_from_site[‘data’][1][‘y’] = updated_df[“adjusted close”]

meaning I am updating directly the list I get from the site.

But this means I need to remember which data goes in which place in the list.

the names of those graphs is in the layout part of the figure…

is there a name to get the name of the data so I wont mix up the data of different stocks?

another question

i want to ask questions about each line…

  1. can I name them?
  2. is there an easy way to get all lines per graph??

Hi @koren88i, sounds like you’re making great progress!

Each trace has a name property that you can use to set and access a custom name for the trace, so you could use your dataframe column name for these. Names are also what show up in the legend by default. You can control whether each trace is present in the legend using the showlegend property.

You can get a tuple of all of all of the traces using the fig.data property.

So you should be able to update your figure with something like:

for trace in fig_from_site.data:
    trace.y = updated_df[trace.name]

The lines are going to be stored in the fig.layout.shapes tuple.

Hope that helps!

1 Like

I’ll try that.

Is there a neat way to give a line a name?

Or access lines per graph?

Ok got the naming right.

I’ll iterate through all lines and via the “xref” and “yref” I will know whoch graph they belong (i will still need to hold a dictionary between graph number and graph name though…).

Now for the next problem :frowning:

the line is two points…

I want to know the y value of the line in several other points…

I guess there is not an elegant why of doing that? I will have to use the data itself and recompute the line etc…?

do not answer yet - working on my own solution and will publish if have problems :slight_smile:

1 Like

OK It is working! :slight_smile:

  1. Is it possible to make a “short cut” button for drawing lines?

  2. Is it possible to “click” on a graph and than have the line shape by default belong to this graph axis?

  3. size of subplots - I want to have each subplot a fixed size, regardless how many subplots i have - is that possible? I get crazy results when trying to play with margins and width etc…

  4. zoom in/out using mouse wheel?

  5. panning as default / pressing “ctrl” for example?

this library is awesome!


For 1 and 2, are you talking about the chart editor?

  1. Here’s an approach
from plotly import tools
import plotly.plotly as py
import plotly.graph_objs as go

trace1 = go.Scatter(
    x=[1, 2, 3],
    y=[4, 5, 6],
    textposition='bottom center'

nrows = 3
ncols = 2
row_widths = [350] * nrows
column_widths = [500] * ncols

fig = tools.make_subplots(rows=nrows,

for row in range(nrows):
    for col in range(ncols):
        fig.add_trace(trace1, row=row+1, col=col+1)

fig['layout'].update(width=sum(column_widths), height=sum(row_widths))
fig_widget = go.FigureWidget(fig)

TBH, it doesn’t seem like it should be necessary to specify the layout width/height explicitly. But in any case, if you do, it works out :slightly_smiling_face:

  1. Scroll zoom. You can specify this by adding the config={'scrollZoom': True} to plotly.offline.plot. In my testing this works with my touchpad using plotly.offline.plot (where the figure pops up its own browser window), but it doesn’t seem to have any affect with plotly.offline.iplot (figure inline in notebook). The config options aren’t supported by FigureWidget yet, but it’s something we’ll add at some point (See https://github.com/plotly/plotly.py/issues/1074)

  2. Try pressing shift while dragging in either pan or zoom mode. I think it will temporarily switch between pan and zoom.

Hope some of that was helpful! Glad you’re having fun :slightly_smiling_face:

1 Like
  1. yes… my main work after plotting is drawing horizontal and custom lines on each graph… choosing the right axis (and not by name…) and clicking on shapes-line-custom lines are all actions i want to do less.

  2. yes

  3. this is what i have done - seems to work- is your solution better?

    fig = tools.make_subplots(rows=num_rows, cols=num_cols, subplot_titles=([df for df in stocks_dict]), horizontal_spacing=0.2,vertical_spacing=0.2)

    curr_row = 1
    curr_col = 1
    for trace in traces:
    curr_trace = traces[trace]
    fig.append_trace(curr_trace, curr_row, curr_col)
    if curr_col % num_cols == 1:

    fig[‘layout’].update(height=700num_rows, width=700num_cols, title=‘Portfolio Stocks’,

  4. I am talking about the chart editor in my browser. not in my jupyter notebook.

  5. likewise…

after I’m pulling my data and creating the plots - I’m looking only at the chart editor… and adding lines
then I’m re downloading the graphs and doing some math about those lines and data…
then re uploading and loop…

also - loading several graphs makes the chart editor work very slow.

I tried loading only 3 years of information each graph - helped…
I tried ploting the candles of only open and close (no high low) - helped…
I tried disabling the slider bar - helped

more ideas?
will buying a non free account help here?

Hi @koren88i,

Unfortunately my knowledge about the chart editor is pretty limited. I’m not sure if any way to customize/optimize these things. You might try a post in the “Chart Studio” category of the forums.


And drawing lines offline? Is that possible?

The offline option is going to be the JupyterLab chart editor. See https://github.com/plotly/jupyterlab-chart-editor. But I don’t think it has the capability yet to open existing existing figures (So far it’s focused on opening CSVs and building charts from scratch).

One goal of mine over the next couple of months is to be able to save a figure to a file from plotly.py, open it in the JupyterLab chart editor, edit it (add annotations, etc.), and then save it back to a file. This would make the chart editing workflow available fully offline.

Also, this chart editor is a brand new implementation (compared to the current online chart editor) so it would be great if you’d be interested in trying it out!


I’m confused :confused:

What’s the difference between the online chart editor and this offline option?