What are the guidelines for using matplotlib's set_array() routine? - python

The documentation for set_array is very skimpy. What does it do? What range of values can it take? How does it work in conjunction with other color-related routines and data structures?
On the collections docpage it is said to "Set the image array from numpy array A." It is described in the same way in the colormap API. That's all.
I find no mention of set_array() (much less examples) in any of several popular books on matplotlib programming, such as Devert (2014), McGreggor (2015), Root (2015) and Tossi (2009).
Yet, if set_array() is some arcane function that is only needed in rare cases, why does it show up so often both in matplotlib examples and in examples posted on the SciKit Learn website? Seems like a pretty mainstream function, and so it ought to have more mainstream documentation.
For example:
Matplotlib docs: Use of set_array() in creation of a multi-colored line
Matplotlib docs: Line collection with masked arrays
Scikit Learn docs: Visualization of stockmarket structure
Sifting through Stack Overflow posts that mention set_array() I found this one, where a poster states that "set_array() handles mapping an array of data values to RGB", and this one where posters indicate that set_array() must be called in some cases when one is setting up a ScalarMappable object.
I've tried experimenting with the examples I've found on-line, changing the range of values passed in to set_array(), for example, to try to figure out what it is doing. But, at this point, I'm spending way too much time on this one dumb function. Those deeply into color maps have enough context to guess what it does, but I can't afford to take a detour that big, just to understand this one function.
Could someone please offer a quick description and maybe some links?

The set_array method doesn't do much per se. It only defines the content of an array that is internal to the object in which it is defined. See for instance in the source of matplotlib.cm
def set_array(self, A):
"""
Set the image array from numpy array *A*.
Parameters
----------
A : ndarray
"""
self._A = A
self._update_dict['array'] = True
In the multicolored_line example of the matplotlib documentation, this is used to map colors of a cmap.
Let's take a similar example and create a collection of lines and map the segments to indexed colors in a colormap:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection
from matplotlib.colors import ListedColormap, BoundaryNorm
f, axes = plt.subplots(ncols=3)
y = np.arange(0,1,0.1).repeat(2)
x = np.append(y[1:], [1])
segments = np.array(list(zip(x,y))).reshape(-1, 2, 2)
cmap = ListedColormap(['r', 'g', 'b'])
norm = BoundaryNorm([-0.5, 0.5, 1.5, 2.5], cmap.N)
for ax in axes:
ax.add_collection(LineCollection(segments, cmap=ListedColormap(['r', 'g', 'b']), norm=norm))
axes[1].collections[0].set_array(np.array([0,1]))
axes[2].collections[0].set_array(np.array([0,1,2]))
axes[1].set_title('set_array to [0,1]')
axes[2].set_title('set_array to [0,1,2]')
This gives the following output:
What is does is to map the segment to the indexed colors defined in the cmap (here 0->'r', 1->'g', 2->'b'). This behaviour is specified in the matpotlib.collections source:
Each Collection can optionally be used as its own `.ScalarMappable` by
passing the *norm* and *cmap* parameters to its constructor. If the
Collection's `.ScalarMappable` matrix ``_A`` has been set (via a call
to `.Collection.set_array`), then at draw time this internal scalar
mappable will be used to set the ``facecolors`` and ``edgecolors``,
ignoring those that were manually passed in.

Related

Can't alter figsize of a plot

I am using the function described here to get some diagnostics on multiple linear regressions.
The last code line reads # Fig and ax can be used to modify axes or plot properties after the fact.
My code:
cls = LRD(lm6_fit)
f,ax = cls();
Now, I have tried so many different ways to change the size of the figure but nothing worked...
if I run f? I some information about f, such as:
Type: Figure
String form: Figure(1000x1000)
Attributes
----------
patch
The `.Rectangle` instance representing the figure background patch.
suppressComposite
For multiple images, the figure will make composite images
depending on the renderer option_image_nocomposite function. If
*suppressComposite* is a boolean, this will override the renderer.
Init docstring:
Parameters
----------
figsize : 2-tuple of floats, default: :rc:`figure.figsize`
Figure dimension ``(width, height)`` in inches.
But I'm not sure how to modify the parameter figsize existing in f. I tried f.set_size_inches(K,L), for different values of K and L, but nothing changes.

How to find out what set_data expects

I'm trying to make an animation with matplotlib, in this case a 3D scatter plot. I'm hitting a problem that I absolutely always hit when I try to do this, which is that I don't know what arguments I should pass to set_data, and I don't know how to find out. In this case, it apparently expects two arguments, despite it being a 3d plot.
Since I've experienced related problems often, rather than asking about the specifics of the particular plot I'm trying to animate, I will ask the general question: given an element of a MatPlotLib plot, how can I determine what arguments its set_data method expects, either by interrogating it, or by knowing where it's documented?
From an example for an Animated 3D random walk from the MatPlotLib documentation:
def update_lines(num, dataLines, lines):
for line, data in zip(lines, dataLines):
# NOTE: there is no .set_data() for 3 dim data...
line.set_data(data[0:2, :num])
line.set_3d_properties(data[2, :num])
return lines
So as confusing as you discovered it is set_data by itself is not meant for 3D data, as well as according to the docs it accepts:
2D array (rows are x, y) or two 1D arrays
Looking more at this example we can see that the set_3d_properties has been used altogether.
This whole update_lines was set as a callback parameter for animation.FuncAnimation.
Usually to find the documentation you can either search it up online (e.g doc for set_data) or from a python prompt you can use the help function, which will show you the docstring of the object (can be used on a module/function/class etc) if it has any.
For example if you want to know what the datetime.datetime.now does (I dont have mathplotlib install to use it on it):
>>> import datetime
>>> help(datetime.datetime.now)
Help on built-in function now:
now(tz=None) method of builtins.type instance
Returns new datetime object representing current time local to tz.
tz
Timezone object.
If no tz is specified, uses local timezone.

