How to add a hovering annotation on a bar plot with mplcursors - python-3.x

How can I modify this plot to show me the value of each bar upon hovering mouse?
sns.barplot(x = "date", y = "no_of_dogs", data = dogs_adopted_per_day, palette="husl")
plt.show()

You could employ mplcursors as follows:
import matplotlib.pyplot as plt
import mplcursors
import numpy as np
import pandas as pd
import seaborn as sns
df = pd.DataFrame({"date": pd.date_range('20210101', periods=10),
"no_of_dogs": np.random.randint(10, 30, 10)})
fig, ax = plt.subplots(figsize=(15, 5))
sns.barplot(x="date", y="no_of_dogs", data=df, palette="husl", ax=ax)
x_dates = df['date'].dt.strftime('%Y-%m-%d')
ax.set_xticklabels(labels=x_dates)
cursor = mplcursors.cursor(hover=True)
#cursor.connect("add")
def on_add(sel):
x, y, width, height = sel.artist[sel.target.index].get_bbox().bounds
sel.annotation.set(text=f"{x_dates[round(x)]}\n{height:.0f}",
position=(0, 20), anncoords="offset points")
sel.annotation.xy = (x + width / 2, y + height)
plt.show()

Related

How do I get matplotlib subplot and GridSpec to position and size subplots as I want them?

I am trying to create a figure with 2x10 subplots. I would like them all to be square with a thin white space in between them, but they are coming out as rectangles (longer in height than width). The images I'm putting in each cell of the grid are all square, but the cell itself is not square so the extra space just becomes white space which creates a giant gap between the top row and the bottom row. Here's the code that shows the rectangles:
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec
from PIL import Image
fig = plt.figure()
gs1 = GridSpec(2, 10)
for a in range(10):
ax = plt.subplot(gs1[0, a])
ax2 = plt.subplot(gs1[1, a])
plt.show()
output from above code
Imagine this but with little to no gaps in between cells and each cell is square instead of rectangular. Thanks in advance for any help!
You can use plt.tight_layout() to clean up your subplot figure. Also, play around with plt.rcParams for the figure size:
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec
from PIL import Image
plt.rcParams["figure.figsize"] = (20,10)
fig = plt.figure()
gs1 = GridSpec(2, 10)
for a in range(10):
ax = plt.subplot(gs1[0, a])
ax2 = plt.subplot(gs1[1, a])
plt.tight_layout()
plt.show()
Output
For more control, you can use fig,ax and turn off all the labels and ticks. Then you can remove the white space between the subplots.
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec
from PIL import Image
plt.rcParams["figure.figsize"] = (20,4)
fig, ax = plt.subplots(2,10)
gs1 = GridSpec(2, 10)
for x in range(2):
for y in range(10):
ax[x,y].plot()
ax[x,y].tick_params(axis = 'both', bottom= False, left = False,
labelbottom = False, labelleft = False)
ax[1,0].tick_params(axis = 'both', bottom= True, left = True,
labelbottom = True, labelleft = True)
plt.subplots_adjust(wspace=0.05, hspace=0.05)
plt.show()
Output:

How to change x,y in plt to lon, lat in cartopy?

I want to change x, y to lon, lat (Picture below yellow marker) when I click some point in map and get x, y.
How can I change it? Help me please...
import cartopy.crs as ccrs
import matplotlib.pyplot as plt
import numpy as np
import cartopy
def mouse_click(event):
x, y = event.xdata, event.ydata
print(x, y)
proj = ccrs.LambertConformal(central_longitude=125, central_latitude=35, false_easting=400000,false_northing=400000,
standard_parallels=(46, 49))
fig = plt.figure(figsize=(16.535433, 11.692913))
ax = fig.add_subplot(1,1,1, projection=proj)
ax.set_extent((79, 156, 10, 66))
gl = ax.gridlines(crs=ccrs.PlateCarree(), draw_labels=False, linewidth=0.2,color='black', alpha=0.5,
linestyle=(3, (20, 5)), xlocs=np.arange(-180, 200, 10), x_inline=False, y_inline=False)
#xlabel_style = {'rotation': 0},ylabel_style = {'rotation': 0})
ax.coastlines(resolution='50m', alpha=1, linewidth=0.5)
ax.add_feature(cartopy.feature.BORDERS, alpha=1,linewidth=0.5)
ax.add_feature(cartopy.feature.LAKES, alpha=0.4)
plt.connect('button_press_event', mouse_click)
plt.show()
I tried to find about it but It's hard to understanding.
I found some way.
Change the projection.
fig = plt.figure()
ax = fig.add_axes([0, 0, 1, 1], projection=ccrs.PlateCarree())
ax.add_feature(cartopy.feature.LAND, facecolor='black')
ax.set_global()
In LambertConformal,x,y is different with lon,lat. But in PlateCarree, they are same.

