Jupyter/ipython notebook : how to prevent plot redraw using interactive widget - python-2.7

I am struggling to have construct an interactive tool in jupyter notebook. Based on the discussion here : IPython Notebook widgets for Matplotlib interactivity, I've build the following example:
%matplotlib notebook
import matplotlib.pyplot as plt
from ipywidgets import Select,interactive,Dropdown
from IPython.display import display
fig,ax = plt.subplots()
ax.plot(range(5))
vline = ax.axvline(1, color='k')
hline = ax.axhline(0.5, color='k')
def set_cursor(x, y):
vline.set_xdata((x, x))
hline.set_ydata((y, y))
ax.figure.canvas.draw_idle()
interactive(set_cursor, x=ax.get_xlim(), y=ax.get_ylim())
It works pretty well except that that the last line (interactive...) has to be run in a different cell.
If I want to launch everything in the same cell (or from the same object if use a Class approach, which is what I want at the end), I have to use the following code:
%matplotlib notebook
import matplotlib.pyplot as plt
from ipywidgets import Select,interactive,Dropdown
from IPython.display import display
fig,ax = plt.subplots()
ax.plot(range(5))
vline = ax.axvline(1, color='k')
hline = ax.axhline(0.5, color='k')
def set_cursor(x, y):
vline.set_xdata((x, x))
hline.set_ydata((y, y))
ax.figure.canvas.draw_idle()
display(fig)
tool = interactive(set_cursor, x=ax.get_xlim(), y=ax.get_ylim())
display(tool)
But in this case, the complete figure is redraw each time a new value is selected in a widget
Is there any possibility to get everything launch smoothly from the same cell ?
Any idea is more than welcome !

Related

Changing date format and show it on tkinter

Is there a way to change the axis' format on a tkinter graph? As you can see I use a plot widget to put my graphs on my frame. Is there a way for me to make the dates on the bottom in num/num format? Like 4/18 rather than April 18 2017? Heres my code: (Also is it possible to change color of my graph backgrounds? They are defaulted to gray)
import numpy as np
import datetime as dt
import yahoo_finance as yf
import matplotlib.pyplot as plt
from Tkinter import *
import quandl
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
root=Tk()
root.geometry('1400x875')
root.title("Stock Information")
fmain=Frame(root, width=1400, height=900)
fmain.place(x=100, y=0)
today=dt.date.today()
thirty_day_graph_frame=Frame(fmain, width=1290, height=300)
thirty_day_graph_frame.place(x=0, y=240)
thirty_days=dt.timedelta(days=43)
thirty_days_ago=today-thirty_days
five_yrs_graph_frame=Frame(fmain, width=1290, height=300)
five_yrs_graph_frame.place(x=0, y=540)
five_years=dt.timedelta(days=1825)
five_years_ago=today-five_years
def stock_info(stock_name):
global five_yrs_graph_frame
five_yrs_graph_frame.destroy()
global thirty_day_graph_frame
thirty_day_graph_frame.destroy()
thirty_day_graph_frame=Frame(fmain, width=1290, height=300)
thirty_day_graph_frame.place(x=0, y=240)
five_yrs_graph_frame=Frame(fmain, width=1290, height=300)
five_yrs_graph_frame.place(x=0, y=540)
stock=yf.Share(stock_name)
stock_price=stock.get_price()
name_price_label=Label(fmain, text=(stock_name,':', stock_price),font=("Times New Roman",23))
name_price_label.place(x=400, y=10)
day_change=stock.get_change()
if float(day_change) > 0:
font_color="green"
elif float(day_change) < 0:
font_color="red"
else:
font_color="yellow"
day_change_label=Label(fmain, text=(day_change),font=("Times New Roman",20),fg=str(font_color))
day_change_label.place(x=400, y=40)
thirty_day_data = quandl.get("WIKI/"+str(stock_name), start_date=str(thirty_days_ago), end_date=str(today),column_index=4) #So quandl.get gives a lot of info, so the column_index=4 is just getting closing prices
five_year_data = quandl.get("WIKI/"+str(stock_name),start_date=str(five_years_ago), end_date=str(today), column_index=4)
thirty_day_fig = plt.figure(figsize=(10,3.75))
plt.plot(thirty_day_data)
canvas = FigureCanvasTkAgg(thirty_day_fig, master=thirty_day_graph_frame)
plot_widget = canvas.get_tk_widget()
plot_widget.place(x=0,y=0)
five_year_fig=plt.figure(figsize=(10,3.75))
plt.plot(five_year_data)
canvas1=FigureCanvasTkAgg(five_year_fig, master=five_yrs_graph_frame)
plot_widget1=canvas1.get_tk_widget()
plot_widget1.place(x=1,y=0)
apple_button=Button(root,text='AAPL', command=lambda:stock_info('AAPL'))
tesla_button=Button(root,text='TSLA', command=lambda:stock_info('TSLA'))
google_button=Button(root,text='GOOG', command=lambda:stock_info('GOOG'))
apple_button.place(x=10, y=15)
tesla_button.place(x=10, y=45)
google_button.place(x=10,y=75)
root.mainloop()
You can use the datetime library with using the function strftime
from datetime import datetime
today = datetime.today()
print ('ISO :', today) # ISO: 2017-05-25 16:23:35.850570
format = "%d/%m"
s = today.strftime(format)
print (s) # 25/05
You can read more about this function and formats options in here

