How to add hovering annotations with multiple curves - python

I am using matplotlib to plot multiple curves (time series) in one plot. To do this, I use a for loop as seen below.
%matplotlib
for i in range(0, len(force)):
plt.plot(distance, (force[i]), alpha=0.1)
plt.xlabel('Distance [mm]', fontsize=12)
plt.ylabel('Force [N]', fontsize=12)
Unfortunately, with the number of curves (approx. 70) that I have, the plot would be unreadable if I labeled each curve. Does anyone know of a way to create labels that only appear when the cursor hovers in the vicinity of that curve (timeseries)?
I looked on the example from this post, but have no clue how to adapt it to my issue:
Possible to make labels appear when hovering over a point in matplotlib?

You could use mplcursors. Each curve can have a unique label, which is shown by default.
from matplotlib import pyplot as plt
import mplcursors
import numpy as np
force = np.random.randn(70, 100).cumsum(axis=1)
force -= force.mean(axis=1, keepdims=True)
plt.figure(figsize=(12, 5))
for i in range(len(force)):
plt.plot(force[i], alpha=0.2, label=f'force[{i}]')
plt.margins(x=0.01)
cursor = mplcursors.cursor(hover=True)
plt.show()
If you're working with a Jupyter notebook, you might need %matplotlib nbagg or %matplotlib qt instead of %matplotlib inline to enable interactivity.

Related

Moving labels on a treemap Matplotlib squarify

I have a treemap that has small enough sections that the labels overlap. Is there any way to move the labels for sections under size=4 (or something around that) to either outside of the plot with an arrow pointing to it, or into a small legend only containing the labels for the small portions?
The treemap generated and code is below.
import squarify #pip install squarify
import matplotlib.pyplot as plt
labels=["longlabel1","longlabel2","longlabel3","longlabel4","longlabel5","longlabel6","longlabel7","longlabel8","longlabel9","longlabel10","longlabel11","longlabel12",]
sizes=[1.8,1.3,10.5,13.8,7.8,6.7,9.9,12.2,12.7,10.9,7.6,4.8]
x=dict(zip(labels,sizes))
sortedDict=dict(sorted(x.items(),key=lambda item:item[1],reverse=True))
squarify.plot(sizes=list(sortedDict.values()),color=['red','blue','cyan','black','gray','green'],label=list(iter(sortedDict)),alpha=.8)
plt.axis('off')
plt.show
Maybe you can use the matplotlib-extra package, which includes a treemap function to plot a hierarchical treemap.
For your case, it's simple:
import matplotlib.pyplot as plt
import mpl_extra.treemap as tr
labels=["longlabel1","longlabel2","longlabel3","longlabel4","longlabel5",
"longlabel6","longlabel7","longlabel8","longlabel9","longlabel10",
"longlabel11","longlabel12",]
sizes=[1.8,1.3,10.5,13.8,7.8,6.7,9.9,12.2,12.7,10.9,7.6,4.8]
fig, ax = plt.subplots(figsize=(7,7), dpi=100, subplot_kw=dict(aspect=1.156))
tr.treemap(ax, sizes, labels=labels,
fill=labels, cmap=['red','blue','cyan','black','gray','green'],
rectprops=dict(ec='w'),
textprops=dict(c='w'))
ax.axis('off')
The following is the obtained figure:

How to update projection of GeoAxes using Cartopy?

I'm trying to make a somewhat interactive map plot with matplotlib utilizing a button added to the toolbar in Matplotlib's navigation Toolbar.
The objective:
The objective that I'm trying to achieve is to be able to change the axes projection on the fly without creating a new axes. There are many methods in the axes object that gets created by Matplotlib to change other aspects of the plot, but I want to be able to change projection from say,
PlateCarree to NorthPolarStereo and vice versa.
Some Source:
import os
import sys
import matplotlib.pyplot as plt
import matplotlib
import mpl_toolkits
import numpy as np
import cartopy
import cartopy.crs as ccrs
fig = plt.figure()
ax = plt.axes(projection=ccrs.NorthPolarStereo())
ax.stock_img()
ny_lon, ny_lat = -75, 43
delhi_lon, delhi_lat = 77.23, 28.61
plt.plot([ny_lon, delhi_lon], [ny_lat, delhi_lat],
color='blue', linewidth=2, marker='o',
transform=ccrs.Geodetic(),
)
plt.plot([ny_lon, delhi_lon], [ny_lat, delhi_lat],
color='gray', linestyle='--',
transform=ccrs.PlateCarree(),
)
ax.add_patch(matplotlib.patches.Polygon([[0,0],[20,0],[20,20],[0,20]],
fill = False,color='g',ls='--',
transform=ccrs.PlateCarree()))
ax.add_patch(matplotlib.patches.Circle([30,30],radius=10,color='g',ls='--',
transform=ccrs.PlateCarree()))
plt.text(ny_lon - 3, ny_lat - 12, 'New York',
horizontalalignment='right',
transform=ccrs.Geodetic())
plt.text(delhi_lon + 3, delhi_lat - 12, 'Delhi',
horizontalalignment='left',
transform=ccrs.Geodetic())
# ax.set_extent([-180,180,-90,90])
ax.set_global()
The problem:
As can be seen, the axes is created with a projection = ccrs.NorthPolarStereo().
The projection of the axes can be obtained by executing the following:
ax.projection
Then, I try setting the projection to ccrs.PlateCarree()
ax.projection = ccrs.PlateCaree()
This alone does not update the plot, however. I have noticed that in editing some of the properties you need to draw the canvas again with
ax.figure.canvas.draw()
however, this doesn't seem to have an effect. But if I do
ax.set_global()
to set the extent to the maximum, the axes updates and changes to the correct projection... however, the data on the plot does not get updated again. Yet calling
ax.projection
indicates that the projection is now a PlateCarree projection.
How can I update the children of the axes to reflect this new projection?
I have tried
ax.update(ax.properties())
as per the matplotlib dox, however, it throws an error.
Any Ideas?
Edit:
If it is not obvious... You will need to run this in an iPython console and run those extra commands while the figure is open in order to edit it. And it must be done this way in order to achieve what I want to do. I know I can just make a new axes with a new projection, however, the end goal of this project is to maintain this axes. This is for editing and different viewing purposes that my project requires. Also, I'm stuck using matplotlib and cartopy, so no new library recommendations for plotting, please.
In reading this question I notice that I use 'however' way too often.

