Hi! As it was mentioned in #53 it is somehow possible to display multiple plots with 'returnfig' kwarg. I want to display 3 plots in a row or even 3x3. While I am not really familiar with matplotlib can someone explain please how to do it with fig and ax returned from mpf.plot()? Or should I do it another way?
returnfig does not give you the ability to control how many subplots you have, nor what their geometry is. You will get back a Figure with either 1 or 2 subplots stacked vertically (with a primary and secondar Axes each). You can do what you want with them at that point, but the number of Axes and their geometry is fixed.
I just today began work on https://github.com/matplotlib/mplfinance/issues/17 which anticipate will take somewhere between 3 and 5 weeks to complete. You can see a rough outline for my implementation here.
mpf.plot() and mpf.make_addplot().So if you can wait a few weeks you should be in good shape. Alternatively you can spend some time learning more about matplotlib, and use the old api for which there are examples here and documentation here.
Thank you for your reply! But what if I will call mpf.plot() 3 times with different data and will get 3 fig objects and 3 axlist objects. Can I than display it in a row? Or it is not how matplotlib works by default and "matplotlib method" will do it?
But what if I will call mpf.plot() 3 times with different data and will get 3 fig objects and 3 axlist objects.
I honestly don't know (you can try it). I suspect that, given the current mplfinance code, when mpf.plot() attempts to create a new Figure and Axes, it will get back the same Figure and Axes from matplotlib, which, as I understand it, does some kind of "caching" of the Figure. I think this is how matplotlib works, except when the call to figure() specifically includes an "identifier" with which to label the Figure, in which case each identifer will either create a new Figure or get a chached one depending on whether that identifier was used already. And it is definitely the case that mplfinance presently is not specifying an identifier when getting the Figure.
None-the-less, I'm not 100% sure about this matplotlib behavior, so feel free to give it a try and let me know how it works.
If not, #17 will should definitely fulfill your needs.
To add a new row we can shift the existing axes and then add our own axes
fig, axlist = mpf.plot(..., returnfig=True)
ax1 = axlist[0]
height = 0.2
pos = ax1.get_position()
ax1.set_position([pos.xmin, pos.ymin + height, pos.width, pos.height - height])
ax = fig.add_axes([pos.xmin, pos.ymin, pos.width, height], sharex=ax1)
ax.tick_params(bottom=False, labelbottom=False)
ax.plot(...)

@char101 Charles - That's awsome! Very creative! Thank you for sharing that! --Daniel
I have wrapped above code into a function and also added code to apply style to the new axes (since mplfinance.plot resets the style after it returns). Maybe this can be used until https://github.com/matplotlib/mplfinance/wiki/SubPlots is implemented.
@mpf.plotting.with_rc_context
def add_axes(fig, axlist, n=1, height=0.2, style=None, position='top'):
"""Adds one or more axes
params:
- n: number of axes to add
- height: total height of the lower axes including the volume axes
- style: the same value passed to mplfinance plot function
- position: 'top' or 'bottom' of the volume axes if there is a volume axes
returns:
- ax if n == 1
- [ax1, ax2, ...] if n > 1
"""
from mplfinance import _styles
# apply style
if isinstance(style, str):
style = _styles._get_mpfstyle(style)
if isinstance(style, dict):
_styles._apply_mpfstyle(style)
has_volume = len(axlist) > 2
# shift chart axes
ax1 = axlist[0]
pos1 = ax1.get_position()
if not has_volume:
ax1.set_position([pos1.xmin, pos1.ymin + height, pos1.width, pos1.height - height])
else:
ax2 = axlist[2]
pos2 = ax2.get_position()
if pos2.height != height:
d = height - pos2.height
ax1.set_position([pos1.xmin, pos1.ymin + d, pos1.width, pos1.height - d])
# shift volume axes
pos1 = ax1.get_position()
if has_volume:
ax_height = height / (n + 1)
if position == 'top':
ax_y = pos1.ymin
ax2.set_position([pos2.xmin, pos2.ymin, pos2.width, ax_height])
elif position == 'bottom':
ax_y = pos1.ymin - ax_height
ax2.set_position([pos2.xmin, ax_y, pos2.width, ax_height])
else:
ax_height = height / n
ax_y = pos1.ymin
# add new axes
axs = []
for _ in range(n):
ax_y -= ax_height
ax = fig.add_axes([pos1.xmin, ax_y, pos1.width, ax_height])
ax.set_xlim(*ax1.get_xlim())
ax.tick_params(bottom=False, labelbottom=False)
axs.append(ax)
return axs[0] if n == 1 else axs
Example: adding 2 axes on top of volume axes
fig, axlist = mpf.plot(...style=style, returnfig=True)
ax1, ax2 = add_axes(fig, axlist, height=0.3, n=2, style=style)
ax1.plot(...)
ax2.plot(...)

Edit 1: added ax.set_xlim(*ax1.get_xlim()) so that the xticks are aligned
@DanielGoldfarb,
Excellent work with mplfinance! A serious contender among the various plotting modules/libraries out there trying to support financial charting. I had this same issue as I require multiple subplots both above and below the main price chart. For example:

@char101
Nice work adding additional subplots with the function. Definitely a time saver! Is it possible to plot above the price chart as well?
Thanks,
KJ
@twopirllc
Kevin,
There is an enhancement currently in my fork that allows up to three charts (called "panels") and you can control the order (put additional panels above or below the main panel), and you can control the relative size of each panel with the panel_ratio kwarg. From your image however it looks like you've got six charts there. I will look into whether I can increase the number of panels without overly complicating the code. @char101 Charle's function shows some awesome creativity as workaround until this enhancement is complete. If you get a chance to test with the code in my fork, let me know. Otherwise I am hoping to release it by the end of this week.
All the best. --Daniel
@twopirllc ... actually you've given me an idea how I can might generalize the code in my fork to have N panels stacked up, and to specify which one is the main panel (so it can have charts both above and below it). Will play with this today and see if I can get it working without to much complexity.
@DanielGoldfarb,
I am in no rush. Quality takes time. That chart has 7 panels including price. Hopefully heights of each panel are adjustable.
Thanks for your time and expertise,
KJ
Currently the layout and the plot type is rather tightly coupled. It would be nice to have an abstraction between the layout and the plot type, probably in OOP style.
fig = mpf.add_figure(ohlc, style, ...)
ax = fig.add_axes(...)
ax.add_plot(mpf.plot.candle(...), ...)
ax.add_plot(mpf.plot.mav(...), ...)
ax.add_plot(mpf.plot.mav(...), ...)
ax2 = fig.add_axes(...).add_plot(mpf.plot.volume(...), ...)
def my_custom_plot(ax, data):
pass
ax3 = fig.add_axes(...).add_plot(my_custom_plot(...), ...)
This isn't practical in something like jupyter notebook but is useful when using it from python program so that we can easily mix and match multiple plot types and to customize the layout.
For quick typing we can use the chain style
mpf.add_figure(...).add_axes(plot=candle(...)).add_axes(plot=volume(...))
External Axes Mode is now available.
Most helpful comment
I have wrapped above code into a function and also added code to apply style to the new axes (since
mplfinance.plotresets the style after it returns). Maybe this can be used until https://github.com/matplotlib/mplfinance/wiki/SubPlots is implemented.Example: adding 2 axes on top of volume axes
Edit 1: added
ax.set_xlim(*ax1.get_xlim())so that the xticks are aligned