Displaying PNG in matplotlib.pyplot framework in python 2.7

I am pulling PNG images from Jupyter Notebooks and manage to display with IPython.display.Image but not with matplotib.pyplot.plt. What am I missing? I use python 2.7.
I am using the following algorithm:
To open the notebook JSON content I do:
import nbformat
notebook_ = nbformat.read(file_notebook, 4)
After retrieving the relevant cell information I pull the png information from it using:
def cell_to_image(cell, out_value_item_number=1):
if "execution_count" in cell.keys(): # i.e version >=4
return cell["outputs"][out_value_item_number]['data']['image/png']
elif "prompt_number" in cell.keys(): # i.e version < 4
return cell["outputs"][out_value_item_number]['png']
return None
cell_image = cell_to_image(cell)
The first few characters of cell_image (which is unicode) looks like:
iVBORw0KGgoAAAANSUhEUgAAA64AAAFMCAYAAADLFeHSAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\n
AAALEgAACxIB0t1+/AAAIABJREFUeJzs3Xd8jef/x/HXyTjZiYQkCGrU3ruR0tr9oq2qGtGo0dbe
\nm5pVlJpFUSMoVb6UoEZ/lCpatWuPUiNEEiMDmef3R75OexonJKUO3s/HI4/mXPd1X/d1f+LRR965
\n7/u6DSaTyYSIiIiIiIiIjbJ70hMQERERERERyYiCq4iIiIiIiNg0BVcRERERERGxaQquIiIiIiIi
\nYtMUXEVERERERMSmKbiKiIiIiIiITVNwFRGRxyIkJIRixYqxfv36+24/e/YsxYoVo3jx4v/yzGxb
\naGgoderUIS4uDoBdu3bRsmVLKlasyCuvvMKgQYOIjo622CcsLIyGDRtSunRp6tSpw8KFC62OW7p0
\naRo2bJju53Lnzh1GjRrFyy+/TNmyZWnRogW//fbbQ835q6++olGjRpQvX5769eszc+ZMkpOTzdtT
\nU1OZNGkSNWrUoHTp0jRp0oTdu3enGyc2NpZOn
I can easily plot in my Jupityer notebook using
from IPython.display import Image
Image(cell_image)
And now to my question:
How can I manipulate cell_image to be plt.subplot friendly?
(Assuming import matplotlib.pyplot as plt).
I realise that plt.imshow wouldn't work because this would require an array, which is not my case (which is a string, as far as I understand).
If you have your image string representation in a variable string_rep, the following code should work.
from io import BytesIO
import matplotlib.image as mpimage
import matplotlib.pyplot as plt
with BytesIO(string_rep.decode('base64')) as byte_rep:
image = mpimage.imread(byte_rep)
plt.imshow(image)

