I have previously used the following to ensure my figure-size in my plots is a consistent size:
import matplotlib as mpl
rc_fonts = {'figure.figsize': (15, 9.3)}
mpl.rcParams.update(rc_fonts)
import matplotlib.pylab as plt
However, I am now finding that for my usual default values (15, 9.3) this is being ignored. The following demonstrates this:
import matplotlib as mpl
rc_fonts = {'figure.figsize': (15, 9.3)}
mpl.rcParams.update(rc_fonts)
import matplotlib.pylab as plt
# I draw some boring plot.
plt.clf()
plt.plot(*[range(10)]*2)
print plt.gcf().get_size_inches()
print mpl.rcParams['figure.figsize']
plt.gcf().set_size_inches(15, 9.3, forward=True)
print plt.gcf().get_size_inches()
The initial plot size is [10.35, 9.3] and after it is [15, 9.3] as desired. If however I make the default very much large or smaller, e.g. (32, 19.3) then the figure window is correctly sized. I would like to keep my desired route of changing rcParams to set the default, rather than trying to set it twice by making an interim dummy plot. Is this a bug, or am I going about this the wrong way?
Details:
Python 2.7.12 (inside a virtual environment, a must).
Backend TkAgg (I want this kept as it is).
Matplotlib version 2.1.0. (This bug/feature persists in version 2.1.2 also).
PS - I prefer avoiding having to make matplotlib fig and ax objects and instead use the plt interface directly. If possible I would like to keep it this way with any solutions.
Possible known issue:
I have found the following issue 2716 on github which I think is causing this, but there don't appear any fixes suitable for the rcParam settings route. So any help or suggestions are still welcome.
Current output:
Following the comments below is some example output (done using Python 3 to allow me to install the latest version of matplotlib):
Python 3.5.2 (default, Nov 23 2017, 16:37:01)
[GCC 5.4.0 20160609] on linux
>>>
... import matplotlib as mpl
... print(mpl.__version__)
... rc_fonts = {'figure.figsize': (15, 9.3)}
... mpl.rcParams.update(rc_fonts)
... import matplotlib.pylab as plt
... plt.plot(*[range(10)]*2)
...
Backend Qt4Agg is interactive backend. Turning interactive mode on.
2.2.0rc1+124.gf1f83f6
>>>
... print(plt.gcf().get_size_inches())
... print(mpl.rcParams['figure.figsize'])
... plt.gcf().set_size_inches(15, 9.3, forward=True)
... print(plt.gcf().get_size_inches())
...
[ 10.35 9.3 ]
[15.0, 9.3]
[ 15. 9.3]
DEMONSTRATION
Root of the problem
As explained in the accepted answer, the issue is that I am using more than one display, and Matplotlib cannot produce a window that is larger than the primary display. Unfortunately changing what Ubuntu considers to be the primary display is currently an unresolved bug. Hence the problem does not lie with Matplotlib, but with Ubuntu. I was able to resolve this issue by setting the display to the top left monitor in my setup.
The problem occurs because there are several screens in use and the one the figure is shown in is not the primary one.
There is currently no way to automatically show the figure larger than a maximized window on the primary screen would allow for. If the figure is larger than that, it is still shrunk to fit the plotting window.
After the window is initiated, one may indeed resize the figure to any other size, as is being done in the question using
plt.gcf().set_size_inches(15, 9.3, forward=True)
Related
I am trying to update the color of the faces of a pcolormesh using set_facecolor. The purpose of this operation is to "bleach" (emulate transparency by whitening the facecolor) some regions of the plot -- see this post. Although I am pretty sure I have been getting this to work in the past, for some reason it does not work anymore in a jupyter lab or jupyter notebook environment (not tested in a script yet). Unexpectedly, calling fig.canvas.draw() seems to restore the initial face colors. Here is a minimal example reproducing the error:
from matplotlib import pyplot as plt
import numpy as np
## Generate data and show initial plot
xx = np.linspace(-1, 1, 5)
xx, yy = np.meshgrid(xx, xx)
data = np.exp( -(xx**2+yy**2) )
### Generate plot
fig, ax = plt.subplots(1, 1)
hpc = ax.pcolormesh(data)
plt.colorbar(hpc)
ax.set_aspect(1)
fig.canvas.draw() # this is required to generate the facecolor array
colors = hpc.get_facecolors() # for checking: this contains the RGBA array
newc = np.ones((colors.shape[0], 3))/2. # uniform grey
hpc.set_facecolor(newc) # this should update the facecolor of the plot
newc = hpc.get_facecolors() # indeed, the facecolor seems to have been updated
fig.canvas.draw() # re-generating the plot
### On my machine: the plot is unchanged and the new facecolors are back to the initial values
print(newc[0,:], hpc.get_facecolors()[0,:])
Configuration:
backend: %matplotlib inline or %matplotlib widget both produce the error
python 3.9.13 (macOS Big Sur) or python 3.8.11 (Linux on a cluster -- maybe Fedora)
matplotlib 3.5.1 or 3.5.2 (resp), jupyterlab 3.4.4 or 3.4.0 (resp.)
Does anyone have an idea of what is going on? Am I doing something wrong? Thanks a lot in advance
OK, I found a "trick" based on this matplotlib issue (that I am sure was not necessary with a previous configuration): inserting hpc.set_array(None) before calling set_facecolor enables achieving the desired result.
I'm trying to make use of Interact in a Jupyter Notebook. A bit down on that page, it's stated that
On occasion, you may notice interact output flickering and jumping, causing the notebook scroll position to change as the output is updated. The interactive control has a layout, so we can set its height to an appropriate value (currently chosen manually) so that it will not change size as it is updated.
And I'm experiencing exactly that problem when I'm trying to replicate the example.
The following snippet...
%matplotlib inline
from ipywidgets import interactive
import matplotlib.pyplot as plt
import numpy as np
def f(m, b):
plt.figure(2)
x = np.linspace(-10, 10, num=1000)
plt.plot(x, m * x + b)
plt.ylim(-5, 5)
plt.show()
interactive_plot = interactive(f, m=(-2.0, 2.0), b=(-3, 3, 0.5))
output = interactive_plot.children[-1]
output.layout.height = '350px'
interactive_plot
... should produce this output:
But I'm only getting this:
To be precise, the sliders do pop up for half a second, but seem to be overwritten by the graph. I'm guessing that this is exactly the problem they are adressing. So I thought I could remedy the problem using different values than 350 in output.layout.height = '350px', but with absolutley no success so far. I've tried 100, 200, 250, 300, 750 and 1400.
So could there be something else causing the problems?
Thank you for any suggestions!
I just checked that the solution proposed here:
Jupyter Notebook: interactive plot with widgets
works with recent classic Jupyter.
To avoid flickering you could switch to using
https://github.com/AaronWatters/jp_doodle -- look at the examples
under "Features" named interactive*. The jp_doodle dual_canvas
has a context manager which suppresses intermediate updates.
I plot a figure containing several curves using matplotlib and then try to convert it into bokeh:
import numpy as np
import matplotlib.pyplot as plt
from bokeh import mpl
from bokeh.plotting import show, output_file
num_plots = 6
colormap = plt.cm.gist_ncar
time = np.random.random_sample((300, 6))
s_strain = np.random.random_sample((300, 6))
def time_s_strain_bokeh(num_plots, colormap, time, s_strain):
plt.gca().set_color_cycle([colormap(i) for i in np.linspace(0, 0.9, num_plots)])
plt.figure(2)
for i in range(0, num_plots):
plt.plot(time[:,i], s_strain[:,i])
plt.grid(True)
# save it to bokeh
output_file('anywhere.html')
show(mpl.to_bokeh())
time_s_strain_bokeh(num_plots, colormap, time, s_strain)
it works fine. However, I want to have a semilogx plot. When I change plt.plot in the "for" loop into plt.semilogx, I have the following error:
UnboundLocalError: local variable 'laxis' referenced before assignment
What can I do to change the x-axis onto log scale?
I'm with the same issue! 1/2 of the solution is this (supose my data is in a Pandas dataframe called pd):
pd.plot(x='my_x_variable', y='my_y_variable)
p = mpl.to_bokeh()
p.x_mapper_type='log' # I found this property with p.properties_with_values()
show(p)
I edited this answare because I just found part 2/2 of the solution:
When I use just the code above, the plot is semilog (ok!), but the x axis is flipped (mirrored)!!!
The solution I found is explicitly redefine xlim:
p.x_range.start=0.007 # supose pd['my_x_variable'] starts at 0.007
p.x_range.end=0.17 # supose pd['my_x_variable'] ends at 0.17
With this my plot became identical with the matplotlib original plot. The final code looks like:
pd.plot(x='my_x_variable', y='my_y_variable)
p = mpl.to_bokeh()
p.x_mapper_type='log'
p.x_range.start= pd['my_x_variable'].iloc[1] # numpy start at 0, take care!
p.x_range.end= pd['my_x_variable'].iloc[-1]
show(p)
As of Bokeh 0.12, partial and incomplete MPL compatibility is provided by the third party mplexporter library, which now appears to be unmaintained. Full (or at least, much more complete) MPL compat support will not happen until the MPL team implements MEP 25. However, implementing MEP 25 is an MPL project task, and the timeline/schedule is entirely outside of the control of the Bokeh project.
The existing MPL compat based on mplexporter is provided "as-is" in case it is useful in the subset of simple situations that it currently works for. My suggestion is to use native Bokeh APIs directly for anything of even moderate complexity.
You can find an example of a semilog plot created using Bokeh APIs here:
http://docs.bokeh.org/en/latest/docs/user_guide/plotting.html#log-scale-axes
Is there a way to close a pyplot figure in OS X using the keyboard (as far as I can see you can only close it by clicking the window close button)?
I tried many key combinations like command-Q, command-W, and similar, but none of them appear to work on my system.
I also tried this code posted here:
#!/usr/bin/env python
import matplotlib.pyplot as plt
plt.plot(range(10))
def quit_figure(event):
if event.key == 'q':
plt.close(event.canvas.figure)
cid = plt.gcf().canvas.mpl_connect('key_press_event', quit_figure)
plt.show()
However, the above doesn't work on OS X either. I tried adding print statements to quit_figure, but it seems like it's never called.
I'm trying this on the latest public OS X, matplotlib version 1.1.1, and the standard Python that comes with OS X (2.7.3). Any ideas on how to fix this? It's very annoying to have to reach for the mouse every time.
This is definitely a bug in the default OS X backend used by pyplot. Adding the following two lines at the top of the file switches to a different backend that works for me, if this helps anyone else.
import matplotlib
matplotlib.use('TKAgg')
I got around this by replacing
plt.show()
with
plt.show(block=False)
input("Hit Enter To Close")
plt.close()
A hack at its best, but I hope that helps someone
use interactive mode:
import matplotlib.pyplot as plt
# Enable interactive mode:
plt.ion()
# Make your plot: No need to call plt.show() in interactive mode
plt.plot(range(10))
# Close the active plot:
plt.close()
# Plots can also be closed via plt.close('all') to close all open plots or
# plt.close(figure_name) for named figures.
Checkout the "What is interactive mode?" section in this documentation
Interactive mode can be turned off at any point with plt.ioff()
When you have focus in the matplotlib window, the official keyboard shortcut is ctrl-W by this:
http://matplotlib.org/1.2.1/users/navigation_toolbar.html
As this is a very un-Mac way to do things, it is actually cmd-W. Not so easy to guess, is it?
If you are using an interactive shell, you can also close the window programmatically. See:
When to use cla(), clf() or close() for clearing a plot in matplotlib?
So, if you use pylab or equivalent (everything in the same namespace), it is just close(fig). If you are loading the libraries manually, you need to take close from the right namespace, for example:
import matplotlib.pyplot as plt
fig = plt.figure()
plt.plot([0,1,2],[0,1,0],'r')
fig.show()
plt.close(fig)
The only catch here is that there is no such thing as fig.close even though one would expect. On the other hand, you can use plt.close('all') to regain your desktop.
In the following minimal example, I create 1-point scatter plot and later change color of points in loop using Collection.set_color. If I set the color(s) the first time scatter is called, set_color will not change its face color (only edge color), whereas if I don't specify it when the scatterplot is created, face color will change according to set_color.
from pylab import *
from numpy import *
coll=scatter([0],[0],s=500,c=[.1]) # omit c=[.1] here to have face color changing later
ion(); show()
for a in linspace(.1,.9):
coll.set_color(coll.get_cmap()(a))
draw()
Is that a bug, or am I missing something in the documentation?
I would say it is a bug/limitation of that matplotlib version.
I tried the code with:
matplotlib 1.0.1 (ActivePython 2.6.7, win7 64bit) --> reproduced the behavior
matplotlib 1.1.0.dev (ActivePython 3.2.2, winXP, 32bit) --> works as expected
There is also a comment from Avaris saying he gets expected behavior with mpl 1.1.0 (win7, 32bit)
So I recommend you to upgrade your installation if this is possible