python - How to get a named color in PyQt?

PyQt has a whole class (QtGui.QColor) for handling colors in several formats. This class includes a setNamedColor() method which receives a named color as defined by the SVG color keyword names provided by the World Wide Web Consortium and returns a color as an RGB value.
So, given the (pseudo)code:
my_color = QtGui.QColor()
my_color.setNamedColor("red")
one gets something like "#0000ff"
But what I want is precisely the opposite: a "getNamedColor()" function which, given a valide RGB value would return the name of the color according to the above mentioned SVG color keyword names.
A satisfactory solution would be to use the Matplotlib colors table (see here) in a handy function like that:
import matplotlib.colors as colors
def get_named_color(hex):
return colors.cnames.keys()[colors.cnames.values().index(hex)]
but just to makes things difficult, it seems that the hex codes generated by QColor() are not compatible with those in the Matplotlib color dictionary!
Is there any solution for this out there?
It turned out that the answer to my problem was pretty simple (although not immediately obvious):
QColor() hex codes are as follows: '#0000ff' whereas in Matplotlib colors dictionary all codes are in uppercase: '#0000FF'.
So, modifying the little function above to:
import matplotlib.colors as colors
def get_named_color(hex):
return colors.cnames.keys()[colors.cnames.values().index(hex.upper())]
it works fine.

Modifying viridis colormap (replacing some colors) in matplotlib

I've searched around and found things that came close to working but nothing exactly suiting what I need.
Basically, I really like the viridis colormap as a starting point. However, I would like to replace the purple at the lowest end of the map with white.
I tried using set_under() but that doesn't suite my needs.
I need to simply replace purple with white.
For example, I tried the following (from here Matplotlib discrete colorbar) -
cmap = plt.get_cmap('jet')
cmaplist = [cmap(i) for i in range(cmap.N)]
cmaplist[0] = (1.0,1.0,1.0,1.0)
cmap = cmap.from_list('Custom cmap', cmaplist, cmap.N)
Which works perfectly and does exactly what I need with 'jet' but when I replace 'jet' with 'viridis' I get the following error
AttributeError: 'ListedColormap' object has no attribute 'from_list'
How can I get around this and simply do what I want?
Any assistance at all would be greatly appreciated.
Thank you!
The from_list() method is a static method of the LinearSegmentedColormap class. It may not make too much sense to call it on an instance of the class, as you do in case of the jet map (although it does work of course).
Now, 'viridis' is implemented as a ListedColormap instead of a LinearSegmentedColormap, which implies that it does not have this method.
In any case it makes more sense to call the static method from the class itself.
import matplotlib.colors
cmap = plt.cm.viridis
cmaplist = [cmap(i) for i in range(cmap.N)]
cmaplist[0] = (1.0,1.0,1.0,1.0)
cmap = matplotlib.colors.LinearSegmentedColormap.from_list('mcm',cmaplist, cmap.N)
In this way, it will work for just any colormap, not only those which are segmented ones.

Pyplot error when calling the axis function:

I am just trying to set the axis limits with pyplot, but it seems like it is not detecting the argument of the axis function correctly, as it returns this error:
TypeError: 'list' object is not callable.
It is related to the axis function, but I can not see where the problem is. The part of my code which is giving the problem is the following:
plt.figure(1)
plt.plot(x[:,0],x[:,1])
ax=[0.0,10.0,0.0,10.0]
plt.axis(ax)
If I use x = numpy.random.randn(10,2) then the remainder of this code works with no issue, using NumPy 1.4, matplotlib 1.1.1, and Python 2.7.3. The axis function in the pyplot API accepts a list of 4 values as the first positional argument, so the usage here is correct. The error you are experiencing does not come from this piece of code.
If you provide the full details of the data you are trying to plot and the full details of the code and traceback message, perhaps we can help you.
# Works fine assuming packages are installed...
import numpy as np
import matplotlib.pyplot as plt
x = np.random.randn(10,2)
plt.figure(1)
plt.plot(x[:,0], x[:,1])
ax = [0.0, 10.0, 0.0, 10.0]
plt.axis(ax)
plt.show()
Given the error message you've posted, one possibility is that you have taken the instance of a list object (the thing called ax in your code) that was intended to serve as the boundary of an axis and confused it with the API function axis. In that case, look in your code for a place where you put the function call syntax after the variable name of ax, such as:
ax(x1, x2, y1, y2)
instead of
plt.axis(x1, x2, y1, y2)
In the first case, trying to "call" ax with some arguments will not succeed, since the Python list class does not implement the __call__ protocol, so that suffixing the function call symbols, () (potentially with arguments) after the variable name of a variable that is an instance of list will cause the error you are seeing.
Other things may cause it too, but this is my best guess given the limited info available in the question.

Categories