Title: mplfinance - add_artist raises AttributeError: 'dict' object has no attribute 'axes'
Tags: python,matplotlib,mplfinance

Question: I am using mplfinance to create a OHLC chart (stock prices)
This is implemented as a custom class as I need to add additional elements to the final chart
class CandlestickChart:
    def __init__(self, data):
        self.data = data
        self.fig, self.ax = mpf.plot(
            self.data,
            type="ohlc",
            volume=False,
            returnfig=True,
        )

I then have another function that

def add_swap_zone(self, swap_zone):
        zone_data = self.data.copy()
        zone_data["in_swap_zone"] = (zone_data.index >= swap_zone.x_left) & (
            zone_data.index <= swap_zone.x_right
        )
        zone_data["swap_zone_val"] = np.nan
        zone_data.loc[zone_data["in_swap_zone"], "swap_zone_val"] = swap_zone.y_down
        zone_data["swap_zone_val"].fillna(swap_zone.y_up, inplace=True)

        ap_swap_zone = mpf.make_addplot(
            zone_data["swap_zone_val"],
            type="bar",
            width=0.5,
            color=swap_zone.style.FILL_COLOUR,
            alpha=swap_zone.style.FILL_ALPHA,
            panel=0,
            secondary_y=False,
        )

        self.ax[0].add_artist(ap_swap_zone)


While the mechanics of the function may look complex, in essence I am using mpf.make_addplot to create a new plot, which then gets added to self.ax[0]
The error I receive is
Traceback (most recent call last):
  File "/Users/user/projects/charter/src/draw/demo/demo_plot.py", line 42, in <module>
    main()
  File "/Users/user/projects/charter/src/draw/demo/demo_plot.py", line 35, in main
    cs_chart.add_swap_zone(
  File "/Users/user/projects/charter/src/draw/plot.py", line 39, in add_swap_zone
    self.ax[0].add_artist(ap_swap_zone)
  File "/Users/user/projects/charter/venv/lib/python3.11/site-packages/matplotlib/axes/_base.py", line 2219, in add_artist
    a.axes = self
    ^^^^^^
AttributeError: 'dict' object has no attribute 'axes'

I have tried the below alternative ways to add the plot and still failed

self.ax[list(self.ax.keys())[0]].add_artist(ap_swap_zone)
self.ax["0"].add_artist(ap_swap_zone)

EDIT:
Revised code based on selected answer
class CandlestickChart:
    def __init__(self, data):
        self.data = data
        self.addplot_specs = []

    def add_swap_zone(self, swap_zone):
        zone_data = self.data.copy()
        zone_data["in_swap_zone"] = (zone_data.index >= swap_zone.x_left) & (
            zone_data.index <= swap_zone.x_right
        )
        zone_data["swap_zone_val"] = np.nan
        zone_data.loc[zone_data["in_swap_zone"], "swap_zone_val"] = swap_zone.y_down
        zone_data["swap_zone_val"].fillna(swap_zone.y_up, inplace=True)

        ap_swap_zone = mpf.make_addplot(
            zone_data["swap_zone_val"],
            type="bar",
            width=0.5,
            color=swap_zone.style.FILL_COLOUR,
            alpha=swap_zone.style.FILL_ALPHA,
            panel=0,
            secondary_y=False,
        )

        self.addplot_specs.append(ap_swap_zone)

    def plot(self):
        self.fig, self.ax = mpf.plot(
            self.data,
            type="ohlc",
            volume=False,
            returnfig=True,
            addplot=self.addplot_specs,
        )
        mpf.show()

Constructor initialises self.addplot_specs[] which is then appended with addplot specification in add_swap_zone(). The mpl.plot() passes addplot=self.addplot_specs

Answer: While the mechanics of the function may look complex, in essence I am using mpf.make_addplot to create a new plot, which then gets added to self.ax[0]

Your problem is that mpf.make_addplot() does not return a matplotlib Artist object.
Rather, mpf.make_addplot() returns an "addplot specification object" which can then be passed into the addplot= kwarg of mpf.plot()
(alternatively one can also assign a list of such "addplot specification" objects to the addplot= kwarg).
You should rearrange you code accordingly to first build the list of one or more make_addplot() objects (inside your CandlestickChart object), and then call mpf.plot().
Thus the CandlestickChart constructor should not call mpf.plot() but rather create a method on the class that will call mpf.plot() when you are ready.
(Or alternatively the constructor can call mpf.plot() but only if it has all of the addplot specification objects at the time of construction).
Let me know if that answers your question or if you need any additional information.
(P.S. Just fyi, the reason you are getting an error messsage about a dict is because, for the time being, the addplot specification object is a dict, however this is not always guaranteed to be the case.  It could be that some day in the future mplfinance will have a need to define its own class for the addplot specification object, which is why mplfinance users should not manipulate this dict on their own but rather only use mpf.make_addplot() to build it.)