Matplotlib plot with scalable/updatable x-axis - python

Is it possible to create a plot where a slider can update the length/location of the x-axis?
Here is an example of the type of slider required.
A somewhat similar matplotlib slider can be found here. Unfortunately, as you can see there is no documentation/explanation of how it works - this makes it rather difficult to understand/adapt!
The type of plot I would like to add this to is quite simple, here is a small, random example:
import matplotlib.pyplot as plt
import random
li = []
for x in xrange(100):
li.append(random.randint(0,20))
plt.plot(li)
plt.show()

Here's something to get you started. It's adapted directly from your second example in the matplotlib docs - using the slider to update the plot bounds, rather than to scale the data.
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider
import numpy as np
fig, ax = plt.subplots()
plt.subplots_adjust(bottom=0.25)
t = np.arange(0.0, 1.0, 0.001)
s = np.sin(5*np.pi*t)
l, = plt.plot(t,s)
viewwindow = 0.1
axpos = plt.axes([0.25, 0.1, 0.65, 0.03])
axslider = Slider(axpos, '', t[0]+viewwindow, t[-1]-viewwindow, valinit=(t[-1]+t[0])/2.0)
def update(val):
new_pos = axslider.val
ax.set_xbound(new_pos-viewwindow, new_pos+viewwindow)
fig.canvas.draw_idle()
update(axslider.val)
axslider.on_changed(update)
plt.show()

Related

Matplotlib more efficient way to update chart when using slider to scroll through chart?

I want to be able to scroll through a lengthy chart. Is there a more efficient/faster way than having to clear the axis and replot the whole thing every time the scroll bar moves?
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider
import random
x=[c for c in range(300)]
y=[random.randint(1,10) for c in range(300)]
showbars=100
fig = plt.figure()
ax = plt.subplot(111)
ax.bar(x[:showbars],y[:showbars])
def slidebar(pos):
pos = int(pos)
ax.clear()
ax.bar(x[pos:pos+showbars],y[pos:pos+showbars])
slidebarpos = plt.axes([0.1, 0.01, 0.5, 0.03], facecolor="skyblue")
slider = Slider(slidebarpos, '', 0, len(x)-showbars, valinit=0)
slider.on_changed(slidebar)
slidebar(0)
plt.show()
This is slow on my computer
First of all you could plot the bars only once, and use the slider just to change the range that is shown, i.e. the limits of the x-axis.
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider
import numpy as np
x=np.arange(300)
y=np.random.randint(1,10, size=300)
showbars=100
fig, ax = plt.subplots()
ax.bar(x,y)
def slidebar(pos):
ax.set_xlim(pos-1, pos+showbars+1)
slidebarpos = plt.axes([0.1, 0.01, 0.5, 0.03], facecolor="skyblue")
slider = Slider(slidebarpos, '', 0, len(x)-showbars, valinit=0)
slider.on_changed(slidebar)
slidebar(0)
plt.show()
One could also keep the same bar's in place, but change their height and fake the ticks and labels in such a way that the bars look like being updated.
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider
from matplotlib.ticker import AutoLocator
import numpy as np
x=np.arange(300)
y=np.random.randint(1,10, size=300)
showbars=100
fig, ax = plt.subplots()
bars = ax.bar(x[:showbars],y[:showbars])
loc = AutoLocator()
def slidebar(pos):
pos = int(pos)
for bar, yi in zip(bars, y[pos:showbars+pos]):
bar.set_height(yi)
ticks = loc.tick_values(pos, showbars+pos)
ax.set_xticks(ticks-pos)
ax.set_xticklabels(ticks)
slidebarpos = plt.axes([0.1, 0.01, 0.5, 0.03], facecolor="skyblue")
slider = Slider(slidebarpos, '', 0, len(x)-showbars, valinit=0)
slider.on_changed(slidebar)
slidebar(0)
plt.show()

How not to show the intermediate values in matplotlib [duplicate]

Can anyone help me set the ticks on a fixed position using matplotlib? I've tried using FixedPosition as this tutorial describes:
ax = pl.gca()
ax.xaxis.set_major_locator(eval(locator))
http://scipy-lectures.github.io/intro/matplotlib/matplotlib.html#figures-subplots-axes-and-ticks
But when I try to run, it tells me that set_major_locator method does not exist.
A simple example would be very useful.
Thanks.
Just use ax.set_xticks(positions) or ax.set_yticks(positions).
For example:
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.set_xticks([0.15, 0.68, 0.97])
ax.set_yticks([0.2, 0.55, 0.76])
plt.show()
import numpy as np
import matplotlib.ticker as ticker
import matplotlib.pyplot as plt
name_list = ('Omar', 'Serguey', 'Max', 'Zhou', 'Abidin')
value_list = np.random.randint(0, 99, size = len(name_list))
pos_list = np.arange(len(name_list))
ax = plt.axes()
ax.xaxis.set_major_locator(ticker.FixedLocator((pos_list)))
ax.xaxis.set_major_formatter(ticker.FixedFormatter((name_list)))
plt.bar(pos_list, value_list, color = '.75', align = 'center')
plt.show()

Statsmodel Probplot Tick customization

