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.
I'm new to python and programing and I'm trying to make a code to display an image with some data from a .fits file. I'm first trying to make this example I found from this site: https://docs.astropy.org/en/stable/generated/examples/io/plot_fits-image.html#sphx-glr-download-generated-examples-io-plot-fits-image-py. When I run it, it shows everything it should, except the figure, which is the most important part. How do I make the figure show up?
The code is the following:
import matplotlib.pyplot as plt
from astropy.visualization import astropy_mpl_style
plt.style.use(astropy_mpl_style)
from astropy.utils.data import get_pkg_data_filename
from astropy.io import fits
image_file = get_pkg_data_filename('tutorials/FITS-images/HorseHead.fits')
fits.info(image_file)
image_data = fits.getdata(image_file, ext=0)
print(image_data.shape)
plt.figure()
plt.imshow(image_data, cmap='gray')
plt.colorbar()
Appending plt.show() at the end of your code should work ...
I ignored the fact that the figure was not showing up in the example and went straight to my .fits file. With that file the figure worked fine. Turns out there was probably something wrong with the example file.
A few days ago, I need to draw a plot by using matplotlib, since it could not display the font properly, so I
edited matplotlibrc file, unhashtag "font.family" and "font.serif".
added specific font file to ttf.
deleted .matplotlib file.
Then I code:
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['Microsoft JhengHei']
plt.rcParams['axes.unicode_minus'] = False
Now when I tried to use "to_csv" to write the dataframe into csv, there's a
unicode problem. It ran without problem before. So I changed those 3 steps back and still have a unicode problem.
Not sure if there's any problem of my setting.
In matplotlib, one can easily use latex script to label axes, or write legends or any other text. But is there a way to use new fonts such as 'script-r' in matplotlib? In the following code, I am labelling the axes using latex fonts.
import numpy as np
import matplotlib.pyplot as plt
tmax=10
h=0.01
number_of_realizations=6
for n in range(number_of_realizations):
xpos1=0
xvel1=0
xlist=[]
tlist=[]
t=0
while t<tmax:
xlist.append(xpos1)
tlist.append(t)
xvel1=np.random.normal(loc=0.0, scale=1.0, size=None)
xpos2=xpos1+(h**0.5)*xvel1 # update position at time t
xpos1=xpos2
t=t+h
plt.plot(tlist, xlist)
plt.xlabel(r'$ t$', fontsize=50)
plt.ylabel(r'$r$', fontsize=50)
plt.title('Brownian motion', fontsize=20)
plt.show()
It produces the following figure
But I want 'script-r' in place of normal 'r'.
In latex one has to add the following lines in preamble to render 'script-r'
\DeclareFontFamily{T1}{calligra}{}
\DeclareFontShape{T1}{calligra}{m}{n}{<->s*[2.2]callig15}{}
\DeclareRobustCommand{\sr}{%
\mspace{-2mu}%
\text{\usefont{T1}{calligra}{m}{n}r\/}%
\mspace{2mu}%
}
I don't understand how to do this in matplotlib. Any help is appreciated.
Matplotlib uses it's own hand-rolled (pure Python) implementation of TeX to do all of the math text stuff, so you absolutely cannot assume that what works in standard LaTeX will work with Matplotlib. That being said, here's how you do it:
Install the calligra font so that Matplotlib can see it, then rebuild the font cache.
Lots of other threads deal with how to do this, I'm not going to go into detail, but here's some reference:
Use a font installed in a random spot on your filesystem.
How to install a new font into the Matplotlib managed font cache.
List all fonts currently known to your install of Matplotlib.
Replace one of Matplotlib's TeX font families with your font of choice.
Here's a function I wrote a while ago that reliably does that:
import matplotlib
def setMathtextFont(fontName='Helvetica', texFontFamilies=None):
texFontFamilies = ['it','rm','tt','bf','cal','sf'] if texFontFamilies is None else texFontFamilies
matplotlib.rcParams.update({'mathtext.fontset': 'custom'})
for texFontFamily in texFontFamilies:
matplotlib.rcParams.update({('mathtext.%s' % texFontFamily): fontName})
For you, a good way to use the function would be to replace the font used by \mathcal with calligra:
setMathtextFont('calligra', ['cal'])
Label your plots, for example, r'$\mathcal{foo}$', and the contents of the \math<whatever> macro should show up in the desired font.
Here's how you'd change your label-making code:
plt.ylabel(r'$\mathcal{r}$', fontsize=50)
and that should do it.
Is there a way to save a Matplotlib figure such that it can be re-opened and have typical interaction restored? (Like the .fig format in MATLAB?)
I find myself running the same scripts many times to generate these interactive figures. Or I'm sending my colleagues multiple static PNG files to show different aspects of a plot. I'd rather send the figure object and have them interact with it themselves.
I just found out how to do this. The "experimental pickle support" mentioned by #pelson works quite well.
Try this:
# Plot something
import matplotlib.pyplot as plt
fig,ax = plt.subplots()
ax.plot([1,2,3],[10,-10,30])
After your interactive tweaking, save the figure object as a binary file:
import pickle
pickle.dump(fig, open('FigureObject.fig.pickle', 'wb')) # This is for Python 3 - py2 may need `file` instead of `open`
Later, open the figure and the tweaks should be saved and GUI interactivity should be present:
import pickle
figx = pickle.load(open('FigureObject.fig.pickle', 'rb'))
figx.show() # Show the figure, edit it, etc.!
You can even extract the data from the plots:
data = figx.axes[0].lines[0].get_data()
(It works for lines, pcolor & imshow - pcolormesh works with some tricks to reconstruct the flattened data.)
I got the excellent tip from Saving Matplotlib Figures Using Pickle.
As of Matplotlib 1.2, we now have experimental pickle support. Give that a go and see if it works well for your case. If you have any issues, please let us know on the Matplotlib mailing list or by opening an issue on github.com/matplotlib/matplotlib.
This would be a great feature, but AFAIK it isn't implemented in Matplotlib and likely would be difficult to implement yourself due to the way figures are stored.
I'd suggest either (a) separate processing the data from generating the figure (which saves data with a unique name) and write a figure generating script (loading a specified file of the saved data) and editing as you see fit or (b) save as PDF/SVG/PostScript format and edit in some fancy figure editor like Adobe Illustrator (or Inkscape).
EDIT post Fall 2012: As others pointed out below (though mentioning here as this is the accepted answer), Matplotlib since version 1.2 allowed you to pickle figures. As the release notes state, it is an experimental feature and does not support saving a figure in one matplotlib version and opening in another. It's also generally unsecure to restore a pickle from an untrusted source.
For sharing/later editing plots (that require significant data processing first and may need to be tweaked months later say during peer review for a scientific publication), I still recommend the workflow of (1) have a data processing script that before generating a plot saves the processed data (that goes into your plot) into a file, and (2) have a separate plot generation script (that you adjust as necessary) to recreate the plot. This way for each plot you can quickly run a script and re-generate it (and quickly copy over your plot settings with new data). That said, pickling a figure could be convenient for short term/interactive/exploratory data analysis.
Why not just send the Python script? MATLAB's .fig files require the recipient to have MATLAB to display them, so that's about equivalent to sending a Python script that requires Matplotlib to display.
Alternatively (disclaimer: I haven't tried this yet), you could try pickling the figure:
import pickle
output = open('interactive figure.pickle', 'wb')
pickle.dump(gcf(), output)
output.close()
Good question. Here is the doc text from pylab.save:
pylab no longer provides a save function, though the old pylab
function is still available as matplotlib.mlab.save (you can still
refer to it in pylab as "mlab.save"). However, for plain text
files, we recommend numpy.savetxt. For saving numpy arrays,
we recommend numpy.save, and its analog numpy.load, which are
available in pylab as np.save and np.load.
I figured out a relatively simple way (yet slightly unconventional) to save my matplotlib figures. It works like this:
import libscript
import matplotlib.pyplot as plt
import numpy as np
t = np.arange(0.0, 2.0, 0.01)
s = 1 + np.sin(2*np.pi*t)
#<plot>
plt.plot(t, s)
plt.xlabel('time (s)')
plt.ylabel('voltage (mV)')
plt.title('About as simple as it gets, folks')
plt.grid(True)
plt.show()
#</plot>
save_plot(fileName='plot_01.py',obj=sys.argv[0],sel='plot',ctx=libscript.get_ctx(ctx_global=globals(),ctx_local=locals()))
with function save_plot defined like this (simple version to understand the logic):
def save_plot(fileName='',obj=None,sel='',ctx={}):
"""
Save of matplolib plot to a stand alone python script containing all the data and configuration instructions to regenerate the interactive matplotlib figure.
Parameters
----------
fileName : [string] Path of the python script file to be created.
obj : [object] Function or python object containing the lines of code to create and configure the plot to be saved.
sel : [string] Name of the tag enclosing the lines of code to create and configure the plot to be saved.
ctx : [dict] Dictionary containing the execution context. Values for variables not defined in the lines of code for the plot will be fetched from the context.
Returns
-------
Return ``'done'`` once the plot has been saved to a python script file. This file contains all the input data and configuration to re-create the original interactive matplotlib figure.
"""
import os
import libscript
N_indent=4
src=libscript.get_src(obj=obj,sel=sel)
src=libscript.prepend_ctx(src=src,ctx=ctx,debug=False)
src='\n'.join([' '*N_indent+line for line in src.split('\n')])
if(os.path.isfile(fileName)): os.remove(fileName)
with open(fileName,'w') as f:
f.write('import sys\n')
f.write('sys.dont_write_bytecode=True\n')
f.write('def main():\n')
f.write(src+'\n')
f.write('if(__name__=="__main__"):\n')
f.write(' '*N_indent+'main()\n')
return 'done'
or defining function save_plot like this (better version using zip compression to produce lighter figure files):
def save_plot(fileName='',obj=None,sel='',ctx={}):
import os
import json
import zlib
import base64
import libscript
N_indent=4
level=9#0 to 9, default: 6
src=libscript.get_src(obj=obj,sel=sel)
obj=libscript.load_obj(src=src,ctx=ctx,debug=False)
bin=base64.b64encode(zlib.compress(json.dumps(obj),level))
if(os.path.isfile(fileName)): os.remove(fileName)
with open(fileName,'w') as f:
f.write('import sys\n')
f.write('sys.dont_write_bytecode=True\n')
f.write('def main():\n')
f.write(' '*N_indent+'import base64\n')
f.write(' '*N_indent+'import zlib\n')
f.write(' '*N_indent+'import json\n')
f.write(' '*N_indent+'import libscript\n')
f.write(' '*N_indent+'bin="'+str(bin)+'"\n')
f.write(' '*N_indent+'obj=json.loads(zlib.decompress(base64.b64decode(bin)))\n')
f.write(' '*N_indent+'libscript.exec_obj(obj=obj,tempfile=False)\n')
f.write('if(__name__=="__main__"):\n')
f.write(' '*N_indent+'main()\n')
return 'done'
This makes use a module libscript of my own, which mostly relies on modules inspect and ast. I can try to share it on Github if interest is expressed (it would first require some cleanup and me to get started with Github).
The idea behind this save_plot function and libscript module is to fetch the python instructions that create the figure (using module inspect), analyze them (using module ast) to extract all variables, functions and modules import it relies on, extract these from the execution context and serialize them as python instructions (code for variables will be like t=[0.0,2.0,0.01] ... and code for modules will be like import matplotlib.pyplot as plt ...) prepended to the figure instructions. The resulting python instructions are saved as a python script whose execution will re-build the original matplotlib figure.
As you can imagine, this works well for most (if not all) matplotlib figures.
If you are looking to save python plots as an interactive figure to modify and share with others like MATLAB .fig file then you can try to use the following code. Here z_data.values is just a numpy ndarray and so you can use the same code to plot and save your own data. No need of using pandas then.
The file generated here can be opened and interactively modified by anyone with or without python just by clicking on it and opening in browsers like Chrome/Firefox/Edge etc.
import plotly.graph_objects as go
import pandas as pd
z_data=pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/api_docs/mt_bruno_elevation.csv')
fig = go.Figure(data=[go.Surface(z=z_data.values)])
fig.update_layout(title='Mt Bruno Elevation', autosize=False,
width=500, height=500,
margin=dict(l=65, r=50, b=65, t=90))
fig.show()
fig.write_html("testfile.html")