Overlay Plot on png image using Matplotlib. Python 2.7 - python

Configuration:
MOXA Debian 9, using Python 2.7 latest version (The software is written in Python2.7) with Matplotlib 2.2.5. The program is not in service anymore, but still works great.
Question:
I want to overlay a generated plot, on top of an png image using matplotlib. This would generate final image
Situation:
The program measures the sky brightness using a sensor and with that data it generates a plot. This every 5 minutes. The plot.py script file is used to build a plot.
I use to just overlay the plot on top of the image at the end of the night using Imagemagick overlay line with a small sh script. But as the program updates the plot every 5 minutes at night, i want to be able to already overlay the plot on top of the image, if possible using matplotlib inside the plot.py script. The plot and the image are both png.
Is this possible? I have investigated this a bit, and i think i need to add some code between line
print('Ploting photometer data ...')
if (input_filename is None):
input_filename = config.current_data_directory+\
'/'+config._device_shorttype+'_'+config._observatory_name+'.dat'
# Define the observatory in ephem
Ephem = Ephemerids()
# Get and process the data from input_filename
NSBData = SQMData(input_filename,Ephem)
# Moon and twilight ephemerids.
Ephem.calculate_moon_ephems(thedate=NSBData.Night)
Ephem.calculate_twilight(thedate=NSBData.Night)
Ephem.calculate_observation(thedate=NSBData.Night)
# Calculate data statistics
NSBData.data_statistics(Ephem)
# Write statiscs to file?
if write_stats==True:
save_stats_to_file(NSBData.Night,NSBData,Ephem)
# Plot the data and save the resulting figure
NSBPlot = Plot(NSBData,Ephem)
Above is the plot generated, and here i think i would need to overlay it before it will be saved as quoted below.
output_filenames = [\
str("%s/%s_%s.png" %(config.current_data_directory,\
config._device_shorttype,config._observatory_name)),\
str("%s/%s_120000_%s-%s.png" \
%(config.daily_graph_directory, str(NSBData.Night).replace('-',''),\
config._device_shorttype, config._observatory_name))\
]
for output_filename in output_filenames:
NSBPlot.save_figure(output_filename)
Is this correct, and how do i do this?
I have found some information: test.png would then be ofcourse the destination location of the image.png. But to be honest, do not know where to start and how to interpreted it.I have read error's of people using plt.show() in the end, but that freezes the system, so i do not need that line.
import matplotlib.pyplot as plt
im = plt.imread('test.png')
implot = plt.imshow(im)
plt.plot([100,200,300],[200,150,200],'o')
Thank you in advance.

Related

Image not updating in python plot during animation

