Colored Bar Graph According to its Value - GNU Octave - octave

I want to set the color of the bar graph according to its value. Here is the data
Kp index
UT
0
76.00
2
76.12
5
76.25
6
76.37
5
76.50
8
76.62
8
76.75
7
76.87
8
77.00
This is what I wan to replicate:
**0-3 = green;
4 = yellow;
5-9 = red**
I tried for loop but it was not successful.
Thank you for your help.

You can draw your bar graph one bar at a time, so that you can have full control of each bar as a separate graphics object:
x = 1:10;
y = randi( 10, [1,10] );
colours = { 'g', 'g', 'g', 'g', 'y', 'r', 'r', 'r', 'r', 'r' };
hold on
for i = 1 : length(x)
H(i) = bar( x(i), y(i), 0.4, 'facecolor', colours{i} );
endfor
hold off;
PS. Alternatively, if you don't want that much fine-grained control, and you know that a group will always have the same colour, then you can draw each 'group' separately, instead of each bar separately, and simply set a single colour for the whole group.

Related

Csv reader PyQt5 [duplicate]

I've an iterable list of over 100 elements. I want to do something after every 10th iterable element. I don't want to use a counter variable. I'm looking for some solution which does not includes a counter variable.
Currently I do like this:
count = 0
for i in range(0,len(mylist)):
if count == 10:
count = 0
#do something
print i
count += 1
Is there some way in which I can omit counter variable?
for count, element in enumerate(mylist, 1): # Start counting from 1
if count % 10 == 0:
# do something
Use enumerate. Its built for this
Just to show another option...hopefully I understood your question correctly...slicing will give you exactly the elements of the list that you want without having to to loop through every element or keep any enumerations or counters. See Explain Python's slice notation.
If you want to start on the 1st element and get every 10th element from that point:
# 1st element, 11th element, 21st element, etc. (index 0, index 10, index 20, etc.)
for e in myList[::10]:
<do something>
If you want to start on the 10th element and get every 10th element from that point:
# 10th element, 20th element, 30th element, etc. (index 9, index 19, index 29, etc.)
for e in myList[9::10]:
<do something>
Example of the 2nd option (Python 2):
myList = range(1, 101) # list(range(1, 101)) for Python 3 if you need a list
for e in myList[9::10]:
print e # print(e) for Python 3
Prints:
10
20
30
...etc...
100
for i in range(0,len(mylist)):
if (i+1)%10==0:
do something
print i
A different way to approach the problem is to split the iterable into your chunks before you start processing them.
The grouper recipe does exactly this:
from itertools import izip_longest # needed for grouper
def grouper(iterable, n, fillvalue=None):
"Collect data into fixed-length chunks or blocks"
# grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx
args = [iter(iterable)] * n
return izip_longest(fillvalue=fillvalue, *args)
You would use it like this:
>>> i = [1,2,3,4,5,6,7,8]
>>> by_twos = list(grouper(i, 2))
>>> by_twos
[(1, 2), (3, 4), (5, 6), (7, 8)]
Now, simply loop over the by_twos list.
You can use range loops to iterate through the length of mylist in multiples of 10 the following way:
for i in range(0,len(mylist), 10):
#do something

Plotly Express: Prevent bars from stacking when Y-axis catgories have the same name

