How can I make matplotlib plot rendering faster - python

I want to work with a scatter plot within a FigureCanvasQTAgg. The scatter plot may have 50,000 or more data points. The user wants to draw a polygon in the plot to select the data points within the polygon. I've realized that by setting points via mouse clicks and connect them with lines using Axis.plot(). When the user has set all points the polygon is drawn. Each time I add a new point I call FigureCanvasQTAgg.draw() to render the current version of the plot. This is slow, because the scatter plot has so much data.
Is there a way to make this faster?

Two possible solutions:
Don't show a scatter plot, but a hexbin plot instead.
Use blitting.
(In case someone wonders about the quality of this answer; mind that the questioner specifially asked for this kind of structure in the comments below the question.)

I can try to convert the scatter plot into an image using matplotlib to render it and display the image with imshow:
import matplotlib
matplotlib.use('QT4AGG')
import matplotlib.pyplot as plt
import Image # PIL
from io import BytesIO
from matplotlib import image
plt.scatter(xdata, ydata)
plt.axis('off')
plt.subplots_adjust(0, 0, 1, 1, 0, 0)
stream = BytesIO()
plt.savefig(stream, format='raw')
pilImage = Image.fromstring('RGBA',size=(640, 480), data = stream.getvalue())
plt.imshow(image.pil_to_array(pilImage))

Related

Image artefacts when using cyclic colormaps for periodic data

I am currently trying to visualize the phase of an electromagnetic field which is 2pi-periodic. To visualize that e.g. 1.9 pi is almost the same as 0, I am using a cyclic colormap (twilight). However, when I plot my images, there are always lines at the sections where the phase jumps from (almost) 2pi to 0. When you zoom in on these lines, these artefacts vanish.
Here is a simple script and example images that demonstrate this issue.
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(-3,3,501)
x,y = np.meshgrid(x,x)
data = x**2+y**2
data = np.mod(data, 2)
plt.set_cmap('twilight')
plt.imshow(data)
plt.show()
I tested it with "twilight_shifted" and "hsv" as well and got the same issue. The problem also occurs after saving the image via plt.savefig(). I also tried other image formats like svg but it did not change anything.
As suggested in this answer you can set the image interpolation to "nearest", e.g.,
plt.imshow(data, interpolation="nearest")
See here for a discussion of image antialiasing effects with different interpolation methods.

How to draw a Heatmap in a image using the coordinates in Python OpenCV?

I've a huge list of Coordinates(x,y) of people walking in the streets and I like to design a heatmap using those Coordinates(x,y), i.e., it should look something like this. I want much hotter spot for multiple coordinates in a single spot, hotter means red colored spot. I've tried this but ended up getting a heatmap like this not the one I expected nor the site mentioned in the beginning(the wikipedia heatmap). This is the code I tried,
import cv2
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
x,y = [230,150,200],[200,100,150]
plt.imshow(img)
ax = sns.kdeplot(x,y, cmap = "Blues", shade= True, shade_lowest=False)
ax.set_frame_on(False)
plt.axis('off')
plt.savefig('heatmap_pic.png')
This code also made the result image size smaller the actual image was much bigger. I'm new to OpenCV and Matplotlib someone please help me with this, to plot a Heatmap(like this) in a image using a bunch of Coordinates.
You need to take image, create the heatmap, and superimpose it.
Check this or this.

project numpy array to aitoff projection

I have an (as yet incomplete) image of the whole sky. In order to display it properly it needs to be projected onto an ellipse (specifically an Aitoff projection).
I have tried various versions of this:
plt.subplot(111, projection="aitoff")
plt.imshow(image, vmin=0.004, vmax=0.01, extent=[0,360,-90,90])
plt.show()
...and have tried changing the values in the extent kwarg to radians, as well as using pcolor or pcolormesh instead of imshow.
These have given me: an empty Aitoff plot, various Aitoff plots with all or part of my image sitting inside it, but not filling it, or an Aitoff plot with a small part of my image (one or two pixels by the looks of things) completely filling it.
My whole image sitting within a plot
The unprojected image
I also do not have access to things like Basemap or astroproj as I'm using a machine owned by my university.
Edit: As was pointed out by another user the above example is not Minimal, Complete, and Verifiable. Below is a version which should be:
A=np.random.rand(180,360)
plt.imshow(A)
plt.show()
plt.subplot(111, projection="aitoff")
plt.pcolormesh(A)
plt.show()
I want the entire image generated in the plt.imshow() command to be projected in the Aitoff figure. Instead only a few pixels are. Any ideas?
Thanks!
Using imshow in non-rectilinear projections will mostly fail. But instead pcolormesh may be used.
The aitoff projection ranges from -π to π in horizontal and from -π/2 to π/2 in vertical direction. This is the range of values to use when plotting the pcolormesh plot.
import numpy as np
import matplotlib.pyplot as plt
im = plt.imread("house.jpg")
x = np.linspace(-np.pi,np.pi,im.shape[1])
y = np.linspace(-np.pi/2,np.pi/2,im.shape[0])
X,Y = np.meshgrid(x,y)
plt.subplot(111, projection="aitoff")
plt.pcolormesh(X,Y[::-1],im[:,:,2])
plt.show()