Matplotlib- Add a color bar below a multi-colored line subplot as shown in the image

I am having a multicolored line plot and I want to add a color bar under it in the same figure like as shown in the image below, Is it possible?
I have attached a color bar image as a reference which I took from another code.
My intention here is to use the color bar like a legend for each segment of the line in the plot.
Edit-1: I want to have the color bar using a mappable object such as an image, So don't want to create a new subplot for the sole purpose of the color bar.
Any suggestion is welcome. Thanks in Advance.
This is the code for multicolored line plot
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection
Segments=[[[3,1],[6,1]],[[6,2],[9,2]],[[9,3],[12,3]],[[12,4],[15,4]], [[12,4],[15,4]]]
Points_1 = np.concatenate([Segments[:-1], Segments[1:]], axis=1)
lc = LineCollection(Points_1, colors=['r','g','b','y'], linewidths=2)
fig, ax = plt.subplots()
ax.add_collection(lc)
ax.autoscale()
plt.show()
This is a workaround I'am using:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection
import matplotlib.colorbar as mcolorbar
import matplotlib.colors as mcolors
Segments=[[[3,1],[6,1]],[[6,2],[9,2]],[[9,3],[12,3]],[[12,4],[15,4]], [[12,4],[15,4]]]
Points_1 = np.concatenate([Segments[:-1], Segments[1:]], axis=1)
lc = LineCollection(Points_1, colors=['r','g','b','y'], linewidths=2)
fig, ax = plt.subplots(2, 1, gridspec_kw={'height_ratios' : [5,1]})
ax[0].add_collection(lc)
bounds = np.linspace(0, 1, 5)[:-1]
labels = ['Action1', 'Action2', 'Action3', 'Action4']
ax[0].set_xlim([0, 15])
ax[0].set_ylim([0, 10])
cb2 = mcolorbar.ColorbarBase(ax = ax[1], cmap = cmap, orientation = 'horizontal', extendfrac='auto')
cb2.set_ticks(bounds)
cb2.set_ticklabels(labels)
plt.tight_layout()
plt.show()
If you specifically want to avoid subplots, you can use a scalar mappable:
fig, ax = plt.subplots()
ax.add_collection(lc)
ax.autoscale()
cmap = mcolors.ListedColormap(['r','g','b','y'])
sm = plt.cm.ScalarMappable(cmap=cmap)
sm.set_array([]) # this line may be ommitted for matplotlib >= 3.1
cbar = fig.colorbar(sm, ax=ax, orientation='horizontal',aspect=90)
bounds = np.linspace(0, 1, 5)[:-1]
labels = ['Action1', 'Action2', 'Action3', 'Action4']
ax.set_xlim([0, 15])
ax.set_ylim([0, 10])
cbar.set_ticks(bounds)
cbar.set_ticklabels(labels)
plt.tight_layout()
plt.show()
This helped me to get what I asked.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
from matplotlib.collections import LineCollection
Segments=[[[3,1],[6,1]],[[6,2],[9,2]],[[9,3],[12,3]],[[12,4],[15,4]], [[12,4],[15,4]]]
Points_1 = np.concatenate([Segments[:-1], Segments[1:]], axis=1)
lc = LineCollection(Points_1, colors=['r','g','b','y'], linewidths=2)
fig, ax = plt.subplots()
ax.add_collection(lc)
ax.autoscale()
c=[1,2,3,4,5]
labels = ['Action1', 'Action2', 'Action3', 'Action4']
cmap = mcolors.ListedColormap(['r','g','b','y'])
norm = mcolors.BoundaryNorm([1,2,3,4,5],4)
sm = plt.cm.ScalarMappable(norm=norm, cmap=cmap)
sm.set_array([]) # this line may be ommitted for matplotlib >= 3.1
cbar=fig.colorbar(sm, ticks=c, orientation='horizontal')
cbar.set_ticklabels(['Action1', 'Action2', 'Action3', 'Action4'])
plt.show()

