You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[ENH]: Add an easy way to plot an infinite half space (e.g. with a HalfSpace patch) #28152
Giving this another look, and currently my approach is to make the patch larger than can be displayed, and then clipping it to the bounding box. I am not sure if this is the best way to do this, but to clip to the bounding box a closed polygon must exist and rectangle seems the simplest.
I think it is possible to use axes.get_xlim() and axes.get_ylim() to get the edges of what can be displayed, since patches are artists. However if there is no associated axes I don't know what to do, logically with no boundary it should attempt to draw an infinite shape but this could cause the program to crash or freeze.
However if there is no associated axes I don't know what to do, logically with no boundary it should attempt to draw an infinite shape but this could cause the program to crash or freeze.
ETA: also .get_xlim(), .get_ylim() are in data coordinate space, and I'm suggestion using axis coordinate space (which gets you things like infinite lines)
The same thing can easily be achieved with ax.fill_between except there is no guarantee it is infinite, but you can make it practically infinite, so I'm not clear on the use case that requires a special method. If anything, though, this brings up the idea that we should be able to take individual artists out of autoscale.
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots()
# a x + b y >= c
# y = c/b - a/b x
a = 1.
b = -1.
c = 0.
x = np.array([-1e13, 1e13])
y = c/b - a / b * x
# ax.set_autoscale_on(False)
ax.fill_between(x, y, -1e20)
ax.set_xlim([0, 10])
ax.set_ylim([0, 10])
plt.show()
Yeah, I think this ultimately gets implemented as a sorta almost thin wrapper over either polygon patch or fill_between that handles the mixed coordinate systems/transforms - which basically far as I can tell what the ax{hspan, vspan, vline, hline, axline} methods are doing is automatically updating limits and handling transforms.
There is no mixed co-ordinates needed - you just make the patch really huge in the out of bounds area, and crop to the axis view limits you want. Thats what cropping is for.
you just make the patch really huge in the out of bounds area, and crop to the axis view limits you want. Thats what cropping is for.
You still want it dynamically updated for pan/zoom or adding more data - any time you need to update the limits -which is what all the ax{span, line} methods and/or defining in axis coordinates gives you.
ETA: basically, your solution inherently doesn't handle the infinite case cause you'll have to explicitly update the patch bounds every time the data gets changed if it affects the view limits and happens to fall outside the polygon
You can zoom the above as much as you want, and you can change the data in it the same way you would for any patch, you just have to add the fictitious points at plus or minus infinity.
your solution inherently doesn't handle the infinite case cause you'll have to explicitly update the patch bounds every time the data gets changed
you just have to add the fictitious points at plus or minus infinity.
What I'm trying to get at is that implementing it as a standalone method would remove the need for the user to manage adding the fictitious points so that the patch grows in sync w/ the data.
For example, here's most of the implementation for axhspan and ahvspan and you can see how they're flipped versions of each other, where axh manages the y (data coordinate) and infinite x, and axv manages the x (data coordinate) and infinite y.
It should be fairly simple to create axhalfspace() inspired by axline(). The latter has most of the API and logic in place. You just have to define whether to fill left/right of the line, and on drawing, complete the line to an area using the Axes boundaries.
I belief more complex forms would fall in a different category: functional relations that are sampled on draw to always give a smooth relation - basic: line, a bit more advanced: fill between.
Activity
timhoffm commentedon May 17, 2024
This would be a reasonable feature. PRs welcome.
OdileVidrine commentedon Jul 26, 2024
I think best way to do this is to make it similar to connection patch, as this already takes in two points and draws a line between them.
OdileVidrine commentedon Aug 6, 2024
Giving this another look, and currently my approach is to make the patch larger than can be displayed, and then clipping it to the bounding box. I am not sure if this is the best way to do this, but to clip to the bounding box a closed polygon must exist and rectangle seems the simplest.
story645 commentedon Aug 6, 2024
This was once asked for at pydata and the proposed solution, far as I can remember, is something like half the box should be be defined in data space and the other half in axis space and I wonder if the {axhspan/axvspan} implementations might be worth looking at? https://matplotlib.org/devdocs/api/_as_gen/matplotlib.axes.Axes.axhspan.html#matplotlib.axes.Axes.axhspan
OdileVidrine commentedon Aug 7, 2024
I think it is possible to use axes.get_xlim() and axes.get_ylim() to get the edges of what can be displayed, since patches are artists. However if there is no associated axes I don't know what to do, logically with no boundary it should attempt to draw an infinite shape but this could cause the program to crash or freeze.
story645 commentedon Aug 7, 2024
If there's no axis then you've got the figure boundaries, and you may want to take a look at https://matplotlib.org/devdocs/users/explain/artists/transforms_tutorial.html if you haven't already
ETA: also
.get_xlim(), .get_ylim()are in data coordinate space, and I'm suggestion using axis coordinate space (which gets you things like infinite lines)OdileVidrine commentedon Aug 7, 2024
Oh I see, thank you
jklymak commentedon Aug 7, 2024
The same thing can easily be achieved with
ax.fill_betweenexcept there is no guarantee it is infinite, but you can make it practically infinite, so I'm not clear on the use case that requires a special method. If anything, though, this brings up the idea that we should be able to take individual artists out of autoscale.story645 commentedon Aug 7, 2024
The request at PyData was specifically to show decision boundaries for classifiers, something like https://www.scikit-yb.org/en/latest/api/contrib/boundaries.html, where you want it infinitely zoomable like for interactive visualizations.
jklymak commentedon Aug 7, 2024
That still seems doable with a Polygon patch?
story645 commentedon Aug 7, 2024
Yeah, I think this ultimately gets implemented as a sorta almost thin wrapper over either polygon patch or fill_between that handles the mixed coordinate systems/transforms - which basically far as I can tell what the
ax{hspan, vspan, vline, hline, axline}methods are doing is automatically updating limits and handling transforms.Just to confirm, I think the goal here is:

