Discussion:
Adding a second vertical plot
Tony Lewis
2013-04-15 14:43:43 UTC
Permalink
Hi, I'm new to Chaco, and new-ish to Python. Apologies in advance for
dumb questions.

I am trying to plot a OHLC finance chart, but also have overlay plots
(e.g. for now, a moving average). I also want to add another plot
below, (e.g. for MACD). All pretty standard trading stuff for now.

I can get the OHLC chart OK, and overlay a moving average, but am
struggling to add the second window, and I think it's because I'm trying
to add the second plot after the _plot_default() gets called

All the VPlotContainer example code seems to assume you know all the
plots you want to do beforehand, and have put them all in the function
that gets called by _plot_default(). But that seems a bit restrictive.
In the long run I want to be able to add and remove plots dynamically,
and have both the plot update, and the underlying data.

So my specific question is: what am I doing wrong, and my general
question is: can Chaco do this kind of dynamic adding and removing of
plots from (say) a VPlotContainer? If so, how do I make that happen.

Here's some trimmed code, derived from your example candle.py. I hope
pastebin is OK.
http://pastebin.com/ytxQfKy1 : CandleChartTest.py - the main code that
creates the instance of CandleChart
http://pastebin.com/qua5Ur1w : CandleChart.py - the class of the plot

Thanks,

Tony
Tony Lewis
2013-04-16 13:18:22 UTC
Permalink
Post by Tony Lewis
Hi, I'm new to Chaco, and new-ish to Python. Apologies in advance for
dumb questions.
I am trying to plot a OHLC finance chart, but also have overlay plots
(e.g. for now, a moving average). I also want to add another plot
below, (e.g. for MACD). All pretty standard trading stuff for now.
I can get the OHLC chart OK, and overlay a moving average, but am
struggling to add the second window, and I think it's because I'm trying
to add the second plot after the _plot_default() gets called
All the VPlotContainer example code seems to assume you know all the
plots you want to do beforehand, and have put them all in the function
that gets called by _plot_default(). But that seems a bit restrictive.
In the long run I want to be able to add and remove plots dynamically,
and have both the plot update, and the underlying data.
So I think the dynamic part is a bit of a red herring. Inside
_plot_default(), I tried getting multiple plots in a VPlotContainer and
this failed until I made them all of type Plot. Trying to add a
LinePlot and a Plot (containing the two candles) failed.

Is that a bug or a feature?
Robert Kern
2013-04-16 13:35:04 UTC
Permalink
Post by Tony Lewis
Post by Tony Lewis
Hi, I'm new to Chaco, and new-ish to Python. Apologies in advance for
dumb questions.
I am trying to plot a OHLC finance chart, but also have overlay plots
(e.g. for now, a moving average). I also want to add another plot
below, (e.g. for MACD). All pretty standard trading stuff for now.
I can get the OHLC chart OK, and overlay a moving average, but am
struggling to add the second window, and I think it's because I'm trying
to add the second plot after the _plot_default() gets called
All the VPlotContainer example code seems to assume you know all the
plots you want to do beforehand, and have put them all in the function
that gets called by _plot_default(). But that seems a bit restrictive.
In the long run I want to be able to add and remove plots dynamically,
and have both the plot update, and the underlying data.
So I think the dynamic part is a bit of a red herring. Inside
_plot_default(), I tried getting multiple plots in a VPlotContainer and
this failed until I made them all of type Plot. Trying to add a
LinePlot and a Plot (containing the two candles) failed.
Is that a bug or a feature?
I'm afraid that you are falling afoul of a poor naming scheme. `Plot`
isn't really the same kind of thing as `LinePlot`. `LinePlot` a
descendant of `BasePlotRenderer` and is responsible for drawing the
lines of a single line-plot and nothing else. It doesn't do axes or
titles or legends or anything but the line-plot itself. `Plot` is a
descendant of `OverlayPlotContainer` and is responsible for managing
many `BasePlotRenderers` that should be drawn on the same axes (and
the axes themselves, the title, legend, etc.). You would generally not
want to put a `LinePlot` in the same container as a `Plot`.

