plotly imagesc repeat yaxis labels - plotly-python

I have a wide matrix that I render using plotly express. Let's say:
import plotly.express as px
data=[[1, 25, 30, 50, 1], [20, 1, 60, 80, 30], [30, 60, 1, 5, 20]]
fig = px.imshow(data,
labels=dict(x="Day of Week", y="Time of Day", color="Productivity"),
x=['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'],
y=['Morning', 'Afternoon', 'Evening']
)
fig.update_xaxes(side="top")
fig.layout.height = 500
fig.layout.width = 500
fig.show()
For enhancing readability, I would like to repeat (or add an identical) yaxis on the right side of the matrix.
I tried to follow this
fig.update_layout(xaxis=dict(domain=[0.3, 0.7]),
# create 1st y axis
yaxis=dict(
title="yaxis1 title",),
# create 2nd y axis
yaxis2=dict(title="yaxis2 title", anchor="x", overlaying="y",
side="right")
)
but I cannot make it work with imshow as it does not accept a yaxis argument.
Any workarounds?

Found an answer through the plotly forum:
import plotly.graph_objects as go
from plotly.subplots import make_subplots
# Create figure with secondary y-axis
fig = make_subplots(specs=[[{"secondary_y": True}]])
data=[[1, 25, 30, 50, 1], [20, 1, 60, 80, 30], [30, 60, 1, 5, 20]]
fig.add_trace(go.Heatmap(
z=data,
x=['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'],
y=['Morning', 'Afternoon', 'Evening']
),secondary_y=False)
fig.add_trace(go.Heatmap(
z=data,
x=['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'],
y=['Morning', 'Afternoon', 'Evening']
),secondary_y=True)
fig.update_xaxes(side="top")
fig.update_layout(xaxis_title="Day of Week", yaxis_title="Time of Day")
fig.show()
Note that adding the trace twice may be suboptimal, but it works.

Related

Plot rows of df on Plotly

The df is like this:
X Y Label
0 [16, 37, 38] [7968, 4650, 3615] 0.7
1 [29, 37, 12] [4321, 4650, 1223] 0.8
2 [12, 2, 445] [1264, 3456, 2112] 0.9
This should plot three lines on the same plot with labels as continuous variables. What is the fastest & simplest way to plot it using plotly?
Taking This should plot three lines on the same plot as the requirement. (Which is inconsistent with where I want subplots from each row of the df)
Simple case of create a trace for each row, using https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.explode.html to prepare x and y
import pandas as pd
import plotly.graph_objects as go
df = pd.DataFrame(
{
"X": [[16, 37, 38], [29, 37, 12], [12, 2, 445]],
"Y": [[7968, 4650, 3615], [4321, 4650, 1223], [1264, 3456, 2112]],
"Label": [0.7, 0.8, 0.9],
}
)
go.Figure(
[
go.Scatter(
x=r["X"].explode(), y=r["Y"].explode(), name=str(r["Label"].values[0])
)
for _, r in df.groupby(df.index)
]
)
with continuous color defined by label
import pandas as pd
import plotly.graph_objects as go
from plotly.colors import sample_colorscale
import plotly.express as px
df = pd.DataFrame(
{
"X": [[16, 37, 38], [29, 37, 12], [12, 2, 445]],
"Y": [[7968, 4650, 3615], [4321, 4650, 1223], [1264, 3456, 2112]],
"Label": [0.1, 0.5, 0.9],
}
)
fig = px.scatter(x=[0], y=[0], color=[.5], color_continuous_scale="YlGnBu")
fig = fig.add_traces(
[
go.Scatter(
x=r["X"].explode(),
y=r["Y"].explode(),
name=str(r["Label"].values[0]),
line_color=sample_colorscale("YlGnBu", r["Label"].values[0])[0],
showlegend=False
)
for _, r in df.groupby(df.index)
]
)
fig

How can I keep a subplot table from stretching?

