How to use multiple themes for multiple matplotlib imports - python

I am importing multiple matplotlib as names within my python program and would like to use different styles for different plots.
However when i change the style for one plot (say : dark_background) it changes the style for all other plots as well.
suggestions shall be appreciated
Current import is something like this :
import matplotlib.pyplot as plt_surfacegt
import matplotlib.pyplot as plt_mascon
import matplotlib.pyplot as plt_gravmod
import matplotlib.pyplot as plt_realtime
plt_realtime.style.use('dark_background')
it should only change the theme for plt_realtime to dark however all others are changed to dark as well.!

I cannot exactly explain why this wouldn't work, but it seems to me a crazy idea to achieve your desired result.
Instead, I think you should use matplotlib's context manager to change the style sheet on a per-plot basis. Something like (from the link):
with plt.style.context('dark_background'):
plt.plot(np.sin(np.linspace(0, 2 * np.pi)), 'r-o')
plt.show()

Related

Change default matplotlib value in jupyter notebook

I was wondering how you can change the matplotlib.rcParams permanently instead of indicating it every time when you open jupyter notebook. (like change in the profile as the default value).
Thanks
A short answer, also for personal reference...
I would still prefer indicating it in the code though. However it doesn't have to be done for every single parameters as it can be done in one line calling for a style file for instance.
Anyway, here are several ways of doing so, from the most permanent change to the most soft and subtle way of changing the parameters:
1. Change default config file
Change the default parameters in matplotlibrc file, you can find its location with:
import matplotlib as mpl
mpl.get_configdir()
2. Modify iPython profile
Change how matplotlib default options are loaded in iPython by modifying options in ~/.ipython/profile_default/ipython_kernel_config.py, or wherever your configuraiton file is (ipython locate profile to find out) (see this answer for details)
3. Create your own styles
You can create your own custom rcParams files and store them in .config/matplotlib/stylelib/*.mplstyle or wherever os.path.join(matplotlib.get_configdir(), stylelib) is.
The file should be in the following format, similar to matplotlibrc, e.g. my_dark.mplstyle:
axes.labelcolor: white
axes.facecolor : 333333
axes.edgecolor : white
ytick.color : white
xtick.color : white
text.color : white
figure.facecolor : 0D0D0D
This is an example of a style for a dark background with white axes, and white tick labels...
To use it, before your plots, call:
import matplotlib.pyplot as plt
plt.style.use("my_dark")
# Note that matplotlib has already several default styles you can chose from
You can overlay styles by using several ones at once, the last one overwrites its predecessors' parameters. This can be useful to keep e.g. font variables from a certain style (paper-like, presentation) but simultaneously toggle a dark mode on top, by overwriting all color-related parameters.
With something like plt.style.use(["paper_fonts", "my_dark"])
More info in their documentation.
4. Context manager for rc_params
You can also use a context manager, this option is great in my opinion, to do something like:
import matplotlib as mpl
import matplotlib.pyplot as plt
with mpl.rc_context(rc={'text.usetex': True}, fname='screen.rc'):
plt.plot(x, a)
plt.plot(x, b)
Here we used a first set of parameters as defined in the file screen.rc then tweak the text.usetex value solely for the plt.plot(x,a) while plt.plot(x, b) will be using another (default here) set of rc parameters.
Again, see the doc for more information.

How to create visual profiler?

I would like to visualize some statistics about a program's running time in Python. Unfortunately this program has written in Fortran and C++, and I cannot use any language specific visualization tool. From the output of the program I have created a class including the start time and the end time of different functions, and subroutines. For example:
class MyProgramRuntime:
def __init__(self):
self.foo1CallTime
self.foo1EndTime
self.foo2CallTime
self.foo2EndTime
I would like to get a similar plot like on the picture on the following link: Picture
I am not sure if is this the best solution, but it works really nice for me. I have used the matplotlib.patches lib to plot as long rectangles as the actual function/subroutine runned in seconds. The variables in the class are float variables, I got them by extracting from the actual datetime the datetime of the program's beginning with datetime.timedelta.total_seconds() . The plotting looks like the following:
import matplotlib.pyplot as plt
import matplotlib.patches as patches
def plotRunningTimes(mpr): #mpr is an instance of the MyProgramRuntime class
fig = plt.figure()
ax = plt.subplot(111)
ax.add_patch( patches.Rectangle( (mpr.foo1CallTime, 0.1),
mpr.foo1EndTime-mpr.foo1Calltime,
0.1) )

How do pyplot functions (show, savefig, etc) work without "object" being passed in?

How do pyplot functions such as show() and savefig() not require a "plot object" to work?
For example, the following code works, but somehow I expect to use a file handler or pass a "plot object" into plt.show() and plot.savefig("venn3.pdf").
from matplotlib import pyplot as plt
from matplotlib_venn import venn3, venn3_circles
# Subset sizes
s = (2,3,4,3,1,0.5,4)
v = venn3(subsets=s, set_labels=('A', 'B', 'C'))
# Subset labels
v.get_label_by_id('100').set_text('Abc')
v.get_label_by_id('010').set_text('aBc')
v.get_label_by_id('110').set_text('ABc')
v.get_label_by_id('001').set_text('Abc')
v.get_label_by_id('101').set_text('aBc')
v.get_label_by_id('011').set_text('ABc')
v.get_label_by_id('111').set_text('ABC')
# Subset colors
v.get_patch_by_id('100').set_color('c')
v.get_patch_by_id('010').set_color('#993333')
v.get_patch_by_id('110').set_color('blue')
# Subset alphas
v.get_patch_by_id('101').set_alpha(0.4)
v.get_patch_by_id('011').set_alpha(1.0)
v.get_patch_by_id('111').set_alpha(0.7)
# Border styles
c = venn3_circles(subsets=s, linestyle='solid')
c[0].set_ls('dotted') # Line style
c[1].set_ls('dashed')
c[2].set_lw(1.0) # Line width
plt.show() # For show() to work without using variable v seems counter-intuitive to me.
plt.savefig("venn3.pdf") # For savefig() to work without using variable v seems counter-intuitive to me.
2[]
matplotlib.pyplot is often called "statemachine". This means that the function it provides do certain things depending on the internal state of pyplot.
In your code, you have created a figure and this is stored as an object; pyplot knows it has one figure.
If you then call other commands, it is assumend that they apply to that one figure which has been created previously, like plt.savefig.
plt.show() would work on all previously created figures (all of them would be shown).
Pyplot uses a global variable to hold the figure object. All pyplot functions work with that variable(s). If you are working interactively, pyplot is perfectly fine since only you will modify that variable. If you are writing multi-threaded or multi-user code pyplot will not work, and you would have to use the layer benath it, which needs the figure object passed in (and is a terrible interface).

Why is Jupyter Notebook creating duplicate plots when making updating plots

I'm trying to make plots in a Jupyter Notebook that update every second or so. Right now, I just have a simple code which is working:
%matplotlib inline
import time
import pylab as plt
import numpy as np
from IPython import display
for i in range(10):
plt.close()
a = np.random.randint(100,size=100)
b = np.random.randint(100,size=100)
fig, ax = plt.subplots(2,1)
ax[0].plot(a)
ax[0].set_title('A')
ax[1].plot(b)
ax[1].set_title('B')
display.clear_output(wait=True)
display.display(plt.gcf())
time.sleep(1.0)
Which updated the plots I have created every second. However, at the end, there is an extra copy of the plots:
Why is it doing this? And how can I make this not happen? Thank you in advance.
The inline backend is set-up so that when each cell is finished executing, any matplotlib plot created in the cell will be displayed.
You are displaying your figure once using the display function, and then the figure is being displayed again automatically by the inline backend.
The easiest way to prevent this is to add plt.close() at the end of the code in your cell.
Another alternative would be to add ; at the end of the line! I am experiencing the same issue with statsmodels methods to plot the autocorrelation of a time series (statsmodels.graphics.tsaplot.plot_acf()):
from statsmodels.graphics.tsaplots import plot_acf
plot_acf(daily_outflow["count"]);
Despite using %matplotlib inline, it's not working for some libraries, such as statsmodels. I recommend always use plt.show() at the end of your code.

Plot semilogx with matplotlib then convert it into Bokeh

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

Categories