Test if object is subplot in Matplotlib - python-3.x

I have defined some plots which I now like to arrange using subplots. So I will pass an axis object to the plot definition and tell it to plot on that instead of making a new plot. However, to make this fool-proof I like to check that the passed object is actually of the right type, i.e. an axis.
When I make a subplot like so: f, ax = pyplot.subfigure(2,2) and inspect type(ax[1,1]) it returns matplotlib.axes._subplots.AxesSubplot, however I cannot use isinstance() to test against that value. What works is isinstace(ax[1,1],matplotlib.axes._subplots.Subplot). But I can also test against matplotlib.axes._subplots.Axes or matplotlib.axes._subplots.SubplotBase, all equate to True. I'm a bit confused by the ambiguity here. What is the correct way to test if something is an object one can plot on?

Related

Zoom-out for manim Axes

Suppose we have an Axes object and a graph plotted in the coordinate system defined by these axes.
Is it possible to "zoom-out" by one or both axes, so we can see more of the graph, while the dimensions of the Coordinate system on the screen are kept constant?
For example, I've tried using the ValueTracker for both x_range properties of the Axes and the graph but it gives strange and unexpected results.
class Test(Scene):
def construct(self):
x_max_tracker = ValueTracker(0.0)
axes = always_redraw(lambda: Axes(
(-np.pi, x_max_tracker.get_value(), 0.5), (-5., 5.),
width=8, height=10
))
xsin_graph = always_redraw(
lambda: axes.get_graph(
lambda x: 0.5*x*np.sin(x)-1, color=BLUE,
x_range=[-np.pi, x_max_tracker.get_value()]
)
)
self.play(
Write(axes, lag_ratio=0.01, run_time=1), ShowCreation(xsin_graph)
)
self.wait(2)
self.play(x_max_tracker.animate.set_value(4*np.pi), run_time=2)
Additional, but connected question: is it possible to give the position of the coordinate system (Axes) at initiation?
UPDATE
I have defined a method generate_axes() which: 1) generates the Axes object; 2) Places it at specified coordinates on the Scene.
Now, if I am calling the always_redraw method on this generate_axes() method (keeping the x_tracker from the code above to control the x_range) then I could obtain nice "zoom-out/in" animation by calling play(x_tracker.animate.set_value(X)).
However, this doesn't change the axes variable, which is, apparently, still keeping the pointer on the first initial Axes object with not modified x_range. I thought that always_redraw() creates a new mobject each frame? Somehow this updated object is transferred to the Scene to be displayed but can't be accessed! For example, if I print axes.x_range after the end of the animation I am getting the initial x_range value.
P.S.: I am using the manimgl package, so the method always_redraw is probably not from the standard manim package. But it is generally the add_updater with become
Currently, Axes unfortunately do not support the sort of rescaling you would like to use. The easiest way to achieve this sort of behavior probably is by implementing a custom animation that repeatedly updates the axes and any curves within with become.
And as for your second question: Axes are always drawn in a way such that the center of the mobject is in the scene origin. You can move them to where you would like to show them, and only add them after moving.
Update
.become creates a new mobject, yes, but then only transfers some of the new mobject's properties and attributes to the original mobject. If there are some attributes that you need updated, it is best if you simply updated them yourself in your method -- which is also why using a general updater function is more flexible than always_redraw.
And for future reference: make sure to say right away whether you are working with manim or manimgl, they are substantially different in some aspects.

python define style/vairable for line (but not for figure)

I very often plot two types of results - e.g. prediction vs measurement - into a figure for a document, where the look of the corresponding lines/scatters should be match each other in different plots, but at the beginning of the writing/plotting the final look is not decided. I would like to define a bunch of plot options for every such curve, to make it possible to replot them very efficiently.
For example a would like to define the styles like:
s_theory = [linestyle="--", color="grey", marker=None, label="simulation"]
s_measurement = [linestyle=":", color="black", marker="s", markersize="5",label="measurement"]
I would like to apply these magically on plt.plot():
plt.plot(xt,yt,**s_theory)
plt.plot(xm,ym,**s_measurement)
How can I do that? What is the magic word I did not found during my search for this task? I am pretty sure there is a very simple to do that.
Based on the comment of ImportanceOfBeingErnest:
style_sim = {"linestyle":"--", "color":"grey", "marker":"None", "label":"simulation"}
style_meas = {"linestyle":":", "color":"black", "marker":"s", "markersize":5, "label":"measurement"}
plt.plot(xt,yt,**style_sim)
plt.plot(xm,ym,**style_meas)
If you find it useful, please vote up the comment of ImportanceOfBeingErnest!

