Sumowanie kolorowych wykresów

9

W niektórych przypadkach, często w fizyce, trzeba sumować wykresy. Twoim wyzwaniem jest napisanie, w wybranym języku, programu lub funkcji, która pobiera wiele wykresów jako obrazy, oblicza wszystkie możliwe sumy i generuje wynik.

Wykresy

Wykresy to obrazy, które zawierają białe ( rgb(255, 255, 255)) tło z białymi pikselami w każdej kolumnie. Przykłady:

przykładowy wykres przykładowy wykres przykładowy wykres

Wartości skryptu są reprezentowane jako pozycje Y kolorowych pikseli. Wartość przy określonej współrzędnej X jest równa pozycji Y najwyższego kolorowego piksela w tej kolumnie, przy współrzędnych zaczynających się od 0 w lewym dolnym rogu. Ze względów estetycznych poniżej tych pikseli mogą znajdować się dodatkowe kolorowe piksele.

Zadanie

Twoim zadaniem jest napisanie, w wybranym języku, programu lub funkcji, która pobiera wiele wykresów jako obrazy, oblicza wszystkie możliwe 2^n - 1sumy i wyświetla wynik.

Suma wykresów to wykres, na którym wartość każdej kolumny jest równa sumie wartości odpowiedniej kolumny na każdym z wykresów wejściowych.

Wykresy będą dostępne w wielu kolorach. Obraz wynikowy musi zawierać wszystkie możliwe sumy wykresów jak inne wykresy, w tym wykresy oryginalne, ale z wyłączeniem sumy zerowej.

Kolor każdej sumy jest określany przez średnią kolorów zawartych wykresów, na przykład wykresów kolorów rgb(255, 0, 255)i rgb(0, 255, 255)tworzy wykres rgb(128, 128, 255)(może być również zaokrąglony w dół).

Wynikowy obraz powinien być tak wysoki, jak to konieczne, aby pasował do wszystkich wykresów. Oznacza to, że być może będziesz musiał wydrukować obraz większy niż którekolwiek z wejść.

Kolejność, w jakiej wykresy wynikowe są rysowane na obrazie wynikowym, nie ma znaczenia, tzn. Jeśli wykresy wynikowe nachodzą na siebie, możesz wybrać, który z nich jest na górze, ale musi to być jeden z wykresów, a nie kombinacja ich kolorów.

Możesz założyć, że obrazy wejściowe mają równą szerokość, że wszystkie kolumny obrazów mają co najmniej jeden inny niż biały piksel i że wysokość obrazów (łącznie z danymi wyjściowymi) jest mniejsza niż 4096 pikseli.

Przykład

Wejście A:

przykładowy wykres a

Wejście B:

przykładowy wykres b

Przykładowe dane wyjściowe:

przykładowa suma wykresu

(Jeśli ktoś jest zainteresowany, skopiowałem dane dla nich z wykresów giełdowych przypadkowych firm. To był pierwszy sposób, w jaki udało mi się uzyskać realistyczne dane jako CSV.)

Zasady

  • Możesz wybrać dowolny format pliku obrazu bitmapowego.
  • Możesz wybrać dowolny format pliku wyjściowego obrazu bitmapowego, który nie musi być zgodny z danymi wejściowymi.
  • Możesz korzystać z bibliotek przetwarzania obrazu, jednak wszelkie funkcje umożliwiające bezpośrednie wykonanie tego zadania są zabronione.
  • Obowiązują standardowe luki .
  • To jest , więc wygrywa najkrótszy kod w bajtach.

Skrypt generatora wykresów

Oto skrypt w języku Python 2, który generuje wykresy. Dane wejściowe są podawane w wierszach, z trzema pierwszymi liniami jako kolorem RGB, a pozostałe jako danymi, zakończonymi przez EOF.

import PIL.Image as image
import sys

if len(sys.argv) < 2:
    sys.stderr.write("Usage: graphgen.py <outfile> [infile]")
    exit(1)
outfile = sys.argv[1]
if len(sys.argv) > 2:
    try:
        stream = open(sys.argv[2], "r")
        data = stream.read()
        stream.close()
    except IOError as err:
        if err.errno == 2:
            sys.stderr.write("File \"{0}\" not found".format(sys.argv[2]))
        else:
            sys.stderr.write("IO error {0}: {1}".format(err.errno, err.strerror))
        exit(1)
