Julia pyplot from script (not interactive) - matplotlib

I just installed PyPlot in Julia. It's working fine when I run it from julia's interactive environment. But when I make a .jl script an run from bash the plot graphics does not displays.
I'm familiear with matplotlib (pylab) where show() command is used to view the figures. I probably don't undestand the readme of PyPlot here https://github.com/stevengj/PyPlot.jl
You can get the current figure as a Figure object (a wrapper around
matplotlib.pyplot.Figure) by calling gcf(). The Figure type supports
Julia's multimedia I/O API, so you can use display(fig) to show a
fig::PyFigure
If I run this script:
using PyPlot
x = linspace(0,2*pi,1000); y = sin(3*x + 4*cos(2*x));
plot(x, y, color="red", linewidth=2.0, linestyle="--")
title("A sinusoidally modulated sinusoid")
fig1 = gcf()
display(fig1)
I get no graphics on the screen, just text output with address of the figure object
$ julia pyplottest.jl
Loading help data...
Figure(PyObject <matplotlib.figure.Figure object at 0x761dd10>)
I'm also not sure why it take so long time and what "Loading help data..." does mean
if I run the same script from inside of Julia evironment using include("pyplottest.jl") the plot does shows fine

display only works if you are running an environment that supports graphical I/O, like IJulia, but even there you don't really need to call it directly (the plot is displayed automatically when an IJulia cell finishes executing).
You can do show() just like in Python. However, PyPlot loads Matplotlib in interactive mode, with the GUI event loop running in the background, so show() is non-blocking and doesn't really do anything. One option is to just do
using PyPlot
x = linspace(0,2*pi,1000); y = sin(3*x + 4*cos(2*x));
plot(x, y, color="red", linewidth=2.0, linestyle="--")
title("A sinusoidally modulated sinusoid")
print("Hit <enter> to continue")
readline()
to pause.
If you just want to do non-interactive Matplotlib, you don't need the PyPlot package at all. You can just do:
using PyCall
#pyimport matplotlib.pyplot as plt
x = linspace(0,2*pi,1000); y = sin(3*x + 4*cos(2*x));
plt.plot(x, y, color="red", linewidth=2.0, linestyle="--")
plt.title("A sinusoidally modulated sinusoid")
plt.show()
and the show() command will block until the user closes the plot window.
(Possibly I should add an option to PyPlot to load it in non-interactive mode.)

If you are not in REPL or interactive mode (i.e. using sublime like me) then you have to add plt[:show]() to see the plot.
I asked the same question a while ago:
https://groups.google.com/forum/#!topic/julia-users/A2JbZMvMJhY

Related

matplotlib chart construction to suit use flask? (working example uses matplotlib.figure FigureCanvasAgg) can I construct errorbars?