How should I alter the following script to keep the subplot (on right_ from stretching? Is there a way to set either plot area of the subplot? Frustrating as I go thru the row/column sizing in the function, but when plot it just expands to fill the area. In the left subplot is the full list (22 rows). In the right I just pass half the df rows, and it fills vertically? Thx.
import pandas as pd
import matplotlib.pyplot as plt
import six
plt.rcParams['font.family'] = "Lato"
raw_data = dict(TF_001=[42, 39, 86, 15, 23, 57, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25],
SP500=[52, 41, 79, 80, 34, 47, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
23, 24, 25],
Strategy=[62, 37, 84, 51, 67, 32, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
22,
23, 24, 25],
LP_Port=[72, 43, 36, 26, 53, 88, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
22, 23, 24, 25])
df = pd.DataFrame(raw_data, index=pd.Index(
['Sharpe Ratio', 'Sortino Ratio', 'Calmars Ratio', 'Ulcer Index', 'Max Drawdown', 'Volatility',
'VaR', 'CVaR', 'R-Squared', 'CAGR', 'Risk-of-Ruin', 'Gain-Pain Ratio', 'Pitfall Indicator',
'Serentity Ratio', 'Common Sense Ratio', 'Kelly Criteria', 'Payoff Ratio', 'Ratio-A',
'Ratio-B', 'Ratio-C', 'Ratio-D', 'Ratio-E'], name='Metric'),
columns=pd.Index(['TF_001', 'SP500', 'Strategy', 'LP_Port'], name='Series'))
def create_table(data,
ax=None,
col_width=None,
row_height=None,
font_size=8,
header_color='#E5E5E5',
row_colors=None,
edge_color='w',
header_columns=0,
bbox=None):
if row_colors is None:
row_colors = ['#F1F8E9', 'w']
if bbox is None:
bbox = [0, 0, 1, 1]
data_table = ax.table(cellText=data.values,
colLabels=data.columns,
rowLabels=data.index,
bbox=bbox,
cellLoc='center',
rowLoc='left',
colLoc='center',
colWidths=([col_width] * len(data.columns)))
cell_map = data_table.get_celld()
for i in range(0, len(data.columns)):
cell_map[(0, i)].set_height(row_height * 0.2)
data_table.auto_set_font_size(False)
data_table.set_fontsize(font_size)
for k, cell in six.iteritems(data_table._cells):
cell.set_edgecolor(edge_color)
if k[0] == 0 or k[1] < header_columns:
cell.set_text_props(weight='heavy', color='black')
cell.set_facecolor(header_color)
else:
cell.set_facecolor(row_colors[k[0] % len(row_colors)])
for row, col in data_table._cells:
if (row == 0) or (col == -1):
data_table._cells[(row, col)].set_alpha(0.8)
return ax
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 7), constrained_layout=False)
create_table(df, ax1, col_width=1.1, row_height=0.25, font_size=8)
create_table(df.iloc[0:11, ], ax2, col_width=1.1, row_height=0.25, font_size=8)
ax1.set_title("- Conventional Risk Measures -",
fontsize=10,
fontweight='heavy',
loc='center')
ax1.axis('off')
ax2.set_title("- Second Order Risk Measures -",
fontsize=10,
fontweight='heavy',
loc='center')
ax2.axis('off')
plt.suptitle('EF QuantOne - Performance and Risk Assessment ("PaRA")',
x=0.0175,
y=0.9775,
ha='left',
fontsize=12,
weight='heavy')
plt.tight_layout()
plt.savefig('risk_parameter_table[1].pdf',
orientation='portrait',
pad_inches=0.5)
plt.show()
Figured it out ...
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import six
plt.rcParams['font.family'] = "Lato"
raw_data = dict(TF_001=[42, 39, 86, 15, 23, 57, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25],
SP500=[52, 41, 79, 80, 34, 47, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
23, 24, 25],
Strategy=[62, 37, 84, 51, 67, 32, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
22,
23, 24, 25],
LP_Port=[72, 43, 36, 26, 53, 88, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
22, 23, 24, 25])
df = pd.DataFrame(raw_data, index=pd.Index(
['Sharpe Ratio', 'Sortino Ratio', 'Calmars Ratio', 'Ulcer Index', 'Max Drawdown', 'Volatility',
'VaR', 'CVaR', 'R-Squared', 'CAGR', 'Risk-of-Ruin', 'Gain-Pain Ratio', 'Pitfall Indicator',
'Serentity Ratio', 'Common Sense Ratio', 'Kelly Criteria', 'Payoff Ratio', 'Ratio-A',
'Ratio-B', 'Ratio-C', 'Ratio-D', 'Ratio-E'], name='Metric'),
columns=pd.Index(['TF_001', 'SP500', 'Strategy', 'LP_Port'], name='Series'))
def create_table(data,
ax=None,
col_width=None,
row_height=None,
font_size=8,
header_color='#E5E5E5',
row_colors=None,
edge_color='w',
header_columns=0,
bbox=None):
if row_colors is None:
row_colors = ['#F1F8E9', 'w']
if bbox is None:
bbox = [0, 0, 1, 1]
data_table = ax.table(cellText=data.values,
colLabels=data.columns,
rowLabels=data.index,
bbox=bbox,
cellLoc='center',
rowLoc='left',
colLoc='center',
colWidths=([col_width] * len(data.columns)))
cell_map = data_table.get_celld()
for i in range(0, len(data.columns)):
cell_map[(0, i)].set_height(row_height * 0.2)
data_table.auto_set_font_size(False)
data_table.set_fontsize(font_size)
for k, cell in six.iteritems(data_table._cells):
cell.set_edgecolor(edge_color)
if k[0] == 0 or k[1] < header_columns:
cell.set_text_props(weight='heavy', color='black')
cell.set_facecolor(header_color)
else:
cell.set_facecolor(row_colors[k[0] % len(row_colors)])
for row, col in data_table._cells:
if (row == 0) or (col == -1):
data_table._cells[(row, col)].set_alpha(0.8)
return ax
# fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(11, 8.5), constrained_layout=False)
fig = plt.figure(figsize=(12, 10))
w, h = fig.get_size_inches()
div = np.array([w, h, w, h])
col_width = 1.1
row_height = 0.25
ax1_subplot_size = (np.array(df.shape[::-1]) + np.array([0, 1])) * np.array(
[col_width, row_height])
ax1 = fig.add_axes(np.array([1.6, 1, 4.4, 5.75]) / div)
ax2_subplot_size = (np.array(df.shape[::-1]) + np.array([0, 1])) * np.array(
[col_width, row_height])
ax2 = fig.add_axes(np.array([7.5, 3.75, 4.4, 3]) / div)
create_table(df, ax1, col_width, row_height, font_size=8)
create_table(df.iloc[0:11, ], ax2, col_width, row_height, font_size=8)
ax1.set_title("- Conventional Risk Measures -",
fontsize=10,
fontweight='heavy',
loc='center')
ax1.axis('off')
ax2.set_title("- Second Order Risk Measures -",
fontsize=10,
fontweight='heavy',
loc='center')
ax2.axis('off')
plt.suptitle('EF QuantOne - Performance and Risk Assessment ("PaRA")',
x=0.0175,
y=0.9775,
ha='left',
fontsize=12,
weight='heavy')
# plt.tight_layout()
plt.savefig('risk_parameter_table[1].pdf',
orientation='portrait',
pad_inches=0.5)
plt.show()

