Related
How to add two sets of arrows with different colours, please? I obtained just green arrows. Are red arrows overplotted? How to suppress that?
When I comment the part between ###, I have red arrows.
The desired result is to have both arrows - red and green.
Thank you
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
d = {'a': [1, 2, 2], 'b': [3, 5, 4], 'c': [0.1, 0.2, 0.6]}
df = pd.DataFrame(data=d)
fig = px.scatter(df, x='a', y='b', error_y='c')
fig.update_xaxes(title_font_family="Trebuchet")
fig.update_layout(yaxis=dict(scaleanchor="x", scaleratio=1),
template = "plotly_white",
title="<b>V</b>",
)
fig.update_layout(xaxis = dict(autorange="reversed"))
x_end = [1, 2, 2]
y_end = [3, 5, 4]
x_start = [0, 1, 3]
y_start = [4, 4, 4]
list_of_all_arrows = []
for x0,y0,x1,y1 in zip(x_end, y_end, x_start, y_start):
arrow = go.layout.Annotation(dict(
x=x0,
y=y0,
xref="x", yref="y",
text="",
showarrow=True,
axref="x", ayref='y',
ax=x1,
ay=y1,
arrowhead=3,
arrowwidth=1.5,
arrowcolor='rgb(255,51,0)',)
)
list_of_all_arrows.append(arrow)
fig.update_layout(annotations=list_of_all_arrows)
###
list_of_all_arrows2 = []
for x0,y0,x1,y1 in zip([i-2 for i in x_end], [i-3 for i in y_end], x_start, y_start):
arrow = go.layout.Annotation(dict(
x=x0,
y=y0,
xref="x", yref="y",
text="",
showarrow=True,
axref="x", ayref='y',
ax=x1,
ay=y1,
arrowhead=3,
arrowwidth=1.5,
arrowcolor='green',)
)
list_of_all_arrows2.append(arrow)
fig.update_layout(annotations=list_of_all_arrows2)
###
# fig.write_html("Fig.html")
fig.show()
The origin of the problem is that in the background figures in plotly are dictionaries. The fact that you are calling two times fig.update_layout(annotations=list_anotation) updates figure's dictionary annotations entry. To check the dictionary of a figure just print the figure print(fig), there you can see the key layout and sub key annotations.
Therefore only calling one the function update_layout works as you want.
Step1: delete this line
fig.update_layout(annotations=list_of_all_arrows) # delete this line
Step2: change last line
fig.update_layout(annotations=list_of_all_arrows2 + list_of_all_arrows)
this is equivalent to appending all arrows to a single list
Total code
import plotly.express as px
import numpy as np
import pandas as pd
import plotly.graph_objects as go
d = {'a': [1, 2, 2], 'b': [3, 5, 4], 'c': [0.1, 0.2, 0.6]}
df = pd.DataFrame(data=d)
fig = px.scatter(df, x='a', y='b', error_y='c')
fig.update_xaxes(title_font_family="Trebuchet")
fig.update_layout(yaxis=dict(scaleanchor="x", scaleratio=1),
template = "plotly_white",
title="<b>V</b>",
)
fig.update_layout(xaxis = dict(autorange="reversed"))
x_end = [1, 2, 2]
y_end = [3, 5, 4]
x_start = [0, 1, 3]
y_start = [4, 4, 4]
list_of_all_arrows = []
for x0,y0,x1,y1 in zip(x_end, y_end, x_start, y_start):
arrow = go.layout.Annotation(dict(
x=x0,
y=y0,
xref="x", yref="y",
text="",
showarrow=True,
axref="x", ayref='y',
ax=x1,
ay=y1,
arrowhead=3,
arrowwidth=1.5,
arrowcolor='rgb(255,51,0)',)
)
list_of_all_arrows.append(arrow)
list_of_all_arrows2 = []
for x0,y0,x1,y1 in zip([i-2 for i in x_end], [i-3 for i in y_end], x_start, y_start):
arrow = go.layout.Annotation(dict(
x=x0,
y=y0,
xref="x", yref="y",
text="",
showarrow=True,
axref="x", ayref='y',
ax=x1,
ay=y1,
arrowhead=3,
arrowwidth=1.5,
arrowcolor='green',)
)
list_of_all_arrows2.append(arrow)
fig.update_layout(annotations=list_of_all_arrows2 + list_of_all_arrows)
The final plot
I would like to utilize a tkinter window with integrated matplotlib graphs that cycle every x seconds. However, this is what I have and I am stuck. Any help would be greatly appreciated. Thank you!
import time
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import tkinter as tk
root = tk.Tk()
root.geometry('500x500')
x = [1, 2, 3, 4, 5]
y = [[3, 6, 1, 9, 2], [2, 0, 1, 4, 6], [6, 3, 8, 2, 0]]
fig = plt.figure(figsize=(5,5))
i = 0
while i < len(y):
plt.plot(x, y[i])
canvas = FigureCanvasTkAgg(fig, master=root)
canvas.draw()
canvas.get_tk_widget().pack()
time.sleep(1)
plt.clf()
i += 1
root.mainloop()
What you're looking for is after(). You'll likely have an easier time if you wrap everything up in a simple Root class, so I've done that here.
# imports go here as usual...
class Root(tk.Tk):
def __init__(self):
super().__init__() # init tk.Tk()
self.geometry('500x500')
self.x = [1, 2, 3, 4, 5]
self.y = [[3, 6, 1, 9, 2], [2, 0, 1, 4, 6], [6, 3, 8, 2, 0]]
self.fig = plt.figure(figsize=(5, 5))
# set up the canvas
self.canvas = FigureCanvasTkAgg(fig, master=root)
self.canvas.get_tk_widget().pack()
# begin cycling plots, starting with index 0
self.index = 0
self.cycle_plots(self.index)
def cycle_plots(self, index):
plt.clf # clear plot here
self.index += 1 # go to the next index
if self.index >= len(self.y):
self.index = 0 # wrap around
plt.plot(self.x, self.y[self.index])
self.canvas.draw() # update the canvas
# after 1000mS, call this function again
self.after(1000, lambda i=self.index: self.cycle_plots(i))
if __name__ == '__main__': # run the app!
root = Root()
root.mainloop()
Using a class makes it easier to pass your UI objects - like the Canvas - around between functions (methods). Here, self refers to your Root class, so anything inside it can share variables with self.<varname>, like self.canvas
How Can i make this image stretchable using mouse event in matplotlib. please help.
Here the code:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as image
from matplotlib.offsetbox import OffsetImage, AnnotationBbox
fig = plt.figure()
X = [1, 2, 3, 4, 5, 6, 7]
Y = [1, 3, 4, 2, 5, 8, 6]
mainaxes = fig.add_axes([0.1, 0.1, 0.8, 0.8]) # main axes
img = image.imread('https://upload.wikimedia.org/wikipedia/commons/7/70/Example.png')
z = 0.3 + 0.3
imagebox = OffsetImage(img, zoom=z)
imgbox = AnnotationBbox(imagebox, (0.3,0.5), frameon=True)
mainaxes.add_artist(imgbox)
imgbox.draggable()
plt.show()
I have the following data frame my_df:
my_1 my_2 my_3
--------------------------------
0 5 7 4
1 3 5 13
2 1 2 8
3 12 9 9
4 6 1 2
I want to make a plot where x-axis is categorical values with my_1, my_2, and my_3. y-axis is integer. For each column in my_df, I want to plot all its 5 values at x = my_i. What kind of plot should I use in matplotlib? Thanks!
You could make a bar chart:
import pandas as pd
import matplotlib.pyplot as plt
df = pd.DataFrame({'my_1': [5, 3, 1, 12, 6], 'my_2': [7, 5, 2, 9, 1], 'my_3': [4, 13, 8, 9, 2]})
df.T.plot(kind='bar')
plt.show()
or a scatter plot:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
df = pd.DataFrame({'my_1': [5, 3, 1, 12, 6], 'my_2': [7, 5, 2, 9, 1], 'my_3': [4, 13, 8, 9, 2]})
fig, ax = plt.subplots()
cols = np.arange(len(df.columns))
x = np.repeat(cols, len(df))
y = df.values.ravel(order='F')
color = np.tile(np.arange(len(df)), len(df.columns))
scatter = ax.scatter(x, y, s=150, c=color)
ax.set_xticks(cols)
ax.set_xticklabels(df.columns)
cbar = plt.colorbar(scatter)
cbar.set_ticks(np.arange(len(df)))
plt.show()
Just for fun, here is how to make the same scatter plot using Pandas' df.plot:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
df = pd.DataFrame({'my_1': [5, 3, 1, 12, 6], 'my_2': [7, 5, 2, 9, 1], 'my_3': [4, 13, 8, 9, 2]})
columns = df.columns
index = df.index
df = df.stack()
df.index.names = ['color', 'column']
df = df.rename('y').reset_index()
df['x'] = pd.Categorical(df['column']).codes
ax = df.plot(kind='scatter', x='x', y='y', c='color', colorbar=True,
cmap='viridis', s=150)
ax.set_xticks(np.arange(len(columns)))
ax.set_xticklabels(columns)
cbar = ax.collections[-1].colorbar
cbar.set_ticks(index)
plt.show()
Unfortunately, it requires quite a bit of DataFrame manipulation just to call
df.plot and then there are some extra matplotlib calls needed to set the tick
marks on the scatter plot and colorbar. Since Pandas is not saving effort here,
I would go with the first (NumPy/matplotlib) approach shown above.
I'm exploring the bokeh library.
I tried to add several plots to each tab using VBox, but it did not work.
I read somewhere that tabs & VBox/HBox cannot be used together.
How do I handle the layout on the tabs then?
Modified example to add several elements per tab:
from bokeh.models.widgets import Panel, Tabs
from bokeh.io import output_file, show
from bokeh.plotting import figure
from bokeh.models.widgets.layouts import VBox
output_file("slider.html")
p1 = figure(plot_width=300, plot_height=300)
p1.circle([1, 2, 3, 4, 5], [6, 7, 2, 4, 5], size=20, color="navy", alpha=0.5)
p2 = figure(plot_width=300, plot_height=300)
p2.line([1, 2, 3, 4, 5], [6, 7, 2, 4, 5], line_width=3, color="navy", alpha=0.5)
p=VBox(p1,p2)
tab1 = Panel(child=p,title="circle")
tab2 = Panel(child=p2, title="line")
tabs = Tabs(tabs=[ tab1, tab2 ])
show(tabs)
Example from the website:
from bokeh.models.widgets import Panel, Tabs
from bokeh.io import output_file, show
from bokeh.plotting import figure
output_file("slider.html")
p1 = figure(plot_width=300, plot_height=300)
p1.circle([1, 2, 3, 4, 5], [6, 7, 2, 4, 5], size=20, color="navy", alpha=0.5)
tab1 = Panel(child=p1, title="circle")
p2 = figure(plot_width=300, plot_height=300)
p2.line([1, 2, 3, 4, 5], [6, 7, 2, 4, 5], line_width=3, color="navy", alpha=0.5)
tab2 = Panel(child=p2, title="line")
tabs = Tabs(tabs=[ tab1, tab2 ])
show(tabs)
I'm not sure about using HBox and VBox with Tabs, but you can use layout to arrange things in tabs, it has worked well for me and I think is a bit more flexible than the other options. Here's a quick example I think works:
from bokeh.layouts import layout
from bokeh.models.widgets import Tabs, Panel
from bokeh.io import curdoc
from bokeh.plotting import figure
fig1 = figure()
fig1.circle([0,1,2],[1,3,2])
fig2 = figure()
fig2.circle([0,0,2],[4,-1,1])
fig3 = figure()
fig3.circle([0,4,3],[1,2,0])
l1 = layout([[fig1, fig2]], sizing_mode='fixed')
l2 = layout([[fig3]],sizing_mode='fixed')
tab1 = Panel(child=l1,title="This is Tab 1")
tab2 = Panel(child=l2,title="This is Tab 2")
tabs = Tabs(tabs=[ tab1, tab2 ])
curdoc().add_root(tabs)
I found the movies example very useful for all sorts of stuff, the code for which is here, and well worth a look.