How do I save color mapped array of same dimensions of the original array? - matplotlib

I have data that I would like to save as png's. I need to keep the exact pixel dimensions - I don't want any inter-pixel interpolation, smoothing, or up/down sizing, etc. I do want to use a colormap, though (and mayber some other features of matplotlib's imshow). As I see it there are a couple ways I could do this:
1) Manually roll my own colormapping. (I'd rather not do this)
2) Figure out how to make sure the pixel dimenensions of the image in the figure produced by imshow are exactly correct, and then extract just the image portion of the figure for saving.
3) Use some other method which will directly give me a color mapped array (i.e. my NxN grayscale array -> NxNx3 array, using one of matplotlibs colormaps). Then save it using another png save method such as scipy.misc.imsave.
How can I do one of the above? (Or another alternate)
My problem arose when I was just saving the figure directly using savefig, and realized that I couldn't zoom into details. Upscaling wouldn't solve the problem, since the blurring between pixels is exactly one of the things I'm looking for - and the pixel size has a physical meaning.
EDIT:
Example:
import numpy as np
import matplotlib.pyplot as plt
X,Y = np.meshgrid(np.arange(-50.0,50,.1), np.arange(-50.0,50,.1))
Z = np.abs(np.sin(2*np.pi*(X**2+Y**2)**.5))/(1+(X/20)**2+(Y/20)**2)
plt.imshow(Z,cmap='inferno', interpolation='nearest')
plt.savefig('colormapeg.png')
plt.show()
Note zooming in on the interactive figure gives you a very different view then trying to zoom in on the saved figure. I could up the resolution of the saved figure - but that has it's own problems. I really just need the resolution fixed.

It seems you are looking for plt.imsave().
In this case,
plt.imsave("filename.png", Z, cmap='inferno')

Related

python numpy/scipy zoom changing center

I have a 2D numpy array, say something like:
import numpy as np
x = np.random.rand(100, 100)
Now, I want to keep zoom this image (keeping the size the same i.e. (100, 100)) and I want to change the centre of the zoom.
So, say I want to zoom keeping the point (70, 70) at the centre and normally how one would do it is to "translate" the image to that point and then zoom.
I wonder how I can achieve this with scipy. I wonder if there is way to specify say 4 coordinates from this numpy array and basically fill the canvas with the interpolated image from this region of interest?
You could use ndimage.zoom to do the zooming part. I use ndimage a lot, and it works well and is fast. https://docs.scipy.org/doc/scipy/reference/generated/scipy.ndimage.zoom.html
The 4 coordinates part you mention is I presume two corners of region you want to zoom into. That's easy by just using numpy slicing of your image (presuming your image is an np array):
your_image[r1:r2, c1:c2]
Assuming you want your output image at 100x100, then your r1-r2, and c1-c2 differences will be the same, so your region is square.
nd.zoom takes a zoom factor (float). You would need to compute whta athat zoom factor is in order to take your sliced image and turn it into a 100x100 sized array:
ndimage.zoom(your_image[r1:r2, c1:c2], zoom=your_zoom_factor)

Matplotlib multiple scatter subplots - reduce svg file size

I generated a plot in Matplotlib which consists of 50 subplots. In each of these subplots I have a scatterplot with about 3000 datapoints. I'm doing this, because I just want to have an overview of the different scatter plots in a document I'm working on.
This also works so far and looks nice, but the problem is obviously that the SVG file that I'm getting is really big (about 15 MB). And Word just can't handle such a big SVG file.
So my question: is there a way to optimize this SVG file? A lot of my datapoints in the scatter plots are overlapping each other, so I guess it should be possible remove many "invisible" ones of them without changing the visible output. (so something like this in illustrator seems to be what I want to do: Link) Is it also possible to do something like this in Inkscape? Or even directly in Matplotlib?
I know that I can just produce a PNG file, but I would prefer to have the plot as a vector graphic in my document.
If you want to keep all the data points as vector graphics, its unlikely you'll be able to reduce the file size.
While not ideal, one potential option is to rasterize only the data points created by ax.scatter, and leave the axes, labels, titles, etc. all as vector elements on your figure. This can dramatically reduce the file size, and if you set the dpi high enough, you probably won't lose any useful information from the plot.
You can do this by setting rasterized=True when calling ax.scatter.
You can then control the dpi of the rasterized elements using dpi=300 (or whatever dpi you want) when you fig.savefig.
Consider the following:
import matplotlib.pyplot as plt
figV, axesV = plt.subplots(nrows=10, ncols=5)
figR, axesR = plt.subplots(nrows=10, ncols=5)
for ax in figV.axes:
ax.scatter(range(3000), range(3000))
for ax in figR.axes:
ax.scatter(range(3000), range(3000), rasterized=True)
figV.savefig('bigscatterV.svg')
figR.savefig('bigscatterR.svg', dpi=300)
bigscatterV.svg has a file size of 16MB, while bigscatterR.svg has a file size of only 250KB.

