123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778openCore_kernelopenPolyletnum_charn=Char.of_int_exn((Char.to_int'0')+n)letdata_linepercentage=List.init(percentage+1)~f:(funi->ifimod10=0thenbeginlettens=i/10iniftens=0||tens=10then'|'elsenum_chartensendelseifimod5=0then'+'else'-')|>String.of_char_listlet%test_=data_line27="|----+----1----+----2----+--"let%test_=data_line0="|"let%test_=data_line100="|----+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----|"letnarrow_data_linepercentage=letdiv=2inList.init(percentage/div+1)~f:(funi->letparts_per_10=10/divinifimodparts_per_10=0thenbeginlettens=i/parts_per_10iniftens=0||tens=10then'|'elsenum_chartensendelse'-')|>String.of_char_listlet%test_=narrow_data_line27="|----1----2---"let%test_=narrow_data_line0="|"let%test_=narrow_data_line100="|----1----2----3----4----5----6----7----8----9----|"letline~narrow~label~value~norm=letpercentage=Option.value(Float.iround_towards_zero(value*.norm))~default:0inassert(0<=percentage&&percentage<=100);letpre=ifnorm>1.0thensprintf"%10s %5.2f "labelvalueelsesprintf"%10s %8.0f "labelvalueinifnarrowthenpre^narrow_data_linepercentageelsepre^data_linepercentagelet%test_=line~narrow:false~label:"bar1"~value:1.05062~norm:10.0=" bar1 1.05 |----+----1"let%test_=line~narrow:false~label:"bar2"~value:499.6~norm:0.004=" bar2 500 |-"letrender?(narrow=false)labels_and_values=if(List.is_emptylabels_and_values||List.exists~f:(fun(_,x)->x<0.0)labels_and_values)thenfailwiths"Text_graph.render: Labels and values should be non-empty and values must be positive"labels_and_values[%sexp_of:(string*float)list];letlargest=matchlabels_and_valueswith|[]->assertfalse(* checked above *)|(_,v)::tl->List.foldtl~init:v~f:(funmax(_,v)->Float.maxmaxv)inletnorm=100.0/.largestinletlines=List.maplabels_and_values~f:(fun(label,value)->line~narrow~label~value~norm)inletlast_line=sprintf"(each \'-\' is approximately %.3f units.)"(ifnarrowthen2.0/.normelse1.0/.norm)inletconcatl=String.concatl~sep:"\n"inconcat[concatlines;last_line;""]