I'm new to plotly.
Working with:
Ubuntu 20.04
Python 3.8.10
plotly==5.10.0
I'm doing a comparative graph using a horizontal bar chart. Different instruments measuring the same chemical compounds. I want to be able to do an at-a-glance, head-to-head comparison if the measured value amongst all machines.
The problem is; if the compound has the same name amongst the different instruments - Plotly stacks the data bars into a single bar with segment markers. I very much want each bar to appear individually. Is there a way to prevent Plotly Express from automatically stacking the common bars??
Examples:
CODE
gobardata = []
for blended_name in _df[:20].blended_name: # should always be unique
##################################
# Unaltered compound names
compound_names = [str(c) for c in _df[_df.blended_name == blended_name]["injcompound_name"].tolist()]
# Random number added to end of compound_names to make every string unique
# compound_names = ["{} ({})".format(str(c),random.randint(0, 1000)) for c in _df[_df.blended_name == blended_name]["injcompound_name"].tolist()]
##################################
deltas = _df[_df.blended_name == blended_name]["delta_rettime"].to_list()
gobardata.append(
go.Bar(
name = blended_name,
x = deltas,
y = compound_names,
orientation='h',
))
fig = go.Figure(data = gobardata)
fig.update_traces(width=1)
fig.update_layout(
bargap=1,
bargroupgap=.1,
xaxis_title="Delta Retention Time (Expected - actual)",
yaxis_title="Instrument name(Injection ID)"
)
fig.show()
What I'm getting (Using actual, but repeated, compound names)
What I want (Adding random text to each compound name to make it unique)
OK. Figured it out. This is probably pretty klugy, but it consistently works.
Basically...
Use go.FigureWidget...
...with make_subplots having a common x-axis...
...controlling the height of each subplot based on number of bars.
Every bar in each subplot is added as an individual trace...
...using a dictionary matching bar name to a common color.
The y-axis labels for each subplot is a list containing the machine name as [0], and then blank placeholders ('') so the length of the y-axis list matches the number of bars.
And manually manipulating the legend so each bar name appears only once.
# Get lists of total data
all_compounds = list(_df.injcompound_name.unique())
blended_names = list(_df.blended_name.unique())
#################################################################
# The heights of each subplot have to be set when fig is created.
# fig has to be created before adding traces.
# So, create a list of dfs, and use these to calculate the subplot heights
dfs = []
subplot_height_multiplier = 20
subplot_heights = []
for blended_name in blended_names:
df = _df[(_df.blended_name == blended_name)]#[["delta_rettime", "injcompound_name"]]
dfs.append(df)
subplot_heights.append(df.shape[0] * subplot_height_multiplier)
chart_height = sum(subplot_heights) # Prep for the height of the overall chart.
chart_width = 1000
# Make the figure
fig = make_subplots(
rows=len(blended_names),
cols=1,
row_heights = subplot_heights,
shared_xaxes=True,
)
# Create the color dictionary to match a color to each compound
_CSS_color = CSS_chart_color_list()
colors = {}
for compound in all_compounds:
try: colors[compound] = _CSS_color.pop()
except IndexError:
# Probably ran out of colors, so just reuse
_CSS_color = CSS_color.copy()
colors[compound] = _CSS_color.pop()
rowcount = 1
for df in dfs:
# Add bars individually to each subplot
bars = []
for label, labeldf in df.groupby('injcompound_name'):
fig.add_trace(
go.Bar(x = labeldf.delta_rettime,
y = [labeldf.blended_name.iloc[0]]+[""]*(len(labeldf.delta_rettime)-1),
name = label,
marker = {'color': colors[label]},
orientation = 'h',
),
row=rowcount,
col=1,
)
rowcount += 1
# Set figure to FigureWidget
fig = go.FigureWidget(fig)
# Adding individual traces creates redundancies in the legend.
# This removes redundancies from the legend
names = set()
fig.for_each_trace(
lambda trace:
trace.update(showlegend=False)
if (trace.name in names) else names.add(trace.name))
fig.update_layout(
height=chart_height,
width=chart_width,
title_text="∆ of observed RT to expected RT",
showlegend = True,
)
fig.show()

Grouped bar plot with multiple labels in x-axis

