How to use setattr if value is not single? - python

I want to use setattr to create a plot:
import numpy as np
import matplotlib.pyplot as plt
x = np.random.rand(10)
y = np.random.rand(10)
# I want this:
# plt.scatter(x, y)
setattr(plt, "scatter", [HOW TO PASS X AND Y])
Since value I want to pass is not single, how should I do it? Basically, this should be the result: plt.scatter(x, y)

I think what you are looking for is getattr. In this case, it will return a Callable, so you can just treat it like a function, like this:
getattr(plt, 'scatter')(x, y)
Is the same as this:
plt.scatter(x, y)
Using setattr in that way would be more akin to plt.scatter = (x, y), which I don't think is what you want to do.

You're not setting an attribute, but instead calling one.
getattr(plt, some_func)(x, y)
will call
plt.some_func(x, y)
So, in your case, you want to run
getattr(plt, 'scatter')(x, y)

Related

How can I use the formatters to make custom ticks in matplotlib?

How can I use the default tickformatters (which I like and don't want to have to recreate) to make my own custom tickmarks? The problem I am trying to solve is that I'd like to apply a function to all of the numbers on the y-axis.
For instance, let's say that I wanted to square all of the y-axis tick labels. I don't want to change their positions or change the underlying data, I just want to change the labels. I understand that I could write my own formatter from scratch, but I'd prefer to just write a wrapper around the existing formatters. I tried:
import matplotlib.pyplot as plt
from matplotlib.ticker import ScalarFormatter
def my_formatter(x,pos):
return ScalarFormatter(x**2,pos)
x = np.arange(10)
y = x
fig, ax = plt.subplots()
plt.plot(x,y)
ax.yaxis.set_major_formatter(plt.FuncFormatter(my_formatter))
plt.show()
But that doesn't work:
I understand why it doesn't work, I'm trying to figure out how to actually call the ScalarFormatter so that I can get the strings it would generate.
Use mpl.ticker.FuncFormatter which allows you to modify the value of your ticks (not the position) with a function.
I prefer to decorate the formatter like so:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.ticker import FuncFormatter
#FuncFormatter
def my_formatter(x, pos):
return "{}".format(x ** 2)
x = np.arange(10)
y = x
fig, ax = plt.subplots()
ax.plot(x, y)
# As we decorated the function we can just use
# the function name as the formatter argument
ax.yaxis.set_major_formatter(my_formatter)
plt.show()
You should return a string from your formatter and matplotlib will handle the positioning.
I think you can try setting: ax.set_xticklabels() instead of having to define a function to pass it in.
Define your labels:
labels = x**2 # x is a np.array
ax.set_yticklabels(labels)
Found this very good answer:
class MyFormatter(ScalarFormatter):
def __call__(self, x, pos=None):
return super().__call__(x ** 2, pos=pos)
ax.yaxis.set_major_formatter(MyFormatter())

How to speed up Matplotlib?

I am new to Matplotlib and that's why there might be a more efficient way to run my program.
It is plotting a bunch of points with different colours (depending on some factors). It is constantly producing new pictures in a loop of the current colour state.
Basically it looks like this:
import matplotlib.pyplot as plt
def getColour():
#calculate some stuff with x and y and the changing factors
while True:
fig = plt.figure(figsize=(17,10))
plt.scatter(x, y , c=getColour())
plt.show()
plt.close(fig)
I was trying out clf() as well. However, it didn't change the pace at all. Does anyone have ideas? What am I doing wrong?
Thank you!
Edit:
The target is to produce a picture each time it goes through the loop. Since my program is doing this quite slowly, my question is whether there is a way to make it run faster.
I am working with python 2.7
Something like an animation:
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import numpy as np
ms_between_frames = 100
n_points = 100
x = np.arange(n_points, dtype=float) #EDIT
y = np.random.random(n_points)
z = np.random.random(n_points)
def getColour(x, y, z):
c = np.empty((len(x),3))
for i in range(len(x)):
c[i] = [x[i]/n_points, z[i], 1.-z[i]]
return c
def update(frame_number):
global x, y
z = np.random.random(n_points)
c = getColour(x, y, z)
graph.set_color(c)
fig = plt.figure(figsize=(17,10))
ax = fig.add_subplot(111)
graph = ax.scatter(x, y , c=getColour(x, y, z))
animation = FuncAnimation(fig, update, interval=ms_between_frames)
plt.show()
EDIT: made x hold floats so the division inside getColour would not return 0 (could also have made /float(n_points))
By the way, it should be possible to define only one function to update the colours, depending on the arguments you require to do so, to avoid the call overhead.

How to get color of most recent plotted line in Python's plt

I plot a line without specifying the color (think: plt.plot(x,y)).
Say the color comes out blue.
Question: How do I obtain this color from the plt object so that I can put it into a variable?
Seems like this is close (and potentially the solution):
p = plt.plot(x,y)
color = p[0].get_color()
Updated question:
I am not sure I understand the "0" index: Does p[0] always access the most recent plotted line?
In your example, p is a list of Line2D object. In that example you have only one line object, p[0]. The following is an example plotting three lines. As more line is added, it is appended to the p. So if you want the color of the last plot, it will be p[-1].get_color().
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(10)
y = np.arange(10)
p = plt.plot(x,y, x,y*2, x,y*3) # make three line plots
type(p) # list
type(p[0]) # <class 'matplotlib.lines.Line2D'>
p[0].get_color() # 'b'
p[1].get_color() # 'g'
p[2].get_color() # 'r'
If you cannot access or store the return value of the call to plt.plot, you should also be able to use plt.gca().lines[-1].get_color() to access the color of the last line which was added to the plot.
In the following example, I'm creating example data, run curve_fit and show both data and fitted curve in the same color.
import matplotlib.pyplot as plt
import numpy as np
from scipy.optimize import curve_fit
m = 5
n = 3
x = np.arange(m)
y = np.array([i * x + np.random.normal(0, 0.2, len(x)) for i in range(n)])
def f(x, a, b):
return a * x + b
for y_i in y:
popt, pcov = curve_fit(f, x, y_i)
plt.plot(x, y_i, linestyle="", marker="x")
plt.plot(x, f(x, *popt), color=plt.gca().lines[-1].get_color())
plt.show()
For regular plt.plot, doing item.get_color() on each element of the list it returns will get you the colors of each line.
But other plot functions, like plt.scatter, will return a Collection. For a Collection, you can call result.get_facecolor(). This will return an array of color values of the foreground colors of the elements. So if they're all the same color (as they are when you make a scatter plot with just X and Y values), result.get_facecolor()[0] will suffice.

Can update .fill_betweenx() arguments? How?

I'm aware that it's possible to update the x and y values of a plot by using its artist with .set_xdata() and .set_ydata().
Can something similar be done with .fill_betweenx() to update its arguments ( y, x1, x2 and where ) to avoid clearing the axes and plotting it again?
It is somewhat a hack, there is a set_path method for the PolyCollection that fill_between returns, but it seems not to be functional. Have to directly assign new Path to _path:
from matplotlib.path import Path
x = [0,2,3,4,5]
y = [1,4,5,6,7]
z = [4,5,6,7,8]
PC = plt.fill_between(x, y, z)
PC._paths = [Path(np.vstack([[1,1,2,3,4,5,5,5,4,3,2,1,1],
[4,3,4,5,6,7,8,8,7,6,5,4,4]]).T,
np.array([1,2,2,2,2,2,2,2,2,2,2,2,9]))]
Before
After

How to plot with mplot3d

I am trying to plot the solutions of a minimization problem,
'X, Y = meshgrid(gammas, psis)'
gammas and psis are my 2 axes,
'mplot3d(X, Y, x)'
x is the solution of my problem,
While executing my script : name 'mplot3d' is not defined......
import pylab
def scatterme(x, y, z):
pylab.figure()
imi = pylab.scatter(x, y, c = z, edgecolor = "none")
pylab.colorbar(imi)
pylab.show()
In this case, my x and y are what for you would be X.flatten() and Y.flatten() and the z would be your x.flatten(). This code also works if your data does not come from something square, so if you just want to see what something looks like, if you have a lot of x and y values, and for each one you have a z, this shows you what you want as well.
Note: this is not a 3D plot, but i (personnal opinion) feel that a scatterplot in which the z-dimension is your colorbar seems to show much more what you need to know, compared to a 3D plot that you have to rotate around all the time, to be able to see at the angle that might show you something you want to know
Edit:
for the full code, that you can just copypaste (put this after the first piece in my post)
import numpy
X,Y = meshgrid(gammas, psis)
scatterme(X.flatten(), Y.flatten(), x.flatten())

Categories

Resources