Matplotlib navigation toolbar is invisible

When I plot an image, my Navigation toolbar (zoom-in, forward, back...) is invisible. I helped myself with this link: disable matplotlib toolbar. I have first tried:
import matplotlib as mpl
mpl.rcParams['toolbar'] = 'toolbar2'
And also checked if in the file itself is set as 'None' but it is not.
Did I perhaps forget to install some packages? Even though I don't get any errors.
Is there alternative way to zoom-in and see the coordinates of cursor, because that is all I need.
Edit 1
This is the code which I am using. I copied just the part, where I use plot.
#___plotting part___
import matplotlib as mpl
mpl.rcParams['toolbar'] = 'toolbar2'
import matplotlib.pyplot as plt
plt.ion()
fig, ax = plt.subplots(figsize=(20, 10))
ax.set_title(plot_titel, loc='center', fontname=font_name, fontsize=16, color='black')
ax.set_xlabel('Column number', fontname=font_name, fontsize=16, color='black')
ax.set_ylabel('Mean of raw backscatter', fontname=font_name, fontsize=16, color='black')
ax.plot(range(len(param_image)), param_image, c='black', marker='o')
ax.plot(idx1[0], param_image[idx1], c='red', mec='red', marker='o', linestyle='')
ax.plot(idx2, param_image[idx2], c='blue', mec='blue', marker='o', linestyle='')
ax.grid()
fig.tight_layout()
plt.show()
I had the same problem before. uninstall it and then install it again (try to use Anaconda or miniconda distribution to install). for sure after that it will work.
do not mess with matplotlibrc

PyQt4 and Qwt Error when opening

i´m trying to do a simple plot, using PyQt4 and Qwt5. When i start the app, it shows as i expected, but i can´t do anything, such as click or zoom for example. And if i minimize it, the plot disappears.
This is my code:
import sys
from PyQt4 import Qt
import numpy as np
import PyQt4.Qwt5.iqt
from PyQt4.Qwt5.qplt
class SimpleData(QwtPlot):
def __init__(self):
QwtPlot.__init__(self)
x = np.arange(-2*np.pi, 2*np.pi, 0.01)
p = IPlot(Curve(x, np.cos(x), Pen(Magenta,2), "cos(x)"),
Curve(x, np.exp(x), Pen(Red), "exp(x)", Y2),
Axis(Right, Log),"Ejemplo de PyQt con PyQwt")
x = x[0: -1: 10]
p.plot(Curve(x, np.cos(x-np.pi/4), Symbol(Circle, Yellow), "circle"),
Curve(x, np.cos(x+np.pi/4), Pen(Blue), Symbol(Square, Cyan), "Square"))
app = QApplication(sys.argv)
app.exec_()
The indentation is correct, maybe i made a mistake writting it here, but it´s ok.
Another thing, when i close the app, i get this error:
QObject::killTimers: timers cannot be stopped from another thread
[Finished in 2.6s with exit code -1073741510]
Thank you for your time and answers. I hope you can help me.

3D CartoPy similar to Matplotlib-Basemap