matplotlib widgets slider on object (Ellipse)

I want that the x-position (=d_in) of my object (the Ellipse) is changed by changing the slider d_in. This is what I got:
from numpy import pi, sin
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider, Button, RadioButtons
from matplotlib.patches import Ellipse
from scipy.optimize import fsolve
import pylab
axis_color = 'lightgoldenrodyellow'
#variable
d_in=80
fig = plt.figure(figsize=(12,6))
ax = fig.add_subplot(111)
fig.subplots_adjust(left=0.25, bottom=0.35)
x = np.arange(0.0, 300, 0.01)
# object ellipse
Spiegel = Ellipse(xy=(d_in, 0), width=2, height=73.2,
edgecolor='black', fc='#808080', lw=1)
ax.add_patch(Spiegel)
#Draw d_in slider
d_in_slider_ax = fig.add_axes([0.25, 0.1, 0.65, 0.03], axisbg=axis_color)
d_in_slider = Slider(d_in_slider_ax, 'd_in', 1, 150, valinit=d_in)
#axis range
ax.set_xlim([0, 300])
ax.set_ylim([-40, 40])
plt.show()
How can I tell the slider to change the position of the Ellipse?
Thank you
You need to register a callback for when the slider values changes,
slider.on_changed(callback)
and inside that callback, update the position of the ellipse
ellipse.center = new_center
Here, this could look as follows
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider
from matplotlib.patches import Ellipse
#variable
d_in=80
fig = plt.figure(figsize=(12,6))
ax = fig.add_subplot(111)
fig.subplots_adjust(left=0.25, bottom=0.35)
x = np.arange(0.0, 300, 0.01)
# object ellipse
Spiegel = Ellipse(xy=(d_in, 0), width=2, height=73.2,
edgecolor='black', fc='#808080', lw=1)
ax.add_patch(Spiegel)
#Draw d_in slider
d_in_slider_ax = fig.add_axes([0.25, 0.1, 0.65, 0.03])
d_in_slider = Slider(d_in_slider_ax, 'd_in', 1, 150, valinit=d_in)
def update(val):
Spiegel.center = (val,0)
d_in_slider.on_changed(update)
#axis range
ax.set_xlim([0, 300])
ax.set_ylim([-40, 40])
plt.show()

How to draw a graph using matplotlib?

draw a graph of equation in the form of y=mx+b in python3.x
example y = 5x + 9
This is a very general question. Try to be more specific. It depends how you want to draw it.
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(0., 5., 0.2)
y = 5 * x + 9
plt.plot(x, y)
plt.show()
or
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(-1., 5., 0.2)
y = 5 * x + 9
fig, ax = plt.subplots()
ax.plot(x,y)
ax.grid(True, which='both')
ax.axhline(y=0, color='k')
ax.axvline(x=0, color='k')
These are very basic drawing. You can create more sophisticated graphs, but you will have to be more specific in your question.
You can define your y(x) function and then plot it as follows:
import matplotlib.pyplot as plt
def y(x):
return [5*i+9 for i in x]
x = range(0,10)
plt.plot(x,y(x))
plt.show()
This produces follwing graph:
With turtle
You can as well get a graph with turtle with following code for example:
from turtle import Turtle, Screen
def y(x):
return 5*x+9
def plotter(turtle, x_range):
turtle.penup()
for x in x_range:
turtle.goto(x, y(x))
turtle.pendown()
screen = Screen()
screen.setworldcoordinates(0, 0, 9, 60)
turtle = Turtle(visible=False)
x = range(0,10)
plotter(turtle, x)
screen.exitonclick()
Which produces:

Resources