Select appropriate colors in stacked Seaborn barplot

I want to create a stacked barplot using Seaborn with this MiltiIndex DataFrame
header = pd.MultiIndex.from_product([['#'],
['TE', 'SS', 'M', 'MR']])
dat = ([[100, 20, 21, 35], [100, 12, 5, 15]])
df = pd.DataFrame(dat, index=['JC', 'TTo'], columns=header)
df = df.stack()
df = df.sort_values('#', ascending=False).sort_index(level=0, sort_remaining=False)
The code I'm using for the plot is:
fontP = FontProperties()
fontP.set_size('medium')
colors = {'TE': 'green', 'SS': 'blue', 'M': 'yellow', 'MR': 'red'}
kwargs = {'alpha':0.5}
plt.figure(figsize=(12, 9))
sns.barplot(x=df2.index.get_level_values(0).unique(),
y=df2.loc[pd.IndexSlice[:, df2.index[0]], '#'],
color=colors[df2.index[0][1]], **kwargs)
sns.barplot(x=df2.index.get_level_values(0).unique(),
y=df2.loc[pd.IndexSlice[:, df2.index[1]], '#'],
color=colors[df2.index[1][1]], **kwargs)
sns.barplot(x=df2.index.get_level_values(0).unique(),
y=df2.loc[pd.IndexSlice[:, df2.index[2]], '#'],
color=colors[df2.index[2][1]], **kwargs)
bottom_plot = sns.barplot(x=df2.index.get_level_values(0).unique(),
y=df2.loc[pd.IndexSlice[:, df2.index[3]], '#'],
color=colors[df2.index[3][1]], **kwargs)
bar1 = plt.Rectangle((0, 0), 1, 1, fc='green', edgecolor="None")
bar2 = plt.Rectangle((0, 0), 0, 0, fc='yellow', edgecolor="None")
bar3 = plt.Rectangle((0, 0), 2, 2, fc='red', edgecolor="None")
bar4 = plt.Rectangle((0, 0), 3, 3, fc='blue', edgecolor="None")
l = plt.legend([bar1, bar2, bar3, bar4], [
"TE", "M",
'MR', 'SS'
],
bbox_to_anchor=(0.95, 1),
loc='upper left',
prop=fontP)
l.draw_frame(False)
sns.despine()
bottom_plot.set_ylabel("#")
axes = plt.gca()
axes.yaxis.grid()
And I get:
My problem is the order of the colors in the second bar ('TTo'), I want the colors to be automatically selected based on the level 1 index value (['TE', 'SS', 'M', 'MR']) so that they are ordered correctly. Further down the one with the highest value with its corresponding color, in front the next one with the next highest value and its color and so on, as the first bar shows ('JC).
Maybe there is a simpler way to do this in Seaborn than the one I'm using...
I'm not sure how to create such a plot with seaborn. Here is a way to create it with a loop through the rows and adding one matplotlib bar at each step:
import pandas as pd
import seaborn as sns
from matplotlib import pyplot as plt
sns.set()
header = pd.MultiIndex.from_product([['#'],
['TE', 'SS', 'M', 'MR']])
dat = ([[100, 20, 21, 35], [100, 12, 5, 15]])
df = pd.DataFrame(dat, index=['JC', 'TTo'], columns=header)
df = df.stack()
df = df.sort_values('#', ascending=False).sort_index(level=0, sort_remaining=False)
colors = {'TE': 'green', 'SS': 'blue', 'M': 'yellow', 'MR': 'red'}
prev_index0 = None
for (index0, index1), quantity in df.itertuples():
if index0 != prev_index0:
bottom = 0
plt.bar(index0, quantity, fc=colors[index1], ec='none', bottom=bottom, label=index1)
bottom += quantity
prev_index0 = index0
legend_handles = [plt.Rectangle((0, 0), 0, 0, color=colors[c], label=c) for c in colors]
plt.legend(handles=legend_handles)
plt.show()
To plot the bars back to front without stacking, the code can be simplified:
colors = {'TE': 'forestgreen', 'SS': 'cornflowerblue', 'M': 'gold', 'MR': 'crimson'}
for (index0, index1), quantity in df.itertuples():
plt.bar(index0, quantity, fc=colors[index1], ec='none', label=index1)
legend_handles = [plt.Rectangle((0, 0), 0, 0, color=colors[c], label=c, ec='black') for c in colors]
plt.legend(handles=legend_handles, bbox_to_anchor=(1.02, 1.02), loc='upper left')
plt.tight_layout()

How to reverse colorbar values in matpotlib?

I am using the cbar.ax.tick_params matplotlib command to make a colorbar for an XY scatterplot. How do I reverse the values (not the color-ramp) so that the lowest value is at the top of the bar. This is to represent geological data where the youngest rocks are on top of the older rocks. Here the age is represented by color.
Here is my code:
plt.scatter(summary["d18O"], summary["eHf"], s=150, c = color, cmap = color_map, edgecolors='black', marker='o')
plt.errorbar(summary["d18O"], summary["eHf"], summary["xerr"], summary["yerr"], ls='none', color='lightgrey', zorder=-1)
cbar=plt.colorbar()
cbar.ax.tick_params(labelsize=14)
cbar.minorticks_on()
cbar.set_label('Age (Ma)', style='italic', fontsize=16)
plt.axvline(x=5.3, color='black', zorder=-1)
plt.axhline(y=0, color='black', zorder=-1)
plt.tick_params(labelsize=14)
ax.set_xticks([4, 5, 6, 7, 8, 9, 10, 11, 12, 13])
ax.set_yticks([-6, -4, -2, 0, 2, 4, 6, 8, 10, 12, 14, 16])
plt.ylabel(u'${\epsilon}$Hf$_{T}$', style='italic', fontsize=18)
plt.xlabel(u'$\delta^{18}$O$_{V-SMOW}$ ‰',style='italic', fontsize=18)
plt.text(11.5, 0.3, 'CHUR', fontsize=18)
plt.text(4.9, 5, 'mantle zircon = 5.3‰', fontsize=16, rotation=90)
plt.show()
As #r-beginners mentioned,
cbar.ax.invert_yaxis()
would solve the problem if cbar is your colorer object.

matplotlib histogram with equal bars width

I use a histogram to display the distribution. Everything works fine if the spacing of the bins is uniform. But if the interval is different, then the bar width is appropriate (as expected). Is there a way to set the width of the bar independent of the size of the bins ?
This is what i have
This what i trying to draw
from matplotlib import pyplot as plt
my_bins = [10, 20, 30, 40, 50, 120]
my_data = [5, 5, 6, 8, 9, 15, 25, 27, 33, 45, 46, 48, 49, 111, 113]
fig1 = plt.figure()
ax1 = fig1.add_subplot(121)
ax1.set_xticks(my_bins)
ax1.hist(my_data, my_bins, histtype='bar', rwidth=0.9,)
fig1.show()
I cannot mark your question as a duplicate, but I think my answer to this question might be what you are looking for?
I'm not sure how you'll make sense of the result, but you can use numpy.histogram to calculate the height of your bars, then plot those directly against an arbitrary x-scale.
x = np.random.normal(loc=50, scale=200, size=(2000,))
bins = [0,1,10,20,30,40,50,75,100]
fig = plt.figure()
ax = fig.add_subplot(211)
ax.hist(x, bins=bins, edgecolor='k')
ax = fig.add_subplot(212)
h,e = np.histogram(x, bins=bins)
ax.bar(range(len(bins)-1),h, width=1, edgecolor='k')
EDIT Here's with the adjustment to the x-tick labels so that the correspondence is easier to see.
my_bins = [10, 20, 30, 40, 50, 120]
my_data = [5, 5, 6, 8, 9, 15, 25, 27, 33, 45, 46, 48, 49, 111, 113]
fig = plt.figure()
ax = fig.add_subplot(211)
ax.hist(my_data, bins=my_bins, edgecolor='k')
ax = fig.add_subplot(212)
h,e = np.histogram(my_data, bins=my_bins)
ax.bar(range(len(my_bins)-1),h, width=1, edgecolor='k')
ax.set_xticks(range(len(my_bins)-1))
ax.set_xticklabels(my_bins[:-1])