I expect that you want to put multiple `Plots` in your
`VPlotContainer`. Don't use `create_line_plot()` but use the
`Plot.plot()` method on the second `Plot` to draw the line-plot. Don't
try to share the mappers between them. Mappers map data-space to
screen-space, so if two objects don't share the same space, they
should not have the same mappers. Instead, you want to lock the
mappers' ranges:

https://github.com/enthought/chaco/blob/master/examples/tutorials/tutorial9.py

In other situations, you may have to do some layout jiggery-pokery to
make sure that everything aligns right, but the defaults should work
okay here.

--
Robert Kern
Enthought
Didrik Pinte
2013-04-16 13:40:43 UTC
Permalink
To add to Robert's answer, if you want to see code where you
dynamically add plots within a container, here is a simple example :

https://gist.github.com/dpinte/5395968

-- Didrik
Post by Robert Kern
Post by Tony Lewis
Post by Tony Lewis
Hi, I'm new to Chaco, and new-ish to Python. Apologies in advance for
dumb questions.
I am trying to plot a OHLC finance chart, but also have overlay plots
(e.g. for now, a moving average). I also want to add another plot
below, (e.g. for MACD). All pretty standard trading stuff for now.
I can get the OHLC chart OK, and overlay a moving average, but am
struggling to add the second window, and I think it's because I'm trying
to add the second plot after the _plot_default() gets called
All the VPlotContainer example code seems to assume you know all the
plots you want to do beforehand, and have put them all in the function
that gets called by _plot_default(). But that seems a bit restrictive.
In the long run I want to be able to add and remove plots dynamically,
and have both the plot update, and the underlying data.
So I think the dynamic part is a bit of a red herring. Inside
_plot_default(), I tried getting multiple plots in a VPlotContainer and
this failed until I made them all of type Plot. Trying to add a
LinePlot and a Plot (containing the two candles) failed.
Is that a bug or a feature?
I'm afraid that you are falling afoul of a poor naming scheme. `Plot`
isn't really the same kind of thing as `LinePlot`. `LinePlot` a
descendant of `BasePlotRenderer` and is responsible for drawing the
lines of a single line-plot and nothing else. It doesn't do axes or
titles or legends or anything but the line-plot itself. `Plot` is a
descendant of `OverlayPlotContainer` and is responsible for managing
many `BasePlotRenderers` that should be drawn on the same axes (and
the axes themselves, the title, legend, etc.). You would generally not
want to put a `LinePlot` in the same container as a `Plot`.
I expect that you want to put multiple `Plots` in your
`VPlotContainer`. Don't use `create_line_plot()` but use the
`Plot.plot()` method on the second `Plot` to draw the line-plot. Don't
try to share the mappers between them. Mappers map data-space to
screen-space, so if two objects don't share the same space, they
should not have the same mappers. Instead, you want to lock the
https://github.com/enthought/chaco/blob/master/examples/tutorials/tutorial9.py
In other situations, you may have to do some layout jiggery-pokery to
make sure that everything aligns right, but the defaults should work
okay here.
--
Robert Kern
Enthought
_______________________________________________
Chaco-users mailing list
https://mail.enthought.com/mailman/listinfo/chaco-users
--
Didrik Pinte +32 475 665 668
+44 1223 969515
Enthought Europe dpinte-***@public.gmane.org
Scientific Computing Solutions http://www.enthought.com

The information contained in this message is Enthought confidential &
not to be dissiminated to outside parties without explicit prior
approval from sender. This message is intended solely for the
addressee(s), If you are not the intended recipient, please contact
the sender by return e-mail and destroy all copies of the original
message.
Tony Lewis
2013-04-16 14:44:57 UTC
Permalink
Post by Didrik Pinte
To add to Robert's answer, if you want to see code where you
https://gist.github.com/dpinte/5395968
Didrik, thanks that's very useful!