else:
    data = sys.stdin.read()

try:
    items = map(int, data.strip().split("\n"))
    red, green, blue = items[:3]
    items = items[3:]
    highest = max(items)
except (ValueError, TypeError, IndexError):
    sys.stderr.write("Invalid value(s) in input")

img = image.new("RGB", (len(items), highest + 1), (255, 255, 255))

prev = items[0]
img.putpixel((0, highest - items[0]), (red, green, blue))
for x, item in enumerate(items[1:]):
    img.putpixel((x + 1, highest - item), (red, green, blue))
    if item < prev:
        for i in range(item + 1, prev):
            img.putpixel((x, highest - i), (red, green, blue))
    else:
        for i in range(prev + 1, item):
            img.putpixel((x + 1, highest - i), (red, green, blue))
    prev = item

img.save(outfile, "png")
PurkkaKoodari
źródło
@ MartinBüttner Obecnie tworzę jeden dla dwóch wykresów. Robię to ręcznie (nie ma jeszcze referencji), więc nie wiem, czy mam cierpliwość na 3. Ponadto trzech podanych przeze mnie osób nie można zsumować, ponieważ mają one różne szerokości.
PurkkaKoodari
Więc jeśli istnieją nwykresy wejściowe, 2^n - 1na obrazie wyjściowym będą linie?
Peter Taylor
@PeterTaylor Tak.
PurkkaKoodari
Rozumiem, że dane wyjściowe nie muszą zawierać żadnych pionowych linii? Tylko najwyższy piksel w każdej kolumnie?
Martin Ender
@ MartinBüttner To prawda, ponieważ dane te można nadal analizować jako wykres zgodnie z definicją w pierwszej sekcji.
PurkkaKoodari

Odpowiedzi:

3

MATLAB, 405

Zadzwoń przez: f('http://i.stack.imgur.com/ffCzR.png','http://i.stack.imgur.com/zHldg.png')

function f(varargin)
for k=1:nargin
i=im2double(imread(varargin{k}))
V(k,:)=size(i,1)-cellfun(@(V)find(any(V~=1,3),1),num2cell(i,[1,3]))
C(k,:)=i(find(any(i(:,1,:)~=1,3),1),1,:)
end
s=2^nargin-1
G=dec2bin(1:s)-'0'
C=bsxfun(@rdivide,G*C,sum(G,2))
V=G*V
m=max(V(:))
r=ones(m+1,size(V,2))
g=r
b=r
for i=1:s
M=bsxfun(@eq,(m:-1:0).',V(i,:))
r(M)=C(i,1)
g(M)=C(i,2)
b(M)=C(i,3)
end
imwrite(cat(3,r,g,b),'S.png')
knedlsepp
źródło
4

Python, 422

Zadzwoń z wiersza poleceń python plotsum im1.png im2.png im3.png

import sys
from numpy import*
from scipy import misc as m
R=m.imread
r=range
a=array
N=sys.args[1:]
L=len(N)
P=[map(argmin,R(n,1).T)for n in N]               #converts image to list of heights, counting from the top
C=a([R(N[i])[P[i][0],0,:]for i in r(L)])         #finds and stores the colour
P=a([len(R(N[i]))-a(P[i])for i in r(L)])         #flips the numbers, measures actual heights from bottom
w=len(P[0])
h=max(sum(P,0))+1                                    #compute dimensions
G=ones((h,w,3))*255                                  #and make a white grid
for i in r(1,2**L):
 z=where(a(list(bin(i)[2:].zfill(L)))=='1');y=sum(P[z],0)    #sum the graphs
 for x in r(w):G[y[x],x,:]=average(C[z],0)                   #average the colours
m.imsave('S.png',G[::-1])                            #flip image vertically and save

Przykładowe dane wyjściowe
wprowadź opis zdjęcia tutaj
Kolejny przykład
wprowadź opis zdjęcia tutaj

To była trudna, wysokopoziomowe operacje tablicowe i używanie tablic jako indeksów bardzo tu pomaga. Nie oczekuję rozwiązań poniżej 1000 bajtów oprócz Mathematica i Matlab

DenDenDo
źródło