MatPlotLib Dollar Sign with Thousands Comma Tick Labels - python-3.x

Given the following bar chart:
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
df = pd.DataFrame({'A': ['A', 'B'], 'B': [1000,2000]})
fig, ax = plt.subplots(1, 1, figsize=(2, 2))
df.plot(kind='bar', x='A', y='B',
align='center', width=.5, edgecolor='none',
color='grey', ax=ax)
plt.xticks(rotation=25)
plt.show()
I'd like to display the y-tick labels as thousands of dollars like this:
$2,000
I know I can use this to add a dollar sign:
import matplotlib.ticker as mtick
fmt = '$%.0f'
tick = mtick.FormatStrFormatter(fmt)
ax.yaxis.set_major_formatter(tick)
...and this to add a comma:
ax.get_yaxis().set_major_formatter(
mtick.FuncFormatter(lambda x, p: format(int(x), ',')))
...but how do I get both?
Thanks in advance!

You can use StrMethodFormatter, which uses the str.format() specification mini-language.
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.ticker as mtick
df = pd.DataFrame({'A': ['A', 'B'], 'B': [1000,2000]})
fig, ax = plt.subplots(1, 1, figsize=(2, 2))
df.plot(kind='bar', x='A', y='B',
align='center', width=.5, edgecolor='none',
color='grey', ax=ax)
fmt = '${x:,.0f}'
tick = mtick.StrMethodFormatter(fmt)
ax.yaxis.set_major_formatter(tick)
plt.xticks(rotation=25)
plt.show()

You can also use the get_yticks() to get an array of the values displayed on the y-axis (0, 500, 1000, etc.) and the set_yticklabels() to set the formatted value.
df = pd.DataFrame({'A': ['A', 'B'], 'B': [1000,2000]})
fig, ax = plt.subplots(1, 1, figsize=(2, 2))
df.plot(kind='bar', x='A', y='B', align='center', width=.5, edgecolor='none',
color='grey', ax=ax)
--------------------Added code--------------------------
# getting the array of values of y-axis
ticks = ax.get_yticks()
# formatted the values into strings beginning with dollar sign
new_labels = [f'${int(amt)}' for amt in ticks]
# Set the new labels
ax.set_yticklabels(new_labels)
-------------------------------------------------------
plt.xticks(rotation=25)
plt.show()

Related

Change orientation of one of Y axis of a HConcat

For the below HConcat charts, I want to change the orientation of y2 to be on the right hand side. Could you please help.
import altair as alt
import pandas as pd
x = ['a', 'b']
y1 = [10, 20]
y2 = [12, 15]
df = pd.DataFrame({'x':x,'y1':y1, 'y2':y2})
Chart1 = alt.Chart(df).mark_bar().encode(
alt.X('x'),
alt.Y('y1')
)
Chart2 = alt.Chart(df).mark_bar().encode(
alt.X('x'),
alt.Y('y2')
)
Chart1|Chart2
Result
Both Y axes on left side
Expected:
y1 on left and y2 on right
You can orient the axis of the second plot to the right with:
import altair as alt
import pandas as pd
x = ['a', 'b']
y1 = [10, 20]
y2 = [12, 15]
df = pd.DataFrame({'x':x,'y1':y1, 'y2':y2})
Chart1 = alt.Chart(df).mark_bar().encode(
alt.X('x'),
alt.Y('y1')
)
Chart2 = alt.Chart(df).mark_bar().encode(
alt.X('x'),
alt.Y('y2', axis=alt.Axis(orient="right")),
)
Chart1|Chart2

How to set markers with errorbars in different colours?

