Scatterplot legend and fill not working in Octave - 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.

Related

Niftis being plotted skewed

When I plot single images they appear to be skewed, but doesn't appear that way when I look at the images in 3DSlicer or another viewer. I'm not sure if there's something I should be adjusting that I'm not aware of. The below is how I converted from DICOM:
dicom2nifti.convert_directory(path_to_dicom_before, path_to_dicom_before_converted, compression=True, reorient=True)
dicom2nifti.convert_directory(path_to_dicom_post, path_to_dicom_post_converted, compression=True, reorient=True)
print(glob(path_to_dicom_before_converted + '*.nii.gz'))
nii_before = nib.load(glob(path_to_dicom_before_converted + '*.nii.gz')[0])
nii_after = nib.load(glob(path_to_dicom_post_converted + '*.nii.gz')[0])
nii_before_data = nii_before.get_fdata()
nii_after_data = nii_after.get_fdata()
fig, ax = plt.subplots(figsize=[10, 5])
plotting.plot_img(nii_before, cmap='gray', axes=ax)
plt.show()
fig, ax = plt.subplots(figsize=[10, 5])
plotting.plot_img(nii_after, cmap='gray', axes=ax)
plt.show()
plt.imshow(nii_before_data[100], cmap='bone')
plt.axis('off')
plt.show()
Affine of the first:
[[-3.19454312e-01 7.17869774e-02 3.95075195e-02 6.01478424e+01]
[ 5.83867840e-02 2.97792435e-01 -2.28872180e-01 1.27874863e+02]
[ 4.69673797e-02 1.18071720e-01 5.53225577e-01 1.12181287e+03]
[ 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00]]
As you can see in this answer you are plotting the row 100 with all columns and all slices! Also you need to plot the pixel array nii_before_data and not the whole Nifti image nii_before which contains other types of data.
you can try:
nii_before = nib.load(glob(path_to_dicom_before_converted + '*.nii.gz')[0])
nii_after = nib.load(glob(path_to_dicom_post_converted + '*.nii.gz')[0])
nii_before_data = nii_before.get_fdata()
nii_after_data = nii_after.get_fdata()
## Same goes for nii_after_data
if(len(nii_before_data.shape)==3):
for slice_Number in range(nii_before_data.shape[2]):
plt.imshow(nii_before_data[:,:,slice_Number ])
plt.show()
if(len(nii_before_data.shape)==4):
for frame in range(nii_before_data.shape[3]):
for slice_Number in range(nii_before_data.shape[2]):
plt.imshow(nii_before_data[:,:,slice_Number,frame])
plt.show()
If you can provide a sample Nifti Image the solution might be more precise according to your data.

How to graph the function in matlab?