jklymak commentedon Aug 7, 2024
There is no mixed co-ordinates needed - you just make the patch really huge in the out of bounds area, and crop to the axis view limits you want. Thats what cropping is for.
jklymak commentedon Aug 7, 2024
story645 commentedon Aug 7, 2024
You still want it dynamically updated for pan/zoom or adding more data - any time you need to update the limits -which is what all the ax{span, line} methods and/or defining in axis coordinates gives you.
ETA: basically, your solution inherently doesn't handle the infinite case cause you'll have to explicitly update the patch bounds every time the data gets changed if it affects the view limits and happens to fall outside the polygon
jklymak commentedon Aug 7, 2024
You can zoom the above as much as you want, and you can change the data in it the same way you would for any patch, you just have to add the fictitious points at plus or minus infinity.
I'm not sure what this means.
story645 commentedon Aug 8, 2024
What I'm trying to get at is that implementing it as a standalone method would remove the need for the user to manage adding the fictitious points so that the patch grows in sync w/ the data.
For example, here's most of the implementation for axhspan and ahvspan and you can see how they're flipped versions of each other, where axh manages the y (data coordinate) and infinite x, and axv manages the x (data coordinate) and infinite y.

hspan
matplotlib/lib/matplotlib/axes/_axes.py
Lines 1026 to 1038 in 3d37d7a
vspan
matplotlib/lib/matplotlib/axes/_axes.py
Lines 1089 to 1100 in 3d37d7a
Where an implementation for a patch like this would probably need separable {top, bottom, right, left) and manage some pair of those.
timhoffm commentedon Aug 21, 2024
It should be fairly simple to create
axhalfspace()inspired byaxline(). The latter has most of the API and logic in place. You just have to define whether to fill left/right of the line, and on drawing, complete the line to an area using the Axes boundaries.I belief more complex forms would fall in a different category: functional relations that are sampled on draw to always give a smooth relation - basic: line, a bit more advanced: fill between.