Conditionally change background color of specific cells - python

I have a DataFrame and I can save it as a png file. But now I want to change the background color of specific cells who meet a certain condition.
Conditions:
Numbers who are 80 or higher must get a green background.
Numbers below 80 must get a red background.
All column names and index cells need a black background with a white text color.
The following posts came close to what I want but didn't provided with the answer I needed.
Post 1
Post 2
My code:
import matplotlib.pyplot as plt
from pandas.tools.plotting import table
import pandas as pd
#My dataframe
df = pd.DataFrame({
'Weeks' : [201605, 201606, 201607, 201608],
'Computer1' : [50, 77, 96, 100],
'Computer2' : [50, 79, 100, 80],
'Laptop1' : [75, 77, 96, 95],
'Laptop2' : [86, 77, 96, 40],
'Phone' : [99, 99, 44, 85],
'Phone2' : [93, 77, 96, 25],
'Phone3' : [94, 91, 96, 33]
})
df2 = df.set_index('Weeks') #Makes the column 'Weeks' the index.
#Make a png file out of an dataframe.
plt.figure(figsize=(9,3))
ax = plt.subplot(211, frame_on=False) # no visible frame
ax.xaxis.set_visible(False) # hide the x axis
ax.yaxis.set_visible(False) # hide the y axis
table(ax, df2, rowLabels=df2.index, colLabels=df2.columns, loc='center', cellColours=None)
plt.savefig('mytable.png') #save it as an png.
This is how it currently looks:
This is how I want it to look

you can do something like this:
colors = df2.applymap(lambda x: 'green' if x>= 80 else 'red').reset_index().drop(['Weeks'], axis=1)
tbl = table(ax, df2, loc='center',
cellColours=colors.as_matrix(),
colColours=['black']*len(colors.columns),
rowColours=['black']*len(colors))
Setting index's color:
[tbl._cells[row, -1]._text.set_color('white') for row in range(1, len(colors)+1)]
setting header's colors:
[tbl._cells[0, col]._text.set_color('white') for col in range(len(colors.columns))]
plt.show()
Code (complete):
import matplotlib.pyplot as plt
from pandas.tools.plotting import table
import pandas as pd
#My dataframe
df = pd.DataFrame({
'Weeks' : [201605, 201606, 201607, 201608],
'Computer1' : [50, 77, 96, 100],
'Computer2' : [50, 79, 100, 80],
'Laptop1' : [75, 77, 96, 95],
'Laptop2' : [86, 77, 96, 40],
'Phone' : [99, 99, 44, 85],
'Phone2' : [93, 77, 96, 25],
'Phone3' : [94, 91, 96, 33]
})
df2 = df.set_index('Weeks') #Makes the column 'Weeks' the index.
colors = df2.applymap(lambda x: 'green' if x>= 80 else 'red') \
.reset_index().drop(['Weeks'], axis=1)
#print(colors)
plt.figure(figsize=(10,5))
ax = plt.subplot(2, 1, 1, frame_on=True) # no visible frame
#ax.xaxis.set_visible(False) # hide the x axis
#ax.yaxis.set_visible(False) # hide the y axis
# hide all axises
ax.axis('off')
# http://matplotlib.org/api/pyplot_api.html?highlight=table#matplotlib.pyplot.table
tbl = table(ax, df2,
loc='center',
cellLoc='center',
cellColours=colors.as_matrix(),
colColours=['black']*len(colors.columns),
rowColours=['black']*len(colors),
#fontsize=14
)
# set color for index (X, -1) and headers (0, X)
for key, cell in tbl.get_celld().items():
if key[1] == -1 or key[0] == 0:
cell._text.set_color('white')
# remove grid lines
cell.set_linewidth(0)
# refresh table
plt.show()
# save it as an png.
plt.savefig('mytable.png')

Related

plotly column with vertical border and color for specific column