I am trying to replicate something close to the following graph in gnuplot as I need to use it on a latex paper. I have tried a lot but I cannot make the two-line labels at the bottom. Could you please guide me? Also, how is it possible to have the % character as part of a label in the x-axis? Latex complains about it.
The data are in the following format (example). Each different color corresponds to different method. Blue is method 1 (m1), orange is method 2 (m2), and brown is method 3 (m3)
#% system1-m1 system1-m2 system1-m3 system2-m1 ...
0.5% 16 8 15 6
1% 15 17 16 8
2% 12 10 20 15
Thanks
Edit
My code so far is as follows:
set rmargin 0
set key outside tmargin center top horizontal width 3
set border
set grid
set boxwidth 0.8
set style fill solid 1.00
set xtics nomirror rotate by 0
set format y '%1.f'
set yrange [0 to 22]
set ylabel 'Gain (\%)'
set ytics 0, 5
set style data histograms
set label 1 at -0.3, -4 '|---------System 1------------|'
set label 2 at 2.7, -4 '|---------System 2------------|'
plot "./data/metrics.dat" using 2:xtic(1) title 'Method 1' ,\
"" using 3 title 'Method 2', \
"" using 4 title 'Method 3',
And I have modified the .dat file as
0.5 16 8 15
1.0 15 17 16
2.0 12 10 20
0.5 13 6 4
1.0 11 13 13
2.0 14 12 14
because I cannot make it print the % character. The output graph is
As you can see it is not scalable. I have to put labels by hand (trial and error) and also the labels below the x-axis do not contain the % character.
We've been close: set format x '%.1f\%%'. The following works for me with cairolatex terminal (check help cairolatex).
Code:
### percent sign for tic label in TeX
reset session
set term cairolatex
set output 'SO70029830.tex'
set title 'Some \TeX\ or \LaTeX\ title: $a^2 + b^2 = c^2$'
set format x '%.1f\%%'
plot x
set output
### end of code
Result: (screenshot)
Addition:
Sorry, I forgot the second part of your question: the labels.
Furthermore, in your graph you are using xtic(1) as tic labels, i.e. text format, so the command set format x '%.1f\%%' from my answer above will not help here. One possible solution would be to create and use your special TeX label like this:
myTic(col) = sprintf('%.1f\%%',column(col))
plot $Data using 2:xtic(myTic(1))
For the labels, I would use arrows and labels. Each histogram is placed at integer numbers starting from 0. So, the arrows have to go from x-values -0.5 to 2.5 and from 2.5 to 5.5. The labels are placed at x-value 1 and 4. There is certainly room for improvements.
Code:
### tic labels with % for TeX and lines/labels
reset session
set term cairolatex
set output 'SO70029830.tex'
$Data <<EOD
0.5 16 8 15
1.0 15 17 16
2.0 12 10 20
0.5 13 6 4
1.0 11 13 13
2.0 14 12 14
EOD
set rmargin 0
set key outside center top horizontal width 3
set border
set grid
set boxwidth 0.8
set style fill solid 1.00
set xtics nomirror rotate by 0
set format y '%1.f'
set yrange [0 to 22]
set ylabel 'Gain (\%)'
set ytics 0, 5
set style data histograms
set bmargin 4
set arrow 1 from -0.5, screen 0.05 to 2.5, screen 0.05 heads size 0.05,90
set label 1 at 1, screen 0.05 'System 1' center offset 0,-0.7
set arrow 2 from 2.5, screen 0.05 to 5.5, screen 0.05 heads size 0.05,90
set label 2 at 4, screen 0.05 'System 2' center offset 0,-0.7
myTic(col) = sprintf('%.1f\%%',column(col))
plot $Data using 2:xtic(myTic(1)) title 'Method 1' ,\
"" using 3 title 'Method 2', \
"" using 4 title 'Method 3',
set output
### enf of code
Result: (screenshot from LaTeX document)
As an alternative to the answer of #theozh there is already a build-in function called newhistogram that directly allows to place labels below the x-axis.
While working on an an answer that involves newhistogram I discovered a bug with horizontal key layout, which is now fixed thanks to Ethan. So, with the newest development version of gnuplot at hand I am able to offer a solution that allows for more finetuning like the ability to change the inter-group spacing.
set terminal cairolatex standalone colour header '\usepackage{siunitx}' size 25cm, 7cm
# generate some random data in your format
N = 7
set print $MYDATA
do for [i=1:N] {
print sprintf('0.5 %f %f %f', rand(0)*20, rand(0)*20, rand(0)*20)
print sprintf('1.0 %f %f %f', rand(0)*20, rand(0)*20, rand(0)*20)
print sprintf("2.0 %f %f %f", rand(0)*20, rand(0)*20, rand(0)*20)
}
unset print
# define the look
set style data histograms
set style fill solid 1.00
set boxwidth 0.8
set key horizontal outside t c width 1
set xr [-1:27]
set xtics nomirror
set ytics out 5 nomirror
set grid y # I don't think vertical grid lines are needed here
set ylabel 'Gain/\%'
set rmargin 0.01
set bmargin 3
As for the tic marks, I adapted #theozh's answer a bit – since you are using LaTeX already, you might as well parse the numbers through siunitx, which will ensure correct spacing between numbers and the unit:
myTic(col) = sprintf('\SI{%.1f}{\%}',column(col))
The vertical separation marks like in the screenshot you provided can be created iteratively:
do for [i=1:N+1] {set arrow i from first -1+(i-1)*4, graph 0 to first -1+(i-1)*4, screen 0 lw 2 nohead}
Now for the actual plot command:
plot newhistogram "System 1" offset 0,-0.5 lt 1, for [i=1:3] $MYDATA using (column(i+1)):xtic(myTic(1)) every ::0::2 title sprintf('Method %.0f',i), \
newhistogram "System 2" offset 0,-0.5 lt 1 at 4, for [i=1:3] $MYDATA using (column(i+1)):xtic(myTic(1)) every ::3::5 not, \
newhistogram "System 3" offset 0,-0.5 lt 1 at 8, for [i=1:3] $MYDATA using (column(i+1)):xtic(myTic(1)) every ::6::8 not, \
newhistogram "System 4" offset 0,-0.5 lt 1 at 12, for [i=1:3] $MYDATA using (column(i+1)):xtic(myTic(1)) every ::9::11 not, \
newhistogram "System 5" offset 0,-0.5 lt 1 at 16, for [i=1:3] $MYDATA using (column(i+1)):xtic(myTic(1)) every ::12::14 not, \
newhistogram "System 6" offset 0,-0.5 lt 1 at 20, for [i=1:3] $MYDATA using (column(i+1)):xtic(myTic(1)) every ::15::17 not, \
newhistogram "System 7" offset 0,-0.5 lt 1 at 24, for [i=1:3] $MYDATA using (column(i+1)):xtic(myTic(1)) every ::18::20 not
That looks very nasty, what's going on here?
newhistogram creates a new group of histogram boxes, its first argument is a string that is put below the x axis. It is also told to reset the linetype counter to 1.
Then the three columns of the data are plotted iteratively, but not all lines at once, but only the first three lines, with corresponding key entries.
Then another newhistogram is created and it is told to start at the x value 4 (which would be the default anyway). Now the next three lines are plotted, and so.
Now, every time newhistogram is called an empty line is added to key, hence making trouble with the key placement. Therefore the new keyword introduced by Ethan is
set style histogram nokeyseparators
which will disable this behaviour.
As you see, the spaces between the groups are larger than inside. You might want to change the numbers in newhistogram at ... and adjust the calculation of vertical line positions accordingly.
The plot command is of course highly repetitive, and it would be nice to make it an iterative call. Unfortunately, iterations that span multiple objects are not possible within a plot call. However, it is possible to iteratively put the plot command string together (excessively using string concatenation .) and then plot it.
A = 'newhistogram "System '
B = '" offset 0,-0.5 lt 1'
C = 'for [i=1:3] $MYDATA using (column(i+1)):xtic(myTic(1)) every ::'
myplotstring = A.'1'.B.', '.C."0::2 title sprintf('Method %.0f',i),"
do for [i=2:N] {myplotstring = myplotstring.A.i.B.'at '.(4*(i-1)).', '.C.(3*i-3).'::'.(3*i-1).' not, '}
plot #myplotstring

