I'm currently trying to change the secondary y-axis values in a matplot graph to ymin = -1 and ymax = 2. I can't find anything on how to change the values though. I am using the secondary_y = True argument in .plot(), so I am not sure if changing the secondary y-axis values is possible for this. I've included my current code for creating the plot.
df.plot()
df.plot(secondary_y = "Market")
From your example code, it seems you're using Pandas built in ploting capabilities. One option to add a second layer is by using matplotlib directly like in the example "two_scales.py".
It uses
import matplotlib.pyplot as plt
fig, ax1 = plt.subplots()
ax1.plot(df["..."])
# ...
ax2 = ax1.twinx()
ax2.plot(df["Market"])
ax2.set_ylim([0, 5])
where you can change the y-limits.
Setting ylim on plot does not appear to work in the case of secondary_y, but I was able to workaround with this:
import pandas as pd
df = pd.DataFrame({'one': range(10), 'two': range(10, 20)})
ax = df['one'].plot()
ax2 = df['two'].plot(secondary_y=True)
ax2.set_ylim(-20, 50)
fig = ax.get_figure()
fig.savefig('test.png')
This is a solution for showing as much y-axes as data columns the dataframe has
colors = ['tab:blue',
'tab:orange',
'tab:green',
'tab:red',
'tab:purple',
'tab:brown',
'tab:pink',
'tab:gray',
'tab:olive',
'tab:cyan']
#X axe and first Y axe
fig, ax1 = plt.subplots()
x_label = str( dataFrame.columns[0] )
index = dataFrame[x_label]
ax1.set_xlabel(x_label)
ax1.set_xticklabels(dataFrame[x_label], rotation=45, ha="right")
firstYLabel = str( dataFrame.columns[1] )
ax1.set_ylabel(firstYLabel, color = colors[0])
ax1.plot(index, dataFrame[firstYLabel], color = colors[0])
ax1.tick_params(axis='y', labelcolor = colors[0])
#Creates subplots with independet y-Axes
axS =[]
def newTwix(label, ax1, index, dataFrame):
print(label)
actualPos = len(axS)
axS.append(ax1.twinx())
axS[actualPos].set_ylabel(label, color = colors[actualPos%10 + 1])
axS[actualPos].plot(index, dataFrame[label], color=colors[actualPos%10 + 1])
axS[actualPos].tick_params(axis='y', labelcolor=colors[actualPos%10 + 1])
identation = 0.075 #would improve with a dynamic solution
p = 1 + identation
for i in range(2,len(dataFrame.columns)):
newTwix(str(dataFrame.columns[i]), ax1, index, dataFrame)
if (len(axS) == 1):
axS[len(axS)-1].spines.right.set_position(("axes", p))
else:
p = int((p + identation)*1000)/1000
axS[len(axS)-1].spines.right.set_position(("axes", p))
fig.tight_layout() # otherwise the right y-label is slightly clipped
plt.subplots_adjust(left=0.04, right=0.674, bottom=0.1)
mng = plt.get_current_fig_manager()
mng.full_screen_toggle()
plt.show()
multiple y-axes with independent scales
Related
I'm currently trying to change the secondary y-axis values in a matplot graph to ymin = -1 and ymax = 2. I can't find anything on how to change the values though. I am using the secondary_y = True argument in .plot(), so I am not sure if changing the secondary y-axis values is possible for this. I've included my current code for creating the plot.
df.plot()
df.plot(secondary_y = "Market")
From your example code, it seems you're using Pandas built in ploting capabilities. One option to add a second layer is by using matplotlib directly like in the example "two_scales.py".
It uses
import matplotlib.pyplot as plt
fig, ax1 = plt.subplots()
ax1.plot(df["..."])
# ...
ax2 = ax1.twinx()
ax2.plot(df["Market"])
ax2.set_ylim([0, 5])
where you can change the y-limits.
Setting ylim on plot does not appear to work in the case of secondary_y, but I was able to workaround with this:
import pandas as pd
df = pd.DataFrame({'one': range(10), 'two': range(10, 20)})
ax = df['one'].plot()
ax2 = df['two'].plot(secondary_y=True)
ax2.set_ylim(-20, 50)
fig = ax.get_figure()
fig.savefig('test.png')
This is a solution for showing as much y-axes as data columns the dataframe has
colors = ['tab:blue',
'tab:orange',
'tab:green',
'tab:red',
'tab:purple',
'tab:brown',
'tab:pink',
'tab:gray',
'tab:olive',
'tab:cyan']
#X axe and first Y axe
fig, ax1 = plt.subplots()
x_label = str( dataFrame.columns[0] )
index = dataFrame[x_label]
ax1.set_xlabel(x_label)
ax1.set_xticklabels(dataFrame[x_label], rotation=45, ha="right")
firstYLabel = str( dataFrame.columns[1] )
ax1.set_ylabel(firstYLabel, color = colors[0])
ax1.plot(index, dataFrame[firstYLabel], color = colors[0])
ax1.tick_params(axis='y', labelcolor = colors[0])
#Creates subplots with independet y-Axes
axS =[]
def newTwix(label, ax1, index, dataFrame):
print(label)
actualPos = len(axS)
axS.append(ax1.twinx())
axS[actualPos].set_ylabel(label, color = colors[actualPos%10 + 1])
axS[actualPos].plot(index, dataFrame[label], color=colors[actualPos%10 + 1])
axS[actualPos].tick_params(axis='y', labelcolor=colors[actualPos%10 + 1])
identation = 0.075 #would improve with a dynamic solution
p = 1 + identation
for i in range(2,len(dataFrame.columns)):
newTwix(str(dataFrame.columns[i]), ax1, index, dataFrame)
if (len(axS) == 1):
axS[len(axS)-1].spines.right.set_position(("axes", p))
else:
p = int((p + identation)*1000)/1000
axS[len(axS)-1].spines.right.set_position(("axes", p))
fig.tight_layout() # otherwise the right y-label is slightly clipped
plt.subplots_adjust(left=0.04, right=0.674, bottom=0.1)
mng = plt.get_current_fig_manager()
mng.full_screen_toggle()
plt.show()
multiple y-axes with independent scales
I'm trying to make a heatmap a heatmap with extensive y axis descriptions.
I would like to know if there is anyways to have a second and a third layer on the y tick labels.
fig, ax = plt.subplots(figsize=(20,25))
sns.set(style="darkgrid")
colName = [r'A', r'B', r'C', r'D', r'E']
colTitile = 'Test'
rowName = [r'a', r'b', r'c', r'd']
rowsName = [r'Vegetables', r'Fruits', r'Meats', r'Cheese',
r'Candy', r'Other']
rowTitile = 'Groups'
heatmapdata= np.arange(100).reshape(24,5)
sns.heatmap(heatmapdata,
cmap = 'turbo',
cbar = True,
vmin=0,
vmax=100,
ax=ax,
xticklabels = colName,
yticklabels = rowName)
for x in np.arange(0,len(ax.get_yticks()),4):
ax.axhline(x, color = 'white', lw=2)
Is there any way to do this? Which function should I use?
Thanks!
The labels for the rows can be set up in the graph settings, but other than that, I think the annotation function is the only way to handle this. the second level group names are set using the annotation function, and the coordinate criteria are set using the axis criteria. Axis labels are added using the text function with axis criteria.
import seaborn as sns
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots(figsize=(10,10))
sns.set(style="darkgrid")
colName = [r'A', r'B', r'C', r'D', r'E']
colTitile = 'Test'
rowName = [r'a', r'b', r'c', r'd']
rowsName = [r'Vegetables', r'Fruits', r'Meats', r'Cheese',
r'Candy', r'Other']
rowTitle = 'Groups'
heatmapdata= np.arange(120).reshape(24,5)
sns.heatmap(heatmapdata,
cmap='turbo',
cbar=True,
vmin=0,
vmax=100,
ax=ax,
xticklabels=colName,
yticklabels=np.tile(rowName, 6))
for x in np.arange(0,ax.get_ylim()[0],4):
ax.axhline(x, color = 'white', lw=2)
for idx,g in enumerate(rowsName[::-1]):
ax.annotate(g, xy=(-100, idx*90+45), xycoords='axes points', size=14)
ax.text(x=-0.3, y=0.5, s=rowTitle, ha='center', transform=ax.transAxes, rotation=90, font=dict(size=16))
plt.show()
I am trying to create an axis plot. I was trying to loop over it as I am plotting the same variable for two different categories. Currently, I have written code two times but I am looking for a smarter way with looping, if possible. Any other suggestion will also be helpful.
zone = ['AB','CD']
plt.style.use('default')
fig,(ax0,ax1) = plt.subplots(2,1, figsize = (18,18), sharex = False)
i = 0
while i < len(zone):
if zone[i] == zone[0]:
ax0.plot(df0['datetime'], df0['pnl1'], color='k', linewidth=1, label ='PnL1')
ax0.plot(df0['datetime'], df0['pnl2'], color='m', linewidth=1, label ='PnL2')
ax00 = ax0.twinx()
ax00.bar(df0['datetime'], df0['qty'], width = 1/96, color='g', align = 'edge', alpha = 0.5, label ='Qty')
elif zone[i] == zone[1]:
ax1.plot(df0['datetime'], df0['pnl1'], color='k', linewidth=1, label ='PnL1')
ax1.plot(df0['datetime'], df0['pnl2'], color='m', linewidth=1, label ='PnL2')
ax01 = ax1.twinx()
ax01.bar(df0['datetime'], df0['hedge'], width = 1/96, color='g', align = 'edge', alpha = 0.5, label ='Qty')
i = i + 1
I want to check if something like below can be done with axis plots or not.
zone = ['AB','CD']
plt.style.use('default')
fig,(ax0,ax1) = plt.subplots(2,1, figsize = (18,18), sharex = False)
i = 0
while i < len(zone):
ax{''}.format(i).plot(df0['datetime'], df0['pnl1'], color='k', linewidth=1, label ='PnL1')
ax{''}.format(i).plot(df0['datetime'], df0['pnl2'], color='m', linewidth=1, label ='PnL2')
ax0{''}.format(i) = ax{''}.format(i).twinx()
ax0{''}.format(i).bar(df0['datetime'], df0['qty'], width = 1/96, color='g', align = 'edge', alpha = 0.5, label ='Qty')
It did not work for me. Any leads to execute axis plot with loop will be helpful.
Here are some ways:
Simply loop over the list of axes
import matplotlib.pyplot as plt
import numpy as np
fig,axes = plt.subplots(2,1)
x = np.linspace(0,5,21)
for ax in axes:
ax.plot(x,np.sin(x))
plt.show()
Works also with index:
for i in range(len(axes)):
axes[i].plot(x,np.sin(x))
For a grid of plot you can use a similar approach:
import matplotlib.pyplot as plt
import numpy as np
fig,axes = plt.subplots(2,2)
x = np.linspace(0,5,21)
for i in range(len(axes)):
for j in range(len(axes[0])):
axes[i][j].plot(x,np.sin(x))
plt.show()
If you don't like double-loops, you can flatten the array with np.ravel()
fig,axes = plt.subplots(2,2)
x = np.linspace(0,5,21)
for ax in np.ravel(axes):
ax.plot(x,np.sin(x))
plt.show()
I have a code from a dataframe
Y = df['label']
for col in categorical_cols:
tab = pd.crosstab(df[col],Y)
annot = x.div(x.sum(axis=1).astype('float64'),axis=0)
annot.plot(kind='bar',stacked=True)
plt.title('Distribution of %s'%col)
plt.xlabel('%s'%col,size='x-large')
plt.xticks(rotation=45)
plt.legend()
How can I plot these using different subplots in a single figure because this loops prints the last column's figure. So all figures are same.
Also: How can I produce the same using matplotlib/seaborn using matplotlib which shows me the % or absolute values.
You need to create the different subplots and then pass one axes object to each call of annot.plot via the ax keyword, something like this:
import math
import matplotlib.pyplot as plt
n = len(categorical_cols)
nrows = math.ceil(float(n) / 3.0)
fig, ax = plt.subplots(ncols=3, nrows=nrows, figsize=(9, nrows*3))
ax = ax.flatten()
Y = df['label']
for idx, col in enumerate(categorical_cols):
tab = pd.crosstab(df[col],Y)
annot = x.div(x.sum(axis=1).astype('float64'),axis=0)
annot.plot(kind='bar',stacked=True, ax=ax[idx])
ax[idx].title('Distribution of %s'%col)
ax[idx].set_xlabel('%s'%col,size='x-large')
ax.tick_params('x', labelrotation=45)
plt.legend()
I have code that generates four subplots, but i want to generate those charts through loops , Currently i am following this piece of code to generate the chart
Code:
plt.figure(figsize=(20, 12))
plt.subplot(221)
sns.barplot(x = 'Category', y = 'POG_Added', data = df)
xticks(rotation = 90)
plt.xticks(size = 11)
plt.yticks(size = 11)
plt.xlabel("Category",size = 13)
plt.ylabel("POG_Added",size = 13)
plt.subplot(222)
sns.barplot(x = 'Category', y = 'Live_POG', data = df)
xticks(rotation = 90)
plt.xticks(size = 11)
plt.yticks(size = 11)
plt.xlabel("Category",size = 13)
plt.ylabel("Live_POG",size = 13)
plt.subplot(223)
sns.lineplot(x = 'Category', y = 'D01_CVR', data = df)
#sns.barplot(x = 'Category', y = 'D2-08-Visits', data = df,label='D2-08_Visits')
xticks(rotation = 90)
plt.xticks(size = 11)
plt.yticks(size = 11)
plt.xlabel("Category",size = 13)
plt.ylabel("D01_CVR",size = 13)
plt.subplot(224)
plt.xticks(rotation='vertical')
ax = sns.barplot(x='Category',y='D2-08-Units',data=df)
ax2 = ax.twinx()
ax2.plot(ax.get_xticks(), df["D01_CVR"], alpha = .75, color = 'r')
plt.subplots_adjust(hspace=0.55,wspace=0.55)
plt.show()
Here's how I do things like that:
import numpy as np
import matplotlib.pyplot as plt
data = [np.random.random((10, 10)) for _ in range(6)]
fig, axs = plt.subplots(ncols=3, nrows=2, figsize=(9, 6))
for ax, dat in zip(axs.ravel(), data):
ax.imshow(dat)
This produces:
The idea is that plt.subplots() produces an array of Axes objects, so you can loop over it and make your plots in the loop. In this case I need ndarray.ravel() because axs is a 2D array.
Consider tightening up repetitive code by:
Set unchanging aesthetics like all x-ticks and y-ticks font sizes in one call with plt.rc calls.
Build plt.subplots() and use its array of Axes objects.
Use ax argument of seaborn's barplot and lineplot to loop above Axes array.
While not completely DRY given the special two plots, below is adjustment:
# AXES AND TICKS FONT SIZES
plt.rc('xtick', labelsize=11)
plt.rc('ytick', labelsize=11)
plt.rc('axes', labelsize=13)
# FIGURE AND SUBPLOTS SETUP
fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(20, 12))
# BAR PLOTS (FIRST ROW)
for i, col in enumerate(['POG_Added', 'Live_POG']):
sns.barplot(x='Category', y=col, data=df, ax=axes[0,i])
axes[0,i].tick_params(axis='x', labelrotation=90)
# LINE PLOT
sns.lineplot(x='Category', y='D01_CVR', data=df, ax=axes[1,0])
axes[1,0].tick_params(axis='x', labelrotation=90)
# BAR + LINE DUAL PLOT
sns.barplot(x='Category', y='D2-08-Units', data=df, ax=axes[1,1])
ax2 = axes[1,1].twinx()
ax2.plot(axes[1,1].get_xticks(), df["D01_CVR"], alpha = .75, color = 'r')
axes[1,1].tick_params(axis='x', labelrotation=90)