Djalil lounis
Djalil lounis

Reputation: 121

Matplotlib change the bar color if a condition is met

enter image description here

I am trying to build a Figure with 2 subplots.

If the Item is in ax and ax1 the color of the bar is blue.
If the item is in ax and not in ax1 the bar color should be green.
If the item is not in ax and it is in ax1 the bar color should be red. so in my example:

The bar Exploit should be green and XSS should be red.

Is there a way to do this with Matplotlib?

Here is the code:

import matplotlib.pyplot as plt
from collections import OrderedDict
from matplotlib.backends.backend_pdf import PdfPages
from  Processesing import dataProcess
from Sizeconvertor import Szconv




def chartmak (curvdic,prevdic,imgname,unit) :
Colors =[]
ImgName=imgname
D={}
D1={}
D=curvdic
D1=prevdic
if len(D):
    listo=list(D.items())
    listo1=list(D1.items())
    if len(listo) < 10:
        listo.extend([('', 0)] * (10 - len(listo)))

    if len(listo1) < 10:
        listo1.extend([('', 0)] * (10 - len(listo1)))

    values1 = [v for l, v in listo1]
    values = [v for l, v in listo]

    Dict=listo
    Dict1=listo1

    fig, (ax,ax1) = plt.subplots(ncols=2,figsize=(12, 5))
    n = len(Dict)
    n1 = len(Dict1)
    #--------------add the 1 barchart
    ax.barh(range(n), values, align='center', fc='#80d0f1', ec='w')
    ax.set_yticks(range(n))
    ax.set_yticklabels(['' if e == 0 else Szconv(e,unit) for e in values], color='gray')# add the unit
    ax.tick_params(pad=10)
    for i, (label, val) in enumerate(Dict):
        ax.annotate(label.title(), xy=(10, i), fontsize=10, va='center')
    for spine in ('top', 'right', 'bottom', 'left'):
        ax.spines[spine].set_visible(False)
    ax.xaxis.set_ticks([])
    ax.yaxis.set_tick_params(length=0)
    ax.invert_yaxis()
    ax.set_title('curmonth')

    #----------add the secound plot
    ax1.barh(range(n1), values1, align='center', fc='#80d0f1', ec='w')
    ax1.set_yticks(range(n1))
    ax1.set_yticklabels(['' if e == 0 else Szconv(e,unit) for e in values1], color='gray')#this need more work to put the GB or the TB
    ax1.tick_params(pad=10)
    for i, (label, val) in enumerate(Dict1):
      ax1.annotate(label.title(), xy=(10, i), fontsize=10, va='center')
    for spine in ('top', 'right', 'bottom', 'left'):
        ax1.spines[spine].set_visible(False)
    ax1.xaxis.set_ticks([])
    ax1.yaxis.set_tick_params(length=0)
    ax1.invert_yaxis()
    ax1.set_title('PrevMonth')
    #---------------------------------------------------------------------

    #fig.set_size_inches(4, 3.5)

    plt.savefig("BarChart/"+ImgName,bbox_inches='tight')
    plt.show()

   Testdic =OrderedDict([('Exploit', 14664), ('Botnet', 123), ('Virus', 52)])
   Testdic2 =OrderedDict([('Botnet', 1252), ('Virus', 600), ('XSS', 452)])
   imgname="TestImageformt.png"
   unit = "transaction"
   chartmak(Testdic,Testdic2,imgname,unit)

Upvotes: 0

Views: 1518

Answers (1)

tmdavison
tmdavison

Reputation: 69076

You can change the color of the Rectangle patches that barh creates after its been plotted based on your conditions.

I modified your code a little to remove some of the unnecessary parts and make it run. I hope its clear below what its doing. You can use ax.patch[i].set_color('r') to change the color of patch i to red, for example.

import matplotlib.pyplot as plt
from collections import OrderedDict

fig,(ax1,ax2) = plt.subplots(1,2)

Testdic1 =OrderedDict([('Exploit', 14664), ('Botnet', 123), ('Virus', 52)])
Testdic2 =OrderedDict([('Botnet', 1252), ('Virus', 600), ('XSS', 452)])

list1 = list(Testdic1.items())
list2 = list(Testdic2.items())

n1 = len(list1)
n2 = len(list2)

values1 = [v for l,v in list1]
values2 = [v for l,v in list2]

ax1.barh(range(n1),values1,align='center', fc='#80d0f1', ec='w')
ax2.barh(range(n2),values2,align='center', fc='#80d0f1', ec='w')

# ====================================
# Here's where we change colors
# ====================================
for i,(label,val) in enumerate(list1):
    if label.title() in Testdic2:
        pass # leave it blue
    else:
        ax1.patches[i].set_color('g')
for i,(label,val) in enumerate(list2):
    if label.title() in Testdic1:
        pass # leave it blue
    else:
        ax2.patches[i].set_color('r')
# ====================================

ax1.set_yticks(range(n1))
ax2.set_yticks(range(n2))

for i, (label, val) in enumerate(list1):
    ax1.annotate(label.title(), xy=(10, i), fontsize=10, va='center')

for i, (label, val) in enumerate(list2):
    ax2.annotate(label.title(), xy=(10, i), fontsize=10, va='center')

ax1.invert_yaxis()
ax2.invert_yaxis()

plt.show()

enter image description here

Upvotes: 1

Related Questions