mirror of
https://github.com/red-data-tools/YouPlot.git
synced 2025-05-06 07:10:10 +08:00
Use Data struct
This commit is contained in:
parent
e887dc3f5a
commit
ff7b0680aa
@ -303,31 +303,34 @@ module Uplot
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def get_lim(str)
|
||||||
|
str.split(/-|:|\.\./)[0..1].map(&:to_f)
|
||||||
|
end
|
||||||
|
|
||||||
def run
|
def run
|
||||||
# Sometimes the input file does not end with a newline code.
|
# Sometimes the input file does not end with a newline code.
|
||||||
while input = Kernel.gets(nil)
|
while input = Kernel.gets(nil)
|
||||||
input.freeze
|
input.freeze
|
||||||
@raw_inputs << input
|
@raw_inputs << input
|
||||||
data, headers = preprocess(input)
|
@data = Preprocess.input(input, @delimiter, @headers, @transpose)
|
||||||
pp input: input, data: data, headers: headers if @debug
|
|
||||||
case plot_type
|
case plot_type
|
||||||
when :bar, :barplot
|
when :bar, :barplot
|
||||||
barplot(data, headers)
|
barplot(@data)
|
||||||
when :count, :c
|
when :count, :c
|
||||||
@count = true
|
@count = true
|
||||||
barplot(data, headers)
|
barplot(@data)
|
||||||
when :hist, :histogram
|
when :hist, :histogram
|
||||||
histogram(data, headers)
|
histogram(@data)
|
||||||
when :line, :lineplot
|
when :line, :lineplot
|
||||||
line(data, headers)
|
line(@data)
|
||||||
when :lines, :lineplots
|
when :lines, :lineplots
|
||||||
lines(data, headers)
|
lines(@data)
|
||||||
when :scatter, :scatterplot
|
when :scatter, :scatterplot
|
||||||
scatter(data, headers)
|
scatter(@data)
|
||||||
when :density
|
when :density
|
||||||
density(data, headers)
|
density(@data)
|
||||||
when :box, :boxplot
|
when :box, :boxplot
|
||||||
boxplot(data, headers)
|
boxplot(@data)
|
||||||
else
|
else
|
||||||
raise "unrecognized plot_type: #{plot_type}"
|
raise "unrecognized plot_type: #{plot_type}"
|
||||||
end.render($stderr)
|
end.render($stderr)
|
||||||
@ -336,90 +339,44 @@ module Uplot
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Transpose different sized ruby arrays
|
def barplot(data)
|
||||||
# https://stackoverflow.com/q/26016632
|
headers = data.headers
|
||||||
def transpose2(arr)
|
series = data.series
|
||||||
Array.new(arr.map(&:length).max) { |i| arr.map { |e| e[i] } }
|
if @count
|
||||||
end
|
series = Preprocess.count(series[0])
|
||||||
|
params.title = headers[0] if headers
|
||||||
def preprocess(input)
|
|
||||||
arr = CSV.parse(input, col_sep: @delimiter)
|
|
||||||
# Remove blank lines.
|
|
||||||
arr.delete([])
|
|
||||||
# Remove rows where all elements are nil
|
|
||||||
arr.delete_if { |i| i.all? nil }
|
|
||||||
p parsed_csv: arr if @debug
|
|
||||||
headers = get_headers(arr)
|
|
||||||
data = get_data(arr)
|
|
||||||
[data, headers]
|
|
||||||
end
|
|
||||||
|
|
||||||
def get_headers(data)
|
|
||||||
if @headers
|
|
||||||
if @transpose
|
|
||||||
data.map(&:first)
|
|
||||||
else
|
|
||||||
data[0]
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
def get_data(data)
|
|
||||||
if @transpose
|
|
||||||
if @headers
|
|
||||||
data.map { |row| row[1..-1] }
|
|
||||||
else
|
|
||||||
data
|
|
||||||
end
|
|
||||||
else
|
|
||||||
if @headers
|
|
||||||
transpose2(data[1..-1])
|
|
||||||
else
|
|
||||||
transpose2(data)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def preprocess_count(data)
|
|
||||||
# tally was added in Ruby 2.7
|
|
||||||
if Enumerable.method_defined? :tally
|
|
||||||
data[0].tally
|
|
||||||
else
|
|
||||||
# https://github.com/marcandre/backports
|
|
||||||
data[0].each_with_object(Hash.new(0)) { |item, res| res[item] += 1 }
|
|
||||||
.tap { |h| h.default = nil }
|
|
||||||
end
|
|
||||||
.sort { |a, b| a[1] <=> b[1] }
|
|
||||||
.reverse
|
|
||||||
.transpose
|
|
||||||
end
|
|
||||||
|
|
||||||
def barplot(data, headers)
|
|
||||||
data = preprocess_count(data) if @count
|
|
||||||
params.title ||= headers[1] if headers
|
params.title ||= headers[1] if headers
|
||||||
UnicodePlot.barplot(data[0], data[1].map(&:to_f), **params.to_hc)
|
labels = series[0]
|
||||||
|
values = series[1].map(&:to_f)
|
||||||
|
UnicodePlot.barplot(labels, values, **params.to_hc)
|
||||||
end
|
end
|
||||||
|
|
||||||
def histogram(data, headers)
|
def histogram(data)
|
||||||
params.title ||= headers[0] if headers # labels?
|
headers = data.headers
|
||||||
series = data[0].map(&:to_f)
|
series = data.series
|
||||||
UnicodePlot.histogram(series, **params.to_hc)
|
params.title ||= data.headers[0] if headers
|
||||||
|
values = series[0].map(&:to_f)
|
||||||
|
UnicodePlot.histogram(values, **params.to_hc)
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_lim(str)
|
def line(data)
|
||||||
str.split(/-|:|\.\./)[0..1].map(&:to_f)
|
headers = data.headers
|
||||||
end
|
series = data.series
|
||||||
|
if series.size == 1
|
||||||
def line(data, headers)
|
# If there is only one series, it is assumed to be sequential data.
|
||||||
if data.size == 1
|
|
||||||
params.ylabel ||= headers[0] if headers
|
params.ylabel ||= headers[0] if headers
|
||||||
y = data[0].map(&:to_f)
|
y = series[0].map(&:to_f)
|
||||||
UnicodePlot.lineplot(y, **params.to_hc)
|
UnicodePlot.lineplot(y, **params.to_hc)
|
||||||
else
|
else
|
||||||
params.xlabel ||= headers[0] if headers
|
# If there are 2 or more series,
|
||||||
params.ylabel ||= headers[1] if headers
|
# assume that the first 2 series are the x and y series respectively.
|
||||||
x = data[0].map(&:to_f)
|
if headers
|
||||||
y = data[1].map(&:to_f)
|
params.xlabel ||= headers[0]
|
||||||
|
params.ylabel ||= headers[1]
|
||||||
|
end
|
||||||
|
x = series[0].map(&:to_f)
|
||||||
|
y = series[1].map(&:to_f)
|
||||||
UnicodePlot.lineplot(x, y, **params.to_hc)
|
UnicodePlot.lineplot(x, y, **params.to_hc)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -428,65 +385,73 @@ module Uplot
|
|||||||
(method1.to_s + '!').to_sym
|
(method1.to_s + '!').to_sym
|
||||||
end
|
end
|
||||||
|
|
||||||
def xyy_plot(data, headers, method1) # improve method name
|
def xyy_plot(data, method1)
|
||||||
|
headers = data.headers
|
||||||
|
series = data.series
|
||||||
method2 = get_method2(method1)
|
method2 = get_method2(method1)
|
||||||
data.map! { |series| series.map(&:to_f) }
|
series.map! { |s| s.map(&:to_f) }
|
||||||
params.name ||= headers[1] if headers
|
if headers
|
||||||
params.xlabel ||= headers[0] if headers
|
params.name ||= headers[1]
|
||||||
params.ylim ||= data[1..-1].flatten.minmax # need?
|
params.xlabel ||= headers[0]
|
||||||
plot = UnicodePlot.public_send(method1, data[0], data[1], **params.to_hc)
|
end
|
||||||
2.upto(data.size - 1) do |i|
|
params.ylim ||= series[1..-1].flatten.minmax # why need?
|
||||||
UnicodePlot.public_send(method2, plot, data[0], data[i], name: headers[i])
|
plot = UnicodePlot.public_send(method1, series[0], series[1], **params.to_hc)
|
||||||
|
2.upto(series.size - 1) do |i|
|
||||||
|
UnicodePlot.public_send(method2, plot, series[0], series[i], name: headers&.[](i))
|
||||||
end
|
end
|
||||||
plot
|
plot
|
||||||
end
|
end
|
||||||
|
|
||||||
def xyxy_plot(data, headers, method1) # improve method name
|
def xyxy_plot(data, method1)
|
||||||
|
headers = data.headers
|
||||||
|
series = data.series
|
||||||
method2 = get_method2(method1)
|
method2 = get_method2(method1)
|
||||||
data.map! { |series| series.map(&:to_f) }
|
series.map! { |s| s.map(&:to_f) }
|
||||||
data = data.each_slice(2).to_a
|
series = series.each_slice(2).to_a
|
||||||
params.name ||= headers[0] if headers
|
params.name ||= headers[0] if headers
|
||||||
params.xlim = data.map(&:first).flatten.minmax
|
params.xlim = series.map(&:first).flatten.minmax # why need?
|
||||||
params.ylim = data.map(&:last).flatten.minmax
|
params.ylim = series.map(&:last).flatten.minmax # why need?
|
||||||
x1, y1 = data.shift
|
x1, y1 = series.shift
|
||||||
plot = UnicodePlot.public_send(method1, x1, y1, **params.to_hc)
|
plot = UnicodePlot.public_send(method1, x1, y1, **params.to_hc)
|
||||||
data.each_with_index do |(xi, yi), i|
|
series.each_with_index do |(xi, yi), i|
|
||||||
UnicodePlot.public_send(method2, plot, xi, yi, name: headers[(i + 1) * 2])
|
UnicodePlot.public_send(method2, plot, xi, yi, name: headers&.[]((i + 1) * 2))
|
||||||
end
|
end
|
||||||
plot
|
plot
|
||||||
end
|
end
|
||||||
|
|
||||||
def lines(data, headers)
|
def lines(data)
|
||||||
case @fmt
|
case @fmt
|
||||||
when 'xyy'
|
when 'xyy'
|
||||||
xyy_plot(data, headers, :lineplot)
|
xyy_plot(data, :lineplot)
|
||||||
when 'xyxy'
|
when 'xyxy'
|
||||||
xyxy_plot(data, headers, :lineplot)
|
xyxy_plot(data, :lineplot)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def scatter(data, headers)
|
def scatter(data)
|
||||||
case @fmt
|
case @fmt
|
||||||
when 'xyy'
|
when 'xyy'
|
||||||
xyy_plot(data, headers, :scatterplot)
|
xyy_plot(data, :scatterplot)
|
||||||
when 'xyxy'
|
when 'xyxy'
|
||||||
xyxy_plot(data, headers, :scatterplot)
|
xyxy_plot(data, :scatterplot)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def density(data, headers)
|
def density(data)
|
||||||
case @fmt
|
case @fmt
|
||||||
when 'xyy'
|
when 'xyy'
|
||||||
xyy_plot(data, headers, :densityplot)
|
xyy_plot(data, :densityplot)
|
||||||
when 'xyxy'
|
when 'xyxy'
|
||||||
xyxy_plot(data, headers, :densityplot)
|
xyxy_plot(data, :densityplot)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def boxplot(data, headers)
|
def boxplot(data)
|
||||||
headers ||= (1..data.size).map(&:to_s)
|
headers = data.headers
|
||||||
data.map! { |series| series.map(&:to_f) }
|
series = data.series
|
||||||
UnicodePlot.boxplot(headers, data, params.to_hc)
|
headers ||= (1..series.size).map(&:to_s)
|
||||||
|
series.map! { |s| s.map(&:to_f) }
|
||||||
|
UnicodePlot.boxplot(headers, series, params.to_hc)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
Loading…
Reference in New Issue
Block a user