Define custom linestyles in Octave for use on multiple figures

I'd like to define line styles in Octave (like in gnuplot) for further usage:
I was thinking about something like that:
styles = {['color',[.5 .2 .8],'--', 'linewidth', 1.25], ['or', markersize, 4],
['-sb', markersize, 2]}
plot (x,y, styles{1})
plot (x,y, styles{2})
and so on. But such a thing didn't work. Does someone have any suggestions how to solve this?
Thanks in advance.
Let's have a look, what MATLAB does and copy the ideas: You can use Comma-Separated Lists as Function Call Arguments. Actually, there's an example describing exactly, what you want to achieve. Nevertheless, to get this working as you'd like to, you also have to "disassemble" the LineSpec properly. Please see the following code snippet to get the solution for the examples given by you.
x = linspace(0, 2*pi, 50);
% styles = {['color',[.5 .2 .8],'--', 'linewidth', 1.25], ['or', markersize, 4], ['-sb', markersize, 2]}
styles = {
{'Color', [.5 .2 .8], 'LineStyle', '--', 'LineWidth', 1.25}, ...
{'Color', 'r', 'Marker', 'o', 'MarkerSize', 4}, ...
{'Color', 'b', 'LineStyle', '-', 'Marker', 's', 'MarkerSize', 2} ...
};
figure(1);
hold on;
for ii = 1:numel(styles)
plot(x, sin(x + ii * pi/4), styles{ii}{:});
end
hold off;
legend();
And, here is an exemplary output:

Scatterplot legend and fill not working in Octave