I am looking for a solution to set a vertical border and color for a specific column(s). for this example the column "Scores".
import plotly.graph_objects as go
import plotly
fig = go.Figure(data=[go.Table(
header=dict(values=['<b>Values', '<b>Scores', 'column'],
line_color='darkslategray',
#fill_color='lightskyblue',
align='center'),
cells=dict(values=[[100, 100, 100, 300], # 1st column
[90, 90, 90, 270],
[90, 90, 90, 270]], # 2nd column
line_color='darkslategray',
#fill_color='lightcyan',
align='center'))
])
fig.update_layout(width=250, height=130)
fig.update_layout(margin=dict(l=10, r=10, t=10, b=10))
fig.show()
the perfect solution I expect looks like the table (created with excel). if somebody only know how to color the column this also would help. Thanks!
As far as I know, you cannot change the color of individual ruled lines. The only settings for lines are line width and color. The color for each cell can be specified individually by column or by an array corresponding to the cell.
import plotly.graph_objects as go
import plotly
fig = go.Figure(data=[go.Table(
header=dict(values=['<b>Values', '<b>Scores', 'column'],
line_color=['white','mediumpurple','white'],
fill_color=['white','mediumpurple','white'],
align='center'),
cells=dict(values=[[100, 100, 100, 300], # 1st column
[90, 90, 90, 270],
[90, 90, 90, 270]], # 2nd column
line_color=['white','mediumpurple','white'],
fill_color=['white','mediumpurple','white'],
align='center'))
])
fig.update_layout(width=250, height=130)
fig.update_layout(margin=dict(l=10, r=10, t=10, b=10))
fig.show()

python - plotly save table without whitespace

i generate a table in python with plotly and i save it as png . but the saved png has a lot of whitespace. i there a solution that the png/or image is "filled" or "Full-screen/image".
i generate the table with:
import plotly.graph_objects as go
fig = go.Figure(data=[go.Table(header=dict(values=['A Scores', 'B Scores']),
cells=dict(values=[[100, 90, 80, 90], [95, 85, 75, 95]]))
])
plotly.io.write_image(fig, file='example_table.png', format='png')
thanks for ideas and solutions. greets alex
Use this code:
import plotly.graph_objects as go
fig = go.Figure(data=[go.Table(header=dict(values=['A Scores', 'B Scores']),
cells=dict(values=[[100, 90, 80, 90], [95, 85, 75, 95]]))
])
fig.update_layout(
autosize=False,
margin = {'l':0,'r':0,'t':0,'b':0},
height = 125
)
fig.write_image("fig1.png")
the update_layout will help you to fix the height and weight of the chart.
Output:

Matplotlib blank space with no color when use fill_between with where option

Update:
I slice days into 100 points then interpolate the corresponding value of min_temp and max_temp, the result become better, but still some area have no color, how to modify it?
days_vals=numpy.linspace(1,10,100)
min_interp=numpy.interp(days_vals,days,min_temp)
max_interp=numpy.interp(days_vals,days,max_temp)
plt.xticks(days)
plt.plot(days_vals,min_interp,c='b',marker='o')
plt.plot(days_vals,max_interp,c='g',marker='o')
plt.fill_between(days_vals,min_interp,max_interp,where=[i>35 for i in min_interp],
facecolor='lightgreen',alpha=0.7,interpolate=False)
plt.fill_between(days_vals,min_interp,max_interp,where=[i<=35 for i in min_interp],
facecolor='lightpink',alpha=0.7,interpolate=False)
==========================================================================
I am using fill_between with where option to fill the color, min_temp > 35 fill green and min_temp <= 35 fill pink, but see the result is not as my expected
there are so many blank area with no color.
I search one question somelike my issue link
it solution is to add additional data-points to the series that that lie on the axis, but it not fix my issue
How can i modify my codes to make the color continuous with no blank space?
here's the codes:
from matplotlib import pyplot as plt
days=range(1,11)
max_temp=[37, 35, 42, 36, 39, 56, 50, 45, 41, 39]
min_temp=[32, 30, 37, 20, 34, 40, 37, 38, 32, 30]
fig=plt.figure(figsize=(10,8))
font={'weight':'normal',
'color':'cyan',
'fontsize':24,
}
plt.title('Weather 2014',fontdict=font)
plt.xlabel('Month',fontdict=font)
plt.ylabel('Temperature',fontdict=font)
plt.title('Weather 2014',fontdict=font)
plt.xlabel('Month',fontdict=font)
plt.ylabel('Temperature',fontdict=font)
plt.xticks(days)
plt.plot(days,max_temp,marker='o',mfc='red',mec='None',markersize=3,label='Max Temp')
plt.plot(days,min_temp,marker='o',mfc='g',mec='None',markersize=3,label='Min Temp')
'''add additional data points'''
eta=1e-6
plt.fill_between(days,min_temp,max_temp,where=[i+eta>35 for i in min_temp],
facecolor='lightgreen',alpha=0.7)
plt.fill_between(days,min_temp,max_temp,where=[i-eta<=35 for i in min_temp],
facecolor='lightpink',alpha=0.7)
plt.legend(loc='upper left',bbox_to_anchor=(1,1))
fig.autofmt_xdate()
plt.grid(True)
plt.show()

