Python - MatplotLib - Annotate Last Point - python

Wondering How to add
Marker + Corresponding value to the last point of a series.
To plot my series I use :
var= pd.read_excel("ExcelFilePath")
x = list(var['Date'])
y = list(var['Values'])
plt.plot(x,y,label='blabla')
Which Give (For example) :
How would I get this :

You could use annotate:
import numpy as np
x = np.linspace(0,6.5)
y = np.sin(x)
plt.plot(x,y,label='blabla')
plt.plot(x[-1], y[-1], marker='+')
plt.annotate(f'({x[-1]:.2f}, {y[-1]:.2f})', (x[-1], y[-1]), ha='right')
output:

You could use the Plotly Library for this.
e.g.
import plotly.express as px
df = px.data.gapminder().query("continent == 'Oceania'")
fig = px.line(df, x='year', y='lifeExp', color='country', markers=True)
fig.show()
This will give you an output:

Related

How do I extend/pad a CDF plot (using seaborn.ecdfplot) to the x-axis limits?

This code:
N = 1000
df = pd.DataFrame({
'distribution_1': np.random.randn(N),
'distribution_2': np.random.randn(N)
})
df['distribution_2'] = df['distribution_2'] / 2
df = df.melt(value_vars=['distribution_1', 'distribution_2'], value_name='value', var_name='distribution')
g = sns.ecdfplot(data=df, x='value', hue='distribution')
g.set(ylim=(-.1, 1.1))
yields a figure like this:
The CDFs of both distributions do not extend to the limits of the x-axis. I would like to know how to do this. In ggplot2 there is a boolean flag called pad that does this (see e.g. REF).
This is also possible in seaborn? (I was unable to find it ...)
sns.ecdfplot() doesn't seem to support such an option. As a workaround, you could loop through the generated lines, and move the endpoints. (Also note that sns.ecdfplot doesn't return a FacetGrid, but a subplot. Naming the return value g might be a bit confusing when comparing to code in example and tutorials.)
from matplotlib import pyplot as plt
import seaborn as sns
import numpy as np
import pandas as pd
N = 1000
df = pd.DataFrame({'distribution_1': np.random.randn(N),
'distribution_2': np.random.randn(N) / 2})
df = df.melt(value_vars=['distribution_1', 'distribution_2'], value_name='value', var_name='distribution')
ax = sns.ecdfplot(data=df, x='value', hue='distribution', palette='winter')
ax.set_ylim(-.1, 1.1)
xmin, xmax = ax.get_xlim()
for line in ax.lines:
x = line.get_xdata()
x[0] = xmin
x[-1] = xmax
line.set_xdata(x)
plt.show()

How to show every value in y-axis using Plotly Express?

When I do:
fig = px.line(df, x="day", y="avg_spending")
fig.show()
It doesn't put values in y axis by 2 (0, 2, 4,...). I want it to be 1 by 1 (0,1,2,3,..). My maximum value of "avg_spending" in df is 17, so I would like there to be 1,2,3,...,17 on y axis. How to do that?
set the dtick parameter on the axis
import numpy as np
import pandas as pd
import plotly.express as px
df = pd.DataFrame({"day":range(50),"avg_spending":np.random.randint(1,17,50)})
fig = px.line(df, x="day", y="avg_spending")
fig.update_layout(yaxis={"dtick":1},margin={"t":0,"b":0},height=500)

Subplots in Python with x axis having too large of a jump between values

import matplotlib.pyplot as plt
import numpy as np
delta = 0.0001
t = np.arange(0,5+delta,delta)
xt = np.sin(np.pi*t)
fig = plt.figure(1)
ax1= plt.subplot(3,2,1)
ax1.plot(t,xt, "tab:red")
ax1.set(ylabel = "Amplitude")
ax1.set(xlabel = 'Time(s)')
ax1.set(title = 'for n = 1')
ax1.grid()
ax2 = plt.subplot(3,2,2)
ax2.plot(t,xt, "tab:green")
ax2.set(ylabel = "Amplitude")
ax2.set(xlabel = 'Time(s)')
ax2.set(title = 'for n = 2')
ax2.grid()
plt.tight_layout()
plt.show()
Hi this is just a snip of my code but my problem basically is with the x axis of the subplots.
On the axis the values jump from 0-2-4 and I need it to be from 0-1-2-3-4-5.
Is there a way I can get those values to display on the x axis rather than just 0-2-4.
There are several possible ways of doing this. One of the simplest is to manually set the x ticks.
ax1.set_xticks(np.arange(6))
ax2.set_xticks(np.arange(6))
you can set the locator for x axis.
import matplotlib as mpl
ax1.xaxis.set_major_locator(mpl.ticker.MultipleLocator(1))
ax2.xaxis.set_major_locator(mpl.ticker.MultipleLocator(1))

Value Error when altering x-ticks matplotlib