I am using Octave.
My problem is this: I want to fill the bubbles of my scatter plot, as well as place a legend. But I get errors when I try to use 'filled', and no legend comes up when I use legend(...).
Part of my code looks like this:
%ALL SAMPLES, PHI(Signal) # THETA(Sample)=0
figure(5)
plot( Angles(:,1)([18:27]), ALL([18:27]), 10, [1 0 1]); %Magenta
hold on
scatter(Angles(:,1)([68:76]), ALL([68:76]), 10, [0 0 0]); %Black
scatter(Angles(:,1)([86:95]), ALL([86:95]), 10, [1 0 0]); %Red
scatter(Angles(:,1)([119:127]), ALL([119:127]), 10, [0 1 0]); %Green
scatter(Angles(:,1)([133:141]), ALL([133:141]), 10, [0 0 1]); %Blue
hold off
xlabel('Signal PMT angle (Sample angle at 0)');
ylabel('Normalized (signal/monitor) intensity');
legend('Control', 'Control', '1+2','Virgin','Cycle #1', 'Location','NorthEast');
title('Plot of All Samples, "-int Intensity"')
I know it should beplot( Angles(:,1)([18:27]), ALL([18:27]), 10, [1 0 1], 'filled');, but I receive errors when I do that. Also, a legend never seems to show up.
Apparently there is a problem with using legend with scatter in Octave. Based on this post:
http://octave.1599824.n4.nabble.com/Legend-in-scatter-plot-td3568032.html
the trick is to use the plot function to make scatter plot. I wrote the following function for plotting a bunch of scatter plots on the same axis.
This function takes in a bunch of cell arrays of the same length. Each element of the cell array corresponds to a separate series. The function returns a cell array of the same length containing the handle associated with each plot. The arguments of the function are explained below:
x_vals: a cell array of arrays of doubles corresponding to x values.
y_vals: a cell array of arrays of doubles corresponding to y values.
sizes: a cell array of doubles representing the size of the markers.
colors: a cell array of double arrays of length 3, representing [R, G, B] color values of the markers.
styles: a cell array of strings representing the shape of the markers.
function [handles] = scatter_series_set(x_vals, y_vals, sizes, colors, styles)
N = length(x_vals);
if ( (~ ( N == length(y_vals))) || (~ ( N == length(sizes))) || ...
(~ ( N == length(colors))) || (~ ( N == length(styles))) )
error('scatter_series_set: all arguments must be cell arrays of the same length');
end
%plot the first series
handles = cell([N, 1]);
handles{1} = plot(x_vals{1}, y_vals{1});
set(handles{1}, 'linestyle', 'none');
set(handles{1}, 'marker', styles{1});
set(handles{1}, 'markersize', sizes{1});
set(handles{1}, 'color', colors{1});
%plot additional series if present
if N > 1
hold on;
for ind = 2:N
handles{ind} = plot(x_vals{ind}, y_vals{ind});
set(handles{ind}, 'linestyle', 'none');
set(handles{ind}, 'marker', styles{ind});
set(handles{ind}, 'markersize', sizes{ind});
set(handles{ind}, 'color', colors{ind});
end
hold off;
end
end
The following example demonstrates how to use this function.
x1 = 0:(2*pi/100):(2*pi);
x2 = 2*x1;
y1 = sin(x1);
y2 = cos(x1);
y3 = sin(x2);
y4 = cos(x2);
names = {'a', 'b', 'c', 'd'};
x_vals = {x1, x1, x1, x1};
y_vals = {y1, y2, y3, y4};
sizes = {10, 10, 10, 10};
colors = {[1, 0, 0], [0, 0, 1], [0, 0, 0], [0.7071, 0, 0.7071]};
styles = {'^', 's', 'x', '+'}
scatter_series_set(x_vals, y_vals, sizes, colors, styles);
legend(names, 'location', 'southeast');
The example code produces the following plot:
The following works for me:
n = 100;
x = randn(n, 1);
y = randn(n, 1);
S = rand(n, 1)*20;
hold on
scatter(x(1:50), y(1:50), S(1:50), "red", "filled")
scatter(x(51:100), y(51:100), S(51:100), "green", "filled")
hold off
print('-depsc', 'bubbleplot.eps');
However, I'm not able to add a legend, and I didn't find any bug report or indication of a missing functionality for this. So, as an alternative, I would suggest adding marker and text to your plot.