I have the following 2n*π-periodic function F(x) = sin(x/n) and I need to graph the dx/dt = γ - F(x) on the segment from 0 to 2pi. So it should look like this. I tried to do it matlab this way:
gamma = 1.01;
n=3;
[t,phi] = ode45(#(t,x)gamma-sin(x/n), [0,400], pi);
[t1,phi1] = ode45(#(t,x)gamma-sin(x/n), [112,400], 0);
[t2,phi2] = ode45(#(t,x)gamma-sin(x/n), [231,250], 0);
figure();
plot(t, phi, 'k', t1, phi1, 'k', t2, phi2, 'k');
ylim([0 2*pi]);
yticks([0 pi 2*pi]);
yticklabels(["0" "\pi" "2\pi"]);
grid on; grid minor;
title('\itsin(x/n)')
but I only got something like this. So there the lines are not transferred, but "begin anew". does anyone here know how to do that?
I get a plot similar to your first sketch, and based on your code in the comments (in future, put such additions into the question itself, use formatting to mark it as addition, and cite it then in the comment) with the changes
use pi as initial point as seen in the drawing,
use the options of the ODE solver to restrict the step size, directly and by imposing error tolerances
your original time span covers about 3 periods, reduce this to [0, 200] to get the same features as the drawing.
gamma = 1.01; n=3;
opts = odeset('AbsTol',1e-6,'RelTol',1e-9,'MaxStep',0.1);
[t, phi] = ode45(#(t,x)gamma-sin(x/n), [0,200], pi, opts);
phi = mod(phi, 2*pi);
plot(t, phi, 'k');
ylim([0 2*pi]); yticks([0 pi 2*pi]); yticklabels(["0" "\pi" "2\pi"]);
grid on; grid minor;
title('\itsin(x/n)')
To get more elaborate, use events to get points on the numerical solution where it exactly crosses the 2*pi periods, then use that to segment the solution plot (styling left out)
function [ res, term, dir ] = event(t,y)
y = mod(y+pi,2*pi)-pi;
res = [ y ];
dir = [1]; % only crossing upwards
term = [0]; % do not terminate
end%function
opts = odeset(opts,'Events',#(t,y)event(t,y));
sol = ode45(#(t,x)gamma-sin(x/n), [0,200], pi, opts);
tfs = [ sol.xe; sol.x(end) ]
N = length(tfs)
clf;
t0 = 0;
for i=1:N
tf = tfs(i);
t = linspace(t0+1e-2,tf-1e-2,150);
y = deval(sol,t); % octave: deval=#(res,t) interp1(res.x, res.y,t)
y = mod(y,2*pi);
plot(t, y);
hold on;
t0=tf;
end;
hold off;

callback function throws unexpected "nonconformant arguments" error

I'm using GNU Octave, version 4.4.1. I'm trying to make an interactive plot of a simple oscillator by including two sliders which would allow the initial velocity and oscillator mass to be changed.
The plot itself shows fine, as well as the script with one slider (for velocity). Here's a part of that script with the callback function:
function titranje_ia1 (hslider, event)
v0 = get ( hslider, "value" );
m = 1;
k = 1;
t = 0:0.1:30;
x = v0*sin(sqrt(k/m)*t);
axes ('position', [0.1, 0.2, 0.8, 0.75]);
h = plot ( t, x );
axis ([0 30 -11 11]);
set (h, "linewidth", 2);
set (gca, "xlabel", "t (s)", "ylabel", "x (m)", "fontsize", 12);
set (gca, 'XTick', 0:pi:10*pi)
set (gca, 'XTickLabel', {'0','\pi','2\pi','3\pi','4\pi','5\pi','6\pi','7\pi','8\pi','9\pi','10\pi'})
grid on;
l = legend (sprintf('v0 = %f', v0));
set (l, "fontsize", 12)
endfunction
However, when I include a second slider
function titranje_ia2 (hslider1, hslider2, event)
v0 = get ( hslider1, "value" );
m = get ( hslider2, "value" );
k = 1;
t = 0:0.1:30;
x = v0.*sin(sqrt(k./m).*t);
axes ('position', [0.1, 0.2, 0.8, 0.75]);
h = plot ( t, x );
axis ([0 30 -11 11]);
set (h, "linewidth", 2);
set (gca, "xlabel", "t (s)", "ylabel", "x (m)", "fontsize", 12);
set (gca, 'XTick', 0:pi:10*pi)
set (gca, 'XTickLabel', {'0','\pi','2\pi','3\pi','4\pi','5\pi','6\pi','7\pi','8\pi','9\pi','10\pi'})
grid on;
l = legend (sprintf('v0 = %f', v0));
set (l, "fontsize", 12)
endfunction
I receive an error:
error: titranje_ia2: product: nonconformant arguments (op1 is 0x0, op2 is 1x301)
execution error in graphics callback function
Since I know that 'k' is a scalar and 't' a vector (but I'm not sure what v0 and m would be; I suppose scalars), I included an elementwise operations in function 'x' definition. 't' size is 1x301, so I assume that 'sqrt(k./m)' is 0x0 (as seen by Octave). Shouldn't it be 1x1?
Indeed, when I try
size(m)
I receive ans = 0 0 (for size(v0) I get ans = 1 1). Could it be that there is a problem with slider definition? I include at the end both slider definitions:
%Definiramo ui element: 'klizac' za v0
hslider1 = uicontrol (
"style", "slider",
"units", "normalized",
"position", [0.1, 0.0, 0.8, 0.1],
"min", 1,
"max", 10,
"value", 4,
"callback", #titranje_ia2
);
%Definiramo ui element: 'klizac' za m
hslider2 = uicontrol (
"style", "slider",
"units", "normalized",
"position", [0.1, 0.05, 0.8, 0.1],
"min", 1,
"max", 10,
"value", 1,
"callback", #titranje_ia2
);
Thank You in advance!
Best regards,
Igor
You seem to be misunderstanding a bit how callbacks work. Whenever you interact with a uicontrol object, the associated callback is always called automatically with [at least] two arguments: the first is always the 'handle' of the corresponding uicontrol object that triggerred he callback, and the second is the type of 'event' that was triggered. Therefore your callback function needs to always have a signature of callbackname( hndl, evt ) at the very least, so that it can handle those two arguments passed to it by default.
You can specify extra arguments to passed to the callback if you want, but these will necessarily be interpreted as 3rd, 4th, and so on, inside the callback function (see example below).
If you have a case like yours where you don't really care where the event originated from, and you want to affect (or in this case 'read from') two existing uicontrols in a single callback, regardless which one triggerred the event, the simplest thing to do is to make both slider handles to be extra arguments to the callback, and simply ignore the first argument (i.e. the 'active handle') inside your callback. (in fact, you're already ignoring the 'event' argument too!).
Here's an example:
%% In file makesliders.m
function makesliders()
% Label and slider for initial velocity
IV_label = uicontrol( 'style', 'text' , 'units', 'normalized', 'position', [0.10, 0.025, 0.30, 0.075], 'string', 'Initial Velocity' );
IV_slider = uicontrol( 'style', 'slider', 'units', 'normalized', 'position', [0.45, 0.025, 0.50, 0.075], 'min', 1, 'max', 10 );
% Label and slider for oscillator mass
OM_label = uicontrol( 'style', 'text' , 'units', 'normalized', 'position', [0.10, 0.125, 0.30, 0.075], 'string', 'Oscillator Mass ' );
OM_slider = uicontrol( 'style', 'slider', 'units', 'normalized', 'position', [0.45, 0.125, 0.50, 0.075], 'min', 1, 'max', 10 );
% Set callbacks and initial values to IV and OM sliders, and plot initial graph
v0_init = 4; m_init = 1;
set( IV_slider, 'value', v0_init, 'callback', { #slider_callback, IV_slider, OM_slider } );
set( OM_slider, 'value', m_init , 'callback', { #slider_callback, IV_slider, OM_slider } );
plot_oscillation( v0_init, m_init );
endfunction
function slider_callback (active_handle, event, IV_slider, OM_slider )
v0 = get( IV_slider, 'value' );
m = get( OM_slider, 'value' );
plot_oscillation( v0, m );
endfunction
function plot_oscillation( v0, m )
k = 1;
t = 0 : 0.1 : 30;
x = v0 * sin( sqrt( k / m ) * t );
h = plot( t, x ); set( h , 'linewidth', 2);
set( gca, 'position', [0.1, 0.325, 0.85, 0.650], 'xlim', [0, 30], 'ylim', [-11, 11], 'xlabel', 't (s)', 'ylabel', 'x (m)', 'fontsize', 12, 'xtick', [0 : pi : 10 * pi], 'xticklabel', strcat( arrayfun( #num2str, 0:10, 'uniformoutput', false ), '\pi' ), 'xgrid', 'on', 'ygrid', 'on' );
l = legend( sprintf( 'v0 = %.2f, m = %.2f', v0, m ) ); set( l, 'fontsize', 12 );
endfunction

Why am I getting out of range error?

I'm building a function to extract all negatives from the list xs. Then I'm appending those negatives to a list negatives, and adding list negatives to list new_home, which may or may not already have values to it. The function was working before I added xs.pop(num). Why is it now out of range?
Here is the code:
def extract_negatives(xs,new_home=None):
negatives=[]
if new_home==None:
for num in range(len(xs)):
if xs[num] <0:
negatives.append(xs[num])
xs.pop(num)
return negatives
else:
for num in range(len(xs)):
if xs[num] <0:
new_home.append(xs[num])
xs.pop(num)
return new_home.append(negatives)
As stated, you are mutating list passed to the function and hence index is getting messed up.
If you must delete from passed list then one idea is to delete at the end of function just before you returned result. That way mutation wont affect indexing.
Also , I don't understand why you have if and else both looking for xs<0 . I cleaned up your function and got it working.
EDIT1 -Working Code
def extract_negatives(xs,new_home):
negatives=[]
for num in range(len(xs)):
if xs[num] <0:
negatives.append(xs[num])
new_home = new_home + negatives
for i in negatives:
xs.remove(i)
return new_home
new_home=[-9,-11,]
xs = [ 2 ,-3, 4, -5, 6, -7]
new_home = extract_negatives(xs,new_home)
print new_home
Output
>>>
[-9, -11, -3, -5, -7]
>>> xs
[2, 4, 6]

How can I get the color halfway between two colors?

I have two colors:
#15293E
#012549
How can I find the color that is half way in between them? Is there some way to do this calculation?
As Mr Lister just said, it is easy to automate the calculation with any programming language :
Separate your two colors into their 3 color numbers for Red, Green, Blue : (r1,g1,b1) and (r2,g2,b2).
For example #15293E, #012549 become ("15", "29", "3E"), ("01", "25", "49")
Convert each color string into an integer, specifying explicitly that you are parsing a hexadecimal-based representation of a number.
For example ("15", "29", "3E") becomes (21, 41, 62)
Calculate the average (r',g',b') = ( (r1+r2)/2, (g1+g2)/2, (b1+b2)/2 ).
For example ( (21+1)/2, (41+37)/2, (62+73)/2) = (11, 39, 67)
Convert them again to strings , specifying explicitly that you are generating two-digit hexadecimal representations (pad with a zero when necessary).
For example (11, 39, 67) -> ("0B", "27", "43")
Concatenate a hash character followed by the 3 strings
For example ("0B", "27", "43") -> "#0B2743"
Edit : Implementation is not "very easy" as I initially stated. I took the time to write the code in several languages on Programming-Idioms .
I use this website to do this task for me: ColorBlender.
The mid-color will be #0B2744.
With LESS
If you use the latest LESS CSS preprocessor then you'll notice there is a function (mix()) that does this:
mix(#15293E, #012549, 50%)
Outputs: #0b2744.
If you need to do this generically, and expect the middle colour to be visually accurate in more cases (i.e. the visual colour and tone of the mid point should "look right" to a human viewer), then as suggested above you may want to convert from RGB to HSV or HSL before calculating the mid point, and then convert back afterwards. This may differ significantly from averaging RGB values directly.
Here is some JavaScript code for the conversion to/from HSL that I found on a brief search, and that on a brief check appears to do the right thing:
github.com/mjackson/mjijackson.github.com/blob/master/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript.txt
https://web.archive.org/web/20170919064926/https://github.com/mjackson/mjijackson.github.com/blob/master/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript.txt
Just apply the rgbToHsl function to your two r,g,b colour vectors, average the two resulting vectors, and apply hslToRgb to that . . .
Handy-Dandy Function
function padToTwo(numberString) {
if (numberString.length < 2) {
numberString = '0' + numberString;
}
return numberString;
}
function hexAverage() {
var args = Array.prototype.slice.call(arguments);
return args.reduce(function (previousValue, currentValue) {
return currentValue
.replace(/^#/, '')
.match(/.{2}/g)
.map(function (value, index) {
return previousValue[index] + parseInt(value, 16);
});
}, [0, 0, 0])
.reduce(function (previousValue, currentValue) {
return previousValue + padToTwo(Math.floor(currentValue / args.length).toString(16));
}, '#');
}
console.log(hexAverage('#111111', '#333333')); // => #222222
console.log(hexAverage('#111111', '#222222')); // => #191919
console.log(hexAverage('#111111', '#222222', '#333333')); // => #222222
console.log(hexAverage('#000483', '#004B39')); // => #00275e
Like this:
function colourGradientor(p, rgb_beginning, rgb_end){
var w = p * 2 - 1;
var w1 = (w + 1) / 2.0;
var w2 = 1 - w1;
var rgb = [parseInt(rgb_beginning[0] * w1 + rgb_end[0] * w2),
parseInt(rgb_beginning[1] * w1 + rgb_end[1] * w2),
parseInt(rgb_beginning[2] * w1 + rgb_end[2] * w2)];
return rgb;
};
where p is a value between 0 and 1 specifying how far through the gradient the colour should be and rgb_beginning is the from colour and rgb_end is the to colour. Both are [r,g,b] arrays so you'll have to convert from hex first. This is a simplified version of LESS's mix function which I think is from SASS. For the poster p would be 0.5
i just wrote a function that calculates colors between two colors so here it is in case somebody needs it, i think it's quite short and readable, it accepts two colors in hex strings, and the number of colors to calculate in between, returns the colors in an array of hex strings
i took the rgbToHex and hexToRgb functions from
here
Hope this helps!
function rgbToHex(r, g, b) {
return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
}
function hexToRgb(hex) {
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result
? {
r: parseInt(result[1], 16),
g: parseInt(result[2], 16),
b: parseInt(result[3], 16)
}
: null;
}
// returns an array of startColor, colors between according to steps, and endColor
function getRamp(startColor, endColor, steps) {
var ramp = [];
ramp.push(startColor);
var startColorRgb = hexToRgb(startColor);
var endColorRgb = hexToRgb(endColor);
var rInc = Math.round((endColorRgb.r - startColorRgb.r) / (steps+1));
var gInc = Math.round((endColorRgb.g - startColorRgb.g) / (steps+1));
var bInc = Math.round((endColorRgb.b - startColorRgb.b) / (steps+1));
for (var i = 0; i < steps; i++) {
startColorRgb.r += rInc;
startColorRgb.g += gInc;
startColorRgb.b += bInc;
ramp.push(rgbToHex(startColorRgb.r, startColorRgb.g, startColorRgb.b));
}
ramp.push(endColor);
return ramp;
}
I found an npm module that does this: https://www.npmjs.com/package/color-between
Here's some example usage:
const colorBetween = require('color-between');
// rgb format
colorBetween('rgb(255, 255, 255)', 'rgb(0, 0, 0)', 0.5, 'rgb');
// output: 'rgb(128, 128, 128)'
// rgba format
colorBetween('rgba(255, 255, 255, .2)', 'rgba(0, 0, 0, .8)', 0.5, 'rgb');
// output: 'rgba(128, 128, 128, 0.5)
// hex format
colorBetween('#fff', '#000', 0.5, 'hex');
// output: '#808080'
// mixed format
colorBetween('#fff', 'rgb(0, 0, 0)', 0.5, 'hsl');
output: 'hsl(0, 0%, 50%)'
If you so wished you could do it yourself with windows calculator.
Open Windows Calculator > View > Programmer
Choose the Hex option
Enter the Hex value
Switch to Dec and write down the value given
Repeat for steps 2-4 for the second hex value
Calculate the average by adding the two Dec numbers and dividing by 2
Enter this value into calculator with the Dec option
selected then switch to the hex option and voila
Example:
15293E (HEX) = 1386814 (DEC)
012549 (HEX) = 75081 (DEC)
Mid Point = (1386814+75081)/2
Mid Point = 730947 (DEC)
730947 (DEC) = 0B2743 (HEX)
#0B2743
or use ColorBlender as mentioned above ;)
Here I leave the code that I use in my typescript app
function mixHexColors(color1: string, color2: string) {
const valuesColor1 = color1.replace('#', '').match(/.{2}/g).map((value) =>
parseInt(value, 16)
)
const valuesColor2 = color2.replace('#', '').match(/.{2}/g).map((value) =>
parseInt(value, 16)
)
const mixedValues = valuesColor1.map((value, index) =>
((value + valuesColor2[index]) / 2).toString(16).padStart(2, '')
)
return `#${mixedValues.join('')}`
}
Here's a Python version.
# -*- coding: utf-8 -*-
"""jcolor_split.py splits 2 hex color values, HEX_COLOR_1 and HEX_COLOR_2,
printing the color halfway between the two colors
Usage: jcolor_split.py HEX_COLOR_1 HEX_COLOR_2
Example: ./jcolor_split.py 3E599C 2E4892
"""
import sys
def jcolor_split(hex_color_1, hex_color_2):
print()
print (hex_color_1)
r1s = hex_color_1[0:2]
g1s = hex_color_1[2:4]
b1s = hex_color_1[4:6]
print(r1s,g1s,b1s)
print()
print (hex_color_2)
r2s = hex_color_2[0:2]
g2s = hex_color_2[2:4]
b2s = hex_color_2[4:6]
print(r2s,g2s,b2s)
# convert rgb's to ints
r1 = int(r1s, 16); g1 = int(g1s, 16); b1 = int(b1s, 16);
r2 = int(r2s, 16); g2 = int(g2s, 16); b2 = int(b2s, 16);
print()
print(r1,g1,b1)
print(r2,g2,b2)
# get the average
ra = int(round(float(r1+r2)/2))
ga = int(round(float(g1+g2)/2))
ba = int(round(float(b1+b2)/2))
print()
print(format(ra, 'x')+ format(ga, 'x')+ format(ba, 'x') )
NUM_ARGS = 2
def main():
args = sys.argv[1:]
if len(args) != NUM_ARGS or "-h" in args or "--help" in args:
print (__doc__)
sys.exit(2)
jcolor_split(args[0], args[1])
if __name__ == '__main__':
main()
sample_run = '''
PS C:\1d\JoeCodeswellHomePage> ./jcolor_split.py 3E599C 2E4892
3E599C
3E 59 9C
2E4892
2E 48 92
62 89 156
46 72 146
365097
PS C:\1d\JoeCodeswellHomePage>
'''
I know this thread is about 10 years old, but this answer might be interesting for someone who is searching for a CSS-only alternative. Therefore you can just create a CSS gradient between two colors where you set an huge size, e.g. 10000vw and set the position to center:
background: linear-gradient(90deg, rgb(255,255,0) 0%, rgb(0,0,255) 100%);
background-size: 10000vw;
background-position: center;
Based on the percentage of the gradient positions you can also set a ratio to one direction of color.