I've created a cumulative probability plot with StatsModels in Python, but there are way too many ticks on the axis.
I want there to be only be tick marks at 0.1, 10, 50, 90, 99, and 99.9. Anyone know how to make this work? I tried using the code below but it only gives me the first n number of ticks, making it pretty useless (See figure below.)
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import matplotlib.ticker as ticker
import statsmodels.api as sm
csv = pd.read_csv('cumProbMaxData.csv')
data = csv.values.tolist()
flat_list = [item for sublist in data for item in sublist]
fig,ax = plt.subplots()
x = np.array(flat_list)
pp_x = sm.ProbPlot(x, fit=True)
figure = pp_x.probplot(exceed=False, ax=ax, marker='.', color='k', markersize=12)
plt.xlabel('Cumulative Probability (%)')
plt.ylabel('Maximum CO$_2$ Flux (g m$^-$$^2$ d$^-$$^1$)')
tick_spacing=5
ax.xaxis.set_major_locator(ticker.MaxNLocator(tick_spacing))
plt.tight_layout()
plt.show()
Statsmodels ProbPlot plots the data in their real units. It is only the axes ticks which are then changed as to show some percentage value. This is in general bad style but of course you have to live with it if you want to use ProbPlot.
A solution for the problem of showing less ticks on such a plot which uses a FixedLocator and FixedFormatter would be to subsample the shown ticks. The ticklabels you want to show are at indices locs = [0,3,6,10,14,17,20] (you want to show the ticklabel 0, 3, 6, etc.).
You can use this list to select from the shown ticks only those in the list as shown below.
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import statsmodels.api as sm
x = np.random.randn(200)
fig,ax = plt.subplots()
pp_x = sm.ProbPlot(x, fit=True)
pp_x.probplot(exceed=False, ax=ax, marker='.', color='k', markersize=12)
locs = [0,3,6,10,14,17,20]
ax.set_xticklabels(np.array(ax.xaxis.get_major_formatter().seq)[locs])
ax.set_xticks(ax.get_xticks()[locs])
plt.tight_layout()
plt.show()

changes axis of scatter plot with slider matplotlib python

I have a very large data set and want the user to be able to slide along the axis to view sections of the data. I'm trying to leverage off of the slider example but I'm unsure of how to update the graph. Hoping someone can explain some of the behinds the scenes with this.
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.widgets import Slider, Button, RadioButtons
fig = plt.figure()
ax = fig.add_subplot(111)
fig.subplots_adjust(left=0.25, bottom=0.25)
min0 = 0
max0 = 10
x = np.arange(10)
y = np.arange(10)
im1 = plt.scatter(x,y, s=3, c=u'b', edgecolor='None',alpha=.75)
#most examples here return something iterable
plt.ylim([0,10])#initial limits
axcolor = 'lightgoldenrodyellow'
axmin = fig.add_axes([0.25, 0.1, 0.65, 0.03], axisbg=axcolor)
axmax = fig.add_axes([0.25, 0.15, 0.65, 0.03], axisbg=axcolor)
smin = Slider(axmin, 'Min', 0, 10, valinit=min0)
smax = Slider(axmax, 'Max', 0, 10, valinit=max0)
def update(val):
plt.ylim([smin.val,smax.val])
ax.canvas.draw()#unsure on this
smin.on_changed(update)
smax.on_changed(update)
plt.show()
The graph updates itself when you set new limits. You just don't see this because you update wrong subplot. Just select right subplot to update:
def update(val):
plt.subplot(111)
plt.ylim([smin.val,smax.val])
(this work for me)
or maybe even:
def update(val):
plt.ylim([smin.val,smax.val])
plt.subplot(111)
smin.on_changed(update)
smax.on_changed(update)
if you don`t do anything with it elsewhere
UPD: also in matplotlib examples you can find fig.canvas.draw_idle()

How can I have one annotation pointing to several points in matplotlib?

I have some data that I usually plot in matplotlib. Certain values of the independent variable are resonances, and I want to label them with something resembling matplotlib's annotate. Is there a way to have one annotation (one balloon that says something like "resonances") with arrows that point to several points on the plot?
In this form is better to you?
import matplotlib.pyplot as plt
import numpy as np
a = np.ones(100)
multi = np.arange(0,100,5)
plt.ylim(-0.5,10)
plt.text(50, 6.5,'a=5k',fontsize=20)
for x in multi:
plt.annotate("",xy=(x,1),xytext=(50,6),
arrowprops=dict(facecolor='black', shrink=0.005))
plt.plot(a,'k.')
plt.show()
how about (basically ripped out of the docs http://matplotlib.org/users/annotations_intro.html)
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
t = np.arange(0.0, 5.0, 0.01)
s = np.cos(2*np.pi*t)
line, = ax.plot(t, s, lw=2)
coords_to_annote = [(2,1),(3,1),(4,1)]
for coords in coords_to_annote:
ax.annotate('local max', xy=coords, xytext=(3, 1.5),
arrowprops=dict(facecolor='black', shrink=0.05),
)
ax.set_ylim(-2,2)
plt.show()
You are looking for some similar to?
import matplotlib.pyplot as plt
import numpy as np
a = np.ones(100)
multi = np.arange(0,100,5)
plt.ylim(-0.5,10)
for x in multi:
plt.annotate("a=5k",xy=(x,1),xytext=(x,1+4*np.random.rand()),
arrowprops=dict(facecolor='black', shrink=0.05))
plt.plot(a,'k.')
plt.show()

Categories

Resources