How to suppress seaborn output when recalling figure object with regplot

I am trying to plot data to a figure and respective axis in matplotlib and as new work comes up, recall the figure with the additional plot on the axis:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
x=np.arange(0,20)
y=2*x
fig,ax=plt.subplots()
ax.scatter(x,x)
ax.scatter(x,y)
fig
Which works fine with matplotlib, if I however use seaborn's regplot:
fig2,ax2=plt.subplots()
sns.regplot(x,x,ax=ax2,fit_reg=False)
sns.regplot(x,y,ax=ax2,fit_reg=False)
fig2
fig2 generates the figure that I want but the regplot command generates an empty figure. Is there a way to suppress the regplot's empty output or have it display the updated ax2 without recalling fig2?
It seems you are using the jupyter notebook with the inline backend. In some circumstances regplot triggers the creation of a new figure even if the artists are being added to the previous one and this messes up the output. I don't know why this happens but I found a workaround that might help you, using plt.ioff to temporarily disable automatic display of figures.
plt.ioff()
fig, ax = plt.subplots()
sns.regplot(x, x, ax=ax)
fig
sns.regplot(x, 2 * x, ax=ax)
fig
You have to call plt.ioff before creating the figure for this to work. After that you have to explicitly display the figure. Then you can call plt.ion to restore the default behaviour.
regplot does not generate an empty figure. According to the documentation:
Understanding the difference between regplot() and lmplot() can be a
bit tricky. In fact, they are closely related, as lmplot() uses
regplot() internally and takes most of its parameters. However,
regplot() is an axes-level function, so it draws directly onto an axes
(either the currently active axes or the one provided by the ax
parameter), while lmplot() is a figure-level function and creates its
own figure, which is managed through a FacetGrid.
When I do the following:
fig2,ax2 = plt.subplots()
same_fig2 = sns.regplot(x,x,ax=ax2,fit_reg=False)
same_fig2.figure is fig2
>>> True

issue in using tooltip in scatter plot through mpld3 in ipython and Spark

I have a RDD which has studentid and their scores:
Student_record = data.map(lambda x:x[0]).zip(score)
I then display the scores on a scatter plot using mpld3.
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
import mpld3
fig, ax = plt.subplots()
x = np.arange(1,score.count()+1,1)
ax.scatter(x, predict, c='red', s=100, alpha=0.4)
ax.grid(color='lightgray', alpha=0.7)
ax.set_ylabel("score")
ax.set_xlabel("student")
mpld3.display(fig)
What I have been trying to do is to include a tooltip functionality such that when my mouse hovers over a particular score point on the plot it shows the studentid whose score it is. I was going through this documentation, which uses tooltip to shows that when the mouse hovers over a point it displays the point number, but I am having difficulty in understanding how to do it in my case. How can I get this hover functionality added to my current code?
The Scatter Plot With Tooltips example seems like just the thing for you. Just change the last line from mpld3.show() to mpld3.display() to get it inline in the IPython notebook.

Second y-axis label getting cut off

I'm trying to plot two sets of data in a bar graph with matplotlib, so I'm using two axes with the twinx() method. However, the second y-axis label gets cut off. I've tried a few different methods with no success (tight_layout(), setting the major_pads in rcParams, etc...). I feel like the solution is simple, but I haven't come across it yet.
Here's a MWE:
#!/usr/bin/env python
import numpy as np
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
matplotlib.rcParams.update({'font.size': 21})
ax = plt.gca()
plt.ylabel('Data1') #Left side
ax2 = ax.twinx()
for i in range(10):
if(i%2==0):
ax.bar(i,np.random.randint(10))
else:
ax2.bar(i,np.random.randint(1000),color='k')
plt.ylabel('Data2') #Right
side
plt.savefig("test.png")
I just figured it out: the trick is to use bbox_inches='tight' in savefig.
E.G. plt.savefig("test.png",bbox_inches='tight')
I encountered the same issue which plt.tight_layout() did not automatically solve.
Instead, I used the labelpad argument in ylabel/set_ylabel as such:
ax.set_ylabel('label here', rotation=270, color='k', labelpad=15)
I guess this was not implemented when you asked this question, but as it's the top result on google, hopefully it can help users of the current matplotlib version.

Categories

Resources