I am trying to alter the x-ticks on the plot below. When I run the code below I'm getting an error:
ValueError: unit abbreviation w/o a number
I can't seem to find anything on this except it's related to pd.to_timedelta. However, I can't find any solutions on this.
I've upgraded all relevant packs including matplotlib.
import pandas as pd
import matplotlib.pyplot as plt
d = ({
'A' : ['08:00:00','08:10:00','08:12:00','08:26:00','08:29:00','08:31:00','10:10:00','10:25:00','10:29:00','10:31:00'],
'B' : ['1','1','1','2','2','2','7','7','7','7'],
'C' : ['X','Y','Z','X','Y','Z','A','X','Y','Z'],
})
df = pd.DataFrame(data=d)
fig,ax = plt.subplots()
x = df['A']
y = df['B']
x_numbers = (pd.to_timedelta(df['A']).dt.total_seconds())
plt.scatter(x_numbers, y)
xaxis = ax.get_xaxis()
ax.set_xticklabels([str(pd.Timedelta(i.get_text()+' seconds')).split()[2] for i in xaxis.get_majorticklabels()], rotation=45)
plt.show()
Any suggestions? Has anyone come across this?
Based on this SO question and answer, one solution is to trigger axis tick positioning with a call to fig.canvas.draw() after the scatter, but before getting the labels:
[...]
plt.scatter(x_numbers, y)
# draw canvas to trigger tick positioning
fig.canvas.draw()
xaxis = ax.get_xaxis()
[...]
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
d = ({
'A' : ['08:00:00','08:10:00','08:12:00','08:26:00','08:29:00','08:31:00','10:10:00','10:25:00','10:29:00','10:31:00'],
'B' : ['1','1','1','2','2','2','7','7','7','7'],
'C' : ['X','Y','Z','X','Y','Z','A','X','Y','Z'],
})
df = pd.DataFrame(data=d)
x = df['A']
y = df['B']
x_numbers = (pd.to_timedelta(df['A']).dt.total_seconds())
fig, axes = plt.subplots(figsize=(10, 4))
axes.scatter(x_numbers, y)
axes.set_xticks(x_numbers)
axes.set_xticklabels([i+' seconds' for i in df['A'].get_values()], rotation=90)
plt.tight_layout()
output:

How to format axis number format to thousands with a comma

How can I change the format of the numbers in the x-axis to be like 10,000 instead of 10000?
Ideally, I would just like to do something like this:
x = format((10000.21, 22000.32, 10120.54), "#,###")
Here is the code:
import matplotlib.pyplot as plt
# create figure instance
fig1 = plt.figure(1)
fig1.set_figheight(15)
fig1.set_figwidth(20)
ax = fig1.add_subplot(2,1,1)
x = 10000.21, 22000.32, 10120.54
y = 1, 4, 15
ax.plot(x, y)
ax2 = fig1.add_subplot(2,1,2)
x2 = 10434, 24444, 31234
y2 = 1, 4, 9
ax2.plot(x2, y2)
fig1.show()
Use , as format specifier:
>>> format(10000.21, ',')
'10,000.21'
Alternatively you can also use str.format instead of format:
>>> '{:,}'.format(10000.21)
'10,000.21'
With matplotlib.ticker.FuncFormatter:
...
ax.get_xaxis().set_major_formatter(
matplotlib.ticker.FuncFormatter(lambda x, p: format(int(x), ',')))
ax2.get_xaxis().set_major_formatter(
matplotlib.ticker.FuncFormatter(lambda x, p: format(int(x), ',')))
fig1.show()
The best way I've found to do this is with StrMethodFormatter:
import matplotlib as mpl
ax.yaxis.set_major_formatter(mpl.ticker.StrMethodFormatter('{x:,.0f}'))
For example:
import pandas as pd
import requests
import matplotlib.pyplot as plt
import matplotlib as mpl
url = 'https://min-api.cryptocompare.com/data/histoday?fsym=BTC&tsym=USDT&aggregate=1'
df = pd.DataFrame({'BTC/USD': [d['close'] for d in requests.get(url).json()['Data']]})
ax = df.plot()
ax.yaxis.set_major_formatter(mpl.ticker.StrMethodFormatter('{x:,.0f}'))
plt.show()
I always find myself on this same page everytime I try to do this. Sure, the other answers get the job done, but aren't easy to remember for next time! ex: import ticker and use lambda, custom def, etc.
Here's a simple solution if you have an axes named ax:
ax.set_yticklabels(['{:,}'.format(int(x)) for x in ax.get_yticks().tolist()])
Short answer without importing matplotlib as mpl
plt.gca().yaxis.set_major_formatter(plt.matplotlib.ticker.StrMethodFormatter('{x:,.0f}'))
Modified from #AlexG's answer
If you like it hacky and short you can also just update the labels
def update_xlabels(ax):
xlabels = [format(label, ',.0f') for label in ax.get_xticks()]
ax.set_xticklabels(xlabels)
update_xlabels(ax)
update_xlabels(ax2)
You can use matplotlib.ticker.funcformatter
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as tkr
def func(x, pos): # formatter function takes tick label and tick position
s = '%d' % x
groups = []
while s and s[-1].isdigit():
groups.append(s[-3:])
s = s[:-3]
return s + ','.join(reversed(groups))
y_format = tkr.FuncFormatter(func) # make formatter
x = np.linspace(0,10,501)
y = 1000000*np.sin(x)
ax = plt.subplot(111)
ax.plot(x,y)
ax.yaxis.set_major_formatter(y_format) # set formatter to needed axis
plt.show()
x = [10000.21, 22000.32, 10120.54]
You could use a list comprehension to make a list of labels, and then pass them the plt.xticks.
xlabels = [f'{label:,}' for label in x]
plt.xticks(x, xlabels)
If you want original values to appear in ticks, use
plt.xticks(ticks=plt.xticks()[0], labels=plt.xticks()[0])
This will prevent abbreviations like from 3000000 to 1.3 e5 etc. and will show 3000000 (the exact value) in ticks.
Easiest way in my opinion:
current_values = plt.gca().get_yticks()
plt.gca().set_yticklabels(['{:,.0f}'.format(x) for x in current_values])
From:
https://queirozf.com/entries/matplotlib-examples-number-formatting-for-axes-labels
For non-comma separators, improving the accepted answer, below answer will use SEP as the separator.
SEP = '.'
ax.get_yaxis().set_major_formatter(
matplotlib.ticker.FuncFormatter(
lambda x, p: str.replace(format(int(x), ','), ',', SEP)
)
)

Categories

Resources