I have a matplotlib chart working nicely as a python script. I need to create this chart style in flask. Can't use this method within flask as flask thread management doesn't play with matplotlib.
Oddly, the current method will run once successfully, subsequent runs will produce this error.
RuntimeError: main thread is not in main loop
So this is my desired chart format to produce in flask.
the code I'm using currently.
fig, ax = plt.subplots()
fig.subplots_adjust(bottom=0.29, top=.91)
ax.set_title(title)
ax.set_ylabel("y label text")
ax.set_xlabel('x label text')
ax.tick_params(axis='x', labelrotation = -80)
l = ax.plot(df_output['column1'])
y_error = df_output['column2']
plt.errorbar(list(df_output.index), \
list(df_output['column1']), \
yerr = y_error,fmt='o',ecolor = 'blue',color='blue')
fig.legend(l, loc=8, labels=labels)
#loc=2 = top left corner, loc=8 = 'lower center'
#plt.show()
plt.savefig(output_path+"/"+title+'_errorbars.png')
I found this example that works with flask
https://gist.github.com/illume/1f19a2cf9f26425b1761b63d9506331f
it uses this matplotlib charting syntax. Need to convert my old matplotlib format to suit the flask compatible format. Is this chart format possible via FigureCanvasAgg?
fig = Figure()
axis = fig.add_subplot(1, 1, 1)
print("type(axis):", type(axis))
x_points = data.iloc[:, 0]
y_points = data['mean minus sterility control mean']
axis.plot(x_points, y_points)
output = io.BytesIO()
FigureCanvasAgg(fig).print_png(output)
return Response(output.getvalue(), mimetype="image/png")
I'll admit to not being strong in building matpotlib charts. changing between chart building methods throws me.
I'm digging around the docs at moment.
https://matplotlib.org/stable/gallery/user_interfaces/canvasagg.html
I did find this Q&A (RuntimeError: main thread is not in main loop with Matplotlib and Flask)
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
while this appears to run for me. I want to move away from creating charts as files on the server, too much potential for file mismanagement, creating the chart as a io.BytesIO() output (or some format within the flask http response to user) is a much better solution.
(I'd like to keep at an image output, rather than change architecture to (say) a json output and constructing chart in client using javascript libraries)

Turning off specgram auto-plotting in Jupyter notebook

I'm using Matplotlib's specgram function, which has a form like:
Pxx, freqs, bins, im = specgram(x, NFFT=NFFT, Fs=Fs, noverlap=900)
where Pxx, freqs, bins, and im represent the periodogram, frequency vector, center of time bins, and the image.AxesImage instance. Additionally, you can feed in arguments (**kwargs) that get passed onto imshow.
I cannot seem to use specgram in a Jupyter Notebook, without producing a plot automatically. What argument can I pass into specgram that will stop it from plotting automatically?
I am not calling any plt.show() command. I've tried adding a semi-colon at the end of the line, and I've tried setting the final argument (im) as nothing, like this:
Pxx, freqs, bins, _ = specgram(x, NFFT=NFFT, Fs=Fs, noverlap=900);
but nothing seems to work.
From the PyPlot.jl docs: https://github.com/JuliaPy/PyPlot.jl#non-interactive-plotting
If you use PyPlot from an interactive Julia prompt, such as the Julia command-line prompt or an IJulia notebook, then plots appear immediately after a plotting function (plot etc.) is evaluated.
However, if you use PyPlot from a Julia script that is run
non-interactively (e.g. julia myscript.jl), then Matplotlib is
executed in non-interactive mode: a plot window is not opened until
you run show() (equivalent to plt.show() in the Python examples).
See the docs linked above for further reference.

why are my matplotlib plots come out as png's only and not as Matlab figures?

i use a piece of code to produce figures as i run in Pycharm, e.g.:
t=np.arange(1,5)
s=2*t+3
fig, ax = plt.subplots()
ax.plot(t, s)
ax.set(xlabel='time (s)', ylabel='voltage (mV)',title='About as simple as it gets, folks')
ax.grid()
plt.show()
they come out as png's - how can i display them as figs (as in Matlab) - whats wrong?
In Pycharm, go to Preferences > Tools > Python Scientific, and disable Show plots in tool window (see screenshot attached). You may need to restart Pycharm after. Plots should appear in a separate, interactive pop-up window next time you plot with Matplotlib (that is, more similar to Matlab). If it doesn't work, check your matplotlib backend with matplotlib.get_backend(), and try different ones with matplotlib.use('<backend_name>'). You can access backend lists like this:
matplotlib.rcsetup.interactive_bk, matplotlib.rcsetup.non_interactive_bk,
matplotlib.rcsetup.all_backends.

Fast image sequences / animation in Jupyter Notebook with matplotlib

I can't seem to find a simple and fast way of plotting image sequences with plain matplotlib in a Jupyter Notebook. I've tried FuncAnimation, fig.canvas.draw(), blitting, as well as just the standard imshow-pause combo; without success or with very slow refresh rate. I don't need the images to be interactive - they just need to be shown sequentially and can't pop up a new figure window for each image. I've seen many solutions here, with none seeming to work the way I want.
My general pipeline does significant processing, with each image generated and plotted within a while or for loop. FuncAnimation is not desirable since it requires passing a function handle and my use case involves many arguments and state variables that make it difficult to use.
The best I've got is the working example below using fig.canvas.draw() - showing that drawing time increases linearly per iteration, where I need it to remain constant!
import numpy as np
import matplotlib.pyplot as plt
from timeit import default_timer as timer
%matplotlib notebook
num_iters = 50
im = np.arange(60).reshape((15,4))
fig, ax = plt.subplots(1,1)
fig.show()
fig.canvas.draw()
iter_times = np.zeros(num_iters)
for i in range(num_iters):
im = np.roll( a=im, shift=1, axis=0 )
t0 = timer()
ax.imshow(im.T, vmin=im.min(), vmax=im.max())
ax.set_title('Iter # {}/{}'.format(i+1, num_iters))
fig.canvas.draw()
iter_times[i] = timer()-t0
plt.figure(figsize=(6,3))
plt.plot(np.arange(num_iters)+1, iter_times)
plt.title('Imshow/drawing time per iteration')
plt.xlabel('Iteration number')
plt.ylabel('Time (seconds)')
plt.tight_layout()
plt.show()
I think the problem is that the plots are 'building up', so every one is being plotted every time. If you add ax.clear() right before the imshow(), you'll get linear plot times.

IPython plotting inline not showing

I have the following code in IPython running IPython QT Console on Linux.
%pylab inline
Welcome to pylab, a matplotlib-based Python environment [backend: module://IPython.zmq.pylab.backend_inline].
For more information, type 'help(pylab)'.
fig = figure()
ax = fig.add_axes()
ax = fig.add_axes([0,500, 0, 5000])
ax.plot([1,2,3,44], [4,4,55,55])
Out[5]: [<matplotlib.lines.Line2D at 0x3d8e7d0>]
fig
Out[6]: <matplotlib.figure.Figure at 0x3d25fd0>
fig.show()
/usr/lib/pymodules/python2.7/matplotlib/figure.py:362: UserWarning: matplotlib is currently using a non-GUI backend, so cannot show the figure
"matplotlib is currently using a non-GUI backend, "
I've been struggling to make this work for some time, I've tried changing the backend manually with matplotlib.use() to Qt4Agg, GTK etc with no luck. This also happens in IPython notebook even when I call display().
Any ideas how to get the inline plotting working?
Marked Jakob's answer as the answer, but both are true actually. I had to replace the matploblibrc file with a new copy, started IPython QT Console with --pylab=None then manually entered %pylab inline in the console. Somehow this fixed the problem.
The axis object is defined incorrectly, this prevents matplotlib from rendering.
Remove the first ax = fig.add_axes(), and replace the second line with
ax = fig.add_axes([0, 0, 1, 1]).
The add_axes method requests the size of the axis in relative coordinates, in the form left, bottom, width, height with values between 0 and 1, see e.g. matplotlib tutorial.
You may also try fig.add_subplot(111) instead of fig.add_axes() or fig,ax = subplots() to create your figure and axis objects. The latter assumes that you have populated the interactive namespace matplotlib (%pylab) call in IPython.
It looks like your matplotlib build was compiled without a gui backend.
This is done when either a) it's explicitly specified (handy for webservers), or b) the required libraries for at least one gui backend aren't present (e.g. no Tk, Gtk, Qt, etc).
How did you install matplotlib?
If you compiled it from source, make sure that you have the development libraries for at least Tk installed and that your python install was compiled with Tk support (it is by default). If you installed it from your distro's repositories, whoever built the package built it without gui support, and you'll need to install it from another source.