# draw ASCII function plots

Consider a function plot like this:

                                                       ###########
#################
####################
#######################
###########################
#############################
################################
###################################
#####################################
########################################
--------------------------------------------------------------------------------
#####################################
###################################
#################################
#############################
###########################
#######################
#####################
#################
###########


This function plot has been created with the J code below, which is not a solution to this challenge.

([: |: ([: |."1 [: #&'#'"0 [: >. [: - (* 0&>)) ,. '-' ,. [: #&'#'"0 [: <. (* 0&<)) 10 * sin 12.7 %~ i. 80


Your task is to write a function or program that takes as input from an implementation defined source that is not the source code of your entry:

1. Two positive integers
• w, the width of the plot
• h, the height of the plot
2. Two real numbers
• b, the beginning of the region to plot
• e, the end of the region to plot
3. A function f mapping real numbers to real numbers. You may assume that this function does not crash, throw an exception, return a NaN or ±∞ for arguments in the range b to e inclusive. The way in which this function is described is implementation defined, but it should be possible to use any combination of the following:
• floating point constants except NaN and ±∞
• subtraction
• multiplication
• division
• the ex function
• natural logarithm
• sine and cosine

Your function or program shall return or print out an ASCII art plot with dimensions w × h that looks like plot above and plots f in the range b to e inclusive. The plot shall be scaled so that both the topmost and bottommost line contain a # sign or a -. Your output format may diverge from the output format shown above in a meaningful way if that doesn't simplify your solution. In particular, you may exchange # and - for other characters that give the impression of black space and horizontal line.

The score of your submission is the number of tokens your program source consists of. String literals count as the length of the string they describe but at least as one point, numeric literals count as ⌈log256(|n|)⌉ where n is the number described by the numeric literal.

An identifier which is either predefined by the language or a library your submission uses or whose name can be exchanged with any other unused name counts as one character. All other identifiers count as their length in characters.

If the programming language your submission is written does not have the concept of a token, it's score is the total number of characters that can't be removed from the source without changing the meaning of the program.

The scoring rules ensure that you can indent your code and use descriptive names for your variables, etc. and lowers the edge of domain-specific languages for golfing.

The winner is the submission with the least score.

• @FryAmTheEggman I didn't know that tag existed. Thank you for the information. Feb 4, 2015 at 16:51
• If your main concern is readability of the code, ask people to include an ungolfed version. If your main concern is golfing languages, then I guess you'll have to go along with scoring by tokens, but in my experience it doesn't really help a lot, because in most languages a function call is 3 tokens (function name plus parentheses) + 1 token for the first argument + 2 tokens for every further argument (because of a delimiter like a comma), whereas in CJam, say, it's just number of arguments + 1. Feb 4, 2015 at 16:56
• I like this question, but I think it could have benefited from a pass in the sandbox. Feb 4, 2015 at 16:59
• The spec needs to explicitly state the criteria for shading a cell, because there are a number of plausible options and we can't tell which is intended. In particular, is the cheap and crappy "shade a pixel iff its midpoint is between 0 and the value at that x-coordinate" intended, or should the program attempt to compute the extrema of the image of the column and either shade the pixel iff its (centre-bottom / midpoint / centre-top) is between 0 and one of the extrema, or shade the pixel iff at least 50% of its area is? Feb 4, 2015 at 17:28
• Or, indeed, am I guessing wrongly that the shaded pixels in the column should always extend to the x-axis? For all I know, the example image shows sin(x)sin(1000x) and the line does actually pass through all of those shaded pixels. Feb 4, 2015 at 17:30

# Ruby (>=2.1), ~28.19812

As @FUZxxl considered that the scoring scheme is flawed anyway, I shall make full use of it.

eval (123125010100101102032105110116040115116114044102109116061034037115034041010098101103105110010115116114061115116114046100117112010115116114046103115117098033040039094039044039042042039041010115116114046103115117098033040047040097099111115104124097115105110104124097116097110104124097116097110050124097116097110124097115105110124097099111115124099111115104124115105110104124116097110104124115105110124099111115124116097110124115113114116124108111103049048124108111103050124103097109109097124108111103124101120112124101114102099124101114102124104121112111116041047105041123034077097116104046035123036049046100111119110099097115101125034125010115116114046103115117098033040047040101040036124091094114120093041124112105041047105041123034077097116104058058035123036049046117112099097115101125034125010101118097108040102109116037115116114041010114101115099117101032069120099101112116105111110061062101010112117116115032034105110118097108105100032105110112117116034010101120105116032049010101110100010101110100010119061105110116040065082071086046115104105102116041046116111095105010104061105110116040065082071086046115104105102116041046116111095105010098061105110116040065082071086046115104105102116041046116111095102010101061105110116040065082071086046115104105102116041046116111095102010102061105110116040065082071086046106111105110040039032039041044034045062120123037115125034041010119105110061065114114097121046110101119040104041123065114114097121046110101119040119041123039032039125125010100120061040101045098041047119046116111095102010098101103105110010121061065114114097121046110101119040119041123124120124102091098043040120043048046053041042100120093125010114101115099117101032069120099101112116105111110010112117116115032034105110118097108105100032105110112117116034010101120105116032049010101110100010114044113061121046109105110109097120010114061048032105102032114062048010113061048032105102032113060048010114045061048046048048049032105102032114061061113010121046109097112033032100111032124122124032010112121061040040122045114041042104047040113045114041046116111095102045048046053041046114111117110100010112121061048032105102032112121032060032048010112121061104045049032105102032112121062061104010112121010101110100010121048061040045114042104047040113045114041046116111095102045048046053041046114111117110100010121048061048032105102032121048060048010121048061104045049032105102032121048062061104010100121061040113045114041047104046116111095102010119046116105109101115032100111032124120124010121049044121050061091121048044121091120093093046109105110109097120010040121049046046121050041046101097099104123124122124119105110091122093091120093061063035125010119105110091121048093091120093061063045010101110100010112117116115032119105110046114101118101114115101046109097112040038058106111105110041046106111105110040034010034041010/123125010100101102032105110116040115116114044102109116061034037115034041010098101103105110010115116114061115116114046100117112010115116114046103115117098033040039094039044039042042039041010115116114046103115117098033040047040097099111115104124097115105110104124097116097110104124097116097110050124097116097110124097115105110124097099111115124099111115104124115105110104124116097110104124115105110124099111115124116097110124115113114116124108111103049048124108111103050124103097109109097124108111103124101120112124101114102099124101114102124104121112111116041047105041123034077097116104046035123036049046100111119110099097115101125034125010115116114046103115117098033040047040101040036124091094114120093041124112105041047105041123034077097116104058058035123036049046117112099097115101125034125010101118097108040102109116037115116114041010114101115099117101032069120099101112116105111110061062101010112117116115032034105110118097108105100032105110112117116034010101120105116032049010101110100010101110100010119061105110116040065082071086046115104105102116041046116111095105010104061105110116040065082071086046115104105102116041046116111095105010098061105110116040065082071086046115104105102116041046116111095102010101061105110116040065082071086046115104105102116041046116111095102010102061105110116040065082071086046106111105110040039032039041044034045062120123037115125034041010119105110061065114114097121046110101119040104041123065114114097121046110101119040119041123039032039125125010100120061040101045098041047119046116111095102010098101103105110010121061065114114097121046110101119040119041123124120124102091098043040120043048046053041042100120093125010114101115099117101032069120099101112116105111110010112117116115032034105110118097108105100032105110112117116034010101120105116032049010101110100010114044113061121046109105110109097120010114061048032105102032114062048010113061048032105102032113060048010114045061048046048048049032105102032114061061113010121046109097112033032100111032124122124032010112121061040040122045114041042104047040113045114041046116111095102045048046053041046114111117110100010112121061048032105102032112121032060032048010112121061104045049032105102032112121062061104010112121010101110100010121048061040045114042104047040113045114041046116111095102045048046053041046114111117110100010121048061048032105102032121048060048010121048061104045049032105102032121048062061104010100121061040113045114041047104046116111095102010119046116105109101115032100111032124120124010121049044121050061091121048044121091120093093046109105110109097120010040121049046046121050041046101097099104123124122124119105110091122093091120093061063035125010119105110091121048093091120093061063045010101110100010112117116115032119105110046114101118101114115101046109097112040038058106111105110041046106111105110040034010034041011r).numerator.to_s.chars.each_slice(3).map{|x|x.join.to_i.chr}.join


Try it online here at repl.it. Click run, then enter a valid argument line, such as 35 15 0 2*pi sin x.

Note that ruby has got numeric literals in rational notation, ie. 4/5r is the number 0.8. For your convenience, that number is in decimal notation:

0.99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999187817325507631477699523385795515799913435957136728483704843160446828746942390560409186850860550459503103569586130927727288203772199112576191921844592640902889572035182931044557197282985366759740529782716849115850973388128888140605856016243400934225013988573856465542961369877921225012232953123348907301055390544351983324259941650975914266982601521665336561026433337692479737252981932280375408178656797642567580351663715370847184948090264644342895761006305302658546567374207081251715305393141559888678604977336029384249599993510989638718694557098772678079302066224417461706230825883262839423706745230612246592682896861249489867511258470413422890405366642937755571215609655828342795522353669812478241921849184839881173278930914688691396470788124987284884994811350626430408706034083184877791252901811307637379707951652160630308934802951331036015209780395306897171922455792008341833306929756217105134837856722072340152691999593553044410316914296444316575597487088525352291142399342475681074383014729577969560349972908717460451924770322618430398137345975228390098138869196651815744192409770636367186809979333259806799971376312736295078106749882462806603965702298252800964932469571749077234373118173757367981246728722700185281874663305484854815686267951948417500805081514299284030097759433335422488161129087633379029256009841419395473193916652580757339572787031196350523848595739059934610272262632032121135958705400942675585265747208134940670459504182950490822639691988552469570184285722029155876735451418448434291837262494438475865157329632147682775273525502912629309290525247994344119402352906746562912938813927144960422882419280530188325720273357853282893027151548648597228005528806765612233826918005205637908161744746471586122788946189949197068027339580298342252401459219142053457266988043819308357365906624005185998891437015020338032062403957367331681344553645293069200824975432746819295160780502306565769430776755994267478055740983942989630802287991539070194275453164595814059912284843601522641410777102500263105136878073562527389017443916782604694404080884774270752289843169670231007599978515021264254378508439750915875696503075901715672796427206476124499884915354847212732145752199507692504324028476581994433822922095411336560774187464600857696611043903444276823939715034512911523115906203964192584762514518937414389869657622224007910810557978457559493621672434510900434676685136972372427070800690493574076002506601857966532889163912919790105381442988912454576487941545180577660951785673131001806319591499835474292142459954689545865168183300727693709294406587624795251901082689944668219506486589909889789178251301044755043291325912683548593327027307428216501496164310642944204812200141529560315129763903199886131965593255497607579963064788560238693963956045769026069143853104216790763807120448790598924521987287764993238737


This is a complete program, use it like this from the command line:

~ $ruby cplot.rb 35 15 0 2*pi 'sin x' ###### ######## ########## ############ ############## ############### ################# ----------------------------------- ################# ############### ############## ############ ########## ######## ######  or ~$ ruby cplot.rb 35 15 1/pi pi '1/x'
#
#
##
##
###
###
####
######
#######
#########
#############
##################
#############################
###################################
-----------------------------------


I count the code as follows:

eval
(
<numeric> [log_256(1)=0]
)
.
numerator
.
to_s
.
chars
.
each_slice
(
<numeric> [log_256(3)=0.19812]
)
.
map
{
|
x
|
.
join
.
to_i
.
chr
}
.
join

• Jupp. This scoring system turned out to be a bad idea. May 7, 2015 at 8:06
• I cant figure it out
– Ewan
May 7, 2015 at 8:27
• @Ewan That long number is of the form a/br, with b=a+1. In ruby, that's a numeric literal and taking the logarithmic gives pretty much zero. The numerator a contains 3*n digits, each group of 3 representing a byte (100=0x64="d"). These bytes are the actual program. Try replacing eval with puts and you can see the program. May 7, 2015 at 8:50
• i get the scoring trickery, i don't understand how the program functions
– Ewan
May 7, 2015 at 8:51
• ahh ok i see now, v clever!
– Ewan
May 7, 2015 at 8:52

c# - 70ish?

using System;
using System.Collections.Generic;
using System.Linq;
class P
{
static void Main()
{
Func<double,double> f = x => Math.Sin(x) -0.5;
string r = Draw(60, 20, -10, 10, f);
Console.Write(r);
}

static string Draw(int w, int h, int b, int e, Func<double, double> f)
{
IEnumerable<double> values = Enumerable.Range(0, w).Select(i => f(i * (double)(e - b) / w));
double scale = h / (values.Max() - values.Min());

return String.Join(Environment.NewLine,
Enumerable.Range(0, h)
.Select(y => ((h - y) / scale) - Math.Abs(values.Min()))
.Select(ypos => Math.Abs(ypos) < 1 / (scale * 2)
? new String('-', w)
: new String(values.Select(v => v > ypos ^ ypos < 0
? '#'
: ' ').ToArray())
)
);
}
}