How to:
display symbols in the legend
colour markers in the same way as the errorbars (argument color gives an error: ValueError: RGBA sequence should have length 3 or 4
remove connecting lines - get only the scatter with errorbars
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.lines import Line2D # for legend handle
fig, ax = plt.subplots(figsize = (10,10))
times = [1, 2, 3, 4, 5]
rvs = [2, 4, 2, 4, 7]
sigma = [0.564, 0.6, 0.8, 0.8, 0.4]
rv_telescopes = ['A', 'B', 'A', 'C', 'C']
d = {'rv_times': times, 'rv_rvs': rvs, 'rv_sigma': sigma, 'rv_telescopes': rv_telescopes }
df = pd.DataFrame(data=d)
colors = {'A':'#008f00', 'B':'#e36500', 'C':'red'}
plt.errorbar(df['rv_times'], df['rv_rvs'], df['rv_sigma'], marker = '_', ecolor = df['rv_telescopes'].map(colors), color = df['rv_telescopes'].map(colors), zorder = 1, ms = 30)
handles = [Line2D([0], [0], marker='_', color='w', markerfacecolor=v, label=k, markersize=10) for k, v in colors.items()]
ax.legend(handles=handles, loc='upper left', ncol = 2, fontsize=14)
plt.show()
After edit
import matplotlib.pyplot as plt
from matplotlib.lines import Line2D # for legend handle
import pandas as pd
import numpy as np
times = [1, 2, 3, 4, 5]
rvs = [2, 4, 2, 4, 7]
sigma = [0.564, 0.6, 0.8, 0.8, 0.4]
rv_telescopes = ['A', 'B', 'A', 'C', 'C']
d = {'rv_times': times, 'rv_rvs': rvs, 'rv_sigma': sigma, 'rv_telescopes': rv_telescopes}
df = pd.DataFrame(data=d)
colors = {'A': '#008f00', 'B': '#e36500', 'C': 'red'}
fig, ax = plt.subplots(figsize=(10, 10))
ax.errorbar(df['rv_times'], df['rv_rvs'], df['rv_sigma'], color='none', ecolor=df['rv_telescopes'].map(colors) ,linewidth=1)
ax.scatter(df['rv_times'], df['rv_rvs'], marker='_', linewidth=3, color=df['rv_telescopes'].map(colors), s=1000)
for rv_teles in np.unique(df['rv_telescopes']):
color = colors[rv_teles]
df1 = df[df['rv_telescopes'] == rv_teles] # filter out rows corresponding to df['rv_telescopes']
ax.errorbar(df1['rv_times'], df1['rv_rvs'], df1['rv_sigma'],
color=color, ls='', marker='_', ms=30, linewidth=3, label=rv_teles)
ax.legend(loc='upper left', ncol=1, fontsize=14)
plt.show()
plt.errorbar() works very similar to plt.plot() with extra parameters. As such, it primarily draws a line graph, using a single color. The error bars can be given individual colors via the ecolor= parameter. The markers, however, get the same color as the line graph. The line graph can be suppressed via an empty linestyle. On top of that, plt.scatter() can draw markers with individual colors.
In order not the mix the 'object-oriented' with the 'functional interface', the following example code uses ax.errorbar() and ax.scatter().
import matplotlib.pyplot as plt
from matplotlib.lines import Line2D # for legend handle
import pandas as pd
import numpy as np
times = [1, 2, 3, 4, 5]
rvs = [2, 4, 2, 4, 7]
sigma = [0.564, 0.6, 0.8, 0.8, 0.4]
rv_telescopes = ['A', 'B', 'A', 'C', 'C']
d = {'rv_times': times, 'rv_rvs': rvs, 'rv_sigma': sigma, 'rv_telescopes': rv_telescopes}
df = pd.DataFrame(data=d)
colors = {'A': '#008f00', 'B': '#e36500', 'C': 'red'}
fig, ax = plt.subplots(figsize=(10, 10))
ax.errorbar(df['rv_times'], df['rv_rvs'], df['rv_sigma'], color='none', ecolor=df['rv_telescopes'].map(colors))
ax.scatter(df['rv_times'], df['rv_rvs'], marker='_', color=df['rv_telescopes'].map(colors), s=100)
handles = [Line2D([0], [0], linestyle='', marker='_', color=v, label=k, markersize=10) for k, v in colors.items()]
ax.legend(handles=handles, loc='upper left', ncol=1, fontsize=14)
plt.show()
A far easier approach would be to call ax.errorbar() multiple times, once for each color. This would automatically create appropriate legend handles:
for rv_teles in np.unique(df['rv_telescopes']):
color = colors[rv_teles]
df1 = df[df['rv_telescopes'] == rv_teles] # filter out rows corresponding to df['rv_telescopes']
ax.errorbar(df1['rv_times'], df1['rv_rvs'], df1['rv_sigma'],
color=color, ls='', marker='_', ms=30, label=rv_teles)
ax.legend(loc='upper left', ncol=1, fontsize=14)
plt.show()

python saborn.heatmap annotation as symbols

I want heatmap annotation as symbols. '*' at place of 1 and blank at 0.
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
x = pd.DataFrame({'a':[1,0,1,0]})
fig, (ax) = plt.subplots(ncols=1)
sns.heatmap(x, cmap="BuPu",annot=True,fmt='g',annot_kws={'size':10},ax=ax, yticklabels=[], cbar=False, linewidths=.5,robust=True, vmin=0, vmax=1)
plt.show()
The heatmap can only annotate with numbers. To put other text (or unicode symbols), ax.text can be used. The center of each cell is at 0.5 added to both the row and the column number.
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
x = pd.DataFrame({'a': [1, 0, 1, 0], 'b': [1, 1, 0, 1], 'c': [0, 1, 0, 0]})
fig, (ax) = plt.subplots(ncols=1)
sns.heatmap(x, cmap="BuPu", annot=False, ax=ax, yticklabels=[], cbar=False, linewidths=.5)
for i, c in enumerate(x.columns):
for j, v in enumerate(x[c]):
if v == 1:
ax.text(i + 0.5, j + 0.5, '★', color='gold', size=20, ha='center', va='center')
plt.show()

Categorical x-axis errorbar plot in matplotlib

I'd like to plot errorbars with categorical X variable. The error bars (upper and lower) are on Y values only.
For example, the code
import numpy as np
import matplotlib.pyplot as plt
x = ["4", "10", "50"]
y = [3, 2, 1]
yerr = np.matrix([[1.5, 1.1, 0.9], [1.3, 1.2, 0.8]])
fig, ax = plt.subplots(1, 1)
ax.errorbar(x, y, yerr=yerr)
plt.show()
plt.close()
gives the following error:
ValueError: In safezip, len(args[0])=3 but len(args[1])=1
The error you get has nothing to do with categorical axis.
You just cannot use a matrix. Use a numpy array,
yerr = np.array([[1.5, 1.1, 0.9], [1.3, 1.2, 0.8]])
or simply a list, there is no need to use numpy here,
yerr = [[1.5, 1.1, 0.9], [1.3, 1.2, 0.8]]

How to add column next to Seaborn heat map

Given the code below, which produces a heat map, how can I get column "D" (the total column)
to display as a column to the right of the heat map with no color, just aligned total values per cell? I'm also trying to move the labels to the top. I don't mind that the labels on the left are horizontal as this does not occur with my actual data.
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
%matplotlib inline
df = pd.DataFrame(
{'A' : ['A', 'A', 'B', 'B','C', 'C', 'D', 'D'],
'B' : ['A', 'B', 'A', 'B','A', 'B', 'A', 'B'],
'C' : [2, 4, 5, 2, 0, 3, 9, 1],
'D' : [6, 6, 7, 7, 3, 3, 10, 10]})
df=df.pivot('A','B','C')
fig, ax = plt.subplots(1, 1, figsize =(4,6))
sns.heatmap(df, annot=True, linewidths=0, cbar=False)
plt.show()
Here's the desired result:
Thanks in advance!
I think the cleanest way (although probably not the shortest), would be to plot Total as one of the columns, and then access colors of the facets of the heatmap and change some of them to white.
The element that is responsible for color on heatmap is matplotlib.collections.QuadMesh. It contains all facecolors used for each facet of the heatmap, from left to right, bottom to top.
You can modify some colors and pass them back to QuadMesh before you plt.show().
There is a slight problem that seaborn changes text color of some of the annotations to make them visible on dark background, and they become invisible when you change to white color. So for now I set color of all text to black, you will need to figure out what is best for your plots.
Finally, to put x axis ticks and label on top, use:
ax.xaxis.tick_top()
ax.xaxis.set_label_position('top')
The final version of the code:
import matplotlib.pyplot as plt
from matplotlib.collections import QuadMesh
from matplotlib.text import Text
import seaborn as sns
import pandas as pd
import numpy as np
%matplotlib inline
df = pd.DataFrame(
{'A' : ['A', 'A', 'B', 'B','C', 'C', 'D', 'D'],
'B' : ['A', 'B', 'A', 'B','A', 'B', 'A', 'B'],
'C' : [2, 4, 5, 2, 0, 3, 9, 1],
'D' : [6, 6, 7, 7, 3, 3, 10, 10]})
df=df.pivot('A','B','C')
# create "Total" column
df['Total'] = df['A'] + df['B']
fig, ax = plt.subplots(1, 1, figsize =(4,6))
sns.heatmap(df, annot=True, linewidths=0, cbar=False)
# find your QuadMesh object and get array of colors
quadmesh = ax.findobj(QuadMesh)[0]
facecolors = quadmesh.get_facecolors()
# make colors of the last column white
facecolors[np.arange(2,12,3)] = np.array([1,1,1,1])
# set modified colors
quadmesh.set_facecolors = facecolors
# set color of all text to black
for i in ax.findobj(Text):
i.set_color('black')
# move x ticks and label to the top
ax.xaxis.tick_top()
ax.xaxis.set_label_position('top')
plt.show()
P.S. I am on Python 2.7, some syntax adjustments might be required, though I cannot think of any.

Resources