I am having an issue with FuncAnimation where my annotations are removed after updating xlim. Here is the code with a preview underneath
You can try the code in a google colab here https://colab.research.google.com/drive/1NrM-ZnSQKhADccpjCbNeOC5PU8uXw-Sb?authuser=2#scrollTo=bcYtgNaTYJ3g
import os
import matplotlib.animation as ani
import matplotlib.pyplot as plt
from collections import deque
from typing import List
from IPython.display import Image
from matplotlib.offsetbox import OffsetImage, AnnotationBbox
def create_animation_for_data(qty_lists: List[List[int]], gif_path, add_horizontal_guides=True, dynamic_y_axis=True,
dynamic_x_axis=True):
plt.style.use(['dark_background'])
fruits_to_color = ["red", "orange"]
qtys1, qty2 = qty_lists
times = [i for i in range(len(qtys1))]
artists = []
zoom = 0.5
first_image_path = 'assets/apple.png'
first_image = plt.imread(first_image_path)
first_offset_image = OffsetImage(first_image, zoom=zoom)
second_image_path = 'assets/orange.png'
second_image = plt.imread(second_image_path)
second_offset_image = OffsetImage(second_image, zoom=zoom)
# initializing a figure in
# which the graph will be plotted
my_dpi = 200
figsize_pixels = (650, 1000)
figsize = (int(figsize_pixels[0] / my_dpi), figsize_pixels[1] / my_dpi)
fig = plt.figure(figsize=figsize, dpi=my_dpi)
fig.set_tight_layout(True)
records_per_second = 1
seconds_show_on_screen = 30
max_width_on_screen = records_per_second * seconds_show_on_screen
ticks_every = 20
graph_max_y = 100
max_y_list = list(range(60, graph_max_y + 1, ticks_every * 2))
max_y_index = 0
max_y = max_y_list[max_y_index]
highest_max_y = max_y_list[- 1]
xlim_min = times[0]
if dynamic_x_axis:
xlim_max = times[max_width_on_screen - 1]
else:
xlim_max = times[-1]
axes_xlim = (xlim_min, xlim_max)
if dynamic_y_axis:
ylim_max = max_y
else:
ylim_max = highest_max_y
axes_ylim = (0, ylim_max)
ax1 = plt.axes(xlim=axes_xlim, ylim=axes_ylim)
# Set a title
plt.title('Qty over time', fontsize=20)
# Set axis labels
plt.xlabel('Time', fontsize=18)
plt.ylabel('Qty', fontsize=18)
plotlays, plotcols = [2], fruits_to_color
labels = ['Apple', 'Orange']
lines = []
for index in range(len(qty_lists)):
lobj = ax1.plot([], [], lw=5, color=plotcols[index],
label=labels[index])[0]
lines.append(lobj)
# Make sure your axis ticks are large enough to be easily read.
# You don't want your viewers squinting to read your plot.
plt.yticks(range(0, highest_max_y + 1, ticks_every), [str(x) for x in range(0, highest_max_y + 1, ticks_every)],
fontsize=14)
plt.xticks(fontsize=14)
# Provide tick lines across the plot to help your viewers trace along
# the axis ticks. Make sure that the lines are light and small so they
# don't obscure the primary data lines.
if add_horizontal_guides:
max_x = len(times)
for y in range(0, highest_max_y + 1, ticks_every):
plt.plot(times, [y] * max_x, "--",
lw=1, color="white", alpha=0.7)
# Do this after the plotting done above
ax1.set_ylim(*axes_ylim)
# Remove the tick marks; they are unnecessary with the tick lines we just plotted.
plt.tick_params(axis="both", which="both", bottom="off", top="off",
labelbottom="on", left="off", right="off", labelleft="on")
# empty list to store x and y axis values
xdata = deque()
ydata1 = deque()
ydata2 = deque()
first_image_annotation = AnnotationBbox(
first_offset_image, (times[0], 0), xycoords='data', frameon=False)
artists.append(ax1.add_artist(first_image_annotation))
second_image_annotation = AnnotationBbox(
second_offset_image, (times[0], 0), xycoords='data', frameon=False)
artists.append(ax1.add_artist(second_image_annotation))
ann_list = [
first_image_annotation,
second_image_annotation,
]
# animation function
def animate(i):
nonlocal max_y_index
nonlocal ann_list
# appending new points to x, y axes points list
x1_and_x2 = times[i]
xdata.append(x1_and_x2)
y1 = qty_lists[0][i]
ydata1.append(y1)
y2 = qty_lists[1][i]
ydata2.append(y2)
xlist = [xdata, xdata]
ylist = [ydata1, ydata2]
# If we have passed our max_width_on_screen
if len(xdata) > max_width_on_screen:
# Delete the oldest record
xdata.popleft()
max_x = max(xdata)
min_x = max_x - seconds_show_on_screen
# Update our x axis
if dynamic_x_axis:
ax1.set_xlim(min_x, max_x)
graph_max_y_data = max(ydata1[-1], ydata2[-1])
max_y_data = max_y_list[max_y_index]
while graph_max_y_data > max_y_data:
max_y_index += 1
max_y_data = max_y_list[max_y_index]
# Update our y axis
if dynamic_y_axis:
ax1.set_ylim(0, max_y_data)
ydata1.popleft()
ydata2.popleft()
first_image_annotation_xybox = (x1_and_x2, y1)
first_image_annotation.xybox = first_image_annotation_xybox
second_image_annotation_xybox = (x1_and_x2, y2)
second_image_annotation.xybox = second_image_annotation_xybox
for lnum, line in enumerate(lines):
# set data for each line separately.
line.set_data(xlist[lnum], ylist[lnum])
return lines, ann_list
# call the animator
anim = ani.FuncAnimation(fig, animate, frames=len(times), interval=30, blit=False)
# save the animation as gif file
anim.save(gif_path, writer='imagemagick', fps=2)
return os.path.abspath(gif_path)
static_axes_gif = 'FuncAnimation-annotated-static-axes.gif'
print(static_axes_gif)
animation_path_static_axes = create_animation_for_data(data_to_plot,
static_axes_gif,
dynamic_x_axis=False,
dynamic_y_axis=False)
Image(url=animation_path_static_axes)
static_x_gif = 'FuncAnimation-annotated-static-x.gif'
print(static_x_gif)
animation_path_static_x_axis = create_animation_for_data(data_to_plot,
static_x_gif,
dynamic_x_axis=False,
dynamic_y_axis=True)
Image(url=animation_path_static_x_axis)
static_y_gif = 'FuncAnimation-annotated-static-y.gif'
print(static_y_gif)
animation_path_static_y_axis = create_animation_for_data(data_to_plot,
static_y_gif,
dynamic_x_axis=True,
dynamic_y_axis=False)
Image(url=animation_path_static_y_axis)
dynamic_axes_gif = 'FuncAnimation-annotated-dynamic-axes.gif'
print(dynamic_axes_gif)
animation_path_dynamic_axes = create_animation_for_data(data_to_plot,
dynamic_axes_gif,
dynamic_x_axis=True,
dynamic_y_axis=True)
Image(url=animation_path_dynamic_axes)
I am making 4 graphs with variable dynamic axes (dynamic = updating axis during amination):
FuncAnimation-annotated-static-axes.gif
xlim and ylim are fixed
FuncAnimation-annotated-static-x.gif
xlim is fixed
ylim is dynamic
FuncAnimation-annotated-static-y.gif
xlim is dynamic
ylim is fixed
FuncAnimation-annotated-dynamic-axes.gif
xlim and ylim are dynamic
My annotations disappear in the two cases where the xlim is updated:
FuncAnimation-annotated-static-y.gif
FuncAnimation-annotated-dynamic-axes.gif
Note that when xlim is static this doesn't happen:
FuncAnimation-annotated-static-axes.gif
FuncAnimation-annotated-static-x.gif
Does anyone know why this happens or how to update the xlim without removing annotations?
Please let me know if something is unclear / worded poorly as I really need to solve this.
So the issue is with how I was moving my annotation.
This is the fix:
# Don't do this - updating xlim will causing the annotation do disappear
# first_image_annotation_xybox = (x1_and_x2, y1)
# first_image_annotation.xybox = first_image_annotation_xybox
#
# second_image_annotation_xybox = (x1_and_x2, y2)
# second_image_annotation.xybox = second_image_annotation_xybox
for lnum, line in enumerate(lines):
# set data for each line separately.
line.set_data(xlist[lnum], ylist[lnum])
# Do this - Update our annotations
for ann in ann_list:
ann.remove()
ann_list = []
first_image_annotation = AnnotationBbox(
first_offset_image, (x1_and_x2, y1), xycoords='data', frameon=False)
ann_list.append(ax1.add_artist(first_image_annotation))
second_image_annotation = AnnotationBbox(
second_offset_image, (x1_and_x2, y2), xycoords='data', frameon=False)
ann_list.append(ax1.add_artist(second_image_annotation))
return lines, ann_list
The rest of the code is the same. Wonder why this happens on updating xlim and not on updating ylim ¯\(ツ)/¯
Related
x = range(11, 31)
y_1 = [1,0,1,1,2,4,3,2,3,4,4,5,6,5,4,3,3,1,1,1]
y_2 = [1,0,3,1,2,2,3,3,3,2,1,2,1,1,1,1,1,1,1,1]
# 图形大小
plt.figure(figsize=(20, 8), dpi = 80)
# 设置x轴刻度
x_label = ["{}岁".format(i) for i in x]
plt.xticks(list(x), x_label, fontproperties = my_font) # 显示中文刻度
# 绘制网格
plt.grid(alpha = 0.4)
# 添加图例
plt.legend(prop = my_font, loc = "upper left")
# Execution
plt.plot(x, y_1, label = "Mine")
plt.plot(x, y_2, label = "Him")
# Display
plt.show()
This is the code for legends showing in Python matplotlib, and I wanna show the legend, but the result is that there is no show at all.
You need to call plt.legend after plotting the curves:
# first
plt.plot(x, y_1, label = "Mine")
plt.plot(x, y_2, label = "Him")
# next
plt.legend(loc = "upper left")
output (smaller size):
Background
In Matplotlib, we can render the string using mathtext as a marker using $ ..... $ (Reference 1)
Question
Is there any way to enclose this text in a circular or rectangular box, or any different different shape? Similar to the registered symbol as shown here
I want to use this marker on a plot as shown below:
Text '$T$' is used in this plot, I want the text to be enclosed in a circle or rectangle.
Solution
As suggested in the comments of the answer, I have plotted a square marker of a bit larger size before the text marker. This resolved the issue.
The final figure is shown below:
Edit: Easiest way is to simply place patches to be the desired "frames" in the same location as the markers. Just make sure they have a lower zorder so that they don't cover the data points.
More sophisticated ways below:
You can make patches. Here is an example I used to make a custom question mark:
import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.markers as m
fig, ax = plt.subplots()
lim = -5.8, 5.7
ax.set(xlim = lim, ylim = lim)
marker_obj = m.MarkerStyle('$?$') #Here you place your letter
path = marker_obj.get_path().transformed(marker_obj.get_transform())
path._vertices = np.array(path._vertices)*8 #To make it larger
patch = mpl.patches.PathPatch(path, facecolor="cornflowerblue", lw=2)
ax.add_patch(patch)
def translate_verts(patch, i=0, j=0, z=None):
patch._path._vertices = patch._path._vertices + [i, j]
def rescale_verts(patch, factor = 1):
patch._path._vertices = patch._path._vertices * factor
#translate_verts(patch, i=-0.7, j=-0.1)
circ = mpl.patches.Arc([0,0], 11, 11,
angle=0.0, theta1=0.0, theta2=360.0,
lw=10, facecolor = "cornflowerblue",
edgecolor = "black")
ax.add_patch(circ)#One of the rings around the questionmark
circ = mpl.patches.Arc([0,0], 10.5, 10.5,
angle=0.0, theta1=0.0, theta2=360.0,
lw=10, edgecolor = "cornflowerblue")
ax.add_patch(circ)#Another one of the rings around the question mark
circ = mpl.patches.Arc([0,0], 10, 10,
angle=0.0, theta1=0.0, theta2=360.0,
lw=10, edgecolor = "black")
ax.add_patch(circ)
if __name__ == "__main__":
ax.axis("off")
ax.set_position([0, 0, 1, 1])
fig.canvas.draw()
#plt.savefig("question.png", dpi=40)
plt.show()
Edit, second answer:
creating a custom patch made of other patches:
import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
import mpl_toolkits.mplot3d.art3d as art3d
class PlanetPatch(mpl.patches.Circle):
"""
This class combines many patches to make a custom patch
The best way to reproduce such a thing is to read the
source code for all patches you plan on combining.
Also make use of ratios as often as possible to maintain
proportionality between patches of different sizes"""
cz = 0
def __init__(self, xy, radius,
color = None, linewidth = 20,
edgecolor = "black", ringcolor = "white",
*args, **kwargs):
ratio = radius/6
mpl.patches.Circle.__init__(self, xy, radius,
linewidth = linewidth*ratio,
color = color,
zorder = PlanetPatch.cz,
*args, **kwargs)
self.set_edgecolor(edgecolor)
xy_ringcontour = np.array(xy)+[0, radius*-0.2/6]
self.xy_ringcontour = xy_ringcontour - np.array(xy)
self.ring_contour = mpl.patches.Arc(xy_ringcontour,
15*radius/6, 4*radius/6,
angle =10, theta1 = 165,
theta2 = 14.5,
fill = False,
linewidth = 65*linewidth*ratio/20,
zorder = 1+PlanetPatch.cz)
self.ring_inner = mpl.patches.Arc(xy_ringcontour,
15*radius/6, 4*radius/6,
angle = 10, theta1 = 165 ,
theta2 = 14.5,fill = False,
linewidth = 36*linewidth*ratio/20,
zorder = 2+PlanetPatch.cz)
self.top = mpl.patches.Wedge([0,0], radius, theta1 = 8,
theta2 = 192,
zorder=3+PlanetPatch.cz)
self.xy_init = xy
self.top._path._vertices=self.top._path._vertices+xy
self.ring_contour._edgecolor = self._edgecolor
self.ring_inner.set_edgecolor(ringcolor)
self.top._facecolor = self._facecolor
def add_to_ax(self, ax):
ax.add_patch(self)
ax.add_patch(self.ring_contour)
ax.add_patch(self.ring_inner)
ax.add_patch(self.top)
def translate(self, dx, dy):
self._center = self.center + [dx,dy]
self.ring_inner._center = self.ring_inner._center +[dx, dy]
self.ring_contour._center = self.ring_contour._center + [dx,dy]
self.top._path._vertices = self.top._path._vertices + [dx,dy]
def set_xy(self, new_xy):
"""As you can see all patches have different ways
to have their positions updated"""
new_xy = np.array(new_xy)
self._center = new_xy
self.ring_inner._center = self.xy_ringcontour + new_xy
self.ring_contour._center = self.xy_ringcontour + new_xy
self.top._path._vertices += new_xy - self.xy_init
fig = plt.figure(figsize=(6, 6))
ax = fig.add_subplot()
lim = -8.5, 8.6
ax.set(xlim = lim, ylim = lim,
facecolor = "black")
planets = []
colors = mpl.colors.cnames
colors = [c for c in colors]
for x in range(100):
xy = np.random.randint(-7, 7, 2)
r = np.random.randint(1, 15)/30
color = np.random.choice(colors)
planet = PlanetPatch(xy, r, linewidth = 20,
color = color,
ringcolor = np.random.choice(colors),
edgecolor = np.random.choice(colors))
planet.add_to_ax(ax)
planets.append(planet)
fig.canvas.draw()
#plt.savefig("planet.png", dpi=10)
plt.show()
I'm struggling to adjust my plot legend after adding the axline/ hline on 100 level in the graph.(screenshot added)
if there's a way to run this correctly so no information will be lost in legend, and maybe add another hline and adding it to the legend.
adding the code here, maybe i'm not writing it properly.
fig, ax1 = plt.subplots(figsize = (9,6),sharex=True)
BundleFc_Outcome['Spend'].plot(kind = 'bar',color = 'blue',width = 0.4, ax = ax1,position = 1)
#
# Make the y-axis label, ticks and tick labels match the line color.
ax1.set_ylabel('SPEND', color='b', size = 18)
ax1.set_xlabel('Bundle FC',color='w',size = 18)
ax2 = ax1.twinx()
ax2.set_ylabel('ROAS', color='r',size = 18)
ax1.tick_params(axis='x', colors='w',size = 20)
ax2.tick_params(axis = 'y', colors='w',size = 20)
ax1.tick_params(axis = 'y', colors='w',size = 20)
#ax1.text()
#
ax2.axhline(100)
BundleFc_Outcome['ROAS'].plot(kind = 'bar',color = 'red',width = 0.4, ax = ax2,position = 0.25)
plt.grid()
#ax2.set_ylim(0, 4000)
ax2.set_ylim(0,300)
plt.title('ROAS & SPEND By Bundle FC',color = 'w',size= 20)
plt.legend([ax2,ax1],labels = ['SPEND','ROAS'],loc = 0)
The code gives me the following picture:
After implementing the suggestion in the comments, the picture looks like this (does not solve the problem):
You can use bbox_to_anchor attribute to set legend location manually.
ax1.legend([ax1],labels = ['SPEND'],loc='upper right', bbox_to_anchor=(1.25,0.70))
plt.legend([ax2,ax1],labels = ['SPEND','ROAS'],loc='upper right', bbox_to_anchor=(1.25,0.70))
https://matplotlib.org/users/legend_guide.html#legend-location
So finally figured it out , was simpler for a some reason
Even managed to add another threshold at level 2 for minimum spend.
fig, ax1 = plt.subplots(figsize = (9,6),sharex=True)
BundleFc_Outcome['Spend'].plot(kind = 'bar',color = 'blue',width = 0.4, ax = ax1,position = 1)
#
# Make the y-axis label, ticks and tick labels match the line color.
ax1.set_ylabel('SPEND', color='b', size = 18)
ax1.set_xlabel('Region',color='w',size = 18)
ax2 = ax1.twinx()
ax2.set_ylabel('ROAS', color='r',size = 18)
ax1.tick_params(axis='x', colors='w',size = 20)
ax2.tick_params(axis = 'y', colors='w',size = 20)
ax1.tick_params(axis = 'y', colors='w',size = 20)
#ax1.text()
#
BundleFc_Outcome['ROAS'].plot(kind = 'bar',color = 'red',width = 0.4, ax = ax2,position = 0.25)
plt.grid()
#ax2.set_ylim(0, 4000)
ax2.set_ylim(0,300)
plt.title('ROAS & SPEND By Region',color = 'w',size= 20)
fig.legend([ax2,ax1],labels = ['SPEND','ROAS'],loc = 0)
plt.hlines([100,20],xmin = 0,xmax = 8,color= ['r','b'])
I don't recommend using the builtin functions of pandas to do more complex plotting. Also when asking a question it is common courtesy to provide a minimal and verifiable example (see here). I took the liberty to simulate your problem.
Due to the change in axes, we need to generate our own legend. First the results:
Which can be achieved with:
import matplotlib.pyplot as plt, pandas as pd, numpy as np
# generate dummy data.
X = np.random.rand(10, 2)
X[:,1] *= 1000
x = np.arange(X.shape[0]) * 2 # xticks
df = pd.DataFrame(X, columns = 'Spend Roast'.split())
# end dummy data
fig, ax1 = plt.subplots(figsize = (9,6),sharex=True)
ax2 = ax1.twinx()
# tmp axes
axes = [ax1, ax2] # setup axes
colors = plt.cm.tab20(x)
width = .5 # bar width
# generate dummy legend
elements = []
# plot data
for idx, col in enumerate(df.columns):
tax = axes[idx]
tax.bar(x + idx * width, df[col], label = col, width = width, color = colors[idx])
element = tax.Line2D([0], [0], color = colors[idx], label = col) # setup dummy label
elements.append(element)
# desired hline
tax.axhline(200, color = 'red')
tax.set(xlabel = 'Bundle FC', ylabel = 'ROAST')
axes[0].set_ylabel('SPEND')
tax.legend(handles = elements)
I tried with the package epade but I failed!
Example:
Each one of the x values defines the height of each bar (bars as many x values exist, with x height).
xa<-c(9.45,6.79,14.03,7.25,16.16,19.42,16.30,4.60,14.76,19.24,
16.04,7.80,13.16,10.00,15.76,16.29,19.52,27.22,7.74,6.75)
barplot(xa)
So I would like exactly the same plot in 3d looking fashion!
Is it possible?
UPDATED SOLUTION
This was done in Python, not in R :(
Here is the code:
# needed modules
import csv
import pandas as pandas
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from matplotlib import cm
from scipy.interpolate import spline
from textwrap import wrap
from mpl_toolkits.mplot3d import proj3d
import pylab
import os
# we define some names in order to change only one
# 3 columnes are imported each time
# by changing col_inc from 0 to something
# we can define which range of columns will be imported
col_num = np.arange(2, 1001)
col_num_tuple = tuple(col_num)
cnt = col_num_tuple
cnt
# last counter col_inc = 279
col_inc = 273
str = 0 + col_inc
fin = 3 + col_inc
cols = cnt[str:fin]
cols
# importing a simple datafile, csv type. Data are comma seperated
# importing only 1st, 2nd and 4th columns
# We can call these data now by giving a new name, 'io'.
io = pandas.read_csv(
'/data.csv', sep=",", usecols=cols)
# Try to get the name of singer & the name of song
# in the first two rows
names = io[0:2]
nm = names
nm1 = np.array(nm[:], dtype='string')
nm_singer = nm1[0:1][0:2, 1][0]
nm_song = nm1[1:2][0:2, 1][0]
nm_singer
nm_song
nms = nm_singer + ' - ' + nm_song
# we drop nan values
io = io.dropna()
# we make this in order not change each time, the name of column
io_all = np.array(io[3:])
io_st = np.array(io_all[:, 0], dtype=float)
io_end = np.array(io_all[:, 1], dtype=float)
io_dur = np.array(io_all[:, 2], dtype=float)
io_all
io_st
io_end
io_dur
# We define a new name for the column that is named alice inside io dataset
result = io_dur
# we need to make these data 'array type'
result = np.array(result)
# we now define the dimensions of our figure/plot, as well its dpi
fig = plt.figure(figsize=(16, 8), dpi=150)
# This line defines our first plot
# Afterwards, the '112' will define our second plot.
ax1 = fig.add_subplot(111, projection='3d')
# ax1 = Axes3D(fig)
# we define here labels
xlabels = io_end
xpos = np.arange(xlabels.shape[0])
ylabels = np.array([''])
ypos = np.arange(ylabels.shape[0])
xposM, yposM = np.meshgrid(xpos, ypos, copy=False)
zpos = result
zpos = zpos.ravel()
# this defines the dimensions of the actual boxes
# you can play with these values.
dx = 0.7
dy = 0.7
dz = zpos
# here, we define ticks, they are placed in the 'middle' of each bar
ax1.w_xaxis.set_ticks(xpos + dx / 2.)
ax1.w_xaxis.set_ticklabels(xlabels, rotation='vertical')
ax1.w_yaxis.set_ticks(ypos + dy / 2.)
ax1.w_yaxis.set_ticklabels(ylabels)
# here we define the colors of the bars, rainbow style
# you can play with these numbers
values = np.linspace(0.2, 1., xposM.ravel().shape[0])
colors = cm.rainbow(values)
# figure subtitle
# fig.suptitle('test title', fontsize=20)
# here, we define in the x axis the size of its ticks, its numbers
ax1.tick_params(axis='x', which='major', pad=0, labelsize=7)
# Here, we define the limits of y axis,
# NOTE that this defines WHERE bars will be placed
# IN relation to the rest figure,
# their offset point
plt.ylim((-2, 5))
# this says if the grid will be printed
plt.grid(True)
# this defines the placement of the 3d plot in its placeholders,
# in the surrounding white space
# I was surprised! The below line is not needed at all!
# fig.subplots_adjust(left=0, right=0, bottom=0, top=0)
# this is the actual command to define the plot
# all 6 parameters that we previously defined, are placed here.
# colors is an extra parameter
ax1.bar3d(xposM.ravel(), yposM.ravel(), dz * 0, dx, dy, dz, color=colors)
# elevation and azimuth, basically, definition of the view angle
ax1.view_init(0, -95)
# here we define that we will place a second plot
# Neither this line is needed!
# ax1 = fig.add_subplot(112, projection='3d')
# To produce numbers from 0 according to how many data exist in 'result'
x = np.arange(0, len(result))
y = result
# I try to center the line in relation to the top of bars.
y += 5
# Produce more points in order to make the line to look nicer (300).
x_smooth = np.linspace(x.min(), x.max(), 300)
y_smooth = spline(x, y, x_smooth)
# smooth line sometimes went below zero in some extreme cases.
# Therefore I added this if statement to find these cases
# and increase the height of the smooth line so much points
# as the points that went below 0
if min(y_smooth) <= 0:
y -= (min(y_smooth))-1
y_smooth = spline(x, y, x_smooth)
# a trick to center the line to bars
x_smooth += 0.4
# here,i try to produce a 'z' array of so many zeros as the length
# of 'x_smooth line'
z = np.linspace(0, 0, len(x_smooth))
# here, we define the parameters of the second plot.
# ax1' symbol is duplicated
# in order to plot the line in the same plot with the barplot.
ax1.plot(x_smooth, z, y_smooth)
# this try to align the y title
ax1.annotate(
'\n'.join(wrap('Duration of each Rythm (in sec)', 20)),
xy=(0.20, 0.80), xytext=(0, 0), fontsize=8, color='steelblue',
style='italic',
xycoords='axes fraction', textcoords='offset points',
bbox=dict(facecolor='mistyrose', alpha=0.3),
horizontalalignment='center', verticalalignment='down')
# this try to align the x title
ax1.annotate(
'\n'.join(wrap('Where Rythm is broken (in sec)', 20)),
xy=(0.27, 0.06), xytext=(0, 0), fontsize=9, color='steelblue',
xycoords='axes fraction', textcoords='offset points',
bbox=dict(facecolor='peachpuff', alpha=0.3),
horizontalalignment='center', verticalalignment='down')
# this try to center the bottom title
ax1.annotate(
'\n'.join(wrap(nms, 100)), xy=(0.5, 0.07),
xytext=(0, 0), fontsize=11,
xycoords='axes fraction', textcoords='offset points',
bbox=dict(facecolor='mediumorchid', alpha=0.3),
horizontalalignment='center', verticalalignment='down')
# Eedefine path and filename in order to save in custom made filename
pathnm = '/'
filenm = nms
nflnm = '%s_3D.png' % filenm
npath = os.path.join(pathnm, nflnm)
# saving our plot
#fig.savefig(npath, bbox_inches='tight', pad_inches=0,figsize=(46,15),dpi=400)
plt.show(fig)
io[0:2]'code'
I have a time series plot and I need to draw a moving vertical line to show the point of interest.
I am using the following toy example to accomplish the same. However, it prints all the lines at the same time while I wanted to show these vertical line plotting one at a time.
import time
ion() # turn interactive mode on
# initial data
x = arange(-8, 8, 0.1);
y1 = sin(x)
y2 = cos(x)
line1, = plt.plot(x, y1, 'r')
xvals = range(-6, 6, 2);
for i in xvals:
time.sleep(1)
# update data
plt.vlines(i, -1, 1, linestyles = 'solid', color= 'red')
plt.draw()
If I understood well, you want to use the animation tools of matplotlib. An example (adapted from the doc):
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
X_MIN = -6
X_MAX = 6
Y_MIN = -1
Y_MAX = 1
X_VALS = range(X_MIN, X_MAX+1) # possible x values for the line
def update_line(num, line):
i = X_VALS[num]
line.set_data( [i, i], [Y_MIN, Y_MAX])
return line,
fig = plt.figure()
x = np.arange(X_MIN, X_MAX, 0.1);
y = np.sin(x)
plt.scatter(x, y)
l , v = plt.plot(-6, -1, 6, 1, linewidth=2, color= 'red')
plt.xlim(X_MIN, X_MAX)
plt.ylim(Y_MIN, Y_MAX)
plt.xlabel('x')
plt.ylabel('y = sin(x)')
plt.title('Line animation')
line_anim = animation.FuncAnimation(fig, update_line, len(X_VALS), fargs=(l, ))
#line_anim.save('line_animation.gif', writer='imagemagick', fps=4);
plt.show()
Resulting gif looks like this:
Could you try calling plt.draw after plt.vlines? plt.draw is used to interactively redraw the figure after its been modified.