I'm new to Python with a question about Cartopy being able to be used in a 3D plot. Below is an example using matplotlibBasemap.
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from mpl_toolkits.basemap import Basemap
m = Basemap(projection='merc',
llcrnrlat=52.0,urcrnrlat=58.0,
llcrnrlon=19.0,urcrnrlon=40.0,
rsphere=6371200.,resolution='h',area_thresh=10)
fig = plt.figure()
ax = Axes3D(fig)
ax.add_collection3d(m.drawcoastlines(linewidth=0.25))
ax.add_collection3d(m.drawcountries(linewidth=0.35))
ax.add_collection3d(m.drawrivers(color='blue'))
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Height')
fig.show()
This creates a map within a 3D axis so that you can plot objects over the surface. But with Cartopy returns a matplotlib.axes.GeoAxesSubplot. Not clear how to take this and add to a 3D figure/axis as above with matplotlib-basemap.
So, can someone give any pointers on how to do a similar 3D plot with Cartopy?
The basemap mpl3d is a pretty neat hack, but it hasn't been designed to function in the described way. As a result, you can't currently use the same technique for much other than simple coastlines. For example, filled continents just don't work AFAICT.
That said, a similar hack is available when using cartopy. Since we can access shapefile information generically, this solution should work for any poly-line shapefile such as coastlines.
The first step is to get hold of the shapefile, and the respective geometries:
feature = cartopy.feature.NaturalEarthFeature('physical', 'coastline', '110m')
geoms = feature.geometries()
Next, we can convert these to the desired projection:
target_projection = ccrs.PlateCarree()
geoms = [target_projection.project_geometry(geom, feature.crs)
for geom in geoms]
Since these are shapely geometries, we then want to convert them to matplotlib paths with:
from cartopy.mpl.patch import geos_to_path
import itertools
paths = list(itertools.chain.from_iterable(geos_to_path(geom)
for geom in geoms))
With paths, we should be able to just create a PathCollection in matplotlib, and add it to the axes, but sadly, Axes3D doesn't seem to cope with PathCollection instances, so we need to workaround this by constructing a LineCollection (as basemap does). Sadly LineCollections don't take paths, but segments, which we can compute with:
segments = []
for path in paths:
vertices = [vertex for vertex, _ in path.iter_segments()]
vertices = np.asarray(vertices)
segments.append(vertices)
Pulling this all together, we end up with a similar result to the basemap plot which your code produces:
import itertools
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection
import numpy as np
import cartopy.feature
from cartopy.mpl.patch import geos_to_path
import cartopy.crs as ccrs
fig = plt.figure()
ax = Axes3D(fig, xlim=[-180, 180], ylim=[-90, 90])
ax.set_zlim(bottom=0)
target_projection = ccrs.PlateCarree()
feature = cartopy.feature.NaturalEarthFeature('physical', 'coastline', '110m')
geoms = feature.geometries()
geoms = [target_projection.project_geometry(geom, feature.crs)
for geom in geoms]
paths = list(itertools.chain.from_iterable(geos_to_path(geom) for geom in geoms))
# At this point, we start working around mpl3d's slightly broken interfaces.
# So we produce a LineCollection rather than a PathCollection.
segments = []
for path in paths:
vertices = [vertex for vertex, _ in path.iter_segments()]
vertices = np.asarray(vertices)
segments.append(vertices)
lc = LineCollection(segments, color='black')
ax.add_collection3d(lc)
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Height')
plt.show()
On top of this, mpl3d seems to handle PolyCollection well, which would be the route I would investigate for filled geometries, such as the land outline (as opposed to the coastline, which is strictly an outline).
The important step is to convert the paths to polygons, and use these in a PolyCollection object:
concat = lambda iterable: list(itertools.chain.from_iterable(iterable))
polys = concat(path.to_polygons() for path in paths)
lc = PolyCollection(polys, edgecolor='black',
facecolor='green', closed=False)
The complete code for this case would look something like:
import itertools
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection, PolyCollection
import numpy as np
import cartopy.feature
from cartopy.mpl.patch import geos_to_path
import cartopy.crs as ccrs
fig = plt.figure()
ax = Axes3D(fig, xlim=[-180, 180], ylim=[-90, 90])
ax.set_zlim(bottom=0)
concat = lambda iterable: list(itertools.chain.from_iterable(iterable))
target_projection = ccrs.PlateCarree()
feature = cartopy.feature.NaturalEarthFeature('physical', 'land', '110m')
geoms = feature.geometries()
geoms = [target_projection.project_geometry(geom, feature.crs)
for geom in geoms]
paths = concat(geos_to_path(geom) for geom in geoms)
polys = concat(path.to_polygons() for path in paths)
lc = PolyCollection(polys, edgecolor='black',
facecolor='green', closed=False)
ax.add_collection3d(lc)
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Height')
plt.show()
To yield: