Python Forum
How to do bar graph with positive and negative values different colors? - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: Python Coding (https://python-forum.io/forum-7.html)
+--- Forum: General Coding Help (https://python-forum.io/forum-8.html)
+--- Thread: How to do bar graph with positive and negative values different colors? (/thread-37441.html)



How to do bar graph with positive and negative values different colors? - Mark17 - Jun-10-2022

I've been battling this one for over an hour so I'm going to ask for help.

I have a dataframe column that shows trade results. I want those less than zero to plot red and nonnegative values to plot green. I saw this on SO:

import numpy as np
import matplotlib.pyplot as plt

x = np.arange(10)
y = np.arange(10) * 0.1

mask1 = y < 0.5
mask2 = y >= 0.5

plt.bar(x[mask1], y[mask1], color = 'red')
plt.bar(x[mask2], y[mask2], color = 'blue')
plt.show()
Here's my attempt:

plt.figure(figsize=(15, 10))
mask1 = summary_results['ROI%'] < 0
mask2 = summary_results['ROI%'] >= 0
plt.bar(summary_results.index,summary_results['ROI%'][mask1],color = 'r')
plt.bar(summary_results.index,summary_results['ROI%'][mask2],color = 'g')
plt.grid()
plt.show()
This gives ValueError: shape mismatch: objects cannot be broadcast to a single shape .

I think the problem is the number of values either negative or nonnegative are less than the number of total values, which is conveyed by summary_results.index. I'm really not sure what to do with the x-argument. I don't really want to bring the whole index in using this approach--just the index values corresponding to the negative or nonnegative ROI% values, accordingly, as the position for the bar to be plot.

Really, I just want to go down the summary_results['ROI%'] column and plot a bar for each value. I originally thought default would be left to right, but that gave TypeError with one positional argument missing.

Another way I thought of doing this was to have color = colors where colors is a list of 'r' and 'g' depending on whether summary_results['ROI%'] is negative or nonnegative. Seems like I could do this with a list comprehension, but I'm not quite sure how to do it. I can't say if summary_results['ROI%'] < 0 because summary_results['ROI%'] is a dataframe column (Series?) and it doesn't make sense to evaluate a whole series against one value. I really mean to iterate down the series and evaluate each value. So maybe this could be done with a for loop?

colors = []
for i in summary_results['ROI%']:
    if i < 0:
        colors.append('r')
    else:
        colors.append('g')
This could work, but it seemed like the list comprehension would be simpler.

And the mask idea seems nifty... any way to make that work?


RE: How to do bar graph with positive and negative values different colors? - Mark17 - Jun-10-2022

This works for the mask approach:
plt.figure(figsize=(15, 10))
mask1 = summary_results['ROI%'] < 0
mask2 = summary_results['ROI%'] >= 0
plt.bar(summary_results.index[mask1],summary_results['ROI%'][mask1],color = 'r')
plt.bar(summary_results.index[mask2],summary_results['ROI%'][mask2],color = 'g')
plt.grid()
plt.show()