Matplotlib set year on x axis

i would like to have a plot of nasdaq market index that has on x axis the years since 1971 and on y axis the values.
dataframe = pd.read_csv('nasdaq-historical-chart.csv', usecols=[1], engine='python')
dataset = dataframe.values
df = pd.read_csv('nasdaq-historical-chart.csv',parse_dates=True)
df['date'] = pd.to_datetime(df['date'])
df['year'] = df['date'].dt.year
plt.plot(dataset)
plt.figure(figsize=(25,10))
plt.plot(df['year'], dataset)
plt.title('NASDAQ historical chart',fontsize=24)
plt.xlabel('Time',fontsize=14)
plt.ylabel('Value',fontsize=14)
plt.tick_params(axis='both',labelsize=14)
plt.show()
In this way i have the right plot but without years on x axis
If i put:
plt.plot(df['year'], dataset)
i have:
why the plot changed? How can i modify it?
I created some data similar to yours as example, and you can do in a similar way:
import pandas as pd
import matplotlib.pyplot as plt
df = pd.DataFrame({'date':['1971-1-1','1971-1-2','1971-1-3','1971-1-4','1971-1-5','1971-1-6','1971-1-7','1971-1-8','1971-1-9',
'1971-1-10', '1971-1-11', '1971-1-12', '1972-1-1','1972-1-2','1972-1-3','1972-1-4',
'1972-1-5','1972-1-6','1972-1-7','1972-1-8','1972-1-9','1972-1-10', '1972-1-11', '1972-1-12'],
'values':[150, 130, 100, 95, 100, 105, 200, 180, 170, 160, 150, 155, 155, 170, 190, 192, 195, 200, 220,
230, 220, 210, 230, 235]})
print (df)
df['date'] = pd.to_datetime(df['date'], format='%Y-%d-%m')
plt.figure(figsize=(25,10))
plt.plot(df['date'], df['values'])
plt.title('NASDAQ historical chart',fontsize=24)
plt.xlabel('Time',fontsize=14)
plt.ylabel('Value',fontsize=14)
plt.tick_params(axis='both',labelsize=14)
plt.show()

How to remove empty "padding" in matplotlib barh plot?

I want to remove/reduce the empty top and bottom padding space (marked with red squares) in the matplotlib.pyplot.barh plot. How can I do it?
Here is an example of my plot:
Here is the code:
import matplotlib.pyplot as plt
from collections import Counter
import random
values = sorted(tags_dic.values())
labels = sorted(tags_dic, key=tags_dic.get)
bars = plt.barh(range(len(tags_dic)), values, align='center')
plt.yticks(range(len(tags_dic)), labels)
plt.xlabel('Count')
plt.ylabel('POS-tags')
plt.grid(True)
random.shuffle(COLLECTION)
for i in range(len(tags_dic)):
bars[i].set_color(COLLECTION[i])
print COLLECTION[i]
plt.show()
Random test data:
tags_dic = Counter({u'NNP': 521, u'NN': 458, u'IN': 450, u'DT': 415, u'JJ': 268, u'NNS': 244, u'VBD': 144, u'CC': 138, u'RB': 103, u'VBN': 98, u'VBZ': 69, u'VB': 65, u'TO': 64, u'PRP': 57, u'CD': 51, u'VBG': 50, u'VBP': 48, u'PRP$': 26, u'POS': 26, u'WDT': 20, u'WP': 20, u'MD': 19, u'EX': 11, u'WRB': 10, u'JJS': 7, u'RP': 6, u'JJR': 6, u'RBR': 5, u'NNPS': 5, u'FW': 4, u'SYM': 1, u'UH': 1})
You can control this with plt.margins. To completely remove the whitespace at the top and bottom, you can set:
plt.margins(y=0)
As an aside, I think you also have an error in your plotting script: you sort the values from your dictionary, but not the keys, so you end up with labels that don't correspond to the value they represent.
I think you can fix this as follows:
labels = sorted(tags_dic, key=tags_dic.get)
plt.yticks(range(len(tags_dic)), labels)

Categories