Plot semilogx with matplotlib then convert it into Bokeh - python

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

Related

How to get visible bars on a histogram/distribution plot? [duplicate]

While doing some practice problems using seaborn and a Jupyter notebook, I realized that the distplot() graphs did not have the darker outlines on the individual bins that all of the sample graphs in the documentation have. I tried creating the graphs using Pycharm and noticed the same thing. Thinking it was a seaborn problem, I tried some hist() charts using matplotlib, only to get the same results.
import matplotlib.pyplot as plt
import seaborn as sns
titanic = sns.load_dataset('titanic')
plt.hist(titanic['fare'], bins=30)
yielded the following graph:
Finally I stumbled across the 'edgecolor' parameter on the plt.hist() function, and setting it to black did the trick. Unfortunately I haven't found a similar parameter to use on the seaborn distplot() function, so I am still unable to get a chart that looks like it should.
I looked into changing the rcParams in matplotlib, but I have no experience with that and the following script I ran seemed to do nothing:
import matplotlib as mpl
mpl.rcParams['lines.linewidth'] = 1
mpl.rcParams['lines.color'] = 'black'
mpl.rcParams['patch.linewidth'] = 1
mpl.rcParams['patch.edgecolor'] = 'black'
mpl.rcParams['axes.linewidth'] = 1
mpl.rcParams['axes.edgecolor'] = 'black'
I was just kind of guessing at the value I was supposed to change, but running my graphs again showed no changes.
I then attempted to go back to the default settings using mpl.rcdefaults()
but once again, no change.
I reinstalled matplotlib using conda but still the graphs look the same. I am running out of ideas on how to change the default edge color for these charts. I am running the latest versions of Python, matplotlib, and seaborn using the Conda build.
As part of the update to matplotlib 2.0 the edges on bar plots are turned off by default. However, you may use the rcParam
plt.rcParams["patch.force_edgecolor"] = True
to turn the edges on globally.
Probably the easiest option is to specifically set the edgecolor when creating a seaborn plot, using the hist_kws argument,
ax = sns.distplot(x, hist_kws=dict(edgecolor="k", linewidth=2))
For matplotlib plots, you can directly use the edgecolor or ec argument.
plt.bar(x,y, edgecolor="k")
plt.hist(x, edgecolor="k")
Equally, for pandas plots,
df.plot(kind='hist',edgecolor="k")
A complete seaborn example:
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
x = np.random.randn(100)
ax = sns.distplot(x, hist_kws=dict(edgecolor="k", linewidth=2))
plt.show()
As of Mar, 2021 :
sns.histplot(data, edgecolor='k', linewidth=2)
work.
Using hist_kws=dict(edgecolor="k", linewidth=2) gave an error:
AttributeError: 'PolyCollection' object has no property 'hist_kws'
Using the available styles in seaborn could also solve your problem.
Available styles in seaborn are :
ticks
dark
darkgrid
white
whitegrid

Python Matplotlib/Seaborn/Jupyter - Putting bar plot in wrong place?

I'm using the following in a Jupyter notebook, using the latest Anaconda update (including Matplotlib 3.1.1,)
Thanks to SpghttCd, I have the code to do a stacked horizontal bar, but Seaborn puts it on a new plot below the default one.
How might I best fix this problem?
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
data=pd.DataFrame(data={"R1":["Yes","Yes","Yes","No","No"]})
freq = data["R1"].value_counts(normalize=True)*100
fig,ax = plt.subplots()
freq.to_frame().T.plot.barh(stacked=True)
You see two axes in Jupyter because you create a fresh one with plt.subplots() and pandas also creates another one.
If you need to reuse an existing axe, pass it to plotting method using ax switch:
fig, axe = plt.subplots()
freq.to_frame().T.plot.barh(stacked=True, ax=axe)
See pandas documentation for details, plotting method always exhibits an ax switch:
ax : Matplotlib axis object, optional
If you accept pandas creates it for you, as #Bharath M suggested, just issue:
axe = freq.to_frame().T.plot.barh(stacked=True)
Then you will see an unique axes and you can access it trough the variable axe.

No outlines on bins of Matplotlib histograms or Seaborn distplots