Selecting a single color from a matplotlib colormap in Juila

I'm constructing a graph plot in Julia and need to color each edge of the graph differently, based on some weighting factor. I can't find a way to get a specific RGB (or HSV, it doesn't matter) value from a colormap. Let's say I'd like to get the RGB value on 'jet' that would correspond to a data value of n on imshow plot.
In python, I would just use jet(n), where n is the value along the colormap in which I am interested. PyPlot in Julia doesn't seem to have wrapped this functionality. I've also already tried indexing into the cmap object returned from get_cmap(). Any advice?
I'm stumped, so even an approximate solution would help. Thanks!
Maybe you can look at the Colors.jl package (https://github.com/JuliaGraphics/Colors.jl):
using Colors
palette = colormap("Oranges", 100)
Then you can access each color with palette[n]. Or are you using PyCall? A code describing what you're trying to do would help.

How can I get and set the position of a draggable legend in matplotlib

I'm trying to get and set the position of a draggable legend in matplotlib. My application consists of an interactive GUI, which has a redraw/plot function that should perform the follow steps:
save the position of the current legend.
clear the current axes and perform various plotting operations, which may or may add labels to their plots.
build a new draggable legend (ax.legend().draggable()) and restore the old position of the legend.
In between these steps the user is free to drag the legend around, and the goal is to persist the legend position when the plots are redrawn.
My first approach was to use oldpos = legend.get_bbox_to_anchor() and legend.set_bbox_to_anchor(oldpos) in steps 1 and 3. However this causes to move the legend completely off the visible area.
Note that I have to use ax.legend() and cannot use fig.legend(lines, labels), since step 2 is completely decoupled, i.e., I don't know anything about lines and labels in step 3. According to answers to the question How to position and align a matplotlib figure legend? there seems to be a difference between these two possibilities regarding axes or figure coordinates. Obviously my problem calls for figure coordinates, but I haven't fully understood how to convert the bbox to a "bbox in figure coordinates".
The even more severe problem I just realized is that apparently legend.get_bbox_to_anchor() always seems to return the same values irrespective of the drag position. So maybe the anchor can only be (ab-)used to manipulate the position of static legends? Is there another/proper way to save and restore the position of a draggable legend?
By looking at the implementation of Legend I found out that there is an undocumented property _loc, which exactly does what I want. My solution now looks astonishingly simple:
oldLegPos = ax.get_legend()._loc
# perform all plotting operations...
legend = ax.legend().draggable()
legend._loc = oldLegPos
It looks like _loc automatically stores figure coordinates, since I do not have to convert the coordinates in any way (eg. when the plotting operations completely change the axes ranges/coordinates).

Put pcolormesh and contour onto same grid?

I'm trying to display 2D data with axis labels using both contour and pcolormesh. As has been noted on the matplotlib user list, these functions obey different conventions: pcolormesh expects the x and y values to specify the corners of the individual pixels, while contour expects the centers of the pixels.
What is the best way to make these behave consistently?
One option I've considered is to make a "centers-to-edges" function, assuming evenly spaced data:
def centers_to_edges(arr):
dx = arr[1]-arr[0]
newarr = np.linspace(arr.min()-dx/2,arr.max()+dx/2,arr.size+1)
return newarr
Another option is to use imshow with the extent keyword set.
The first approach doesn't play nicely with 2D axes (e.g., as created by meshgrid or indices) and the second discards the axis numbers entirely
Your data is a regular mesh? If it doesn't, you can use griddata() to obtain it. I think that if your data is too big, a sub-sampling or regularization always is possible. If the data is too big, maybe your output image always will be small compared with it and you can exploit this.
If you use imshow() with "extent" and "interpolation='nearest'", you will see that the data is cell-centered, and extent provided the lower edges of cells (corners). On the other hand, contour assumes that the data is cell-centered, and X,Y must be the center of cells. So, you need to be care about the input domain for contour. The trivial example is:
x = np.arange(-10,10,1)
X,Y = np.meshgrid(x,x)
P = X**2+Y**2
imshow(P,extent=[-10,10,-10,10],interpolation='nearest',origin='lower')
contour(X+0.5,Y+0.5,P,20,colors='k')
My tests told me that pcolormesh() is a very slow routine, and I always try to avoid it. griddata and imshow() always is a good choose for me.