The Problem:
I'm trying to simulate a live video by cycling through a series of still images I have saved in a directory, but when I add the animation and update functions my plot is displayed empty.
Background on why I'm doing this:
I believe its important for me to do it this way rather than a complete change of approach, say turning the images into a video first then displaying that, because what I really want to test is the image analysis I will be adding and then overlaying on each frame. The final application will be receiving frames one by one from a camera and will need to do some processing, display the image + annotations + output the data as .csv etc... I'm simulating this for now because I do not have any of the hardware to generate the images and will not have it for several months during which time I need to get the image processing set up, but I do have access to some sets of stills that are approximately what will be produced. In case its relevant my simulation images are 1680x1220 and are 1.88 Mb TIFFs, though I could covert and compress them if needed, and in the final form the resolution will be a bit higher and probably the image format could be adjusted if needed.
What I have tried:
I followed an example to list all files in a folder, and an example
to update a plot. However, the plot displays blank when I run the
code.
I added a line to print the current file name, and I can see this
cycling as expected.
I also made sure the images will display in the plot if I just create
a plot and add one image, and they do. But, when combined with the
animation function the plot is blank and I'm not sure what I've done
wrong/failed to include.
I also tried adding a plt.pause() in the update, but again this
didn't work.
I increased the interval up to 2000 to give it more time, but that didn't work. I believe 2000 is extreme, I'm expecting it should work with more like 20-30fps. Going to 0.5fps tells me the code is wrong or incomplete, rather than it just being a question of needing time to read the image file.
I appreciate no one else has my images, but they are nothing special. I'm using 60 images but I guess it could be tested with any 2 random images and setting range(60) to range(2) instead?
The example I copied originally demonstrated the animation function by making a random array, and if I do that it will show a plot that updates with random squares as expected.
Replacing:
A = np.random.randn(10,10)
im.set_array(A)
...with my image instead...
im = cv2.imread(files[i],0)
...and the plot remains empty/blank. I get a window shown called "Figure1" (like when using the random array), but unlike with the array there is nothing in this window.
Full code:
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import os
import cv2
def update(i):
im = cv2.imread(files[i],0)
print(files[i])
#plt.pause(0.1)
return im
path = 'C:\\Test Images\\'
files = []
# r=root, d=directories, f = files
for r, d, f in os.walk(path):
for file in f:
if '.TIFF' in file:
files.append(os.path.join(r, file))
ani = FuncAnimation(plt.gcf(), update, frames=range(60), interval=50, blit=False)
plt.show()
I'm a python and a programming novice so have relied on adjusting examples others have given online but I have only a simplistic understanding of how they are working and end up with a lot of trial and error on the syntax. I just can't figure out anything to make this one work though.
Cheers for any help!
The main reason nothing is showing up is because you never add the images to the plot. I've provided some code below to do what you want, be sure to look up anything you are curious about or don't understand!
import glob
import os
from matplotlib import animation
import matplotlib.image as mpimg
import matplotlib.pyplot as plt
IMG_DIRPATH = 'C:\\Test Images\\' # the folder with your images (be careful about
# putting spaces in directory names!)
IMG_EXT = '.TIFF' # the file extension of your images
# Create a figure, and set to the desired size.
fig = plt.figure(figsize=[5, 5])
# Create axes for the current figure so that images can be sized appropriately.
# Passing in [0, 0, 1, 1] makes the axes fill the whole figure.
# frame_on=False means we won't have a bounding box, and setting xticks=[] and
# yticks=[] means that we won't have pesky tick marks along our image.
ax_props = {'frame_on': False, 'xticks': [], 'yticks': []}
ax = plt.axes([0, 0, 1, 1], **ax_props)
# Get all image filenames.
img_filepaths = glob.glob(os.path.join(IMG_DIRPATH, '*' + IMG_EXT))
def update_image(img_filepath):
# Remove all existing images on the axes, and restore our settings.
ax.clear()
ax.update(ax_props)
# Read the current image.
img = mpimg.imread(img_filepath)
# Add the current image to the plot axes.
ax.imshow(img)
anim = animation.FuncAnimation(fig, update_image, frames=img_filepaths, interval=250)
plt.show()

Can't make MatPlotLib display mid-function

I am writing a programme to input data into a JSON database. Part of this is:
displaying an image (file name entered by user)
asking for coordinates of interest (entered by user)
re-displaying cropped image using those coordinates
asking for tags for this cropped segment (entered by user)
saving tags & coordinates in the JSON database
This same process was used for text files but now that I am doing images I am having the problem that when my programme calls the function:
img = mpimg.imread("raw_data" + system_slash + "images" + system_slash + database[i]['image_file'])
plot.imshow(img)
it does not display the image immediately, but instead only after the whole programme completes. Could anyone suggest a different call to make it display in line, like a print function for text?
*the system slash is a quick and dirty fix for me and my colleague using both PC and MAC file systems when using the programme, so either / or \
After the plotting command, you should put matplotlib.pyplot.pause(t), where t is the time you want to pause. The interval t is in seconds, so if you want for example an animation with roughly 60fps, you could set t=1/60.
The function updates the figure and displays it for t seconds.
EDIT What also came to my mind is: Don't call plt.imshow repeatedly. This is very slow. Better call it once and then just set the data. Little demo:
import matplotlib.pyplot as plt
import numpy as np
im = plt.imshow(np.random.rand(10,10))
while True:
im.set_data(np.random.rand(10,10))
plt.pause(1/10)

displaying charts from python executables in shell