Vector graphics + matplotlib pcolorfast

To keep it short: Is there a way to export plots created with methods like
pcolorfast which basically draw pixels as "real" vector graphics?
I tried to do just that using savefig and saving to a PDF but what would happen is that the plot was actually a vector graphic but the parts drawn by pcolorfast(so basically, what is inside the axes) something like a bitmap. - I checked this using Inkscape.
This resulted in really low resolution plots even though the arrays drawn with pcolorfast where about 3000x4000. I achieved higher resolution by increasing the dpi when exporting, but I'd really appreciate a conversion to a real vector graphic.
Edit: I updated my original code by the piece of code below that should serve to illustrate what exactly I am doing. I tried to involucrate the rasterized tip, but it has had no effect. I still end up with a supersmall PDF-file where the plots are acually raster images (png). I am going to provide you with the data I used and the resulting PDF.
http://www.megafileupload.com/k5ku/test_array1.txt
http://www.megafileupload.com/k5kv/test_array2.txt
http://www.megafileupload.com/k5kw/test.pdf
import numpy as np
import matplotlib.pyplot as plt
arr1= np.loadtxt("test_array1.txt")
arr2= np.loadtxt("test_array2.txt")
fig, (ax1, ax2)=plt.subplots(1, 2)
ax1.set_rasterized(False)
ax1.pcolorfast(arr1)
ax2.pcolorfast(arr2, rasterized=False)
plt.show()
fig.set_rasterized(False)
fig.savefig("test.pdf")

Image plotted from a FITS file with matplotlib oriented incorrectly

I'm having a little issue with something regarding plotting a fits image using matplotlib's imshow. It seems that my image is flipped both horizontally and vertically. I'm sure there is something simple I am overlooking, if anyone could point me in the right direction that would be great.
This is what my image should look like:
So, I'm loading my image as:
from astropy.io import fits
import matplotlib
import matplotlib.pyplot as pyplot
#Opening/reading in my fits file
hdulist = fits.open('.../myfits.fits')
#Accessing the image data and specifying the dimensions I wish to use
my_image = hdulist[0].data[0,0:,0:]
#Plotting the image
pyplot.imshow(image_SWIFT_uvm2_plot, cmap='gray', vmin=0, vmax=0.5)
pyplot.show()
This is what my image in the plot looks like (the plot is a little more complex than the code I have included, but I have given the critical lines as, hopefully, a self-sufficient code):
Those of you with keen eyes should see that the image has flipped both horizontally and vertically.
For FITS files the convention is that the origin is at the lower left hand corner of the image, so you need to use origin='lower' (by default Matplotlib uses origin='upper').
I have never used the astropy module, but I know that PyFITS opens the image data as a NumPy array (and from what I'm reading, astropy.io.fits has inherited the functionality of PyFITS anyway, so it should work the same way). If that is the case, then you may use numpy.fliplr and numpy.flipud to flip the array to your desired orientation. Just replace the line
pyplot.imshow(image_SWIFT_uvm2_plot, cmap='gray', vmin=0, vmax=0.5)
with
import numpy as np
pyplot.imshow(np.fliplr(np.flipud(image_SWIFT_uvm2_plot)), cmap='gray',
vmin=0, vmax=0.5)
Alternatively, you could do a little linear algebra to flip it, or just note that performing both of these flips is the same as using np.rot90 twice
pyplot.imshow(np.rot90(image_SWIFT_uvm2_plot, k=2), cmap='gray', vmin=0, vmax=0)

Categories

Resources