Search code examples
pythonimagematplotlibhiddensubplot

Image hidden from a matplotlib plot when shifted


I lose my image from a subplot when I shift the image. (The code is run in Jupyter Lab):

from mpl_toolkits.axes_grid1 import host_subplot
from mpl_toolkits import axisartist
hostImage = host_subplot(221, axes_class=axisartist.Axes)
from matplotlib.offsetbox import TextArea, DrawingArea, OffsetImage, AnnotationBbox
import matplotlib.image as mpimg
test_image = mpimg.imread('testImage.png')
imagebox = OffsetImage(test_image, zoom=1)
ab = AnnotationBbox(imagebox, (-0.0014, 0), box_alignment=(1, 0))
hostImage.add_artist(ab)

The image can still be seen with the above configuration.
Next, when I change parameters the image vanishes:

Shifting the image to the left changing line 7
ab = AnnotationBbox(imagebox, (-0.0025, 0), box_alignment=(1, 0))
to
ab = AnnotationBbox(imagebox, (-0.5, 0), box_alignment=(1, 0))

Changing the matrix layout of the subplots changing line
hostImage = host_subplot(221, axes_class=axisartist.Axes)
to
hostImage = host_subplot(111, axes_class=axisartist.Axes)

-> How can I show everything I add to a subplot (more or less) regardless how far off it may be from the axes 'central part' (the area spanned by the two axes, 'axes' in the sense of a plot)?

Using the plt.tight_layout() method did not help.

Image in a subplot before and after disappearance

Here is the test image I used (the red rhomboid).

%%%%%%%%%%% To make it clearer what I really want to achieve (practical background of the question):

I have line plots showing measurement data of about 30 sensors which are positioned in the real world in a rather geometrically complex 3D measurement setup. The position of the sensors is essential for anybody trying to understand the chart. So the image serves as a kind of 3D legend for the chart. In a single plot I show data of about 5-6 sensors (more sensors in single chart would make it unreadable). See this real example (work in progress where I stopped to post my question):

image of the real case

This example I established by creating a second subplot below the subplot with the curves. This second suplot has hidden axes (in the sense of plural of axis). It already is a workable solution and my current baseline.
By the way, for this reason I want the image to be rather below the plot in order not to 'waste' horizontal space for the chart where I plot curves.

So the '3D image legend' is integral part of the finally exported 'all-in-one' plot (.png) The .pngs go into my written report which is my ultimate goal.

In the report I could also add each image corresponding to a plot by hand, but having all info (plot and image) included in one-in-all matplotlib figures makes it more convenient to establish the report and also less error-prone (pairing wrong images and plots, since I have many sensors and many configurations thus creating quite a number of such plots).

What triggered my question beyond my above solution already established:
I want to finally place labels (matplotlib annotations) as 'overlay' on the image with the sensor names on top of the image. And then connect these labels via arrow lines with the corresponding curves of the plot. This would make it very clear and convenient to the reader to understand which plot curve corresponds to which sensor position in the image -> kind of '3D legend'. I had found ConnectionPatch as a solution for drawing lines between subplots but I got an error message which I ultimately did not want to try to resolve but choose the approach: Have the image as part of the very same subplot of the curves because connecting labels within a subplot is easy (actually you can see in the image I uploaded already such sensor name labels placed along the right y-axis).

Why do I use host_subplot?
I have up to five y-axes in my plot (I am aware that this high number of y-axis may be questionable but it is please not what I want to discuss in this post) and I understood having more than 2 additional y-axis is possible only with host_subplot using .twinx().

P.S.: After all I think I should for now lower my high expectations and stick with my workable solution of two subplots and just renounce on the possibility of connecting labels in the second subplot with curves in the first subplot.


Solution

  • Edit on 2022-09-28: I have found a solution for my case by browsing the help/py-code of matplotlib.offsetbox.AnnotationBbox:

    The desired effect can be achieved by modifying the argument xybox of AnnotationBbox like so, for example

    ab = AnnotationBbox(imagebox, xy = (1, 0), xybox = (2.0, 1.0), box_alignment=(1, 0))
    

    Setting xybox = (2.0, 1.0), hence the x-value to 2.0 shifts the image far to the right of the plot area.