How can i specify the color of a bar in a bar chart by its value? - bokeh

Well, i created a bar chart and now i want to specify the color of a bar depending of its value on y-axis. simplified- if the value is positive the bar should be red and is the value nagative the bar should be blue.
For me it's only possible to change the color along the x-axis but not the y-axis.
from bokeh.palettes import plasma
source = ColumnDataSource(data={'date' : pd.to_datetime(df_data['date'], format='%Y-%m'), 'values' : df_data['values'], 'color' : plasma(256)})
p = figure(x_axis_label='time',
x_axis_type='datetime',
y_axis_label='diff',
tools = [hover]
toolbar_location=None
title="title")
p.vbar(x = 'date',top = 'values', source=source, width=timedelta(days=20), color = 'color')
I've found an example on:
https://docs.bokeh.org/en/latest/docs/user_guide/categorical.html
But i need to differentiate or to color the bars by their values no by their number. I know my example makes no sense, but i only want to demonstrate what my expectations are.

Ok, i found a solution by myself by unsing the cut function of pandas.
import pandas as pd
import numpy as np
values = array(df_data['values']).values)
bins = [np.NINF, 0, np.inf]
categories = pd.cut(values, bins, right=False)
palette = ['blue', 'red']
colors = []
for i in categories.codes:
colors.append[palette[i]]
# Now i can add this column to my ColumnDataSource:
source = ColumnDataSource(data={'date' : pd.to_datetime(df_data['date'], format='%Y-%m'), 'values' : df_data['values'], 'color' : colors}
p.vbar(x = 'date',top = 'values', source=source, width=timedelta(days=20), color = 'colors')
Of course this is just as "quick and dirty" solution and there is enough room for optimization.

Related

Color grid lines in Julia

I would like to color the grid lines in a plot. Here is some reproducible code:
using Plots
Plots.plot(rand(10))
Output:
Imagine I want to have green grid lines, how can we change the color of grid lines in Julia? I check the docs, but I can only find attributes like alpha, line width and style and not the color.
Here is some code to get the green grid:
plt = Plots.plot(rand(10))
xaxis = Plots.get_axis(Plots.get_subplot(plt,1),:x)
yaxis = Plots.get_axis(Plots.get_subplot(plt,1),:y)
xaxis[:gridalpha] = 0.6
yaxis[:gridalpha] = 0.6
xaxis[:foreground_color_grid] = colorant"green"
yaxis[:foreground_color_grid] = colorant"green"
plt
Many other attributes are described in the docs page you linked to.

Adding values to grouped bar chart in hvplot

I'm trying to add labels to a grouped hvplot barchart.
My example dataframe has the following structure:
import pandas as pd
import numpy as np
import holoviews as hv
import hvplot.pandas
hv.extension('bokeh')
df = pd.DataFrame({'A' : ['A','B','A','B','A','B'],
'B' : [1,1,2,2,3,3],
'C' : list((range(20,26)))
})
The bar chart is created with the following code:
bar = df.hvplot.bar(x='B', y='C', by='A')
bar
hvplot bar chart
I tried to add labels according to this and this SO questions:
labels = hv.Labels(data=df, kdims=['B','A'],vdims='C')
labels
But an overlay of both plots
bar * labels
results in an error, though the dimensions seem to be the same for me.
ValueError: all the input arrays must have same number of dimensions
:Overlay
.Bars.I :Bars [B,A] (C)
.Labels.I :Labels [B,A] (C)
Any hint to the solution is appreciated. Thank you!
This is possible for normal bar charts, but unfortunately this is not possible yet for grouped barcharts: https://github.com/holoviz/holoviews/pull/3385
You could create separate bar charts per category in col A and then add labels, but you won't have a grouped bar chart then:
def barplot_and_labels_category(category):
df_subset = df[df.A == category]
plot = df_subset.hvplot.bar(x='B', y='C', ylim=(0, 30))
labels = hv.Labels(
df_subset,
kdims=['B', 'C'],
vdims='C',
).opts(text_color='black', text_font_size='20pt')
return plot * labels
(barplot_and_labels_category('A') + barplot_and_labels_category('B')).cols(1)

matplotlib bar plot add legend from categories dataframe column

I try to add the legend which should, according to my example, output:
a red square with the word fruit and
a green square with the word
veggie.
I tried several things (the example below is just 1 of the many trials), but I can't get it work.
Can someone tell me how to solve this problem?
import pandas as pd
from matplotlib import pyplot as plt
data = [['apple', 'fruit', 10], ['nanaba', 'fruit', 15], ['salat','veggie', 144]]
data = pd.DataFrame(data, columns = ['Object', 'Type', 'Value'])
colors = {'fruit':'red', 'veggie':'green'}
c = data['Type'].apply(lambda x: colors[x])
bars = plt.bar(data['Object'], data['Value'], color=c, label=colors)
plt.legend()
The usual way to create a legend for objects which are not in the axes would be to create proxy artists as shown in the legend guide
Here,
colors = {'fruit':'red', 'veggie':'green'}
labels = list(colors.keys())
handles = [plt.Rectangle((0,0),1,1, color=colors[label]) for label in labels]
plt.legend(handles, labels)
So this is a hacky solution and I'm sure there are probably better ways to do this. What you can do is plot individual bar plots that are invisible using width=0 with the original plot colors and specify the labels. You will have to do this in a subplot though.
import pandas as pd
from matplotlib import pyplot as plt
data = [['apple', 'fruit', 10], ['nanaba', 'fruit', 15], ['salat','veggie', 144]]
data = pd.DataFrame(data, columns = ['Object', 'Type', 'Value'])
colors = {'fruit':'red', 'veggie':'green'}
c = data['Type'].apply(lambda x: colors[x])
ax = plt.subplot(111) #specify a subplot
bars = ax.bar(data['Object'], data['Value'], color=c) #Plot data on subplot axis
for i, j in colors.items(): #Loop over color dictionary
ax.bar(data['Object'], data['Value'],width=0,color=j,label=i) #Plot invisible bar graph but have the legends specified
ax.legend()
plt.show()

r bokeh chart legend - placed poorly move

I have been working in flexdashboards using rbokeh to draw some dynamic graphs. Because this is a bar chart mapped to categorical data in the variable Classification, I am unable to manually create a legend, which is fine because rbokeh does it automatically.
However, I am having some issues with the legend and labeling:
It is placed horribly, I would like to tell r to place in the upper left hand corner to get it away from bars with content.
I would like to drop the red ab_line into the legend and label it (using standard legend = will not work because of the mapped variables in the base chart
This graph needs to be 508 compliant for translation, the flexdashboard is, as well as the bokeh tools on the left hand margin and the keys in the pop ups, but the values and labels remain in English. Does anyone have a way of making the charts responsive to google translate? I am fine if that involves editing the extruded page....I will just need more guidance in doing it there.
figure(title=" Confirmed & Probable Cases by Year",width= 1400, height
=350)%>%
ly_bar(x=Year, y= count, position='stack', data=probConf,
width=.9,hover=TRUE, legend=TRUE, color=Classification) %>%
x_axis(label ='Year')%>%
y_axis(label ='Cases')%>%
ly_abline(v=17.5, legend=NULL, color = "red", width =1, alpha=.5)%>%
[![enter image description here][1]][1]set_palette(discrete_color = pal_color(c("#ee9f00", "#ffcc66")))
To answer number 1, you can use legend_location to specify the placement of the legend (see example below and note I replaced the probConf data with the lattice barley dataset so that it is reproducible for others).
figure(title = " Confirmed & Probable Cases by Year", width = 1400,
height = 350, legend_location = "top_left") %>%
ly_bar(x = variety, y = yield, position = "stack", data = lattice::barley,
width = 0.9, hover = TRUE, legend = TRUE, color = year) %>%
x_axis(label = "Year") %>%
y_axis(label = "Cases") %>%
ly_abline(v = "Svansota:1", color = "red", width = 1, alpha = 0.5) %>%
set_palette(discrete_color = pal_color(c("#ee9f00", "#ffcc66")))
#2 is currently difficult to achieve in rbokeh but it should be more robust to situations like this (mixing mapped and user-defined legend entries) in the future. If ly_abline() were to accept data as an argument, you could use use a mapped variable for color to resolve the issue.
One solution that isn't very pretty is to manually draw the bar chart polygons with ly_rect (one call to ly_rect for each classification) and use custom legend entries for those and then add a custom legend entry for ly_abline.
I do not know the answer to #3.

Highlight only correct class in a different color in R histogram

I'm working on a k-Nearest Neighbors classification system, and using a "bucket voting" system that samples predicted classes and then returns a prediction based on which class got the highest number of 'votes' within the sample.
My problem is that I want to automatically generate histograms that have blue bars for the incorrect predictions and a red bar for the correctly predicted class. Here's a snippet of code:
for (class in 14:15) {
class_test_index <- which(walkTest_labels == class)
class_test <- as.numeric(walkTest_pred[class_test_index])
hist(class_test,
breaks = 0:22,
col = ifelse(class_test == class, "red", "blue"),
border = "green",
main = "Distribution by Classes",
ylab = "Count",
xlab = "Class")
}
I've just used two of the classes in my loop to illustrate. Links to the two histograms that result are here.
http://i.stack.imgur.com/VXger.png
http://i.stack.imgur.com/ChAE7.png
In both ONLY one bar, the largest one, should be red. In one of them the correct bar is red, but there's another bar that's red as well. In the other histogram there are again two bars that are red but they're both wrong.
Okay, I found an answer to my own question. Thanks to Nathan Day for suggesting I look into using the barplot() function as this is how I solved the problem.
What I did was to create a vector which contained all of my classes (a list of integers from 1 to 22). Then within the for loop I created another vector that was created by comparing each of these numbers to the class value that was being tested - if the value doesn't match it creates a value of "blue" in the vector, and if correct it creates "red".
When the barplot is created this vector is used as the color parameter, thereby adding red to the correct class and coloring all other classes blue. Voila!
Here's the code:
class_list <- 1:22
for (class in 14:15) {
class_test_index <- which(walkTest_labels == class)
class_test <- table(walkTest_pred[class_test_index])
this_class <- ifelse(class_list == class, "red", "blue")
barplot(class_test,
col = this_class,
border = "green",
main = "Distribution by Classes",
ylab = "Count",
xlab = "Class")
}
If anybody can think of a more elegant way to execute this, that would also be very much appreciated.

Resources