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:
In order to be a sensible highlighting bar, it needs to have the following two traits:
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.
MatPlotLib with Python Create x and y points, using numpy. To zoom a part of an image, we can make data for x and y points, in that range. Plot x and y points (Step 1), using the plot() method with lw=2, color red and label. Use the legend() method to place text for the plot, Main curve.
Press the right mouse button to zoom, dragging it to a new position. The x axis will be zoomed in proportionately to the rightward movement and zoomed out proportionately to the leftward movement. The same is true for the y axis and up/down motions.
zoom() function in axis module of matplotlib library is used to zoom in or out on axis .
Matplotlib is a plotting library for the Python programming language and its numerical mathematics extension NumPy. It provides an object-oriented API for embedding plots into applications using general-purpose GUI toolkits like Tkinter, wxPython, Qt, or GTK.
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 mtrans
import numpy as np
class FixedPointOffsetTransform(mtrans.Transform):
"""
Always returns the same transformed point plus
the given point in device coordinates as an offset.
"""
def __init__(self, trans, fixed_point):
mtrans.Transform.__init__(self)
self.input_dims = self.output_dims = 2
self.trans = trans
self.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() + values
else:
return fp + values
plt.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()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With