While doing some practice problems using seaborn and a Jupyter notebook, I realized that the distplot() graphs did not have the darker outlines on the individual bins that all of the sample graphs in the documentation have. I tried creating the graphs using Pycharm and noticed the same thing. Thinking it was a seaborn problem, I tried some hist() charts using matplotlib, only to get the same results.
import matplotlib.pyplot as plt
import seaborn as sns
titanic = sns.load_dataset('titanic')
plt.hist(titanic['fare'], bins=30)
yielded the following graph:
Finally I stumbled across the 'edgecolor' parameter on the plt.hist() function, and setting it to black did the trick. Unfortunately I haven't found a similar parameter to use on the seaborn distplot() function, so I am still unable to get a chart that looks like it should.
I looked into changing the rcParams in matplotlib, but I have no experience with that and the following script I ran seemed to do nothing:
import matplotlib as mpl
mpl.rcParams['lines.linewidth'] = 1
mpl.rcParams['lines.color'] = 'black'
mpl.rcParams['patch.linewidth'] = 1
mpl.rcParams['patch.edgecolor'] = 'black'
mpl.rcParams['axes.linewidth'] = 1
mpl.rcParams['axes.edgecolor'] = 'black'
I was just kind of guessing at the value I was supposed to change, but running my graphs again showed no changes.
I then attempted to go back to the default settings using mpl.rcdefaults()
but once again, no change.
I reinstalled matplotlib using conda but still the graphs look the same. I am running out of ideas on how to change the default edge color for these charts. I am running the latest versions of Python, matplotlib, and seaborn using the Conda build.
As part of the update to matplotlib 2.0 the edges on bar plots are turned off by default. However, you may use the rcParam
plt.rcParams["patch.force_edgecolor"] = True
to turn the edges on globally.
Probably the easiest option is to specifically set the edgecolor when creating a seaborn plot, using the hist_kws argument,
ax = sns.distplot(x, hist_kws=dict(edgecolor="k", linewidth=2))
For matplotlib plots, you can directly use the edgecolor or ec argument.
plt.bar(x,y, edgecolor="k")
plt.hist(x, edgecolor="k")
Equally, for pandas plots,
df.plot(kind='hist',edgecolor="k")
A complete seaborn example:
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
x = np.random.randn(100)
ax = sns.distplot(x, hist_kws=dict(edgecolor="k", linewidth=2))
plt.show()
As of Mar, 2021 :
sns.histplot(data, edgecolor='k', linewidth=2)
work.
Using hist_kws=dict(edgecolor="k", linewidth=2) gave an error:
AttributeError: 'PolyCollection' object has no property 'hist_kws'
Using the available styles in seaborn could also solve your problem.
Available styles in seaborn are :
ticks
dark
darkgrid
white
whitegrid

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.

Animating a Quadmesh from pcolormesh with matplotlib

As a result of a full day of trial and error, I'm posting my findings as a help to anyone else who may come across this problem.
For the last couple days, I've been trying to simulate a real-time plot of some radar data from a netCDF file to work with a GUI I'm building for a school project. The first thing I tried was a simple redrawing of the data using the 'interactive mode' of matplotlib, as follows:
import matplotlib.pylab as plt
fig = plt.figure()
plt.ion() #Interactive mode on
for i in range(2,155): #Set to the number of rows in your quadmesh, start at 2 for overlap
plt.hold(True)
print i
#Please note: To use this example you must compute X, Y, and C previously.
#Here I take a slice of the data I'm plotting - if this were a real-time
#plot, you would insert the new data to be plotted here.
temp = plt.pcolormesh(X[i-2:i], Y[i-2:i], C[i-2:i])
plt.draw()
plt.pause(.001) #You must use plt.pause or the figure will freeze
plt.hold(False)
plt.ioff() #Interactive mode off
While this technically works, it also disables the zoom functions, as well as pan, and well, everything!
For a radar display plot, this was unacceptable. See my solution to this below.
So I started looking into the matplotlib animation API, hoping to find a solution. The animation did turn out to be exactly what I was looking for, although its use with a QuadMesh object in slices was not exactly documented. This is what I eventually came up with:
import matplotlib.pylab as plt
from matplotlib import animation
fig = plt.figure()
plt.hold(True)
#We need to prime the pump, so to speak and create a quadmesh for plt to work with
plt.pcolormesh(X[0:1], Y[0:1], C[0:1])
anim = animation.FuncAnimation(fig, animate, frames = range(2,155), blit = False)
plt.show()
plt.hold(False)
def animate( self, i):
plt.title('Ray: %.2f'%i)
#This is where new data is inserted into the plot.
plt.pcolormesh(X[i-2:i], Y[i-2:i], C[i-2:i])
Note that blit must be False! Otherwise it will yell at you about a QuadMesh object not being 'iterable'.
I don't have access to the radar yet, so I haven't been able to test this against live data streams, but for a static file, it has worked great thus far. While the data is being plotted, I can zoom and pan with the animation.
Good luck with your own animation/plotting ambitions!

Categories