I was trying to figure if it was a necessity or convention that most of
the _create_plot_component() functions happened outside the class. At
one point I couldn't make it work being a method on the class, but as a
side effect you've shown that it can all be in the class.

Tony
Didrik Pinte
2013-04-16 14:51:52 UTC
Permalink
Post by Tony Lewis
Post by Didrik Pinte
To add to Robert's answer, if you want to see code where you
https://gist.github.com/dpinte/5395968
Didrik, thanks that's very useful!
I was trying to figure if it was a necessity or convention that most of
the _create_plot_component() functions happened outside the class. At
one point I couldn't make it work being a method on the class, but as a
side effect you've shown that it can all be in the class.
Yes, it is more a question of class design than requirement.

!! This is not the case for the traits magic methods (for static trait
change handlers, etc.).

-- Didrik
Tony Lewis
2013-04-16 14:55:02 UTC
Permalink
Post by Robert Kern
I'm afraid that you are falling afoul of a poor naming scheme. `Plot`
isn't really the same kind of thing as `LinePlot`. `LinePlot` a
descendant of `BasePlotRenderer` and is responsible for drawing the
lines of a single line-plot and nothing else. It doesn't do axes or
titles or legends or anything but the line-plot itself. `Plot` is a
descendant of `OverlayPlotContainer` and is responsible for managing
many `BasePlotRenderers` that should be drawn on the same axes (and
the axes themselves, the title, legend, etc.). You would generally not
want to put a `LinePlot` in the same container as a `Plot`.
I expect that you want to put multiple `Plots` in your
`VPlotContainer`. Don't use `create_line_plot()` but use the
`Plot.plot()` method on the second `Plot` to draw the line-plot. Don't
try to share the mappers between them. Mappers map data-space to
screen-space, so if two objects don't share the same space, they
should not have the same mappers. Instead, you want to lock the
https://github.com/enthought/chaco/blob/master/examples/tutorials/tutorial9.py
Thank you.

Your example works fine, but I can't make it work in my code.

https://gist.github.com/bigtonylewis/5396525

Here I create two line plots, and lock the mapper ranges as per tutorial
9. Note, I didn't link the value_mappers because that doesn't make
sense - they are different scales.

When run, I can pan around the rsiPlot, by dragging either the rsiPlot
or the pricePlot. But in either case, the pricePlot remains fixed in
range. The axis pans with the drag, but not the plot itself.

If I change the index_mapper locking line to:
rsiPlot.index_mapper.range = pricePlot.index_mapper.range
then the problem is reversed - any panning affects only the range of
pricePlot; rsiPlot remains fixed.

I am missing something simple, I know, but I seem to be stuck.
Didrik Pinte
2013-04-16 15:06:07 UTC
Permalink
It works fine for me with some differences slight differences to yours:

https://gist.github.com/dpinte/5395968

-- Didrik
Tony Lewis
2013-04-16 16:08:39 UTC
Permalink
Post by Didrik Pinte
https://gist.github.com/dpinte/5395968
Hmmm, doesn't work for me:


I was using Chaco 4.1.0 from the Ubuntu repository, but I just updated
to 4.3.0 via pip install. Problem remains.

Tony
Tony Lewis
2013-04-17 15:01:58 UTC
Permalink
Post by Tony Lewis
Post by Didrik Pinte
https://gist.github.com/dpinte/5395968
Hmmm, doesn't work for me: http://youtu.be/3mrsr3KZAn4
I was using Chaco 4.1.0 from the Ubuntu repository, but I just updated
to 4.3.0 via pip install. Problem remains.
Cracked it, it seems

Tutorial 9 seems to work because it uses create_line_plot() to create
LinePlot objects. But Didrik's example, and my code, both use the the
Plot.plot() function.

So rather than lock the index_mappers of the Plot objects, I lock the
index_mappers of the Plot()'s .plot_component[0].index_mapper to the
other line plots.

Seems to work. Not sure why Didrik's was working for him and not for me
out of the box, though.

Onwards!

Loading...