Matplotlib artist to stay same size when zoomed in but ALSO move with panning?

2024/10/6 14:36:42

This is a very direct follow-up on this question.

Using matplotlib, I'd like to be able to place a sort of "highlighting bar" over a range of data markers that I know will all be in a straight horizontal line.

This bar/rectangle should be slightly taller than the markers and contain them, something like this for the three markers below:

enter image description here

In order to be a sensible highlighting bar, it needs to have the following two traits:

  • If the plot is panned, the bar moves with the markers (so it always covers them).
  • If the plot is zoomed, the bar's display height doesn't change (so it always is slightly taller than the markers).

If it is helpful to know, these markers have no meaningful y values (they are plotted all at y=-1), only meaningful x values. Therefore, the height of the bar is meaningless in data coordinates; it merely needs to be always just tall enough to enclose the markers.

Answer

Great question! This was a good challenge and requires a combination of things to achieve.

Firstly, we need to invent a transform which will return the device coordinates of a pre-defined value plus an offset based on the given point. For instance, if we know we want the bar to be at x_pt, y_pt, then the transform should represent (in pseudo code):

def transform(x, y):return x_pt_in_device + x, y_pt_in_device + y

Once we have done this, we could use this transform to draw a box of 20 pixels around a fixed data point. However, you only want to draw a box of fixed pixel height in the y direction, but in the x direction you would like standard data scaling.

Therefore, we need to create a blended transform which can transform the x and y coordinates independently. The whole code to do what you are asking:

import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
import matplotlib.path as mpath
import matplotlib.transforms as mtransimport numpy as npclass FixedPointOffsetTransform(mtrans.Transform):"""Always returns the same transformed point plusthe given point in device coordinates as an offset."""def __init__(self, trans, fixed_point):mtrans.Transform.__init__(self)self.input_dims = self.output_dims = 2self.trans = transself.fixed_point = np.array(fixed_point).reshape(1, 2)def transform(self, values):fp = self.trans.transform(self.fixed_point)values = np.array(values)if values.ndim == 1:return fp.flatten() + valueselse:return fp + valuesplt.scatter([3.1, 3.2, 3.4, 5], [2, 2, 2, 6])ax = plt.gca()
fixed_pt_trans = FixedPointOffsetTransform(ax.transData, (0, 2))xdata_yfixed = mtrans.blended_transform_factory(ax.transData, fixed_pt_trans)x = [3.075, 3.425] # x range of box (in data coords)
height = 20 # of box in device coords (pixels)
path = mpath.Path([[x[0], -height], [x[1], -height],[x[1], height],  [x[0], height],[x[0], -height]])
patch = mpatches.PathPatch(path, transform=xdata_yfixed,facecolor='red', edgecolor='black',alpha=0.4, zorder=0)
ax.add_patch(patch)plt.show()
https://en.xdnf.cn/q/70358.html

Related Q&A

How to invoke Lambda function with Event Invocation Type via API Gateway?

Docs says:By default, the Invoke API assumes RequestResponse invocation type. You can optionally request asynchronous execution by specifying Event as the InvocationType. So all I can send to my functi…

How do I unlock the app engine database when localhost runs?

Right now I get a blank page when localhost runs, but the deployed app is fine. The logs show the "database is locked". How do I "unlock" the database for localhost?

PyCrypto: Generate RSA key protected with DES3 password

I have been able to create a RSA key protected by password with DES3 (well... I think because Im very new to this encryption world) by using the command:openssl genrsa -out "/tmp/myKey.pem" -…

Normalize/Standardize a numpy recarray

I wonder what the best way of normalizing/standardizing a numpy recarray is. To make it clear, Im not talking about a mathematical matrix, but a record array that also has e.g. textual columns (such as…

How to read /dev/log?

I would like to directly access to syslog messages from Python by reading /dev/log.My (very limited) understanding is that the correct way is to read from there is to bind a datagram socket. import soc…

Determining if a number evenly divides by 25, Python

Im trying to check if each number in a list is evenly divisible by 25 using Python. Im not sure what is the right process. I want to do something like this:n = [100, 101, 102, 125, 355, 275, 435, 134, …

OpenCV SimpleBlobDetector detect() call throws cv2.error: Unknown C++ exception from OpenCV code?

I need to detect semicircles on image and I find follow stuff for this: import cv2 import numpy as npdef get_circle(img_path):im = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE)detector = cv2.SimpleBlobDet…

Is it possible to add a global argument for all subcommands in Click based interfaces?

I am using Click under a virtualenv and use the entry_point directive in setuptools to map the root to a function called dispatch.My tool exposes two subcommands serve and config, I am using an option …

Error importing h5py

Ive been trying to import h5py to read this type of file.Here is my code:import h5pyfile_1 = h5py.File("Out_fragment.h5py")print file_1The output is:Traceback (most recent call last):File &qu…

Tensorflow leaks 1280 bytes with each session opened and closed?

It seems that each Tensorflow session I open and close consumes 1280 bytes from the GPU memory, which are not released until the python kernel is terminated. To reproduce, save the following python scr…