I'm using python 2.7 on Ubuntu to draw charts from text files containing data.
My point is, when using python executables in shell, I have no problem recording plots, but if I want them shown on my screen instead I have to go through the graphic interface. If possible, I would very much like to skip that part and get a dynamic display that I can interact with (as if I were to run my script from a python shell)!!
a MWE of what i'm doing is :
MWE
import numpy as np
import matplotlib.pyplot as plt
with open('filename','r') as myfile:
DATA = np.genfromtxt(myfile,unpack=True)
fig = plt.figure()
... my plot configuration ...
plt.savefig("image_name"+'.png')
plt.close()
end of MWE
Using this script image_name.png appears in my repertory. I tried replacing the last 2 lines with plt.plot() and plt.draw() but nothing happened.
Many thanks!
Michel
(edited)

Custom Artist In Matplotlib Legend

I have a program using PtQt that utilizes matplotlib to do some plot rendering. For saving images, I would like to make use of the legend to render a custom image (additionally the built-in draggable feature makes this very appealing). I'm reading up on the legend, but I can't seem to figure out how to make a legend that calls my own paintEvent() method for Qt in which I can render custom images.
In case this approach is terrible, here's my goal: I want to put a image (rendered inside the program by Qt) either inside the plot window or find a way to append this image on top of the exported figure.
Here's a screenshot of what the output looks like now:
I'd like to take the DAIP... sequence at the top and have that exported with the figure.
Hopefully someone has tackled a similar problem before.
I solved it by using the OffsetImage and AnnotationBBox features of matplotlib after saving the image to a temporary png file. For some reason keeping it as a temporary file didn't work well.
Briefly:
#draw stuff onto QPixmap named pix
byteArray = QByteArray()
buffer = QBuffer(byteArray)
buffer.open(QIODevice.WriteOnly)
pix.save(buffer, 'PNG')
stringIO = StringIO(byteArray)
stringIO.seek(0)
tfile = tempfile.NamedTemporaryFile(suffix=".png", mode="wb", delete=False)
tfile.write(stringIO.buf)
tfile.close()
imagebox = mpl.offsetbox.OffsetImage(mpl._png.read_png(tfile.name),zoom=zlvl)
ab = mpl.offsetbox.AnnotationBbox(imagebox, [w/2,0],frameon=False)
ab.set_figure(self.canvas.figure)
ab.draggable()
self.subplot.axes.add_artist(ab)
os.remove(tfile.name)

How do I print a PDF file to a printer in landscape from Python?

I'm using Mac OSX but I need a platform independent method to print a pdf file.
I created a graph in Matplotlib and want to print it to my printer.
I can set the orientation of the canvas to fit a portrait layout with:
fig.set_size_inches( 8.27,11.69) # set the figure size in inches
but using:
fig.set_size_inches( 11.69, 8.27)
prints a cropped portrait oriented figure
I found this on another post here:
import subprocess
import shlex
printfile='test.pdf'
fig.savefig(printfile)
proc=subprocess.Popen(shlex.split('lpr {f}'.format(f=printfile)))
Can anyone help me with the format of the code to set the print orientation to landscape?
I have seen lpr -o landscape, but do not have enough experience with it to know if it works for all printers.
Rather than changing orientation while printing, you can do it when generating the image (if it fits with your workflow). The matplotlib savefig command allows you to specify saving in landscape orientation, but currently only for postscript. That is not a problem, however, since we can easily convert the postscript file to PDF format. Below is an example.
In Python:
from pylab import *
import numpy as np
x = np.arange(0, 10, 0.1)
y = np.sin(x)
plot(x, y)
xlabel('x')
ylabel('y')
savefig('img.eps', orientation='landscape')
I left out the canvas size for convenience and brevity.
Now we have a file named img.eps. In the shell do the following.
epstopdf img.eps
Here is what the resulting img.pdf file looks like:
One downside to keep in mind with this approach is that postscript does not like transparency, so if you want transparency this is not the approach for you. To see what I mean take the matplotlib patch_collection.py example. Replace the pylab.show() on the last line with pylab.savefig('patch.pdf'), run it, and then look at the resulting PDF file. It will look like the image in the example. If, however, you do pylab.savefig('patch.eps'), you will see that the objects are all opaque.

Categories

Resources