Using "for" in MatPlotLib

I want to create a histogram serie. However, I also need to use weights (I cannot use seaborn).
I tried to use "for" to create this serie using:
list=range(28,37)
for i in list:
plt.hist(Base.iloc[:,i],weights=Base['weights']
But I got a Strange histogram:
I have 2 questions:
how do I create this serie; and,
what is this strange histogram?
for i in range (28,37)
plt.hist(Base.iloc[:,i],weights=Base['weights']

PyQt: Obtain all pixels inside QPolygon

In PyQt 5, is there a way to obtain all pixel positions that would be modified by a call to QPainter.drawPolygon for a QPainter object constructed with some QImage as an argument without actually drawing the polygon? Ideally I would like to obtain separate sets of pixel positions for the polygon's border and for all pixels inside the polygon.
Just like #ekhumoro said, QPolygon is a subclass of QVector (that is, a QList). However, in Pyqt this is a Python array and not a QList. I got runtime errors when trying to iterate over this list, because it was inside the QPolygon object and there was no getter. In this case, in PyQt the solution is not very efficient. You need to iterate over each pixel of the image, creating a QPoint with pixel coordinates and checking if the QPolygon contains this point through the containsPoint method. There aren't many implementation details, but consider the following code snippet.
array_qpoints = [] # this array will have all the QPoints
polygon = QPolygon([
QPoint(140,234),
QPoint(126,362),
QPoint(282,409),
QPoint(307,273),
QPoint(307,233),
])
# let's consider a 640x480 image
for x in range(640):
for y in range(480):
point = QPoint(x, y)
if polygon.containsPoint(point, Qt.FillRule.OddEvenFill):
array_qpoints.append(point)
You can get the coordinates of each pixel by calling the x() and y() methods for each element in array_qpoints.
for point in array_qpoints:
x = point.x()
y = point.y()
# do what you want with the information
I'm posting this answer for others who visit this question and are looking for a solution by code. Since it's been several years, if you've found a better solution, please post :)

Wrong fit parameters, Undefined value during function evaluation

I'm trying to do some simple fits using Gnuplot and encountering an error which somehow I'm not able to explain. Seems that I'm doing something terribly wrong with the definition of my function.
I first started with a fit of some functions. The functional form of these is not important as the fits work pretty well, but since they are involved later I'm reporting them as well.
evap(x)=(x>x_fc)?A*qnet(x)/wm2_to_mmh:(x<x_wp)?0:(A*qnet(x)/wm2_to_mmh)*(x-x_wp)/(x_fc-x_wp)
fit evap(x) './fluxes_da_1p0.txt' using 1:2 via A, x_fc, x_wp
sensible(x)=( (qnet(x)/wm2_to_mmh)-evap(x) ) / (1+B)+C
fit sensible(x) './fluxes_da_1p0.txt' using 1:3 via B,C
Then I defined
deltasensible(x)=abs(sensible(x)-sensible(0.454))
deltalatent(x)=abs(evap(x)-evap(0.454))
period_adv=18.0
g(x)=m*deltalatent(x)*period_adv*(deltasensible(x))**e
If I impose
m=3.8
e=0.5
and just plot the function g(x) superimposed on the data it seems to work pretty well.
However if I try to fit it using the parameters
fit g(x) './advection_da_1p0.txt' using 5:2 via m,e
I get the following error
iter chisq delta/lim lambda m e
0 4.2471983038e+00 0.00e+00 5.51e+00 3.800000e+00 5.000000e-01
1 3.7149813491e+00 -1.43e+04 5.51e-01 3.573384e+00 4.843345e-01
Current data point
=========================
# = 8 out of 8
x = 0.0178156
z = 0.0309726
Current set of parameters
=========================
m = 0.0178156
e = -0.0583802
"rain_estimate.gpl", line 52: Undefined value during function evaluation
For some reason Gnuplot is trying out really strange values for m,e, although I provided their initial values. If I remove the deltalatent(x) dependency everything is working fine. Am I missing something simple?
So I think I figured it out the problem by myself. Given my data a line was the best fit for Gnuplot so that it was trying to remove the exponential dependency on deltasensible by choosing a really small coefficient. Seems more an "error" with the data than with Gnuplot itself.

Resources